[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

6. Goodies

A number of special routines are provided that make working with simple forms even simpler. All these routines build simple forms and handle the interaction with the user.


6.1 Messages and Questions

The following routines are meant to give messages to the user and to ask simple questions:

 
void fl_show_message(const char *s1, const char *s2, const char *s3);

It shows a simple form with three lines of text and a button labeled OK on it. The form is so shown such that the mouse pointer is on the button.

Sometimes, it may be more convenient to use the following routine

 
void fl_show_messages(const char *str);

when the message is a single line or when you know the message in advance. Embed newlines in str to get multi-line messages.

As a third alternative you can also use

 
void fl_show_messages_f(const char * fmt, ...);

The only required argument fmt is a format string as you would use it for e.g., printf(3), which then is followed by as many arguments as there are format specifiers in the format string. The string resulting from expanding the format string, using the remaining arguments, can have arbitrary length and embedded newline characters ('\n'), producing line breaks. The size of the message box is automatically made to fit the whole text.

Both of the message routines block execution and do not return immediately (but idle callbacks and asynchronous IO continue to be run and checked). Execution resumes when the OK button is pressed or <Return> is hit, or when the message form is removed from the screen by the following routine (for example, triggered by a timeout or idle callback):

 
void fl_hide_message(void)

There is also a routine that can be used to show a one-line message that can only be removed programmatically

 
void fl_show_oneliner(const char *str, FL_Coord x, FL_Coord y);
void fl_hide_oneliner(void);

where str is the message and x and y are the coordinates (relative to the root window) the message should be placed. Note that multi-line messages are possible by embedding the newline character into str. See the demo program `preemptive.c' for an example of its use.

By default, the background of the message is yellow and the text black. To change this default, use the following routine

 
void fl_set_oneliner_color(FL_COLOR background, FL_COLOR textcol);

A similar routine exists to change the font style and size

 
void fl_set_oneliner_font(int style, int size);

 
void fl_show_alert(const char *s1, const char *s2, const char *s3,
                   int centered);
void fl_hide_alert(void);

work the same as fl_show_messages() goodie except that an alert icon (!) is added and the first string is shown bold-faced. The extra parameter centered controls whether to display the form centered on the screen.

As in the case of messages also another function is avaialble

 
void fl_show_alert2(int centered, const char *fmt, ...);

centered controls if the alert message is centered and fmt must be a format string as e.g., used for printf(3). After the format string as many further arguments are required as there are format specifiers in the format string. The string resulting from expanding the format string, using the rest of the arguments, can have arbitrary length and the first embedded form-feed character ('\f') is used as the separator between the title string and the message of the alert box. Embedded newline characters ('\n') produce line breaks.

In combination with fl_add_timeout(), it is easy to develop a timed alert routine that goes away when the user pushes the OK button or when a certain time has elapsed:

 
static void dismiss_alert(int ID, void *data) {
    fl_hide_alert();
}

void show_timed_alert(const char *s1, const char *s2,
                      const char *s3, int centered) {
    fl_add_timeout( 10000, dismiss_alert, 0 ); /* ten seconds */

    /* fl_show_alert blocks, and returns only when the OK button
       is pushed or when the timeout, in this case, 10 seconds,
       has elapsed */

    fl_show_alert(s1, s2, s3, centered);
}

Then you can use show_timed_alert() just as fl_show_alert() but with added functionality that the alert will remove itself after 10 seconds even if the user does not push the OK button.

 
int fl_show_question(const char *message, int def);
void fl_hide_question(void);

Again shows a message (with possible embedded newlines in it) but this time with a Yes and a No button. def controls which button the mouse pointer should be on: 1 for Yes, 0 for No and any other value causes the form to be shown so the mouse pointer is at the center of the form. It returns whether the user pushed the Yes button. The user can also press the <Y> key to mean Yes and the <N> key to mean No.

If the question goodie is removed programmatically via fl_hide_question(), the default def as given in fl_show_question() is taken. If no default is set, 0 is returned by fl_show_question(). The following code segment shows one way of using fl_hide_question()

 
void timeout_yesno(int id, void *data) {
    fl_hide_question();
}

...

fl_add_timeout(5000, timeout_yesno, 0);

/* show_question blocks until either timeouts or
   one of the buttons is pushed */

if (fl_show_question("Want to Quit ?", 1))
    exit(0);

/* no is selected, continue */

...  /* rest of the code *.

In the above example, the user is given 5 seconds to think if he wants to quit. If within the 5 seconds he can't decide what to do, the timeout is triggered and fl_show_question() returns 1. If, on the other hand, he pushes the No button before the timeout triggers, fl_show_question() returns normally and fl_hide_question() becomes a no-op.

 
int fl_show_choice(const char *s1, const char *s2, const char *s3,
                   int numb, const char *b1, const char *b2,
                   const char *b3, int def);

int fl_show_choices(const char *s, int numb,
                    const char *b1, const char *b2, const char *b3,
                    int def);

void fl_set_choices_shortcut(const char *s1, const char *s2,
                             const char *s3);

void fl_hide_choice(void);

The first routine shows a message (up to three lines) with one, two or three buttons. numb indicates the number of buttons. b1, b2 and b3 are the labels of the buttons. def can be 1, 2 or 3, indicating the default choice. The second routine is similar to the first except that the message is passed as a single string with possible embedded newlines in it. Both routines return the number of the button pressed (1, 2 or 3). The user can also press the <1>, <2> or <3> key to indicate the first, second, or third button. More mnemonic hotkeys can be defined using the shortcut routine, s1, s2 and s3 are the shortcuts to bind to the three buttons. If the choice goodie is removed by fl_hide_choice(), the default def is returned.

To change the font used in all messages, use the following routine

 
void fl_set_goodies_font(int style, int size);

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

 
const char *fl_show_input(const char *str1, const char *defstr);
void fl_hide_input(void);

This shows a box with one line of message (indicated by str1), and an input field into which the user can enter a string. defstr is the default input string placed in the input box. In addition, three buttons, labeled Cancel, OK and Clear respectively, are added. The button labeled Clear deletes the string in the input field. The routine returns the string in the input field when the user presses the OK button or the <Return> key. The function also returns when button Cancel is pressed. In this case, instead of returning the text in the input field, NULL is returned. This routine can be used to have the user provide all kinds of textual input.

Removing the input field programmatically by calling fl_hide_input() results in NULL being returned by fl_show_input(), i.e., it's equivalent to pressing the Cancel button.

A similar but simpler routine can also be used to obtain textual input

 
const char *fl_show_simple_input(const char *str1, const char *defstr);

The form shown in this case only has the OK button. The example program `goodies.c' shows you these goodies.

It is possible to change some of the built-in button labels via the following resource function with proper resource names

 
void fl_set_resource(const char *res_str, const char *value)

To, for example, change the label of the Dismiss button to "Go" in the alert form, code similar to the following can be used after calling fl_initialize() but before any use of the alert goodie:

 
fl_set_resource("flAlert.dismiss.label", "Go");

Currently the following goodies resources are supported:

flAlert.title

The window title of the alert goodie

flAlert.dismiss.label

The label of the Dismiss button

flQuestion.yes.label

The label of the Yes button

flQuestion.no.label

The label of the No button

flQuestion.title

The window title of the Question goodie

flChoice.title

The window title of the Choice goodie

*.ok.label

The label of the OK button

Note that all goodies are shown with FL_TRANSIENT and not all window managers decorate such forms with titles. Thus the title setting in the above listing may not apply.


6.2 Command Log

In a number of situations, a GUI is created specifically to make an existing command-line oriented program easier to use. For stylistic considerations, you probably don't want to have the output (stderr and stdout) as a result of running the command printed on the terminal. Rather you want to log all the messages to a browser so the user can decide if and when to view the log. For this, a goodie is available

 
long fl_exe_command(const char *cmd, int block);

This function, similar to a system(3) call, forks a new process that runs the command cmd, which must be a (null-terminated) string containing a command line passed to the (sh) shell. The output (both stderr and stdout) of cmd is logged into a browser, which can be presented to the user when appropriate (see below). The block argument is a flag indicating if the function should wait for the child process to finish. If the argument block is true (non-zero), the function waits until the command cmd completes and then returns the exit status of the command cmd (i.e., the status one gets form wait() or waitpid(), so use WEXITSTATUS() on it if you want the return or exit() value from the program started)). If the argument block is false (0), the function returns immediately without waiting for the command to finish. In this case, the function returns the process ID of the child process or -1 if an error occured.

