next up previous contents index
Next: Designing your own object Up: XForms Online Manual Previous: The Form Designer

An overview of all object classes

 

Introduction

This part describes all different object classes that are available in the Forms Library.

All available object classes are summarized in Table 13.1.

  

NameDescription
Static Objects
BoxRectangular area to visually group objects
FrameA box with an empty inside region.
LabelframeA frame with label on the frame
TextSimple one line labels.
BitmapDisplays an X11 bitmap.
PixmapDisplays a pixmap using the XPM libraray.
ClockA clock.
ChartBar-charts, pie-charts, strip-chart, etc.
Button Like Objects
ButtonMany different kinds and types of buttons that the user can push to indicate certain settings or actions.
Valuator Objects
SliderBoth vertical and horizontal sliders to let the user indicate some float value.
DialA dial to let the user indicate a float value.
PositionerLets the user indicate an (x,y) position with the mouse.
CounterA different way to let a user step through values.
Input Objects
InputLets the user type in an input string.
Choice Objects
MenuBoth pop-up and drop-down menus can be created.
ChoiceCan be used to let the user make a choice from a set of items
BrowserA text browser with a slider. Can be used for making selections from sets of choices.
Other Objects
TimerA timer that runs from a set time towards 0. Can e.g. be used to do default actions after some time has elapsed.
XYPlotXYPlot shows simple 2D xy-plot from a tabulated function or a datafile. Data points can be interactively manipulated and retrieved.
Pop-upsPop-ups are used by menu and choice. It can also be used stand-alone to allow the user to make selections among many choices.
CanvasCanvases are managed plain X windows. It differs from a raw application window only in the way its geometry is managed, not in anyway various interaction is set up.


Table 13.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.

Static objects

 

Box

Short description

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.

Adding an object

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.

Types

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.

Interaction

No interaction takes place with boxes.

Other routines

No other routines are available for boxes.

Attributes

Color1 controls the color of the box.

Remarks

Do not use FL_NO_BOX type if the label is to change during the execution of the program.

Boxes are used in most demo's. Also see Fig. 3.1. 

Frame

   

Short description

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 an 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.

Adding an object

To add a 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.

Types

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.

Interaction

No interaction takes place with frames.

Other routines

None.

Attributes

Color1 controls the color of the frame if applicable. Boxtype attribute does not apply to the frame class.

Remarks

It may be faster to use frames instead of boxes for text that is truly static. See freedraw.c for an example use of frame objects. 

LabelFrame

   

Short description

A label frame is almost the same as a frame except that the label is placed on the frame (See Fig. 14.1)

instead of inside or outside of the bounding box as in a regular frame.

  

[figure]

Figure 14.1: Labelframe Classes

Adding an object

To add a labelframe to a form you use the routine

 

   FL_OBJECT *fl_add_labelframe(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.

Types

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.

Interaction

No interaction takes place with frames.

Other routines

None.

Attributes

Color1 controls the color of the frame if applicable. Color2 controls the background color of the label. Boxtype attribute does not apply to the labelframe class.

Remarks

You can not draw a label inside or outside of the frame box. If you try, say, by requesting FL_ALIGN_CENTER, the label is drawn using FL_ALIGN_TOP_LEFT.   CLASSES/lframe.tex

Text

   

Short description

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

Adding an object

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.

Types

Only one type of text exists: FL_NORMAL_TEXT.

Interaction

No interaction takes place with text objects.

Other routines

No other routines are available for texts.

Attributes

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.

Remarks

Don't use boxtype FL_NO_BOX if the label is to change dynamically.

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. 

Bitmap

     

Short description

A bitmap is a simple bitmap shown on a form.

Adding an object

 

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.

Types

Only the type FL_NORMAL_BITMAP is available.

Interaction

No interaction takes place with a bitmap. For bitmap that interacts, see Section 15.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.) 

Other routines

To set the actual bitmap being displayed use      

   void fl_set_bitmap_data(FL_OBJECT *ob, int w, int h, unsigned 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.

Attributes

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.

Remarks

See demo33.c for a demo of a bitmap. 

Pixmap

     

Short description

A pixmap is a simple pixmap shown on a form .

Adding an object

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.

Types

Only the type FL_NORMAL_PIXMAP is available.

Interaction

No interaction takes place with a pixmap. For pixmap that interacts, see Section 15.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.)

Other routines

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.

Attributes

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);

Remarks

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. hotx and hoty are the center of the pixmap (useful if the pixmap is to be used as a cursor). 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 (version 3.4c or later) 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).

Clock

 

Short description

