!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!       AltMenu                 An Inform 6 Library extension to create 
!  Version 6                    object-oriented menus.  By L. Ross Raszewski
!                               (rraszews@acm.org)
!  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;