Next: Popup Interaction, Up: Part III Popups [Contents][Index]
There are two ways to create and populate a popup with entries. The first method, that allows more fine-grained control consists of first generating a popup and then adding entries. Using this method all the properties of entries can be set immediately. The second method, to be discussed later, is simpler and may be sufficient for many applications, and internally uses the first method.
To define a new popup using the more general interface call
FL_POPUP *fl_popup_add(Window win, const char *title);
The function returns the address of the new popup on success and
NULL
on failure. win
is the window of a parent object
(use FL_ObjWin()
to find out about it). You can also use
fl_root
for the root window, with None
having the
same effect . title
is an optional string that gets shown at
the top of the popup in a framed box. If not wanted pass an empty
string or NULL
. The function returns a pointer to a new popup
or NULL
on failure.
The title may contain embedded newline characters, this allows to create titles that span more than one line.)
There is no built-in limit to the number of popups that can be created.
Once you have popup you may add one or more entries by using
FL_POPUP_ENTRY *fl_popup_add_entries(FL_POPUP *popup, const char *entries, ...);
On success the return value is the address of the first entry created
and NULL
on failure. The first argument, entries
, is a
pointer to the popup the new entry (or entries) is added to. The
second argument, entries
, encodes information about the entries
to add. In the most simple case it consists just of the entries texts,
separated by |
characters, e.g., "Item 1|Item 2|Item 3"
. This would create three simple entries in the popup with labels
"Item 1"
, "Item 2"
and "Item 3"
.
The entries
string may contain newline characters which allows
to create entries that span more than a single line.
There’s no built-in limit to the number of entries than be added to a
popup. fl_popup_add_entries()
can be called repeatedly to
append further entries to a popup.
It often is necessary to have more complex entries. E.g., one may
want to have keyboard shortcuts for entries, which are shown on the
right hand side of an entry, one may want to have sub-popups or set
callbacks etc. This can be achieved by embedding special character
sequences within the string describing the entries and passing further
arguments to the function, similar to the use of a format string in
e.g., printf(3)
. All special sequences start with a %
.
The following sequences are recognized:
%x
Set a value of type long int
that’s passed to all callback
routines for the entry. The value must be given in the arguments
following the entries
string.
%u
Set a user_void
pointer that’s passed to all callbacks of the
entry. The pointer must be specified in the arguments following the
entries
string.
%f
Set a callback function that gets called when the entry is selected. The function is of type
int callback(FL_POPUP_RETURN *r);
Information about the entry etc. gets passed to the callback function
via the FL_POPUP_RETURN
structure (see below) and the return
value of the function can be used to keep the selection being reported
back to the caller of fl_popup_do()
by returning a value
of FL_IGNORE
(-1). The functions address must be given in the
arguments following the entries
string.
%E
Set a callback routine that gets called each time the mouse enters the
entry (as long as the entry isn’t disabled or hidden). The type of the
function is the same as that of the callback function for the
selection of the item but it’s return value is never used. The
functions address must be given in the arguments following the
entries
string.
%L
Set a callback routine that gets called each time the mouse leaves the
entry. The type of the function is the same as that of the callback
function for the selection of the entry but it’s return value is never
used. The functions address must be given in the arguments following
the entries
string.
%m
When this is specified a sub-popup gets opened when the mouse enters the
entry (the entry itself thus can’t be selected). The sub-popup to be
opened must be an already existing popup and its address must be given
in the arguments following the entries
string. A triangle will
be drawn on the right of the entry to indicate that it’s an entry
for a sub-popup.
Mutually exclusive with %t
, %T
, %r
, %R
and %l
.
%t
%T
This makes the entry a "toggle" entry, an entry that represents binary
states and gets a check-mark drawn on its left if in "on" state. If
created with %t
its in "off" state at the start, if created with
"T"
its in "on" state. Switching states happens automatically
when the entry is selected.
Mutually exclusive with %m
, %r
, %R
and %l
.
%r
%R
This makes the entry a "radio" entry, i.e., it becomes part of a
group of entries of which only one can be "on" at a time. The group,
an integer value (don’t use INT_MIN
and INT_MIN
), must
be given in the arguments following the entries
string.
Radio entries are drawn with a small circle to the left, with the one for the entry in "on" state filled with a color (blue per default). When a radio entry is selected by the user that was in "off" state the entry of the group that was is "on" state before is automatically switched to "off" state.
If the entry gets created with %r
the entry is in "off" state,
if created with %R
it’s in "on" state (in that case all entries
created before in "on" state are reset to "off" state, i.e., the
one created last "wins").
Mutually exclusive with %m
, %t
, %T
and %l
.
%l
This creates not a real entry but indicates that a line is to be drawn to visually group other entries. While other properties can be set for such an "entry" only the "hidden" property (see below) is taken into acount.
Mutually exclusive with %m
, %t
, %T
, %
and
%R
.
%d
Marks the entry as disabled, i.e., it can’t be selected and its text is per default drawn in a different color
%h
Marks the entry as hidden, i.e., it is not shown while in this state.
%S
For entries with shortcut keys it’s quite common to have them shown on
the right hand side. Using %S
you can split the entrys text
into two parts, the first one (before %S
) being drawn flushed
left and the second part flushed right. Note that using this special
sequence doesn’t automatically sets a shortcut key, this still has to
be done using %s
.
%s
Sets one or more shortcut keys for an entry. Requires a string with
the shortcuts in the arguments following the entries
string,
see Shortcuts for details on how to define shortcuts. Please note
that the character in the label identical to the shortcut character is
only shown as underlined if %S
isn’t used.
%%
Use this to put a %
character within the text of an entry.
Please note that since fl_popup_add_entries()
is a
variadic function (i.e., it takes a variable number of arguments)
only very limited error checking is possible and thus it is of
importance that the arguments passed to the function have exactly the
required types!
The return value of fl_popup_add_entries()
is a pointer
to the first of the entries created. Since entries are stored as a
linked list this value can be used to iterate over the list (see below
for more information about the FL_POPUP_ENTRY
structure).
If the function returns NULL
no entries were created.
A typical piece of code creating a popup may look like this:
int save_cb(FL_POPUP_RETURN *result) { ... } int main(int argc, char *argv[]) { FL_POPUP *popup; File *fp; ... popup = fl_popup_add(None, NULL); fl_popup_add_entries(popup, "Save%SCtrl+S%s%f%u|" "Quit%SEsc%s|" "%l|" "Work Offline%SCtrl+O%T%s", "^S", save_cb, (void *) fp, "^[", "^O"); ... }
This creates a popup with three entries. The first one has the label
"Save"
shown at the left and "Ctrl+S"
at the right can
be selected by pressing <Ctrl>S
, in which case the function
save_cb()
will be invoked with a pointer to a structure that,
beside other informations, contains the file pointer fp
. The
second entry has the labels "Quit"
and "Esc"
and it’s
shortcut key is set to <Esc>
. Below this entry a separator line
is drawn, followed by the third entry with labels "Work
Offline"
and "Ctrl+O"
and shortcut key <Ctrl>O
. This
label is a "toggle" entry in "on" state, thus a check-marker is shown
beside it.
A few remarks about the callback routines. All have a type of
FL_POPUP_CB
as given by this typedef
:
typedef int (*FL_POPUP_CB)(FL_POPUP_RETURN *);
There are three kinds of callbacks, all with the same type. Whenever an item is entered (by moving the mouse on top of it or with the keyboard) its enter callback function is invoked (if one is set). Exceptions are entries that are disabled or hidden or entries, that just stand for separator lines. When an entry that can receive enter callbacks is left, its leave callback is invoked.
Leave callbacks are not called when a selection has been made. Instead, only the selection callback for the selected entry is invoked.
A "sub-popup entry", i.e., an entry that when entered results in a sub-popup to open, also can have an enter callback. Its leave callback is not called when the user moves the mouse onto the sub-popup but only once the sub-popup has been closed again and the mouse has been moved off the sub-popup entry.
While enter and leave callback functions are defined to return an
integer value, it’s never used. But for the third kind of callback,
invoked on selection of an entry, this isn’t true. Instead, the
callbacks return value is important: if it is FL_IGNORE
(-1),
the selection isn’t reported back to the caller (and following
callbacks also aren’t called). This can be useful when the callback
function already does everything required and nothing is left to be
done.
All callbacks receive a pointer to a structure of the type
FL_POPUP_RETURN
:
typedef struct { long int val; /* value assigned to entry */ void *user_data; /* pointer to user data */ const char *text; /* text of selected popup entry */ const char *label; /* text drawn on left */ const char *accel; /* text drawn on right */ const FL_POPUP_ENTRY *entry; /* selected popup entry */ const FL_POPUP *popup; /* (sub-) popup it belongs to */ } FL_POPUP_RETURN;
val
is the value set by "%x"
. If "%x"
wasn’t
given, it’s an automatically generated value: when a popup is created
with fl_popup_add_entries()
a counter is initalized to 0.
Whenever an entry gets added the value of the counter is assigned to
the entry and then incremented. Unless a different value is set
explicitely via "%x"
the first entry added to a popup thus gets
a value val
of 0, the second one gets 1 etc. This even holds
for entries that just stand for separator lines. In simple situations
the value of val
is probably sufficient to identify which entry
got selected.
Please note: it is possible that by setting the val
members two
or more structures for items of the same popup get the same value. It
is the programmers responsibility to avoid that (unless, of course,
that’s just what you intended).
The user_data
member of the structure is the user_void
pointer set via "%u"
. It allows to pass more complex data to
the callback function (or have returned on selection of an entry.
The text
member is exactly the string used to create the entry,
including all the special sequences starting with '%'
.
label
is what’s left after all those sequences as well as
backspace characters have been removed, tabs replaced by single spaces
and the string is split at "%S"
. I.e., it’s exactly what’s
drawn left-flushed for the entry in the popup. accel
is then
what’s left after clean-up and came after "%S"
, i.e., it’s
what appears as the right-flushed text of the entry. Please note that
one or more of these pointers could under some circumstances be
NULL
.
Finally, the two member entry
and popup
are pointers to
the entry itself and the popup the callback function is invoked for -
to find out the popup the selected entry itself belongs to use the
popup
member of the entrys FL_POPUP_ENTRY
structure.
Please note: while in a callback you are only allowed to change the
values of the val
and user_data
members. This can be
useful in the case of a cascade of selection callback calls since all
the selection callbacks receive the same structure (and this is also
the structure that finally gets passed back to the caller of
fl_popup_do()
) at the end in order to implement more
complex information interchange between the callbacks involved.
The elements of a FL_POPUP_ENTRY
structure that might be of
interest) are
typedef { FL_POPUP_ENTRY *prev; /* previous popup entry */ FL_POPUP_ENTRY *next; /* next popup entry */ int type; /* normal, toggle, radio, sub-popup, line*/ unsigned int state; /* disabled, hidden, checked */ int group; /* group (for radio entries only) */ FL_POPUP *sub; /* sub-popup bound to entry */ ... } FL_POPUP_ENTRY;
Note that you should not change the members of a
FL_POPUP_ENTRY
structure directly! Use the appropriate
functions documented below to modify them instead.
prev
and next
are pointers to the previous and the
following popup entry (or NULL
if none exists).
type
tells what kind of popup entry this is. There are five
different types:
FL_POPUP_NORMAL
FL_POPUP_TOGGLE
"Toggle" or "binary" entry, drawn with a check-mark to its left if in "on" state
FL_POPUP_RADIO
Radio entry, drawn with a circle to its left (color-filled when "on".
The group
member of the FL_POPUP_ENTRY
structure
determines to which group the entry belongs.
FL_POPUP_SUB
Entry for a sub-popup. The sub
member of its
FL_POPUP_ENTRY structure is a pointer to the sub-popup
that gets shown when the mouse enters the entry.
FL_POPUP_LINE
Not a "real" entry, just indicates that a separator line is to be drawn between the previous and the next entry.
Finally, the state
member can have the following values:
FL_POPUP_NONE
FL_POPUP_DISABLED
The entry is disabled, i.e., isn’t selectable (and normally is drawn in a way to indicate this).
FL_POPUP_HIDDEN
FL_POPUP_CHECKED
Only relevant for toggle and radio entries. Indicates that the state of a toggle entry is "on" (drawn with a check-marker) and for a radio entry that it is the one in "on" state of its group.
The state can be a combination of the above constants by using a bitwise OR.
The more interesting members of a FL_POPUP
structure are
typedef struct { FL_POPUP *next; /* previously created popup */ FL_POPUP *prev; /* later created popup */ FL_POPUP *parent; /* for sub-popups: direct parent */ FL_POPUP *top_parent; /* and top-most parent */ Window win; /* window of the popup */ FL_POPUP_ENTRY *entries; /* pointer to list of entries */ char *title; /* title string of the popup */ ... } FL_POPUP;
Note again that you are not supposed to change the members of the structure.
Like popup entries also popups are stored in a (doubly) linked list.
Thus the prev
and next
members of the structure are
pointers to popups created earlier or later. If a popup is a sub-popup
of another popup then parent
points to the next higher level
popup (otherwise it’s NULL
). In case there’s a cascade of
popups the top_parent
member points to the "root" popup (i.e.,
the top-level popup), while for popups that aren’t sub-popups it
always points back to the popup itself (in that case parent
is
NULL
).
win
is the window created for the popup. It’s None
(0)
while the popup isn’t shown, so it can be used to check if the popup
is currently visible.
The entries
member points to the first element of the list of
entries of the popup. See the FL_POPUP_ENTRY
structure
documented above on how to iterate over all entries.
Finally, title
is the title shown at the top of the popup (if
one is set). Never try to change it directly, there ars the functions
fl_popup_set_title()
and
fl_popup_set_title_f()
, described below, to do just that.
int fl_popup_entry_delete(FL_POPUP_ENTRY *entry);
The function return 0 on success and -1 if it failed for some reasons. Note that the function for a sub-popup entry also deletes the popup that was associated with the entry!
You may also insert one or more entries into a popup at arbitrary places using
FL_POPUP_ENTRY *fl_popup_insert_entries(FL_POPUP *popup, FL_POPUP_ENTRY *after, const char *entries, ...);
popup
is the popup the entries are to be inserted in,
after
is the entry after which the new entries are to be added
(use NULL
if the new entries are to be inserted at the very
first position), and entries
is the same kind if string as
already used in fl_popup_add_entries()
, including all the
available special sequences. The arguments indicated by ...
have to be given according to the entries
string.
Finally, when you don’t need a popup anymore simply call
int fl_popup_delete(FL_POPUP *popup);
The function returns 0 on success and -1 on failure. It’s not possible to call the function while the popup is still visible on the screen. Calling it from any callback function is problematic unless you know for sure that the popup to be deleted (and sub-popups of it) won’t be used later and thus normally should be avoided.
Above was described how to first generate a popup and then populate it. But there’s also a (though less general) method to create and populate a popup in a single function call. For this use
FL_POPUP *fl_popup_create(Window win, const char *title, FL_POPUP_ITEM *items);
The win
and title
arguments are the same as used in
fl_popup_add()
, i.e., they are parent window for the
popup (or fl_root
or None
) and the (optional, can
be NULL
) title for the popup.
items
is a pointer to an array of structures of the following
form:
typedef struct { const char *text; /* text of entry */ FL_POPUP_CB callback; /* (selection) callback */ const char *shortcut; /* keyboard shortcut description */ int type; /* type of entry */ int state; /* disabled, hidden, checked */ } FL_POPUP_ITEM;
The array must contain one structure for each entry of the popup and
must end in a structure where at least the text
member is set
to NULL
.
The text
member describes the text of the entry. If it contains
the string "%S"
the text is split up at this position and the
first part is used as the label drawn left-flushed for the entry and
the second part for the right-flushed part (for showing accelerator
keys etc.). Two more characters have a special meaning if they appear
at the very start of the string (and which then do not become part of
the label shown):
'_'
Draw a separator line above this entry.
'/'
This entry is a sub-popup entry and the following elements of the
items
array (until the first element with text
set to
NULL
define the entries of the sub-popup.
Both '_'
and '/'
can appear at the start of the string,
it doesn’t matter which one comes first.
The callback
member is a function to be invoked when the entry
is selected (irrelevant for sub-popup entries). shortcut
is a
string, encoding which keyboard shortcut keys can be used to select
the item (see Shortcuts for details on how such a string has to
be assembled).
type
describes the type of the entry and must be one of
FL_POPUP_NORMAL
, FL_POPUP_RADIO
(all radio
entries automatically belong to the same group (numbered
INT_MIN
). You can’t use FL_POPUP_LINE
or
FL_POPUP_SUB
. If you want a sub-popup entry use
FL_POPUP_NORMAL
and set '/'
as the first character
of the text
member of the structure. If you need a separator
line put a '_'
at the start of the text
member string of
the entry which comes after the separator line.
Finally, the state
member can be 0 or the bitwise or of
FL_POPUP_DISABLED
, FL_POPUP_HIDDEN
and
FL_POPUP_CHECKED
. The first one makes the entry appear
disabled and non-selectable, the second will keep the entry from being
drawn at all, and the third one puts the entry into "on" state
(relevant for toggle and radio entries only). If you try to set
FL_POPUP_CHECKED
for more than a single radio entry the
last one you set if for "wins", i.e., only this one will be in "on"
state. See below for a more detailed discussion of these entry
properties.
fl_popup_create()
does not allow to associate values or
pointers to user data to individual entries, set titles for
sub-popups, have radio entries belong to different groups or set enter
or leave callback functions (though there exist a number of functions
to remedy the situation in case such things are needed).
The function returns a pointer to the newly created popup (or
NULL
on failure). You are guaranteed that each entry has been
assigned a unique value, starting at 0 and which is identical to the
index of corresponding element in the items
array, i.e., the
first element results in an entry assigned 0, the second entry gets
1 etc.
All functions working on popups or entries can, of course, be used on
popups and their entries generated via fl_popup_create()
.
They can be employed to remedy some of the limitations imposed by the
simpler popup creation API.
Here’s an example of how to create a popup using
fl_popup_create()
:
FL_POPUP *popup; FL_POPUP_ITEMS items[] = { {"Item 1%S^1", NULL, "^1", FL_POPUP_NORMAL, FL_POPUP_NONE }, {"Item 2%S^2", NULL, "^2", FL_POPUP_RADIO, FL_POPUP_CHECKED }, {"Item 3%S^3", NULL, "^3", FL_POPUP_RADIO, FL_POPUP_NONE }, {"_/Item 4", NULL, NULL, FL_POPUP_NORMAL, FL_POPUP_NONE }, {"Sub-item A", cbA, "^A", FL_POPUP_NORMAL, FL_POPUP_DISABLED}, {"Sub-item B", cbB, "^B", FL_POPUP_TOGGLE, FL_POPUP_NONE }, {NULL, NULL, NULL, 0, 0 }, {"Item 5", NULL, NULL, FL_POPUP_NORMAL, FL_POPUP_NONE }, {NULL, NULL, NULL, 0, FL_POPUP_NONE } }; popup = fl_popup_create(None, "Test", items);
This creates a new popup with the title "Test"
and 5 entries as
well as a a sub-popup with two entries, that gets opened when the
mouse is over the entry labeled "Item 4"
.
The first entry in the main popup has the label "Item 1"
on the
left and "^1"
of the right side. It has no callback routine and
can be selected via the <Crtl>1
shortcut. It’s just a normal
menu entry.
The second entry has the label "Item 2"
on the left and
"^2"
of the right side, also no callack and <Crtl>2
as
its keyboard shortcut. It’s a radio entry that is in "on" state. The
third entry is like the second, labels are "Item 3"
and
"^3"
and it reacts to <Crtl>3
, except that it’s in "off"
state. The second and third label belong to the same group (with the
group number set to INT_MIN
), i.e., when the third entry gets
selected the second one gets switched to "off" state (and vice versa).
Before the fourth entry a separator line will be drawn (that’s the
effect of its text starting with '_'
. It’s a sub-popup entry
(due to the '/'
at the start of its text). It’s label is simply
"Item 4"
and no right hand label (but that isn’t supposed to
indicate that sub-entries couldn’t have shortcuts!). It has no
selection callback (which wouldn’t sense make sense for a sub-popup
entry anyway).
The following three elements of the items
array are for the
sub-popup that gets opened when the mouse is over the fourth item of
the main popup. In the sub-popup we first have an normal entry with
label "Sub-item A"
. The function cbA()
will be called
when this entry of the sub-popup is selected. Then we have a second
entry, labled "Sub-item B"
, which is a currently disabled
toggle entry in "off" state. If it weren’t disabled its selection
would result in the callback function cbB()
getting called. The
next element of the items
array, having NULL
as its
text
member, signifies the end of the sub-popup.
Now that we’re done with the sub-popup another entry in the main popup
follows, a normal entry with just a left-label of Item 5
. The
final element of items
, where text
is set to NULL
then signifies that this is the end of the popup.
As there are functions to append to and insert entries into a popup with
a kind of format string, followed by a variable list of arguments,
there are also functions for adding and inserting entries using an
array of FL_POPUP_ITEM
. These are
FL_POPUP_ENTRY *fl_popup_add_items(FL_POPUP *popup, FL_POPUP_ITEM *items); FL_POPUP_ENTRY *fl_popup_insert_items(FL_POPUP *popup, FL_POPUP_ENTRY *after, FL_POPUP_ITEM *items);
Both functions return the address of the first entry created on
success and NULL
on error. The first argument is the popup the
entries are to be appended to or inserted into, the last argument the
array of items (as in the case of fl_popup_create()
at
least the text
member of the last element must be a NULL
pointer to indicate the end). fl_popup_insert_items()
takes
another argument, after
, the entry after which the new entries
are to be inserted (if called with after
set to NULL
the
new entries are inserted at the very start of the popup).
Next: Popup Interaction, Up: Part III Popups [Contents][Index]