A clock object simply displays a clock on the form.

Adding an object

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.

Types

The following types are available:

 
  FL_ANALOG_CLOCK		 An analog clock complete with the second hand.

FL_DIGITAL_CLOCK A digital clock.

Interaction

No interaction takes place with clocks.

Other routines

To get the current time use the routine

 

   void fl_get_clock(FL_OBJECT *obj, int *h, int *m, int *s)

Attributes

Never use FL_NO_BOX as boxtype for a digital clock.

Color1 controls the color of the background, color2 the color of the hands.

Remarks

See flclock.c for an example of the use of clocks.  

Chart

 

Short description

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.

Adding an object

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.

Types

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 less than or equal to 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 512. Switching between different types can be done without any complications.

Interaction

No interaction takes place with charts.

Other routines

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 (FL_RED etc) 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().

By default, the label is drawn with tiny font in black. You can change the font style, size or color using the following routine

     

   void fl_set_chart_lstyle(FL_OBJECT *ob, int fontstyle)

   void fl_set_chart_lsize(FL_OBJECT *ob, int fontsize)

   void fl_set_chart_lcolor(FL_OBJECT *ob, int color)

Note that fl_set_chart_lcolor() only affects the label color of subsequent items, not the items already created.

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.

Attributes

Don't use FL_NO_BOX for a chart object if it changes value. Color1 controls the color of the box.

Remarks

  See chartall.c and chartstrip.c for examples of the use of chart objects.

Button like objects

Button

   

Short description

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.

  

[figure]

Figure 15.1: Button Classes

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.

Adding an object

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_round3dbutton(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, round3dbutton, bitmapbutton   and pixmapbutton, it is placed to the right of the circle and to the bottom of the bitmap/pixmap respectively.

Types

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 similar 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.

Interaction

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

See demo butttypes.c for a feel of the different button types.

Other routines

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). When setting a FL_RADIO_BUTTON to be pushed this automatically releases the currently pushed button if different.

Also note that 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     or more conveniently follow fl_set_button() with fl_call_object_callback().

To figure out whether a button is pushed  [footnote] 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 one of the constants FL_LEFT_MOUSE, FL_MIDDLE_MOUSE and FL_RIGHT_MOUSE indicating the physical location of the mouse button on the mouse.

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 22.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 addition 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.

Finally there is routine that can be used to disable the focus outline with a false flag

 

   void fl_set_pixmapbutton_focus_outline(FL_OBJECT *ob, int flag)

See also Section 14.6 for pixmap color and transparency   handling.

Attributes

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 round3dbutton, color1 is the color of the inside of the circle and color2 the color of the embedded circle. 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.  

Remarks

See all demo programs, in particular pushbutton.c and buttonall.c, for the use of buttons.  

Valuator objects

Slider

   

Short description

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.

Adding an object

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.

Types

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.
	FL_VERT_BROWSER_SLIDER   A different looking vertical slider.
	FL_HOR_BROWSER_SLIDER    A different looking horizontal slider.

 

[figure]

Figure 16.1: All sliders

Interaction

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

               

FL_RETURN_END_CHANGED
return at end (mouse release) if value is changed (since last return).

FL_RETURN_CHANGED
return whenever the slider value is changed.

FL_RETURN_END
return at end (mouse release) regardless if the value is changed or not.

FL_RETURN_ALWAYS
return all the time. Not very useful.

See demo objreturn.c for an example use of this.

Other routines

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.

By default, if mouse is pressed below or above the the sliding bar, the sliding bar jumps to the location where the mouse is pressed. You can, however, use

the following the routine to change this default so the jumps are made is several steps:

 

   void fl_set_slider_increment(FL_OBJECT *obj, double lj, double sj)

where lj indicates how much to jump if the left mouse button is pressed and sj indicates how much to jump if other mouse buttons pressed. For example, for the slider in the browser class, the left mouse jump is made to be one page and small jump is made to be one line.

Attributes

Never use FL_NO_BOX as boxtype for a slider. For FL_VERT_NICE_SLIDERs and FL_HOR_NICE_SLIDERs 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. The default is FL_SLIDER_WIDTH = 0.10 for regular sliders and 0.15 for browser sliders. With size=1.0, the slider covers the box completely and can no longer be moved. This function does not apply to NICE_SLIDER and FILL_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. The default filter is equivalent to the following

   const char *filter(FL_OBJECT *ob, double value, int prec)
   {
       static char buf[32];
       sprintf(buf, "%.*f",prec,value);
       return buf;
   }

Remarks

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, it is not true. All internal calculations are done with float precision. 

