Newsgroups: comp.sys.acorn.tech
Subject: (long) Better definition of what menu template should do
From: jwil1@cs.aukuni.ac.nz (TMOTA)
Date: Thu, 7 Jan 1993 21:33:10 GMT
Organization: Computer Science Dept. University of Auckland

Ah... I've just found that file I was working on a while back.

This is a menu template system that I've designed around a text-file
(i.e. easily editable) format for my own use. The main idea of this
one is to give all the features listed below, while being small and
reasonably efficient to implement, and easy and convenient to use from
within your program. The text file format is very simple so as to
force minimal parsing code on the application. Obviously a Glass file
binary format for this data will reducethe file size and the amount of
loading-support-code needed.

Hopefully this will explain all the details of what I want out of a
menu template system a bit better... Obviously the actual syntax of the
file is of little relevance, but it still serves to illustrate the ideas.

(sorry, 2400bps users, but it's a bit long)

---

			     The Menu Template System
				by  Jason Williams

We already use template files containing definitions for windows in our
applications: They make life much quicker and easier for the programmer,
and allow the user to alter the layout of windows (at least to some extent)
to suit themselves.

However, a startling omission from RISC OS is the lack of a similar function
for definition of menu structures. Partially this stems from the dynamic
nature allowed by the menu system, but I feel it is mostly caused by laziness
and mis-design of menus...

In most cases, menus can be designed as fixed entities, with an occasional
menu (a font list, for example) being created 'on the fly'. Much of the
data-entry of menu items *should* be placed into dialogue boxes which are
available in a menu, and by clicking a menu item, and by pressing a certain
key-combination. Some other data may be placed as a group of 'tickable' menu
items, in which the programmer currently has to do all the work of only
allowing one item to be ticked at once. Another failing in many applications
is that when they shade (make unselectable) an item which leads to a submenu,
the submenu can no longer be brought up in order to see what is in it.

The menu template system is a C code library which solves all of these
problems in one go. It goes further than any attempt I have ever seen to
provide a menu-template system.

The template system, as well as providing an automated system by which menu
templates can be loaded, and used to create menu trees, also gives functions
which automatically handle menus in useful ways, and make menu decoding much
simpler for the programmer.

The fundamental concepts behind the template system are:
  * Text file (easily read/edited) contains the templates
  * Intermediate interface between the user, the OS and the program, with
    the program using tags to which menu items are attached, and the user
    being free to edit item data. Thus, the program doesn't have to worry
    about what language the menus are displaying, or where in the menu tree
    an item was when it was selected: A unique tag allows the user to move
    any item anywhere, and it will still operate as normal.
  * Extra automated handling to ease the work of the programmer. Correct
    menu shading and tickable-item e.s.g. handling are provided.

---

Menu template file syntax
=========================

COMMENTS
  Blank lines, and any line whose first non-blank character is a '#' will
  be treated as comments. Everything on a line after a '#' will be ignored,
  excepting if the '#' appears in a string (between a pair of double quotes)


TAGS
Menus and their items are referred to using tags. For speed and simplicity
these tags are 4 characters long, and are handled by the loading code in
such a way as to allow
  definition in file:  tag1
  comparison in C:     if (thetag == 'tag1')
		       switch (thetag)
		       {
			 case 'tag1':
			 case 'tag2':
		       }
which really is extremely convenient.
Tags can be defined as less than 4 characters, in which case, they will be
padded out with space characters, so t1 will become the tag 't1  '.

Item tags are localised within each menu definition, but *PLEASE* use
globally unique tags for menu items. This will allow you to act on a
selection of any menu item regardless of where it was situated in any menu
tree. The user could then edit your menus to look completely different,
split menus, and generally rearrange anything anywhere anytime, and your
application would continue to run correctly, completely unaffected (except
for the external menu interface for the user).
This will also improve the chances of porting this code to work as an
interface layer for other operating systems so that porting RISC OS WIMP
applications to other WIMPs might be made easier.

Menu tags should be different from all other menu tags, but need not be
different from item tags.


MENU
A menu is a set of n items, with a header containing the menu tag, the
title text, and the number of items in the menu. NOTE that the numitems
value can be larger than the menu needs (for future menu adjustment), but
must not be smaller.
Each entry must be on a single separate line as shown:

  menu   = MENU tag:4 "title" numitems
	     item
	     item
	     ...
	   ENDMENU


ITEM
Each item specifies the item tag, item text, and a set of space-separated
flags.

  item   = ITEM tag:4 text [flags]


The text is an arbitrary string contained within double quotes (double quotes
not allowed within the string: tough titty). For a writable icon, this string
is used as the default text.

  text   = "any string"

The flags are explained in detail below.
Each flag is separated by a space.
A summary of the flags is:

  flags    >                                    ; has subwindow
	   >menu                                ; has submenu "menu"
	   _                                    ; dotted line after this item
	   -                                    ;   "
	   T01+                                 ; this item is tickable, with
						; esg number 1 & is ticked
	   K020                                 ; Key equivalent (decimal)
	   ?6                                   ; Writable, 6 chars allowed
	   S                                    ; Shaded

Full flag descriptions:
>
  This specifies that the item should have a sublink arrow and generate a
  sublink message, for the program to provide the appropriate window.

>menu
  This specifies that this item will bring up the named submenu.

_ or -
  This specifies that the item is followed by a dotted line
  This may also be used on it's own on a line to indicate the same.
  (Everything after the first _ or - will be ignored)

T00+
  This specifies that the item is tickable.
  The following decimal number (not optional) specifies the esg number for the
  tick. Values from 0 to 250 are allowed (251-255 are used internally as
  special values, so do not use them). The esg number of 0 is special,
  indicating no esg - the item is unrelated to any other items.
  ESGs are localised to within one (sub)menu definition.
  Optionally, this can be followed by a + which indicates that the item is
  ticked. If no + is present, the item is not ticked.

K020
  This specifies the decimal wimp keycode for the key equivalent.
  You should also set the item text to show this key equivalent to the right
  side of the menu, in the standard format.

?6
  This indicates that the item is writable, with a maximum of 6 characters
  allowed in it. NOTE: This doesn't count the terminator (as the WIMP does),
  so 6 means allow up to 6 characters to be entered.

S
  This indicates that the item should be shaded by default.
  (NOTE: If this item also has a submenu, the item will be made grey but will
  remain selectable in order to allow users to see the submenu. If such an
  item is shaded, all items below it recursively will be shaded as well, in
  the internal database, though, this 'global' shading is kept separate from
  individual item shading so that unshading a menu item will restore the
  previous single-item shading in the submenu.)


QUICKKEYS
This extra feature has been added, as it is very esy to integrate, and saves
extra work along similar lines in another portion of your code.
The quickkeys segment of the template file MUST be the last thing in the file
(i.e. no menu definitions may follow it)

It simply defines a set of mappings between tags and WIMP key codes. These
are stored by the Menu manager, and when you request a check for a quickkey,
the menu manager scans all the quick-keys in the menu items it owns, as well
as the quick-key list. If any quick-key is matched, it's tag will be returned
to your menu-selection handler. Thus, all possible functions should be given
a unique tag and be connected by it into your menu-selection handler, so that
your program becomes a simple macro processor (in future a scheme may be
added whereby several tags may be attached to a keypress, such that a single
keypress will be able to perform the equivalent of several menu selections
in sequence) 


Example:
  menu save "Save format" 2                # Save submenu, 2 items
    item sav1 "Armadeus   " > S            # Shaded, has a sub-window
    item sav2 "DataVox    " >              # Has a sub-window
  endmenu

  menu optn "Options" 3                    # Options submenu, 3 items
    item opt1 "Type 1" T01                 # Tickable, esg = 1, not ticked
    item opt2 "Type 2" T01+                # Tickable, esg = 1, ticked
    item opt3 "Thingo" T00+                # Tickable, NO esg,  ticked
  endmenu

  menu main "DSEdit II" 8                  # Main menu, up to 8 items long
    info "Info     ^I" K009 >              # Key equiv. 9 (ctrl-I), subwindow
	  -----------                      # ...with dotted line underneath
    optn "Options    " >optn S             # optn (options) submenu, shaded
    save "Save       " >save               # save (save format) submenu
	  -----------                      # ...with dotted line underneath
    quit "Quit       "                     # Nothing special about this item
  endmenu

  quickkeys                                # This must be last thing in file
    ok K13                                 # "OK" key is return
    canc K27                               # "Cancel" key is escape


Will generate this set of menus:
 +---------------+
 |  DSEdit II    |
 +---------------+
 | Info    ^I => | -> to Info window
 | - - - - - - - | +---------+
 | Options    => | | Options | +-------------+
 | Save       => | +---------+ | Save format |
 | - - - - - - - | | Type 1  | +-------------+
 | Quit          | |/Type 2  | | Armadeus => | -> to save-as window
 +---------------+ |/Thingo  | | DataVox  => | -> to save-as window
		   +---------+ +-------------+
The options submenu will automatically pop up from the "Options" item if you
move the pointer over the arrow.
The Save format submenu will automatically pop up from the "Save" item...

As well as generating the menus, the above template will set up information
needed ny the handers to handle various things such as ticked items, shading,
submenu linking, and quick-keys automatically.

---

Supplied Functions
==================

  Menu_Init(void)
    Initialises the menu system. Call this once (only) before you call any
    other menu functions. If not called, effects are unpredictable.

  BOOL Menu_LoadTemplates(char *filename)
    Loads all menus from the given template file, allocating exactly the
    needed space. Returns TRUE if it succeeds, FALSE if it fails.

  Menu_ReleaseTemplates()
    Deallocates the memory used by ALL the menus.

  Menu_Show(menutag menu, BOOL iconbar)
    Creates and opens the menu structure requested. If iconbar == TRUE, then
    the menu is placed at the correct height above the iconbar, else it is
    placed at the current mouse pointer position.

  Menu_Reopen()
    Re-opens the last menu created. Internal call called by Menu_Decode when
    an adjust-click is used on a menuitem.

  Menu_Decode(wimp_eventstr *event, menutag *menu, menutag *item)
    When you recieve a menu selection (9) event from the WIMP, for a menu
    you opened with a Menu_Open() call, call this function, which will decode
    the event into menu and item tags.

    If the item tag returned is menu_INVALID, ignore the event (do nothing)
    -This can occur from invalid selections and most notably from greyed
    items that have been left selectable to allow the user to see submenus.
    The menu decoder will work out if the selection is valid for you.

    Upon receipt, use the *item* tag to determine your action. If *absolutely*
    necessary, you can use the menu tag for this determination, but this will
    remove the ability for anyone to move items to arbitrary positions in
    the menu tree (Also, try to use globally unique tags, although this is
    not enforced by the menu code). The menu tag returned is meant to only
    be used if it is necessary to tick/shade the item or read data from a
    writable...

  Menu_CheckKey(wimp_eventstr *event, menutag *menu, menutag *item)
    When you recieve a keypress event from the WIMP, call this function to
    check for quick-keys after checking any more important keypresses. If
    it returns values other than menu_INVALID for the menu/item, then a
    quick-key is being requested, and you should pass these tags to the
    same handling code that you call on a menu selection event.

  Menu_ShadeItem(menutag menu, menutag item, BOOL shaded)
    Shades/unshades the given menuitem. Two different shading values are used
    by the menu system (really shaded, and just greyed out so that submenus can
    still be seen). The menu system will not return a click on either type
    of shaded icon. Shading/unshading an item in a globally-shaded menu will
    alter the internal database, but will only have a noticable effect when the
    entre menu is globally-un-shaded.

  Menu_TickItem(menutag menu, menutag item, BOOL ticked)
    Ticks/unticks the menu item, with the following provisos:
    * Won't alter an untickable item
    * Will only untick an item with esg 0, which indicates it is a 'loner'.
      If the item is part of an esg group, it will be ticked regardless.
    * Will search for other items of the same esg in the submenu, and will
      untick them, guaranteeing that only one of them is ever ticked.

  Menu_SetWritable(menutag menu, menutag item, char *newtext)
    Will set the text in a writable menu item to the given text. It will be
    truncated if necessary to fit the template buffer size.

  char *Menu_ReadWritable(menutag menu, menutag item)
    Returns a pointer to the text buffer of the writable. This should ONLY
    be treated as a read-only resource. Use the above call if you wish to
    write to this buffer. If you want to use/alter the text, make a copy
    of the string to your own workspace.

Attaching your own submenus/tweaking the WIMP menu data
If you want a dynamic menu (e.g. a font list) anywhere in your menus, you
must create it separately yourself, and then attach it to the Menu_()
created menu tree manually. If you want to 'twiddle' any of the base WIMP
menu items (as passed to Wimp_CreateMenu), then you also need to build and
show the menu in two steps.

Example of adding a submenu:
  mainmenu = Menu_Build("main");     /* Create the main menu structure       */
  itemptr  = Menu_ReturnAddress("show","font");
				     /* find the "Show => Font" submenu item */
  menuptr  = Create_My_Font_Menu();  /* Create the font submenu              */
  itemptr->sublink = menuptr;        /* Link it in as this item's submenu    */
  Menu_Open(mainmenu, FALSE);

Changing other data for an item is a very similar process to the above.

  menu_block *Menu_Build(menutag menu)
    Recursively builds the given menu structure, returning a pointer to
    the WIMP menu definition block. You'll have to use Menu-ReturnAddress
    to chain down the menu structure to a leaf-item where you can attach
    your own submenu (e.g. a font menu), or you can attach this menu tree
    as a subtree of your own menu...

  Menu_ReturnAddress(menutag menu, menutag item)
    Returns the address of the last place to which this item was 'built'.
    (So be careful to only use this call when the menu has just been built)
    You can then modify the item's WIMP data directly to tweak things, attach
    your own dynamic submenus, etc.
    If the item tag passed in is menu_INVALID, the address of the menu header
    will be returned instead.

  Menu_Open(menu_block *menu, BOOL iconbar)
    Opens the WIMP menu defined in the given block under the pointer. If
    iconbar == TRUE, then it is opened at the appropriate height above the
    icon bar.
    
---

Internal Data Structures
========================

/* Actual WIMP menu blocks... */
typedef struct
{
  unsigned int ticked    : 1;
  unsigned int dotted    : 1;
  unsigned int writable  : 1;
  unsigned int reserved1 : 4;
  unsigned int lastitem  : 1;
  unsigned int reserved2 : 24;
} menu_flags


typedef union
{
  int              value;
  window_handle    window;
  struct menu_item *submenu;
}


typedef struct
{
  menu_flags   flags;
  menu_sublink sublink;
  icon_flags   iconflags;
  icon_data    data;
} menu_item;


typedef struct
{
  char title[12];
  int  colours;
  int  width;
  int  height;
  int  gap;
  /* menu_item items[]; */
} menu_block;


/* New structures for holding augmented menu structures... */

/*  ESG numbers: 0 means this is tickable, but not in any ESG (a loner)
 *               250-254 are reserved for future expansion
 *               255 means this is not tickable
 */
#define ESG_LONER  0
#define ESG_NOTICK 255

#define menu_INVALID 0;
typedef int menutag;

typedef struct
{
  unsigned int shaded    :1;    /* greyed and unselectable          */
  unsigned int greyed    :1;    /* greyed, but still selectable     */
  unsigned int writable  :1;    /* Item is writable                 */
  unsigned int ticked    :1;    /* This item is ticked              */

  unsigned int lastitem  :1;    /* This is the last valid menu item */

  unsigned int reserved1 :3;

  unsigned int tickesg   :8;    /* Tickable esg number (see above)  */
  unsigned int buffsize  :8;    /* Writable maximum text length     */

  unsigned int reserved2 :8;
} menuflags;


typedef struct
{
  menutag   tag;
  menutag   sublink;             /* Either menu tag or SUBWINDOW             */
  char      *text;               /* Pointer to text/writable buffer          */
  menuflags flags;
  menu_item *lastaddress;        /* Ptr to last place WIMP item for this was */
} menuentry;


typedef struct
{
  menutag    tag;
  char       *title;
  menu_block *lastaddress;       /* Ptr to last place WIMP defn for this was */
  char       numitems;           /* Max. # of items: size of allocated array */
  char       menuwidth;          /* Menu width (in characters)               */
  menuentry  *items;             /* Pointer to array of items                */
} menuheader;
-- 
themasterofthearcanejwil1@cs.aukuni.ac.nzthismessagewassentonrecycledelectrons