!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!       AltMenu                 An Inform 6 Library extension to create
!  Version 6                    object-oriented menus.  By L. Ross Raszewski
!                               ([email protected])
!  Requires DoMenu.h and utility.h
!
!
!  New in this version: Main code rewrite. The low memory "footprint"
!  of altmenu-related objects has been greatly reduced. This _should_
!  be invisible to the programmer, but whatever you do, don't go messing
!  with the Menu_Controller.
!
!  See the NOTES section for more information about this update
!
!    In brief, this is an object oriented front-end to my modified domenu
!    library.  It is designed for use with toggle options and dynamic menus
!    It supports menus over a page long.  It's easy to use and yet
!    greatly versatile.
!
! Usage:
!       To activate a menu, send the select(); message to the appropriate
!       Menu-Class object.  The menu will automatically manipulate menus
!       longer than one screen.
!       Set the "nolook" attribute to suppress the <<look>> action generated
!       when quitting the menu
!       the short name:
!               if a title bar is given, printed on the second line of the
!               banner, else printed on the first line.
!       the description property:
!               Holds the description test to be printed at the top of the
!               menu.
!       the number property:
!               Holds the number of lines which the description takes up
!               or a function to determine them.  If someone can provide
!               me with a reliable function, which can account for
!               differing screen widths, variable pitch font,
!               and manual new_lines, please send it this way!.
!       the title_bar property:
!               If given, is printed on the top line of the banner
!       the sup_bar property:
!               if given, is printed on the second line of the banner.
!               DO NOT use both a sup_bar and a title_bar.
!       the banner_tags property:
!               if given, this array contains the top bar tags to be used
!               by domenu (see domenu.h for the format of the tagarray
!
!    The children of a menu are the items of that menu. All children
!    of a menu must inherit from class Option.
!       the select property:
!               Performs the task of the option.  Returns 1 to wait for a
!               keypress, 2 to return with no keypress, and 3 to return and
!               exit the current menu. By default, this prints the description
!               of the object.
!       the "tag" property:
!               if given, this is used as the name given in menu itself
!       the label property: if given, this is used as the name placed in the
!               top bar when the option is selected
!
!   This library contains 2 additional varities of option classes:
!       Separator: A menu item which cannot be selected.  Useful for
!               grouping options together within a menu.
!               An option with the "locked" attribute also acts like a
!               separator
!       SwitchOption: A menu item designed to toggle, as in game settings
!          the label property: Printed in the menu.  Should be changed
!                to reflect the setting of the switch
!          (synonymous to tag property.  If both a tag and a label are given
!           preference is given to the tag)
!          the toggle property: Does the work of the switch.  This may be
!                as simple as turning the object from ~on to on, but might
!                involve global variables or otherwise affect the behavior
!                of the game
!
!
!  ONCE-MODE EMULATION: Set the "menu_style" property of the menu object to
!       "TRADITIONAL", "ONCE", or a positive integer to define the menu style.
!       The default value (-1) will cause the menu to be presented in the
!       same style as the _last menu activated_
!
!  NOTES:
!       For adaptive menus, in order to keep items in the same order,
!       use the Pmove function (from utility.h) to preserve lineage.
!
!       Menu objects may not make use of the "door" attribute. I can't see why
!       you would anyway, but if you need to for some reason, define
!       MENUS_USE_DOOR before inclusion (this will cost you an attribute)
!
!       In order to keep the memory footprint low, the old stubs have been
!       removed. If you are not using all of the features of Altmenu, you
!       may recieve an error while compiling, to the effect of "no such
!       constant as ..." attributed to altmenu.h. Define ALTMENU_PROP_STUBS
!       before inclusion to suppress these errors
!
!  This is part of a series of inter-dependant libraries.
!  For this to work, you have to include:
!  DoMenu       -> A modified DoMenu routine to support extended functionality
!  Utility      -> A set of generic utility functions
!
! For maximum enjoyment, add on (not required)
!  Hints.H      -> A system for making object-oriented hints which appear
!                      formatted in the same way as Infocom's InvisiClues
!
System_file;
iffalse DOMENU_LIBRARY>=62;
message error "AltMenu 6.0 requires version 6.2 or greater of the DoMenu library";
endif;
ifndef ALTMENU_LIBRARY;
Constant ALTMENU_LIBRARY 60;
ifndef MENUS_USE_DOOR;
Attribute nolook alias door;
ifnot;
Attribute nolook;
endif;
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
! Option Class (Menu options)
!        select             (calls self.description to perform menu
!                                       function.)
!                               returns: self.description();
!       Usage:
! Option "Option One"
!       with description "Some text here.";
!       Note - description returns 1 to run and wait for a keypress,
!               2 to run and return to the menu with no keypress
!               3 to run and quit the current menu.
!
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Class Option
       with    !tag [; print (name) self;],
               select [;
                         if (self provides description)
                          return self.description();
                         else rtrue;
                      ];

!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
! Separator Class (Null Menu Item)
!      Usage:
! Separator "Game Commands";
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Class separator;

!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
! SwitchOption Class (Toggle options)
!       with sup_bar (this is only a stub property.  Switchoptions will never
!                        use a sup_bar.)
!           short_name (prints self.label, if provided.)
!           select (runs self.toggle();)
!           title_bar (this is also a stub.)
!
!       Usage:
!  SwitchOption sound
!        with label [; print "Sound     ";
!                       if (self has on) style reverse; print "ON";
!                       style roman; print "   ";
!                       if (self hasnt on) style reverse; print "OFF";
!                       style roman;],
!               toggle [; if (self has on) give self ~on; else give self on;];
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Class SwitchOption
 with
      tag [; if (self provides label)
             { self.label(); return 1;}
          ],
      select [; self.toggle(); return 2;];


!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
! Menu class (This is the big one.)
!       class option (A menu can also be an option of another menu.)
!       with select (The main menu loop. throws the results back to Domenu.)
!            label (Stub for the option label property.)
!            toggle (Stub for the switchoption toggle property)
!            emblazon (prints the menu text, self.description, and the
!               list of children.  This is the first argument sent to Domenu.)
!            titles (generates the option names sent to Domenu.)
!            execute (runs the selected option.  Sent as the third argument
!                       to Domenu)
!            selection_name (generates the name needed by self.titles)
!            doname (prints the name of the menu.  A separate property,
!               because of the form of argument required by Domenu.)
!
!       Usage:
! Menu "Main Menu"
!       with description "This is the main Menu",
!            number 1, ! not strictly required, because in this case it is 1,
!                      !but provided for clarity
!            title_bar "The big game",  !will be printed on the first line
!                               ! of the menu bar
!            sup_bar "A menu"; !will be printed on the second line.  Use one,
!                               ! or the other, not both.
!
!
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Object Menu_Controller ""
 with select [m i j k l;
               l=self.current_menu;
               self.current_menu=m;
               if (self.current_menu has nolook) i=1;
               else i=0;
               k=menu_mode;
               if (self.current_menu provides menu_style && self.current_menu.menu_style~= -1)
                menu_mode=self.current_menu.menu_style;
               if (menu_mode~=TRADITIONAL && self.current_menu provides description)
                self.current_menu.description();
               if (self.current_menu provides banner_tags && self.current_menu.banner_tags ~=0)
                if (self.current_menu.#banner_tags~=2) j=self.current_menu.&banner_tags;
                else j=self.current_menu.banner_tags;
               DoMenu(self.emblazon,self.titles,self.execute,i,j);
               menu_mode=k;
               self.current_menu=l;
               return 2;
             ],
      current_menu 0,
      emblazon [ doFrom doTo o;
                 if (doFrom==0)
                  {
                   if (self.current_menu provides description)
                    self.current_menu.description();
                   else new_line;
                   dofrom=1;
                  }

                 o=Scion(self.current_menu,dofrom);
                 if (doto==0) doto==children(self.current_menu)+1;
                 while (o ofclass object && doTo>=0)
                  {
                   doTo--;
                   font off;
                   #ifdef V6DEFS_H;
                   StatusWin.SetFontStyle(ST_FIXED);
                   #endif;
                   spaces(5);
                   font on;
                   #ifdef V6DEFS_H;
                   StatusWin.SetFontStyle(ST_ROMAN);
                   #endif;
                   if (Menu_Mode~=Traditional)
                    style reverse;
                   if (o provides tag) o.tag();
                   else print (name) o;
                   new_line;
                   o=sibling(o);
                   if (Menu_Mode~=Traditional)
                    style reverse;

                  }

               ],
      titles [ o;
               if (menu_item==-5)
               {
                 o=Scion(self.current_menu,SkipItem);
                 if (o ofclass separator || o has locked)
                  return SKIP;
               }
               else if (menu_item==-1)
               {
                if (self.current_menu provides sup_bar)
                 item_name=self.current_menu.sup_bar;
                if (self.current_menu provides title_bar)
                 item_name=amtag;
                if (self.current_menu provides number)
                 return self.current_menu.number;
                else return 1;
               }
               else if (menu_item==0)
               {
                if (self.current_menu provides title_bar)
                 item_name=self.current_menu.title_bar;
                else item_name=amtag;
                return children(self.current_menu);
               }
               else
               {
                o=Scion(self.current_menu,menu_item);
                if (o ofclass object)
                { item_width=o;
                  item_name=selection_name;
                }
               }
             ],
      execute [ o j;
                j=2;
                o=Scion(self.current_menu,menu_item);
                if (o ofclass object)
                 j=o.select();
                return j;
              ];
Class Menu
 with select [; return Menu_Controller.select(self);],
      tag [; print (name) self;];

[ amtag; print (name) Menu_controller.current_menu;];
[ selection_name;
                       if (item_width provides label && item_width.label~=NULL)
                        if (item_width.label ofclass string) print (string) item_width.label;
                        else item_width.label();
                       else print (name) item_width;
                     ];
#ifdef ALTMENU_PROP_STUBS;
Object "" with label 0, toggle 0, menu_style 0, banner_tags 0, sup_bar 0, title_bar 0;
#endif;
endif;