Dial

 

Short description

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.

Adding an object

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.

Types

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.
	  FL_FILL_DIAL     	 The area between initial and current is filled.

 

[figure]

Figure 16.2: Types of dials

Interaction

By default, the dial value is returned to the application when the user releases the mouse. It is possible to change this behavior using the following routine

 

   void fl_set_dial_return(FL_OBJECT *obj, int how_return)

where how_return can be one of the following

FL_RETURN_END_CHANGED Return at end (mouse release) and only if the dial value is changed. The Default.
FL_RETURN_CHANGED Return whenever the dial value is changed.
FL_RETURN_END Return at the end regardless if the dial value is changed or not.

Other routines

To change the value of the dial use

   

   void fl_set_dial_value(FL_OBJECT *obj, double val)

   void fl_set_dial_bounds(FL_OBJECT *obj, double min, double max)

By default, the minimum value is 0.0, the maximum is 1.0 and the value is 0.5. To obtain the current values of the dial use

   

   double fl_get_dial_value(FL_OBJECT *obj)

   void fl_get_dial_bounds(FL_OBJECT *obj, double *min, double *max)

Sometimes, it might be desirable to limit the angular range a dial can take or choose an angle other than 0 to represent the minimum value. For this purpose, use the following routine

 

   void fl_set_dial_angles(FL_OBJECT *ob, double thetai, double thetaf)

where thetai maps to the minimum value of the dial and thetaf maps to the maximum value of the dial. The angles are relative to the origin of the dial, which is by default at 6 o'clock (270 degrees from 3 o'clock) and rotates clock-wise. 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.

By default, clock-wise rotation increases the dial value. To change, use the following routine

   void fl_set_dial_direction(FL_OBJECT *obj, int dir)

where dir can be either FL_DIAL_CCW or FL_DIAL_CW.

Attributes

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 or the fill color.

Remarks

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, ndial.c and fdial.c for examples of the use of dials. 

Positioner

 

Short description

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.

Adding an object

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.

Types

Only one type of positioner exists at the moment:

 
	FL_NORMAL_POSITIONER     	Cross-hair inside a box.

Interaction

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.

Other routines

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.

Attributes

Never use FL_NO_BOX for a positioner. Color1 controls the color of the box, color2 the color of the cross-hair.

Remarks

A demo can be found in positioner.c. 

Counter

 

Short description

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.

Adding an object

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.

Types

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.

 

[figure]

Figure 16.3: Counter types

Interaction

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.

Other routines

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 is 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.)

For conflicting settings, bounds take precedence over value, i.e., if setting a value that is outside of the current bounds, it is clamped.

To obtain the current value of the counter use

 

   double fl_get_counter_value(FL_OBJECT *obj)

To obtain the current bounds, use the following function

 

   double fl_get_counter_bounds(FL_OBJECT *obj, double *min, double *max)

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, double value, int prec)
   {
       static char buf[32];
       sprintf(buf, "%.*f",prec,value);
       return buf;
   }

Attributes

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.

Remarks

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 for 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.

Input objects

Input

   

Short description

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.

Adding an object

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.

Types

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_DATE_INPUT		Only a date (MM/DD/YY) can be typed in.
	FL_MULTILINE_INPUT	An input field allowing for multiple lines.
	FL_SECRET_INPUT		A normal input field that does not show the text.
	FL_HIDDEN_INPUT		A normal input field but 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 a float, it is not shown and the bell is sounded. Similarly, an int input field can only contain an integer number and a date input field can only contain a valid date (see below). 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.

Interaction

Whenever the user presses the mouse inside an input field a cursor will appear in it (and the field will change color to indicate input focus). Further input will be directed to this field. The user can use the following keys (as in emacs(1)) to edit or move around inside the input field:


	delete previous char  <Delete>
	delete next char      <Cntl> D
	delete previous word  <Meta> <Delete>, <Cntl> W
	delete next word      <Meta> d
	delete to end of line <Cntl> k
	backspace             <Cntl> H
	to beginning of line  <Cntl> A, <Shift> <Left>
	to end of line        <Cntl> E, <Shift> <Right>
	char backward         <Cntl> B, <Left>
	char forward          <Cntl> F, <Right>
	next line             <Cntl> N, <Down>
	previous line         <Cntl> P, <Up>
	next page             <PageDown>
	previous page         <PageUp>
	word backward         <Meta> b
	word forward          <Meta> f
	beginning of field    <Meta> <Home>, <Shift><Up>
	end of field          <Meta> <End>, <Shift><Down>
	clear input field     <Cntl> U
	paste                 <Cntl> y

