THE FORMS LIBRARY

A Graphical User Interface Toolkit for X

- short reference manual -

INDEX

1 BASIC CONCEPTS

1.1 Structure of an application using XForms
1.2 Initialization (fl_initialize)
1.3 Defining forms (fl_bgn_form, fl_end_form)
1.4 Adding objects to a form (fl_add_XXXX)
1.5 Showing forms (fl_show_form)
1.5.1 Controlling the position and size of forms, 1.5.2 Hiding a form (fl_hide_form)
1.6 Doing interaction
1.6.1 Blocking interaction (fl_do_forms), 1.6.2 Non-blocking interaction (fl_check_forms), 1.6.3 Using callback functions (fl_set_object_callback)

2 MORE ON FORMS AND OBJECTS

2.1 Modifying an existing form by adding/deleting objects
2.2 Grouping objects in a form
2.3 Hiding and showing objects
2.4 Activating, deactivating and triggering objects
2.5 Activating and deactivating forms
2.6 Generic object attributes
2.6.1 Color, 2.6.2 Bounding box, 2.6.3 Label, 2.6.4 Symbols
2.7 Forcing or preventing redrawing
2.7.1 Redrawing objects and forms, 2.7.1 Freezing forms
2.8 Object shortcuts
2.9 Goodies (predefined objects)
2.9.1 Messages and questions, 2.9.2 File selector

3 OVERVIEW OF ALL OBJECT CLASSES

3.1 Static objects
3.1.1 Box, 3.1.2 Frame, 3.1.3 Text, 3.1.4 Bitmap, 3.1.5 Pixmap, 3.1.6 Clock, 3.1.7 Chart
3.2 Button-like objects
3.2.1 Button
3.3 Valuator objects
3.3.1 Slider, 3.3.2 Dial, 3.3.3 Positioner, 3.3.4 Counter
3.4 Input objects
3.4.1 Input field
3.5 Choice objects
3.5.1 Menu, 3.5.2 Choice, 3.5.3 Browser, 3.5.4 Pop-ups
3.6 Other objects
3.6.1 Timer, 3.6.2 XYPlot
3.7 Canvas
3.7.1 OpenGl canvas

1- BASIC CONCEPTS

1.1- STRUCTURE OF AN APPLICATION USING XFORMS

Every Forms Library application program must perform the following steps:
  1. Initialize the Forms Library
    This step establishes a connection to the X server, allocates resources and otherwise initializes the Forms Library's internal structures, which include visual selection, font initialization and command line parsing.
  2. Defining forms
    Every program creates one or more forms and all the objects on them to construct the user interface. This step may also include callback registration and per object initialization such as setting bounds for sliders etc.
  3. Showing forms
    This step makes the designed user interface visible by creating and mapping the window (and subwindows) used by the forms.
  4. Main loop
    Forms Library applications are event-driven. The Forms Library main loop retrieves events from the X event queue, dispatches the retrieved event through appropriate objects, and notifies the application of what action, if any, should be taken. The actual notification methods depend on how the interaction is set up, which could be object callback or by returning to the application program the object whose status has changed.

1.2- INITIALIZATION

The program starts by calling the routine fl_initialize() to initialize the Forms Library:
  Display *fl_initialize(int *argc, char *argv[], 
                         const char *appclass, XrmOptionDescList app_opt,
                         int n_app_opt)
argc,argv are the command line parameters. appclass is the application class name. app_opt, n_app_opt are an option list and the number of its entries (usually 0, 0).
This routine should be called before any other calls to the library are made (except for fl_set_defaults()). One of the things this routine does is to establish a connection to the X server and initialize a resource database used by the X resource manager. It also does many other things, such as parsing command line options and initializing internal Forms Library structures.

1.3- DEFINING FORMS

A form consists of a collection of objects. A form definition is started with the routine fl_bgn_form() and ended with fl_end_form(). Between these two calls, various objects, including group of objects, are added to the form.

The following routine starts a form definition:

 FL_FORM *fl_bgn_form(int type,FL_Coord w,FL_Coord h) 
type indicates the type of the background drawn in the form. The background is a box. w and h indicate the width and height of the form in pixels.
It returns a pointer to the form created. This pointer must be used, for example, when drawing the form or doing interaction with it.

The following routine ends a form definition:

 void fl_end_form() 
Many different forms can be defined and displayed when required. It is a good habit to first define all your forms before starting the actual work.

1.4- ADDING OBJECTS TO A FORM

For (almost) all classes of objects, the routine to add an object to a form has the same form:
 FL_OBJECT *fl_add_NAME(int type, FL_Coord x, FL_Coord y,
                         FL_Coord w, FL_Coord h, const char *label)
NAME is the class name. type is the type of the object in its class. Most classes have many different types. x,y,w,h give the left bottom corner and the width and height of the bounding box of the object. label is the label that is placed inside or next to the object.
The function returns a pointer to the object.

After an object has been created, it is possible to set up its attributes. Object attributes can be divided into generic and object specific ones. For generic attributes (e.g., the object label size) the routines that change them always start with:

 fl_set_object_xxx() 
xxx is the name of the attribute.

Here is a list of XForms object classes and a short description of each class:

1.5- SHOWING FORMS

The program has to display the forms with which it wants the user to interact. This is done using the routine:
 Window fl_show_form(FL_FORM *form,int place,int border, const char *name)
