Deprecated Objects
******************

In this chapter describes object types that have been replaced by newer ones. But they will remain part of XForms and also can be used in new programs. But there probably will be not more support for these objects than bug fixes etc.

Choice Object
=============

A choice object is an object that allows the user the choose among a number of choices. The current choice is shown in the box of the choice object. The user can either cycle through the list of choices using the middle or right mouse button or get the list as a menu using the left mouse button.

Adding Choice Objects
---------------------

To add a choice object to a form use the routine

     FL_OBJECT *fl_add_choice(int type, FL_Coord x, FL_Coord y,
                              FL_Coord w, FL_Coord h, const char *label);

It shows a box on the screen with the label to the left of it and the current choice (empty in the beginning), centered in the box.

Choice Types
------------

The following types are available:

FL_NORMAL_CHOICE
     Middle/right mouse button shortcut.

FL_NORMAL_CHOICE2
     Same as FL_NORMAL_CHOICE except drawn differently.

FL_DROPLIST_CHOICE
     Menu is activated only by pressing and releasing the mouse on the arrow.

Choice Interaction
------------------

Beside simply opening up the popup behind the choice object and selecting an entry with the left mouse button you can also use the middle and right mouse buttons and the scroll wheel: a short click with the middle mouse button selects the entry before the currently selected one, a click with the right mouse button the next. Keeping the middle or right mouse button pressed down slowly cycles trough the entries, backward or forward. The same can be down with the sroll wheel.

In both cases, whenever a choice entry is selected (even when it is the original one) the object is returned to the application program. But you can control the condition under which the choice object gets returned to the application by using the function

     int fl_set_object_return(FL_OBJECT *obj, unsigned int when)

where when can have the following values

FL_RETURN_NONE
     Never return or invoke callback.

FL_RETURN_END_CHANGED
     Return or invoke callback if end of interaction and selection of an item coincide.

FL_RETURN_CHANGED
     Return or invoke callback whenever an item is selected (this is the default).

FL_RETURN_END
     Return or invoke callback on end of an interaction.

FL_RETURN_ALWAYS
     Return (or invoke callback) whenever the interaction ends and/or an item is selected.

Other Choice Routines
---------------------

There are a number of routines to change the list of possible choices. To add a line to a choice object use

     int fl_addto_choice(FL_OBJECT *obj, const char *text);
     int fl_addto_choice_f(FL_OBJECT *obj, const char *fmt, ...);

The function returns the number of the new item. The items in the list are numbered in the order in which they were inserted. The first item has number 1, etc. The two functions differ in that the first one accepts just a simple string while for the second the text is assembled from a format string as used by printf() etc. and the following arguments.

Note that, because a choice object uses a popup, the string passed with fl_addto_choice() cann also contain some additional information not directly shown in the entries text. E.g., you can create several entries as once if the string you pass to fl_addto_choice() contains '|' characters - these aren't shown but instead are treated as separators between the strings for the entries. Some extra control sequences, starting with the character '%' can also be embedded (see Creating XPopups), thus a literal '%' in a string must be escaped by doubling it.

To delete a line use:

     void fl_delete_choice(FL_OBJECT *obj, int line);

Whenever the application program wants to clear the complete list of choices it should use the routine

     void fl_clear_choice(FL_OBJECT *obj)

One can also replace a line using

     void fl_replace_choice(FL_OBJECT *obj, int line, const char *text);
     void fl_replace_choice(FL_OBJECT *obj, int line, const char *fmt, ...);

(The second function assembles the new text from a format string as used for printf() etc. and the following arguments.)

To obtain the currently selected item in the choice object use the call

     int fl_get_choice(FL_OBJECT *obj);

The function returns the number of the current choice (0 if there is no choice).

You can also obtain the text of the currently selected choice item using the call

     const char *fl_get_choice_text(FL_OBJECT *obj);

NULL is returned when there is no current choice.

To obtain the text of an arbitrary choice item, use the following routine

     const char *fl_get_choice_item_text(FL_OBJECT *obj, int n);

