Menus are automated by a dynamic
structure, which is interpreted at runtime. There are two types of menus Popups
and standard (toolbar) Menus. Popups allow a subset of the features of Menus to
be used.
Toolbar or top menus require
dynamic storage for enabling/disabling and checking/un-checking menu options
and, less frequently, changing the icons and selecting the top of the menu.
These have separate drawing routines and need to be sent the key presses so
that they can open up when the appropriate function keys are pressed.
//MenuBegin(struct) or use MenuNew,
MenuAdd, MenuBegin to build the menu
enum MENU_TYPE {
MT_TEXT=0x8000, MT_XREF=0x9000, MT_ICON=0xA000 /* ((n*0x1000)|0x8000) */
MT_CASCADE=0x4000 }; /* top 4 bits */
/* If ICON offset
not defined, it is a Redef type */
typedef union {
struct {
WORD ID; /* MENU_TYPE | ID
returned */
WORD Val; /* offset of ICON or TEXT, or XR_String
value (NB top bit clear) */
//WORD CascadeOffset; /*
if( ID&&MT_CASCADE ) */
} entry;
DWORD l; /*
-1 is end terminator */
} MENU_ENTRY;
/* Note: The top
bits of MT_TEXT, MT_XREF & MT_ICON are set because MENU_ENTRY is a
* variable length structure (4 or 6
bytes) depending on whether a cascade is
* defined. To correctly move between
entry indexes, i.e. up & down, the following occurs
* .down – if MT_CASCADE set move down 6
bytes, otherwise move down 4 bytes
* .up – move back 4 bytes if bit is
clear => on entry.Val, move back another 2 bytes
*/
typedef struct {
WORD ID; /* without the
MENU_TYPE | */
ICON Icon;
} MENU_REDEF;
typedef struct {
WORD DisplayOffset;
WORD Flags;
WORD TotalItems;
SCR_COORDS Width, Height;
WORD MainItems;
WORD DynSize; /*
for dynamic building of menus */
WORD RedefOffset;
WORD RedefItems;
BYTE Data[1]; /*
variable length structure should be [] */
} MENU;
typedef struct {
MENU *Menu; /*
0x0 Menu structure this belongs to */
MENU_ENTRY *StartEntry; /* 0x4 Current
MENU_ENTRY open */
SCR_RECT Rect; /*
0x8 Top Bar */
WORD Flags; /*
0xC MenuFlags */
WORD TopSelect; /*
0xE Top number selected (see Geom) (MenuTopSelect) */
WORD TopStatIndex; /* 0x10 Top flags,
Index in Data[] (0) (MenuTopStat) */
WORD SubStatIndex; /* 0x12 (MenuSubStat)
*/
WORD CheckIndex; /* 0x14 (MenuCheck) */
WORD TopRedefIndex; /* 0x16 Geometry
(MenuTopRedef) */
BYTE Data[1]; /*
0x18 flags - should be [] */
} MENU_STATE;
/* Stat and Check
take 1 bit per item, RedefIndex's are each one WORD */
static const BYTE
BITS[8] = { 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80 };
static const
MULTI_LINES TopTab[16] = { 3,
{ A_REVERSE, -2, 0, 2, 0, },
{ A_NORMAL, -3, 0, 0, 3, },
{ A_NORMAL, 0, 3, 3, 0, },
};
#ifndef AMS2
static const
MULTI_LINES BottomTab[16] = { 3, //Not used
{ A_REVERSE, -2, 0, 2, 0, },
{ A_NORMAL, -3, 0, 0, -3, },
{ A_NORMAL, 0, -3, 3, 0, },
};
#endif
void MenuInit(
void );
void MenuUpdate(
void );
#define MenuUpdate ASAP_ref(73,
void (*const)( void ))
WORD
MenuPopup(MENU *Menu, WORD x, WORD y, WORD ID);
#define MenuPopup ASAP_ref(59, WORD
(*const)(MENU *, WORD, WORD, WORD))
/* Displays popup menu, and returns
selected item
ID is starting item to select
*/
//(toolbar) menus which maintain
the state in a handle: (activated by MenuKey)
void
MenuSubStat(HANDLE State, WORD ID, BOOL Status);
#define MenuSubStat ASAP_ref(60,
void (*const)(HANDLE, WORD, BOOL))
/* Set Enabled/Disabled flag of
sub-entry with event ID */
void
MenuTopStat(HANDLE State, WORD Top, BOOL Status);
#define MenuTopStat ASAP_ref(61,
void (*const)(HANDLE, WORD, BOOL))
/* Set Enabled/Disabled flag of Top
menu */
void
MenuCheck(HANDLE State, WORD ID, WORD Check);
#define MenuCheck ASAP_ref(55, void
(*const)(HANDLE, WORD, WORD))
/* Set Checked/Unchecked flag of
sub-entry with event ID
Should be BOOL? although 2 is
actually considered for some reason
*/
HANDLE
MenuBegin(MENU *Menu, WORD x, WORD y, WORD Flags);
#define MenuBegin ASAP_ref(54,
HANDLE (*const)(MENU *, WORD, WORD, WORD))
/* creates and returns state */
void MenuOn(HANDLE
State);
#define MenuOn ASAP_ref(58, void
(*const)(HANDLE))
/* draws dynamic menu (after
MenuBegin etc) */
//changing the top states (see
Geometry)
void
MenuTopSelect(HANDLE State, WORD Top);
#define MenuTopSelect ASAP_ref(62,
void (*const)(HANDLE, WORD))
/* Select (draws thick surround)
Menu Top
-1 for none */
void
MenuTopRedef(HANDLE State, WORD Top, WORD Index);
#define MenuTopRedef ASAP_ref(63,
void (*const)(HANDLE, WORD, WORD))
/* Set the Top Menu icon to new
Index */
WORD
MenuGetTopRedef(HANDLE State, WORD Top);
#define MenuGetTopRedef
ASAP_ref(64, WORD (*const)(HANDLE, WORD))
/* Get the Index of Top Menu num's
icon */
void
MenuEnd(HANDLE State);
#define MenuEnd ASAP_ref(56, void
(*const)(HANDLE))
/* deallocate state etc. */
WORD
MenuKey(HANDLE State, WORD KeyCode);
#define MenuKey ASAP_ref(57, WORD
(*const)(HANDLE, WORD))
/* Send KeyCode to (state) menu,
used to drop down appropriate menu when FKey pressed
return the value if item selected
(-2 if bad KeyCode, 0 if esc) */
//Create MENU dynamically (used for
custom menus, see below)
//Note: once created dynamically
this structure can be used as a resource
HANDLE
MenuAddText(HANDLE h, WORD Link, const char *Text, WORD ID, WORD Flags);
#define MenuAddText ASAP_ref(65,
HANDLE (*const)(HANDLE, WORD, const char *, WORD, WORD))
HANDLE
MenuAddIcon(HANDLE h, WORD Link, pICON Icon, WORD ID, WORD Flags);
#define MenuAddIcon ASAP_ref(66,
HANDLE (*const)(HANDLE, WORD, pICON, WORD, WORD))
HANDLE
MenuNew(WORD Flags, WORD Width, WORD Height);
#define MenuNew ASAP_ref(67, HANDLE
(*const)(WORD, WORD, WORD))
//Create popup MENU, these are
simplified menus, same structure though
HANDLE
PopupAddText(HANDLE h, WORD Link, const char *Text, WORD ID);
#define PopupAddText ASAP_ref(68,
HANDLE (*const)(HANDLE, WORD, const char *, WORD))
HANDLE PopupClear(HANDLE
h);
#define PopupClear ASAP_ref(70,
HANDLE (*const)(HANDLE))
HANDLE
PopupNew(const char *Title, WORD Height);
#define PopupNew ASAP_ref(69,
HANDLE (*const)(const char *, WORD))
WORD
PopupDo(HANDLE h, WORD x, WORD y, WORD ID);
#define PopupDo ASAP_ref(71, WORD
(*const)(HANDLE, WORD, WORD, WORD))
/* Display dynamically created menu
calls MenuPopup
*/
char
*PopupText(HANDLE h, WORD ID);
#define PopupText ASAP_ref(72, char
*(*const) (HANDLE, WORD))
/* returns name associated with ID
*/
static void
*GetItemInfo(MENU *Menu, MENU_ITEM *Cur);
/* Return either MenuItemName or
MENU_REDEF for Cur */
static MENU_ITEM
*FindPopupTextItem(HANDLE h, WORD ID);
/* for PopupText */
static HANDLE
PopupInit(HANDLE h, char *Title, WORD Height);
/* PopupClear & PopupNew use
this */
static HANDLE
MenuAdd(HANDLE h, WORD Link, const void *Ptr, WORD ID, WORD Flags);
static void
PaintPopup(HANDLE State, MENU *Menu, MENU_ENTRY *Start, MENU_ENTRY *Cur,
MENU_ENTRY *Last, pIcon OptionalIcon);
/* Every time popup is opened or
redrawn */
static void
PaintItem(HANDLE State, MENU_ENTRY *Cur, const void *Item, BOOL Draw);
/* Draws Icon or Text from
GetItemInfo */
static void
PaintTop(HANDLE State, MENU_ENTRY *Start, WORD Attrs /* BOOL Draw */);
/* Draw entire Top toolbar */
static void
MenuRect(SCR_RECT *Dest, MENU *Menu, WORD x, WORD y);
/* Fill in Dest rect from Menu at
(x,y) */
WORD
GetPopupOffset(MENU *Menu, WORD ID);
/* Find offset (number from top) of
item with ID in menu structure */
static WORD
GetIDOffset(MENU *Menu, WORD ID);
static WORD
GetIDOffset_aux(MENU *Menu, WORD ID, BOOL noscan);
/* returns offset in a0 */
static WORD
CountAllItems(MENU_ENTRY *Cascade, BOOL CountIconsTwice, WORD *CascadeCount);
static MENU_ENTRY
*GetCascade(MENU *Menu, MENU_ENTRY *Cur);
static MENU_ENTRY
*MoveDown(MENU_ENTRY *Cur);
/* Note at top this will wrap
around to bottom (although this is never allowed on AMS1) */
static MENU_ENTRY
*MoveUp(MENU_ENTRY *Cur);
/* As with MoveDown, at bottom will
wrap to top */
//These checks to stop above 2 from
wrapping on AMS1
static BOOL
AtTop(MENU_ENTRY *Cur);
static BOOL
AtBottom(MENU_ENTRY *Cur);
static WORD
DefaultWidth(MENU *Menu, MENU_ENTRY *Cur);
/* Returns size or minimum default
if "small" (used for top menus) */
static MENU_ENTRY
*GetUptoWidth(WORD Width, MENU *Menu, MENU_ENTRY *Start);
/* Strange – seems to sum up widths
unti Width is reached, returning MENU_ENTRY */
static MENU_ENTRY
*LastItemFit(WORD Height, MENU_ENTRY *Start);
/* Returns the last entry that will
fit within the given height */
char
*MenuItemName(MENU *Menu, MENU_ENTRY *Cur);
/* Get the name of cur, either from
structure or XR name */
static WORD
CountBetweenItems(MENU_ENTRY *Start, MENU_ENTRY *Cur, BOOL CountIconsTwice);
static MENU_REDEF
*GetRedef(MENU *Menu, WORD ID);
/* Do a binary search in Redef
section of Menu for ID */
static MENU_ENTRY
*MenuItemN(MENU_ENTRY *Start, WORD num);
/* used for finding offset of popup
in menu structure (for FKeys etc.) */
static MENU_ENTRY
*Find(MENU *Menu, MENU_ENTRY *Start, char c);
/* searches for entry starting with
char 'c' */
MENU_ENTRY
*MenuItemNSub(MENU *Menu, MENU_ENTRY *start, WORD num);
/* Return pointer to ItemN in (Sub)
Menu, ignoring popup menus in count */
static WORD
GetFKey(KEYCODE key);
/* Return FKey num or –2 if key out
of (FKey) range */
static WORD
FindWidth(MENU *Menu, MENU_ENTRY *Start);
/* Finds maximum width of all items
from Start to end of entries */
static void
InvertTop(HANDLE State, MENU_ENTRY *Start, MENU_ENTRY *Cur);
/* Used in deselecting &
selecting */
static BYTE
InvertSub(SCR_RECT r, MENU_ENTRY *Start, MENU_ENTRY *Cur, WORD yOffset);
/* Returns r.y1 */
static BYTE
NumToChar(BYTE c);
/* isn't supposed to go above 8 */
static WORD
GetJumpKey(KEYCODE key);
/* Return number from top, or –1 if
out of range */
static BOOL
GetTopStat(MENU_STATE *State, WORD Top);
/* returns the state of Top,
non-zero if enabled etc.
(Not true BOOL returned, shifted
according to position)
*/
static BOOL
GetSubStat(HANDLE State, MENU_ENTRY *Cur, WORD *Offset);
/* if found Offset is set,
otherwise 1 is retured (default – enabled)
If Offset isn't supplied, it is
looked up from cur
(Not true BOOL returned, shifted
according to position)
*/
static BOOL
GetCheck(HANDLE State, MENU_ENTRY *Cur, WORD *Offset);
/* As GetSubStat, but returns
default value of 0 (unchecked)
(Not true BOOL returned, shifted
according to position)
*/
static WORD
CountItems(MENU *Menu, WORD PopupOffset)
BOOL
is_cascade(MENU_ENTRY *Cur);
static WORD
DoPopup(HANDLE State, MENU *Menu, MENU_ENTRY *Cur, MENU_ENTRY *Start, WORD x,
WORD y, WORD StartOffset);
/* State or Menu & entry */
// Save system states before and
after menu
static void
MenuBackup( void );
static void
MenuRestore( void );
static WORD
*GetTopRedef(MENU_STATE *State, WORD num);
static WORD
FindOffset(MENU *Menu, MENU_ENTRY *Start);
/* Recursivly search for global
FindID in Menu, returning Index in cascade
-1 if not found
*/
static pICON
TopDef;
static MENU_ENTRY
*CurEntry;
static WORD x, y;
static WORD tmp;
WORD StatPos;
KEYCODE KeyPress;
WORD FindID;
WINDOW wMenu;
BOOL
OldCursorActive;
SCR_STATE
OldScrState;
WORD TopXPos[11];
BOOL
DrawTopCascade; /* Haven't
seen this in use */
WORD FirstFKey;
WORD LastFKey;
WORD Cascades; /* Recursion
count */
struct
MENU_ENTRY {
WORD ID; /* MENU_TYPE | ID returned */
WORD Val; /* offset of ICON or TEXT, or
XR_String value */
packed union { /* if cascade, we have an extra
MENU_ENTRY offset: */
WORD CascadeOffset;
} extras;
};
struct
MENU {
WORD DisplayOffset; /* Text or Icon */
WORD Flags;
WORD TotalItems;
SCR_COORDS Width, Height;
WORD MainItems;
WORD DynSize; /*
0 for const */
WORD RedefOffset; /* Redefinable
icons */
WORD RedefItems;
DWORD separator=-1;
MENU_ENTRY titles[];
DWORD separator=-1;
struct {
MENU_ENTRY Entry;
DWORD separator=-1;
} cascade[]; /*
defined later in structure */
packed union {
ICON Icon;
TEXT Name;
} Display[];
MENU_REDEF RedefIcons[];
};