It is possible to remap the the bindings, see later for details.

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 (<TAB> and <RETURN>) does not work for multi-line input fields where <RETURN> key is used to separate lines and <TAB> is a legitimate input character (not currently handled). 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:

     

FL_RETURN_END_CHANGED
The default. Callback is called at the end if the field is modified.

FL_RETURN_CHANGED
Invoke the callback function whenever the field is changed.

FL_RETURN_END
Invoke the callback function at the end regardless if the field is modified or not.

FL_RETURN_ALWAYS
Invoke the callback function upon each keystroke.

See demo objreturn.c for an example use of this.

There is a routine that can be used to limit the number of characters per line for NORMAL_INPUT

 

   void fl_set_input_maxchars(FL_OBJECT *ob, int maxchars);

To reset the limit to infinite, set maxchars to 0.

Although an input with FL_RETURN_ALWAYS attributes can be used in combination with the callback function to check the validity of characters that are entered into the input field, use of the following is typically more appropriate

     

   typedef int (*FL_INPUTVALIDATOR)(FL_OBJECT *ob,
               const char *old, const char *cur, int c);
   FL_INPUTVALIDATOR fl_set_input_filter(FL_OBJECT *ob, 
                     FL_INPUTVALIDATOR 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.

This still leaves the possibility that the input is valid for every character entered, but the string is invalid for the field because it is incomplete.

For example, 12.0e is valid for a float input field for every character typed, but the final string is not a valid floating point. To guard again this, the filter function is called just prior to returning the object with c set to zero. If the validator returns FL_INVALID, the object is not returned to the application program, but input focus can change to the next input field. If the return value is FL_INVALID|FL_RINGBELL, keyboard bell is sound and the object is not returned to the application program. Further, the input focus is not changed.

To facilitate specialized input fields using validators, the following validator dependent routines are available

   

   void fl_set_input_format(FL_OBJECT *ob, int attrib1, int attrib2)

   void fl_get_input_format(FL_OBJECT *ob, int *attrib1, int *attrib2)

These two routines more or less provide a means for the validator to store and retrieve some information about user preference or other state dependent information. attrib1 and attrib2 can be any validator defined variables. For the built-in class, only DATE_INPUT utilizes these to store the date format: for attrib1, it can take FL_INPUT_MMDD or FL_INPUT_DDMM     and attrib2 is the separator between month and day. For example, to set the date format to dd/mm, use the following

   void fl_set_input_format(ob, FL_INPUT_DDMM,'/')

For the built-in DATE_INPUT the default is FL_INPUT_MMDD and the separator is '/'. There is no limit on the year other than it must be an integer and appear after month and day.

Other routines

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, const char *str)

There is very limited check for the validity of str for the input field.

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)

This function returns a char pointer for all input types. Thus for numerical input types, atoi(3) or sprintf(3) should be used to convert the string to the proper data type you need. For multiline input, the returned pointer points to the entire content with possibly embedded newlines.

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 routine 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 obtain the cursor position using the following routine

 

   int fl_get_input_cursorpos(FL_OBJECT *ob, int *xpos, int *ypos)

The function returns the cursor position measured in number of characters (including newline characters) in front of the cursor. If the input field does not have input focus (thus does not have a cursor), the function returns -1. Upon function return, ypos is set to the line number (starting from 1) the cursor is on and xpos set to the number of characters in front of the cursor measured from the beginning of the current line, i.e., ypos. If the input field does not have input focus, the xpos is set to -1.

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, 1) places the the cursor after the first character <A> in arbitrary.

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)

By default, if a MULTILINE_INPUT field contains more text than that can be shown, scrollbars will appear with which the user

can scroll the text around horizontally or vertically. To change this default, use the following routines

   

   void fl_set_input_hscrollbar(FL_OBJECT *ob, int how)

   void fl_set_input_vscrollbar(FL_OBJECT *ob, int how)

where how can be one of the following values

FL_AUTO
The default. Shows the scrollbar only if needed.
FL_ON
Always shows the scrollbar.
FL_OFF
No scrollbar is shown.

Note however, turning off scrollbars for an input field does not turn off scrolling, the user can still scroll the field using cursor and other keys.

To completely turn off scrolling for an input field (for both multiline and single line input field), use the following routine with a false flag

 

   void fl_set_input_scroll(FL_OBJECT *obj, int flag)

There are also routines that can scroll the input field programmatically. To scroll vertically (for MULTILINE_INPUT only), use the following routine

 

   void fl_set_input_topline(FL_OBJECT *obj, int line)