It opens a (top-level) window on the screen in which the form is shown. The routine returns the window resource ID of the form. You normally never need this. Immediately after the form becomes visible, a full draw of all objects on the form is performed.
place controls the position and size of the form. border indicates whether a border (window manager's decoration) should be drawn around the form. name is the name of the window.

The location and size of the window are determined by place:

Note that the initial position is dependent upon the window manager used. Some window managers will allow interactive placement of the windows and some will not.

The argument border indicates whether or not to request window manager's decoration. Border should take one of the following values:

For some dialogs, such as demanding an answer etc., you probably do not want window manager's full decoration. Use FL_TRANSIENT for this. A window border is useful to let the user iconify a form or move it around. If a form is transient or has no border, it is normally more difficult (or even impossible) to move the form. A transient form typically should have less decoration, but not necessarily so. It depends on window mangers as well as their options.
FL_NOBORDER is guaranteed to have no border and is immune to iconification request. Because of this, borderless forms can be hostile to other applications, so use this only if absolutely necessary. For almost all situations where the application must demand an action from the user, FL_TRANSIENT is preferred. Also note you can't iconify a form that has no border and under most window managers, FL_TRANSIENT form can't be iconified either.

1.5.1- CONTROLLING SIZE AND POSITION OF FORMS

When placing a form on the screen using place FL_PLACE_GEOMETRY the position and size can be set (before showing the form) using the routines:
 void fl_set_form_position(FL_FORM *form, FL_Coord x, FL_Coord y)
 void fl_set_form_size(FL_FORM *form, FL_Coord w, FL_Coord h)
 void fl_set_form_geometry(FL_FORM form*, FL_Coord x, FL_Coord y,
                           FL_Coord w, FL_Coord h)
 void fl_scale_form(FL_FORM *form, double xsc, double ysc)
x,y,w,h indicate the position of the form on the screen and its size. The position is measured from the top-left corner of the screen.
Routine fl_scale_form() scales with a factor with respect to the current size.

If interactive resizing is to be allowed, it can be useful to limit the range the size of a form can take:

 void fl_set_form_minsize(FL_FORM *form, FL_Coord minw, FL_Coord minh)
 void fl_set_form_maxsize(FL_FORM *form, FL_Coord maxw, FL_Coord maxh)
Although these two routines can be used before or after a form becomes visible, not all window managers honor such requests once the window is visible.

1.5.2- HIDING A FORM

A form can be hidden with:
 void fl_hide_form(FL_FORM *form)
A hidden form continues to exist and can be shown again.

1.6- DOING INTERACTION

Once one or more forms are shown it is time to give the control to the library to handle the interaction with the forms. There are a number of different ways of doing this.

1.6.1- BLOCKING INTERACTION

The first one, appropriate for simple programs, is to call:
 FL_OBJECT *fl_do_forms() 
It controls the interaction until some object in one of the forms changes state. In this case a pointer to the changed object is returned.

When the object is returned by fl_do_forms() the application program can check what the change is and take action accordingly.
Normally, after the action is taken by the application program fl_do_forms() is called again to continue the interaction. Hence, most programs have the following global form:

/* define the forms */ 
/* display the forms */ 
while (! ready)
{  
  obj = fl_do_forms()
  /* handle the change in obj */
}

1.6.2- NON-BLOCKING INTERACTION

The simple interaction mentioned above is adequate for many application programs but not for all. When the program also has to perform tasks when no user action takes place (e.g., redrawing a rotating image all the time) another call can be used:
 FL_OBJECT *fl_check_forms() 
In this case control is returned to the application program immediately. When a change has occurred in some object the object is returned as with fl_do_forms(). But when no change has occurred control is also returned but this time a NULL object is returned. Programs working in this way have the following as the basic structure:
/* define the forms */ 
/* display the forms */ 
while (! ready)
{ 
  obj = fl_check_forms();
  if (obj != NULL) /* handle the change in obj */
  /* update other things */
}
Note that the use of a loop like this will eat up most computer time. Hence, only use it when the application program actually has to do something all the time. Otherwise use fl_do_forms() instead.

1.6.3- USING CALLBACK FUNCTIONS

The recommended method of interaction is to use callback functions. A callback function is a function supplied to the library by the application program that binds a specific condition (e.g., a button is pushed) to the invocation of the function by the system. The application program can bind a callback routine to any object. Once a callback function is bound and the specified condition is met, fl_do_forms() or fl_check_forms() invokes the callback function instead of returning the object.

To bind a callback routine to an object, use:

 FL_CALLBACKPTR fl_set_object_callback(FL_OBJECT *obj, 
                         FL_CALLBACKPTR callback, long argument)
obj is the object. callback is the callback function. argument is an argument that is passed to the callback routine so that it can take different actions for different objects. The function returns the old callback routine already bound to the object. You can change the callback routine any time using this function.

The callback routine should have the form:

 void callback(FL_OBJECT *obj,long argument)
The first argument to every callback function is the object to which the callback is bound. The second parameter is the argument specified by the application program in the call to fl_set_object_callback().

By defaults, callbacks are invoked automatically by the system when an object changes its state. To invoke the callback manually (as opposed to invocation by the main loop) you can use the following function:

 void fl_call_object_callback(FL_OBJECT *obj) 
When dealing with multiple forms, the application program can also bind a callback routine to an entire form. To this end it should use the routine:
 void fl_set_form_callback(FL_FORM *form, 
            void (*callback)(FL_OBJECT *, void *), void *data)
Whenever fl_do_forms() or fl_check_forms() would return an object in form they call the routine callback instead, with the object as an argument. Such callback should have the form:
 void callback(FL_OBJECT *obj, void *data) 

2.1- MODIFYING AN EXISTING FORM

The following routine reopens a form for adding objects to it:
 void fl_addto_form(FL_FORM *form) 
After this call you can start adding objects to the form. To stop adding objects to the form use fl_end_form() as before. The following routine deletes an object from the form it is in:
 void fl_delete_object(FL_OBJECT *obj) 
The following routine frees the memory for an object (the object should be deleted first):
 void fl_free_object(FL_OBJECT *obj) 
An object after being freed should not be referenced.

The following routine frees the memory for a form, together with all its objects:

 void fl_free_form(FL_FORM *form) 
The form should not be visible.

2.2- GROUPING OBJECTS IN A FORM

The following routine starts the definition of a group of objects inside a form:
 FL_OBJECT *fl_bgn_group(void) 
It returns a pointer to the group.

The following routine ends the definition of a group:

 FL_OBJECT * fl_end_group(void) 
Between these two calls, various objects are added to the group. Groups should never be nested.

Groups are useful for two reasons. First of all, it is possible to show/hide or activate/deactivate groups of objects, and to change some of their attributes with a single instruction. The second reason for using groups is for radio buttons. Pushing a radio button makes the currently pushed radio button released. In fact, this happens only with radio buttons in the particular group. Radio buttons are considered related only if they belong to the same group. Using groups is the only way to place unrelated groups of radio buttons on a single form without interference from each other.

It is possible to add objects to an existing group. The following routine reopens a group for adding more objects to it:

 void fl_addto_group(FL_OBJECT *group) 
group is the object returned by fl_bgn_group().
After this call, you can start adding objects to the group. Any new objects added are appended at the end of the group. When through adding, use fl_end_group() as before.

2.3- HIDING AND SHOWING OBJECTS

It is possible to temporarily hide certain objects or groups of objects. To this end, use the routine
 void fl_hide_object(FL_OBJECT *obj) 
obj is the object to hide or the group of objects to hide. Hidden objects don't play any role anymore. All routines on the form act as if the object does not exist.

To make the object or group of objects visible again use:

 void fl_show_object(FL_OBJECT *obj) 
Hiding and showing (groups of) objects are useful to change the appearance of a form depending on particular information provided by the user. You can also make overlapping groups in the form and take care that only one of them is visible.

2.4- DEACTIVATING, REACTIVATING AND TRIGGERING OBJECTS

Sometimes you might want a particular object to be temporarily inactive, e.g., you want to make it impossible for the user to press a particular button or to type input in a particular field. For this you can use the routine:
 void fl_deactivate_object(FL_OBJECT *obj) 
obj is the object to be deactivated. When obj is a group the whole group is deactivated.

To reactivate the group or button use the routine:

 void fl_activate_object(FL_OBJECT *obj) 
It is possible to simulate the action of an object being triggered from within the program by using the following routine:
 void fl_trigger_object(FL_OBJECT *) 
Calling this routine on an object results in the object returned to the application program or its callback called if it exists. Note however, there is no visual feedback, i.e., fl_trigger_object(button) will not make the button appear pushed.

2.5- ACTIVATING AND DEACTIVATING FORMS

An application program may need to take interaction from more than one form at the same time. By default, fl_do_forms() takes interaction from all forms that are shown.

In certain situations, you might not want to have interaction with all of them. For example, when the user presses a quit button in a form you might want to ask a confirmation using another form. You don't want to hide the main form because of that but you also don't want the user to be able to press buttons, etc. in this form. The user first has to give the confirmation. So you want to temporarily deactivate the main form. This can be done using the call:

 void fl_deactivate_form(FL_FORM *form) 
To reactivate the form later again use:
 void fl_activate_form(FL_FORM *form) 
The following routines activate or deactivate all forms:
 void fl_deactivate_all_forms(void)
 void fl_activate_all_forms(void) 

2.6- GENERIC OBJECT ATTRIBUTES

There are a number of general routines that can be used to alter the appearance of any object. Unless stated otherwise, all attributes altering routines affect the appearance or geometry of the object immediately if the object is visible.

2.6.1- COLOR

To change the color of a particular object use the routine:
 void fl_set_object_color(FL_OBJECT *obj,FL_COLOR col1,FL_COLOR col2)
col1 and col2 are indices into a colormap.
It sets the two colors that influence the appearance of the object. The meaning of such two colors depends on the specific object class.
For box and text only col1 is important. It indicates the color of the box or of the box in which the text is placed. For buttons, col1 is the color of the button when released and col2 is the color of the button when pushed. For light buttons the two colors indicate the color of the light when off and when on. For bitmap buttons, col1 is the color of the box and col2 is the color of the bitmap. For sliders col1 is the color of the background of the slider and col2 is the color of the slider itself. Finally, for input objects col1 is the color of the input field when it is not selected and col2 is the color when it is selected.

The following predefined color symbols can be used in all color change requests: FL_BLACK, FL_RED, FL_GREEN, FL_YELLOW, FL_BLUE, FL_CYAN, FL_MAGENTA, FL_WHITE.

The actual color is handled by an internal colormap of FL_MAX_COLS entries (default 1024).
To change or query the values of this internal colormap use the call:

 
 void fl_set_icm_color(FL_COLOR index, int r, int g, int b)
 void fl_get_icm_color(FL_COLOR index, int *r, int *g, int *b)

2.6.2- BOUNDING BOX

Each object has a bounding box. This bounding box has a position, a size, and can have different shapes. The position of a bounding box is the position of its upper-left corner.

The shape of the box can be changed using the routine:

 void fl_set_object_boxtype(FL_OBJECT *obj,int boxtype) 
boxtype should be one of the following: FL_UP_BOX, FL_DOWN_BOX, FL_FLAT_BOX, FL_BORDER_BOX, FL_SHADOW_BOX, FL_ROUNDED_BOX, FL_RFLAT_BOX, FL_RSHADOW_BOX, FL_NO_BOX, with the same meaning as the type for object class box (see Section 3.1.1).

The following routines act on the position and size of the box:

 void fl_set_object_position(FL_OBJECT *ob, FL_Coord x, FL_Cood y)
 void fl_set_object_size(FL_OBJECT *ob, FL_Coord w, FL_Coord h)
 void fl_set_object_geometry(FL_OBJECT *ob, FL_Coord x, FL_Coord y, 
                             FL_Coord w, FL_Coord h)

2.6.3- LABEL

Each object has a label. The default color of the label is black (FL_BLACK). The default font is Helvetica at 10pt. The color, font size, and font style can be changed by using the routines:
 void fl_set_object_lcol(FL_OBJECT *obj, FL_COLOR lcol)
 void fl_set_object_lsize(FL_OBJECT *obj,int lsize)
 void fl_set_object_lstyle(FL_OBJECT *obj,int lstyle)
lsize gives the size in points. The available styles for lstyle are: The last three styles are special in that they are modifiers, i.e., they do not cause font changes themselves, they only modify the appearance of the font already active.

You can change the alignment of the label with respect to the bounding box of the object:

 void fl_set_object_lalign(FL_OBJECT *obj,int align) 
The following possibilities exist: Normally, all the alignment request places the text outside the box, except for FL_ALIGN_CENTER. This can be changed by using a special mask, FL_ALIGN_INSIDE, to request alignments that place the text inside the box.

Finally, the routine:

 void fl_set_object_label(FL_OBJECT *obj, const char *label) 
changes the label of a given object. The passed parameter label is copied internally.

2.6.4- SYMBOLS

Rather than textual labels, it is possible to place symbols like arrows etc. on objects. When the label starts with the character @ no label is drawn but a particular symbol is drawn instead. The rest of the label string indicates the symbol.

A number of predefined symbols are available:

It is possible to put the symbols in different orientations. When the symbol name is preceded by a digit 1-9 (not 5) it is rotated like on the numerical keypad, i.e., 6 indicates no rotation, 9 a rotation of 45 degrees counter -clockwise, 8 a rotation of 90 degrees, etc. Hence the order is 6, 9, 8, 7, 4, 1, 2, 3. It is also possible to put the symbol in other orientations (not covered here).

The application program can also add symbols to the system which it can then use to display symbols on objects that are not provided by the Forms Library (topic not covered here).

2.7- FORCING OR PREVENTING REDRAWING

2.7.1- REDRAWING OBJECTS AND FORMS

It is possible to change the attributes of an object at any time. But when the form is already displayed on the screen some care has to be taken. Whenever changing attributes the system redraws the object. This is fine when drawing the object erases the old one but this is not always the case.
It is always possible to force the system to redraw an object using:
 void fl_redraw_object(FL_OBJECT *obj) 
When the object is a group it redraws the complete group. Normally you should never need this routine because all library routines take care of redrawing but there might be situations in which a redraw is required.

To redraw an entire form, use:

 void fl_redraw_form(FL_FORM *form) 
Use of these routines is normally not necessary and should be kept to an absolute minimum.

2.7.2- FREEZING FORMS

Whenever you change an attribute of an object in a visible form the object is redrawn immediately to make the change visible. This can be undesirable when you change a number of attributes of the same object. You only want the changed object to be drawn after the last change. You can tell the library to temporarily not redraw the form while changes are being made. This can be done by freezing the form. While a form is being frozen it is not redrawn, all changes made are instead buffered internally. Only when you unfreeze the form, all changes made in the meantime are drawn at once.
For freezing and unfreezing two calls exist:
 void fl_freeze_form(FL_FORM *form)
 void fl_unfreeze_form(FL_FORM *form)

2.8- OBJECT SHORTCUTS

The Forms Library has a mechanism of dealing with keyboard shortcuts. In this way the user can use the keyboard rather than the mouse for particular actions. Obviously only active objects can have shortcuts. At the moment there are three object classes that use this, namely buttons, inputs and browsers although they behave differently.

The following routine binds a series of keys to an object:

 void fl_set_object_shortcut(FL_OBJECT *obj, const char *str, int showit)
Any character in string str is considered as a shortcut, except for ^ and #, which stand for combinations with the CONTROL, and ALT key. The symbol ^ itself can be obtained using ^^. The symbol # can be obtained using ^#. The ESCAPE key can be given as ^[. Additional syntax exists to indicate function and arrow keys (topic not covered here).

Parameter showit indicates whether the shortcut letter in the object label should be underlined if a match exists. Although the entire object label is searched for matches, only the first alphanumerical character in the shortcut string is used.

2.9- GOODIES (PREDEFINED FORMS)

2.9.1- MESSAGES AND QUESTIONS

The following routines are meant to give messages to the user and to ask simple questions.
 void fl_show_message(const char *s1, const char *s2, const char * s3)
It shows a simple form with a message and a button with OK on it. s1,s2,s3 are the three lines of the message. Use empty strings if you don' t need all the lines. The routine returns when the user presses the OK button or presses the RETURN key.
 int fl_show_question(const char *s1, const char *s2, const char *s3)
Again shows a three line message but this time with a Yes and a No button. It returns whether the user pushed the Yes button. The user can also press the key to mean Yes and the key to mean No.
 int fl_show_choice(const char *s1,const char *s2,const char *s3, int numb,
                    const char *b1,const char *b2,const char *b3)
Shows a three line message with one, two or three buttons.
numb indicates the number of b uttons. b1,b2,b3 are the labels of the buttons.
The routine returns the number of the button pressed (1, 2 or 3). The user can also press the <1>, <2> or <3> key to indicate the first, second, or third button.

To obtain some text from the user, use the following routine:

 const char *fl_show_input(const char *str1,const char *defstr) 
This shows a box with one line of message (indicated by str1) and an input field in which the user can enter a string. defstr is the default string placed in the input box.
The routine returns the string when the user presses the OK button or presses the RETURN key.

2.9.2- FILE SELECTOR

The file selector provides an easy and interactive way to let the user select files. It is called as follows:
 const char * fl_show_fselector(const char *message,const char *directory,
                                const char *pattern,const char *default)
A form will be shown in which listed are all files in directory directory that satisfy the pattern.

pattern can be any kind of regular expression, e.g. [a-f]*.c gives all files starting with a letter between a and f and ending with .c. default is the default file name. message is the message string placed at the top of the form.

Now the user can choose a file from the list given. Function returns a pointer to a static buffer that contains the filename selected or null if the Cancel button is pressed. The user can also walk through the directory structure, either by changing the directory string by pressing the mouse on it or by pressing his mouse on a directory name to enter this directory. All directory entries read are cached internally (up to 10 directories) and if there is any change in directory entries, click on ReScan button to force an update.

3- OVERVIEW OF ALL OBJECT CLASSES

This part describes all object classes that are available in the Forms Library, and documents object specific routines. Routines that act on generic objects of any class are documented in Section "Generic object attributes" (2.6). However, the effect of certain generic attributes (e.g, color set by fl_set_object_color()) depends on the object class and therefore is discussed here.

3.1- STATIC OBJECTS

3.1.1- BOX

Boxes are simply used to give the dialogue forms a nicer appearance. They can be used to visually group other objects together. The bottom of each form is a box.

To add a box to a form you use the routine:

 FL_OBJECT *fl_add_box(int type, FL_Coord x, FL_Coord y,
                       FL_Coord w, FL_Coord h, const char *label) 
The label is default placed centered in the box. The following types are available: No interaction takes place with boxes. Attribute Color1 controls the color of the box.

3.1.2- FRAME

Frames are simply used to give the dialogue forms a nicer appearance. They can be used to visually group other objects together. Frames are almost the same as a box, except that the interior of the bounding box is not filled.

To add an frame to a form you use the routine:

 FL_OBJECT *fl_add_frame(int type, FL_Coord x, FL_Coord y,
                         FL_Coord w, FL_Coord h, const char *label) 
The frame is drawn outside of the bounding box, so a flat box of the same size just fills the inside of the frame without any gaps. The label is by default placed centered inside the frame. The following types are available: No interaction takes place with frames. Attribute Color1 controls the color of the frame if applicable. Boxtype attribute does not apply to the frame class.

3.1.3- TEXT

Text objects simply consist of a label possibly placed in a box.

To add a text to a form you use the routine:

 FL_OBJECT *fl_add_text(int type, FL_Coord x, FL_Coord y,
                        FL_Coord w, FL_Coord h, const char *label)
The label is by default placed flushed left in the bounding box. Only one type of text exists: FL_NORMAL_TEXT.

No interaction takes place with text objects. Attribute Color1 controls the color of the box. The color of the text is controlled by lcol as usual.

3.1.4- BITMAP

A bitmap is a simple bitmap shown on a form.

To add a bitmap to a form you use the routine:

 FL_OBJECT *fl_add_bitmap(int type, FL_Coord x, FL_Coord y,
                          FL_Coord w, FL_Coord h, const char *label )
The label is by default placed below the bitmap. The bitmap will be empty. Only the type FL_NORMAL_BITMAP is available.

No interaction takes place with a bitmap.

To set the actual bitmap being displayed use:

 void fl_set_bitmap_data(FL_OBJECT *ob, int width,int height,char *bits)
 void fl_set_bitmap_file(FL_OBJECT *ob,const char *file)
bits contains the bitmap data as a character string. file is the name of the file that contains bitmap data.

A number of bitmaps can be found in /usr/include/X11/bitmaps or similar places. The X program bitmap can be used to create bitmaps.

Label color controls the foreground color of the bitmap. Color1 controls the background color of the bitmap (and the color of the box) Color2 is not used.

3.1.5- PIXMAP

A pixmap is a simple pixmap shown on a form.

To add a bitmap to a form you use the routine:

 FL_OBJECT *fl_add_pixmap(int type, FL_Coord x, FL_Coord y,
                          FL_Coord w, FL_Coord h, const char *label)
The label is by default placed below the pixmap. Only the type FL_NORMAL_PIXMAP is available.

No interaction takes place with a pixmap.

To set the actual pixmap being displayed use:

 void fl_set_pixmap_data(FL_OBJECT *ob, char **data)
 void fl_set_pixmap_file(FL_OBJECT *ob, const char *file)
data contains the pixmap data as an array of char pointers and file is the name of the file that contains the pixmap data.

Note that both of these functions do not free the old pixmaps associated with the object. There is more on pixmaps which is not covered here.

3.1.6- CLOCK

A clock object simply displays a clock on the form.

To add a clock to a form you use the routine:

 FL_OBJECT *fl_add_clock(int type, FL_Coord x, FL_Coord y,
                         FL_Coord w, FL_Coord h, char label[])
The label is default placed below the clock. The following types are available: No interaction takes place with clocks.

To get the current time use the routine:

 void fl_get_clock(FL_OBJECT *obj, int *h, int *m, int *s) 
Attribute Color1 controls the color of the background, color2 the color of the hands.

3.1.7- CHART

The chart object gives you an easy way to display a number of different types of charts like bar-charts, pie-charts, line-charts, etc. They can either be used to display some fixed chart or a changing chart (e.g. a strip-chart). Values in the chart can be changed and new values can be added which makes the chart move to the left, i.e., new entries appear at the right and old entries disappear at the left. This can be used to e.g. monitor some process.

To add a chart object to a form use the routine:

 FL_OBJECT *fl_add_chart(int type, FL_Coord x, FL_Coord y,
                         FL_Coord w, FL_Coord h, const char *label)
It shows an empty box on the screen with the label below it. The following types are available: All charts except pie-charts can display positive and negative data. Pie-charts will ignore values that are = 0. Switching between different types can be done without any complications.

No interaction takes place with charts.

To clear a chart use the routine:

 void fl_clear_chart(FL_OBJECT *obj) 
To add an item to a chart use:
 void fl_add_chart_value(FL_OBJECT *obj, double val,
                              const char *text, int col)
val is the value of the item, text is the label to be associated with the item (can be empty) and col is an index in the colormap that is the color of this item.

The chart will be redrawn each time you add an item. This might not be appropriate if you are filling a chart with values. In this case put the calls between fl_freeze_form() and fl_unfreeze_form().

You can also insert a new value at a particular place using:

 void fl_insert_chart_value(FL_OBJECT *obj, int index,
                            double val, const char *text, int col)
index is the index before which the new item should be inserted. The first item is number 1.

To replace the value of a particular item use the routine:

 void fl_replace_chart_value(FL_OBJECT *obj, int index, double val, 
                             const char *text, int col)
index is the index of the value to be replaced. The first value has an index of 1, etc.

Normally, bar-charts and line-charts are automatically scaled in the vertical direction such that all values can be displayed. This is often not wanted when new values are added from time to time. To set the minimal and maximal value displayed use the routine:

 void fl_set_chart_bounds(FL_OBJECT *obj, double min, double max) 
To return to automatic scaling choose min = max = 0.

Also the width of the bars and distance between the points in a line-chart are normally scaled. To change this use:

 void fl_set_chart_autosize(FL_OBJECT *obj, int autosize) 
with autosize = 0.

In this case the width of the bars will be such that the maximal number of items fits in the box. This maximal number (default FL_CHART_MAX which is 256) can be changed using:

 void fl_set_chart_maxnumb(FL_OBJECT *obj, int maxnumb) 

Attribute Color1 controls the color of the box.

3.2- BUTTON LIKE OBJECTS

3.2.1- BUTTON

Buttons are placed on the form such that the user can push them with the mouse. Different button classes exist correspond to different shapes of buttons: To add a button of a certain class use one of the following routines:
 FL_OBJECT *fl_add_button(int type, FL_Coord x, FL_Coord y,
                          FL_Coord w, FL_Coord h, const char *label)
 FL_OBJECT *fl_add_lightbutton(int type, FL_Coord x, FL_Coord y,
                           FL_Coord w,FL_Coord h, const char *label)
 FL_OBJECT *fl_add_roundbutton(int type, FL_Coord x, FL_Coord y,
                           FL_Coord w,FL_Coord h, const char *label)
 FL_OBJECT *fl_add_checkbutton(int type, FL_Coord x, FL_Coord y,
                           FL_Coord w,FL_Coord h, const char *label)
The label is by default placed inside the button for button and lightbutton. For roundbutton, bitmapbutton and pixmapbutton, it is placed to the right of the circle and to the bottom of the bitmap/pixmap respectively.

Different types of buttons correspond to different behaviors of the button. The following types of buttons are available:

Except for the FL_HIDDEN_BUTTON and FL_HIDDEN_RET_BUTTON, which are invisible, they all look the same on the screen but their function is quite different. Each of these buttons gets pushed down when the user presses the mouse on top of it. What actually happens when the user does so depends on the type of the button.
An FL_NORMAL_BUTTON, FL_TOUCH_BUTTON and FL_INOUT_BUTTON gets released when the user releases the mouse button. Their difference lies in the moment at which the interaction routines return them.
A FL_PUSH_BUTTON remains pushed and is only released when the user pushes it again.
A FL_RADIO_BUTTON is a push button with the following extra property. Whenever the user pushes a radio button, all other pushed radio buttons in the form (or in a group) are released. In this way the user can make its choice among some possibilities.
A FL_RETURN_BUTTON behaves like a normal button, but it also reacts when the RETURN key on the keyboard is pressed. When a form contains such a button (of course there can only be one) the RETURN key can no longer be used to move between input fields. For this the TAB key must be used.
A FL_HIDDEN_BUTTON behaves like a normal button but is invisible. A FL_HIDDEN_RET_BUTTON is like a hidden button but also reacts to RETURN key presses.

FL_NORMAL_BUTTONs, FL_PUSH_BUTTONs, FL_RADIO_BUTTONs, FL_RETURN_BUTTONs and FL_HIDDEN_BUTTONs are returned at the moment the user releases the mouse after having pressed it on the button. An FL_INOUT_BUTTON is returned both when the user presses it and when the user releases it. A FL_TOUCH_BUTTON is returned all the time as long as the user keeps it pressed. A FL_RETURN_BUTTON and a FL_HIDDEN_RET_BUTTON are also returned when the user presses the RETURN key.

The application program can also set a button to be pushed or not itself without a user action. To this end use the routine:

 void fl_set_button(FL_OBJECT *obj, int pushed) 
pushed indicates whether the button should be pushed (1) or released (0).

Note that when setting a FL_RADIO_BUTTON to be pushed this does not automatically set the currently pushed button to be released. The application program will have to do that itself. Further, this routine only simulates the visual appearance and perhaps some internal states, it does not affect the program flow in anyway, i.e., setting a button being pushed does not invoke its callback or results in the button returned to the program. For that, fl_trigger_object() is needed.

To figure out whether a button is pushed or not use:

 int fl_get_button(FL_OBJECT *obj) 
To find out which mouse button was used at the last push (or release) use the routine:
 int fl_get_button_numb(FL_OBJECT *obj) 
It returns the number of the mouse button (1 = left, 2 = middle, 3 = right). If the last push is triggered by a shortcut the function returns the keysym (ascii value if ASCII) of the key plus FL_SHORTCUT.

In a number of situations it is useful to define a keyboard equivalent to a button. E.g., you might want to define that ^Q (CNTRL Q) has the same meaning as pressing the Quit button. This can be achieved using the following call:

 void fl_set_button_shortcut(FL_OBJECT *obj, const char *str, int showUL)
Note that str is a string, not a character. This string should contain all the characters that correspond to this button. If you use string "^QQq" the button will react on the keys q, Q and CNTRL Q. As you see you should use the symbol ^ to indicate the control key. Similarly you can use the symbol # to indicate the ALT key.
If the second parameter showUL is true, and one of the letters in the object label matches the shortcut, the matching letter will be underlined. This applies to non-printable characters (such as #A) as well in the sense that if the label contains letter a or A, it will be underlined.

To set the bitmap to use for the bitmap button, the following routines can be used:

 void fl_set_bitmapbutton_data(FL_OBJECT *ob, int w, int h, unsigned char *bits)
 void fl_set_bitmapbutton_file(FL_OBJECT *ob, const char *filename)
Similarly, to set the pixmap to use for the pixmap button, the following routines can be used:
 void fl_set_pixmapbutton_data(FL_OBJECT *ob, unsigned char **bits)
 void fl_set_pixmapbutton_file(FL_OBJECT *ob, const char *filename)
 void fl_set_pixmapbutton_pixmap(FL_OBJECT *ob, Pixmap id, Pixmap mask)
Note that these routines do not free the pixmaps already associated with the button. To free the pixmaps, use the following routine:
 void fl_free_pixmapbutton_pixmap(FL_OBJECT *ob)
To get the pixmap that is currently being displayed, use the following routine:
 Pixmap fl_get_pixmapbutton_pixmap(FL_OBJECT *ob, 
                                   Pixmap &pixmap, Pixmap &mask)
Pixmaps are by default displayed centered inside the bounding box. However, this can be changed using the following routine:
 void fl_set_pixmapbutton_align(FL_OBJECT *ob, int align, 
                                int xmargin, int ymargin)
align is the same as that used for labels. xmargin and ymargin are extra margins to leave in additional to the object border width.

For normal buttons color1 controls the normal color and color2 the color when pushed. For lightbuttons color1 is the color of the light when off and color2 the color when on. For round buttons, color1 is the color of the circle and color2 the color of the circle that is placed inside it when pushed. For bitmapbuttons, color1 is the normal box color (or bitmap background if nobox) and color2 is used to indicate the focus color. The fore ground color of the bitmap is controlled by label color.

3.3- VALUATOR OBJECTS

3.3.1- SLIDER

Sliders are useful for letting the user indicate a value between some fixed bounds. Both horizontal and vertical sliders exist. They have a minimum, maximum and current value (all floats). The user can change the current value by shifting the slider with the mouse. Whenever the value changes, this is reported to the application program.

To add a slider to a form use:

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

 FL_OBJECT *fl_add_valslider(int type, FL_Coord x, FL_Coord y,
                             FL_Coord w, FL_Coord h, const char *label)
The label is by default placed below the slider. The second class of slider displays its value above or to the left of the slider. The following types of sliders are available: Whenever the user changes the value of the slider using the mouse, the slider is returned (or the callback called) by the interaction routines. The slider position is changed by moving the mouse inside the slider area. For fine control, hold down the left or right key while moving the slider.

In some applications you might not want the slider to be returned all the time. To change the default, call the following routine:

 void fl_set_slider_return(FL_OBJECT *obj, int when) 
Parameter when can be one of the four values:
  • FL_RETURN_END_CHANGED: return at end (mouse release) if value is changed (since last return)
  • FL_RETURN_CHANGED: return whenever the slider value is changed.
  • FL_RETURN_END: return at end (mouse release) regardless if the value is changed or not.
  • FL_RETURN_ALWAYS: return all the time.
Default value of the slider is 0 and can vary between 0 and 1. These values can be changed using the routines:
 void fl_set_slider_value(FL_OBJECT *obj,double val) 
 void fl_set_slider_bounds(FL_OBJECT *obj, double min, double max) 
The program can read the slider value using the call:
 double fl_get_slider_value(FL_OBJECT *obj) 
Attribute Color1 controls the color of the background of the slider, color2 the color of the slider itself.

You can control the size of the slider inside the box using the routine:

 void fl_set_slider_size(FL_OBJECT *obj, double size) 
size should be a float between 0.0 and 1.0. With size=1.0, the slider covers the box completely and can no longer be moved. The default is FL_SLIDER_WIDTH = 0.08.

3.3.2- DIAL

Dial objects are dials that the user can put in a particular position using the mouse. They have a minimum, maximum and current value (all floats). The user can change this value by turning the dial with the mouse. Whenever the value changes, this is reported to the application program.

To add a dial to a form use:

 FL_OBJECT *fl_add_dial(int type, FL_Coord x, FL_Coord y, 
                        FL_Coord w, FL_Coord h, const char *label)
The label is by default placed below the dial. The following types of dials are available:
  • FL_NORMAL_DIAL: A dial with a knob indicating the position.
  • FL_LINE_DIAL: A dial with a line indicating the position.
Whenever the user changes the value of the dial using the mouse, the dial is returned by the interaction routine. In some applications you only want the dial to be returned to the application program when the user releases the mouse, i.e., not all the time. To achieve this call the routine:
 void fl_set_dial_return(FL_OBJECT *obj, int always) 
Set always to FALSE to achieve this goal.

To change the value of the dial use:

 void fl_set_dial_value(FL_OBJECT *obj, double val)
 void fl_set_dial_bounds(FL_OBJECT *obj, double min, double max)
By default, the minimum value is 0.0, the maximum is 1.0 and the value is 0.5.

To obtain the current values of the dial use:

 double fl_get_dial_value(FL_OBJECT *obj)
 void fl_get_dial_bounds(FL_OBJECT *obj, double *min, double *max)
Sometimes, it might be desirable to limit the angular range a dial can take or choose an angle other than 0 to represent the minimum value. For this purpose, use the following routine:
 void fl_set_dial_angles(FL_OBJECT *ob, double thetai, double thetaf)
thetai maps to the minimum value of the dial and thetaf maps to the maximum value of the dial.
By default, the minimum angle is 0 and the maximum angle is 360.

By default, crossing from 359.9 to 0 or from 0 to 359.9 is not allowed. To allowing crossing, use the following routine:

 void fl_set_dial_cross(FL_OBJECT *ob, int flag) 
The following routine makes dial values to be rounded to some values, e.g. to integer values:
 void fl_set_dial_step(FL_OBJECT *obj, double step) 
After this call dial values will be rounded to multiples of step. Use the value 0.0 to stop rounding.

The default box for dials is FL_NO_BOX.
Color1 controls the color of the background of the dial, color2 the color of the knob or the line.

3.3.3- POSITIONER

A positioner is an object in which the user can indicate a position with an x- and a y-coordinate. It displays a box with a cross-hair cursor in it. Clicking the mouse inside the box changes the position of the cross-hair cursor and, hence, the x- and y-values.

A positioner can be added to a form using the call:

 FL_OBJECT *fl_add_positioner(int type, FL_Coord x, FL_Coord y,
                              FL_Coord w, FL_Coord h, const char *label)
The label is placed below the box by default. Only one type of positioner exists at the moment: FL_NORMAL_POSITIONER.

The user changes the setting of the positioner using the mouse inside the box. Whenever the values change, the object is returned by the interaction routines.

In some applications you only want the positioner to be returned to the application program when the user releases the mouse, i.e., not all the time. To achieve this call the routine:

 void fl_set_positioner_return(FL_OBJECT *obj, int always) 
Set always to 0 to achieve this goal.

To set the value of the positioner and the boundary values use the routines:

 void fl_set_positioner_xvalue(FL_OBJECT *obj, double val)
 void fl_set_positioner_xbounds(FL_OBJECT *obj, double min, double max)
 void fl_set_positioner_yvalue(FL_OBJECT *obj, double val)
 void fl_set_positioner_ybounds(FL_OBJECT *obj, double min, double max)
By default the minimum values are 0.0, the maximum values are 1.0 and the values are 0.5. For ybounds, min and max should be taken to mean the value at the bottom and value at the top of the positioner.

To obtain the current values of the positioner use:

 double fl_get_positioner_xvalue(FL_OBJECT *obj)
 void fl_get_positioner_xbounds(FL_OBJECT *obj, double *min, double *max)
 double fl_get_positioner_yvalue(FL_OBJECT *obj)
 void fl_get_positioner_ybounds(FL_OBJECT *obj, double *min, double *max)
The following routines allows rounding positioner values to some values, e.g. to integer values:
 void fl_set_positioner_xstep(FL_OBJECT *obj, double step)
 void fl_set_positioner_ystep(FL_OBJECT *obj, double step)
After these calls positioner values will be rounded to multiples of step. Use the value 0.0 to stop rounding.

Attribute Color1 controls the color of the box, color2 the color of the cross-hair.

3.3.4- COUNTER

A counter provides a different mechanism for the user to indicate a value. It consists of a box displaying the value and four buttons two at the left and two at the right side. The user can press these buttons to change the value. The extreme buttons make the value change fast, the other buttons make it change slowly. As long as the user keeps his mouse pressed, the value changes.

To add a counter to a form use:

 FL_OBJECT *fl_add_counter(int type, FL_Coord x, FL_Coord y, 
                           FL_Coord w, FL_Coord h, const char *label)
The label is by default placed below the counter. The following types of counters are available:
  • FL_NORMAL_COUNTER: A counter with two buttons on each side.
  • FL_SIMPLE_COUNTER: A counter with one button on each side.
The user changes the value of the counter by keeping his mouse pressed on one of the buttons. Whenever he releases the mouse the counter is returned to the application program.

In some applications you might want the counter to be returned to the application program whenever the value changes. To achieve this call the routine:

 void fl_set_counter_return(FL_OBJECT *obj, int always)
Set always to TRUE to achieve this.

To change the value of the counter use the routines:

 void fl_set_counter_value(FL_OBJECT *obj, double val)
 void fl_set_counter_bounds(FL_OBJECT *obj, double min, double max)
 void fl_set_counter_step(FL_OBJECT *obj, double small, double large)
The first routine sets the value (default 0), the second routine sets the minimum and maximum values that the counter will take (default -1000000 and 1000000) and the third routine sets the sizes of the small and large steps (default 0.1 and 1). For simple counters only the small step is used.

To obtain the current value of the counter use:

 double fl_get_counter_value(FL_OBJECT *obj) 
Attribute Color1 controls the color of the background of the counter, color2 the color of the arrows in the counter.

3.4- INPUT OBJECTS

3.4.1- INPUT FIELD

Input field are used to obtain textual input from the user. An input field is a field that can be edited by the user using the keyboard.

To add an input field to a form you use the routine:

 FL_OBJECT *fl_add_input(int type, FL_Coord x, FL_Coord y,
                         FL_Coord w, FL_Coord h, const char *label)
The label is by default placed in front of the input field. The following types of input fields exist:
  • FL_NORMAL_INPUT: Any type of text can be typed into this field.
  • FL_FLOAT_INPUT: Only a float value can be typed in.
  • FL_INT_INPUT: Only an integer value can be typed in.
  • FL_MULTILINE_INPUT: An input field allowing for multiple lines.
  • FL_SECRET_INPUT: A normal input field that does not show the text.
  • FL_HIDDEN_INPUT: A normal input field but in visible.
A normal input field can contain one line of text. If the user tries to type in something else in a float or integer input field, it is not shown and the bell is sounded. A multi-line input field can contain multiple lines of text. A secret input field works like a normal input field but the text is not shown. Only the cursor is shown which does move while text is being entered. Finally, a hidden input field is not shown at all but does collect text for the application program to use. Note that multi-line input fields do not scroll (neither horizontally nor vertically), so the area reserved for the field should be large enough to contain the entire text.

Whenever the user presses the mouse inside an input field a cursor will appear in it (and it will change color). Further input will appear inside this field. When the user presses the TAB key the input field is returned to the application program and the input focus is directed to the next input field. This also happens when the user presses the RETURN key but only if the form does not contain a return button. This does not work for multi-line input fields where return key is used to separate lines. Also when the user picks a new input field with the mouse, the current input object is returned.

To set the contents of the input field use the routine:

 void fl_set_input(FL_OBJECT *obj, char str[]) 
To obtain the string in the field (when the user has changed it) use:
 [const] char *fl_get_input(FL_OBJECT *obj) 

3.5- CHOICE OBJECTS

3.5.1- MENU

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.

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. 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 moves the mouse inside it.
PUSH_MENU and PULLDOWN_MENU behave in exactly the same way. The only difference is in the way they are drawn when the menu is active: PUSH_MENU's menu appears to be an up box casting a shadow while PULLDOWN_MENU's is just an extension of the menu box.

When the menu appears the user can make a selection using the right mouse button or make no selection by clicking outside the menu. When he makes a selection the menu object is returned by the interaction routines.

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. It should contain the menu items, separated by a bar, e.g., "First|Second|Third". Special tags can be used to indicate special attributes (not covered here, but see fl_set_menu_item_mode).

Whenever the user selects some menu item, the menu object is returned to the application program. To find the actual menu item selected by the user use:

 int fl_get_menu(FL_OBJECT *obj) 
When the first item is selected 1 is returned, for the second item 2, etc. If no item was selected -1 is returned.

You can also obtain the text of the item selected:

 const char *fl_get_menu_text(FL_OBJECT *obj) 
To obtain the text of any item, use the following routine:
 const char *fl_get_menu_item_text(FL_OBJECT *obj, int n) 
To obtain the total number of menu items, use:
 int fl_get_menu_maxitems(FL_OBJECT *obj) 
It is possible to add menu items to an existing menu using the call:
 void fl_addto_menu(FL_OBJECT *obj, const char *menustr) 
Also routines exist to change a particular menu item or delete it:
 void fl_replace_menu_item(FL_OBJECT *obj,int numb,const char *menustr)
 void fl_delete_menu_item(FL_OBJECT *obj, int numb)
To clear the whole menu use the routine:
 void fl_clear_menu(FL_OBJECT *obj) 
One can change the appearance of different menu items. In particular, it is possible to sometimes make them grey and unselectable and 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 numb, unsigned mode)
mode is the display characteristics you want to apply to the chosen entry. For this parameter, the following symbolic constants exist:
  • FL_PUP_NONE: No special display characteristic. The default.
  • FL_PUP_GREY: Entry is grayed out and disabled. Not selectable.
  • FL_PUP_BOX: Entry has an empty box to the left (indicating toggle/radio).
  • FL_PUP_CHECK: Entry has a checked box (a down box) to the left.
  • FL_PUP_RADIO: Radio entry with a box to the left.
You can specify more than one at a time by bitwise OR-ing these values together. The following routine returns the current mode of an item after interaction, mostly useful for toggle or radio items:
 unsigned int fl_get_menu_item_mode(FL_OBJECT *ob, int numb) 
It is possible to define keyboard shortcuts for particular menu items (not covered here).

Attribute Color1 controls the color of the box when not selected and color2 is the color when the menu is shown.

To change the font used in the popup menu (not the menu label) use the following routines:

 void fl_setpup_fontsize(int size)
 void fl_setpup_fontstyle(int style)
Currently there is not direct support for cascade menus in menu class. You can, however, get a cascade menu by using a popup and then attach the popup ID to a menu object via the following routine:
 void fl_set_menu_popup(FL_OBJECT *ob, int pupID) 
For a menu so created, only fl_get_menu and fl_get_menu_text work as expected. Other services such as mode query etc. should be obtained via popup routines. You can use FL_MENU_BUTTON to initiate a callback and use XPopup directly within the callback.

3.5.2- CHOICE

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

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. The object label is also used as the title of the popup if not empty.

The following types are available:

  • FL_NORMAL_CHOICE: Middle/right mouse button shortcut.
  • FL_DROPLIST_CHOICE: Menu is activated only by pressing and releasing on the arrow.
There are two ways in which the user can pick a new choice. One way is using the right or middle mouse button. Pressing and releasing the right mouse button on the choice object sets the next choice in the list. When pressing the middle mouse button the previous choice is taken. Keeping the mouse pressed cycles through the list.

The other way is to use the left mouse button. In this case a menu appears from which the user can select the proper choice. In both cases, whenever a choice is selected (even when it is the original one) the object is returned to the application program.

The items in the list are numbered in the order in which they are inserted. The first item has number 1, etc.

To clear the list of choices, use the routine:

 void fl_clear_choice(FL_OBJECT *obj) 
To add/delete a line to/from a choice object use:
 void fl_addto_choice(FL_OBJECT *obj, const char *text)
 void fl_delete_choice(FL_OBJECT *obj, int line) 
One can also replace a line using:
 void fl_replace_choice(FL_OBJECT *obj, int line, const char *text)
To obtain the current choice in the choice object use the call:
 int fl_get_choice(FL_OBJECT *obj) 
It returns the number of the current choice (0 if there is no choice).

You can also obtain the actual choice text 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 a choice item, use the routine:

 const char *fl_get_choice_item_text(FL_OBJECT *obj, int n) 
To obtain the total number of choices (items) use:
 int fl_get_choice_maxitems(FL_OBJECT *obj) 
One can set various attributes of an item using the routine:
 void fl_set_choice_item_mode(FL_OBJECT *ob, int numb, unsigned mode)
mode is the same as that used in menu objects.

Finally, the application program can set the currently selected item in the choice by using one of:

 void fl_set_choice(FL_OBJECT *obj, int line) 
 void fl_set_choice_text(FL_OBJECT *obj, const char *txt)
line is the number of the item to be selected. txt must be exactly the same string used in fl_addto_choice to add the item.

Attribute Color1 controls the color of the box and color2 is 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:

 void fl_set_choice_align(FL_OBJECT *ob, int align) 
To set the font size and style used inside the choice object use:
 void fl_set_choice_fontsize(FL_OBJECT *obj, int size)
 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:
 void fl_setpup_fontsize(int size)
 void fl_setpup_fontstyle(int style)

3.5.3- BROWSER

A browser is a box that contains a number of lines of text. If the text does not fit inside the box, a scroll bar is automatically added so that the user can scroll through it. A browser can be used for building up a help facility or to give messages to the user.

It is possible to create a browser from which the user can select lines. In this way the user can make its selections from (possible) long lists of choices. Both single lines and multiple lines can be selected, depending on the type of the browser.

To add a browser to a form use the routine:

 FL_OBJECT *fl_add_browser(int type, FL_Coord x, FL_Coord y,
                           FL_Coord w, FL_Coord h, const char *label)
The label is placed below the box by default. The following types of browsers exist:
  • FL_NORMAL_BROWSER: A browser in which no selections can be made.
  • FL_SELECT_BROWSER: The user can make single line selections.
  • FL_HOLD_BROWSER: Same but the selection remains visible till the next selection.
  • FL_MULTI_BROWSER: Multiple selections can be made and remain visible till de-selected.
The user can change the position of the slider or use keyboard cursor keys (including Home, PgDn, etc.) to scroll through the text. When he/she presses the mouse below or above the slider, the browser scrolls one page down or one page up. When not using an FL_NORMAL_BROWSER, the user can also make selections with the mouse by pointing to the correct line or by using the cursor keys.

For FL_SELECT_BROWSER's, as long as the user keeps the mouse pressed, the current line under the mouse is highlighted. Whenever he releases the mouse the highlighting disappears and the browser is returned to the application program. The application program can now figure out which line was selected using the call fl_get_browser().
An FL_HOLD_BROWSER works exactly the same except that, when the mouse is released, the selection remains highlighted. An FL_MULTI_BROWSER allows the user to select and de-select multiple lines. Whenever he selects or de-selects a line the browser is returned to the application program that can next figure out (using fl_get_browser()) which line was selected or de-selected. When the user presses the mouse on a non-selected line, he will select all lines he touches with his mouse until he releases it. All these lines will become highlighted. When the user starts pressing the mouse on an already selected line he de-selects lines rather than selecting them.

To make a browser empty use:

 void fl_clear_browser(FL_OBJECT *obj) 
To add a line to a browser use one of:
 void fl_add_browser_line(FL_OBJECT *obj, const char *text)
 void fl_addto_browser(FL_OBJECT *obj, const char *text)
The difference is that with the second call the browser will be shifted such that the newly added line is visible.

You can also insert a line in front of a given line. All lines after it will be shifted. Note that the top line is numbered 1 (not 0).

 void fl_insert_browser_line(FL_OBJECT *obj, int line, const char *text) 
To delete a line (shifting the following lines) use:
 void fl_delete_browser_line(FL_OBJECT *obj, int line) 
One can also replace a line using:
 void fl_replace_browser_line(FL_OBJECT *obj, int line, const char *tex)
Making many changes to a visible browser at the same moment, is very slow because the browser is redrawn after each change. The Forms Library has a mechanism for avoiding this using the calls fl_freeze_form() and fl_unfreeze_form().

To obtain the contents of a particular line in the browser, use:

 const char *fl_get_browser_line(FL_OBJECT *obj, int line) 
It returns a pointer to the particular line of text.

It is also possible to load an entire file into a browser using:

 int fl_load_browser(FL_OBJECT *obj, const char *filename) 
The routine returns whether or not the file name was successfully loaded. If the file name is an empty string the box is simply cleared. There is currently a limit of maximum 1024 bytes per line for fl_load_browser().

The application program can select or de-select lines in the browser. To this end the following calls exist:

 void fl_select_browser_line(FL_OBJECT *obj, int line)
 void fl_deselect_browser_line(FL_OBJECT *obj, int line)
 void fl_deselect_browser(FL_OBJECT *ob)
The last call de-selects all lines.

To check whether a line is selected, use the routine:

 int fl_isselected_browser_line(FL_OBJECT *obj, int line) 
The following routine returns the number of lines in the browser:
 int fl_get_browser_maxline(FL_OBJECT *obj) 

The following routine tells how many lines are visible in the browser:

 int fl_get_browser_screenlines(FL_OBJECT *ob) 

To obtain the last selection made by the user, e.g. when the browser is returned, the application program can use the routine:

 int fl_get_browser(FL_OBJECT *obj) 
It returns the line number of the last selection being made (0 if no selection was made). Top line is line 1. When the last action was a de-selection (only for FL_MULTI_BROWSER's) the negation of the line number is returned.

There are also calls to influence and query top line shown in the box (i.e., influence the position of the slider):

 void fl_set_browser_topline(FL_OBJECT *obj, int line)
 int fl_get_browser_topline(FL_OBJECT *obj) 
It is possible to register a callback function that gets called when a line is double-clicked. To this end, the following function can be used:
 void fl_set_browser_dblclick_callback(FL_OBJECT *ob, 
         void (*cb)(FL_OBJECT *,long), long data) 
Of course, double-click callback makes most sense for FL_HOLD_BROWSER.

Finally the following routine can be used to scroll the text horizontally:

 void fl_set_browser_xoffset(FL_OBJECT *ob, FL_Coord xoff) 
xoff is the offset in pixels.

Attribute Color1 controls the color of the box, color2 the color of the selection. The text color is the same as the label color.

To set the font size and style used inside the browser use:

 void fl_set_browser_fontsize(FL_OBJECT *obj, int size)
 void fl_set_browser_fontstyle(FL_OBJECT *obj, int style)
To align different text fields on a line, tabs can be embedded in the text.

The following routine turns the (vertical) scrollbar on and off:

 void fl_set_browser_vscrollbar(FL_OBJECT *ob, int on) 
  • FL_ON: turns the scrollbar on if there are enough lines in the browser.
  • FL_OFF: turns the scrollbar off.
  • FL_ALWAYS_ON: turns the scrollbar on (not currently supported).
Finally there is a routine that can be used to obtain the browser size in pixels for the text area:
 void fl_get_browser_dimension(FL_OBJECT *ob, FL_Coord *x, FL_Coord *y,
                               FL_COORD *w, FL_COORD *h)
x and y are measured from the top-left corner of the form.

3.5.4- POP-UPS

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

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

To define a new popup, use the following routines:

 int fl_newpup(Window parent)
 int fl_defpup(Window parent, const char *str [, args...])
Both functions allocate and initialize a new popup menu and return the menu identifier (-1 if error).

fl_defpup() in addition accepts a pointer to the text you want to add as a menu item. 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 pup belongs. In a situation where pup is used inside an object callback (e.g., FL_MENU_BUTTON) FL_ObjWin(ob) would suffice.

It is possible to pair an "item type" flag with each menu item to specify particular attributes of the item, such as shortcuts and callbacks, etc. (not covered here, but see also fl_setpup_mode).

You can add more menu items to an existing popup menu using the following routine:

 void fl_addtopup(int menuID, const char *str [, args, ...]) 
To display a popup, use the following routine:
 int fl_dopup(int menuID) 
This function displays the specified popup menu until the user makes a selection. The value returned is the value of the item selected. However, if there are callback functions bound to the menu or menu item, the function is invoked and the value returned by fl_dopup is the executed function value. If no selection is made, function returns -1. To select an item, drag the mouse into the item and release the mouse.

It is also possible to bind keyboard keys to menu items (not covered here).

It is possible to modify the display characteristics of a given popup menu entry after its creation using the following routine:

 void fl_setpup_mode(int menuID, int item_num, unsigned mode) 
The following modes (and bitwise ORing thereof) are available:
  • FL_PUP_NONE: No special characteristics. The default.
  • FL_PUP_GREY: Entry is grayed-out and disabled. Selecting a grayed-out entry results in -1 being returned.
  • FL_PUP_BOX: Entry has an empty box to the left.
  • FL_PUP_CHECK: Entry has a box to the left.
  • FL_PUP_RADIO: Radio item, drawn with a box to the left.
Note radio item is drawn with a diamond box to the left while regular binary item is drawn with a square box to the left. Radio attribute set with FL_PUP_RADIO will have a unique and same group ID allocated internally by the popup if the item does not already belong to another radio group.

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

 unsigned int fl_getpup_mode(int menuID, int item_num) 
menuId is the ID returned by fl_newpup or fl_defpup. item_num is the value of the item (it can be an item in one of the submenus of menuID).

The following routine can be used to obtain the menu item text:

 const char *fl_getpup_text(int menuID, int item_num) 
In some situations, especially when the popup is activated by non-pointer events (e.g., as a result of an object shortcut) the default placement of popups based on mouse location might not be adequate or appropriate, thus XPup provides the following routine to override the default placement:
 void fl_setpup_position(int x, int y) 
pair x,y specifies the location where the top-left corner of the popup should be.

This routine should be used immediately before invoking fl_dopup() and the position is not remembered afterwards.

A radio group can be reset programmatically using the following routine:

 void fl_setpup_selection(int menuID, int item_val) 
Use the following routines to modify the default popup font style and size:
 void fl_setpup_fontsize(int size)
 void fl_setpup_fontstyle(int style) 
The background color and text color of a popup can be changed using the following routine:
 void fl_setpup_color(FL_COLOR bkcolor, FL_COLOR textcolor) 
By default, bkcolor is FL_COL1 and textcolor is FL_BLACK.

For item that has check box assocaited with it, the checked color (the default is blue) can be changed with the following routine:

 void fl_setpup_checkcolor(FL_COLOR checkcolor) 

3.6- OTHER OBJECTS

3.6.1- TIMER

Timer objects can be used to make a timer that runs down toward 0.0 after which it starts blinking and returns itself to the application program. Also a hidden timer object can be created. In this case the application program can take action at the moment the timer expires.

To add a timer to a form you use the routine:

 FL_OBJECT *fl_add_timer(int type, FL_Coord x, FL_Coord y, 
                         FL_Coord w, FL_Coord h, const char *label)
There are at the moment three types of timers:
  • FL_NORMAL_TIMER: Visible, Shows label in box. Blinks if time expires.
  • FL_VALUE_TIMER: Visible, showing the time left. Blinks if time expires.
  • FL_HIDDEN_TIMER: Not visible.
When a visible timer expires it starts blinking. The user can stop the blinking by pressing the mouse on it. The timer object is returned to the application program at the moment the time expires.

To set the timer to a particular value use:

 void fl_set_timer(FL_OBJECT *obj, double delay) 
delay gives the number of seconds the timer should run. Use 0.0 to reset the timer.

To obtain the current delay left in the timer use:

 double fl_get_timer(FL_OBJECT *obj) 
Attribute Color1 controls the color of the timer. Color2 is the blinking color.

3.6.2- XYPLOT

The xyPlot object gives you an easy way to display a tabulated function generated on the fly or from an existing data file. An active xyplot is also available to model and/or change a function.

To add an xyplot object to a form use the routine:

 FL_OBJECT *fl_add_xyplot(int type, FL_Coord x, FL_Coord y,
                          FL_Coord w, FL_Coord h, const char *label)
It shows an empty box on the screen with the label below it. The following types are available:
  • FL_NORMAL_XYPLOT: solid line
  • FL_SQUARE_XYPLOT: solid line plus squares on data points
  • FL_CIRCLE_XYPLOT: solid line plus circles on data points
  • FL_FILLED_XYPLOT: the area under the curve is filled
  • FL_POINTS_XYPLOT: only data points are shown
  • FL_DASHED_XYPLOT: dashed line
  • FL_IMPULSE_XYPLOT: vertical line
  • FL_ACTIVE_XYPLOT: accepts manipulations
  • FL_EMPTY_XYPLOT: draws only the axes
All xyplots display the curve auto-scaled to fit the plotting area. Although there is no limitation on the actual data, a non-monotonic increasing X might be plotted incorrectly. For FL_ACTIVE_PLOT, the x data must be monotonically increasing.

Only FL_ACTIVE_XYPLOT takes mouse events by default. Clicking and dragging the data points (marked with little squares) will change the data and result in the object returned to the program. By default, the reporting happens only when the mouse is released.

In some situations, reporting changes as soon as they happen might be desirable. Use the following to force this behavior:

 void fl_set_xyplot_return(FL_OBJECT *ob, int when) 
To obtain the current value of the point that has changed, use the following routine:
 void fl_get_xyplot(FL_OBJECT *ob, float *x, float *y, int *i) 
where i is returned as the data index (starting from 0) and x,y is the actual data point. If no point is changed, i is set to -1.

To set or replace the data for an xyplot, use:

 void fl_set_xyplot_data(FL_OBJECT *obj, float *x, float *y, int n, 
           const char *title, const char *xlabel, const char *ylabel)
x,y is the tabulated function, and n is the number of data points.
If the xyplot being set exists already, old data will be cleared. Note that the tabulated function is copied internally so you can free or do whatever with x,y after the function returns.

To load a tabulated function from a file use the following routine:

 void fl_set_xyplot_file(FL_OBJECT *obj, const char *filename,
         const char *title, const char *xlabel, const char *ylabel)
The data file should be an ASCII file consisting of data lines. Each data line must have two columns indicating the (x,y) pair with space, tab or comma separating the two columns. Lines that start with ! ; # are considered to be comments and are ignored.

To get a copy of the current FL_XYPLOT data, use:

 void fl_get_xyplot_data(FL_OBJECT *ob, float x[], float y[], int *n)
The caller must supply the space for the data.

All xyplot objects can be made aware of mouse clicks by using the following routine:

 void fl_set_xyplot_inspect(FL_OBJECT *ob, int yes) 
Once an xyplot is in inspect mode, whenever the mouse is clicked and the mouse position is on one of the data point, the object is returned to the caller or whose callback is called. You can use fl_get_xyplot() to find out which point the mouse is clicked on.

There are several routines to change the appearance of an xyplot, but are not covered here.

Color1 controls the color of the box and Color2 controls the actual xyplot color.

3.7- CANVAS

A canvas is a managed plain X (sub)window.

To add a canvas to a form you use the routine:

 FL_OBJECT *fl_add_canvas(int type, FL_Coord x, FL_Coord y,
                      FL_Coord w, FL_Coord h, const char *label)
The label is not drawn but used as the window name for possible resource and playback purposes. The following types of canvases exist:
  • FL_NORMAL_CANVAS: Simple window.
  • FL_SCROLLED_CANVAS: Two scrollbars are added (not yet supported).
Canvas is designed to maximize the user's ability to deal with situations where standard form classes may not be flexible enough.

By default, the only event a canvas will receive is Expose. To receive other events, the application program has to select them. One way to do this is by adding an event handler.

To register an event handler, use:

 void fl_add_canvas_handler(FL_OBJECT *ob, int event, 
                            FL_HANDLE_CANVAS handler, void *user_data)
event is the XEvent type, e.g., Expose etc.

To remove a registered handler, use the following routine:

 void fl_remove_canvas_handler(FL_OBJECT *ob, int event, 
                               FL_CANVAS_HANDLER handler)
To obtain the window ID of a canvas, use the following routine:
 Window fl_get_canvas_id(FL_OBJECT *ob) 
or use the macro FL_ObjWin(canvas_object)

Of course, window ID has meaning only after the form is shown.

3.7.1- OPENGL CANVASES

The following routines work for OpenGL (under X) as well as Mesa, a free OpenGL clone.

To add an OpenGL canvas to a form, use the following routine:

 FL_OBJECT *fl_add_glcanvas(int type, FL_Coord x, FL_Coord y, 
                            FL_Coord w, FL_Coord h, const char *label)
where type is the same as the generic canvas.

A glcanvas so created will have the following attributes by default: GLX_RGBA, GLX_DEPTH_SIZE,1, GLX_RED_SIZE,1, GLX_GREEN_SIZE,1, GLX_BLUE_SIZE,1, GLX_DOUBLEBUFFER.

The application program can modify these defaults using the following routine (before the creation of glcanvases):

 void fl_set_glcanvas_defaults(const int *attributes) 
See glXChooseVisual for a list of valid attributes.

To get the current defaults, use the following routine:

 void fl_get_glcanvas_defaults(int *attributes)