To obtain the total number of choice items, use the following function

     int fl_get_choice_maxitems(FL_OBJECT *obj);

One can set various attributes of an item using the following routine

     void fl_set_choice_item_mode(FL_OBJECT *obj, int numb, int mode);

Here mode is the same as that used for menu objects (see above). See also XPopup, for details.

To find about those settings use

     int fl_get_choice_item_mode(FL_OBJECT *obj, int numb);

You can use the follow routine to populate a choice object at once, including mode and shortcut, by using

     int fl_set_choice_entries(FL_OBJECT *obj, FL_PUP_ENTRY *entries);

where entries is a pointer to a FL_PUP_ENTRY structure (terminated by a NULL text field) as already described above for the function fl_set_menu_entries(). Also see XPopup, for more details. Please note that for choice objects no nested entries are permitted and the item callback functions are ignored. The function returns the number of items added to the choice object.

Finally, the application program can set the currently selected entry of the choice using a call of

     void fl_set_choice(FL_OBJECT *obj, int line);
     void fl_set_choice_text(FL_OBJECT *obj, const char *txt)
     void fl_set_choice_text_f(FL_OBJECT *obj, const char *fmt, ...)

where txt (for fl_set_choice_text() or the text resulting from the expansion of the printf()-compatible format string and the following arguments for fl_set_choice_text_f() must must be the text of exactly one of the choice items. For example, after the following choice is created

     fl_addto_choice(obj,"item1|item2|item3");

You can select the second item by using any of the following lines

     fl_set_choice(obj, 2);
     fl_set_choice_text(obj, "item2");
     fl_set_choice_text_f(obj, "item%d", 2 );

Choice Attributes
-----------------

Don't use FL_NO_BOX as the boxtype for a choice object.

The first color argument (col1 to fl_set_object_color() controls the color of the box and the second (col2) the color of the text in the box.

The current choice by default is shown centered in the box. To change the alignment of the choice text in the box, use the following routine

     void fl_set_choice_align(FL_OBJECT *obj, int align);

To set the font size used inside the choice object use

     void fl_set_choice_fontsize(FL_OBJECT *obj, int size);

To set the font style used inside the choice object use

     void fl_set_choice_fontstyle(FL_OBJECT *obj, int style);

Note that the above functions only change the font inside the choice object, not the font used in the popup. To change the font used in the popup, use the XPopup functions fl_setpup_default_fontsize() and fl_setpup_default_fontstyle(). Note that these functions influence the font settings of all popups! See Label Attributes and Fonts, for details on font sizes and styles.

Normally the pop-up shown for the choice objects will be displayed at the current mouse position or, for those of type FL_DROPLIST_CHOICE, directly below the choice object. This can be modified by a call of the function

     int fl_set_choice_align_bottom(GL_OBJECT *obj, int flag);

If flag is 0 the normal behaviour is used, but when flag is 1 the popup will be displayed with its lower right hand corner at the current mouse position or, for objects of type FL_DROPLIST_CHOICE above the choise object. The function returns the previously set value for flag.

Remarks
-------

See choice.c for an example of the use of choice objects.

Menu Object
===========

Also menus can be added to forms. These menus can be used to let the user choose from many different possibilities. Each menu object has a box with a label in it in the form. Whenever the user presses the mouse inside the box (or moves the mouse on top of the box) a pop-up menu appears. The user can then make a selection from the menu.

Adding Menu Objects
-------------------

To add a menu to a form use the routine

     FL_OBJECT *fl_add_menu(int type, FL_Coord x, FL_Coord y,
                            FL_Coord w, FL_Coord h, const char *label);

It shows a box on the screen with the label centered in it.

Menu Types
----------

The following types are available:

FL_PUSH_MENU
     The menu appears when the user presses a mouse button on it.

FL_PULLDOWN_MENU
     The menu appears when the user presses a mouse button on it.

FL_TOUCH_MENU
     The menu appears when the user move the mouse inside it.

FL_PUSH_MENU and FL_PULLDOWN_MENU behave rather similar. When you click on a FL_PUSH_MENU per default a pop-up window gets opened on top of the FL_PUSH_MENU menu's box that has a label at the top, indicating the currently selected menu item. The pop-up window stays open until you either select an item or press a mouse button somewhere outside the pop-up window.

When you click on FL_PULLDOWN_MENU also a pop-up window is shown, but directly below the menu's box. This pop-up window has no label and it only stays open until you release the mouse button.

FL_PUSH_MENU and FL_PULLDOWN_MENU can be made even more similar by using the fl_set_menu_notitle() function (see below). This changes it's properties so that the pop-up window also appears below the menu's box and that no label is shown in the pop-up window. The only remaining difference then is that a FL_PUSH_MENU only gets closed when a menu item is selected or the user presses the mouse outside of the pop-up window while a FL_PULLDOWN_MENU also gets closed when the mouse button is released.

Menu Interaction
----------------

When the menu appears the user can make a selection using the left mouse button or make no selection by clicking outside the menu (or by simply releasing the mouse button in case of a FL_PULLDOWN_MENU type menu. Normally when he makes a selection the menu object is returned by the interaction routines.

You can control the condition under which the menu object gets returned to the application by using the function

     int fl_set_object_return(FL_OBJECT *obj, unsigned int when)

where when can have the following values

FL_RETURN_NONE
     Never return the object or invoke its callback.

FL_RETURN_END_CHANGED
     Return or invoke callback if end of interaction and selection of an item coincide (this is the default for all menu objects except those of type FL_TOUCH_MENU).

FL_RETURN_CHANGED
     Return or invoke callback whenever an item is selected (this is the default for all menu objects of type FL_TOUCH_MENU).

FL_RETURN_END
     Return or invoke callback on end of an interaction.

FL_RETURN_ALWAYS
     Return (or invoke callback) whenever the interaction ends and/or an item is selected.

Other Menu Routines
-------------------

There are two ways to populate a menu, i.e., add items. The first one is a bit more complex but allows for more flexibility, e.g., later adding and removing items, associating callbacks with individual items etc. For the more simple (and in many cases sufficient) method see the function fl_set_menu_entries().

To set the actual menu for a menu object, use the routine

     void fl_set_menu(FL_OBJECT *obj, const char *menustr, ...);

menustr describes the menu in the form used by XPopups (see XPopup). In the simplest case it just contains the texts for the menu items, separated by a bar ('|'), e.g., "First|Second|Third". But it's also possible to employ special tags (see Creating XPopups) that can be used to indicate special attributes (radio, toggle and greyed-out, for example). For this usage the unspecified arguments (the ... in the function call) can be used t add neceassary information. Whenever the user selects a menu item, a pointer to the menu object it belongs to is returned to the application program.

Please note that if you call fl_set_menu() on a menu that already contains items the existing items are replaced by the new ones - the function calls fl_clear_menu() internally before the new items are added.

If you explicitely assign a menu item ID to a menu, using the special tag %x, it is your responsibility to make sure that this ID isn't already used by a different menu item in the same menu. Failure to do so may make it impossible to use the menu properly. All functions working on items expect the menu item ID as one of their arguments. Also note that only values that fit into a char can be used, so the range is restricted to the interval [-128, 127] on most machines with a signed char type and to [0, 255] on those with an unsigned char type. For portability reasons it's thus to be recommended to restrict the range to [0, 127].

In case you don't set menu item IDs they are assigned automatically with the first item obtaining the menu item ID 1, the next 2 etc., i.e., it directly reflects the position of the item in the menu.

It is also possible to add menu items to an existing menu using a call of

     int fl_addto_menu(FL_OBJECT *obj, const char *menustr, ...);

where menustr is a string of the same form as used in fl_set_menu() (you can add one or more new menu items this way).

Also routines exist to delete a particular menu item or change it:

     void fl_delete_menu_item(FL_OBJECT *obj, int miid);
     void fl_replace_menu_item(FL_OBJECT *obj, int miid,
                                const char *menustr, ...);

miid is the menu item ID. menustr must be a string as used in fl_set_menu() with the only difference that only a single menu item can be specified.

Please note: when deleting a menu item all other items keep their menu item IDs. The menu item ID of the deleted menu item isn't re-used when new items are added later. Instead for each menu an internal counter exists that gets incremented for each menu item added and which value is used for the menu item ID unless one is explicitely assigned to the menu item. The counter oly gets reset to 1 when the menu is cleared used fl_clear_menu().

The menu item ID of a menu item changed by using fl_replace_menu_item() does not change unless the library is explicitely asked to via %x in menustr.

For most applications, the following routine may be easier to use at the expense of somewhat restrictive value a menu item can have as well as a loss of the ability to delete menu items or associate callbacks with menu items.

     int fl_set_menu_entries(FL_OBJECT *obj, FL_PUP_ENTRY *ent);

where ent is a pointer to an array of structure of the following type, terminated by an element, where at least the text member is a NULL pointer:

     typedef struct {
         const char *text;
         FL_PUP_CB callback;
         const char *shortcut;
         int mode;
     } FL_PUP_ENTRY;

The meaning of each member is explained in Section 21.3. For menus, item callback function can be NULL if the menu callback handles the interaction results. See demo program popup.c for an example use of fl_set_menu_entries().

The function fl_set_menu_entries() works by creating and associating a popup menu with the menu object. The popup ID is returned by the function. Whenever the function is called, the old popup associated with the object (if one exists) is freed and a new one is created. Although you can manipulate the menu either through the menu API (but adding and removing menu items is not supported for menus created this way ) or popup API, the application should not free the popup directly and use fl_clear_menu() instead.

To clear the whole menu use

     void fl_clear_menu(FL_OBJECT *obj);

To find the menu item selected by the user use

     int fl_get_menu(FL_OBJECT *obj);

The the function returns the menu item ID. In the simplest possible case this is just the position of the menu item (starting at 1). This stops to be true when either IDs have been explicitely assigned to items or items have been deleted. In that case the following rules apply:

 1. A menu item ID may have been assigned to a menu item using %xn in the string for the text of the menu item.

 2. Menu items can get associated with a callback function that is executed when the menu item is selected. The callback function is of type FL_PUP_CB and receives the menu item ID of the selected menu. If such a callback is set for a menu item the return value of fl_get_menu() is the return value of this function instead of the menu item ID that would have been returned otherwise.

To obtain the text of any item, use the following routine

     const char *fl_get_menu_item_text(FL_OBJECT *obj, int miid);

where miid is the menu item ID. If n isn't a valid menu iem ID item NULL is returned.

To obtain the text of the selected enu item use

     const char *fl_get_menu_text(FL_OBJECT *obj);

To obtain the total number of menu items, use the function

     int fl_get_menu_maxitems(FL_OBJECT *obj);

One can change the appearance of different menu items. In particular, it is sometimes desirable to make grey-out menu items and make them unselectable or to put boxes with and without checkmarks in front of them. This can be done using the routine:

     void fl_set_menu_item_mode(FL_OBJECT *obj, int miid, unsigned mode);

miid is the menu index ID of the memu item you want to change. mode represents the special properties you want to apply to the chosen item. You can specify more than one at a time by adding or bitwise OR-ing these values together. For this parameter, the following symbolic constants exist:

FL_PUP_NONE
     No special display characteristic, the default.

FL_PUP_BOX
     "Binary" entry, i.e., an entry that stands for a choice that can be switched on and off. Displayed with an unchecked box to the left.

FL_PUP_RADIO
     "Radio" item belonging to a group, so that gets automatically switched off when another item of the group is selected. Displayed with a diamoned-shaped box at the left.

FL_PUP_GREY
     To be OR-ed with one of the above to make that item appear greyed-out and disable it (i.e., not selectable anymore).

FL_PUP_CHECK
     To be OR-ed with one of FL_PUP_BOX and FL_PUP_RADIO to make the box to the left appear checked or pushed.

There is also a routine that can be used to obtain the current mode of an item after interaction, mostly useful for toggle or radio items:

     unsigned int fl_get_menu_item_mode(FL_OBJECT *obj, int miid);

While a callback associated with a menu entry can be set when it is created it can also set later on or be changed. For this use the function

     FL_PUP_CB fl_set_menu_item_callback(FL_OBJECT *ob,
                                         int numb, FL_PUP_CB cb);

where numb is the menu entries ID and cb is the callback function of type FL_PUP_CB (or NULL to disable a callback). The return value is a pointer to the previously used callback function (or NULL).

It is often useful to define keyboard shortcuts for particular menu items. For example, it would be nice to have <Alt>s behave like selecting "Save" from a menu. This can be done using the following routine:

     void fl_set_menu_item_shortcut(FL_OBJECT *obj, int miid,
                                    const char *str);

miid is the menu item ID of the menu item under consideration. str contains the shortcut for the item. (Actually, it can contain more shortcuts for the same item.) See Shortcuts, for more information about shortcuts.

Finally there is the routine:

     void fl_show_menu_symbol(FL_OBJECT *obj, int yes_no);

With this routine you can indicate whether to show a menu symbol at the right of the menu label. By default no symbol is shown.

Menu Attributes
---------------

Any boxtype can be used for a menu except for those of type FL_PULLDOWN_MENU, for which FL_NO_BOX should not be used.

Using the functiond

The first color argument (col1) to fl_set_object_color() controls the color of the menu's box when not open and the second (col2) is the color when the menu is shown.

To change the font style and size used in the popup menus (not the menu label), use the following routines

     void fl_setpup_default_fontstyle(int style);
     void fl_setpup_default_fontsize(int size);

These settings apply to all menus at once.

If desired, you can attach an external popup to a menu object via the following routine

     void fl_set_menu_popup(FL_OBJECT *obj, int pupID);

where pupID is the ID returned by fl_newpup() or fl_defpup(). See XPopup, for more details on popup creation.

For a menu created this way only fl_get_menu() and fl_get_menu_text() work as expected. Other services such as mode setting and query etc. should be done via the popup routines.

To obtain the popup ID associated with a menu, use the following routine

     int fl_get_menu_popup(FL_OBJECT *obj);

The function returns the popup ID if the menu was created using fl_set_menu_popup() or fl_set_menu_entries(), otherwise it returns -1.

The callback associated with a menu

Normally in the popup opened for a menu a title is shown. This can be switched off (and back on again by using the function

     fl_set_menu_notitle(FL_OBJECT *obj, int off);

Remarks
-------

See menu.c for an example of the use of menus. You can also use FL_MENU_BUTTON to initiate a callback and use an XPopup directly within the callback. See pup.c for an example of this approach.

XPopup
======

XPopup is not really an object class, but because it is used by menu and choice objects and can function stand-alone, it is documented here.

XPopups are simple transient windows that show a number of choices the user can click on to select the desired option.

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 */
     };

XPopup Interaction
------------------

To select an item, move the mouse to the item to be selected while keeping the mouse button pressed down and then release the mouse button on top of the item to be selected. If you don't want to make a selection release the mouse button somewhere outside the area of the XPopup.

If you have a "hanging" XPopup, i.e., a XPopup that's open even though the mouse button isn't pressed anymore you can select by clicking on an item or use the cursor Up and Down keys to navigate through the items and select by pressing the <Return> key. The <Home> and <End> keys allow you to jump to the first or last selectable item, respectively. Use <Esc> to close the popup without selecting an item.

It is also possible to use convenience functions to bind keyboard keys to items (the "hotkeys") instead of using %s with fl_defpup():

     void fl_setpup_shortcut(int popup_id, int item_val,
                             const char *hotkeys);

where item_val is the value associated with the item (either due to its position or set with %x) and hotkeys is a string specifying all the hotkey combinations. See Shortcuts, for details. Briefly, within that string # and ^ denote the <Alt> and <Ctrl> keys, respectively. &n with n = 1, 2 etc. can be used to denote the function key numbered n. Thus if hotkeys is set to "#a^A, both <Ctrl>A and <Alt>A are bound to the item. One additional property of the hotkey is the underlining of corresponding letters in the item string. Again, only the first key in the hotkey string is used. Therefore, the hotkey strings "Cc", "#C" and "^C" will result in the character C in the item string "A Choice" being underlined, while the the hotkey strings "cC" and "#c" will not since there's no c in the item string. There is a limit of maximum 8 shortcut keys.

Two convenience functions are available to set the callback functions for items of a XPopup and the XPopup as a whole (called whenever a selection is made):

     typedef int (*FL_PUP_CB)(int);
     FL_PUP_CB fl_setpup_itemcb(int popup_id, int item_val, FL_PUP_CB cb);
     FL_PUP_CB fl_setpup_menucb(int popup_id, FL_PUP_CB cb);

These functions thus allow to change the popup and item callback functions set at creation of the popup with %F and %f. As usual, popup_id is the ID of the XPopup, item_val the value associated with the item (position or value set via %x), and cb is the address of the callback function.

Please note that Xpopup objects are a bit special in XForms. Normal objects get returned by e.g., fl_do_forms() (or an associated callback gets invoked). But since Xpopup objects are meant to be sub-objects of other objects (like FL_CHOICE and L_MENU objects) and don't get invoked directly by a call of e.g., fl_do_forms() but instead by a call of fl_dopup() they can't get returned to the application. Instead the caller of fl_dopup() (normally some internal function of a FL_CHOICE or FL_MENU object) has to deal with the return value.

Furthermore, also callback functions can be set that get invoked whenever an item in the XPopup is entered or left, even without a selection being made. The following functions can be used to register these item enter/leave callbacks:

     typedef void (*FL_PUP_ENTERCB)(int item_val, void *data);
     typedef void (*FL_PUP_LEAVECB)(int item_val, void *data);

     FL_PUP_ENTERCB fl_setpup_entercb(int popup_id,
                                      FL_PUP_ENTERCB cb, void *data);
     FL_PUP_LEAVECB fl_setpup_leavecb(int popup_id,
                                      FL_PUP_LEAVECB cb, void *data);

The function cb will be called when the mouse enters or leaves an (non-disabled) item of the XPopup popup_id. Two parameters are passed to the callback function. The first parameter is the item number enter/leave applies to and the second parameter is a data pointer. To remove an enter/leave callback, call the functions with the callback function argument cb set to NULL.

There is also a function to associate a XPopup item with a sub-XPopup

     void fl_setpup_submenu(int popup_id, int item_val, int subpopup_id);

If a sub-XPopup is associated with item item_val that item can't be selected anymore (releasing the mouse button on this item makes fl_dopup() return -1 but instead a new XPopup is opened beside the item and you can now make selections within this sub-XPopup. 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.

Other XPopup Routines
---------------------

Note that most of the setpup/getpup routines are recursive in nature and the function will search the menu and all its submenus for the item.

It is possible to modify the display characteristics of a given XPopup item after its creation using the following routine

     void fl_setpup_mode(int popup_id, int item_val, unsigned mode);

As usual popup_id is the XPopup ID as returned by fl_newpup() or fl_defpup() and item_val the value of the item. mode is one of FL PUP NONE, FL PUP GREY, FL PUP BOX or FL PUP RADIO (one of the later two can be bitwise ORed with FL_PUP_CHECK, as already discussed above.

To obtain the mode of a particular menu item, use the following routine

     unsigned int fl_getpup_mode(int popup_id, int item_val)

This comes in handy to check if a binary or radio item is set

     if (fl_getpup_mode(popupd, item_val) & FL_PUP_CHECK)
         /* item is set */

There exists also a routine that can be used to obtain an items text

     const char *fl_getpup_text(int popup_id, int item_val);

In some situations, especially when the popup is activated by non-pointer events (e.g., as a result of a keyboard shortcut), the default placement of popups based on mouse location might not be adequate or appropriate, thus XPopup provides the following routine to override the default placement

     void fl_setpup_position(int x, int y);

where x and y specify the location where the top-left corner of the popup should be. x and y must be given in screen coordinates (i.e., relative to the root window) with the origin at the top-left corner of the screen. This routine should be used immediately before invoking fl_dopup(), the position is not remembered afterwards.

If x or y is negative, the absolute value is taken to mean the desired location relative to the right or bottom corner of the popup (not the screen!).

Another function exists for controlling the positon of the popup. When the fuunction

     void fl_setpup_align_bottom(void);

then the pop-up will appear with its lower right hand corner aligned aligned with the mouse position or, if also fl_setpup_position() is active, the postion set this way will be interpreted to mean the lower right hand position of the popu-up.

A radio item in a group can be initialized to be in "pushed" state by using %R. But you can also switch a such a radio item to "pushed state also programmatically using

     void fl_setpup_selection(int popup_id, int item_val);

Of course, other radio items of the XPopup belonging to the same group are reset to "unpushed" state.

To obtain the number of items in a popup, use the following routine

     int fl_getpup_items(int popup_id)

XPopup Attributes
-----------------

The title of a XPopup can be set using the functions

     void fl_setpup_title(int popup_id, const char *title);
     void fl_setpup_title_f(int popup_id, const char *fmt, ...);

They only differ in the way the new title is passed to the function, the first one accepts a simple string while the second expects a format string as used for printf() etc., followed by the appropriate number of (unspecified) arguments.

Use the following routines to modify the default popup font style, font size and border width:

     int fl_setpup_default_fontsize(int size);
     int fl_setpup_default_fontstyle(int style);
     int fl_setpup_default_bw(int bw);

The functions return the old size, style or border width value, respectively.

All XPopups by default use a right arrow cursor. To change the default cursor, use

     Cursor fl_setpup_default_cursor(int cursor);

where you can use for cursor any of the standard cursors defined in <X11/cursorfont.h> like XC_watch etc. The function returns the previously cursor.

To change the cursor of a particular XPopup only , use the following routine

     Cursor fl_setpup_cursor(int popup_id, int cursor);

For example, after the following sequence,

     id = fl_defpup(win, "item1|item2");
     fl_setpup_cursor(id, XC_hand2);

the popup with ID id will use a "hand" instead of the default arrow cursor.

In versions before 1.0.91 XPopups were drawn with a heavy shadow around the box. Drawing of this shadow could be controlled via

     void fl_setpup_shadow(int popup_id, int yes_no);

Nowadays this function still exists for backward-compatibility but does nothing.

The appearance of XPopups (and their associated sub-popups) can be change by the following routines:

     void fl_setpup_bw(int popup_id, int bw);
     void fl_setpup_softedge(int pupup_id, int yes_no);

The first sets the border width for a XPopup. Calling fl_setpup_softedge() with a true argument for yes_no has the same effect as using a negative border width while using a false (0) argument is equivalent to using a positive one (so this function isn't very useful).

The background color and text color of a popup can be changed using

     void fl_setpup_default_color(FL_COLOR bgcolor, FL_COLOR tcolor);

By default, the background color bgcolor is FL_COL1 and the text color tcolor is FL_BLACK.

For "binary" or radio items, that have check box associated with them, the "checked" or "pushed" color (default is FL_BLUE) can be changed with the following routine

     void fl_setpup_default_checkcolor(FL_COLOR checkcolor);

There is by default a limit of 32 XPopups per process. To enlarge the number of XPopups allowed, use the following routine

     int fl_setpup_maxpups(int new_max);

The function returns the previous limit.

It is possible to use XPopups as a message facility using the following routines

     void fl_showpup(int popup_id);
     void fl_hidepup(int popup_id);

No interaction takes place with a XPopup shown by fl_showpup() and it can only be removed from the screen programmatically via fl_hidepup().

Remarks
-------

Take care to make sure all items, including the items on submenus, of a XPopup have unique values and are positive.

XPopups are used indirectly in the demo programs menu.c, boxtype.c, choice.c and others. For a direct pop-up demo see popup.c.