This part describes all different object classes that are available in the Forms Library.
All available object classes are summarized in Table 12.1.
Table 12.1: List of object classes
For each class there is a section in this document that describes it. The section starts with a short description of the object, followed by the routine(s) to add it to a form. For (almost) all classes this routine 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)
Here type is the type of the object in its class. Most classes have many
different types. They are described in the section. x, y, w and 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.
For each object class the default placement of the label is described. When
the label starts with the character @
the label is not printed but
replaced by a symbol instead.
For each object class there is also a routine
FL_OBJECT *fl_create_NAME(int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label)
that only creates the object but does not put it in the form. This routine is useful for building hierarchical object classes. The routine is not described in the following sections.
An important aspect of objects is how interaction is performed with them. First of all there is the way in which the user interacts with the object and secondly it is indicated when the object changes status and is returned to the application program for some action. Both are described in the section.
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()
where
xxx
is the name of the attribute. When a specific object
is created and added to a form, it inherits many aspects of the
generic object or initializes the object attributes to its needed
defaults. Thus, in the following sections, only the object
specific routines are documented. Routines that set generic object
attributes are documented in Part v.
When appropriate, the effect of certain (generic) attributes of the objects
on the specific object is discussed. In particular it is indicated
what the effect of the routine fl_set_object_color()
is on
the appearance of the object. Also some remarks on possible boxtypes
are made.
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 meaning of the parameters is as usual. The label is default placed centered in the box.
The following types are available:
FL_UP_BOX
A box that comes out of the screen.
FL_DOWN_BOX
A box that goes down into the screen.
FL_FLAT_BOX
A flat box without a border.
FL_BORDER_BOX
A flat box with a border.
FL_FRAME_BOX
A flat box with an engraved frame.
FL_SHADOW_BOX
A flat box with a shadow.
FL_ROUNDED_BOX
A rounded box.
FL_RFLAT_BOX
A rounded box without a border.
FL_RSHADOW_BOX
A rounded box with a shadow.
FL_OVAL_BOX
An elliptic box.
FL_NO_BOX
No box at all, only a centered label.
No interaction takes place with boxes.
No other routines are available for boxes.
Color1 controls the color of the box.
Boxes are used in most demo's. Also see Fig. 3.1.
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. Use of frames can speed up drawing in
certain situations. For example, to place a group of
radio buttons within a FL_ENGRAVED_FRAME
. If we were
to use an FL_FRAME_BOX
to group the buttons, visually
they would look the same. However, the latter is faster as
we don't have to fill the interior of the bounding box
and can also reduce flicker. Frames are useful in decorating
free objects and canvases.
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 meaning of the parameters is as usual except that 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:
FL_NO_FRAME
Nothing is drawn
FL_UP_FRAME
A frame appears coming out of the screen
FL_DOWN_FRAME
A frame that goes down into the screen.
FL_BORDER_FRAME
A frame with a simple outline
FL_ENGRAVED_FRAME
A frame appears to be engraved.
FL_EMBOSSED_FRAME
A frame appears embossed .
FL_ROUNDED_FRAME
A rounded frame.
FL_OVAL_FRAME
An elliptic box.
No interaction takes place with frames.
None.
Color1 controls the color of the frame if applicable. Boxtype attribute does not apply to the frame class.
It is faster to use frames instead of boxes for text that is truly static. See freedraw.c for an example use of frame objects.
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 meaning of the parameters is as usual. 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.
No other routines are available for texts.
Any boxtype can be used for text.
Color1 controls the color of the box. The color of the text is controlled by
lcol as usual. However, if the text is to change dynamically, NO_BOX
should not be used.
Note that there is almost no difference between a box with a label and
a text. The only difference lies in the position where the text
is placed and the fact that text is clipped to the bounding box.
Text is normally placed inside the box at the left side.
This helps you putting different lines of text below each other.
Labels inside boxes are default centered in the box. You can change
the position of the text inside the box using the routine
fl_set_object_lalign()
. In contrast to boxes, when using different
alignments, the label is always placed inside the box rather than outside the
box.
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 meaning of the parameters is as usual. 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. For bitmap that
interacts, see Section 14.1 on bitmapbutton
.
(You can also place a hidden button over
it if you want something to happen when pressing the mouse on a
static 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.
Two additional routines are provided to make a Pixmap from a bitmap file or data
Pixmap fl_read_bitmapfile(Window win, const char *filename, unsigned *width, unsigned *height, int *hotx, int *hoty) Pixmap fl_create_from_bitmapdata(Window win, const char *data, int width, int height);
where win is any window ID in your application and other parameters
have the obvious meanings. If there is no window created yet,
fl_default_win()
may be used.
Note pixmaps created by the above routines have a depth of 1 and
should be displayed using XCopyPlane
.
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.
See demo33.c for a demo of a bitmap.
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 meaning of the parameters is as usual. The label is by default placed below the pixmap. The pixmap will be empty.
Only the type FL_NORMAL_PIXMAP
is available.
No interaction takes place with a pixmap. For pixmap that
interacts, see Section 14.1 on pixmapbutton
.
(You can also place a hidden button over
it if you want something to happen when pressing the mouse on a
static 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);
Where 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. If you're writing a pixmap browser
type applications, be sure to free the old pixmaps using
fl_free_pixmap_pixmap
prior to calling these two routines.
To obtain the pixmap ID currently being displayed, the following routine can be used
Pixmap fl_get_pixmap_pixmap(FL_OBJECT *ob, Pixmap *id, Pixmap *mask);
In some situations, you might already have a Pixmap resource
ID, e.g., from fl_read_pixmapfile
, you can use
the following routine to change the the pixmap
void fl_set_pixmap_pixmap(FL_OBJECT *ob, Pixmap id, Pixmap mask)
where mask is used for transparency (See fl_read_pixmapfile
.)
Use 0 for mask if no special clipping attributes are desired.
This routine does not free the pixmap ID nor the mask already associated with the object. Thus if you no longer need the old pixmaps, they should be freed prior to changing the pixmaps using the following routine
void fl_free_pixmap_pixmap(FL_OBJECT *ob);
This routine in addition to freeing the pixmap and the mask, it also frees the colors the pixmap allocated.
Pixmaps are by default displayed centered inside the bounding box. However, this can be changed using the following routine
void fl_set_pixmap_align(FL_OBJECT *ob, int align, int dx, int dy)
where align is the same as that used for labels. See Section 3.11.3 for a list. dx and dy are extra margins to leave in addition to the object border width. By default, dx and dy are set to 3. Note that although you can place a pixmap outside of the bounding box, it probably is not a good idea.
By default, if a pixmap has more colors than that available in the colormap, the library will use substitute colors that are judged ``close enough". This closeness is defined as the difference between the requested color and color found being smaller than some pre-set threshold values between 0 and 65535 (0 means exact match). The default thresholds are 40000 for red, 30000 for green and 50000 for blue. The change these defaults, use the following routine
void fl_set_pixmap_colorcloseness(int red, int green, int blue);
The following routines may come in handy to read a pixmap file into a Pixmap
Pixmap fl_read_pixmapfile(Window win, const char *filename, unsigned *width, unsigned *height, Pixmap *shape_mask, int *hotx, int *hoty, FL_COLOR tran)
where win is the window in which the pixmap is to be displayed. If
the window is yet to be created, you can use the default window
fl_default_window()
.
Parameter shape_mask is set to a Pixmap, if not null, that can be
used as a clip mask to achieve transparency. Parameter tran is
currently un-used.
If you have already had the pixmap data in memory, the following routine may be used
Pixmap fl_create_from_pixmapdata(Window win, char **data, unsigned *width, unsigned *height, Pixmap *shape_mask, int *hotx, int *hoty, FL_COLOR tran)
All parameters have the same meaning as in fl_read_pixmapfile
.
Note the Forms Library handles transparency,
if specified in the pixmap file or data,
for pixmap and pixmapbutton objects. However, when using
fl_read_pixmapfile
or fl_create_from_pixmapdata
,
the application programmer is responsible to set the clip mask
in appropriate GCs.
Finally there is a routine that can be used to free a Pixmap
void fl_free_pixmap(Pixmap Id)
You will need the XPM library developed by
Arnaud Le Hors and GROUPE BULL (lehors@sophia.inria.fr
)
to use pixmap. XPM library can be obtained from many X distribution/mirror
sites via anonymous ftp
(ftp://ftp.x.org/contrib and ftp://avahi.inria.fr/pub/xpm are the
official sites).
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 meaning of the parameters is as usual. The label is default placed below the clock.
The following types are available:
FL_ANALOG_CLOCK
An analog clock complete with the second hand.
FL_DIGITAL_CLOCK
A digital clock.
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)
Never use FL_NO_BOX
as boxtype for a digital clock.
Color1 controls the color of the background, color2 the color of the hands.
See flclock.c for an example of the use of clocks.
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:
FL_BAR_CHART
A bar-chart
FL_HORBAR_CHART
A horizontal bar-chart
FL_LINE_CHART
A line-chart
FL_FILLED_CHART
A line-chart but area below curve is filled
FL_SPIKE_CHART
A chart with a vertical spike for each value
FL_PIE_CHART
A pie-chart
FL_SPECIALPIE_CHART
A pie-chart with displaced first item
All charts except pie-charts can display positive and negative data.
Pie-charts will ignore values that are 0. The maximal number of
values displayed in the chart can be set using the routine
fl_set_chart_maxnumb()
. The number must be bounded by
FL_CHART_MAX
which is 256. Switching between different types can
be done without any complications.
No interaction takes place with charts.
There are a number of routines to change the values in the chart and to change its behavior. 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)
Here 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. So, for example, to make a strip-chart where the new value appears at the left, each time insert the new value before index 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)
Here 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.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
) can be changed using
void fl_set_chart_maxnumb(FL_OBJECT *obj, int maxnumb)
where maxnumb is the maximal number of items to be displayed.
Don't use FL_NO_BOX
for a chart object if it changes value.
Color1 controls the color of the box.
See chartall.c and chartstrip.c for examples of the use of chart objects.
A very important class of objects are the buttons. Buttons are placed on the form such that the user can push them with the mouse. Different types of buttons exist: buttons that return to their normal position when the user releases the mouse, buttons that stay pushed until the user pushes them again and radio buttons that make other buttons be released.
Also different shapes of buttons exist. Normal buttons are rectangles that come out of the background. When the user pushes them they go into the background (and possibly change color). Lightbuttons have a small light inside them. Pushing the button switches the light on. Round buttons are simple circles. When pushed, a colored circle appears inside them. Bitmap and pixmap buttons are buttons whose labels are graphics rather than text.
To add buttons 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) FL_OBJECT *fl_add_bitmapbutton(int type, FL_Coord x, FL_Coord y, FL_Coord w,FL_Coord h, const char *label) FL_OBJECT *fl_add_pixmapbutton(int type, FL_Coord x, FL_Coord y, FL_Coord w,FL_Coord h, const char *label)
The meaning of the parameters is as usual. 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.
The following types of buttons are available:
FL_NORMAL_BUTTON
Returns value when released.
FL_PUSH_BUTTON
Stays pushed until user pushes it again.
FL_MENU_BUTTON
Returns value when pushed.
FL_TOUCH_BUTTON
Returns value as long as the user pushes it.
FL_RADIO_BUTTON
Push button that switches off other radio buttons.
FL_HIDDEN_BUTTON
Invisible normal button.
FL_INOUT_BUTTON
Returns value both when pushed and when released.
FL_RETURN_BUTTON
Like a normal button but reacts on the <Return> key.
FL_HIDDEN_RET_BUTTON
Invisible return button.
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 (see below). 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_BUTTON
s, FL_PUSH_BUTTON
s, FL_RADIO_BUTTON
s,
FL_RETURN_BUTTON
s and
FL_HIDDEN_BUTTON
s 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)
Sometimes you want to give the button a different meaning depending on which mouse button pressed it. 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 (see below), the function
returns the keysym (ascii value if ASCII) of the key plus
FL_SHORTCUT
. For example, if a button has a shortcut <CNTRL> C,
the button number returned upon activation of the shortcut
would be FL_SHORTCUT
3+.
If more information is desired about the last event, use
const XEvent *fl_last_event(void);
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. So, e.g., 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.)
Be careful with your choices. When the form also contains input fields you
probably don't want to use the normal printable characters because they
can no longer be used for input in the input fields.
Shortcuts always go before input fields.
Other special keys, such as <F1> etc., can also be used as
shortcuts. See Section 21.1 for details.
Finally realize that a return button is in fact a normal button with the
<Return> key as a shortcut. So don't change the shortcuts for such a
button.
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 (i.e., special characters such as #
and ^
are ignored when matching).
A false showUL turns off the underline without affecting
the shortcut. Note that although the entire object label is searched for
matching character to underline, the shortcut string itself is not
searched, thus shortcut ``Yy" for label ``Yes" will result
in the underlining of Y while ``yY" will not.
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);
This function frees the pixmap and mask together with all the colors they allocated.
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)
where align is the same as that used for labels. See Section 3.11.3 for a list. xmargin and ymargin are extra margins to leave in additional to the object border width. Note that although you can place a pixmap outside of the bounding box, it probably is not a good idea.
See also Section 13.5 for pixmap color and transparency handling.
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 foreground color of the bitmap is controlled by label color.
See all demo programs, in particular pushbutton.c and buttonall.c,
for the use of buttons. FL_INOUT_BUTTON
s are e.g. used in the
buttonbox.
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 this 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)
or
FL_OBJECT *fl_add_valslider(int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label)
The meaning of the parameters is as usual. The label is by default placed below the slider. The second type of slider displays its value above or to the left of the slider.
The following types of sliders are available:
FL_VERT_SLIDER
A vertical slider.
FL_HOR_SLIDER
A horizontal slider.
FL_VERT_FILL_SLIDER
A vertical slider, filled from the bottom.
FL_HOR_FILL_SLIDER
A horizontal slider, filled from the left.
FL_VERT_NICE_SLIDER
A nice looking vertical slider.
FL_HOR_NICE_SLIDER
A nice looking horizontal slider.
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 <SHIFT> 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)
where parameter when can be one of the four values
To change the value of the slider use the routines
void fl_set_slider_value(FL_OBJECT *obj, double val) void fl_set_slider_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. For vertical sliders, min and max indicate, respectively,
the values at the top and the bottom of the sliders,
thus max > min
needs not be
observed.
To obtain the current values of the slider use
double fl_get_slider_value(FL_OBJECT *obj) void fl_get_slider_bounds(FL_OBJECT *obj, double *min, double *max)
In a number of situations you would like slider values to be rounded to some values, e.g. to integer values. To this end use the routine
void fl_set_slider_step(FL_OBJECT *obj, double step)
After this call slider values will be rounded to multiples of step. Use the value 0.0 to stop rounding.
Never use FL_NO_BOX
as boxtype for a slider.
For FL_VERT_NICE_SLIDER
s and FL_HOR_NICE_SLIDER
s one best uses a
FL_FLAT_BOX
in the color of the background to get the nicest effect.
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. This only applies to
FL_VERT_SLIDER
and FL_HOR_SLIDER
.
The routine
void fl_set_slider_precision(FL_OBJECT *obj, int prec)
sets the precision with which the value of the slider is shown. This only applies to sliders showing their value.
By default, the value shown by valslider is the slider value in floating point format. You can override the default by registering a filter function using the following routine
void fl_set_slider_filter(FL_OBJECT *obj, const char *(*filter)(FL_OBJECT *, double value, int prec));
where value and prec are the slider value and precision respectively. The filter function filter should return a string that is to be shown. Note that the default filter is equivalent to the following
const char *filter(FL_OBJECT *ob, doube value, int prec) { static char buf[32]; sprintf(buf, "%.*f",prec,value); return buf; }
See the demo program demo05.c for an example of the use of sliders. See demos sldsize.c and sliderall.c for the effect of setting slider sizes and the different types of sliders.
Although all function prototypes would indicate that sliders have a resolution of a double, this is not true. All internal calculations are done with float precision.
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 meaning of the parameters is as usual. 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 a 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)
where 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)
In a number of situations you might want dial values to be rounded to some values, e.g. to integer values. To this end use the routine
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.
You can use any boxtype you like. Default is FL_NO_BOX
.
Color1 controls the color of the background of the dial, color2 the color of the knob or the line.
The resolution of a dial is about 0.2 degrees, i.e., there are only about 2000 steps per 360 degrees and depending on the size of the dial, it is typically less.
See the demo program ldial.c and ndial.c\ for examples of the use of dials.
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 meaning of the parameters is as usual. The label is placed below the box by default.
Only one type of positioner exists at the moment:
FL_NORMAL_POSITIONER
Cross-hair inside a box.
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)
In a number of situations you would like positioner values to be rounded to some values, e.g. to integer values. To this end use the routines
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.
Never use FL_NO_BOX
for a positioner.
Color1 controls the color of the box, color2 the color of the cross-hair.
A demo can be found in positioner.c.
A counter provides a different mechanism for the user to indicate a value. In 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 meaning of the parameters is as usual. 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)
To set the precision (number of digits behind the dot) with which the counter value is displayed use the routine
double fl_set_counter_precision(FL_OBJECT *obj,int prec)
By default, the value shown is the counter value in floating point format. You can override the default by registering a filter function using the following routine
void fl_set_counter_filter(FL_OBJECT *obj, const char *(*filter)(FL_OBJECT *, double value, int prec));
where value and prec are the counter value and precision respectively. The filter function filter should return a string that is to be shown. Note that the default filter is equivalent to the following
const char *filter(FL_OBJECT *ob, doube value, int prec) { static char buf[32]; sprintf(buf, "%.*f",prec,value); return buf; }
Never use FL_NO_BOX
as boxtype for a counter.
Color1 controls the color of the background of the counter, color2 the color of
the arrows in the counter.
Although function prototypes give the impression that a counter has a resolution of a double, this is not true. Internal calculation is done entirely in float precision. The reason of using doubles as function parameters is to workaround bugs in some C++ compilers that always promote floats to doubles for C functions.
See counter.c for an example of the use of counters.
It is often required to obtain textual input from the user, e.g. a file name, some fields in a database, etc. To this end input fields exist in the Forms Library. 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 meaning of the parameters is as usual. 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 (e.g. -23.2e12).
FL_INT_INPUT
Only an integer value can be typed in (e.g. -86).
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 invisible.
A normal input field can contain one line of text, to be typed in by the user. A float input field can only contain a float number. If the user tries to type in something other than digits, it is not shown and the bell is sounded. Similarly, an int input field can only contain an integer number. 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. This can be used for getting passwords, for example. 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. The user can use the following keys (as in emacs(1)) for maneuvering inside the input field:
In addition to the above keys, <CNTRL> L can be used to refresh the input field.
There are three ways to select part of the input field. Dragging, double-click and triple-click. Double-click selects the word the mouse is on and triple-click selects the entire line the mouse is on. The selected part of the input field is removed when the user types the <BACKSPACE> key or replaced by what the user types in. Also the cursor can be placed at different positions in the input field using the mouse.
One additional property of selecting part of the text field is that if the selection is done with the leftmouse the selected part becomes the primary (XA_PRIMARY) selection of the X Selection mechanism, thus other applications, e.g., xterm, can request this selection. Conversely, the cutbuffers from other applications can be pasted into the input field. Use the middle mouse for pasting. Note <CNTRL> y only pastes the cutbuffer generated by <CNTRL> k and is not related to the X Selection mechanism, thus it only works within the same application.
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.
The above mechanism is the default behavior of an input field. Depending
on the application, other options might be useful. To change the
precise condition for the object to be returned (or equivalently
the callback invoked), the following function can be used:.
void fl_set_input_return(FL_OBJECT *obj, int when)
Where when can take one of the following values:
modified or not.
Although an input with FL_RETURN_ALWAYS
attributes can be
used to limit the type of characters that can be entered into
the input field, use of the following is typically more appropriate
typedef int (*FILTER)(const char *old, const char *cur, int c); FILTER fl_set_input_filter(FL_OBJECT *ob, FILTER filter);
The filter function is called whenever a new (regular) character is
entered. old is the string in the input field before the
newly typed character c is merged into cur.
If the new character is not an acceptable character
for the input field, the filter function should return
FL_INVALID
otherwise FL_VALID
. If FL_INVALID
is returned, the new character is discarded and the input field remains
unmodified. The function returns the old filter. Unlike
the built-in filters, keyboard bell is not sound when
FL_INVALID
is received. To sound the bell, return
FL_INVALID|FL_RINGBELL
.
Finally, there is a routine that can be used to limit the number of characters per line
void fl_set_input_maxchars(FL_OBJECT *ob, int maxchars);
To reset the limit to infinite, set maxchars to 0.
Currently this function only works in FL_NORMAL_INPUT
.
Note that the label is not the default text in the input field.
To set the contents of the input field use the routine
void fl_set_input(FL_OBJECT *obj, char str[])
Setting the content of an input field does not trigger object event, i.e., the object callback is not called. In some situations you might want to have the callback invoked. For this, use the following the routine
void fl_call_object_callback(FL_OBJECT *obj)
To obtain the string in the field (when the user has changed it) use:
[const] char *fl_get_input(FL_OBJECT *obj)
To select or deselect the current input or part of it, the following two routines can be used
void fl_set_input_selected(FL_OBJECT *ob, int flag) void fl_set_input_selected_range(FL_OBJECT *ob, int start, int end)
where start and end are measured in characters. When
start is 0 and end equals the number of characters in
the string, fl_set_input_selected()
makes the entire
input field selected. However, there is a subtle difference
between this and fl_set_input_selected()
with flag==1
.
fl_set_input_selected()
always places the cursor at
the end of the string while fl_set_input_selected_range()
places the cursor at the beginning of the selection.
It is possible to move the cursor within the input field programmatically using the following routine
void fl_set_input_cursorpos(FL_OBJECT *ob, int xpos, int ypos)
where xpos and ypos are measured in characters (lines).
E.g., given the input field, "an arbitrary string"
, the call
fl_set_input_cursorpos(ob, 4, y)
places the the cursor
after the character <A> in arbitrary.
Note currently this function only works correctly in FL_NORMAL_INPUT
and does not do anything with ypos.
There is also a function that returns the cursor position within the input field
int fl_get_input_cursorpos(FL_OBJECT *ob, int *xpos, int *ypos)
Where xpos and ypos are the cursor positions measured
in characters (lines) and xpos always gives the number of
characters in front of the cursor. If the input field does not
input focus (thus has no cursor), the xpos is set to -1.
Currently this function works for FL_NORMAL_INPUT
and
ypos always returns 1.
Shortcut keys can be associated with an input field to switch input focus. To this end, use the following routine
void fl_set_input_shortcut(FL_OBJECT *obj, const char *sc, int showit)
Scrolling might not always be desirable and you can disable input field scrolling using the following routine with a false flag
void fl_set_input_scroll(FL_OBJECT *obj, int flag)
Never use FL_NO_BOX
as boxtype.
Color1 controls the color of the input field when it is not selected and color2 is the color when selected.
To change the color of the input text or the cursor use
void fl_set_input_color(FL_OBJECT *obj, int tcol, int ccol)
Here tcol indicates the color of the text and ccol is the color of the cursor.
See the program demo06.c for an example of the use of input fields. See minput.c for multi-line input fields. See secretinput.c for secret input fields.
Also menus can be added to forms. These menus can be used to let the user choose from many different possibilities. Each menu object has a box with a label in it in the form. Whenever the user presses the mouse inside the box (or moves the mouse on top of the box) a pop-up menu appears. The user can then make a selection from the menu.
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 move the mouse inside it.
PUSH_MENU
and PULLDOWN_MENU
behaves 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 (see Fig. 17.1).
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 (See Section 18.3. In short, it should contain the menu items, separated by a bar, e.g., ``First|Second|Third''. See Section 18.3 for special tags that can be used to indicate special attributes (radio, toggle for example). 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 the following function
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)
This is sometimes easier to use than defining the whole menu string at once (especially when the contents of a menu change from time to time).
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)
Here mode is the display characteristics you want to apply to the chosen entry. You can specify more than one at a time by adding or bitwise OR-ing these values together. For this parameter, the following symbolic constants exist:
There is also a routine that can be used to obtain the current mode of an item after interaction, mostly useful for toggle or radio items:
unsigned int fl_get_menu_item_mode(FL_OBJECT *ob, int numb)
It is often useful to define keyboard shortcuts for particular menu items. For example, it would be nice to have <ALT> s behave like selecting Save from a menu. This can be done using the following routine:
void fl_set_menu_item_shortcut(FL_OBJECT *obj,int numb,const char *str)
str contains the shortcut for the item. (Actually, it can contain more shortcuts for the same item.) See the description of the button object class for more information about shortcuts.
Finally there is the routine:
void fl_show_menu_symbol(FL_OBJECT *obj, int show)
With this routine you can indicate whether to show a menu symbol at the right of the menu label. By default no symbol is shown.
Any boxtype can be used for a menu except for PULLDOWN_MENU
for which nobox should not be used.
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.
See menu.c for an example of the use of menus. Cascade
menus are not directly supported. You can use
FL_MENU_BUTTON
to initiate a callback and
use XPopup
directly within the callback. See pup.c for
an example of this approach.
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.
There are a number of routines to change the list of possible choices. The items in the list are numbered in the order in which they are inserted. The first item has number 1, etc. Whenever the application program wants to clear the list of choices it should use the routine
void fl_clear_choice(FL_OBJECT *obj)
To add a line to a choice object use
void fl_addto_choice(FL_OBJECT *obj, const char *text)
To delete a line use:
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 following routine
const char *fl_get_choice_item_text(FL_OBJECT *obj, int n)
To obtain the total number of choices (items), use the following function
int fl_get_choice_maxitems(FL_OBJECT *obj)
One can set various attributes of an item using the following routine
void fl_set_choice_item_mode(FL_OBJECT *ob, int numb, unsigned mode)
Here mode is the same as that used in menu object. See also Section 18.3 for details.
Finally, the application program can set the choice itself using the call
void fl_set_choice(FL_OBJECT *obj, int line) void fl_set_choice_text(FL_OBJECT *obj, const char *txt)
where txt must be exactly the same as the item added in
fl_addto_choice
. For example, after the following choice
is created
fl_addto_choice(obj,"item1 | item2 | item3");
You can select item2 by using
fl_set_choice(obj, 2)
or
fl_set_choice_text(obj, " item2 ");
Note the spaces in the text.
Don't use FL_NO_BOX
for a choice object.
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 the following routine
void fl_set_choice_align(FL_OBJECT *ob, int align)
To set the font size used inside the choice object use
void fl_set_choice_fontsize(FL_OBJECT *obj, int size)
To set the font style used inside the choice object use
void fl_set_choice_fontstyle(FL_OBJECT *obj, int style)
Note that the above functions only change the font inside the choice object, not the font used in the popup. To change the font used in the popup, use
void fl_setpup_fontsize(int size) void fl_setpup_fontstyle(int style)
See section 3.11.3 for details on font sizes and styles.
See choice.c for an example of the use of choice objects.
The object class browser is probably the most powerful that currently exists in the Forms Library. 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 meaning of the parameters is as usual. The label is placed below the box by default.
The following types of browsers exist (see below for more information about them):
FL_NORMAL_BROWSER
A browser in which no selections can be made.
FL_SELECT_BROWSER
In this case 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.
Hence, the difference only lies in how the selection process works.
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()
to be described below. It returns the
number of the last selected line. (Top line is line 1.)
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()
described below) which line was selected. It returns the
number of the last selected line. When the last line was de-selected it returns
the negation of the line number. I.e., if line 10 was selected last the routine
returns 10 and if line 10 was de-selected last, it returns -10.
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.
There are a large number of routines to change the contents of a browser, select and de-select lines, etc.
void fl_clear_browser(FL_OBJECT *obj)
To add a line to a browser use
void fl_add_browser_line(FL_OBJECT *obj, const char *text)
A second way of adding a line to the browser uses the call
void fl_addto_browser(FL_OBJECT *obj, const char *text)
The difference is that with this call the browser will be shifted such that the newly added line is visible. This is useful when, e.g., using the browser for displaying messages.
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 *text)
Making many changes to a visible browser at the same moment, i.e., clearing it
and loading it with a number of new choices, 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()
.
So a piece of code that fills in a visible browser should preferably look
like the following
fl_freeze_form(form); fl_clear_browser(brow); fl_add_browser_line(brow,"line 1"); fl_add_browser_line(brow,"line 2"); . . . fl_unfreeze_form(form);
where form is the form that contains object brow.
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. This routine is particularly useful when using the browser for a help facility. You can make different help files and load the one corresponding to the context.
The application program can select or de-select lines in the browser. To this end the following calls exist with the obvious meaning:
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 *obj)
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 routine
int fl_get_browser_maxline(FL_OBJECT *obj)
returns the number of lines in the browser. For example, when the application
program wants to figure out which lines in a FL_MULTI_BROWSER
are
selected the following piece of code can be used:
int total_lines = fl_get_browser_maxline(brow); for (i=1; i <= total_lines; i++) if (fl_isselected_browser_line(brow,i)) /* Handle the selected line */
Sometimes it is useful to know how many lines are visible in the browser. To this end, the following call can be used
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). When the last action was a de-selection (only for
FL_MULTI_BROWSER
's) a negative 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 there is a routine that can be used to scroll the text horizontally
void fl_set_browser_xoffset(FL_OBJECT *ob, FL_Coord xoff)
where xoff is in pixels.
Never use the boxtype FL_NO_BOX
for browsers.
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 used inside the browser use
void fl_set_browser_fontsize(FL_OBJECT *obj, int size)
To set the font style used inside the browser use
void fl_set_browser_fontstyle(FL_OBJECT *obj, int style)
See section 3.11.3 for details on font sizes and styles.
It is possible to change the appearance of individual lines in the browser.
Whenever the line starts with the symbol @
the next letter indicates
the special characteristic associated with this line. The following
possibilities exist at the moment:
f
Fixed width font.
n
Normal (Helvetica) font.
t
Times-Roman like font.
b
Boldface. Modifier
i
Italic. Modifier
l
Large (new size = FL_LARGE_SIZE).
m
Medium (new size = FL_MEDIUM_SIZE).
s
Small (new size = FL_SMALL_SIZE).
L
Large (current size += 6)
M
Medium (current size += 4)
S
Small (current size -= 2).
c
Centered.
r
Right aligned.
_
Draw underlined text.
-
An engraved separator. Text following - is ignored.
C
The next number indicates the color index of this line.
N
Non-selectable line (in selectable browsers).
@
Regular@
character.
More than one option can be used by putting them next to each other.
For example, @C1@l@f@b@cTitle
will give you a red,
large, bold fixed font, centered word Title. As you can see,
the font change requests accumulate and the order is important, i.e.,
@f@b@i
gives you a fixed bold italic font while
@b@i@f
gives you a (plain) fixed font.
One word of caution is required here: The line spacing inside the browser
is not changed! Hence, when using a large line, you had better take care that
there is an empty line above and below it. In some cases the character
@
might need to be placed at the beginning of the lines without
introducing the special meaning mentioned above. In this
case you can use @@
or change the special character to something other
than @
using the following routine
void fl_set_browser_specialkey(FL_OBJECT *ob, int key)
To align different text fields on a line, tabs (\t
) can
be embedded in the text.
By default, the scroll bar is drawn to the right of the browser. It can easily be changed to be drawn to the left of the browser:
void fl_set_browser_leftslider(FL_OBJECT *ob, int yes)
There is also a routine that can be used to turn the (vertical) scrollbar on and off
void fl_set_browser_vscrollbar(FL_OBJECT *ob, int on)
The following table gives the possible values and their meanings:
Note FL_ALWAYS_ON
is 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)
where x and y are measured from the top-left corner of the form (or the smallest enclosing window).
There is currently a limit of maximum 1024 bytes per line for
fl_load_browser()
.
See demo11.c for an example program using a FL_NORMAL_BROWSER
to view files. browserall.c shows all different browsers.
browserop.c shows the
insertion and deletion of lines in
a FL_HOLD_BROWSER
.
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. This can be used in many different ways. For example, to give a user a particular amount of time for a task, etc. Also a hidden timer object can be created. In this case the application program can take action at the moment the timer expires. For example, you can use this to show a message that remains visible until the user presses the OK button or until a particular amount of time has passed.
The precision of the timer is not very good. Don't count on anything better than say .2 seconds.
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)
The meaning of the parameters is as usual.
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)
Never use FL_NO_BOX
as boxtype for FL_VALUE_TIMER
's.
Color1 controls the color of the timer. Color2 is the blinking color.
See timer.c for the use of timers.
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, and in that
case, 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) while 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)
Here 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.
You can also load a tabulated function from a file using 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. First of all, you can change the number of tic marks using the following routine
void fl_set_xyplot_xtics(FL_OBJECT *ob, int major, int minor); void fl_set_xyplot_ytics(FL_OBJECT *ob, int major, int minor);
here major and minor are the number of tic marks to be
placed on the plot. In particular, -1
suppresses the tic marks
completely while 0
restores the default settings.
Note that the actual scaling routine may choose a value other than that requested if it decides that this would make the plot look nicer, thus major minor can only be taken as a hint to the scaling routine. However, in no case will the scaling routine generate a major that differs from the requested value by more than 3.
To change the size of the symbols draw on the data point, use the following routine
void fl_set_xyplot_symbolsize(FL_OBJECT *ob, int size)
where size should be given in pixels. The default is 4.
To use absolute bounds as opposed to actual bounds in data, use the following routines
void fl_set_xyplot_xbounds(FL_OBJECT *ob, double min, double max); void fl_set_xyplot_ybounds(FL_OBJECT *ob, double min, double max);
Data that fall outside of the range will be clipped. To restore
autoscaling, use max<=min
.
To get the current bounds, use the following routines
void fl_get_xyplot_xbounds(FL_OBJECT *ob, float *min, float *max); void fl_get_xyplot_ybounds(FL_OBJECT *ob, float *min, float *max);
To replace the value of a particular point use the routine
void fl_replace_xyplot_point(FL_OBJECT *obj,int i,double x,double y)
Here index is the index of the value to be replaced. The first value has the index of 0.
It is possible to place inset texts on an xyplot using the following
routine (up to FL_MAX_XYPLOTOVERLAY
, or the value set via
fl_set_xyplot_maxoverlays
, of such insets can be accommodated):
void fl_add_xyplot_text(FL_OBJECT *obj, double x, double y, const char *text, int align, FL_COLOR col);
where x and y are the coordinates where text is to
be placed and align specifies the placement options
relative to the specified point.
(See fl_set_object_lalign()
for valid options).
To remove an inset text, use the following routine
void fl_delete_xyplot_text(FL_OBJECT *obj, const char *text);
It is also possible to overlay several plots together using the following call
void fl_add_xyplot_overlay(FL_OBJECT *obj, int ID, float *x, float *y, int npoints, FL_COLOR col)
where ID must be between 1 and FL_MAX_XYPLOTOVERLAY
(32)
inclusive. Again, the data is copied internally (old data freed if any)
The type (FL_NORMAL_XYPLOT
etc.) used is the same
as the object itself. To change an overlay style, use the following call
void fl_set_xyplot_overlay_type(FL_OBJECT *obj, int ID, int type)
Note although the API of adding an overlay is similar to adding an object, an xyplot overlay is not a separate object. It is simply a property of an xyplot object.
If needed, the maximum number of overlays an object can have (which by default is 32) can be changed using the following routine
int fl_set_xyplot_maxoverlays(FL_OBJECT *ob, int maxoverlays)
The function returns the previous maximum number of overlays.
To delete an overlay, use the following routine
void fl_delete_xyplot_overlay(FL_OBJECT *obj, int ID)
Data may be interpolated using n order Lagrangian polynomial
void fl_set_xyplot_interpolate(FL_OBJECT *ob, int ID, int degree, double grid)
where ID is the overlay ID (use 0 for the original data) of the xyplot; degree is the order of the polynomial to use and grid is the working grid onto which the data are to be interpolated.
By default, linear scale in both the X and Y direction is used. To change the scaling, use the following call
void fl_set_xyplot_xscale(FL_OBJECT *ob, int scale, double base) void fl_set_xyplot_yscale(FL_OBJECT *ob, int scale, double base)
where the valid scaling options for scale
are FL_LINEAR
and FL_LOG
, and base is used
only for FL_LOG
and in that case it is the base of the log desired.
The mapping between the screen coordinates and data can be obtained using the following routines
void fl_get_xyplot_xmapping(FL_OBJECT *ob, float *a, float *b) void fl_get_xyplot_xmapping(FL_OBJECT *ob, float *a, float *b)
where a and b are the mapping constants and are used as follows
If you need to do conversions only occasionally (for example, converting the position of a mouse click to a data point or vice versa) the following routines might be more convenient
void fl_xyplot_s2w(FL_OBJECT *ob, double sx, double sy, float *wx, float *wy); void fl_xyplot_w2s(FL_OBJECT *ob, double wx, double wy, float *sx, float *sy);
where sx and sy are the screen coordinates and wx and wy are the world coordinates.
Finally there are routines to change the font size and style for labels, inset text etc:
fl_set_xyplot_fontsize(FL_OBJECT *ob, int size); fl_set_xyplot_fontstyle(FL_OBJECT *ob, int style);
Don't use FL_NO_BOX
for an xyplot object that is to be
changed dynamically.
The interpolation routine is public and can be used in the application program
int fl_interpolate(const float *inx, const float *iny, int num_in, float *outx, float *outy, double grid, int ndeg)
If successful, the function returns the number of points
((inx[num_in-1] - inx[0]) / grid + 1.01
)
in the interpolated function else it returns -1.
Color1 controls the color of the box and Color2 controls the actual xyplot color.
See xyplotall.c and xyplotactive.c for examples of the use of xyplot objects. There is also an example xyplotover.c showing the use of overlay. In addition, xyplotall.c shows a way of getting all mouse clicks without using active xyplot.
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. If an item requires an argument because of the type, the argument must be supplied by the variable arguments arg.
The following menu types are supported (to get a normal %, stack two together just like in printf):
%F
.
arg
parameter.
The value of the menu item is passed as a parameter of
the routine. If you have also bound the entire menu to
a callback function via %F
, then the result
of the %f
routine is passed as a parameter of the
%F
routine.
#
to specify <ALT>,
^
<CONTROL>, and &n
key Fn
.
FL_PUP_BOX
.
%b
except it also signifies this item is ``true''
and consequently the item is drawn with a checked box on the left.
See also FL_PUP_CHECK
.
g
. Group number g
must be positive
and within (1-64). A radio group is drawn with a small
diamond box to the left.
%rg
except that it also sets the state of
the radio item as ``pushed", i.e., the item is drawn with
a diamon box to the left. See also fl_setpup_selection()
.
%l
except that the character
must precede the item label, i.e., use "\010Abc"
rather
than "Abc\010"
.
Due to variable arguments, error checking is minimal. In addition,
if %x
is used to specify a value that happens to be
identical to a position-based value, the result is unpredictable in
subsequent reference to these items.
Also there is currently a limit of FL_MAXPUPI
(64) items per
popup.
Tabs (\t
) can be embedded in the item string to
align different fields.
You can add more menu items to an existing popup menu using the following routine
void fl_addtopup(int menuID, const char *str, ...);
Again, str can contain the special sequences mentioned earlier.
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 functions bound to the menu or menu item,
the function is invoked with the value as a parameter and the
value returned by fl_dopup
is the executed function value.
If no selection is made, function returns -1. Selecting
the title box or invoking the pop-up via a non-pointer event
results in a ``hanging'' pop-up, and you can
re-select or choose to navigate using the keyboard.
A typical procedure may look as follows:
int item3_cb(int n) { /* handle this */ return whatever; } /* define the menu */ int menu = fl_newpup(parent); fl_addtopup(menu,"Title %t|Item1|Item2|Item3%x10%f|Item4",item3_cb); switch(fl_dopup(menu)) { case 1: /* item1 is selected */ /* handle it */ case 2: /* handle it */ case 4: /* handle it */ case whatever: /* item 3 call back has been executed */ }
Since item3_cb
is bound to item3, upon whose selection,
instead of returning 10, the bound function is called with
10 as the parameter, i.e., item3_cb(10)
. The value returned
by item_cb(10)
is returned by fl_dopup()
.
To destroy a popup menu and release all memory used, use the following routine
void fl_freepup(int menuID);
To select an item, drag the mouse to the item to be selected and release the mouse. If the position prior to releasing is within the title bar, a ``hanging" pop-up results. You can re-select by clicking on or dragging to the item to be selected.
It is possible to use the keyboard to navigate the popup. Specifically
use and
to change the currently marked item;
use <RETURN> to select. <ESC> cancels the selection,
causing -1 being returned. <HOME> and <END> selects,
respectively, the first and the last item.
It is also possible to use convenience functions to bind keyboard keys
to menu items (the ``hotkeys") instead of %s
:
void fl_setpup_shortcut(int menuID, int item_val, const char *hotkeys)
where item_val is the value fl_dopup()
would have
returned if that item was selected (%x or position)
and hotkeys is a string specifying all the
hotkey combinations. See Section 21.1 for
details. Briefly, #
and ^
denote
respectively the <ALT> and the <CONTROL> key.
&n
where n=1,2, etc., can be used to denote
the function key n.
Thus if hotkeys is set to "#a^A
, both <CNTRL> A
and <ALT> A are bound to the item. One additional property
of the hotkey is the underlining of corresponding letters
in the item string. Again, only the first alphabet in the hotkey
is used. Therefore, for item string "A Choice"
,
hotkey "Cc"
, "#C"
or "^C"
will result in
the C
in "A Choice"
being underlined while
"cC"
and "#c"
will not.
Two convenience functions are available to set the callback functions for items and menus:
typedef int (*FL_PUP_CB)(int); FL_PUP_CB fl_setpup_itemcb(int menuID, int item_val, FL_PUP_CB cb); FL_PUP_CB fl_setpup_menucb(int menuID, FL_PUP_CB cb);
Similar function exists to associate a menu item with a submenu
void fl_setpup_submenu(int menuID, int item_val, int submenuID);
Note most of the setpup/getpup routines are recursive in nature and the function will search the menu and its all submenus for the item.
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
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)
where menuId is the ID returned by fl_newpup
or fl_defpup
and item_num is the value
of the item. Note that item_num can be an
item in one of the submenus of menuID.
This comes in handy to check if a toggle or radio item is set
if(fl_getpup_mode(menuID, n) & FL_PUP_CHECK) item is set
There exists also a routine that 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)
where x,y specifies the location where the top-left corner
of the popup should be. x, y should be given in screen
coordinates (i.e., relative to the root window) with the origin at
the top-left corner of the screen. This routine should be used
immediately before invoking fl_dopup()
and the position is not
remembered afterwards.
If x or y is negative, the absolute value is taken to mean the desired location of the right or bottom corner of the popup.
A radio group can be initialized by %R
or
reset programmatically using the following routine
void fl_setpup_selection(int menuID, int item_val);
The difference is that this routine, in addition to setting the ``pushed'' state of the item, also resets any previously selected item to an unpushed state. This routine can be used anytime a menuID is active, although there is rarely any need to use this routine as XPup keeps track of the current selection and draws the item accordingly once it is active.
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);
All pups by default use a right arrow cursor. To change the default cursor, use the following routine
Cursor fl_setpup_default_cursor(int cursor)
where varcursor is one of the standard cursor
names defined in <X11/cursorfonts.h>
, such as
XC_watch
etc. The function returns the current
cursor.
To change the cursor of a particular popup, use the following routine
Cursor fl_setpup_cursor(int menuID, int cursor);
For example, after the following sequence,
m_id = fl_defpup(win, "item1|item2"); fl_setpup_cursor(m_id, XC_hand2);
the popup m_id will use a ``hand" instead of the default arrow cursor.
The appearance of popups can be change by the following routines
void fl_setpup_shadow(int menuID, int yes); void fl_setpup_softedge(int menuID, int yes); void fl_setpup_bw(int menuID, int bw);
FL_PULLDOWN_MENU
by default does not have shadow and
has a ``softer'' look. Note by using a negative value for the
border width, the popup automatically becomes ``softedge".
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)
There is by default a limit of 32 popups per process. To enlarge the number of popups allowed, use the following routine
int fl_setpup_maxpups(int new_max)
The function returns the current limit.
It is possible to use popups as a message facility using the following routines
void fl_showpup(int menuID) void fl_hidepup(int menuID)
No interaction takes place with a pup shown by fl_showpup
and can only be removed from the screen programmatically
via fl_hidepup
.
Take care to make sure all items, including the items on submenus, have unique values and are positive.
Pop-ups are used indirectly in menu.c, boxtype.c and others. For a direct pop-up demo, See pup.c. All these programs are located in the DEMOS/ directory.
Scrolled canvas is not functional yet.
A canvas is a managed plain X (sub)window.
It it different from the free object
in that a canvas is guaranteed to be associated with a window that is
not shared with any other object, thus an application
program has more freedom in utilizing a canvas, such as using its
own colormap or rendering double-buffered OpenGL in it etc. A canvas
is also different from a raw application window because a canvas is
decorated differently and its geometry is managed,
e.g., you can use fl_set_object_resize()
to control its
position and size after its parent form is resized
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 meaning of the parameters is as usual. The label is not
drawn but used as the window name for possible resource and
playback purposes. If label is empty, window name will be
generated on the fly as flcanvas
n, where .
The following types of canvases exist:
FL_NORMAL_CANVAS
Simple window.
FL_SCROLLED_CANVAS
Two scrollbars are added
A scrolled canvas is just a normal canvas with two scrollbars added. A user can set the value for the scrollbar to scroll the entire window or to get signaled when the scrollbar is interactively changed.
Canvas is designed to maximize the user's ability to deal with
situations where standard form classes may not be flexible enough.
With canvases, the user has complete control over everything that
can happen to a window. By default, the only event a canvas will receive
is Expose
. To receive other events, the application
program has to select them via
fl_add_selected_xevent()
.
or XSelectInput()
or by adding an event handler.
The interaction with a canvas is typically set up as follows. First, you register the events you're interested in and their handlers using the following routine
typedef int (*FL_HANDLE_CANVAS)(FL_OBJECT *ob, Window win, int win_width, int win_height, XEvent *xev, void *user_data) void fl_add_canvas_handler(FL_OBJECT *ob, int event, FL_HANDLE_CANVAS handler, void *user_data);
Where event is the XEvent type, Expose etc.
The fl_add_canvas_handler()
function registers a procedure
with the event dispatching system of the Forms Library. The library
takes care of soliciting the proper event from the server.
Other book keeping (e.g., drawing the box that encloses the canvas, etc.)
is done by the object handler.
To remove a registered handler, use the following routine
void fl_remove_canvas_handler(FL_OBJECT *ob, int event, FL_CANVAS_HANDLER handler)
After this function call, the canvas ceases to receive the event registered.
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.
Upon canvas's creation, all its window related attributes, e.g., visual, depth and colormap, etc. are inherited from its parent (i.e., the form the canvas is on). To modify any attributes of the canvas, use the following routine before the form is shown:
void fl_set_canvas_attributes(FL_OBJECT *ob, Visual *visual, int depth, unsigned mask, XSetWindowAttributes *xswa);
Other functions exists that can be used to modify the color/visual property of a canvas:
void fl_set_canvas_colormap(FL_OBJECT *ob, Colormap map) Colormap fl_get_canvas_colormap(FL_OBJECT *ob) void fl_set_canvas_visual(FL_OBJECT *ob, Visual *vi) void fl_set_canvas_depth(FL_OBJECT *ob, int depth) int fl_get_canvas_depth(FL_OBJECT *ob)
By default, canvases are decorated with an FL_DOWN_FRAME
.
To change the decoration, use the following routine
void fl_set_canvas_decoration(FL_OBJECT *ob, int frame_type)
See Section 13.2 for a list of available frame types. Note not all frame types are appropriate for decorations.
The following routine is provided to facilitate the creation of a colormap appropriate for a given visual to be used with a canvas:
Colormap fl_create_colormap(XVisualInfo *xvinfo, int n_colors)
where n_colors indicates how many colors in the newly created colormap should be filled with XForms's default colors (to avoid flashing).
By default, objects with shortcuts appearing on the same form as the canvas will ``steal" keyboard inputs if they match the shortcuts. To disable this feature, use the following routine with a false flag
void fl_canvas_yield_to_shortcut(FL_OBJECT *ob, int flag)
None of the attributes, such as boxtype and object color, apply to the canvas class.
Derive specialized canvases from the general canvas object is
possible. See next subsection for general approaches how this
is done. 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(3G) for a list of valid attributes.
To get the current defaults, use the following routine
void fl_get_glcanvas_defaults(int *attributes)
It is also possible to change the attributes on a canvas by canvas basis by utilizing the following routine
void fl_set_glcanvas_attributes(FL_OBJECT *ob, const int *attributes)
Note this routine can be used to change a glcanvas attributes on the fly even if the canvas is already visible and active.
To obtain the attributes of a particular canvas, use the following routine
void fl_get_glcanvas_attributes(FL_OBJECT *ob, int attributes[])
The caller must supply the space for the attribute values.
To obtain the the glx context (for whatever purposes), use the following routine
GLXContext fl_get_glcanvas_context(FL_OBJECT *ob);
Note by default, the rendering context created by a glcanvas uses direct rendering (i.e., by-passes the X server). To change this default, i.e., always render through the X server, use the following routine
void fl_set_glcanvas_direct(FL_OBJECT *ob, int flag);
Finally there is a routine that can be used to obtain the XVisual information that is used to create the context
XVisualInfo *fl_get_glcanvas_xvisualinfo(FL_OBJECT *ob);
See demo program DEMOS/gl.c for an example use of glcanvases.
The OpenGL canvas routines documented above are derived from
the generic canvas by utilizing some of services provided
by the generic canvas. The following is not meant to be
an exact documentation of how the OpenGL canvas is implemented, rather
it outlines the general steps and approaches needed to create
specialized canvases. The actual implementation of the OpenGL
canvas is in FORMS/gl.c
.
All specialized canvases are created by creating a generic canvas first
FL_OBJECT *fl_create_canvas(int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label)
A canvas so created has all the properties of a real canvas and you can add it to a form and use it with the event handling routines mentioned earlier. In addition, hooks are provided so additional tasks can be performed before and after the creation of the canvas window:
typedef int (*FL_MODIFY_CANVAS_PROP)(FL_OBJECT *); void fl_modify_canvas_prop(FL_OBJECT *ob, FL_MODIFY_CANVAS_PROP init, FL_MODIFY_CANVAS_PROP activate, FL_MODIFY_CANVAS_PROP cleanup);
where init will be called before the creation of the canvas window; activate is called once the window is created; cleanup is called before the window is destroyed.
This routine can also be used to modify a canvas after it is added to a form but before the form is shown:
canvas = fl_add_canvas(type, x, y, w, h, "canvas"); fl_modify_canvas_prop(canvas, myInit, myActivate, myCleanup);
Given these services, creating a specialized canvas mainly consists of writing the three routines to be registered with the canvas handler. We start by writing the initialization routine
#include "forms.h" #include <GL/glx.h> #include <GL/gl.h> static int config[] = {GLX_RGBA,GLX_DOUBLEBUFFER,GLX_DEPTH_SIZE,1,None}; int glx_init(FL_OBJECT *ob) { XVisual *vi; GLXContext context; /* query for OpenGL capabilities */ if(!glxQueryExtension(fl_display, 0, 0)) { fprintf(stderr,"OpenGL is not supported\n"); return -1; /* signal the caller we have failed */ } /* select the desired visual */ if(!(vi = glxChooseVisual(fl_display, fl_screen, config))) return -1; /* change canvas visual/colormap based on what we've got */ fl_set_canvas_visual(ob, vi->visual); fl_set_canvas_depth(ob, vi->depth); /* we need to create a colormap appropriate for the visual we get. * Also it is a good idea to fill it with xform's default * colors to reduce flashing in case the canvas visual is not * the same as the visual rest of the form is using */ fl_set_canvas_colormap(ob, fl_create_colormap(vi, 1)); if(!(context = glxCreateContext(fl_display, vi, None, GL_TRUE))) { fprintf(stderr,"Can't create GLX Context\n"); return -1; } /* use the c_vdata field to store this context. Similar to * u_vdata, the main parts of the library does not reference or * modify c_vdata. */ ob->c_vdata = context; return 0; }
Routine activate and cleanup can be coded in a similar fashion
int glx_activate(FL_OBJECT * ob) { glXMakeCurrent(fl_display, FL_ObjWin(ob), ob->c_vdata); return 0; } int glx_cleanup(FL_OBJECT * ob) { if(ob->c_vdata) glXDestroyContext(fl_display, ob->c_vdata); ob->c_vdata = 0; return 0; }
With the above routines in place, we write the glcanvas interface routine just like the interface routine for any other objects
FL_OBJECT *fl_create_glcanvas(int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label) { FL_OBJECT *ob = fl_create_canvas(type, x, y, w, h, label); fl_modify_canvas_prop(ob, glx_init, glx_activate, glx_cleanup); return ob; } FL_OBJECT * fl_add_glcanvas(int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label) { FL_OBJECT *ob = fl_create_glcanvas(type, x, y, w, h, label); fl_add_object(fl_current_form, ob); return ob; }
Then the application program simply uses the glcanvas as an independent class.