Creating XPopups (XForms (Forms Library) - Version 1.2 (Rev. 4) A Graphical User Interface Toolkit for X)

Next: XPopup Interaction, Up: XPopup [Contents][Index]

#### 23.3.1 Creating XPopups

To define a new popup, use the following routines

    int fl_newpup(Window parent);
    int fl_defpup(Window parent, const char *str, ...);

Both functions allocate and initialize a new popup menu and return the XPopup identifier (or -1 on failure). `fl_defpup()` in addition accepts a pointer `str` to the texts for menu items (optionally also some more arguments, see below). More than one item can be specified by using a vertical bar (`|`) between the items, e.g., `"foo|bar"` adds two menu items. The `parent` parameter specifies the window to which the XPopup belongs. In a situation where the XPopup is used inside an object callback `FL_ObjWin(obj)` will do. If `parent` is `None` the root window will be used.

Calling `fl_defpup()` with the `str` argument set to `NULL` is equivalent to calling `fl_newpup()`.

It is possible to specify XPopup and item properties, such as shortcuts, callbacks etc., together with the items texts using a format string system similar as used for e.g., `oprint(3)`. If XPopup or item properties require arguments, they must be passed to `fl_defpup()` following the `str` argument.

The following item properties are supported:

`%t`

  Marks the item text as the XPopup title string.

`%F`

  Binds a callback function to the XPopup as a whole that is called for every selection made from this XPopup. You must specify the function to be invoked in the parameters following `str`. The value of the selected item is passed as the only argument to the invoked callback function. The callback function must return a non-negative integer. If such a callback function has been registered for a XPopup and you select its third item, in the simplest case 3 will be passed as a parameter to the callback function (more complicated situations would involve that the item had been assigned a different value. e.g., using `%x`, see below, or that there’s also a callback bound to the item itself, in which case the global XPopup callback would receive the return value of the items callback function).