Unlike other goodies, fl_exe_command() does not deactivate other forms even in blockng mode. This means that the user can interact with the GUI while fl_exe_command() waits for the child process to finish. If this is not desired, you can use fl_deactivate_all_forms() and fl_activate_all_forms() to wrap the function.

If fl_exe_command() is called in non-blocking mode, the following function should be called to clean up related processes and resources before the caller exits (otherwise a zombie process may result)

 
int fl_end_command(long pid);

where pid is the process ID returned by fl_exe_command(). The function suspends the current process and waits until the child process is completed, then it returns the exit status of the child process or -1 if an error has occurred.

There is another routine that will wait for all the child processes initiated by fl_exe_command() to complete

 
int fl_end_all_command(void)

The function returns the status of the last child process.

You can also poll the status of a child process using the following routine

 
int fl_check_command(long pid);

where pid is the process ID returned by fl_exe_command(). The function returns the following values: 0 if the child process is finished; 1 if the child process still exists (running or stopped) and -1 if an error has occurred inside the function.

If some interaction with the command being executed is desired, the following functions may be more appropriate. These functions operates almost exactly as the popen(3) and pclose(3) functions:

 
FILE *fl_popen(const char *command, const char *type);
int fl_pclose(FILE *stream);

The fl_popen() function executes the command in a child process, and logs the stderr messages into the command log. Further, if type is "w", stdout will also be logged into the command browser. fl_pclose() should be used to clean up the child process.

