| MenuPopup | Function (ROM Call 0x3B)

menus.h

unsigned short MenuPopup (const void *MenuPtr, short x, short y, unsigned short start_option);

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