 |
MenuPopup |
Function (ROM Call 0x3B) |
Executes a popup menu given a pointer to a popup menu structure.
MenuPopup works exactly like PopupDo, except instead of the handle,
a pointer to the menu structure is given as the parameter. PopupDo
internally calls HeapDeref, then passes the returned pointer
to this function. This function is mainly used internally in the TIOS. Its advantage in
comparison with PopupDo is the fact that the complete popup menu
structure may be given as a static pre-filled array of bytes, and you can pass the pointer
to such a structure to the MenuPopup function. This will save a lot of memory, because you do not need
to call PopupNew and a lot of functions like PopupAddText.
Moreover, MenuPopup allows executing menus with more than one level of submenus even in AMS 1.xx, which
is not possible otherwise. But note that the menu
structure is a quite complicated variable-shape structure, so if you do not know exactly what
you are doing, avoid this function! As the menu structure has a variable length and shape,
it can not be strictly described as a C language type, but it will be described here using
non-formal C-like syntax. Note that toolbar menus use the same structure:
packed struct MENU
{
unsigned short DisplayOffset; // Contains offset to Display[0] from here
unsigned short Flags; // Various flags: see text below
unsigned short TotalItems; // Total number of items
unsigned char Width; // Menu width, 0 for popup menus
unsigned char Height; // Menu height
unsigned short MainItems; // Number of main items only
unsigned short DynSize; // Dynamic size (see text below)
unsigned short RedefOffset; // Offset to RedefIcons, 0 if RedefItems = 0
unsigned short RedefItems; // Number of redefinable icons
long separator = -1;
MENU_ENTRY main_entries []; // for each main item
long separator = -1;
struct
{
MENU_ENTRY sub_entries []; // for each submenu item
long separator = -1;
} cascade []; // for each submenu
packed union
{
ICON Icon; // Used in toolbars with icons instead of text
char Text []; // Text, zero terminated
} Display []; // for each menu item
struct
{
unsigned short ID; // ID number
ICON Icon; // Corresponding icon description
} RedefIcons []; // for each redefinable icon (if any)
};
The Flags field contains various flags defined in the enum
MenuFlagsEnum.
The DynSize field for dynamically created menus (i.e. menus created with
PopupNew) contains the total length of the MENU structure in bytes (this
info is needed for the heap manager). For statically allocated menus, you can put zero in this
field. Also, each element of the array Display should be aligned on a word boundary. This is not
strictly necessary for text items, but it is necessary for icon items.
Each menu item is described using a variable-length (4 or 6 bytes) structure called
MENU_ENTRY, which is described as:
struct MENU_ENTRY
{
unsigned short ID; // Item type (see below) ORed with
// ID number for this item
unsigned short Offset; // Offset of icon/text (from Display[0])
// or XR_string, depending of item type
packed union // If the item is cascaded (i.e if it has
{ // a submenu), we have an extra offset
unsigned short CascadeOffset; // Offset from the begining of menu
} extras; // structure to the begining of the
}; // description of the cascaded submenu
Possible item types are MT_TEXT (0x8000), MT_XREF (0x9000), and MT_ICON (0xA000). They may
optionally be ORed with MT_CASCADE (0x4000) to signalize that the item is cascaded (i.e. that
the item has a submenu). All these constants are defined in the enum ItemTypes.
The CascadeOffset field exists only if ID & MT_CASCADE is non-zero
(i.e. if bit b14 in ID is set). If the Offset field for an item of icon type is not
defined, this is an item with redefinable icons (for example, the toolbar menu item in the Geometry application
uses such menu items).
Note that the topmost (b15) bit of the ID field is always set, and the topmost bit of the
Offset field is always 0. This is necessary because MENU_ENTRY is a variable length
structure (4 or 6 bytes), depending on whether a cascade is defined. To correctly move up and down
through menu items, the TIOS uses the following strategy: on pressing down, if MT_CASCADE is set,
move down 6 bytes, otherwise move down 4 bytes. On pressing up, move back 4 bytes, then check
bit b15. If it is 0, this is an Offset field, so move back another 2 bytes.
All of this will become clearer with a concrete example. A variable-sized variable-shape structure
like MENU cannot be defined using standard C initializers, but it may be defined with the help of
the built-in assembler. This example (called "Static Popup") defines exactly the same menu as the
example given with PopupDo, but saves about 200 bytes:
// Display a predefined popup menu
#define USE_TI89 // Compile for TI-89
#define USE_TI92PLUS // Compile for TI-92 Plus
#define USE_V200 // Compile for V200
#define MIN_AMS 100 // Compile for AMS 1.00 or higher
#include <tigcclib.h> // Include All Header Files
extern void menu;
asm ("menu:\n"
" .word title_text - menu\n"
" .word 0xD5\n"
" .word 9\n"
" .byte 0, 40\n"
" .word 5\n"
" .word 0\n"
" .word 0\n"
" .word 0\n"
" .long -1\n"
" main_entries:\n"
" .word MT_TEXT + 1 /* | is a comment character, */\n"
" .word option_1_text - title_text /* so use + instead */\n"
" .word MT_TEXT + 2\n"
" .word option_2_text - title_text\n"
" .word MT_TEXT + MT_CASCADE + 3\n"
" .word submenu_3_text - title_text\n"
" .word submenu_3_cascade - menu\n"
" .word MT_TEXT + MT_CASCADE + 4\n"
" .word submenu_4_text - title_text\n"
" .word submenu_4_cascade - menu\n"
" .word MT_TEXT + 5\n"
" .word option_5_text - title_text\n"
" .long -1\n"
" submenu_3_cascade:\n"
" .word MT_TEXT + 6\n"
" .word suboption_3_1_text - title_text\n"
" .word MT_TEXT + 7\n"
" .word suboption_3_2_text - title_text\n"
" .word MT_TEXT + 8\n"
" .word suboption_3_3_text - title_text\n"
" .long -1\n"
" submenu_4_cascade:\n"
" .word MT_TEXT + 9\n"
" .word suboption_4_1_text - title_text\n"
" .long -1\n"
" title_text:\n"
" .asciz \"EXAMPLE\"\n"
" option_1_text:\n"
" .asciz \"Option 1\"\n"
" option_2_text:\n"
" .asciz \"Option 2\"\n"
" submenu_3_text:\n"
" .asciz \"Submenu 3\"\n"
" submenu_4_text:\n"
" .asciz \"Submenu 4\"\n"
" option_5_text:\n"
" .asciz \"Option 5\"\n"
" suboption_3_1_text:\n"
" .asciz \"Suboption 3.1\"\n"
" suboption_3_2_text:\n"
" .asciz \"Suboption 3.2\"\n"
" suboption_3_3_text:\n"
" .asciz \"Suboption 3.3\"\n"
" suboption_4_1_text:\n"
" .asciz \"Suboption 4.1\"\n");
void _main(void)
{
MenuPopup (&menu, CENTER, CENTER, 0);
}
There is an alternative method as well. Note that the field DynSize (the tenth and eleventh byte starting from zero)
of the MENU structure contains the total length of the structure for dynamically created menus.
So you can make a menu using commands like PopupNew,
PopupAddText, etc., and then to use VTI and its debugger to pick up bytes
from the menu structure knowing the length of it. After this, you may pass a pointer to the
pre-filled sequence of bytes picked from VTI to this function. I used this approach in the
following (cryptic) example which is functionally equivalent to the example given above:
static long menu[] = {0x4800D5, 0x90028, 0x500BA, 0, -1, 0x80010008,
0x80020012, 0xC003001C, 0x30C004, 0X260040, 0X80050030, -1, 0x8006003A,
0x80070048, 0x80080056, -1, 0X80090064, -1, 0x4558414D, 0x504C4500,
0x4F707469, 0x6F6E2031, 0x4F4F70, 0x74696F6E, 0x20320053, 0x5375626D,
0x656E7520, 0x33005375, 0x626D656E, 0x75203400, 0x4F707469, 0x6F6E2035,
0x535375, 0x626F7074, 0x696F6E20, 0x332E3100, 0x5375626F, 0x7074696F,
0x6E20332E, 0x32005375, 0x626F7074, 0x696F6E20, 0x332E3300, 0x5375626F,
0x7074696F, 0x6E20342E, 0x31000000};
MenuPopup (&menu, CENTER, CENTER, 0);
Uses: ROM Call 0x421
Used by: PopupDo, Dialog
See also: PopupDo