To show or hide the logs of the command output, use the following functions

 
int fl_show_command_log(int border);
void fl_hide_command_log(void);

where border is the same as that used in fl_show_form(). These two routines can be called anytime anywhere after fl_initialize() has been invoked.

The command log is by default placed at the top-right corner of the screen. To change the default placement, use the following routine

 
void fl_set_command_log_position(int x, int y);

where x and y are the coordinates of the upper-left corner of the form relative to the root window. The logging of the output is accumulative, i.e., fl_exe_command() does not clear the browser. To clear the browser, use the following routine

 
void fl_clear_command_log(void);

It is possible to add arbitrary text to the command browser via the following routine

 
void fl_addto_command_log(const char *txt);
void fl_addto_command_log_f(const char *fmt, ...);

where txt for fl_addto_command_log() is a string and fmt for fl_addto_command_log_f() is a format string like for printf() that gets expanded using the following arguments. This string, with possible embedded newlines, gets added to the last line of the browser using fl_addto_browser_chars().

Finally, there is a routine that can be used to obtain the GUI structure of the command browser

 
typedef struct {
    FL_FORM   * form;           /* the form */
    FL_OBJECT * browser;        /* the browser */
    FL_OBJECT * close_browser;  /* the close button */
    FL_OBJECT * clear_browser;  /* the clear button */
} FD_CMDLOG;

FD_CMDLOG *fl_get_command_log_fdstruct(void);

From the information returned the application program can change various attributes of the command browser and its associated objects. Note however, that you should not hide/show the form or free any members of the structure.


6.3 Colormap

In a number of applications the user has to select a color from the colormap. For this a goody has been created. It shows the first 64 entries of the colormap. The user can scroll through the colormap to see more entries. Once the user presses the mouse one of the entries the corresponding index is returned and the colormap is removed from the screen. To display the colormap use the routine

 
int fl_show_colormap(int oldcol);

oldcol should be the current or default color. The user can decide not to change this color by pressing the Cancel button in the form. The procedure returns the index of the color selected (or the index of the old color).


6.4 File Selector

The most extended predefined form is the file selector. It provides an easy and interactive way to let the user select files. It is called as follows:

 
const char *fl_show_fselector(const char *message, 
                              const char *directory,
                              const char *pattern,
                              const char *default);

A form will be shown in which all files in directory directory are listed that satisfy the pattern pattern (see Fig 6.1). pattern can be any kind of regular expression, e.g., [a-f]*.c, which would list all files starting with a letter between a and f and ending with .c. default is the default file name. message is the message string placed at the top of the form. The user can choose a file from the list given and the function then returns a pointer to a static buffer that contains the filename selected, or NULL if the Cancel button is pressed (see below).

The user can also walk through the directory structure, either by clicking on the box with the name of the currently displayed directory to edit it manually, or by double-clicking on the name of a directory (shown with a 'D' in front of it) shown in the list. If the directory content changes while it is being displayed in the file selector the ReScan button can be used to request a rescan of the directory.

xforms_images/fselect

In a typical application, once the file selector goodie is shown, it is up to the user when the file selector should be dismissed by pushing Ready or Cancel button. In some situations the application may want to remove the file selector on it's own. To this end, the following routine is available

 
void fl_hide_fselector(void);

The effect of removing the file selector programmatically is the same as pushing the Cancel button. There are total of FL_MAX_FSELECTOR (6) file selectors in the Forms Library with each having its own current directory and content cache. All the file selector functions documented manipulate the currently active file selector, which can be set using the following routine

 
int fl_use_fselector(int n);

