Article View: comp.sys.acorn.tech
Article #851(long) Better definition of what menu template should do
From: TMOTA
Date: Thu, 07 Jan 1993 21:33
Date: Thu, 07 Jan 1993 21:33
460 lines
19928 bytes
19928 bytes
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
Technical Details
Message-ID:
<1993Jan7.213310.16932@cs.aukuni.ac.nz>Path:
arc1-ca.pugleaf.net!sparky!uunet!wupost!waikato.ac.nz!aukuni.ac.nz!cs18.cs.aukuni.ac.nz!jwil1Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!sparky!uunet!wupost!waikato.ac.nz!aukuni.ac.nz!cs18.cs.aukuni.ac.nz!jwil1 Newsgroups: comp.sys.acorn.tech Subject: (long) Better definition of what menu template should do Message-ID: <1993Jan7.213310.16932@cs.aukuni.ac.nz> From: jwil1@cs.aukuni.ac.nz (TMOTA) Date: Thu, 7 Jan 1993 21:33:10 GMT Sender: jwil1@cs.aukuni.ac.nz (TMOTA) Organization: Computer Science Dept. University of Auckland Lines: 460