`%f`

  Binds a callback to this particular item which is invoked if the item is selected. The routine must be supplied in the parameters following `str`. It has to return a non-negative integer. The value of the selected item is passed as a parameter to this function. If you have also bound the entire XPopup to a callback function via `%F`, then the function specified via `%f` is called first with the items value and its return value (if larger then `0` is then passed as the parameter to to the function bound to the whole XPopup (as set via `%F`).

`%i`

  Disables and greys-out the item. `%d` can be used instead of `%i`.

`%l`

  Adds a line under the current entry. This is useful in providing visual clues to groups of entries

`%m`

  Whenever this item is selected another (already defined) XPopup is bound to the item so that the sub-XPopup is opened when the user moves the mouse onto the item, This can be used to create cascading menus. The identifier of the sub-XPopup to be shown must be provided in the arguments following `str`. It is the programmers responsibility to make sure that the item values of the sub-XPopup don’t clash with those of the higher-level XPopup or it may be impossible to determine which item was selected.

`%h`

  Specify a "hotkeys" that can be used to select this item. Hotkeys must be given in the arguments following `str` as a pointer to a string. Use `#` to specify that a key must be pressed together with the `<Alt>` key, `^` for simultaneous pressing of `<Ctrl>` and `&n` for the function key `Fn`.

  `%s` can be used instead of `%h`.

`%xn`

  Assigns a numerical value to this item. This value must be positive. This new value overrides the default position-based value assigned to this item. Different from most other flags, the value `n` must be entered as part of the text string (i.e., do not try to use the arguments following `str` to specify this value!) and must be number larger than 0. It is the programmers responsibility to make sure that the items value does not clash with those of other items of the XPopup or determining which item was selected may be impossible.

`%b`

  Indicates this item is "binary item" (toggle), currently in off state. When displayed, binary items will be drawn with a small box to the left. See also `FL_PUP_BOX`.

`%B`

  Same as `%b` except that it also signifies that this item is in on or "true" state and consequently is drawn with a checked box on the left. See also `FL_PUP_BOX | FL_PUP_CHECK`.

`%rg`

  Specifies this menu item is a "radio item" belonging to group with number `g`, currently not being selected. The group number `g`, that must be part of the string directly following `%r` (and not specified via the arguments following the string), must be a non-zero, positive number. Radio items are drawn with a small diamond box to the left (empty while not active). See also `FL_PUP_RADIO`.

`%Rg`

  Same as `%rg` except that it also sets the state of the radio item as selected or "pushed", the item is drawn with a filled diamond box to the left. See also `fl_setpup_selection()`. See also `FL_PUP_RADIO | FL_PUP_CHECK`.

`%%`

  Use this if you need a `%` character in the string.

`<Ctrl>H (`\010`)`

  Same as `%l` except that the character must precede the item label, i.e., use `"\010Abc"` and not `"Abc\010"`.

Due to the use of variable arguments error checking can only be minimal. Also note that if `%x` is used to specify a value that happens to be identical to a position-based value, the result is unpredictable when subsequent references to these items are made. There is currently a limit of `FL_MAXPUPI` (64) items per popup.

Tabs characters (`'\t'`) can be embedded in the item string to align different fields.

You can add more items to an existing XPopup using the following routine

    int fl_addtopup(int popup_id, const char *str, ...);

where `popup_id` is the value returned by `fl_newpup()` or `fl_defpup()` for the XPopup. Again, `str` can contain information for one or more new items, including the special sequences described earlier. The function returns -1 if invalid arguments are detected (as far as possible for a function with a variable number of arguments).

To display a popup, use

    int fl_dopup(int popup_id);

This function displays the specified XPopup until the user makes a selection or clicks somewhere outside of the XPopups box. The value returned is the value of the item selected or -1 if no item (or a disabled one) was selected. However, if there is a function bound to the XPopup as a whole or to the selected item itself, this function is invoked with the item value as the argument and the value returned by `fl_dopup()` is then the return value of this function. If a callback function for both the selected item and the XPopup as a whole exists, the callback function for the item is called first with the item value as the argument and then the return value of this item specific callback function is passed to the XPopups callback function. `fl_dopup()` then finally returns the return value of this second function call.

Normally a XPopup get opened when the left mouse button has been pressed down and get closed again when the left mouse button is released. But there are a number of ways to achieve a "hanging" XPopup, i.e., that the XPopup that says open, even though the left mouse button isn’t pressed down anymore. This happens e.g., when the user releases the mouse button in the title area of the XPopup or when the XPopup was opened via a keyboard shortcut. In that case it’s also possible to navigate through the items and select via the keyboard.

A typical procedure may look as follows:

    int item3_cb(int n) {
         return n + 7;
    }

    /* define the menu */
    int menu = fl_newpup(parent);
    fl_addtopup(menu, "Title %t|Item1%rg1|Item2%Rg1|Item3%x10%f|Item4",
                item3_cb);

    switch (fl_dopup(menu)) {
        case 1:   /* item1 is selected */
            /* handle it */
            break;

        case 2:
            /* handle it */
            break;

        case 4:
            /* handle it */

        case 17:
            /* item 3 call back has been executed */
    }

Here callback function `item3_cb()` is bound to the third item and this item has been assigned the number 10. Thus, when it is selected `fl_dopup()` does not return 3 or 10. Instead the callback function `item3_cb()` is invoked with 10 as its argument. And this function in turn returns `10 + 7`, which is the value `fl_dopup()` finally returns.

Note also that items 1 and 2 both are radio items, belonging to the same group (numbered 1). Item 2 is currently the active item of this group.

Sometimes it might be necessary to obtain the popup ID inside an item callback function. To this end, the following function available:

    int fl_current_pup(void);

If no popup is active, the function returns -1. Until all callback functions have been run the function returns the ID of the XPopup the items belong to.

To destroy a popup menu and release all memory used, use the following routine

    void fl_freepup(int popup_id);

For most applications, the following simplified API may be easier to use

    void fl_setpup_entries(int popup_id, FL_PUP_ENTRIES *entries);

where `popup_id` is the popup ID returned by `fl_newpup()` or `fl_defpup()` and `entries` is an array of the following structures

    typedef struct {
        const char * item_text; /* item text label */
        FL_PUP_CB    callback;  /* item callback routine */
        const char * shortcut;  /* shortcut for this item */
        unsigned int mode;      /* item mode */
    } FL_PUP_ENTRY;

The meaning of each member of the structure is as follows:

`text`

  This is the text of a XPopup item. If text is `NULL`, it signifies the end of this popup menu. The first letter of the text string may have a special meaning if it is one of the following:

  `'/'`

    This indicates the beginning of a sub-popup, starting with the next item and ending with the next item with `text` being `NULL`.

  `'_'`

    Indicates that a line should be drawn below this item (typically as a visual reminder of logical groupings of items).

`callback`

  This is the callback function that will be called when this particular item is selected by the user. `fl_dopup()` returns the value returned by this callback. If the callback is `NULL`, the item number will be returned directly by `fl_dopup()`.

`shortcut`

  Specifies the keyboard shortcut.

`mode`

  Specifies special attributes of this item. This can be one or a combination by bitwise OR of one of the following:

  `FL PUP NONE`

    No special characteristics, the default.

  `FL_PUP_GREY`

    Item is greyed-out an can’t be selected. Trying to select it results in `fl_dopup()` returning -1.

  `FL_PUP_BOX`

    "Binary item", drawn with a little box to its left.

  `FL_PUP_RADIO`

    "Radio item", drawn with a little diamond-shaped box to its left. All radio items of the XPopup belong to the same group.

  `FL_PUP_CHECK`

    OR this value with `FL_PUP_BOX` or `FL_PUP_RADIO` to have the box to the left drawn as checked or pushed.

With this simplified API, popup item values start from 1 and are the index in the entries array for the item plus 1. For example, the third element (with index 2) of the array of structure has an item value of 3. Please note that also elements of the array that end a submenu and thus don’t appear as visible items in the XPopup get counted. This way, the application can relate the value returned by fl_dopup() to the array easily. See demo program `popup.c` for an example use of the API.

To illustrate the usage of `fl_setpup_entries()`, Fig 21.2 shows the popup created with the array of structures defined in the following code example:

    FL_PUP_ENTRY entries[ ] = {
       {"Top item1",  callback},      /* item number 1 */
       {"Top item2",  callback},
       {"Top item3",  callback},
       {"/Top item4", callback},
         {"Sub1 item1",  callback},   /* item number 5 */
         {"Sub1 item2",  callback},
         {"Sub1 item3",  callback},
         {"Sub1 item4",  callback},
         {"/Sub1 item5", callback},
           {"Sub2 item1",  callback}, /* item number 10 */
           {"Sub2 item2",  callback},
           {"Sub2 item3",  callback},
           {NULL,         NULL     }, /* end of level2, item number 13 */
         {NULL,           NULL   },   /* end of sublevel1, item nuber 14 */
       {"Top item5",  callback},      /* item number 15 */
       {NULL,         NULL    }       /* end of popup */
    };

Next: XPopup Interaction, Up: XPopup [Contents][Index]