where n is a number between 0 and FL_MAX_FSELECTOR - 1.

To change the font the file selector uses, the following routine can be used:

 
void fl_set_fselector_fontsize(int font_size);
void fl_set_fselector_fontstyle(int font_style);

These routines change the font for all the objects on the form. It is possible to change the font for some of the objects (e.g., browser only) using fl_get_fselector_fdstruct() explained later.

The window title of the file selector can be changed anytime using the following routine

 
void fl_set_fselector_title(const char *title);

To force an update programmatically, call

 
void fl_invalidate_fselector_cache(void);

before fl_show_fselector(). Note that this call only forces an update once, and on the directory that is to be browsed. To disable caching altogether, the following routine can be used:

 
void fl_disable_fselector_cache(int yes);

A false (0) parameter (re)enables directory caching.

The user can also change the pattern by clicking the mouse on top of it it. Note that directories are shown independent of whether they satisfy the pattern. He can also type in a file name directly.

Complete keyboard navigation is built-in. E.g., you can use <Alt>d to change the directory instead of using the mouse.

When the user is satisfied, i.e., found the correct directory and indicated the file name required, he can press the button labeled Ready or press the <Return> key. He can also double click on the file name in the browser. The full path to the filename is returned by the procedure. If the user presses the Cancel button NULL is returned.

It is also possible to set a callback routine so that whenever the user double clicks on a filename, instead of returning the filename, the callback routine is invoked with the filename as the argument. To set such a callback, use the following routine

 
void fl_set_fselector_callback(int (*callback)(const char *, void *),
                               void *user_data);

where the second argument of the callback is the user data. The return value of the callback function is currently not used. Note that the behavior of the file selector is slightly different when a callback is present. Without the callback, a file selector is always modal.

Please note that when a file selector has a callback installed the field for manually entering a file name isn't shown.

The placement of the file selector is by default centered on the screen, which can be changed by the following routine

 
void fl_set_fselector_placement(int place);

where place is the placement request same as in fl_show_form(). The default is FL_PLACE_CENTER | FL_FREE_SIZE.

By default, an fselector is displayed with transient property set. To change the default, use the following routine

 
void fl_set_fselector_border(int border);

The border request by this function is the same as in fl_show_form(), but FL_NOBORDER is ignored.

If the arguments directory, pattern or default passed to fl_show_form() are empty strings or NULL, the previous value is used (with some reasonable defaults getting used when this happens the first time). Thus the file selector "remembers" all the settings the selector had last time. The application program can figure out the directory, pattern and file name (without the path) after the user changed them using the routines

 
const char *fl_get_directory(void);
const char *fl_get_pattern(void);
const char *fl_get_filename(void);

It is also possible to programatically set new values for the default directory and pattern by using the functions

 
int fl_set_directory( const char * dir );
void fl_set_pattern( const char * pattern );

fl_set_directory() returns 0 on success and 1 on failure, either because the argument was a NULL pointer or not a valid directory.

There are other routines that make the fselector more flexible. The most important of which is the ability to accommodate up to three application specific button:

 
void fl_add_fselector_appbutton(const char *label,
                                void (*callback)(void *),
                                 void *data);

The argument data is passed to the callback. Whenever this application specific button is pushed, the callback function is invoked.

To remove an application specific button, use the following routine

 
void fl_remove_fselector_appbutton(const char *label);

Within the callback function, in addition to using the routines mentioned above, the following routines can be used:

 
void fl_refresh_fselector(void);

This function causes the file selector to re-scan the current directory and to list all entries in it.

If, for whatever reasons, there is a need to get the fselector's form the following routine can be used:

 
FL_FORM *fl_get_fselector_form(void);