where line is the new top line (starting from 1) in the input field.

To scroll horizontally, use the following routine

 

   void fl_set_input_xoffset(FL_OBJECT *ob, int pixels)

where xoffset, a positive number, indicates how many pixels to scroll to the left relative to the nominal position of the text lines.

To obtain the number of lines in the input field, use the following routine

 

   int fl_get_input_numberoflines(FL_OBJECT *ob)

To obtain the current topline in the input field, use

 

   int fl_get_input_topline(FL_OBJECT *ob)

To obtain the number of lines that fit inside the input box, use the following routine

 

   int fl_get_input_screenlines(FL_OBJECT *ob)

Attributes

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.

By default, the scrollbar size is dependent on the initial size of the input box. To change the size of the scrollbars, use the following routine

   void fl_set_input_scrollbarsize(FL_OBJECT *ob, int hh, int vw)

where hh is the horizontal scrollbar height and vw is the vertical scrollbar width in pixels.

As mentioned earlier, it is possible to the application program to change the default edit keymaps. The

editing key assignment is held in a FL_EditKeymap structure defined as follows:

 

   typedef struct
   {
      long del_prev_char;         /* delete previous char    */
      long del_next_char;         /* delete next char        */
      long del_prev_word;         /* delete previous word    */
      long del_next_word;         /* delete next word        */

      long moveto_prev_line;     /* one line  up             */
      long moveto_next_line;     /* one line down            */
      long moveto_prev_char;     /* one char left            */
      long moveto_next_char;     /* one char right           */
      long moveto_prev_word;     /* one word left            */
      long moveto_next_word;     /* one word right           */
      long moveto_prev_page;     /* one page up              */
      long moveto_next_page;     /* one page down            */
      long moveto_bol;           /* move to begining of line */
      long moveto_eol;           /* move to end of line      */
      long moveto_bof;           /* move to begin of file    */
      long moveto_eof;           /* move to end of file      */

      long transpose;             /* switch two char positions*/
      long paste;                 /* paste the edit buffer    */
      long backspace;             /* alias for del_prev_char  */
      long del_to_eol;            /* cut to end of line       */
      long del_to_bol;            /* cut to end of line       */
      long clear_field;           /* delete all               */
      long del_to_eos;            /* not implemented yet      */
   } FL_EditKeymap;

To change the default edit keymaps, the following routine is available:

 

   void fl_set_input_editkeymap(FL_EditKeymap *km)

with a filled or partially filled FL_EditKeymap

structure. The unfilled members must be set to zero so the default mapping is retained. Change of edit keymap is global and affects all input field within the application.

Setting km to null restores the default.

All cursor keys (<LEFT>, <HOME> etc.) are reserved and their meanings hard-coded, thus can't be used in the mapping. For example, if you try to set del_prev_char to <HOME>, pressing the <HOME> will not delete the previous character.

In filling the keymap structure, regular control characters (value < 32) should be given their ASCII codes (<CNTRL> C is 3 etc) and special characters their Keysyms (XK_F1 etc). Control and special character combination is obtained by adding FL_CONTROL_MASK to the keysym. To specify meta add FL_ALT_MASK to the key value.

   FL_EditKeymap ekm;

   memset(ekm, 0 , sizeof(ekm));           /* zero struct    */
   ekm.del_prev_char = 8;                  /* control-H      */ 
   ekm.del_next_char = 127;                /* delete         */
   ekm.del_prev_word = 'h'|FL_ALT_MASK;    /* meta-H         */
   ekm.moveto_bof = XK_F1;                 /* F1 to bof      */
   ekm.moveto_eof = XK_F1|FK_CONTROL_MASK; /* cntl-F1 to eof */

   fl_set_input_editkeymap(&ekm);

Remarks

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 and inputall.c for all input fields.  

Choice objects

Menu

 

Short description

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

Adding an object

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.

Types

The following types are available:        

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

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

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

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. 18.1).

  

[figure]

Figure 18.1: Menu types

Interaction

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.

Other 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 19.3. In short, it should contain the menu items, separated by a bar, e.g., ``First|Second|Third''. See Section 19.3 for special tags that can be used to indicate special attributes (radio, toggle and gray for example. Specifying values via %x is not supported). 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:

FL_PUP_NONENo special display characteristic. The default.
FL_PUP_GREYEntry is grayed out and disabled. Not selectable.
FL_PUP_BOXEntry has an empty box to the left (indicating toggle/radio.)
FL_PUP_CHECKEntry has a checked box (a down box) to the left.
FL_PUP_RADIORadio entry with a box to the left.

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.

