Menu  (menu.o)

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[];

};