See `fbrowse.c' for the use of the file selector.

Although discouraged, it is recognized that direct access to the individual objects of a fselector's form maybe necessary. To this end, the following routine exists

 
typedef struct {
    FL_FORM   * fselect;
    void      * vdata;
    char      * cdata;
    long        ldata;
    FL_OBJECT * browser,
              * input,
              * prompt,
              * resbutt;
    FL_OBJECT * patbutt,
              * dirbutt,
              * cancel,
              * ready;
    FL_OBJECT * dirlabel,
              * patlabel;
    FL_OBJECT * appbutt[3];
} FD_FSELECTOR;

FD_FSELECTOR *fl_get_fselector_fdstruct(void);

You can, for example, change the default label strings of various buttons via members of the FD_FSELECTOR structure:

 
FD_FSELECTOR *fs = fl_get_fselector_fdstruct();

fl_set_object_label(fs->ready, "Go !");
fl_fit_object_label(fs->ready, 1, 1);

Since the return value of fl_get_fselector_fdstruct() is a pointer to an internal structures, the members of this structure should not be modified.

In the listing of files in a directory special files are marked with a prefix in the browser (for example, D for directories, p for pipes etc.). To change the prefix, use the following routine

 
void fl_set_fselector_filetype_marker(int dir,
                                      int fifo,
                                      int socket,
                                      int cdev,
                                      int bdev);

where dir is the marker character for directories, fifo the marker for pipes and FIFOs, socket the marker for sockets, cdev the marker for character device files and, finally, bdev the marker character for block device files.

Although file systems under Unix are similar, they are not identical. In the implementation of the file selector, the subtle differences in directory structures are isolated and conditionally compiled so an apparent uniform interface to the underlying directory structure is achieved.

To facilitate alternative implementations of file selectors, the following (internal) routines can be freely used:

To get a directory listing, the following routine can be used

 
const FL_Dirlist *fl_get_dirlist(const char *dirname,
                                 const char *pattern,
                                 int *nfiles, int rescan);

where dirname is the directory name; pattern is a regular expression that is used to filter the directory entries; nfiles on return is the total number of entries in directory dirname that match the pattern specified by pattern (not exactly true, see below). The function returns the address of an array of type FL_Dirlist with nfiles if successful and NULL otherwise. By default, directory entries are cached. Passing the function a true (non-zero) value for the rescan argument requests a re-read.

FL_Dirlist is a structure defined as follows

 
typedef struct {
    char          * name;        /* file name */
    int             type;        /* file type */
    long            dl_mtime;    /* file modification time */
    unsigned long   dl_size;     /* file size in bytes */
} FL_Dirlist;

where type is one of the following file types

FT_FILE

a regular file

FT_DIR

a directory

FT_SOCK

a socket

FT_FIFO

a pipe or FIFO

FT_LINK

a symbolic link

FT_BLK

a block device

FT_CHR

a character device

FT_OTHER

?

To free the list cache returned by fl_get_dirlist(), use the following call

 
void fl_free_dirlist(FL_Dirlist *dl);

Note that a cast may be required to get rid of compiler warnings due to the const qualifier of the return value of fl_get_dirlist(). See demo program `dirlist.c' for an example use of fl_get_dirlist().

Per default not all types of files are returned by fl_get_dirlist(). The specific rules for which types of file are returned are controlled by an additional filter after the pattern filter. It has the type

 
int default_filter(const char *name, int type);

and is called for each entry found in the directory that matched the pattern. This filter function should return true (non-zero) if the entry is to be included in the directory list. The default filter is similar to the following

 
int ffilter(const char *name, int type) {
    return type == FT_DIR || type == FT_FILE || type == FT_LINK;
}

i.e., per default only directories, normal files and symbolic links are shown (the first argument of the function, the file name, isn't used by the default filter).

To change the default filter, use the following routine

 
typedef int (*FL_DIRLIST_FILTER)(const char *, int);
FL_DIRLIST_FILTER fl_set_dirlist_filter(FL_DIRLIST_FILTER filter);

As noted before, directories are by default not subject to filtering. If, for any reason, it is desirable to filter also directories, use the following routine with a true flag

 
int fl_set_dirlist_filterdir(int flag);

The function returns the old setting. Since there is only one filter active at any time in XForms, changing the filter affects all subsequent uses of file browsers.

By default, the files returned are sorted alphabetically. You can change the default sorting using the following routine:

 
int fl_set_dirlist_sort(int method);

where method can be one of the following

FL_NONE

Don't sort the entries

FL_ALPHASORT

Sort the entries in alphabetic order - this is the default

FL_RALPHASORT

Sort the entries in reverse alphabetic order

FL_MTIMESORT

Sort the entries according to the modification time

FL_RMTIMESORT

Sort the entries according to the modification time, but reverse the order, i.e., latest first.

FL_SIZESORT

Sort the entries in increasing size order

FL_RSIZESORT

Sort the entries in decreasing size order

FL_CASEALPHASORT

Sort the entries in alphabetic order with no regard to case

FL_RCASEALPHASORT

Sort the entries in reverse alphabetic order with no regard to case.

The function returns the old sort method. For directories having large numbers of files, reading the directory can take quite a long time due to sorting and filtering. Electing not to sort and (to a lesser degree) not to filter the directory entries (by setting the filter to NULL) can speed up the directory reading considerably.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Jens Thoms Toerring on January 5, 2014 using texi2html 1.82.