Attributes

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.

Remarks

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. 

Choice

 

Short description

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.

Adding an object

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.

Types

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.

Interaction

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.

Other routines

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 19.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.

Attributes

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.

Remarks

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

Browser

 

Short description

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.

Adding an object

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.

Types

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.

Interaction

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 left mouse below or above the slider, the browser scrolls one page (actually one line less than a page) down or one page up. Any other mouse button scrolls one line at a time. 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.

Other routines

There are a large number of routines to change the contents of a browser, select and de-select lines, etc.

To make a browser empty use:

 

   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 appended line is visible. This is useful when, e.g., using the browser to display messages.

Sometimes it may be more convenient to add characters to a browser without implying the starting of a newline. To this end, the following routine exists

 

   void fl_addto_browser_chars(FL_OBJECT *obj, const char *text)

This function appends text to the last line in the browser without advancing the line counter unless text has embedded newline in it. In that case, the text before the embedded newline is appended to the last line, and the line counter is incremented. The characters after the newline, possibly with more embedded newlines in it, is then added to the browser via means similar to fl_addto_browser().

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 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) the negative of the de-selected 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);

Note that the topline starts from 1.

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 programmatically scroll the text horizontally

 

   void fl_set_browser_xoffset(FL_OBJECT *ob, FL_Coord xoff)

where xoff indicates how many pixels to scroll to the left relative to the nominal position of the text lines.

Attributes

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.  See fl_set_tabstop() for how to set tabstops.      

There are routines that can be used to turn the scrollbars on and off

   

   void fl_set_browser_hscrollbar(FL_OBJECT *ob, int how)

   void fl_set_browser_vscrollbar(FL_OBJECT *ob, int how)

The following gives the possible values and their meanings:

FL_AUTO is the default.

By default, the scrollbar size is determined based on the initial size of the browser. To change the default, use the following routine

 

   void fl_set_browser_scrollbarsize(FL_OBJECT *ob, int hh, int vw)

where hh is the horizontal scrollbar height and vw is the vertical scrollbar width. Use 0 to indicate the default.

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).

Remarks

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. 

Other objects

Timer

   

 

Short description

Timer objects can be used to make a timer that runs down toward 0.0 or runs up toward a pre-set value 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, 0.05 seconds. Run demo timerprec.c for an actual accuracy measurement.

Adding an object

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.

Types

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 or elapsed time. Blinks if time expires.
	FL_HIDDEN_TIMER	Not visible.

Interaction

When a visible timer expires it starts blinking. The user can stop the blinking by pressing the mouse on it or by resetting the timer. The timer object is returned to the application program or its callback called at the moment the time expires.

Other routines

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/de-blink the timer.

To obtain the time left in the timer use

   

   double fl_get_timer(FL_OBJECT *obj)

By default, a timer counts down toward zero and the value shown (for VALUE_TIMER) is the time left in the timer. You can change this default so the timer counts up and shows elapsed time

 

    void fl_set_timer_countup(FL_OBJECT *obj, int yes_no)

A timer can be temporarily suspended (stopwatch) using the following routine

 

    void fl_suspend_timer(FL_OBJECT *obj)

and can be resumed again by

 

    void fl_resume_timer(FL_OBJECT *obj)

Unlike fl_set_timer, a suspended timer keeps its internal state (total delay, time left etc) so when it is resumed, it starts from where it was suspended.

Finally there is a routine that allows the application program to change the way the time is presented in VALUE_TIMER:

     

    typedef char *(FL_TIMER_FILTER)(FL_OBJECT *ob, double secs);
    FL_TIMER_FILTER fl_set_timer_filter(FL_OBJECT *ob, FL_TIMER_FILTER filter)

The filter function is passed the timer ID and time (time left for countdown timer and elapsed time for countup timer) in seconds and should return the string representation of the time. The default filter returns the time in hour:minutes:seconds.fraction format.

Attributes

Never use FL_NO_BOX as boxtype for FL_VALUE_TIMER's.

Color1 controls the color of the timer. Color2 is the blinking color.

Remarks

Although with different API and the appearance of different interaction, the way a timer and timeout callback work is almost identical internally. Actually someday, one will be implemented using the other in the library.

See timer.c for the use of timers. 

XYPlot

 

Short description

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.

Adding an object

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.

Types

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.

Interaction

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 application. 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 routine with when equal to FL_RETURN_CHANGED 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 any of ! ; # 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.

Other routines

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, respectively, the number of tic marks to be placed on the plot and divisions between major tic marks. 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.

It is possible to label the major tic marks with alphanumerical characters instead of numerical values. To this end, use the following routines

   

    void fl_set_xyplot_alphaxtics(FL_OBJECT *ob, const char *major, 
                                 const char *minor)

    void fl_set_xyplot_alphaytics(FL_OBJECT *ob, const char *major, 
                                 const char *minor)

where major is a string specifying the labels with embedded character | that specifies major divisions. For example, to label a plot with Monday Tuesday etc, the major should be given Monday|Tuesday|.... Parameter minor is currently unused and the minor divisions are set to 1, i.e, no divisions between major tic marks. Naturally the number of major/minor divisions set by this routine and fl_set_xyplot_[x|y]tics() can't be active at the same time and the one that gets used is the one that gets called last.

To get a grided xyplot, use the following routine

   

    void fl_set_xyplot_xgrid(FL_OBJECT *ob, int xgrid)
    void fl_set_xyplot_ygrid(FL_OBJECT *ob, int ygrid)

where xgrid and ygrid can be one of the following

FL_ONAlways on.
FL_OFFAlways off.
FL_AUTOOn when needed (i.e., more lines/chars than can be shown).
FL_GRID_NONENo Grid
FL_GRID_MAJORGrid for the major divisions.
FL_GRID_MINORGrid for the major and minor divisions.

By default, the plotting area is automatically adjusted for tic labels and titles so that maximum area results. This can be undesirable in certain situations. To control the plotting area manually, the following routines can be used

   

    void fl_set_xyplot_fixed_xaxis(FL_OBJECT *ob, const char *lm, const char *rm)
    void fl_set_xyplot_fixed_yaxis(FL_OBJECT *ob, const char *bm, const char *tm)

where lm and rm specifies the right and left margin respectively and bm and tm specifies the bottom and top margins. The pixel amounts are computed using the current label font and size. Note that even for y-axis margins, the length of the sting, not the height, is used as the margin, thus to leave space for one line of text, a single character (say m) or two narrow characters (say ii) should be used.

To restore automatic margin computation, set all margins to 0 (null).

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 reverse the axes (e.g., min at right and max at left), set min > max for that axis.

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);

Note that the bounds returned are the bounds used in clipping the data, which are not necessarily the bounds used in computing the world/screen mapping due to tic rounding.

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). Normal text interpretation applies, i.e., if   text starts with @, a symbol is drawn.

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)

Similar to the base data, a data file can be used to specify the (x,y) function

 

   void fl_add_xyplot_overlay_file(FL_OBJECT *obj, const char *file
                                   FL_COLOR col)

The type (FL_NORMAL_XYPLOT etc.) used in overlay plot 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 that 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 nth 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. To restore the default linear interpolation, use degree 0 or 1.

To change the line thickness of an xyplot (base or overlay), the follow routine is available

 

    void fl_set_xyplot_linewidth(FL_OBJECT *ob, int ID, int width)

Again, use ID 0 to indicate the base data. Setting width to zero restores the server default and typically is the fastest.

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.

Use the following routine to clear an xyplot

 

   void fl_clear_xyplot(FL_OBJECT *ob)

This routine frees all data associated with an xyplot, including all overlays and all inset text. This routine does not reset all plotting options, such as line thickness, major/minor divisions etc nor does it free all memories associated with the xyplot, which fl_free_object() does.

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

screenCoord = a x data + b		(linearscale)

screenCoord = a x logp(data) + b	(logscale)

where p is the base [ footnote].

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.

Remarks

Don't use FL_NO_BOX for an xyplot object that is to be changed dynamically.

To change the font size and style for the tic labels, inset text etc., use fl_set_object_lsize() and fl_set_object_lstyle()..

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.    

Pop-ups

   

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

Short description

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

Define a new popup

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):

%t
Marks item text as the menu title string.

%F
Invokes a routine for every selection made from this menu. You must specify the invoked routine in the arg parameter. The value of the menu item is used as a parameter of the executed routine. Thus if you select the third menu item, the system passes 3 as a parameter to the function specified by %F.

%f
Invokes a routine when this particular item is selected. The routine must be supplied in the 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.

%d
Disables and gray-out this item.
%i
Makes this item inactive.

%l
Adds a line under the current entry. This is useful in providing visual clues to group like entries together.

%m
Whenever this menu item is selected, pop up another menu (cascade menus). The new menu identifier must be provided in the args argument.

%h
Specify ``hotkeys" that can be used to select this item. Hotkeys must be given in the args parameter as a pointer to string. Use # to specify <ALT>, ^ <CONTROL>, and &n key Fn.

%xn
Assigns a numeric value to this menu item. This value must be positive. This new value overrides the default position-based value assigned to this item. Different from other flags, the value n must be entered as part of the text string. Do not use the arg parameter to specify numeric value.

%b
Indicates this menu item is binary (toggle). When displayed, binary item will be drawn with a small box to the left. See also FL_PUP_BOX.
%B
Same as %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.

%rg
Specifies this menu item is a ``radio item" belonging to group 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
Same as %rg except that it also sets the state of the radio item as ``pushed", i.e., the item is drawn with a diamond box to the left. See also fl_setpup_selection().

cntl-H (
010)
Same as %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);

Interaction

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 the up and down arrow keys 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 22.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);

Other routines

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

           

FL_PUP_NONE
No special characteristics. The default.
FL_PUP_GREY
Entry is grayed-out and disabled. Selecting a grayed-out entry results in -1 being returned.
FL_PUP_BOX
Entry has an empty box to the left.
FL_PUP_CHECK
Entry has a box to the left.
FL_PUP_RADIO
Radio item, drawn with a box to the left.

Note radio item is drawn with a diamond box to the left while regular binary item is drawn with a square box to the left.

Radio attribute set with FL_PUP_RADIO will have a unique and same group ID allocated internally by the popup if the item does not already belong to another radio group.

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

 

   unsigned int fl_getpup_mode(int menuID, int item_num)

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.

Attributes

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

   

   int fl_setpup_fontsize(int size);

   int fl_setpup_fontstyle(int style);

The functions return the old size and style respectively.

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 associated 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.

Too additional routines are available that might be useful for moving popups around:

   

   void fl_reparent_pup(int MenuID, Window newparent)

   void fl_getpup_window(int MenuID, Window *parent, Window *win)

Note however, the pup window itself might not get created before fl_dopup(). The first routine can be used to change the parent of the popup even if the pup window itself is not created yet.

Remarks

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. 

Canvas

  Scrolled canvas is not functional yet.

Short description

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

Adding an object

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 flcanvasn, where n = 0, 1,....

Types

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.

Interaction

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 a canvas 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 first registers a procedure with the event dispatching system of the Forms Library, then it figures out the event masks corresponding to the event event and invokes fl_addto_selected_xevent() to solicit the event from the server. Other book keeping (e.g., drawing the box that encloses the canvas, etc.) is done by the object handler.

Since translation from X event to X event mask is not unique, depending on applications, the default translation of X event to event mask by the canvas may or may not match exactly the intention of the application. Two events, namely MotionNotify and ButtonPress,

are likely candidates that need further clarification from the application. By default, when MotionNotify is registered, it is assumed that the application is interested in mouse movements regardless if the mouse button is pressed or not. If the application is interested in mouse motion only when the mouse button is pressed, fl_remove_selected_xevent() should be called with mask PointerMotionMask|PointerMotionHintMask. With ButtonPress, you need to call fl_addto_selected_xevent() with mask OwnerGrabButtonMask if you are to add or remove other canvas handlers in the button press 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 generic function(macro) (recommanded)

   

   Window FL_ObjWin(FL_OBJECT *ob)

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

Other routines

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, 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)

Note that changing visual or depth does not generally make sense once the canvas window is created (which happens when the parent form is shown). Also, typically if you change the canvas visual, you probably should also change the canvas depth to match the visual.

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 14.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)

Attributes

None of the attributes, such as boxtype and object color, apply to the canvas class.

OpenGL canvases

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,    [footnote], 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-passing 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);

Remember that OpenGL drawing routines always draw into the window the current context bound to. For application with a single canvas, this is not a problem. In case of multiple canvases, the canvas driver takes care of setting the proper context before invoking the expose handler. In some cases, the application may want to draw into canvases actively. In this case, explict drawing context switching may be required. To this end, use the following routine

   

   void fl_activate_glcanvas(FL_OBJECT *ob)

before drawing into glcanvas ob.

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.

Remarks

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 and cleanup is called before the window is destroyed. It is very convenient to set canvas attributes, such as depth and colormap etc (if different from the form), via the init routine.

This routine obviously should be called before the form is shown:

   fd_form = create_form();
   fl_modify_canvas_prop(fd_form->canvas, myInit, myActivate, myCleanup);
   ...
   fl_show_form(fd_form->form, ...)

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.

 


next up previous contents index
Next: Designing your own object Up: XForms Online Manual Previous: The Form Designer

© 1996 1997 Danny Uy,DropDead, Inc.