This is xforms.info, produced by makeinfo version 4.13 from xforms.texi. INFO-DIR-SECTION Development START-INFO-DIR-ENTRY * XForms: (xforms). A Graphical user interface toolkit for X END-INFO-DIR-ENTRY  File: xforms.info, Node: Top, Next: Preface, Up: (dir) XForms (Forms Library) - Version 1.2 A Graphical User Interface Toolkit for X **************************************** * Menu: * Preface: Preface * Part I - Using The Forms Library: Part I * Introduction: Part I Introduction * Getting Started: Part I Getting Started * Defining Forms: Part I Defining Forms * Doing Interaction: Part I Doing Interaction * Free Objects: Part I Free Objects * Free Objects: Part I Goodies * Part II - The Form Designer: Part II * Introduction: Part II Introduction * Getting Started: Part II Getting Started * Command Line Arguments: Part II Command Line Arguments * Creating Forms: Part II Creating Forms * Saving and Loading Forms: Part II Saving and Loading Forms * Language Filters: Part II Language Filters * Generating Hardcopies: Part II Generating Hardcopies * Part III - Object Classes: Part III * Introduction: Part III Introduction * Static Objects: Part III Static Objects * Button-like Objects: Part III Button-like Objects * Valuator Objects: Part III Valuator Objects * Input Objects: Part III Input Objects * Choice Objects: Part III Choice Objects * Container Objects: Part III Container Objects * Other Objects: Part III Other Objects * Popups: Part III Popups * Deprecated Objects: Part III Deprecated Objects * Part IV - Designing Object Classes: Part IV * Introduction: Part IV Introduction * Global Structure: Part IV Global Structure * Events: Part IV Events * The Type `FL_OBJECT': Part IV The Type FL_OBJECT * Drawing Objects: Part IV Drawing Objects * An Example: Part IV An Example * New Buttons: Part IV New Buttons * Using a Pre-emptive Handler: Part IV Using a Pre-emptive Handler * Part V - General Informations: Part V * Overview of Main Functions: Part V Overview of Main Functions * Some Useful Functions: Part V Some Useful Functions * Resources for Forms Library: Part V Resources for Forms Library * Dirty Tricks: Part V Dirty Tricks * Trouble Shooting: Part V Trouble Shooting * Part VI - Image Supprt API: Part VI * Part VI Images:: * Index of Functions:: * Index of Global Variables:: * Index of Constants::  File: xforms.info, Node: Preface, Next: Part I, Prev: Top, Up: Top _Preface_ ********* The Forms Library for the X Window system (or XForms for short) is a GUI toolkit with a rather long history. It was developed in the last decade of the last millenium by *Dr. T. C. Zhao* (then at the Department of Physics, University of Wisconsin-Milwaukee, USA) and *Prof. Dr. Mark Overmars* (Department of Computer Science, Utrecht University, Netherlands) at a time when there were hardly any alternatives except expensive packages. While at first being closed source it became open source software in 2002, distributed according to the Lesser GNU Public License (LGPLv2). While development slowed down a bit while other toolkits became available and matured, XForms is still used, and development continues. While it may not be as polished as newer toolkits it has the advantage of being relatively small and thus easier to get started with it. The XForms home page is at `http://xforms-toolkit.org/' The sources and mailing list are hosted on `https://savannah.nongnu.org/projects/xforms/' The source package can be downloaded from `http://download.savannah.gnu.org/releases/xforms/' while the `git' repository can be accessed via `git://git.savannah.nongnu.org/xforms.git' `http://git.savannah.gnu.org/cgit/xforms.git' `ssh://git.sv.gnu.org/srv/git/xforms.git' There also is a mailing list. You can subscribe to it at `http://lists.nongnu.org/mailman/listinfo/xforms-development' The archive of the mailing list can be found at `http://lists.gnu.org/archive/html/xforms-development/' The archive of messages from before August 2009 and going back until 1996 is at `http://xforms-toolkit.org/old-archive' Please write to the mailing list if you have questions or find bugs. This document is based on the documentation for version 0.89 of the Forms Library. It has been reconstructed from the PDF version (the original sources seem to have been lost) and has been updated to cover all changes introduced since version 0.89. In the following the preface for the last available version of the documentation (version 0.89 from June 2000) is reproduced. Please note that quite a bit of the information there-in is outdated. Many of the URLs mentioned don't exist anymore, email addresses have changed and the restrictions on the distribution of the library have been removed by the original authors in favor of the LGPL. *Preface of Version 0.89 (June 2000)* Window-based user interfaces are becoming a common and required feature for most computer systems, and as a result, users have come to expect all applications to have polished user-friendly interfaces. Unfortunately, constructing user interfaces for programs is in general a time consuming process. In the last few years a number of packages have appeared that help build up graphical user interfaces (so-called GUI's) in a simple way. Most of them, though, are difficult to use and/or expensive to buy and/or limited in their capabilities. The Forms Library was constructed to remedy this problem. The design goals when making the Forms Library were to create a package that is intuitive, simple to use, powerful, graphically good looking and easily extendible. The main notion in the Forms Library is that of a form. A form is a window on which different objects are placed. Such a form is displayed and the user can interact with the different objects on the form to indicate his/her wishes. Many different classes of objects exist, like buttons (of many different flavors) that the user can push with the mouse, sliders with which the user can indicate a particular setting, input fields in which the user can provide textual input, menus from which the user can make choices, browsers in which the user can scroll through large amounts of text (e.g., help files), etc. Whenever the user changes the state of a particular object on one of the forms displayed the application program is notified and can take action accordingly. There are a number of different ways in which the application program can interact with the forms, ranging from very direct (waiting until something happens) to the use of callback routines that are called whenever an object changes state. The application program has a large amount of control over how objects are drawn on the forms. It can set color, shape, text style, text size, text color, etc. In this way forms can be fine tuned to one's liking. The Forms Library consists of a large number of C-routines to build up interaction forms with buttons, sliders, input fields, dials, etc. in a simple way. The routines can be used both in C and in C++ programs. The library uses only the services provided by the Xlib and should run on all workstations that have X installed on them. The current version needs 4bits of color (or grayscale) to look nice, but it will function properly on workstations having less depth (e.g., XForms works on B&W X-terminals). The library is easy to use. Defining a form takes a few lines of code and interaction is fully handled by the library routines. A number of demo programs are provided to show how easy forms are built and used. For simple forms and those that may be frequently used in application programs, e.g., to ask a question or select a file name, special routines are provided. For example, to let the user choose a file in a graphical way (allowing him/her to walk through the directory hierarchy with a few mouse clicks) the application program needs to use just one line of code. To make designing forms even easier a Form Designer is provided. This is a program that lets you interactively design forms and generate the corresponding C-code. You simply choose the objects you want to place on the forms from a list and draw them on a form. Next you can set attributes, change size and position of the objects, etc., all using the mouse. Although this document describes all you need to know about using the Forms Library for X, it is not an X tutorial. On the contrary, details of programming in X are purposely hidden in the Forms Library interfaces, and one need not be an X-expert to use the Forms Library, although some knowledge of how X works would help to understand the inner workings of the Forms Library. Forms Library and all the programs either described in this document or distributed as demos have been tested under X11 R4, R5 & R6 on all major UNIX platforms, including SGI, SUN, HP, IBM RS6000/AIX, Dec Alpha/OSF1, Linux(i386, alpha, m68k and sparc) as well as FreeBSD, NetBSD (i386, m68k and sparc), OpenBSD(i386, pmax, sparc, alpha), SCO and Unixware. Due to access and knowledge, testing on non-unix platforms such as OpenVMS, OS/2 and Microsoft/NT are less than comprehensive. This document consists of four parts. The first part is a tutorial that provides an easy, informal introduction to the Forms Library. This part should be read by everybody that wants to use the library. You are encouraged to try variations of the demo programs distributed in the Forms Library package. Part II describes the Form Designer with which you can design forms interactively and haveForm Designer write code for you. Part III gives an overview of all object classes currently available in the library. The tutorial part only mentions the most basic classes but here you find a complete overview. Adding new object classes to the system is not very complicated. Part IV describes how this should be done. *Version Note* The authors request that the following name(s) be used when referring to this toolkit Forms Library for X, Forms Library or simply XForms Forms Library is not public domain. It is copyright (c) by T.C. Zhao and Mark Overmars, and others, with all published and unpublished rights reserved. However, permission to use for non-commercial and not-for-profit purposes is granted. You may not use xforms commercially (including in-house and contract/consulting use) without contacting (xforms@world.std.com) for a license arrangement. Use of xforms for the sole purpose of running a publically available free software that requires it is not considered a commercial use, even in a commercial setting. You may not "bundle" and distribute this software with commercial systems without prior consent of the authors. Permission to distribute this software with other free software that requires it, including Linux CD distribution, is granted. Further, permission to re-package the software is granted. This software is provided "as is" without warranty of any kind, either expressed or implied. The entire risk as to the quality and performance of the software is with you. Should the software prove defective, you assume the cost of all necessary servicing, repair or correction and under no circumstance shall the authors be liable for any damages resulting from the use or mis-use of this software. It would be appreciated if credit to the authors is acknowledged in published articles on applications based on the library. A reprint of the article would also be appreciated. The development environment for xforms consists of Linux 1.0.8/a.out X11R5 and Linux 2.0/ELF X11R6 with additional testing and validation on SGI R8000 and occasionally IBM RS6000/AIX and other machines. For every public release, most of the demos and some internal testing programs are run on each platform to ensure quality of the distribution. Figures in this document were produced by fd2ps, a program that takes the output of the form designer and converts the form definition into an encapsulated POSTSCRIPT file. fd2ps as ofXForms V0.85 is included in the distribution. This document is dated June 12, 2000. *Support* Although XForms has gone through extensive testing, there are most likely a number of bugs remaining. Your comments would be greatly appreciated. Please send any bug reports or suggestions to T.C. Zhao (tc_zhao@yahoo.com or xforms@world.std.com but not both). Please do not expect an immediate response, but we do appreciate your input and will do our best. *Bindings to other languages* As of this writing, the authors are aware of the following bindings perl binding by Martin Bartlett () ada95 binding by G. Vincent Castellano () Fortran binding by G. Groten () and Anke Haeming () pascal binding by Michael Van Canneyt () scm/guile binding by Johannes Leveling () python binding by Roberto Alsina (). (Seems the author has stopped working on this binding). Follow the links on XForms's home page to get more info on these bindings. *Archive Sites* Permanent home for the Forms Library is at ftp://ncmir.ucsd.edu/pub/xforms ftp://ftp.cs.ruu.nl/pub/XFORMS (Primary mirror site) The primary site is mirrored by many sites around the world. The following are some of the mirror sites ftp://ftp.fu-berlin.de/unix/X11/gui/xforms ftp://gd.tuwien.ac.at/hci/xforms ftp://ftp.st.ryukoku.ac.jp/pub/X11/xforms ftp://ftp.via.ecp.fr/pub2/xforms ftp://ftp.unipi.it/pub/mirror/xforms ftp://ftp.uni-trier.de/pub/unix/X11/xforms Additional mirrors, html version of this document, news and other information related to XForms can be accessed through www via the following URL http://world.std.com/~xforms In addition to ftp and www server, a mail server is available for those who do not have direct internet access. To use the mail server, send a message to or the old-fashioned path alternative . The message should be something like the following begin path fred@stone.age.edu (substitute your address) send help end To get a complete listing of the archive tree, issue send ls-lR.Z. *Mailing List* A mailing list for news and discussions about XForms is available. To subscribe or un-subscribe, send a message to with one of the following commands as the mail body help subscribe unsubscribe To use the mailing list, send mail to . Please remember that the message will be sent to hundreds of people. Please Do not send subscribe/unsubscribe messages to the mailing list, send them to . The mailing list archive is at `http://bob.usuhs.mil/mailserv/list-archives'. *Thanks* Many people contributed, in one way or another, to the development of Forms Library, without whose testing, bug reports and suggestions, Forms Library would not be what it is today and would certainly not be in the relatively bug free state it is in now. We thank Steve Lamont of UCSD (), for his numerous suggestions and voluminous contributions to the mailing list. We thank Erik Van Riper (), formerly of CUNY, and Dr. Robert Williams of USUHS () for running the mailing list and keeping it running smoothly. We also thank every participant on the mailing list who contributed by asking questions and challenging our notion of what typical use of the Forms Library is. The html version of the document, undoubtedly browsed by the thousands, is courtesy of Danny Uy (). We appreciate the accurate and detailed bug reports, almost always accompanied with a demo program, from Gennady Sorokopud () and Rouben Rostamian (). We also thank Martin Bartlett (), who, in addition to marrying Forms Library to perl, made several xforms API suggestions, Last but certainly not least, we thank Henrik Klagges () for his numerous suggestions during the early stages of the development.  File: xforms.info, Node: Part I, Next: Part I Introduction, Prev: Preface, Up: Top _Part I - Using the Forms Library_ ********************************** * Menu: * Part I Introduction:: * Part I Getting Started:: * Part I Defining Forms:: * Part I Doing Interaction:: * Part I Free Objects:: * Part I Goodies::  File: xforms.info, Node: Part I Introduction, Next: Part I Getting Started, Prev: Part I, Up: Top 1 Introduction ************** The Forms Library is a library of C-routines that allows you to build up interaction forms with buttons, sliders, input fields, dials, etc. in a very simple way. Following the X tradition, Forms Library does not enforce the look and feel of objects although in its default state, it does provide a consistent look and feel for all objects. The Forms Library only uses the services provided by Xlib and should be compilable on all machines that have X installed and have an ANSI compatible compiler. Being based on Xlib,Forms Library is small and efficient. It can be used in both C and C++ programs and soon it will be available for other languages(1). The basic procedure of using the Forms Library is as follows. First one or more forms are defined, by indicating what objects should be placed on them and where. Types of objects that can be placed on the forms include: boxes, texts, sliders, buttons, dials, input fields and many more. Even a clock can be placed on a form with one command. After the form has been defined it is displayed on the screen and control is given to a library call `*note fl_do_forms()::'. This routine takes care of the interaction between the user and the form and returns as soon as some change occurs in the status of the form due to some user action. In this case control is returned to the program (indicating that the object changed) and the program can take action accordingly, after which control is returned again to the `*note fl_do_forms()::' routine. Multiple forms can be handled simultaneously by the library and can be combined with windows of the application program. More advanced event handling via object callbacks is also supported. The Forms Library is simple to use. Defining a form takes a few lines of code and interaction is fully handled by the library routines. A number of demo programs are provided to show how to piece together various parts of the library and demonstrate how easy forms are built and used. They can be found in the directory `demos'. Studying these demos is a good way of learning the system. If you only have very simple applications for the Forms Library, e.g., to ask the user for a file name, or ask him a question or give him a short message, *note Goodies: Part I Goodies. contains some even more simple routines for this. So, e.g., a form with the question "Do you want to quit?" can be made with one line of code. To make designing forms even easier a Form Designer is provided. As its name implies, this is a program that lets you interactively design forms and generate the corresponding C-code. *Note Introduction: Part II Introduction, and the following chapters for its use. The current version of the software is already quite extended but we are working on further improvements. In particular, we plan on designing new classes of objects that can be placed on the forms. Adding classes to the system is not very complicated. Part IV of this document describes in detail how to do this yourself. The following chapters will describe the basic application programmer's interface to the Forms Library and lead you through the different aspects of designing and using forms. In *note Part I Getting Started:: we give some small and easy examples of the design and use of forms. In *note Defining Forms: Part I Defining Forms. we describe how to define forms. This chapter just contains the basic classes of objects that can be placed on forms. Also, for some classes only the basic types are described and not all. For an overview of all classes and types of objects see Part III of this document. *note Doing Interaction: Part I Doing Interaction. describes how to set up interaction with forms. A very specific class of objects are free objects and canvases. The application program has full control over their appearance and interaction. They can be used to place anything on forms that is not supported by the standard objects. *note Free Objects: Part I Free Objects. describes their use. Finally, *note Goodies: Part I Goodies. describes some built-in routines for simple interaction like asking questions and prompting for choices etc. ---------- Footnotes ---------- (1) As of this writing, perl, Ada95, scheme, pascal, Fortran and python bindings are in beta testing.  File: xforms.info, Node: Part I Getting Started, Next: Part I Defining Forms, Prev: Part I Introduction, Up: Top 2 Getting Started ***************** This chapter introduces the typographical conventions used throughout the manual and then continues with showing a few, simple examples on using the Forms Library. It concludes with a short resumee of the programming model typically found in programs using the library. * Menu: * Naming Conventions:: * Some Examples:: * Programming Model::  File: xforms.info, Node: Naming Conventions, Next: Some Examples, Up: Part I Getting Started 2.1 Naming Conventions ====================== The names of all Forms Library functions and user-accessible data structures begin with `fl_' or `FL_', and use an "underscore-between-words" convention, that is when function and variable names are composed of more than one word, an underscore is inserted between each word. For example, fl_state fl_set_object_label() fl_show_form() All Forms Library macros, constants and types also follow this convention, except that (at least) the first two letters are capitalized. For example, FL_min() FL_NORMAL_BUTTON FL_OBJECT The term "form" often can be taken to mean a window of your application. But be aware that there are also can be forms that themselves contain further forms, so "form" and "window" aren't necessarily synonyms. The only exceptions from the above convention are names of functions related to image manipulations - they start with `flimage_'. And then there's a single function called `*note flps_init()::' that allows customization of the way hardcopies are created from an existing user interface.  File: xforms.info, Node: Some Examples, Next: Programming Model, Prev: Naming Conventions, Up: Part I Getting Started 2.2 Some Examples ================= Before using forms for interaction with the user you first have to define them. Next you can display them and perform interaction with them. Both stages are simple. Before explaining all the details let us first look at some examples. A very simple form definition would look as FL_FORM *simpleform; simpleform = fl_bgn_form(FL_UP_BOX, 230, 160); fl_add_button(FL_NORMAL_BUTTON, 40, 50, 150, 60, "Push Me"); fl_end_form(); The first line indicates the start of the form definition. `simpleform' will later be used to identify the form. The type of the form is `FL_UP_BOX'. This means that the background of the form is a raised box that looks like it is coming out of the screen. The form has a size of 230 by 160 pixels. Next we add a button to the form. The type of the button is `FL_NORMAL_BUTTON' which will be explained below in detail. It is positioned in the form by virtue of the button geometry supplied and has "Push Me" as its label. After having defined the form we can display it using the call fl_show_form(simpleform, FL_PLACE_MOUSE, FL_NOBORDER, "SimpleForm"); [image src="xforms_images/pushme.png"] This will show the form on the screen at the mouse position. (The third argument indicates whether the form gets window manager's decoration and the fourth is the window title.) Next we give the control over the interaction to the Forms Library's main event loop by calling fl_do_forms(); This will handle interaction with the form until you press and release the button with the mouse, at which moment control is returned to the program. Now the form can be removed from the screen (and have its associated window destroyed) using fl_hide_form(simpleform); The complete program is given in the file `pushme.c' in the subdirectory `demos'. All demonstration programs can be found in this directory. Studying them is a good way of learning how the library works. Compile and run it to see the effect. To compile a program using the Forms Library use the following command or something similar cc -o pushme pushme.c -lforms Please note that linking against the Forms library requires some other libraries to be istalled, at least the `X11' and the `Xpm' library. Some applications may also require the `JPEG' and/or the `GL' library. These libraries don't need to be specified explicitely in the linker command but must be available since the Forms library depends on them. If not installed contact your systems administrator. This simple example is, of course, of little use. Let us look at a slightly more complicated one (the program can be found in `yesno.c'.) #include int main(int argc, char *argv[]) { FL_FORM *form; FL_OBJECT *yes, *no, *but; fl_initialize(&argc, argv, "FormDemo", 0, 0); form = fl_bgn_form(FL_UP_BOX, 320, 120); fl_add_box(FL_NO_BOX, 160, 40, 0, 0, "Do you want to Quit?"); yes = fl_add_button(FL_NORMAL_BUTTON, 40, 70, 80, 30, "Yes"); no = fl_add_button(FL_NORMAL_BUTTON, 200, 70, 80, 30, "No"); fl_end_form(); fl_show_form(form, FL_PLACE_MOUSE, FL_TRANSIENT, "Question"); while (1) { if (fl_do_forms() == yes) { printf("Yes is pushed\n"); break; } else printf("No is pushed\n"); } fl_finish(); return 0; } It creates a form with a simple text and two buttons. After displaying the form `*note fl_do_forms()::' is called. This routine returns the object being pushed. Simply checking whether this is object `yes' or `no' determines whether we should quit. [image src="xforms_images/yesno.png"] As you see, the program starts by calling the routine `*note fl_initialize()::'. This routine should be called before any other calls to the library are made (except for `*note fl_set_defaults()::'). One of the things this routine does is to establish a connection to the X server and initialize a resource database used by the X resource manager. It also does many other things, such as parsing command line options and initializing internal Forms Library structures. For now, it suffices to know that by calling this routine, a program automatically recognizes the following command line options Option Value type Meaning ---------------------------------------------------------------------------- `-display' host:dpy string Remote host `-name' appname string change application name `-visual' class string TrueColor, PseudoColor etc. `-depth' depth integer Preferred visual depth `-private' none Force a private colormap `-shared' none Always share colormap `-stdcmap' none Use standard colormap `-fldebug' level integer Print some debug information `-flhelp' none Print out these options `-sync' none Force synchronous mode Note that the executable name `argv[0]' should not contain period or `*'. *Note Overview of Main Functions: Part V Overview of Main Functions, for further details. The above program can in fact be made a lot simpler, using the goodies described in *note Goodies: Part I Goodies. You can simply write: while (!fl_show_question("Do you want to Quit?", 0)) /* empty */ ; Except printing out a message telling which button was pressed it will have exactly the same effect. The above program only shows one of the event handling methods provided by the library. The direct method of event handling shown is appropriate for simple programs. But, obviously, already for a program with just a few nmore objects it would become rather tedious to have to check each time `*note fl_do_forms()::' returns each of those objects to find out which of them was responsible and react accordingly. Utilizing object callback functions is then typically much easier and thus os strongly recommended. We demonstrate the use of object callbacks using the previous example with some modifications so that event processing via callbacks is utilized. It is recommended and also typical of a good XForms application to separate the UI components and the application program itself. Typically the UI components are generated by the bundled GUI builder and the application program consists mostly of callbacks and some glue code that combines the UI and the program. To use callbacks, a typical procedure would be to define all the callback functions first, then register them with the system using `*note fl_set_object_callback()::'. After the form is realized (shown), control is handed to Forms Library's main loop `*note fl_do_forms()::', which responds to user events indefinitely and never returns. After modifications are made to utilize object callbacks, the simple question example looks as follows: #include #include #include void yes_callback(FL_OBJECT *obj, long user_data) { printf("Yes is pushed\n"); fl_finish(); exit(0); } void no_callback(FL_OBJECT *obj, long user_data) { printf("No is pushed\n"); } int main(int argc, char *argv[]) { FL_FORM *form; FL_OBJECT *obj; fl_initialize(&argc, argv, "FormDemo", 0, 0); form = fl_bgn_form(FL_UP_BOX, 320, 120); fl_add_box(FL_NO_BOX, 160, 40, 0, 0, "Do you want to Quit?"); obj = fl_add_button(FL_NORMAL_BUTTON, 40, 70, 80, 30,"Yes"); fl_set_object_callback(obj, yes_callback, 0); obj = fl_add_button(FL_NORMAL_BUTTON, 200, 70, 80, 30,"No"); fl_set_object_callback(obj, no_callback, 0); fl_end_form(); fl_show_form(form, FL_PLACE_MOUSE, FL_TRANSIENT, "Question"); fl_do_forms(); return 0; } In this example, callback routines for both the yes and no buttons are first defined. Then they are registered with the system using `*note fl_set_object_callback()::'. After the form is shown, the event handling is again handed to the main loop in Forms Library via `*note fl_do_forms()::'. In this case, whenever the buttons are pushed, the callback routine is invoked with the object being pushed as the first argument to the callback function, and `*note fl_do_forms()::' never returns. You might also have noticed that in this example both buttons are made anonymous, that is, it is not possible to reference the buttons outside of the creating routine. This is often desirable when callback functions are bound to objects as the objects themselves will not be referenced except as callback arguments. By creating anonymous objects a program avoids littering itself with useless identifiers. The callback model presented above is the preferred way of interaction for typical programs and it is strongly recommended that programs using XForms be coded using object callbacks.  File: xforms.info, Node: Programming Model, Prev: Some Examples, Up: Part I Getting Started 2.3 Programming Model ===================== To summarize, every Forms Library application program must perform several basic steps. These are Initialize the Forms Library This step establishes a connection to the X server, allocates resources and otherwise initializes the Forms Library's internal structures, which include visual selection, font initialization and command line parsing. Defining forms Every program creates one or more forms and all the objects on them to construct the user interface. This step may also include callback registration and per object initialization such as setting bounds for sliders etc. Showing forms This step makes the designed user interface visible by creating and mapping the window (and subwindows) used by the forms. Main loop Most Forms Library applications are completely event-driven and are designed to respond to user events indefinitely. The Forms Library main loop, usually invoked by calling `*note fl_do_forms()::', retrieves events from the X event queue, dispatches them to the appropriate objects and notifies the application of what action, if any, should be taken. The actual notification method depends on how the interaction is set up, which could be done by calling an object callback or by returning the object whose status has changed to the application program. The following chapters will lead you through each step of the process with more details.  File: xforms.info, Node: Part I Defining Forms, Next: Part I Doing Interaction, Prev: Part I Getting Started, Up: Top 3 Defining Forms **************** In this chapter we will describe the basics of defining forms. Not all possible classes of objects are described here, only the most common ones. Also, for most classes only a subset of the available types are described. See Part III for a complete overview of all object classes currently available. Normally you will almost never have to write the code to define forms yourself because the package includes a Form Designer that does this for you (see Part II). Still it is useful to read through this chapter because it explains what some of the different object classes are and how to work with them. * Menu: * Starting and Ending a Form Definition:: * Boxes:: * Texts:: * Buttons:: * Sliders:: * ValSliders:: * Input Fields:: * Grouping Objects:: * Hiding and Showing:: * Deactivating and Triggering Objects:: * Changing Attributes:: * Adding and Removing Objects:: * Freeing Objects::  File: xforms.info, Node: Starting and Ending a Form Definition, Next: Boxes, Up: Part I Defining Forms 3.1 Starting and Ending a Form Definition ========================================= A form consists of a collection of objects. A form definition is started with the routine FL_FORM *fl_bgn_form(int type, FL_Coord w, FL_Coord h); `w' and `h' indicate the width and height of the form (in pixels by default). Positions in the form will be indicated by integers between 0 and `w-1' or `h-1'. The actual size of the form when displayed on the screen can still be varied. `type' indicates the type of the background drawn in the form. The background of each form is a box. See the next section for the different types available. The routine returns a pointer to the form just defined. This pointer must be used, for example, when drawing the form or doing interaction with it. The form definition ends with void fl_end_form(void); Between these two calls objects are added to the form. The following sections describe some of the more common classes of objects that can be added to a form. there's no built-in upper limit on the number of forms that can be defined and displayed when required. Normally you probably will first define all your forms before starting the actual work but it's no problem to define new forms also later on.  File: xforms.info, Node: Boxes, Next: Texts, Prev: Starting and Ending a Form Definition, Up: Part I Defining Forms 3.2 Boxes ========= The probably simplest type of objects are boxes. Boxes are used to give the forms and objects a nicer appearance. They can be used to visually group other objects together. The background of each form is a box. To add a box to a form you use the routine FL_OBJECT *fl_add_box(int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label); where `type' indicates the shape of the box. The Forms Library at the moment supports the following types of boxes: `FL_NO_BOX' No box at all (it's transparent), just a label `FL_UP_BOX' A box that comes out of the screen `FL_DOWN_BOX' A box that goes down into the screen `FL_BORDER_BOX' A flat box with a border `FL_SHADOW_BOX' A flat box with a shadow `FL_FRAME_BOX' A flat box with an engraved frame `FL_ROUNDED_BOX' A rounded box `FL_EMBOSSED_BOX' A flat box with an embossed frame `FL_FLAT_BOX' A flat box without a border (normally invisible unless given a different color than the surroundings) `FL_RFLAT_BOX' A rounded box without a border (normally invisible unless given a different color than the surroundings) `FL_RSHADOW_BOX' A rounded box with a shadow `FL_OVAL_BOX' A box shaped like an ellipse `FL_ROUNDED3D_UPBOX' A rounded box coming out of the screen `FL_ROUNDED3D_DOWNBOX' A rounded box going into the screen `FL_OVAL3D_UPBOX' An oval box coming out of the screen `FL_OVAL3D_DOWNBOX' An oval box going into the screen [image src="xforms_images/boxtypes.png"] The arguments `x' and `y' in the call of `*note fl_add_box()::'indicate the upper left corner of the box in the form while `w' and `h' are its width and height. `label' is a text that is placed in the center of the box. If you don't want a label in the box use an empty string or a `NULL' pointer. The label can be either one line or multiple lines. To obtain multi-line labels, insert newline characters (`\n') in the label string. It is also possible to underline the label or one of the characters in the label. This is accomplished by embedding ` H' (`\010' or `'\b'') after the letter that needs to be underlined. If the very first character of the label is `H', the entire label is underlined. The routine `*note fl_add_box()::' returns a pointer to the box object. (All routines that add objects return a pointer to the object.) This pointer can be used for later references to the object. It is possible to change the appearance of a box in a form. First of all, it is possible to change the color of the box and secondly, it is possible to change color, size and position of the label inside the box. Details on changing attributes of objects can be found in *note Changing Attributes::. Just a simple example has to suffice here. Assume we want to create a red box, coming out of the screen with the large words "I am a Box" in green in the center: FL_OBJECT *thebox; thebox = fl_add_box(FL_UP_BOX, 20, 20, 100, 100, "I am a Box"); fl_set_object_color(thebox, FL_RED, 0 ); /* make box red */ fl_set_object_lcolor(thebox, FL_GREEN ); /* make label green */ fl_set_object_lsize(thebox, FL_LARGE_SIZE); /* make label large */ Of course, this has to be placed inside a form definition (but the functions for changing the object attributes can also used anywhere else within the program).  File: xforms.info, Node: Texts, Next: Buttons, Prev: Boxes, Up: Part I Defining Forms 3.3 Texts ========= A second type of object is text. Text can be placed at any place on the form in any color you like. Placing a text object is done with the routine FL_OBJECT *fl_add_text(int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label); where `type' indicates the shape of the text. The Forms Library at the moment supports only one type of text: `FL_NORMAL_TEXT'. The text can be placed inside a box using the routine `*note fl_set_object_boxtype()::' to be described in *note Changing Attributes::. Again, the text can be multi-lined or underlined by embedding respectively the newline (`\n') or `H' (`\010' or `'\b'') in the label. The style, size and color of the text can be controlled and changed in many ways, *note Label Attributes and Fonts::. 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 object. Text is normally placed inside the box at the left side. This helps you put different lines of text below each other. Labels inside boxes are by default centered in the box. You can change the position of the text inside the box using the routines in *note Label Attributes and Fonts::. Note that, when not using any box around the text there is no need to specify a width and height of the box, they can both be 0.  File: xforms.info, Node: Buttons, Next: Sliders, Prev: Texts, Up: Part I Defining Forms 3.4 Buttons =========== A very important class of objects are 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. Adding a button to a form can be done using the following routine FL_OBJECT *fl_add_button(int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label); `label' is the text placed inside (or next to) the button. `type' indicates the type of the button. The Forms Library at the moment supports a number of types of buttons. The most important ones are: FL_NORMAL_BUTTON FL_PUSH_BUTTON FL_TOUCH_BUTTON FL_RADIO_BUTTON They all look the same on the screen but their functions are quite different. Each of these buttons get pushed down when the user presses the mouse on top of them. What actually happens when the user does so depends on the type of button. A normal button returns to its normal position when the user releases the mouse button. A push button remains pushed and is only released when the user pushes it again. A touch button is like a normal button except that as long as the user keeps the mouse pressed it is returned to the application program (*note Doing Interaction: Part I Doing Interaction. on the details of interaction). A radio button is a push button with additional extra property: Whenever the user pushes a radio button, all other pushed radio buttons in the form (or at least in the group, see below) they belong to are released. In this way the user can make a choice among some mutually exclusive possibilities. Whenever the user pushes a button and then releases the mouse, the interaction routine `*note fl_do_forms()::' is interrupted and returns a pointer to the button that was pushed and released. If a callback routine is present for the object being pushed, this routine will be invoked. In either case, the application program knows that the button was pushed and can take action accordingly. In the first case, control will have to be returned to `*note fl_do_forms()::' again after the appropriate action is performed; and in the latter, `*note fl_do_forms()::' would never return. *Note Doing Interaction: Part I Doing Interaction, for details on the interaction with forms. Different types of buttons are used in all the example programs provided. The application program can also set a button to appear pushed or not without user action. This is of course only useful for push buttons and radio buttons. To set or reset a push or radio button use the routine void fl_set_button(FL_OBJECT *obj, int pushed); `pushed' indicates whether the button should appear to be pushed (1) or released (0). Note that this does not invoke a callback routine bound to the button or results in the button getting returned to the program, i.e., only the visual appearance of the button is changed and what it returns when asked for its state (and, in the case of a radio button, possibly that of another radio button in the same group). To also get the callback invoked or the button returned to the program additonally call e.g., `*note fl_trigger_object()::'. To figure out whether a button appears as pushed or not use int fl_get_button(FL_OBJECT *obj); See the program `pushbutton.c' for an example of the use of push buttons and setting and getting button information. The color and label of buttons can again be changed using the routines in *note Changing Attributes::. There are other classes of buttons available that behave the same way as buttons but only look different. Light buttons have a small "light" (colored area) in the button. Pushing the button switches the light on, and releasing the button switches it off. To add a light button use `*note fl_add_lightbutton()::' with the same parameters as for normal buttons. The other routines are exactly the same as for normal buttons. The color of the light can be controlled with the routine `*note fl_set_object_color()::', *note Changing Attributes::. Round buttons are buttons that are round. Use `*note fl_add_roundbutton()::' to add a round button to a form. Round3d buttons are buttons that are round and 3D-ish looking. Round and light buttons are nice as radio and push buttons. Check buttons are buttons that have a small checkbox the user can push. To add a check button, use `*note fl_add_checkbutton()::'. More stylish for a group of radio buttons. Bitmap buttons are buttons that have a bitmap on top of the box. Use routine `*note fl_add_bitmapbutton()::' to add a bitmap button to a form. Pixmap buttons are buttons that have a pixmap on top of the box. Use routine `*note fl_add_pixmapbutton()::' to add a pixmap button to a form. Playing with different boxtypes, colors, etc., you can make many different types of buttons. See `buttonall.c' for some examples. Fig. 16.1 shows all buttons in their default states.  File: xforms.info, Node: Sliders, Next: ValSliders, Prev: Buttons, Up: Part I Defining Forms 3.5 Sliders =========== Sliders are useful in letting the user indicate a value between some fixed bounds. A slider is added to a form using the routine FL_OBJECT *fl_add_slider(int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label); The two most important types of sliders are `FL_VERT_SLIDERM' and `FL_HOR_SLIDER'. The former displays a slider that can be moved vertically and the latter gives a slider that moves horizontally. In both cases the label is placed below the slider. Default value of the slider is 0.5 and can vary between 0.0 and 1.0. These values can be changed using the routines: void fl_set_slider_value(FL_OBJECT *obj, double val); void fl_set_slider_bounds(FL_OBJECT *obj, double min, double max); Whenever the value of the slider is changed by the user, it results in the slider being returned to the application program or the callback routine invoked. The program can read the slider value using the call double fl_get_slider_value(FL_OBJECT *obj); and take action accordingly. See the example program `demo05.c' for the use of these routines. [image src="xforms_images/slider.png"]  File: xforms.info, Node: ValSliders, Next: Input Fields, Prev: Sliders, Up: Part I Defining Forms 3.6 ValSliders ============== A valslider is almost identical with a normal slider. The only difference is the way the slider is drawn. For valsliders, in addition to the slider itself, its current value is also shown. To add a valslider, use FL_OBJECT *fl_add_valslider(int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label); For all other interaction with a valslider the same function as for normal sliders can be used.  File: xforms.info, Node: Input Fields, Next: Grouping Objects, Prev: ValSliders, Up: Part I Defining Forms 3.7 Input Fields ================ It is often required to obtain textual input from the user, e.g., a file name, some fields in a database, etc. To this end input fields exist in the Forms Library. An input field is a field that can be edited by the user using the keyboard. To add an input field to a form use FL_OBJECT *fl_add_input(int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label); The main type of input field available is `FL_NORMAL_INPUT'. The input field normally looks like an `FL_DOWN_BOX'. This can be changed using the routine `*note fl_set_object_boxtype()::' to be described in *note Changing Attributes::. Whenever the user presses the mouse inside an input field a cursor will appear in it (and it will change color). Further input will appear inside this field. Full emacs(1) style editing is supported. When the user presses `' or `' the input field is returned to the application program and further input is directed to the next input field. (The `' key only works if there are no default buttons in the form. See the overview of object classes. The `' key always works.) [image src="xforms_images/input.png"] The user can use the mouse to select parts of the input field which will be removed when the user types the erase character or replaced by any new input the user types in. Also the location of the cursor can be moved in the input field using the mouse. The input field is fully integrated with the X Selection mechanism. Use the left button to cut from and the middle button to paste into an input field. The application program can direct the focus to a particular object using the call void fl_set_focus_object(FL_FORM *form, FL_OBJECT *obj); It puts the input focus in the form form onto object `obj'. To obtain the focus object, the following routine is available FL_OBJECT *fl_get_focus_object(FL_FORM *form); Note that the label is not the default text in the input field. The label is (by default) placed in front of the input field. To set the contents of the input field use the routines void fl_set_input(FL_OBJECT *obj, const char *str); void fl_set_input_f(FL_OBJECT *obj, const char *fmt, ...); 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. To obtain the string in the field (when the user has changed it) use: const char *fl_get_input(FL_OBJECT *obj); See the program `demo06.c' for an example of the use of input fields.  File: xforms.info, Node: Grouping Objects, Next: Hiding and Showing, Prev: Input Fields, Up: Part I Defining Forms 3.8 Grouping Objects ==================== Objects inside a form definition can be grouped together. To this end we place them in between the routines FL_OBJECT *fl_bgn_group(void); and void fl_end_group(void); The first function returns a pointer to a pseudo-object that represents the start of the group (its class is `FL_BEGIN_GROUP'). It can be used in a number of functions to work on the whole group at once. Also the second creates a pseudo-object (of class `FL_END_GROUP'), marking the groups end, but since this object can't be used its address isn't returned. Groups can't be nested. Groups are useful for two reasons. First of all it is possible to hide groups of objects. (*note Hiding and Showing:: below.) This is often very handy. We can, for example, display part of a form only when the user asks for it (see demo program `group.c'. Some attributes are naturally multi-objects, e.g., to glue several objects together using the gravity attribute. Instead of setting the gravity for each object, you can place all related objects inside a group and set the resize/gravity attribute of the group. The second reason is for using radio buttons. As indicated in section 3.4 pushing a radio button makes the currently pushed radio button released. In fact, this happens only with radio buttons in the particular group. So to make two pairs (or more) of radio buttons, simply put each pair in a different group so that they won't interfere with each other. See, e.g., the example program `buttonall.c'. It is a good idea to always put radio buttons in a group, even if you have only one set of them. It is possible to add objects to an existing group FL_OBJECT *fl_addto_group(FL_OBJECT *group); where `group' is the object returned by `*note fl_bgn_group()::'. After this call, you can start adding objects to the group (e.g., `*note fl_add_button()::' etc.). The newly added objects are appended at the end of the group. When through with adding, use `*note fl_end_group()::' as before.  File: xforms.info, Node: Hiding and Showing, Next: Deactivating and Triggering Objects, Prev: Grouping Objects, Up: Part I Defining Forms 3.9 Hiding and Showing ====================== It is possible to temporarily hide certain objects or groups of objects. To this end, use the routine void fl_hide_object(FL_OBJECT *obj); `obj' is the object to hide or the group of objects to hide. Hidden objects don't play any role anymore. All routines on the form act as if the object does not exist. To make the object or group of objects visible again use void fl_show_object(FL_OBJECT *obj); Hiding and showing (groups of) objects are useful to change the appearance of a form depending on particular information provided by the user. You can also make overlapping groups in the form and take care that only one of them is visible. If you want to know if an object is shown you can use int fl_object_is_visible(FL_OBJECT *obj); Please note for an object to be visible also the form it belongs to must be shown, which isn't factored into the return value.  File: xforms.info, Node: Deactivating and Triggering Objects, Next: Changing Attributes, Prev: Hiding and Showing, Up: Part I Defining Forms 3.10 Deactivating and Triggering Objects ======================================== Sometimes you might want a particular object to be temporarily inactive, e.g., you want to make it impossible for the user to press a particular button or to type input in a particular field. For this you can use the routine void fl_deactivate_object(FL_OBJECT *obj); `obj' is the object to be deactivated. When `obj' is a group the whole group is deactivated. To reactivate the group or button use the routine void fl_activate_object(FL_OBJECT *obj); To find out if an object is in active state use the function int fl_object_is_active(FL_OBJECT *obj); Normally you also want to give the user a visual indication that the object is not active. This can, for example, be done by changing the label color to grey (see below). This is not done automatically, so unless you set e.g., a different color the objects appearance won't change on deactivation (or re-activation). It is possible to simulate the action of an object being triggered from within the program by using the following routine void fl_trigger_object(FL_OBJECT *obj); Calling this routine on an object `obj' results in the object returned to the application program or its callback being called if it exists. Note however, there is no visual feedback, i.e., `fl_trigger_object(button)' will not make the button object named `button' appear to be pushed.  File: xforms.info, Node: Changing Attributes, Next: Adding and Removing Objects, Prev: Deactivating and Triggering Objects, Up: Part I Defining Forms 3.11 Changing Attributes ======================== There are a number of general routines that can be used to alter the appearance of any object. * Menu: * Color:: * Bounding Boxes:: * Label Attributes and Fonts:: * Tool Tips:: * Redrawing:: * Changing Many Attributes:: * Symbols::  File: xforms.info, Node: Color, Next: Bounding Boxes, Up: Changing Attributes 3.11.1 Color ------------ To change the color of a particular object use the routine void fl_set_object_color(FL_OBJECT *obj, FL_COLOR col1, FL_COLOR col2); `col1' and `col2' are indices into a colormap. Which colors are actually changed depends on the type of the object. For box and text only `col1' is important. It indicates the color of the box or of the box in which the text is placed. For buttons, `col1' is the color of the button when released and `col2' is the color of the button when pushed. (Note that when changing the color of a button the nice property that the color of a button changes when the mouse moves over it disappears.) For light buttons the two colors indicate the color of the light when off and when on. For bitmap buttons, `col1' is the color of the box and `col2' is the color of the bitmap. For sliders `col1' is the color of the background of the slider and `col2' is the color of the slider itself. Finally, for input objects `col1' is the color of the input field when it is not selected and `col2' is the color when it has input focus, i.e., the user can enter text. For all types of objects, the default colors can be found in the file `forms.h'. For example, for input fields the default colors are `FL_INPUT_COL1' and `FL_INPUT_COL2'. Form Designer comes in very handy in familiarizing you with various attributes since you can change all attributes of an object and immediately see the difference by "test"ing the object. To find out the colors of an object use void fl_get_object_color(FL_OBJECT *obj, FL_COLOR *col1, FL_COLOR *col2); The following pre-defined color symbols can be used in all color change requests. If the workstation does not support this many colors, substitution by the closest color will happen. Name RGB triple --------------------------------------------------------------------- `FL_BLACK' `( 0, 0, 0)' [image src="xforms_images/FL_BLACK.png"] `FL_WHITE' `(255, 255, 255)', [image src="xforms_images/FL_WHITE.png"] `FL_COL1' `(173, 173, 173)' [image src="xforms_images/FL_COL1.png"] `FL_BOTTOM_BCOL' `( 89, 89, 89)' [image src="xforms_images/FL_BOTTOM_BCOL.png"] `FL_RIGHT_BCOL' `( 41, 41, 41)' [image src="xforms_images/FL_RIGHT_BCOL.png"] `FL_MCOL' `(191, 191, 191)' [image src="xforms_images/FL_MCOL.png"] `FL_LEFT_BCOL' `(222, 222, 222)' [image src="xforms_images/FL_LEFT_BCOL.png"] `FL_LIGHTER_COL1' `(204, 204, 204)' [image src="xforms_images/FL_LIGHTER_COL1.png"] `FL_DARKER_COL1' `(161, 161, 161)' [image src="xforms_images/FL_DARKER_COL1.png"] `FL_SLATEBLUE' `(113, 113, 198)' [image src="xforms_images/FL_SLATEBLUE.png"] `FL_INDIANRED' `(198, 113, 113)' [image src="xforms_images/FL_INDIANARED.png"] `FL_RED' `(255, 0, 0)' [image src="xforms_images/FL_RED.png"] `FL_BLUE' `( 0, 0, 255)' [image src="xforms_images/FL_BLUE.png"] `FL_GREEN' `( 0, 255, 0)' [image src="xforms_images/FL_GREEN.png"] `FL_YELLOW' `(255, 255, 0)' [image src="xforms_images/FL_YELLOW.png"] `FL_MAGENTA' `(255, 0, 255)' [image src="xforms_images/FL_MAGENTA.png"] `FL_CYAN' `( 0, 255, 255)' [image src="xforms_images/FL_CYAN.png"] `FL_TOMATO' ` 255, 99, 71' [image src="xforms_images/FL_TOMATO.png"] `FL_INACTIVE' `(110, 110, 110)' [image src="xforms_images/FL_INACTIVE.png"] `FL_TOP_BCOL' `(204, 204, 204)' [image src="xforms_images/FL_TOP_BCOL.png"] `FL_PALEGREEN' `(113, 198, 113)' [image src="xforms_images/FL_PALEGREEN.png"] `FL_DARKGOLD' `(205, 149, 10)' [image src="xforms_images/FL_DARKGOLD.png"] `FL_ORCHID' `(205, 105, 201)' [image src="xforms_images/FL_ORCHID.png"] `FL_DARKCYAN' `(40, 170, 175)' [image src="xforms_images/FL_DARKCYAN.png"] `FL_DARKTOMATO' `(139, 54, 38)' [image src="xforms_images/FL_DARKTOMATO.png"] `FL_WHEAT' `(255, 231, 155)' [image src="xforms_images/FL_WHEAT.png"] `FL_DARKORANGE' `(255, 128, 0)' [image src="xforms_images/FL_DARKORANGE.png"] `FL_DEEPPINK' `(255, 0, 128)' [image src="xforms_images/FL_DARKPINK.png"] `FL_CHARTREUSE' `(128, 255, 0)' [image src="xforms_images/FL_CHARTEUSE.png"] `FL_DARKVIOLET' `(128, 0, 255)' [image src="xforms_images/FL_DARKVIOLET.png"] `FL_SPRINGGREEN' `( 0, 255, 128)' [image src="xforms_images/FL_SPRINGGREEN.png"] `FL_DODGERBLUE' `( 0, 128, 255)' [image src="xforms_images/FL_DODGERBLUE.png"] `FL_FREE_COL1' `( ?, ?, ?)' Of all the colors listed in the table above `FL_FREE_COL1' has the largest numerical value, and all color with indices smaller than that are used (or can potentially be used) by the Forms Library although, if you wish, they can also be changed using the following routine prior to `*note fl_initialize()::': void fl_set_icm_color(FL_COLOR index, int r, int g, int b); Note that although the color of an object is indicated by a single index, it is not necessarily true that the Forms Library is operating in PseudoColor. Forms Library is capable of operating in all visuals and as a matter of fact the Forms Library will always select TrueColor or DirectColor if the hardware is capable of it. The actual color is handled by an internal colormap of `FL_MAX_COLORS' entries (default is 1024). To change or query the values of this internal colormap use the call void fl_set_icm_color(FL_COLOR index, int r, int g, int b); void fl_get_icm_color(FL_COLOR index, int *r, int *g, int *b); Call `*note fl_set_icm_color()::' before `*note fl_initialize()::' to change XForms's default colormap. Note that these two routines do not communicate with the X server, they only populate/return information about the internal colormap, which is made known to the X server by the initialization routine `*note fl_initialize()::'. To change the colormap and make a color index active so that it can be used in various drawing routines after `*note fl_initialize()::' initialization, use the following function unsigned long fl_mapcolor(FL_COLOR i, int red, int green, int blue); This function frees the previous allocated pixel corresponding to color index `i' and re-allocates a pixel with the RGB value specified. The pixel value is returned by the function. It is recommended that you use an index larger than `FL_FREE_COL1' for your remap request to avoid accidentally freeing the colors you have not explicitly allocated. Indices larger than 224 are reserved and should not be used. Sometimes it may be more convenient to associate an index with a colorname, e.g., "red" etc., which may have been obtained via resources. To this end, the following routine exists long fl_mapcolorname(FL_COLOR i, const char *name); where `name' is the color name(1). The function returns -1 if the colorname name is not resolved. You can obtain the RGB values of an index by using the following routine unsigned long fl_getmcolor(FL_COLOR i, int *red, int *green, int *blue); The function returns the pixel value as known by the Xserver. If the requested index, `i', is never mapped or is freed, the RGB values as well as the pixel value are random. Since this function communicates with the Xserver to obtain the pixel information, it has a two-way traffic overhead. If you're only interested in the internal colormap of XForms, `*note fl_get_icm_color()::' is more efficient. Note that the current version only uses the lower byte of the primary color. Thus all primary colors in the above functions should be specified in the range of 0-255 inclusive. To free any colors that you no longer need, the following routine should be used void fl_free_colors(FL_COLOR colors[], int ncolors); Prior to XForms version 0.76, there is a color "leakage" in the implementation of the internal colormap that prevents the old index from being freed in the call `*note fl_mapcolor()::', resulting in accelerated colormap overflow and some other undesirable behavior. Since there may still be some applications based on older versions of the Forms Library, a routine is provided to force the library to be compatible with the (buggy) behavior: void fl_set_color_leak(int flag); Due to the use of an internal colormap and the simplified user interface, changing the colormap value for the index may not result in a change of the color for the object. An actual redraw of the object (see below) whose color is changed may be required to have the change take effect. Therefore, a typical sequence of changing the color of a visible object is as follows: fl_mapcolor(newcol, red, green, blue); /* obj uses newcol */ fl_redraw_object(obj); ---------- Footnotes ---------- (1) Standard color names are listed in a file named `rgb.txt' and usually resides in `/usr/lib/X11/'  File: xforms.info, Node: Bounding Boxes, Next: Label Attributes and Fonts, Prev: Color, Up: Changing Attributes 3.11.2 Bounding Boxes --------------------- Each object has a bounding box. This bounding box can have different shapes. For boxes it is determined by the type. For text it is normally not visible. For input fields it normally is a `FL_DOWN_BOX', etc. The shape of the box can be changed using the routine void fl_set_object_boxtype(FL_OBJECT *obj, int boxtype); `boxtype' should be one of the following: `FL_UP_BOX', `FL_DOWN_BOX', `FL_FLAT_BOX', `FL_BORDER_BOX', `FL_SHADOW_BOX', `FL_ROUNDED_BOX', `FL_RFLAT_BOX', `FL_RSHADOW_BOX' and `FL_NO_BOX', with the same meaning as the type for boxes. Some care has to be taken when changing boxtypes. In particular, for objects like sliders, input fields, etc. never use the boxtype `FL_NO_BOX'. Don't change the boxtype of objects that are visible on the screen. It might have undesirable effects. If you must do so, redraw the entire form after changing the boxtype of an object (see below). See the program `boxtype.c' for the effect of the boxtype on the different classes of objects. It is possible to alter the appearance of an object by changing the border width attribute void fl_set_object_bw(FL_OBJECT *obj, int bw); To find out about the current setting for the border width of an object call int fl_get_object_bw(FL_OBJECT *obj); Border width controls the "height" of an object, e.g., a button having a border width of 3 pixels appears more pronounced than one having a border width of 2. The Forms Library's default is `FL_BOUND_WIDTH' (1) pixels (before version 1.0.91 the default was 3). Note that the border width can be negative. Negative border width does not make a down box, rather, it makes the object having an upbox appear less pronounced and "softer". See program `borderwidth.c' for the effect of border width on different objects. All applications developed using XForms accept a command line option `-bw', followed by an integer number, the user can use to select the preferred border width. It is recommended that you document this flag in your application documentation. If you prefer a certain border width, use `*note fl_set_defaults()::' or `*note fl_set_border_width()::' before `*note fl_initialize()::' to set the border width instead of hard-coding it on a per form or per object basis so the user has the option to change it at run time via the `-bw' flag. [image src="xforms_images/borderwidth.png"] There also exists a call that changes the object border width for the entire application void fl_set_border_width(int border_width);  File: xforms.info, Node: Label Attributes and Fonts, Next: Tool Tips, Prev: Bounding Boxes, Up: Changing Attributes 3.11.3 Label Attributes and Fonts --------------------------------- There are also a number of routines to change the appearance of the label. The first one is void fl_set_object_lcolor(FL_OBJECT *obj, FL_COLOR lcol); It sets the color of the label. The default is black (`FL_BLACK'). The font size of the label can be changed using the routine void fl_set_object_lsize(FL_OBJECT *obj, int lsize); where `lsize' gives the size in points. Depending on the server and fonts installed, arbitrary sizes may or may not be possible. Fig 3.5 shows the font sizes that are standard with MIT/XConsortium distribution. So use of these values is encouraged. In any case, if a requested size can not be honored, substitution will be made. The default size for XForms is 10pt. `FL_TINY_SIZE' 8pt `FL_SMALL_SIZE' 10pt `FL_NORMAL_SIZE' 12pt `FL_MEDIUM_SIZE' 14pt `FL_LARGE_SIZE' 18pt `FL_HUGE_SIZE' 24pt [image src="xforms_images/fontsize.png"] Labels can be drawn in many different font styles. The style of the label can be controlled with the routine void fl_set_object_lstyle(FL_OBJECT *obj, int lstyle); The default font for the Forms Library is Helvetica at 10pt. Additional styles are available: `FL_NORMAL_STYLE' Normal text `FL_BOLD_STYLE' Boldface text `FL_ITALIC_STYLE' Guess what `FL_BOLDITALIC_STYLE' BoldItalic `FL_FIXED_STYLE' Fixed width (good for tables) `FL_FIXEDBOLD_STYLE' `FL_FIXEDITALIC_STYLE' `FL_FIXEDBOLDITALIC_STYLE' `FL_TIMES_STYLE' Times-Roman like font `FL_TIMESBOLD_STYLE FL' `FL_TIMESITALIC_STYLE' `FL_TIMESBOLDITALIC_STYLE' `FL_SHADOW_STYLE' Text casting a shadow `FL_ENGRAVED_STYLE' Text engraved into the form `FL_EMBOSSED_STYLE' Text standing out The last three styles are special in that they are modifiers, i.e., they do not cause font changes themselves, they only modify the appearance of the font already active. E.g., to get a bold engraved text, set `lstyle' to `FL_BOLD_STYLE|FL_ENGRAVED_STYLE'. Other styles correspond to the first 12 fonts. The package, however, can handle up to 48 different fonts. The first 16 (numbers 0-15) have been pre-defined. The following table gives their names: 0 helvetica-medium-r 1 helvetica-bold-r 2 helvetica-medium-o 3 helvetica-bold-o 4 courier-medium-r 5 courier-bold-r 6 courier-medium-o 7 courier-bold-o 8 times-medium-r 9 times-bold-r 10 times-medium-o 11 times-bold-o 12 charter-medium-r 13 charter-bold-r 14 charter-medium-i 15 Symbol The other 32 fonts (numbers 16-47) can be filled in by the application program. Actually, the application program can also change the first 16 fonts if required (e.g., to force a particular resolution). To change a font for the the entire application, use one of the following routines: int fl_set_font_name(int index, const char *name); int fl_set_font_name(int index, const char *fmt, ...); The first form accepts just a simple string for the font name while the second assembles the name from a format string as it's used with `printf()' etc. and the following arguments. The first argument, `index', is the number of the font (between 0 and `FL_MAXFONTS-1') and the font name should be a valid font name (with the exception of the size field). If you are defining a completely different font family starting at index `k', it's a good idea to define `k + FL_BOLD_STYLE' to be the corresponding bold font in the family , and `k + FL_ITALIC_STYLE' the corresponding italic font in the family (so object like browser can obtain correct style when switching font styles): #define Pretty 30 #define PrettyBold (Pretty + FL_BOLD_STYLE) #define PrettyItalic (Pretty + FL_ITALIC_STYLE) fl_set_font_name(Pretty, fontname); fl_set_font_name(PrettyBold, boldfontname); fl_set_font_name(PrettyItalic, italicfontname); ... fl_set_object_lstyle(obj, PrettyBold); The function returns a negative value if the requested font is invalid or otherwise can't be loaded. Note however, if this routine is called before `*note fl_initialize()::', it will return 0, but may fail later if the font name is not valid. To change the default font (helvetica-medium), a program should change font `FL_NORMAL_STYLE'. If a font name in XLFD is given, a question mark (`?') in the point size position informs the Forms Library that variable size will be requested later. It is preferable that the complete XLFD name (i.e., with 14 dashes and possibly wildcards) be given because a complete name has the advantage that the font may be re-scalable if scalable fonts are available. This means that although both "-*-helvetica-medium-r-*-*-*-?-*-*-*-*-*-*" "-*-helvetica-medium-r-*-*-*-?-*-*" are valid font names, the first form may be re-scalable while the the second is not. To obtain the actual built-in font names, use the following function int fl_enumerate_fonts(void (*cb)(const char *f), int shortform); where `cb' is a callback function that gets called once for every built-in font name. The font name is passed to the callback function as the string pointer parameter while `shortform' selects if a short form of the name should be used. XForms only specifies the absolutely needed parts of the font names, and assumes the font path is set so that the server always chooses the most optimal fonts for the system. If this is not true, you can use `*note fl_set_font_name()::' or `*note fl_set_font_name_f()::' to select the exact font you want. In general, this is not recommended if your application is to be run/displayed on different servers. See `fonts.c' for a demonstration of all the built-in font styles available. You can change the alignment of the label with respect to the bounding box of the object. For this you should use the routine void fl_set_object_lalign(FL_OBJECT *obj, int align); with the following values for the `align' argument: `FL_ALIGN_LEFT' To the left of the box. `FL_ALIGN_RIGHT' To the right of the box. `FL_ALIGN_TOP' To the top of the box. `FL_ALIGN_BOTTOM' To the bottom of the box. `FL_ALIGN_CENTER' In the middle of the box. `FL_ALIGN_RIGHT_BOTTOM'To the right and bottom of the box. `FL_ALIGN_LEFT_BOTTOM' To the left and bottom of the box. `FL_ALIGN_RIGHT_TOP' To the right and top of the box. `FL_ALIGN_LEFT_TOP' To the left and top of the box. Alignment requests with the abpve constants place the text outside the box (except for `*note FL_ALIGN_CENTER::'). To get a value that can be used to align the label within the object the function int fl_to_inside_lalign(int align); can be used, which returns the necessary value for the corresponding inside alignment. Except for the case of `*note FL_ALIGN_CENTER::' (which is always inside the object) the result is the original value, logically or'ed with the constant . There's also a function for the reverse conversion, i.e., from a calue for inside to outside alignment int fl_to_outside_lalign(int align); Using this functions is a bit simpler than combining the value with the `*note FL_ALIGN_INSIDE::' constant, especially when it comes to `*note FL_ALIGN_CENTER::' (which doesn't has the this bit set, even though labels with this alignment will always be shown within the object. Both functions return `-1' if an invalid value for the alignment is passed to them. There exist also three functions to test for the inside or outside alignment: int fl_is_inside_lalign(int align); int fl_is_outside_lalign(int align); int fl_is_center_lalign(int align); Note that these functions return `0' also in the case that the alignment value passed to them is invalid. Not all objects accept all kinds of label alignment. For example for sliders, inputs etc. it doesn't make sense to have the label within the object und in these cases a request for an inside label is ignored (or, more precisely, converted to the corresponding request for an outside label or, on a request with `*note FL_ALIGN_CENTER::', the reversion to the default label position). On the other hand, some objects like the text object (where the text to be shown is the label's text) accept only inside alignment and a request for an outside alignment will automatically replaced by the corresponding inside alignment. See also the demo program `lalign.c' for an example of the positioning of labels using the above constants. Finally, the routines void fl_set_object_label(FL_OBJECT *obj, const char *label); void fl_set_object_label_f(FL_OBJECT *obj, const char *fmt, ...); change the label of a given object. Whilw the first function expects a simple string for the label. the second one accepts a format string with the same format specifiers as `printf()' etc., followed by as many additional arguments as there are format specifiers. An internal copy of the label for the object is made. As mentioned earlier, newline (`\n') can be embedded in the label to generate multiple lines. By embedding `H' (`\010') in the label, the entire label or one of the characters in the label can be underlined. The function const char * fl_get_object_label(FL_OBJECT *obj); returns the label string.  File: xforms.info, Node: Tool Tips, Next: Redrawing, Prev: Label Attributes and Fonts, Up: Changing Attributes 3.11.4 Tool Tips ---------------- As will be seen later, an object can be decorated by icons instead of labels. For this kind of object, it is helpful to show a text string that explains the function the object controls under appropriate conditions. Forms Library elected to show the message after the mouse enters the object for about 600 milli-seconds. The text is removed when the mouse leaves the object or when the mouse is pressed. To set the text, use the following routines void fl_set_object_helper(FL_OBJECT *obj, const char *helpmsg); void fl_set_object_helper_f(FL_OBJECT *obj, const char *fmt, ...); where `helpmsg' is a text string (with possible embedded newlines in it) that will be shown when the mouse enters the object, after about a 600 milli-second delay. The second form of the function accepts instead a format string like `printf()' etc., followed by the appropriate number of arguments. In both cases an internal copy of the string is made. The boxtype, color and font for the message display can be customized further using the following routines void fl_set_tooltip_boxtype(int boxtype); void fl_set_tooltip_color(FL_COLOR textcolor, FL_COLOR background); void fl_set_tooltip_font(int style, int size); void fl_set_tooltip_lalign(int align); where `boxtype' is the backface of the form that displays the text. The default is `FL_BORDER_BOX'. `textcolor' and `background' specify the colors of the text string and the backface. The defaults for these are `FL_BLACK' and `FL_YELLOW' respectively. The `style' and `size' parameters are the font style and size of the text. `align' is the alignment of the text string with respective to the box. The default is `FL_ALIGN_LEFT | FL_ALIGN_INSIDE' .  File: xforms.info, Node: Redrawing, Next: Changing Many Attributes, Prev: Tool Tips, Up: Changing Attributes 3.11.5 Redrawing Objects ------------------------ A word of caution is required. It is possible to change the attributes of an object at any time. But when the form is already displayed on the screen some care has to be taken. Whenever attributes change the system redraws the object. This is fine when drawing the object erases the old one but this is not always the case. For example, when placing labels outside the box (not using `FL_ALIGN_CENTER') they are not correctly erased. It is always possible to force the system to redraw an object using void fl_redraw_object(FL_OBJECT *obj); When the object is a group it redraws the complete group. To redraw an entire form, use void fl_redraw_form(FL_FORM *form); Use of these routines is normally not necessary and should be kept to an absolute minimum.  File: xforms.info, Node: Changing Many Attributes, Next: Symbols, Prev: Redrawing, Up: Changing Attributes 3.11.6 Changing Many Attributes ------------------------------- Whenever you change an attribute of an object in a visible form the object is redrawn immediately to make the change visible. This can be undesirable when you change a number of attributes of the same object. You only want the changed object to be drawn after the last change. Drawing it after each change will give a flickering effect on the screen. This gets even worse when you, for example, just want to hide a few objects. After each object you hide the entire form is redrawn. In addition to the flickering, it is also time consuming. Thus it is more efficient to tell the library to temporarily not redraw the form while changes are being made. This can be done by "freezing" the form. While a form is being frozen it is not redrawn, all changes made are instead buffered internally. Only when you unfreeze the form, all changes made in the meantime are drawn at once. For freezing and unfreezing two calls exist: void fl_freeze_form(FL_FORM *form); and void fl_unfreeze_form(FL_FORM *form); It is a good practice to place multiple changes to the contents of a form always between calls to these two procedures. Further, it is better to complete modifying the attributes of one object before starting work on the next.  File: xforms.info, Node: Symbols, Prev: Changing Many Attributes, Up: Changing Attributes 3.11.7 Symbols -------------- Rather than using text as a label it is possible to place symbols like an arrows etc. on objects. This is done in the following way: When the label starts with the character `@' instead of the text a particular symbol is drawn(1). The rest of the label string indicates the symbol. A number of pre-defined symbols are available: `->' Normal arrow pointing to the right. `<-' Normal arrow pointing to the left. `>' Triangular arrow pointing to the right. `<' Triangular arrow pointing to the left. `>>' Double triangle pointing to the right. `<<' Double triangle pointing to the left. `<->' Arrow pointing left and right. `->|' A normal arrow with a bar at the end. `>|' A triangular arrow with a bar at the end. `-->' A thin arrow pointing to the right. `=' Three embossed lines. `arrow' Same as `-->'. `returnarrow' `' key symbol. `square' A square. `circle' A circle. `line' A horizontal line. `plus' A plus sign (can be rotated to get a cross). `UpLine' An embossed line. `DnLine' An engraved line. `UpArrow' An embossed arrow. `DnArrow' An engraved arrow. See Fig. 3.6 for how some of them look. It is possible to use the symbols in different orientations. When the symbol name is preceded by a digit `1'-`9' it is rotated like on the numerical keypad, i.e., `6' (and also `5') result in no rotation, `9' a rotation of 45 degrees counter-clockwise, `8' a rotation of 90 degrees, etc. Hence the order is `6', `9', `8', `7', `4', `1', `2', `3'. (Just think of the keypad as consisting of arrow keys with 6 pointing in the default orientation, i.e., to the right). So to get an arrow that is pointing to the left top use a label `@7->'. To put the symbol in other orientations, put a 0 after the `@', followed by the angle (counter-clockwise). E.g., to draw an arrow at an angle of 30 degrees you can use `@030->'. The symbol will be scaled to fit in the bounding box. When the bounding box is not square, scaling in the x- and y-directions will be different. If keeping the aspect ratio is desired, put a sharp (`#') immediately after the . E.g., `@#9->'. Two additional prefixes, `+' and `-', followed by a single digit, can be used to make small symbol size adjustment. A `+' indicates an increase of the symbol size while a `-' a decrease. The single digit following the prefix is the amount of increment (or decrement) in pixels. For example, to draw a square that is 3 pixels smaller in size than the default size use `@-3square'. If a single sequence of `+' or `-' and a single digit does not suffice, it can repeated, the effect is cumulative. Of course, this can also be combined with a rotation etc., so i.e., `@-9-3030->' (the order in which the different sequences are used doesn't matter) will result in an arrow drawn 12 pixels smaller than normal and rotated by 30 degrees counter-clockwise. As already stated the "default" size of a symbol is (this at least holds for the built-in ones) one where it fits autoatically into the box it is to be drawn into, with a bit of room left around it. Thus the size of the symbol should in most cases be fine without any further fine-tuning. If you increase the size for whatever reasons please consider that the symbol automatically gets clipped to the area it is will be drawn into, i.e., increments that result in the symbol becoming larger than the box it is to be drawn into should be avoided. [image src="xforms_images/symbols.png"] In addition to using symbols as object labels, symbols can also be drawn directly using int fl_draw_symbol(const char *symbolname, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, FL_Color col); (the function returns `1' on success and `0' on failure when the symbol name isn't valid) or indirectly via `*note fl_drw_text()::'. Drawing is clipped automatically to the area given by the arguments. The application program can also add symbols to the system which it can then use to display symbols on objects that are not provided by the Forms Library. To add a symbol, use the call int fl_add_symbol(const char *name, void (*drawit)(),int sc); `name' is the name under which the symbol should be known, which may not have a `@', a `#' or a digit at the start (or `+' or `-', directly followed by a digit). `drawit()' is the routine to be called for drawing the symbol. `sc' is reserved and currently has no meaning. Best set it to `0'. The routine `drawit()' should have the form void drawit(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, int angle, FL_COLOR col); `col' is the color in which to draw the symbol. This is the label color that can be provided and changed by the application program. The routine should draw the symbol centered inside the box by `x', `y', `w', `h' and rotated from its natural position by `angle' degrees. The draw function can call all types of drawing routines, including `*note fl_draw_symbol()::'. Before it is called clipping is set to the area given by the first four arguments. If the new symbol name is the same as that of a built-in or of one previously defined, the new definition overrides the built-in or previously defined one. The function returns `1' on success and `0' on failure (due to invalid arguments). The symbol handling routines really should be viewed as a means of associating an arbitrary piece of text (the label) with arbitrary graphics, application of which can be quite pleasant given the right tasks. A symbol (built-in or previously defined) can also be deleted using int fl_delete_symbol(const char *name); On success `1' is returned, otherwise `0'. ---------- Footnotes ---------- (1) If you want a literal `@' character as the first character of a label text, escape it with another `@' character.  File: xforms.info, Node: Adding and Removing Objects, Next: Freeing Objects, Prev: Changing Attributes, Up: Part I Defining Forms 3.12 Adding and Removing Objects ================================ In some situations you might want to add objects to an already existing form (i.e., a form for which ``fl_end_form()'' has already been called. Reopening a form for the addition of further objects can be done by using the call FL_FORM *fl_addto_form(FL_FORM *form); After this call you can again add objects to the form with the usual functions for adding objects (like `*note fl_add_button()::' etc.). When done with adding objects to the form again call `*note fl_end_form()::'. It is possible to add objects to forms that are being displayed, but this is not always a good idea because not everything behaves well (e.g., strange things might happen when a group is started but not yet finished). To remove an object from a form simply use void fl_delete_object(FL_OBJECT *obj); It removes the object from the form it currently belongs to and also from a group it may belong to. The argument can also be the pseudo-object starting a group (i.e., the return value of `*note fl_bgn_group()::') in which case the whole group of objects will be removed from the form. Contrary to what the name of the function may hint at the object itself isn't deleted but it remains available (except if it's an object that marks the start or end of a group) and thus it can be added again to the same or another form (without having to call `*note fl_addto_form()::' first and `*note fl_end_form()::' afterwards) using the function void fl_add_object(FL_FORM *form, FL_OBJECT *obj); Normally, this function should only be used within object classes to add a newly created object to the form currently under construction. It can not be used for pseude-objects representing the start or end of a group.  File: xforms.info, Node: Freeing Objects, Prev: Adding and Removing Objects, Up: Part I Defining Forms 3.13 Freeing Objects ==================== If the application program does not need an object anymore it can completely delete it, freeing all memory used for it, using a call of void fl_free_object(FL_OBJECT *obj); After this the object is truely destroyed and can no longer be used. If you hadn't removed the object from the form it did belong to using `*note fl_delete_object()::' before this will be done automatically. To free the memory used by an entire form use a call of void fl_free_form(FL_FORM *form); This will delete and free all the objects of the form and the form itself. A freed form can not be referenced anymore.  File: xforms.info, Node: Part I Doing Interaction, Next: Part I Free Objects, Prev: Part I Defining Forms, Up: Top 4 Doing Interaction ******************* * Menu: * Displaying a Form:: * Simple Interaction:: * Periodic Events and Non-blocking Interaction:: * Dealing With Multiple Windows:: * Using Callback Functions:: * Handling Other Input Sources::  File: xforms.info, Node: Displaying a Form, Next: Simple Interaction, Up: Part I Doing Interaction 4.1 Displaying a Form ===================== After having defined the forms the application program can use them to interact with the user. As a first step the program has to display the forms with which it wants the user to interact. This is done using the routine Window fl_show_form(FL_FORM *form, int place, int border, const char *name); It opens a (top-level) window on the screen in which the form is shown. The parameter `name' is the title of the form (and its associated icon if any). The routine returns the ID of the forms window. You normally never need this. Immediately after the form becomes visible, a full draw of all objects on the form is performed. Due to the two way buffering mechanism of Xlib, if `*note fl_show_form()::' is followed by something that blocks (e.g., waiting for a device other than X devices to come online), the output buffer might not be properly flushed, resulting in the form only being partially drawn. If your program works this way, use the following function after `*note fl_show_form()::' void fl_update_display(int blocking); where `blocking' is false (0), the function flushes the X buffer so the drawing requests are on their way to the server. When `blocking' is true (1), the function flushes the buffer and waits until all the events are received and processed by the server. For typical programs that use `*note fl_do_forms()::' or `*note fl_check_forms()::' after `*note fl_show_form()::', flushing is not necessary as the output buffer is flushed automatically. Excessive call to `*note fl_update_display()::' degrades performace. The location and size of the window to be shown on the call of `*note fl_show_form()::' are determined by the `place' argument. The following possibilities exist: `FL_PLACE_SIZE' The user can control the position but the size is fixed. Interactive resizing is not allowed once the form becomes visible. `FL_PLACE_POSITION' Initial position used will be the one set via `*note fl_set_form_position()::'. Interactive resizing is possible. `FL_PLACE_GEOMETRY' Place at the latest position and size (see also below) or the geometry set via `*note fl_set_form_geometry()::'. A form so shown will have a fixed size and interactive resizing is not allowed. `FL_PLACE_ASPECT' Allows interactive resizing but any new size will have the aspect ratio as that of the initial size. `FL_PLACE_MOUSE' The form is placed centered below the mouse. Interactive resizing will not be allowed unless this option is accompanied by `*note FL_FREE_SIZE::' as in `*note FL_PLACE_MOUSE::|*note FL_FREE_SIZE::'. `FL_PLACE_CENTER' The form is placed in the center of the screen. If `*note FL_FREE_SIZE::' is also specified, interactive resizing will be allowed. `FL_PLACE_FULLSCREEN' The form is scaled to cover the full screen. If `*note FL_FREE_SIZE::' is also specified, interactive resizing will be allowed. `FL_PLACE_FREE' Both the position and size are completely free. The initial size used is the designed size. Initial position, if setvia `*note fl_set_form_position()::', will be used otherwise interactive positioning may be possible if the window manager allows it. `FL_PLACE_HOTSPOT' The form is placed so that mouse is on the form's "hotspot". If `*note FL_FREE_SIZE::' is also specified, interactive resizing will be allowed. `FL_PLACE_CENTERFREE' Same as `*note FL_PLACE_CENTER::|*note FL_FREE_SIZE::', i.e., place the form at the center of the screen and allow resizing. `FL_PLACE_ICONIC' The form is shown initially iconified. The size and location used are the window manager's default. As mentioned above, some of the settings will result in a fixed size of the form (i.e., a size that can't be changed by the user per default). In some cases this can be avoided by OR'ing the value with `FL_FREE_SIZE' as a modifier. If no size was specified, the designed (or later scaled) size will be used. Note that the initial position is dependent upon the window manager used. Some window managers allow interactive placement of the windows but some don't. You can set the position or size to be used via the following calls void fl_set_form_position(FL_FORM *form, FL_Coord x, FL_Coord y); and void fl_set_form_size(FL_FORM *form, FL_Coord w, FL_Coord h); or, combining both these two functions, void fl_set_form_geometry(FL_FORM form*, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h); before placing the form on the screen. (Actually the routines can also be called while the form is being displayed. They will change the position and/or size of the form.) `x', `y', `w' and `h' indicate the position of the form on the screen and its size(1). The position is measured from the top-left corner of the screen. When the position is negative the distance from the right or the bottom is indicated. Next the form should be placed on the screen using `*note FL_PLACE_GEOMETRY::', `*note FL_PLACE_FREE::'. E.g., to place a form at the lower-right corner of the screen use fl_set_form_position(form, -1, -1); fl_show_form(form, FL_PLACE_GEOMETRY, FL_TRANSIENT, "formName"); (Following the X convention for specifying geometries a negative `x'-position specifies the distance of the right eside of the form from the right side of the screen and a negative `y'-position the distance of the bottom of the form from the bottom of the screen.) To show a form so that a particular object or point is under the mouse, use one of the following two routines to set the "hotspot" void fl_set_form_hotspot(FL_FORM *form, FL_Coord x, FL_Coord y); void fl_set_form_hotobject(FL_FORM *form, FL_OBJECT *obj); and then use `*note FL_PLACE_HOTSPOT::' for the `place' argument in the call of `*note fl_show_form()::'. The coordinates `x' and `y' are relative to the upper-left hand corner of the form (within the window decorations). In the call `*note fl_show_form()::' the argument `border' indicates whether or not to request window manager's decoration. `border' should take one of the following values: `FL_FULLBORDER' Full border decorations. `FL_TRANSIENT' Borders with (possibly) less decorations. `FL_NOBORDER' No decoration at all. For some dialogs, such as demanding an answer etc., you probably do not want the window manager's full decorations. Use `*note FL_TRANSIENT::' for this. A window border is useful to let the user iconify a form, move it around or resize it. If a form is transient or has no border, it is normally more difficult (or even impossible) to move the form. A transient form typically should have less decoration, but not necessarily so. It depends on the window managers as well as their options. `*note FL_NOBORDER::' is guaranteed to have no border(2) and is immune to iconification request. Because of this, borderless forms can be hostile to other applications(3), so use this only if absolutely necessary. There are other subtle differences between the different decoration requests. For instance, (small) transient forms always have `save_under' (see `XSetWindowAttributes()') set to true by default. Some window properties, `WM_COMMAND' in particular, are only set for full-bordered forms and will only migrate to other full-bordered forms when the original form having the property becomes unmapped. The library has a notion of a "main form" of an application, roughly the form that would be on the screen the longest. By default, the first full-bordered form shown becomes the main form of the application. All transient windows shown afterwards will stay on top of the main form. The application can set or change the main form anytime using the following routine void fl_set_app_mainform(FL_FORM *form); Setting the main form of an application will cause the `WM_COMMAND' property set for the form if no other form has this property. Sometimes it is necessary to have access to the window resource ID before the window is mapped (shown). For this, the following routine can be used Window fl_prepare_form_window(FL_FORM *form, int place, int border, const char *name); This routine creates a window that obeys any and all constraints just as `*note fl_show_form()::' does but remains unmapped. To map such a window, the following must be used Window fl_show_form_window(FL_FORM *form); Between these two calls, the application program has full access to the window and can set all attributes, such as icon pixmaps etc., that are not set by `*note fl_show_form()::'. You can also scale the form and all objects on it programmatically using the following routine void fl_scale_form(FL_FORM *form, double xsc, double ysc); where you indicate a scaling factor in the x- and y-direction with respect to the current size. See `rescale.c' for an example. When a form is scaled, either programmatically or interactively, all objects on the form per default will also be scaled. This includes both the sizes and positions of the objects. For most cases, this default behavior is adequate. In some cases, e.g., to keep a group of objects together, more control is needed. To this end, the following routines can be used void fl_set_object_resize(FL_OBJECT *obj, unsigned how_resize); void fl_set_object_gravity(FL_OBJECT *obj, unsigned nw_gravity, unsigned se_gravity); The `how_resize' argument of `*note fl_set_object_resize()::' can be one of `FL_RESIZE_NONE' don't resize the object at all `FL_RESIZE_X' resize it in x- (horizontal) direction only `FL_RESIZE_Y' resize it in y- (vertical) direction only `FL_RESIZE_ALL' is an alias for `*note FL_RESIZE_X::|*note FL_RESIZE_Y::' and makes the object resizable in both dimension. The arguments `nw_gravity' and `se_gravity' of `fl_set_object_gravity()' control the positioning of the upper-left and lower-right corner of the object and work analogously to the `win_gravity' in Xlib. The details are as follows: Let `P' be the corner the gravity applies to, `(dx1,dy1)' the distance to the upper-left corner of the form, `(dx2,dy2)' the distance to the lower-right corner of the form, then, Value Effect --------------------------------------------------------------------------- `FL_NoGravity' Default linear scaling, see below `FL_NorthWest' `dx1', `dy1' constant `FL_North' `dy1' constant `FL_NorthEast' `dy1', `dx2' constant `FL_West' `dx1' constant `FL_East' `dx2' constant `FL_SouthWest' `dx1', `dy2' constant `FL_South' `dy2' constant `FL_SouthEast' `dx2', `dy2' constant `ForgetGravity' don't consider the setting for this argument [image src="xforms_images/gravity.png"] Default for all object is `*note FL_RESIZE_ALL::' and `*note ForgetGravity::'. Note that the three parameters are not orthogonal and the positioning request will always override the scaling request in case of conflict. This means the resizing settings for an object are considered only if one (or both) of the gravities is `*note FL_NoGravity::'. For the special case where `how_resize' is `*note FL_RESIZE_NONE::' and both gravities are set to `ForgetGravity', the object is left un-scaled, but the object is moved so that the new position keeps the center of gravity of the object constant relative to the form. Again, since all sizing requests go though the window manager, there is no guarantee that your request will be honored. If a form is placed with `*note FL_PLACE_GEOMETRY::' or other size-restricting options, resizing it later via `*note fl_set_form_size()::' will likely be rejected. To determine the gravity and resize settings for an object use the functions void fl_get_object_gravity(FL_OBJECT *obj, unsigned int *nw, unsigned int *se); void fl_get_object_resize(FL_OBJECT *obj, unsigned int *resize ); Sometimes, you may want to change an attribute for all objects on a particular form, to this end, the following iterator is available void fl_for_all_objects(FL_FORM *form, int (*operate)(FL_OBJECT *obj, void *data), void *data); where function `operate' is called for every object of the form `form' unless `operate()' returns nonzero, which terminates the iterator. Multiple forms can be shown at the same moment and the system will interact with all of them simultaneously. The graphical mode in which the form is shown depends on the type of machine. In general, the visual chosen by XForms is the one that has the most colors. Application programs have many ways to change this default, either through command line options, resources or programmatically. See the Part V for details. If for any reason, you would like to change the form title (as well as its associated icon) after it is shown, the following functions can be used void fl_set_form_title(FL_FORM *form, const char *name) void fl_set_form_title_f(FL_FORM *form, const char *fmt, ...) To set or change the icon shown when a form is iconified, use the following routine void fl_set_form_icon(FL_FORM *form, Pixmap icon, Pixmap mask); where `icon' and `mask' can be any valid Pixmap ID. (See *note Other Pixmap Routines:: for some of the routines that can be used to create Pixmaps.) Note that an `icon' previously setvia this function (if it exists) is not freed or modified in anyway. See the demo program `iconify.c' for an example. If the application program wants to stop interacting with a form and remove it from the screen, it has to use the call void fl_hide_form(FL_FORM *form); To check if a form is visible or not, use the following call int fl_form_is_visible(FL_FORM *form); The function returns one of `FL_INVISIBLE' if the form is not visible (0), `FL_VISIBLE' if the form is visible (1) and `FL_BEING_HIDDEN' if the form is visible but is in the process of being hidden (-1). Note that if you don't need a form anymore you can deallocate its memory using the call `*note fl_free_form()::' described earlier. Window managers typically have a menu entry labeled "delete" or "close" meant to terminate an application program gently by informing the application program with a `WM_DELETE_WINDOW' protocol message. Although the Forms Library catches this message, it does not do anything except terminating the application. This can cause problems if the application has to do some record keeping before exiting. To perform record keeping or to elect to ignore this message, register a callback function using the following routine int fl_set_atclose(int (*at_close)(FL_FORM *, void *), void *data); The callback function `at_close' will be called before the Forms Library terminates the application. The first parameter of the callback function is the form that received the `WM_DELETE_WINDOW' message. To prevent the Forms Library from terminating the application, the callback function should return the constant `FL_IGNORE'. Any other value (e.g., `FL_OK') will result in the termination of the application. Similar mechanism exists for individual forms int fl_set_form_atclose(FL_FORM *, int (*at_close)(FL_FORM *, void *), void *data); except that `FL_OK' does not terminate the application, it results in the form being closed. Of course, if you'd like to terminate the application, you can always call `exit(3)' yourself within the callback function. ---------- Footnotes ---------- (1) The parameters should be sensitive to the coordinate unit in effect at the time of the call, but at present, they are not, i.e., the function takes only values in pixel units. (2) Provided the window manager is compliant. If the window manager isn't compliant all bets are off. (3) Actually, they are also hostile to their sibling forms. *Note Overview of Main Functions: Part V Overview of Main Functions.  File: xforms.info, Node: Simple Interaction, Next: Periodic Events and Non-blocking Interaction, Prev: Displaying a Form, Up: Part I Doing Interaction 4.2 Simple Interaction ====================== Once one or more forms are shown it is time to give control to the library to handle the interaction with the forms. There are a number of different ways of doing this. The first one, appropriate for most programs, is to call of FL_OBJECT *fl_do_forms(void); It controls the interaction until some object in one of the forms changes state. In this case a pointer to the changed object is returned. A change occurs in the following cases: box A box never changes state and, hence, is never returned by `*note fl_do_forms()::'. text Also a text never changes state. button A button is returned when the user presses a mouse button on it and then releases the button. The change is not reported before the user releases the mouse button, except with touch buttons which are returned all the time as long as the user keeps the mouse pressed on it. (See e.g., `touchbutton.c' for the use of touch buttons.) slider A slider per default is returned whenever its value is changed, so whenever the user clicks on it and moves the mouse the slider object gets returned. input An input field is returned per default when it is deactivated, i.e., the user has selected it and then starts interacting with another object that has the ability to get returned. (This list just contains a small number of objects that exist, see Part III for a list of all objects and the documentation of the exact behaviour of them.) When the (address of the) object is returned by `*note fl_do_forms()::' the application program can take action accordingly. See some of the demo programs for examples of use. Normally, after the action is taken by the application program `*note fl_do_forms()::' is called again to continue the interaction. Hence, simpler programs have the following global form: /* define the forms */ /* display the forms */ while (! ready) { obj = fl_do_forms(); if (obj == obj1) /* handle the change in obj1 */ else if (obj == obj2) /* handle the change in obj2 */ .... } For more complex programs interaction via callbacks is often preferable. For such programs, the global structure looks something like the following /* define callbacks */ void callback(FL_OBJECT *obj, long data) { /* perform tasks */ } void terminate_callback(FL_OBJECT *obj, long data) { /* cleanup application */ fl_finish(); exit(0); } main(int argc, char *argv[]) { /* create form and bind the callbacks to objects */ /* enter main loop */ fl_do_forms(); return 0; } In this case, `*note fl_do_forms()::' handles the interaction indefinitely and never returns. The program exits via one of the callback functions. There is also the possibility to conrol under which exact conditions the object gets returned. An application that e.g., doesn't want to be notified about each change of a slider but instead only want a single notification after the mouse button has been released and the value of the slider was changed in the process would call the function int fl_set_object_return(FL_OBJECT *obj, unsigned int when); with `when' set to `FL_RETURN_END_CHANGED'. There are several values `when' can take: `FL_RETURN_CHANGED' Return (or call object callback) whenever there is a change in the state of the object (button was pressed, input field was changed, slider was moved etc.). `FL_RETURN_END' Return (or invoke callback) at the end of the interaction (typically when the user releases the mouse button) regardless if the objects state was changed or not. `FL_RETURN_END_CHANGED' Return (or call object callback) when interaction stops *and* the state of the object changed. `FL_RETURN_SELECTION' Return when e.g., a line in a `*note FL_MULTI_BROWSER::' browser was selected. `FL_RETURN_DESELECTION' Return when e.g., a line in a `*note FL_MULTI_BROWSER::' browser was deselected. `FL_RETURN_ALWAYS' Return (or invoke callback) on any of the events that can happen to the object. `FL_RETURN_NONE' Never notiy the application about interactions with this object (i.e., never return it nor invoke its callback). Note: this is not meant for deactivation of an object, it will still seem to work as normal, it just doesn't get returned to the application nor does is callbak get invoked. Since for different objects only subsets of these conditions make sense please read the more detailed descriptions for each of the object types in Part III. All of the values above, except `*note FL_RETURN_END_CHANGED::', `*note FL_RETURN_ALWAYS::' and `*note FL_RETURN_NONE::' can be logically `OR''ed. `*note FL_RETURN_END_CHANGED::' is different in that it only can be returned when the conditions for `*note FL_RETURN_END::' and `*note FL_RETURN_CHANGED::' are satisfied at once. If this is request `*note FL_RETURN_END::' and `*note FL_RETURN_CHANGED::' will automatically deselected. So if you want notifications about the conditions that lead to `*note FL_RETURN_END::' or `*note FL_RETURN_CHANGED::' (or both at once) ask instead for the logical `OR' of these two. `*note FL_RETURN_ALWAYS::' includes all conditions except `*note FL_RETURN_END_CHANGED::'. Once an object has been returned (or its callback is invoked) you can determine the reason why it was returned by calling int fl_get_object_return_state(FL_OBBJECT *obj); This returns the logical `OR' of the conditions that led to the object being returned, where the conditions can be `*note FL_RETURN_CHANGED::', `*note FL_RETURN_END::', `*note FL_RETURN_SELECTION::' and `*note FL_RETURN_DESELECTION::'. (The `*note FL_RETURN_END_CHANGED::' condition is satisfied if both `*note FL_RETURN_END::' and `*note FL_RETURN_CHANGED::' are set.) Please note that calling this function only makes sense in a callback for an object or when the object has been just returned by e.g., `*note fl_do_forms()::'. Further interactions with the object overwrite the value!  File: xforms.info, Node: Periodic Events and Non-blocking Interaction, Next: Dealing With Multiple Windows, Prev: Simple Interaction, Up: Part I Doing Interaction 4.3 Periodic Events and Non-blocking Interaction ================================================ The interaction mentioned above is adequate for many application programs but not for all. When the program also has to perform tasks when no user action takes place (e.g., redrawing a rotating image all the time), some other means of interaction are needed. There exist two different, but somewhat similar, mechanisms in the library that are designed specifically for generating and handling periodic events or achieving non-blocking interaction. Depending on the application, one method may be more appropriate than the other. For periodic tasks, e.g., rotating an image, checking the status of some external device or application state etc., interaction via an idle callback comes in very handy. An idle callback is an application function that is registered with the system and is called whenever there are no events pending for forms (or application windows). To register an idle callback, use the following routine FL_APPEVENT_CB fl_set_idle_callback(FL_APPEVENT_CB callback, void *user_data); After the registration, whenever the main loop (`*note fl_do_forms()::') is idle, i.e., no user action or light user action, the callback function of type `FL_APPEVENT_CB' is called typedef int (*FL_APPEVENT_CB)(XEvent *xev, void *user_data); i.e., a function with the signature int idle_callback(XEvent *xev, void *user_data); where `user_data' is the void pointer passed to the system in `*note fl_set_idle_callback()::' through which some information about the application can be passed. The return value of the callback function is currently not used. `xev' is a pointer to a synthetic(1) `MotionNotify' event from which some information about mouse position etc. can be obtained. To remove the idle callback, use `*note fl_set_idle_callback()::' with callback set to `NULL'. Timeouts are similar to idle callbacks but with somewhat more accurate timing. Idle callbacks are called whenever the system is idle, the time interval between any two invocations of the idle callback can vary a great deal depending upon many factors. Timeout callbacks, on the other hand, will never be called before the specified time is elapsed. You can think of timeouts as regularized idle callbacks, and further you can have more than one timeout callbacks. To add a timeout callback, use the following routine typedef void (*FL_TIMEOUT_CALLBACK)(int, void *); int fl_add_timeout(long msec, FL_TIMEOUT_CALLBACK callback, void *data); The function returns the timeout's ID(2). When the time interval specified by `msec' (in milli-seconds) has elapsed the timeout is removed, then the callback function is called. The timeout ID is passed to the callback function as the first parameter. The second parameter the callback function is passed is the data pointer that was passed to `*note fl_add_timeout()::'. To remove a timeout before it triggers, use the following routine void fl_remove_timeout(int id); where `id' is the timeout ID returned by `*note fl_add_timeout()::'. There is also an `FL_OBJECT', the `FL_TIMER' object, especially the invisible type, that can be used to do timeout. Since it is a proper Forms Library object, it may be easier to use simply because it has the same API as any other GUI elements and is supported by the Form Designer. *Note Timer Object::, for complete information on the `FL_TIMER' object. Note that idle callback and timeout are not appropriate for tasks that block or take a long time to finish because during the busy or blocked period, no interaction with the GUI can take place (both idle callback and timeout are invoked by the main loop, blockage or busy executing application code prevents the main loop from performing its tasks). So what to do in situations where the application program does require a lengthy computation while still wanting to have the ability to interact with the user interface (for example, a Stop button to terminate the lengthy computation)? In these situations, the following routine can be used: FL_OBJECT *fl_check_forms(void); This function is similar to `*note fl_do_forms()::' in that it takes care of handling events and appropriate callbacks, but it does not block. Instead it always returns to the application program immediately. If a change has occurred in some object the object is returned as with `*note fl_do_forms()::'. But when no change has occurred control is also returned but this time a `NULL' object is returned. Thus, by inserting this statement in the middle of the computation in appropriate places in effect "polls" the user interface. The downside of using this function is that if used excessively, as with all excessive polls, it can chew up considerable CPU cycles. Therefore, it should only be used outside the inner most loops of the computation. If all objects have callbacks bound to them, `*note fl_check_forms()::' always returns `NULL', otherwise, code similar to the following is needed: obj = fl_check_forms(); if (obj == obj1) /* handle it */ ... Depending on the applications, it may be possible to partition the computation into smaller tasks that can be performed within an idle callback one after another, thus eliminating the need of using `*note fl_check_forms()::'. Handling intensive computation while maintaining user interface responsiveness can be tricky and by no means the above methods are the only options. You can, for example, fork a child process to do some of the tasks and communicate with the interface via pipes and/or signals, both of which can be handled with library routines documented later, or use multi-thread (but be careful to limit Xserver access within one thread). Be creative and have fun. For running external executables while maintaining responsiveness of the interface, see `*note fl_exe_command()::' and `*note fl_popen()::' documented later in *note Command Log::. ---------- Footnotes ---------- (1) I.e., `xev->xmotion.send_event' is true. (2) The function will not return 0 or -1 as timeout IDs, so the application program can use these values to tag invalid or expired timeouts.  File: xforms.info, Node: Dealing With Multiple Windows, Next: Using Callback Functions, Prev: Periodic Events and Non-blocking Interaction, Up: Part I Doing Interaction 4.4 Dealing With Multiple Windows ================================= It is not atypical that an application program may need to take interaction from more than one form at the same time, Forms Library provides a mechanism with which precise control can be exercised. By default, `*note fl_do_forms()::' takes interaction from all forms that are shown. In certain situations, you might not want to have interaction with all of them. For example, when the user presses a quit button in a form you might want to ask a confirmation using another form. You don't want to hide the main form because of that but you also don't want the user to be able to press buttons, etc. in this form. The user first has to give the confirmation. So you want to temporarily deactivate the main form. This can be done using the call void fl_deactivate_form(FL_FORM *form); To reactivate the form later again use void fl_activate_form(FL_FORM *form); It is a good idea to give the user a visual clue that a form is deactivated. This is not automatically done mainly for performance reasons. Experience shows that graying out some important objects on the form is in general adequate. Graying out an object can be accomplished by using `*note fl_set_object_lcolor()::' (see `objinactive.c'. What objects to gray out is obviously application dependent. The following two functions can be used to register two callbacks that are called whenever the activation status of a form is changed: typedef void (*FL_FORM_ATACTIVATE)(FL_FORM *, void *); FL_FORM_ATACTIVATE fl_set_form_atactivate(FL_FORM *form, FL_FORM_ATACTIVATE callback, void *data); typedef void (*FL_FORM_ATDEACTIVATE)(FL_FORM *, void *); FL_FORM_ATDEACTIVATE fl_set_form_atdeactivate(FL_FORM *form, FL_FORM_ATDEACTIVATE callback, void *data); It is also possible to deactivate all current forms and reactivate them again. To this end use the functions: void fl_deactivate_all_forms(void); void fl_activate_all_forms(void); Note that deactivation works in an additive way, i.e., when deactivating a form say 3 times it also has to be activated 3 times to become active again. One problem remains. Mouse actions etc. are presented to a program in the form of events in an event queue. The library routines `*note fl_do_forms()::' and `*note fl_check_forms()::' read this queue and handle the events. When the application program itself also opens windows, these windows will rather likely receive events as well. Unfortunately, there is only one event queue. When both the application program and the library routines would read events from this one queue problems would occur and events missed. Hence, the application program should not read the event queue itself.. To solve this problem, the library maintains (or appears to maintain) a separate event queue for the user. This queue behaves in exactly the same way as the normal event queue. To access it, the application program must use replacements for the usual Xlib routines. Instead of using `XNextEvent()', the program will use `*note fl_XNextEvent()::', with the same parameters except the `Display *' argument. The following is a list of all replacement routines: int fl_XNextEvent(XEvent *xev); int fl_XPeekEvent(XEvent *xev); int fl_XEventsQueued(int mode); int fl_XPutbackEvent(XEvent *xev); Note that these routines normally return `1', but after a call of `*note fl_finish()::' they return `1' instead. Other events routines may be directly used if proper care is taken to make sure that only events for the application windows not handled by the library are removed. These routines include `XWindowEvent()', `XCheckWindowEvent()' etc. To help find out when an event has occurred, whenever `*note fl_do_forms()::' and `*note fl_check_forms()::' encounter an event that is not meant for handling by the library but by the application program itself they return a special object `*note FL_EVENT::'. Upon receiving this special event, the application program can and must remove the pending event from the queue using `*note fl_XNextEvent()::'. So the basis of a program with its own windows would look as follows: /* define the forms */ /* display the forms */ /* open your own window(s) */ while (! ready) { obj = fl_do_forms(); /* or fl_check_forms() */ if (obj == FL_EVENT) { fl_XNextEvent(&xevent); switch (xevent.type) { /* handle the event */ } } else if (obj != NULL) /* handle the change in obj */ /* update other things */ } } In some situations you may not want to receive these "user" events. For example, you might want to write a function that pops up a form to change some settings. This routine might not want to be concerned with any redrawing of the main window, etc., but you also not want to discard any events. In this case you can use the routines `*note fl_do_only_forms()::' and `*note fl_check_only_forms()::' that will never return `*note FL_EVENT::'. The events don't disappear but will be returned at later calls to the normal routines `*note fl_do_forms()::' etc. It can't be over-emphasized that it is an error to ignore `*note FL_EVENT::' or use `*note fl_XNextEvent()::' without seeing `*note FL_EVENT::'. Sometimes an application program might need to find out more information about the event that triggered a callback, e.g., to implement mouse button number sensitive functionalities. To this end, the following routines may be called long fl_mouse_button(void); This function, if needed, should be called from within a callback. The function returns one of the constants `*note FL_LEFT_MOUSE::', `*note FL_MIDDLE_MOUSE::', `*note FL_RIGHT_MOUSE::', `*note FL_SCROLLUP_MOUSE::' or `*note FL_SCROLLDOWN_MOUSE::', indicating which mouse button was pushed or released. If the callback is triggered by a shortcut, the function returns the keysym (ascii value if ASCII) of the key plus `*note FL_SHORTCUT::'. For example, if a button has a shortcut `C' (ASCII value is 3), the button number returned upon activation of the shortcut would be `FL_SHORTCUT + 3'. `*note FL_SHORTCUT::' can be used to determine if the callback is triggered by a shortcut or not if (fl_mouse_button() >= FL_SHORTCUT) /* handle shortcut */ else switch (fl_mouse_button()) { case FL_LEFTMOUSE: .... } More information can be obtained by using the following routine that returns the last `XEvent' const XEvent *fl_last_event(void); Note that if this routine is used outside of a callback function, the value returned may not be the real "last event" if the program was idling and, in this case, it returns a synthetic `MotionNotify' event. Some of the utilities used internally by the Forms Library can be used by the application programs, such as window geometry queries etc. Following is a partial list of the available routines: void fl_get_winorigin(Window win, FL_Coord *x, FL_Coord *y); void fl_get_winsize(Window win, FL_Coord *w, FL_Coord *h); void fl_get_wingeometry(Window win, FL_Coord *x, FL_Coord *y, FL_Coord *w, FL_Coord *h); All positions are relative to the root window. There are also routines that can be used to obtain the current mouse position relative to the root window: Window fl_get_mouse(FL_Coord *x, FL_Coord *y, unsigned int *keymask); where `keymask' is the same as used in `XQueryPointer(3X11)'. The function returns the window ID the mouse is in. To obtain the mouse position relative to an arbitrary window, the following routine may be used Window fl_get_win_mouse(Window win, FL_Coord *x, FL_Coord *y, unsigned int *keymask); To print the name of an XEvent, the following routine can be used: XEvent *fl_print_xevent_name(const char *where, const XEvent *xev); The function takes an XEvent, prints out its name and some other info, e.g., `expose, count=n'. Parameter `where' can be used to indicate where this function is called: fl_print_xevent_name("In tricky.c", &xevent);  File: xforms.info, Node: Using Callback Functions, Next: Handling Other Input Sources, Prev: Dealing With Multiple Windows, Up: Part I Doing Interaction 4.5 Using Callback Functions ============================ As stated earlier, the recommended method of interaction is to use callback functions. A callback function is a function supplied to the library by the application program that binds a specific condition (e.g., a button is pushed) to the invocation of the function by the system. The application program can bind a callback routine to any object. Once a callback function is bound and the specified condition is met, `*note fl_do_forms()::' or `*note fl_check_forms()::' invokes the callback function instead of returning the object. To bind a callback routine to an object, use the following typedef void (*FL_CALLBACKPTR)(FL_OBJECT *obj, long argument); FL_CALLBACKPTR fl_set_object_callback(FL_OBJECT *obj, FL_CALLBACKPTR callback, long argument); where `callback' is the callback function. `argument' is an argument that is passed to the callback routine so that it can take different actions for different objects. The function returns the old callback routine already bound to the object. You can change the callback routine anytime using this function. See, for example, demo program `timer.c'. The callback routine should have the form void callback(FL_OBJECT *obj, long argument); The first argument to every callback function is the object to which the callback is bound. The second parameter is the argument specified by the application program in the call to `*note fl_set_object_callback()::'. See program `yesno_cb.c' for an example of the use of callback routines. Note that callback routines can be combined with normal objects. It is possible to change the callback routine at any moment. Sometimes it is necessary to access other objects on the form from within the callback function. This presents a difficult situation that calls for global variables for all the objects on the form. This runs against good programming methodology and can make a program hard to maintain. Forms Library solves (to some degree) this problem by creating three fields, `void *u_vdata', `char *u_cdata' and `long u_ldata', in the `FL_OBJECT' structure that you can use to hold the necessary data to be used in the callback function. A better and more general solution to the problem is detailed in Part II of this documentation where all objects on a form is are grouped into a single structure which can then be "hang" off of `u_vdata' or some field in the `FL_FORM' structure. Another communication problem might arise when the callback function is called and, from within the callback function, some other objects' state is explicitly changed, say, via `*note fl_set_button()::', `*note fl_set_input()::' etc. You probably don't want to put the state change handling code of these objects in another object's callback. To handle this situation, you can simply call void fl_call_object_callback(FL_OBJECT *obj); When dealing with multiple forms, the application program can also bind a callback routine to an entire form. To this end it should use the routine void fl_set_form_callback(FL_FORM *form, void (*callback)(FL_OBJECT *, void *), void *data); Whenever `*note fl_do_forms()::' or `*note fl_check_forms()::' would return an object in form they call the routine callback instead, with the object as an argument. So the callback should have the form void callback(FL_OBJECT *obj, void *data); With each form you can associate its own callback routine. For objects that have their own callbacks the object callbacks have priority over the form callback. When the application program also has its own windows (via Xlib or Xt), it most likely also wants to know about XEvents for the window. As explained earlier, this can be accomplished by checking for `*note FL_EVENT::' objects. Another (and better) way is to add an event callback routine. This routine will be called whenever an XEvent is pending for the application's own window. To setup an event callback routine (of type `*note FL_APPEVENT_CB::' use the call typedef int (*FL_APPEVENT_CB)(XEvent *, void *); FL_APPEVENT_CB fl_set_event_callback(int (*callback)(XEvent *ev, void *data), void *data); Whenever an event happens the callback function is invoked with the event as the first argument and a pointer to data you want it to receive. So the callback should have the form int callback(XEvent *xev, void *data); This assumes the application program solicits the events and further, the callback routine should be prepared to handle all XEvent for all non-form windows. The callback function normally should return `0' unless the event isn't for one of the applcation-managed windows. This could be undesirable if more than one application window is active. To further partition and simplify the interaction, callbacks for a specific event on a specific window can be registered: FL_APPEVENT_CB fl_add_event_callback(Window window, int xev_type, FL_APPEVENT_CB callback, void *user_data); where `window' is the window for which the callback routine is to be registered. `xev_type' is the XEvent type you're interested in, e.g., `Expose' etc. If `xev_type' is 0, it is taken to mean that the callback routine will handle all events for the window. The newly installed callback replaces the callback already installed. Note that this function only works for windows created directly by the application program (i.e., it won't work for forms' windows or windows created by the canvas object). It is possible to access the raw events that happen on a form's window via `*note fl_register_raw_callback()::' discussed in *note Form Events::. `*note fl_add_event_callback()::' does not alter the window's event mask nor does it solicit events for you. That's mainly for the reason that an event type does not always correspond to a unique event mask, also in this way, the user can solicit events at window's creation and use 0 to register all the event handlers. To let XForms handle solicitation for you, call the following routine void fl_activate_event_callbacks(Window win); This function activates the default mapping of events to event masks built-in in the Forms Library, and causes the system to solicit the events for you. Note however, the mapping of events to masks are not unique and depending on applications, the default mapping may or may not be the one you want. For example, `MotionNotify' event can be mapped into `ButtonMotionMask' or `PointerMotionMask'. Forms Library will use both. It is possible to control the masks you want precisely by using the following function, which can also be used to add or remove solicited event masks on the fly without altering other masks already selected: long fl_addto_selected_xevent(Window win, long mask); long fl_remove_selected_xevent(Window win, long mask); Both functions return the resulting event masks that are currently selected. If event callback functions are registered via both `fl_set_event_callback()' and `*note fl_add_event_callback()::', the callback via the latter is invoked first and the callback registered via `*note fl_set_event_callback()::' is called only if the first attempt is unsuccessful, that is, the handler for the event is not present. For example, after the following sequence fl_add_event_callback(winID, Expose, expose_cb, 0); fl_set_event_callback(event_callback); and all `Expose' events on window `winID' are consumed by `expose_cb' then `event_callback()' would never be invoked as a result of an `Expose' event. To remove a callback, use the following routine void fl_remove_event_callback(Window win, int xev_type); All parameters have the usual meaning. Again, this routine does not modify the window's event mask. If you like to change the events the window is sensitive to after removing the callback, use `*note fl_activate_event_callbacks()::'. If `xev_type' is 0, all callbacks for window `win' are removed. This routine is called automatically if `*note fl_winclose()::' is called to unmap and destroy a window. Otherwise, you must call this routine explicitly to remove all event callbacks before destroying a window using `XDestroyWindow()'. A program using all of these has the following basic form: void event_cb(XEvent *xev, void *mydata1) { /* Handles an X-event. */ } void expose_cb(XEvent *xev, void *mydata2) { /* handle expose */ } void form1_cb(FL_OBJECT *obj) { /* Handles object obj in form1. */ } void form2_cb(FL_OBJECT *obj) { /* Handles object obj in form2. */ } main(int argc, char *argv[]) { /* initialize */ /* create form1 and form2 and display them */ fl_set_form_callback(form1, form1cb); fl_set_form_callback(form2, form2cb); /* create your own window, winID and show it */ fl_addto_selected_xevent(winID, ExposureMask | ButtonPressMask |... ); fl_winshow(winID); fl_set_event_callback(event_cb, whatever); fl_add_event_callback(winID, Expose, expose_cb, data); fl_do_forms(); return 0; } The routine `*note fl_do_forms()::' will never return in this case. See `demo27.c' for a program that works this way. It is recommended that you set up your programs using callback routines (either for the objects or for entire forms). This ensures that no events are missed, events are treated in the correct order, etc. Note that different event callback routines can be written for different stages of the program and they can be switched when required. This provides a progressive path for building up programs. Another possibility is to use a free object so that the application window is handled automatically by the internal event processing mechanism just like any other forms.  File: xforms.info, Node: Handling Other Input Sources, Prev: Using Callback Functions, Up: Part I Doing Interaction 4.6 Handling Other Input Sources ================================ It is not uncommon that X applications may require input from sources other than the X event queue. Outlined in this section are two routines in the Forms Library that provide a simple interface to handle additional input sources. Applications can define input callbacks to be invoked when input is available from a specified file descriptor. The function typedef void (*FL_IO_CALLBACK)(int fd, void *data); void fl_add_io_callback(int fd, unsigned condition, FL_IO_CALLBACK callback, void *data); registers an input callback with the system. The argument `fd' must be a valid file descriptor on a UNIX-based system or other operating system dependent device specification while `condition' indicates under what circumstance the input callback should be invoked. The condition must be one of the following constants `FL_READ' File descriptor has data available. `FL_WRITE' File descriptor is available for writing. `FL_EXCEPT' an I/O error has occurred. When the given condition occurs, the Forms Library invokes the callback function specified by `callback'. The `data' argument allows the application to provide some data to be passed to the callback function when it is called (be sure that the storage pointed to by data has global (or static) scope). To remove a callback that is no longer needed or to stop the Forms Library's main loop from watching the file descriptor, use the following function void fl_remove_io_callback(int fd, unsigned condition, FL_IO_CALLBACK callback); The procedures outlined above work well with pipes and sockets, but can be a CPU hog on real files. To workaround this problem, you may wish to check the file periodically and only from within an idle callback.  File: xforms.info, Node: Part I Free Objects, Next: Part I Goodies, Prev: Part I Doing Interaction, Up: Top 5 Free Objects ************** In some applications the standard object classes as provided by the Forms Library may not be enough for your task. There are three ways of solving this problem. First of all, the application program can also open its own window or use a canvas (the preferred way) in which it does interaction with the user). A second way is to add your own object classes (see Part IV). This is especially useful when your new type of objects is of general use. The third way is to add free objects to your form. Free objects are objects for which the application program handles the drawing and interaction. This chapter will give all the details needed to design and use free objects. * Menu: * Free Object:: Free Object * Example:: An Example  File: xforms.info, Node: Free Object, Next: Example, Up: Part I Free Objects 5.1 Free Object =============== To add a free object to a form use the call FL_OBJECT *fl_add_free(int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label, int (*handle)()); `type' indicates the type of free object, see below for a list and their meaning. `x', `y', `w' and `h' are the bounding box. The `label' is normally not drawn unless the `handle' routine takes care of this. `handle' is the routine that does the redrawing and handles the interaction with the free object. The application program must supply this routine. This routine `handle' is called by the library whenever an action has to be performed. The routine should have the form: int handle(FL_OBJECT *obj, int event, FL_Coord mx, FL_Coord my, int key, void *xev); where `obj' is the object to which the event applies. `event' indicates what has to happen to the object. See below for a list of possible events. `mx' and `my' indicate the position of the mouse (only meaningful with mouse related events) relative to the form origin and `key' is the KeySym of the key typed in by the user (only for `FL_KEYPRESS' events). `xev' is the (cast) XEvent that causes the invocation of this handler. `event' and `xev->type' can both be used to obtain the event types. The routine should return whether the status of the object has changed, i.e., whether `*note fl_do_forms()::' or `*note fl_check_forms()::' should return this object. The following types of events exist for which the routine must take action: `FL_DRAW' The object has to be redrawn. To figure out the size of the object you can use the fields `obj->x', `obj->y', `obj->w' and `obj->h'. Some other aspects might also influence the way the object has to be drawn. E.g., you might want to draw the object differently when the mouse is on top of it or when the mouse is pressed on it. This can be figured out as follows. The field `obj->belowmouse' indicates whether the object is below the mouse. The field `obj->pushed' indicates whether the object is currently being pushed with the mouse. Finally, `obj->focus' indicates whether input focus is directed towards this object. When required, the label should also be drawn. This label can be found in the field `obj->label'. The drawing should be done such that it works correctly in the visual/depth the current form is in. Complete information is available on the state of the current form as well as several routines that will help you to tackle the trickiest (also the most tedious) part of X programming. In particular, the return value of `*note fl_get_vclass()::' can be used as an index into a table of structures, `*note fl_state::[]', from which all information about current active visual can be obtained. *Note Drawing Objects: Part IV Drawing Objects, for details on drawing objects and the routines. `FL_DRAWLABEL' This event is not always generated. It typically follows `FL_DRAW' and indicates the object label needs to be (re)drawn. You can ignore this event if (a) the object handler always draws the label upon receiving `FL_DRAW' or (b) the object label is not drawn at all(1). `FL_ENTER' This event is sent when the mouse has entered the bounding box. This might require some action. Note that also the field `belowmouse' in the object is being set. If entering only changes the appearance redrawing the object normally suffices. Don't do this directly! Always redraw the object using the routine `fl_redraw_object()'. It will send an `FL_DRAW' event to the object but also does some other things (like setting window id's, taking care of double buffering and some other bookkeeping tasks). `FL_LEAVE' The mouse has left the bounding box. Again, normally a redraw is enough (or nothing at all). `FL_MOTION' A motion event is sent between `FL_ENTER' and `FL_LEAVE' events when the mouse position changes on the object. The mouse position is given with the routine. `FL_PUSH' The user has pushed a mouse button in the object. Normally this requires some action. `FL_RELEASE' The user has released the mouse button. This event is only sent if a `FL_PUSH' event was sent earlier. `FL_DBLCLICK' The user has pushed a mouse button twice within a certain time limit (`FL_CLICK_TIMEOUT'), which by default is about 400 msec. `FL_TRPLCLICK' The user has pushed a mouse button three times within a certain time window between each push. This event is sent after a `FL_DBLCLICK', `FL_PUSH', `FL_RELEASE' sequence. `FL_UPDATE' The mouse position has changed. This event is sent to an object between an `FL_PUSH' and an `FL_RELEASE' event (actually this event is sent periodically, even if mouse has not moved). The mouse position is given as the parameter `mx' and `my' and action can be taken based on the position. `FL_FOCUS' Input got focussed to this object. This event and the next two are only sent to a free object of type `FL_INPUT_FREE' (see below). `FL_UNFOCUS' Input is no longer focussed on this object. `FL_KEYPRESS' A key was pressed. The KeySym is given with the routine. This event only happens between `FL_FOCUS' and `FL_UNFOCUS' events. `FL_STEP' A step event is sent all the time (at most 50 times per second but often less because of time consuming redraw operations) to a free object of type `FL_CONTINUOUS_FREE' such that it can update its state or appearance. `FL_SHORTCUT' Hotkeys for the object have been triggered. Typically this should result in the returning of the free object. `FL_FREEMEM' Upon receiving this event, the handler should free all object class specific memory allocated. `FL_OTHER' Some other events typically caused by window manager events or inter-client events. All information regarding the details of the events is in `xev'. Many of these events might make it necessary to (partially) redraw the object. Always do this using the routine `*note fl_redraw_object()::'. As indicated above not all events are sent to all free objects. It depends on their types. The following types exist (all objects are sent `FL_OTHER' when it occurs): `FL_NORMAL_FREE' The object will receive the events `FL_DRAW', `FL_ENTER', `FL_LEAVE', `FL_MOTION', `FL_PUSH', `FL_RELEASE' and `FL_MOUSE'. `FL_INACTIVE_FREE' The object only receives `FL_DRAW' events. This should be used for objects without interaction (e.g., a picture). `FL_INPUT_FREE' Same as `FL_NORMAL_FREE' but the object also receives `FL_FOCUS', `FL_UNFOCUS' and `FL_KEYPRESS' events. The `obj->wantkey' is by default set to `FL_KEY_NORMAL', i.e., the free object will receive all normal keys (0-255) except `' and `' key. If you're interested in `' or `' key, you need to change `obj->wantkey' to `FL_KEY_TAB' or `FL_KEY_ALL'. *Note Events: Part IV Events, for details. `FL_CONTINUOUS_FREE' Same as `FL_NORMAL_FREE' but the object also receives `FL_STEP' events. This should be used for objects that change themselves continuously. `FL_ALL_FREE' The object receives all types of events. See `free1.c' for a (terrible) example of the use of free objects. See also `freedraw.c', which is a nicer example of the use of free objects. Free objects provide all the generality you want from the Forms Library. Because free objects behave a lot like new object classes it is recommended that you also read part IV of this documentation before designing free objects. ---------- Footnotes ---------- (1) Label for free objects can't be drawn outside of the bounding box because of the clippings by the dispatcher.  File: xforms.info, Node: Example, Prev: Free Object, Up: Part I Free Objects 5.2 An Example ============== We conclude our discussion of the free object by examining a simple drawing program capable of drawing simple geometric figures like squares, circles, and triangles of various colors and sizes, and of course it also utilizes a free object. The basic UI consists of three logical parts. A drawing area onto which the squares etc. are to be drawn; a group of objects that control what figure to draw and with what size; and a group of objects that control the color with which the figure is to be drawn. The entire UI is designed interactively using the GUI builder `fdesign' with most objects having their own callbacks. `fdesign' writes two files, one is a header file containing forward declarations of callback functions and other function prototypes: #ifndef FD_drawfree_h_ #define FD_drawfree_h_ extern void change_color(FL_OBJECT *, long); extern void switch_figure(FL_OBJECT *, long); /* more callback declarations omitted */ typedef struct { FL_FORM * drawfree; FL_OBJECT * freeobj; FL_OBJECT * figgrp; FL_OBJECT * colgrp; FL_OBJECT * colorobj; FL_OBJECT * miscgrp; FL_OBJECT * sizegrp; FL_OBJECT * wsli; FL_OBJECT * hsli; FL_OBJECT * drobj[3]; void * vdata; long ldata; } FD_drawfree; extern FD_drawfree *create_form_drawfree(void); #endif /* FD_drawfree_h_ */ The other file contains the actual C-code that creates the form when compiled and executed. Since free objects are not directly supported by fdesign, a box was used as a stub for the location and size of the drawing area. After the C-code was generated, the box was changed manually to a free object by replacing `fl_add_box(FL_DOWN_BOX,...)' with `fl_add_free(FL_NORMAL_FREE,...)'. We list below the output generated by fdesign with some comments: FD_drawfree *create_form_drawfree(void) { FL_OBJECT *obj; FD_drawfree *fdui = fl_calloc(1, sizeof *fdui); fdui->drawfree = fl_bgn_form(FL_NO_BOX, 530, 490); obj = fl_add_box(FL_UP_BOX, 0, 0, 530, 490, ""); This is almost always the same for any form definition: we allocate a structure that will hold all objects on the form as well as the form itself. In this case, the first object on the form is a box of type `FL_UP_BOX'. fdui->figgrp = fl_bgn_group(); obj = fl_add_button(FL_RADIO_BUTTON, 10, 60, 40, 40, "@#circle"); fl_set_object_lcolor(obj,FL_YELLOW); fl_set_object_callback(obj, switch_figure, 0); obj = fl_add_button(FL_RADIO_BUTTON, 50, 60, 40, 40, "@#square"); fl_set_object_lcolor(obj, FL_YELLOW); fl_set_object_callback(obj, switch_figure, 1); obj = fl_add_button(FL_RADIO_BUTTON, 90, 60, 40, 40, "@#8*>"); fl_set_object_lcolor(obj, FL_YELLOW); fl_set_object_callback(obj, switch_figure, 2); fl_end_group(); This creates three buttons that control what figures are to be drawn. Since figure selection is mutually exclusive, we use `RADIO_BUTTON' for this. Further, the three buttons are placed inside a group so that they won't interfere with other radio buttons on the same form. Notice that the callback function `switch_figure()' is bound to all three buttons but with different arguments. Thus the callback function can resolve the associated object via the callback function argument. In this case, 0 is used for circle, 1 for square and 2 for triangle. This association of a callback function with a piece of user data can often reduce the amount of code substantially, especially if you have a large group of objects that control similar things. The advantage will become clear as we proceed. Next we add three sliders to the form. By using appropriate colors for these sliding bars (red, green, blue), there is no need to label them. There's also no need to store their addresses as their callback routine `change_color()' will receive them automatically. fdui->colgrp = fl_bgn_group(); obj = fl_add_slider(FL_VERT_FILL_SLIDER, 25, 170, 30, 125, ""); fl_set_object_color(obj, FL_COL1, FL_RED); fl_set_object_callback(obj, change_color, 0); obj = fl_add_slider(FL_VERT_FILL_SLIDER, 55, 170, 30, 125, ""); fl_set_object_color(obj, FL_COL1, FL_GREEN); fl_set_object_callback(obj, change_color, 1); obj = fl_add_slider(FL_VERT_FILL_SLIDER, 85, 170, 30, 125, ""); fl_set_object_color(obj, FL_COL1, FL_BLUE); fl_set_object_callback(obj, change_color, 2); fdui->colorobj = obj = fl_add_box(FL_BORDER_BOX, 25, 140, 90, 25, ""); fl_set_object_color(obj, FL_FREE_COL1, FL_FREE_COL1); fl_end_group(); Again, a single callback function, `change_color()', is bound to all three sliders. In addition to the sliders, a box object is added to the form. This box is set to use the color indexed by `FL_FREE_COL1' and will be used to show visually what the current color setting looks like. This implies that in the `change_color()' callback function, the entry `FL_FREE_COL1' in the Forms Library's internal colormap will be changed. We also place all the color related objects inside a group even though they are not of radio buttons. This is to facilitate gravity settings which otherwise require setting the gravities of each individual object. Next we create our drawing area which is simply a free object of type `NORMAL_FREE' with a handler to be written obj = fl_add_frame(FL_DOWN_FRAME, 145, 30, 370, 405, ""); fl_set_object_gravity(obj, FL_NorthWest, FL_SouthEast); fdui->freeobj = obj = fl_add_free(FL_NORMAL_FREE, 145, 30, 370, 405, "", freeobject_handler); fl_set_object_boxtype(obj, FL_FLAT_BOX); fl_set_object_gravity(obj, FL_NorthWest, FL_SouthEast); The frame is added for decoration purposes only. Although a free object with a down box would appear the same, the down box can be written over by the free object drawing while the free object can't draw on top of the frame since the frame is outside of the free object. Notice the gravity settings. This kind of setting maximizes the real estate of the free object when the form is resized. Next, we need to have control over the size of the object. For this, two sliders are added, using the same callback function but with different user data (0 and 1 in this case): fdui->sizegrp = fl_bgn_group(); fdui->wsli = obj = fl_add_valslider(FL_HOR_SLIDER, 15, 370, 120, 25, "Width"); fl_set_object_lalign(obj, FL_ALIGN_TOP); fl_set_object_callback(obj, change_size, 0); fdui->hsli = obj = fl_add_valslider(FL_HOR_SLIDER, 15, 55, 410,25, "Height"); fl_set_object_lalign(obj, FL_ALIGN_TOP); fl_set_object_callback(obj, change_size, 1); fl_end_group(); The rest of the UI consists of some buttons the user can use to exit the program, elect to draw outlined instead of filled figures etc. The form definition ends with `*note fl_end_form()::'. The structure that holds the form as well as all the objects within it is returned to the caller: fdui->miscgrp = fl_bgn_group(); obj = fl_add_button(FL_NORMAL_BUTTON, 395, 445, 105, 30, "Quit"); fl_set_button_shortcut(obj, "Qq#q", 1); obj = fl_add_button(FL_NORMAL_BUTTON, 280, 445, 105, 30, "Refresh"); fl_set_object_callback(obj, refresh_cb, 0); obj = fl_add_button(FL_NORMAL_BUTTON, 165, 445, 105, 30, "Clear"); fl_set_object_callback(obj,clear_cb,0); fl_end_group(); obj = fl_add_checkbutton(FL_PUSH_BUTTON, 15, 25, 100, 35, "Outline"); fl_set_object_color(obj, FL_MCOL, FL_BLUE); fl_set_object_callback(obj, fill_cb, 0); fl_set_object_gravity(obj, FL_NorthWest, FL_NorthWest); fl_end_form(); return fdui; } After creating the UI we need to write the callback functions and the free object handler. The callback functions are relatively easy since each object is designed to perform a very specific task. Before we proceed to code the callback functions we first need to define the overall data structure that will be used to glue together the UI and the routines that do real work. The basic structure is the DrawFigure structure that holds the current drawing function as well as object attributes such as size and color: #define MAX_FIGURES 500 typedef void (*DrawFunc)(int /* fill */, int, int, int, int, /* x,y,w,h */ FL_COLOR /* color */ ); typedef struct { DrawFunc drawit; /* how to draw this figure */ int fill, /* is it to be filled? */ x, y, w, h; /* position and sizes */ int pc[3]; /* primary color R,G,B */ int newfig; /* indicate a new figure */ FL_COLOR col; /* color index */ } DrawFigure; static DrawFigure saved_figure[MAX_FIGURES], *cur_fig; static FD_drawfree *drawui; int max_w = 30, /* max size of figures */ max_h = 30; All changes to the figure attributes will be buffered in `cur_fig' and when the actual drawing command is issued (mouse click inside the free object), `cur_fig' is copied into `saved_figure' array buffer. Forms Library contains some low-level drawing routines that can draw and optionally fill arbitrary polygonal regions, so in principle, there is no need to use Xlib calls directly. To show how Xlib drawing routines are combined with Forms Library, we use Xlib routines to draw a triangle: void draw_triangle(int fill, int x, int y, int w, int h, FL_COLOR col) { XPoint xp[4]; GC gc = fl_state[fl_get_vclass()].gc[0]; Window win = fl_winget(); Display *disp = fl_get_display(); xp[0].x = x; xp[0].y = y + h - 1; xp[1].x = x + w / 2; xp[1].y = y; xp[2].x = x + w - 1; xp[2].y = y + h - 1; XSetForeground(disp, gc, fl_get_pixel(col)); if (fill) XFillPolygon(disp, win, gc, xp, 3, Nonconvex, Unsorted); else { xp[3].x = xp[0].x; xp[3].y = xp[0].y; XDrawLines(disp, win, gc, xp, 4, CoordModeOrigin); } } Although more or less standard stuff, some explanation is in order. As you have probably guessed, `*note fl_winget()::' returns the current "active" window, defined to be the window the object receiving the dispatcher's messages (`FL_DRAW' etc.) belongs to(1). Similarly the routine `*note fl_get_display()::' returns the current connection to the X server. Part IV has more details on the utility functions in the Forms Library. The array of structures `*note fl_state::[]' keeps much "inside" information on the state of the Forms Library. For simplicity, we choose to use the Forms Library's default GC. There is no fundamental reason that this has be so. We certainly can copy the default GC and change the foreground color in the copy. Of course unlike using the default GC directly, we might have to set the clip mask in the copy whereas the default GC always have the proper clip mask (in this case, to the bounding box of the free object). We use the Forms Library's built-in drawing routines to draw circles and rectangles. Then our drawing functions can be defined as follows: static DrawFunc drawfunc[] = { fl_oval, fl_rectangle, draw_triangle }; Switching what figure to draw is just changing the member `drawit' in `cur_fig'. By using the proper object callback argument, figure switching is achieved by the following callback routine that is bound to all figure buttons void switch_object(FL_OBJECT *obj, long which) { cur_fig->drawit = drawfunc[which]; } So this takes care of the drawing functions. Similarly, the color callback function can be written as follows void change_color(FL_OBJECT *obj, long which) { cur_fig->c[which] = 255 * fl_get_slider_value(obj); fl_mapcolor(cur_fig->col, cur_fig->c[0], cur_fig->c[1], cur_fig->c[2]); fl_mapcolor(FL_FREE_COL1, cur_fig->c[0], cur_fig->c[1], cur_fig->c[2]); fl_redraw_object(drawui->colorobj); } The first call of `*note fl_mapcolor()::' defines the RGB components for index `cur_fig->col' and the second `*note fl_mapcolor()::' call defines the RGB component for index `FL_FREE_COL1', which is the color index used by `colorobj' that serves as current color visual feedback. Object size is taken care of in a similar fashion by using a callback function bound to both size sliders: void change_size(FL_OBJECT * obj, long which) { if (which == 0) cur_fig->w = fl_get_slider_value(obj); else cur_fig->h = fl_get_slider_value(obj); } Lastly, we toggle the fill/outline option by querying the state of the push button void outline_callback(FL_OBJECT *obj, long data) { cur_fig->fill = !fl_get_button(obj); } To clear the drawing area and delete all saved figures, a Clear button is provided with the following callback: void clear_cb(FL_OBJECT *obj, long notused) { saved_figure[0] = *cur_fig; /* copy attributes */ cur_fig = saved_figure; fl_redraw_object(drawui->freeobj); } To clear the drawing area and redraw all saved figures, a Refresh button is provided with the following callback: void refresh_cb(FL_OBJECT *obj, long notused) { fl_redraw_object(drawui->freeobj); } With all attributes and other services taken care of, it is time to write the free object handler. The user can issue a drawing command inside the free object by clicking either the left or right mouse button. int freeobject_handler(FL_OBJECT *obj, int event, FL_Coord mx, FL_Coord my, int key, void *xev) { DrawFigure *dr; switch (event) { case FL_DRAW: if (cur_fig->newfig == 1) cur_fig->drawit(cur_fig->fill, cur_fig->x + obj->x, cur_fig->y + obj->y, cur_fig->w, cur_fig->h, cur_fig->col); else { fl_drw_box(obj->boxtype, obj->x, obj->y, obj->w, obj->h, obj->col1, obj->bw); for (dr = saved_figure; dr < cur_fig; dr++) { fl_mapcolor(FL_FREE_COL1, dr->c[0], dr->c[1], dr->c[2]); dr->drawit(dr->fill,dr->x + obj->x, dr->y + obj->y, dr->w, dr->h, dr->col); } } cur_fig->newfig = 0; break; case FL_PUSH: if (key == FL_MIDDLE_MOUSE) break; cur_fig->x = mx - cur_fig->w / 2; cur_fig->y = my - cur_fig->h / 2; /* convert figure center to relative to the object*/ cur_fig->x -= obj->x; cur_fig->y -= obj->y; cur_fig->newfig = 1; fl_redraw_object(obj); *(cur_fig + 1) = *cur_fig; fl_mapcolor(cur_fig->col + 1, cur_fig->c[0], cur_fig->c[1], cur_fig->c[2] ); cur_fig++; cur_fig->col++; break; } return FL_RETURN_NONE; } In this particular program, we are only interested in mouse clicks and redraw. The event dispatching routine cooks the X event and drives the handler via a set of events (messages). For a mouse click inside the free object, its handler is notified with an FL_PUSH together with the current mouse position mx, my. In addition, the driver also sets the clipping mask to the bounding box of the free object prior to sending `FL_DRAW'. Mouse position (always relative to the origin of the form) is directly usable in the drawing function. However, it is a good idea to convert the mouse position so it is relative to the origin of the free object if the position is to be used later. The reason for this is that the free object can be resized or moved in ways unknown to the handler and only the position relative to the free object is meaningful in these situations. It is tempting to call the drawing function in response to `FL_PUSH' since it is `FL_PUSH' that triggers the drawing. However, it is a (common) mistake to do this. The reason is that much bookkeeping is performed prior to sending `FL_DRAW', such as clipping, double buffer preparation and possibly active window setting etc. All of these is not done if the message is anything else than `FL_DRAW'. So always use `*note fl_redraw_object()::' to draw unless it is a response to `FL_DRAW'. Internally `*note fl_redraw_object()::' calls the handler with `FL_DRAW' (after some bookkeeping), so we only need to mark `FL_PUSH' with a flag `newfig' and let the drawing part of the handler draw the newly added figure. `FL_DRAW' has two parts. One is simply to add a figure indicated by `newfig' being true and in this case, we only need to draw the figure that is being added. The other branch might be triggered as a response to damaged drawing area resulting from `Expose' event or as a response to `Refresh' command. We simply loop over all saved figures and (re)draw each of them. The only thing left to do is to initialize the program, which includes initial color and size, and initial drawing function. Since we will allow interactive resizing and also some of the objects on the form are not resizeable, we need to take care of the gravities. void draw_initialize(FD_drawfree *ui) { fl_set_form_minsize(ui->drawfree, 530, 490); fl_set_object_gravity(ui->colgrp, FL_West, FL_West); fl_set_object_gravity(ui->sizegrp, FL_SouthWest, FL_SouthWest); fl_set_object_gravity(ui->figgrp, FL_NorthWest, FL_NorthWest); fl_set_object_gravity(ui->miscgrp, FL_South, FL_South); fl_set_object_resize(ui->miscgrp, FL_RESIZE_NONE); cur_fig = saved_figure; cur_fig->pc[0] = cur_fig->pc[1] = cur_fig->pc[2] = 127; cur_fig->w = cur->fig->h = 30; cur_fig->drawit = fl_oval; cur_fig->col = FL_FREE_COL1 + 1; cur_fig->fill = 1; fl_set_button(ui->drobj[0], 1); /* show current selection */ fl_mapcolor(cur_fig->col, cur_fig->pc[0], cur->fig->pc[1], cur->fig->pc[2]); fl_mapcolor(FL_FREE_COL1, cur_fig->pc[0], cur->fig->pc[1], cur->fig->pc[2]); fl_set_slider_bounds(ui->wsli, 1, max_w); fl_set_slider_bounds(ui->hsli, 1, max_h); fl_set_slider_precision(ui->wsli, 0); fl_set_slider_precision(ui->hsli, 0); fl_set_slider_value(ui->wsli, cur_fig->w); fl_set_slider_value(ui->hsli, cur_fig->h); } With all the parts in place, the main program simply creates, initializes and shows the UI, then enters the main loop: int main(int argc, char *argv[]) { fl_initialize(&argc, argv, "FormDemo", 0, 0); drawui = create_form_drawfree(); draw_initialize(drawui); fl_show_form(drawui->drawfree, FL_PLACE_CENTER|FL_FREE_SIZE, FL_FULLBORDER, "Draw"); fl_do_forms(); return 0; } Since the only object that does not have a callback is the Quit button, `*note fl_do_forms()::' will return only if that button is pushed. Full source code to this simple drawing program can be found in `demos/freedraw.c'. ---------- Footnotes ---------- (1) If `*note fl_winget()::' is called while not handling messages, the return value must be checked.  File: xforms.info, Node: Part I Goodies, Next: Part II, Prev: Part I Free Objects, Up: Top 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. * Menu: * Messages and Questions:: * Command Log:: * Colormap:: * File Selector::  File: xforms.info, Node: Messages and Questions, Next: Command Log, Up: Part I Goodies 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 `' 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 `*note 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 `*note 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 `' key to mean Yes and the `' key to mean No. If the question goodie is removed programmatically via `*note fl_hide_question()::', the default `def' as given in `*note fl_show_question()::' is taken. If no default is set, 0 is returned by `*note fl_show_question()::'. The following code segment shows one way of using `*note 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 `*note fl_show_question()::' returns 1. If, on the other hand, he pushes the No button before the timeout triggers, `*note fl_show_question()::' returns normally and `*note 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 `*note 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 `' 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 `*note fl_hide_input()::' results in `NULL' being returned by `*note 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 `*note 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.  File: xforms.info, Node: Command Log, Next: Colormap, Prev: Messages and Questions, Up: Part I Goodies 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, `*note fl_exe_command()::' does not deactivate other forms even in blockng mode. This means that the user can interact with the GUI while `*note fl_exe_command()::' waits for the child process to finish. If this is not desired, you can use `*note fl_deactivate_all_forms()::' and `*note fl_activate_all_forms()::' to wrap the function. If `*note 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 `*note 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 `*note 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 `*note 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 `*note 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. `*note 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 `*note fl_show_form()::'. These two routines can be called anytime anywhere after `*note 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., `*note 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 `*note 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.  File: xforms.info, Node: Colormap, Next: File Selector, Prev: Command Log, Up: Part I Goodies 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).  File: xforms.info, Node: File Selector, Prev: Colormap, Up: Part I Goodies 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. [image src="xforms_images/fselect.png"] 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 `*note 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 `*note 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 `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 `' 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 `*note 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 `*note fl_show_form()::', but `FL_NOBORDER' is ignored. If the arguments `directory', `pattern' or `default' passed to `*note 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 ); `*note 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 `*note 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 `*note 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 `*note fl_get_dirlist()::'. See demo program `dirlist.c' for an example use of `*note fl_get_dirlist()::'. Per default not all types of files are returned by `*note 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.  File: xforms.info, Node: Part II, Next: Part II Introduction, Prev: Part I Goodies, Up: Top _Part II - The Form Designer_ ***************************** * Menu: * Part II Introduction:: * Part II Getting Started:: * Part II Command Line Arguments:: * Part II Creating Forms:: * Part II Saving and Loading Forms:: * Part II Language Filters:: * Part II Generating Hardcopies::  File: xforms.info, Node: Part II Introduction, Next: Part II Getting Started, Prev: Part II, Up: Top 7 Introduction ************** This part of the documentation describes the Form Designer, a GUI builder meant to help you interactively design dialogue forms for use with the Forms Library. This part assumes the reader is familiar with the Forms Library and has read Part I of this document. Even though designing forms is quite easy and requires only a relatively small number of lines of C-code, it can be time consuming to figure out all required positions and sizes of the objects. The Form Designer was written to facilitate the construction of forms. With Form Designer, there is no longer any need to calculate or guess where the objects should be. The highly interactive and WYSIWYG (What You See Is What You Get) nature of the Form Designer relieves the application programmer from the time consuming process of user interface construction so that he/she can concentrate more on what the application program intends to accomplish. Form Designer provides the abilities to interactively place, move and scale objects on a form, also the abilities to set all attributes of an object. Once satisfactory forms are constructed, the Form Designer generates a piece of C-code that can then be included in the application program. This piece of code will contain one procedure create_form_xxx() for each form, where xxx indicates the form name. The application only needs to call it to generate the form designed. The code produced is easily readable. The Form Designer also lets the user identify each object with C variables for later reference in the application program and allows advanced object callback bindings all within the Form Designer. All actions are performed with the mouse or the function keys. It uses a large number of forms itself to let the user make choices, set attributes, etc. Most of these forms were designed using the Form Designer itself. It is important to note that the Form Designer only helps you in designing the layout of your forms. It does not allow you to specify the actions that have to be taken when, e.g., a button is pushed. You can indicate the callback routine to call but the application program has to supply this callback routine. Also, the current version is mostly a layout tool and not a programming environment, not yet anyway. This means that the Form Designer does not allow you to initialize all your objects. You can, however, initialize some objects, e.g., you can set the bounds of a slider inside the Form Designer. Eventually full support of object initialization will be implemented.  File: xforms.info, Node: Part II Getting Started, Next: Part II Command Line Arguments, Prev: Part II Introduction, Up: Top 8 Getting Started ***************** To start up the Form Designer simply type fdesign without any arguments. (If nothing happens, check whether the package has been installed correctly.) A black window (the main window) will appear on the screen. This is the window in which you can create your forms. Next the control panel appears on the screen. No form is shown yet. [image src="xforms_images/fdesign.png"] The control panel consists of five parts. The first part is the menu bar, consisting of several groups of menus from which you can make selections or give commands to the program. Directly below the menu you have a row of buttons for alignment, testing and getting help, see below. Then there's a panel with three browsers. At the left there is a list of all existing forms. When the program is started without an already existing file as an argument the list is empty, indicating that there are no forms yet. There's no upper limit to the number of forms that can be created but you can only work on exactly one form at a time. Use this list to switch between the different forms. Below the forms list is another list showing all groups in the form you're currently working on. It will be empty for a new form because there are no groups yet. Ignore this at the moment as we will come back to groups and their uses later. Just right of those two lists you find a list of all the different classes of objects that can be placed into the form. Use the mouse to select the class of a new object you want to add to the form. On the right side beside the panel with the browsers you find a number of buttons to give commands to the program. Each of these buttons is bound to a function key. You can either press the buttons with the mouse or press the corresponding function keys on the keyboard (while the keyboard focus is on the window with the form). The functions of these keys will be described below. To create a new form select the "New Form" entry in the "Form" menu. A little popup box will appear, prompting you for the name of the new form. This is the name under which the program you're going to write will know the form. Thus you will have to provide a name which must be a legal C variable name. Type in the name and press `'. Now the color of the window for showing the form you're working on changes to that of the default background color of forms. (Actually, each new form gets created with a box already covering its entire area, what you see is the color of this box. You can change most properties of this box using the methods described below. Just its size is fixed to the size of the form, which can be simply changed by resizing the window.) Note that the form's name is added to the list of forms in the control panel. To add an object to the form select its class in the control panel by selecting an item the list of object classes. Then move the mouse into the window with the form you are working on and drag the mouse while pressing the left mouse button. By keeping the mouse button pressed you create a box that has the size of the object to be created. Release the button and the object will appear. Note that a red outline appears around the new object. This indicates that the object is selected. In this way you can put all kinds of objects on the form. Object already created can be modified in several ways. You can move them around, change their sizes or their attributes. To this end first select the object by left-clicking on it. But this only works if there isn't an obkect class selected in the object class browser in the control panel. To get rid of such a selection either click on the selected entry in this browser or by right-click somewhere in the window with the new form. When the object is selected a red outline appears around it. You now will be able to drag the object around with the mouse. By grabbing the object at one of the four red corners you can change its size. It is also possible to select multiple objects and move or scale them simultaneously. See below for details. To change the object's attributes, e.g., its label, simply double-click on it with the left mouse button. Or single-click on it and then press the function key `' (or click on the button labeled "F1 attribs" in the control panel or select "Object attributes" from the "Object" menu). A new form appears in which you can change all the different attributes. Their meanings should be clear (if you have read the documentation on the Forms Library). Change the attributes you want to change and finally press the button labeled "Accept". To reset all attributes to their original values press "Restore" (or "Cancel" if you also want to close the window for modifying the attributes). See below for more information about changing attributes. In this way you can create the forms you want to have. Note that you can have more than one form. Just add another form in the way described above and use the list of forms to switch between them. After you have created all your forms select "Save" or "Save As"from the "File" menu to save them to disk. It will ask you for a file name using the file selector. In this file selector you can walk through the directory tree to locate the place where you want to save the file. Next, you can type in the name of the file (or point to it when you want to overwrite an existing file). The name should end with `.fd'. So for example, choose `ttt.fd'. The program now creates three files: `ttt.c', `ttt.h' and `ttt.fd'. `ttt.c' contains a readable piece of C code that creates the forms you designed. The file `ttt.h' contains the corresponding header file for inclusion in your application program. The file `ttt.fd' contains a description of the forms in such a way that the Form Designer can read it back in later. The application program now simply has to call the routines with names like `create_form_xxx()' (replace `xxx' with the names you gave to the forms) to create the different forms you designed. These are the basic ideas behind the Form Designer. In the following chapters we describe the program in more detail.  File: xforms.info, Node: Part II Command Line Arguments, Next: Part II Creating Forms, Prev: Part II Getting Started, Up: Top 9 Command Line Arguments ************************ To start the Form Designer simply type fdesign [-xformoptions] [-fdesignoptions] [files[.fd]] An initial window will be created and mapped. Depending on the window manager, you may have the option to interactively select where to place the window if the `-geometry' option is not given. Next the program places the control panel on the screen. You can move this panel, if required, to the place you want (you can also change the default placement of the control panel via resources). fdesign accepts all of the XForms command line options as well as the following `-geometry geom' This option specifies the initial placement and size of the working area. `-convert fd-file-list' Normally fdesign does its work interactively. This option causes it to simply read a list of fdesign output files (the `.fd' files) and emit the corresponding C-routines and header files. This can be useful e.g., in automatically compiling packages in Makefiles. Note that the input `.fd' will only be read but never modified when this option is used. `-migrate fd-file-list' When fdesign is invoked with the `-convert' option it just creates new `.c' and `.h' files but leaves the `.fd' files unmodified. In some situations, e.g., if you also want to automatically upgrade `.fd' files created with older versions of fdesign, you can instead use the `-migrate' option which does all what the `-convert' option does but also writes out a new version of the `.fd' file it just read in. It also does a few extra checks, e.g., it will test if XBM and XPM image files used for bitmaps and pixmaps actually exist (if they don't the newly generated `.fd' file won't reference them anymore, so carefully look out for error messages and, if necessary, restore it from the generated `.fd.bak' backup file). `-version' Prints current version and quits. `-help' Prints a brief help message on command line options. `-altformat' Generates an alternative output format. `-border' Forces decorations on some types of windows so that you can move them (only necessary with some window managers). `-unit point|pixel|mm|cp|cmm' Outputs object sizes in units other than pixels. cp and cmm stand for centi-point (1/100 of a point) and centi-mm (1/100 of a milli-meter). For typical displays, pixel and mm are too coarse and subject to round-off errors. `-nocode' Suppresses the output of UI code. Sometimes useful if the UI code is not to be generated interactively, but rather generated by the make process using "fdesign -convert". `-I header' Changes the output include file from `' to header. Per default, the header file name will be enclosed in angle brackets ('`<'' and '`>'') unless the name of the include file specified is already enclosed in double quote ('`"''). Useful on systems where `forms.h' is renamed to something else or if you need an application header file with e.g., definitions of constants/defines for the UI that itself includes the `forms.h' file. `-main' Emits a main program with callback stubs. Can be useful for simple programs. `-callback' Emits callback function template in a separate file. `-lax' Suppresses checking of variable and callback function names for being aceptable C variable names `-bw borderwidth' Changes the default border width of the forms created. Note that `-help', `-version' and `-convert' do not require a connection to an X server. If an output unit other than the default (pixel) is selected, all object sizes in the output file will be in the unit requested. This kind of UI has a fixed and device resolution independent size (in theory at least) and can be useful for drawing applications. fdesign recognizes the following resources: `workingArea.geometry' string Geometry `control.border' bool XForms borderwidth `control.geometry' string Control window geometry (position only) `attributes.geometry' string Attributes window Geometry (position only) `attributes.background'string (e.g., Attributes window background gray80) `align.geometry' string Align window geometry (position only) `help.geometry' string Help window geometry (position only) `convert' bool Convert `unit' string Unit `altformat' bool AltFormat `xformHeader' string Header file name `helpFontSize' int Help font size `main' bool Main Note that resource specification of convert requires an X connection. In addition, all XForms's resources specification can be used to influence the appearance of various panels. The most useful ones are the font sizes `*XForm.FontSize' all label font sizes `XForm.PupFontSize' all pup font sizes  File: xforms.info, Node: Part II Creating Forms, Next: Part II Saving and Loading Forms, Prev: Part II Command Line Arguments, Up: Top 10 Creating Forms ***************** * Menu: * Creating and Changing Forms:: * Adding Objects:: * Selecting Objects:: * Moving and Scaling:: * Aligning Objects:: * Raising and Lowering:: * Setting Attributes:: * Generic Attributes:: * Object Specific Attributes:: * Cut, Copy and Paste: Copy and Paste * Groups:: * Hiding and Showing Objects:: * Testing Forms::  File: xforms.info, Node: Creating and Changing Forms, Next: Adding Objects, Up: Part II Creating Forms 10.1 Creating and Changing Forms ================================ To create a new form use the "New Form" entry in the "Form" menu at the top. When asked for the new form's name enter a (unique) name that is a valid C identifier. The form is shown in the main window and objects can be added to it. There are two ways to change the size of a form. The easiest way is to simply change the size of the main window displaying the form and the form will resize itself to fit the new size. Otherwise you can use the "Resize Form" entry in the "Form" menu, in which case you can enter the width and height of the form manually. To change the name of the current visible form use the "Rename Form" entry in the "Form" menu. You will be prompted for the new form name. To delete a form use the "Delete Form" entry in the "Form" menu . The current form will be removed after a box asking you if you're sure had been shown.  File: xforms.info, Node: Adding Objects, Next: Selecting Objects, Prev: Creating and Changing Forms, Up: Part II Creating Forms 10.2 Adding Objects =================== To add an object choose the class of the new object from the list of object classes in the middle of the control panel. Next drag the left mouse button within the main form. A rubber box outlining the size of the new object will appear. When the size is correct release the mouse button. Note that the position and size of the object is rounded to multiples of 10 pixels per default. How to change the default is described below in the context of alignments.  File: xforms.info, Node: Selecting Objects, Next: Moving and Scaling, Prev: Adding Objects, Up: Part II Creating Forms 10.3 Selecting Objects ====================== To perform operations on objects that are already visible in the form, we first have to select them. Any mouse button can be used for selecting objects. Simply single-click on the object you want to select. A red outline will appear, indicating that the object is selected. Another way of selecting objects is to use the `' or `' keys or the button labeled `F11', all of which iterates over the object list and selects the next object upon each press (the only object not selected this way is the backface object). It is also possible to select multiple objects. To this end draw a box by dragging the mouse around all the objects you want to select. All objects that lie fully inside the box will be selected. Each selected object will get a red outline and a red bounding box is drawn around all of them. To add objects to an already existing selection, hold down the `' key and press the left mouse button inside the object. You can remove objects from the selection by doing the same on an already selected object. It is possible to select all objects (except for the backface object) at once using the function key `'. One note on the backface of the form: Although this is a normal object it can not be treated in the same way as the other objects. It can be selected, but never in combination with other objects. Only changing its attributes is allowed.  File: xforms.info, Node: Moving and Scaling, Next: Aligning Objects, Prev: Selecting Objects, Up: Part II Creating Forms 10.4 Moving and Scaling ======================= To move an object (or a collection of objects) to a new place, first select it (them) as described above. Next press the left mouse button inside the bounding box (not too near to one of the corners) and move the box to its new position. To scale the object or objects, pick up the bounding box near one of its corners (inside the red squares) and scale it by dragging the mouse. When holding the `' key while moving an object or group of objects, first a copy of the object(s) is made and the copy is moved. This allows for a very fast way of duplicating (cloning) objects on the form: First put one on the form, change the attributes as required and next copy it. For precise object movement the cursor keys can be used. Each press of the four directional cursors keys moves the selected object by 10 pixels per default. To change the step sizepress one of the numbers from 0 to 9 with 0 indicating 10 pixels. If the `' key is kept pressed down instead of moving the object its size is increased or decreased by the step size.  File: xforms.info, Node: Aligning Objects, Next: Raising and Lowering, Prev: Moving and Scaling, Up: Part II Creating Forms 10.5 Aligning Objects ===================== Sometimes you have a number of objects and you want to align them in some way, e.g., centered or all starting at the same left position, etc. To this end press the button labeled "Align". A special form will appear in the top right corner. You can leave this form visible as long as you want. You can hide it using the button labeled "Dismiss" on the form or by clicking the "Align" button again. First select the objects you want to align. Next, press one of the alignment buttons in the form. The buttons in the top row have the following meaning: flush left, center horizontally, flush right, and make the objects have equal distances in horizontal direction (see below). The buttons in the bottom row mean: align to bottom, center vertically, align to top, and make all objects have the same vertical distance. Note that alignments are relative to the selection box, not to the form. Equal distance alignment means that between all the objects an equal sized gap is placed. The objects are kept in the same left to right or bottom to top order. [image src="xforms_images/fd_align.png"] The "Undo" button undoes the last alignment change. It is an undo with a depth of 1, i.e., you can only undo the last change and an undo after an undo will undo itself. Note however, that any modification to the selected objects invalidates the undo buffer. In the alignment form you can also indicate the "snapping size" when moving or resizing objects, using the counter at the bottom. Default snapping is 10 pixels. Snapping helps in making objects of the same size and aligning them nicely.  File: xforms.info, Node: Raising and Lowering, Next: Setting Attributes, Prev: Aligning Objects, Up: Part II Creating Forms 10.6 Raising and Lowering ========================= The objects in a form are drawn in the order in which they are added. Sometimes this is undesirable. For example, you might decide at a later stage to put a box around some buttons. Because you add this box later it will be drawn over the buttons, thus hiding the buttons (if you put a framebox over a button, the button will be visible but appears to be inactive!). This is definitely not what you want. The Form Designer makes it possible to raise objects (bring them to the top) or lower them (put them at the bottom). So you can lower e.g., a box to move it under some buttons. Raising or lowering objects is very simple. First select the objects and next press the function key `' to lower the selection or `' to raise it. Another use of raising and lowering is to change the order in which input field receive focus via the `' key. Input fields focus order is the same as the order in which they were added to the form. This can become a problem if another input field is needed after the form is designed because this extra input field will always be the last among all input field on the form. Raising the objects becomes handy to solve this problem. What really happens when a object is raised is that the raised object becomes the last object added to the form. This means you can re-arrange the focus order by raising all input fields one by one in the exact order you want the focus order to be, and they will be added to the form in the order you raised them, thus the input focus order is what you intended.  File: xforms.info, Node: Setting Attributes, Next: Generic Attributes, Prev: Raising and Lowering, Up: Part II Creating Forms 10.7 Setting Attributes ======================= To set attributes like type, color, label, etc., of an object first select it (using the left mouse button) and next press the function key `' (or click on the button labeled "F1"). Also a double click (with the left mouse button) selects the object and opens up the form for changing the objects attributes. If only one object is selected you can change all its attributes, including its label, name, etc. It is also possible to change the attributes of multiple objects as long as they all are of the same object class. In this case you cannot change the labels, names, etc. because you probably want them to remain different for the different objects. The form for changing object attributes allows you to modify all the different settings. Before we continue, the organization of the attributes form and classification of attributes needs a little explanation. Attributes of an object are divided into two categories. The generic attributes are shared by all objects. These include type, colors, label, callback function etc. The other class of attributes are those that are specific to a particular object class, such as slider bounds, precision etc. When the attribute form is first shown, only the generic attributes are shown. Press on the tab rider "Spec" to get to a second form for the object class specific attributes (press the tab rider "Generic" to switch back to the generic attributes part).  File: xforms.info, Node: Generic Attributes, Next: Object Specific Attributes, Prev: Setting Attributes, Up: Part II Creating Forms 10.8 Generic Attributes ======================= The form for setting generic attributes contains four fields for setting different groups of generic properties, discussed in the following. Once you are satisfied with the settings, press the button labeled "Accept" and the form will disappear. If you don't want to change the attributes after all press the button labeled "Cancel". You may also reset the values to what they were when you started editing them by clicking on the "Undo" button. [image src="xforms_images/genattr.png"] * Menu: * Basic Attributes:: * Font:: * Misc. Attributes:: * Colors::  File: xforms.info, Node: Basic Attributes, Next: Font, Up: Generic Attributes 10.8.1 Basic Attributes ----------------------- The basic attributes include the type, boxtype, name, label string, the callback function with its arguments associated with the object and a shortcut. For most object classes several different types exist. The type of the object under consideration can be selected via a choice object. Most objects can also be drawn using different boxtypes. Normally, the default should do, but using the choice object labeled "BoxType" you can switch to a different box type (but note that not all choices may result in a different way the object is drawn and some may look rather ugly). Nearly all objects have a label that can be drawn at different positions within or outside of the object. The input field labeled "Label" lets you set the label string (it may also include return characters, i.e., `\n', for line breaks). An object may have a name by which it can be accessed within the program. This name must be a valid C (or simple C++) variable identifier and can be set via the input field labeled "Name". You need to make sure that there are no objects with the same name! If instead of having e.g., the function `*note fl_do_forms()::' return when an object is triggered a callback may be invoked instead. You can set the name of the callback function in the input field labeled "Callback". Obviously, this must be a valid C or C++ function name. When a callback function is set you must also specify the argument passed to the callback function together with the object's address via the input field labeled "Argument". This normally will be a (long) integer (defaulting to 0 if not specified). Using this value it is e.g., possible to distinguish between different objects when all use the same callback function.  File: xforms.info, Node: Font, Next: Misc. Attributes, Prev: Basic Attributes, Up: Generic Attributes 10.8.2 Font ----------- In the field labeled "Font" you can set properties of the font to be used for the label of the object. You can select between different types of fonts, the style the label is drawn in (normal, shadowed, engraved or embossed) and the size of the font to be used. All three types of properties can be selected via choice objects.  File: xforms.info, Node: Misc. Attributes, Next: Colors, Prev: Font, Up: Generic Attributes 10.8.3 Misc. Attributes ----------------------- The field labeled "Misc. Attributes" allows the setting of a number of attributes that don't fit into any other category. First you can set the alignment of the object's label. It can be placed inside the object or outside of it and in 9 different positions. Use the choice objects labeled "Label/Align" and "In/Out" for this purpose. Another important property of an object is how it reacts if the size of the form it belongs to is changed. It may keep its original size or may be resized in x- or y-direction or both. The details are controlled via its resize and gravity properties as described in chapter 4. With the choice objects labeled "Resize" you can control if an object is to be resized in x- or y-direction or both or none. You may also specify if the object's upper left hand corner or its lower right hand corner is supposed to keep a fixed distance from the form's borders via the choice objects labeled "NW Gravity" and "SE Gravity". Please note that these properties aren't orthogonal, with the NWGravity and SEGravity overriding the resize property if necessary (also see the program `grav' in the `demo' directory that lets you experiment with these properties).  File: xforms.info, Node: Colors, Prev: Misc. Attributes, Up: Generic Attributes 10.8.4 Colors ------------- Within the "Color" field you can set three colors for the object. The colors of the object itself are controlled via the buttons labeled "Color 1" and "Color 2", while the button labeled "LabelColor" is for setting the color the label is drawn in. Clicking on any of the three buttons will result in a new form being shown in which you can select one of the predefined colors from the internal colormap. You also can select one of the "free" colors but since these colors aren't set yet they will appear as black in the form for selecting the color. While it's rather obvious what the label color is, the meaning of "Color 1" and "Color 2" varies a bit with the class and type of the object. E.g., for (normal buttons the first color is the normal color of the button while the second one is the color it's drawn in while the button is pressed, while for a browser that allows selection the first color is the background color and the second color is the color selected lines are highlighted with. Since there are too many combinations of object classes and types to be discussed here comprehensively please refer to a following chapter where the exact properties of all objects are described in detail.  File: xforms.info, Node: Object Specific Attributes, Next: Copy and Paste, Prev: Generic Attributes, Up: Part II Creating Forms 10.9 Object Specific Attributes =============================== Many objects have attributes that are specific to its object class, such as slider bounds, precision etc. You can access these attributes (if existent) via the tab rider labeled "Spec". In most cases the meaning of these attributes hopefully is self-explanatory (otherwise see the detailed description of the different object classes in Part III) and all changes made are shown immediately so you can see what effects the changes have on the object. Once satisfactory results have been achieved the press button labeled "Accept" to accept the settings (clicking on the tab rider "Generic" has the same effect). Two additional buttons, "Cancel" and "Restore", are available to cancel the changes (and quit the attribute settings form) and restore the defaults, respectively. One particular aspect of the pixmap/bitmap button initialization needs a little more explanation as the setting of button labeled "Use data" has no effect on the appearance of the button in fdesign but nonetheless affects the generated code. By default, the "Use data" button is off, indicating the pixmap/bitmap file specified is to be loaded dynamically at run time via `*note fl_set_pixmapbutton_file()::' (or the bitmap counterpart function). If "Use data" is on, the specified file and its associated data will be `#include''d at compile time so the data becomes part of the code. Depending on the application setup, you may choose one method over the other. In general, including the data in the code will make the code slightly larger, but it avoids problems with finding the specified file at runtime. The button labeled "Full Path" only applies if "Use Data" is on. If "Full Path" is also on, the pixmap file will be `#include''d using the full path, otherwise only the filename is used, presumably the compile process will take care of the path via the `-I' flag in some system dependent way.  File: xforms.info, Node: Copy and Paste, Next: Groups, Prev: Object Specific Attributes, Up: Part II Creating Forms 10.10 Cut, Copy and Paste ========================= You can remove objects from the form by first selecting them and then pressing the `' function key or simply by double-clicking on it with the right mouse button. The object(s) will disappear but in fact will be saved in a buffer. You can put it back into the form (or in another form) by pasting, using `'. Note that only the last collection of deleted objects is saved in the buffer. It is also possible to put a copy of the selection (i.e., without removing the original object(s)) into the buffer using `'. The content of the bufer can now be put into the same or another form. This allows for a simple mechanism of making multiple copies of a set of objects and for moving information from one form to another. To clone the currently selected object, hold down the `' key and then drag the selected object to a new position. The cloned object will have exactly the same attributes as the original object except for its name and shortcut keys (would these also be cloned, the generated code would not be compilable or cause runtime misbehavior). When you copy objects belonging to a common group just the individual objects of the group will be copied, but they won't belong to a common group anymore.  File: xforms.info, Node: Groups, Next: Hiding and Showing Objects, Prev: Copy and Paste, Up: Part II Creating Forms 10.11 Groups ============ As described in the tutorial about the Forms Library, sets of radio buttons must be placed inside groups. Groups are also useful for other purposes. E.g., you can hide a group inside an application program with one command. Hence, the Form Designer has some mechanism to deal with groups. In the control panel there is a list of groups in the current form. As long as you don't have groups, this list will be empty. To create a group, select the objects that should become members of the group and press the function key `'. You will be prompted for the name of the group. This should be a legal C variable name (under which the group will be known to the application program) or should be left empty. This name will be added to the list. In this way you can create many groups. Note that each object can be member of only one group. So if you select it again and put it in a new group, it will be removed from its old group. Groups that become empty this way automatically disappear from the list. (When putting objects in a group they will be raised. This is unavoidable due to the structure of groups.) In the list of groups it is always indicated which groups are part of the current selection. (Only the groups that are fully contained in the selection are indicated, not those that are only partially contained in it.) It is also possible to add or delete groups in the current selection by pushing the mouse on their name in the list. A simple click on a groups name will select this group and deselect all objects not belonging to it. Clicking on a groups name while the `' key is pressed down adds the group to the cuurent selection. Note that there is no mechanism to add an object to a group directly. This can, however, be achieved using the following procedure: select the group and the new object and press `' to group them. The old group will be discarded and a new group will be created. You only have to type in the group name again. You can use the menu "Rename group" from the "Group" menu to change the name of a selected group. Only a single group may be selected when changing the name.  File: xforms.info, Node: Hiding and Showing Objects, Next: Testing Forms, Prev: Groups, Up: Part II Creating Forms 10.12 Hiding and Showing Objects ================================ Sometimes it is useful to temporarily hide some objects in your form, in particular when you have sets of overlapping objects. To this end, select the objects you want to hide and press `'. The objects (though still selected) are now invisible. To show them again press `'. A problem might occur here: when you press `' only the selected objects will be shown again. But once an object is invisible it can no longer be selected. Fortunately, you can always use `' to select all objects, including the invisible ones, and then press `'. A possibly better way is to first group the objects before hiding them. Now you can select them by pressing the mouse on the group name in the group browser and then 'unhide' them.  File: xforms.info, Node: Testing Forms, Prev: Hiding and Showing Objects, Up: Part II Creating Forms 10.13 Testing Forms =================== To test the current form, press the button labeled "Test". The form will be displayed in the center of the screen anf a panel appears at the top right corner of the screen. This panel shows you the objects returned and callback routines invoked when working with the form. In this way you can verify whether the form behaves correctly and whether all objects have either callback routines or names (or both) associated with them. You can also resize the form (if the backface of the form allows resizing) to test the gravity and resizing behaviour. You can play with the form as long as you want. When ready, press the "Stop Testing" button. Note that any changes you made to the form while testing (including its size) do not show up when saving the form. E.g., filling in an input field or setting a slider does not mean that in the saved code the input field will be filled in or the slider's preset value.  File: xforms.info, Node: Part II Saving and Loading Forms, Next: Part II Language Filters, Prev: Part II Creating Forms, Up: Top 11 Saving and Loading Forms *************************** To save the set of forms created select the item "Save" or "Save As" from the "File" menu. You will be prompted for a file name using the file selector if the latter is selected. Choose a name that ends with `.fd', e.g., `ttt.fd'. The program will now generate three files: `ttt.c', `ttt.h' and `ttt.fd'. If these files already exist, backup copies of them are made (by appending `.bak' to the already existing file names). `ttt.c' contains a piece of C-code that builds up the forms and `ttt.h' contains all the object and form names as indicated by the user. It also contains declaration of the defined callback routines. Depending on the options selected from the "Options" menu, two more files may be emitted, namely the main program and callback function templates. They are named `ttt_main.c' and `ttt_cb.c' respectively. There are two different kind of formats for the C-code generated. The default format allows more than one instance of the form created and uses no global variables. The other format, activated by the `altformat' option given on the command line or switched on via the "Options" menu by selecting "Alt Format", uses global variables and does not allow more than one instantiation of the designed forms. However, this format has a global routine that creates all the forms defined, which by default is named `create_the_forms()' but that can be changed (see below). Depending on which format is output, the application program typically only needs to include the header file and call the form creation routine. To illustrate the differences between the two output formats and the typical way an application program is setup, we look at the following hypothetical situation: We have two forms, `foo' and `bar', each of which contains several objects, say `fnobj1', `fnobj2' etc. where `n = 1, 2'. The default output format will generate the following header file (`foobar.h'): #ifndef FD_foobar_h_ #define FD_foobar_h_ /* call back routines if any */ extern void callback(FL_OBJECT *, long); typedef struct { FL_FORM * foo; void * vdata; char * cdata; long ldata; FL_OBJECT * f1obj1; FL_OBJECT * f1obj2; } FD_foo; typedef struct { FL_FORM * bar; void * vdata; char * cdata; long ldata; FL_OBJECT * f2obj1; FL_OBJECT * f2obj2; } FD_bar; extern FD_foo *create_form_foo(void); extern FD_bar *create_form_bar(void); #endif /* FD_foobar_h */ and the corresponding C file: #include #include "foobar.h" FD_foo *create_form_foo(void) { FD_foo *fdui = fl_calloc(1, sizeof *fdui); fdui->foo = fl_bgn_form(....); fdui->f1obj1 = fl_add_aaaa(....); fdui->f1obj1 = fl_add_bbbb(....); fl_end_form(); fdui->foo->fdui = fdui; return fdui; } FD_bar *create_form_foo(void) { FD_bar *fdui = fl_calloc(1, sizeof *fdui); fdui->bar = fl_bgn_form(....); fdui->f2obj1 = fl_add_cccc(....); fdui->f2obj2 = fl_add_dddd(....); fl_end_form(); fdui->bar->fdui = fdui; return fdui; } The application program would look something like the following: #include #include "foobar.h" /* add call back routines here */ int main(int argc, char *argv[]) { FD_foo *fd_foo; FD_bar *fd_bar; fl_initialize(...); fd_foo = create_form_foo(); init_fd_foo(fd_foo); /* application UI init routine */ fd_bar = create_form_bar(); init_fd_bar(fd_bar) /* application UI init routine */ fl_show_form(fd_foo->foo, ...); /* rest of the program */ } As you see, `fdesign' generates a structure that groups together all objects on a particular form and the form itself into a structure for easy maintenance and access. The other benefit of doing this is that the application program can create more than one instance of the form if needed. It is difficult to avoid globals in an event-driven callback scheme with most difficulties occurring inside the callback function where another object on the same form may need to be accessed. The current setup makes it possible and relatively painless to achieve this. There are a couple of ways to do this. The easiest and most robust way is to use the member `form->fdui', which fdesign sets up to point to the `FD_' structure of which the form (pointer) is a member. To illustrate how this is done, let's take the above two forms and try to access a different object from within a callback function. fd_foo = create_form_foo(); ... and in the callback function of `ob' on form `foo', you can access other objects as follows: void callback(FL_OBJECT *obj, long data) { FD_foo *fd_foo = obj->form->fdui; fl_set_object_dddd(fd_foo->f1obj2, ....); } Of course this setup still leaves the problems accessing objects on other forms unsolved although you can manually set the `form->u_vdata' to the other `FD_' structure: fd_foo->form->u_vdata = fd_bar; or use the `vdata' field in the `FD_' structure itself: fd_foo->vdata = fd_bar; The other method, not as easy as using `form->fdui' (because you get no help from fdesign), but just as workable, is simply using the `u_vdata' field in the `FD_' structure to hold the address of the object that needs to be accessed. In case of need to access multiple objects, there is a field `u_vdata' in both the `FL_FORM' and `FL_OBJECT' structures you can use. You simply use the field to hold the `FD_' structure: fd_foo = create_form_foo(); fd_foo->foo->u_vdata = fd_foo; ... and in the callback function you can access other objects as follows: void callback(FL_OBJECT *obj, long data) { FD_foo *fd_foo = obj->form->u_vdata; fl_set_object_dddd(fd_foo->f1obj2, ....); } Not pretty, but adequate for practical purposes. Note that the `FD_' structure always has a pointer to the form as the first member, followed by `vdata', `cdata' and `ldata'. There's also a `typedef' for a structure of type `FD_Any' in `forms.h': typedef struct { FL_FORM * form; void * vdata; char * cdata; long ldata; } FD_Any; you can use a cast to a specific `FD_' structure to get at `vdata' etc. Another alternative is to use the `FD_' structure as the user data in the callback(1) fl_set_object_callback(obj, callback, (long) fdui); and use the callback as follows void callback(FL_OBJECT *obj, long arg) { FD_foo *fd_foo = (FD_foo *) arg; fl_set_object_lcolor(fd + foo->f1obj1, FL_RED); ... } Avoiding globals is, in general, a good idea, but as everything else, also an excess of a good things can be bad. Sometimes simply making the `FD_' structure global makes a program clearer and more maintainable. There still is another difficulty that might arise with the current setup. For example, in `f1obj1''s callback we change the state of some other object, say, `f1obj2' via `*note fl_set_button()::' or `*note fl_set_input()::'. Now the state of `f1obj2' is changed and it needs to be handled. You probably don't want to put much code for handling `f1obj2' in `f1obj1''s callback. In this situation, the following function is handy void fl_call_object_callback(FL_OBJECT *obj); `fl_call_object_callback(fdfoo->f1obj2)' will invoke the callback for `f1obj2' callback in exactly the same way the main loop would do and as far as `f1obj2' is concerned, it just handles the state change as if the user changed it. The alternative format outputs something like the following: /* callback routines */ extern void callback(FL_OBJECT *, long); extern FL_FORM *foo, *bar; extern FL_OBJECT *f1obj1, *f1obj2, ...; extern FL_OBJECT *f2obj1, *f2obj2, ...; extern void create_form_foo(void); extern create_form_bar(void); extern void create_the_forms(void); The C-routines: FL_FORM *foo, *bar; FL_OBJECT *f1obj1, *f1obj2, ...; FL_OBJECT *f2obj1, *f2obj2, ...; void create_form_foo(void) { if (foo) return; foo = fl_bgn_form(....); ... } void create_form_bar(void) { if (bar) return; bar = fl_bgn_form(....); ... } void create_the_forms(void) { create_form_foo(); create_form_bar(); } Normally the application program would look something like this: #include #include "foobar.h" /* Here go the callback routines */ .... int main(int argc, char *argv[]) { fl_initialize(....); create_the_forms(); /* rest of the program follows*/ ... } Note that although the C-routine file in both cases is easily readable, editing it is strongly discouraged. If you were to do so, you will have to redo the changes whenever you call fdesign again to modify the layout. The third file created, `ttt.fd', is in a format that can be read in by the Form Designer. It is easy readable ASCII but you had better not change it because not much error checking is done when reading it in. To load such a file select the "Open" item from the "File" menu. You will be prompted for a file name using the file selector. Press your mouse on the file you want to load and press the button labeled "Ready". The current set of forms will be discarded, and replaced by the new set. You can also merge the forms in a file with the current set. To this end select "Merge" from the "File" menu. ---------- Footnotes ---------- (1) Unfortunately, this scheme isn't legal C as a pointer may be longer than a long, but in practice, it should work out ok on virtually all platforms.  File: xforms.info, Node: Part II Language Filters, Next: Part II Generating Hardcopies, Prev: Part II Saving and Loading Forms, Up: Top 12 Language Filters ******************* *Please note: This chapter is probably completely outdated!* This chapter discusses the language filter support in Form Designer, targeted primarily to the developers of bindings to other language. As of this writing, the authors are aware of the following bindings `ada95' by G. Vincent Castellano `perl' by Martin Bartlett `Fortran' by G. Groten and Anke Haeming `pascal' by Michael Van Canneyt `scm/guile' by Johannes Leveling `python' by Roberto Alsina . It would appear that author of python binding is no longer working on it. These bindings are of varying degree of beta-ness and support. It appears to the authors that the most convenient and flexible way of getting output in the targeted language is through external filters that are invoked transparently by fdesign. This way, developers of the binding would have complete control over the translation of the default output from the fdesign to the target language and at the same time have the translation done transparently. * Menu: * External Filters:: * Command Line Arguments of the Filter::  File: xforms.info, Node: External Filters, Next: Command Line Arguments of the Filter, Up: Part II Language Filters 12.1 External Filters ===================== An external filter is a stand-alone program that works on the output of Form Designer and translates the output to the target language. The filter can elect to work on the `.fd' or the C output or both simultaneously. However, in non-testing situations, the c output from Form Designer probably should be deleted by the filter once the translation is complete. By default, Form Designer only outputs the `.fd' and C files. If the presence of `-ada', `-perl', `-python', `-fortran', `-pascal' or `-scm' command line options to Form Designer is detected, then after emitting the default output, Form Designer invokes the the external filter with the root filename (without the `.fd' extension) as an argument, together with possible other flags, to the filter. Any runtime error messages are presented to the user in a browser. The filter name by default is `fd2xxxx' where `xxxx' is the language name (such as `fd2perl' etc.), which can be changed using the `-filter' command line option (or equivalent resources). The resources that are relevant to the filter are listed below Resource Type Default language string C filter string None  File: xforms.info, Node: Command Line Arguments of the Filter, Prev: External Filters, Up: Part II Language Filters 12.2 Command Line Arguments of the Filter ========================================= Form Designer passes along the options that affect the output format to the filter. These options may or may not apply to the filter, most likely not if the filter works on the C file. For those that do not apply, the filter can simply ignore them, but shouldn't stop running because of these options. `-callback' callback stubs are generated `-main' main stub is generated `-altformat' output in alternate format `-compensate' emit size compensation code  File: xforms.info, Node: Part II Generating Hardcopies, Next: Part III, Prev: Part II Language Filters, Up: Top 13 Generating Hardcopies ************************ A variety of tools are available that can be used to turn your carefully constructed (and hopefully pleasing) user interfaces into printed hardcopies or something appropriate for inclusion in your program document. Most of these involves saving a snapshot of your interface on the screen into a file. Then this file is translated into something that a printer can understand, such as `PostScript'. Another approach is to design the printing capabilities into the objects themselves so the GUI is somewhat output device independent in that it can render to different devices and X or the printer is just one of the devices. While this approach works better than screen snapshot, in general, it bloats the library unnecessarily. It is our observation that most of the time when a hardcopy of the interface is desired, it is for use in the application documentation. Thus we believe that there are ways to meet the needs of wanting hardcopies without bloating the library. Of course, some object classes, such as xyplot, charts and possibly canvas (if vector graphics), that are dynamic in nature, probably should have some hardcopy output support in the library, but even then, the relevant code should only be loaded when these specific support is actually used. This fattening problem is becoming less troublesome as computers get faster and typically have more RAMs nowadays. `fd2ps' was designed to address the need of having a hardcopy of the interface for application documentation development. Basically, `fd2ps' is a translator that translates the Form Designer output directly into `PostScript' or `Encapsulated PostScript' in full vector graphics. The result is a small, maybe even editable, `PostScript' file that you can print on a printer or include into other documents. The translation can be done in two ways. One way is to simply give the Form Designer the command line option `-ps' to have it output `PostScript' directly. or you can run `fd2ps' stand alone using the command fd2ps fdfile where `fdfile' is the Form Designer output with or without the `.fd' extension. The output is written into a file named `fdfile.ps'. `fd2ps' accepts the following command line options when run as a stand-alone program `-h' This option prints a brief help message. `-p' This option requests Portrait output. By default, the orientation is switched to landscape automatically if the output would not fit on the page. This option overrides the default. `-l' This option requests landscape orientation. `-gray' This option requests all colors be converted to gray levels. By default, `fd2ps' outputs colors as specified in the `.fd' file. `-bw width' This option specifies the object border width. By default, the border width specified in the `.fd' file is used. `-dpi res' This option specifies the screen resolution on which the user interface was designed. You can use this flag to enlarge or shrink the designed size by giving a DPI value smaller or larger than the actual screen resolution. The default DPI is 85. If the `.fd' file is specified in device independent unit (point, mm etc), this flag has no effect. Also this flag does not change text size. `-G gamma' This option specifies a value (gamma) that will be used to adjust the builtin colors. The larger the value the brighter the colors. The default gamma is 1. `-rgb file' The option specifies the path to the colorname database `rgb.txt'. (It is used in parsing the colornames in XPM file). The default is `/usr/lib/X11/rgb.txt'. The environment variable `RGBFile' can be used to change this default. `-pw width' This option changes the paper width used to center the GUI on a printed page. By default the width is that of US Letter (i.e., 8.5 inches) unless the environment variable `PAPER' is defined. `-ph height' This option changes the paper height used to center the output on the printed page. The default height is that of US Letter (i.e., 11 inches) unless the environment variable `PAPER' is defined. `-paper format' This option specifies one of the standard paper names (thus setting the paper width and height simultaneously). The current understood paper formats are Letter 8.5 x 11 inch. Legal 8.5 x 14 inch A4 210 x 295mm B4 257 x 364mm B5 18 x 20 cm B 11 x 17 inch Note 4 x 5inch The `fd2ps' program understands the environment variable `PAPER', which should be one of the above paper names.  File: xforms.info, Node: Part III, Next: Part III Introduction, Prev: Part II Generating Hardcopies, Up: Top _Part III - Object Classes_ *************************** * Menu: * Part III Introduction:: * Part III Static Objects:: * Part III Button-like Objects:: * Part III Valuator Objects:: * Part III Input Objects:: * Part III Choice Objects:: * Part III Container Objects:: * Part III Other Objects:: * Part III Popups:: * Part III Deprecated Objects::  File: xforms.info, Node: Part III Introduction, Next: Part III Static Objects, Prev: Part III, Up: Top 14 Introduction *************** This part describes all different object classes that are available in the Forms Library. All available object classes are summarized in a table below. 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_CLASS(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 upper 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_CLASS(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, there is the way in which the user interacts with the object, and second there's the question under which circumstances an object changes its state and how this is returned to the application program. All this is described in detail in the following sections. 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. Object classes can be roughly divided into static object classes (Box, Frame, LabelFrame, Text, Bitmap, Pixmap, Clock and Chart), Buttons, valuator objects classes (Slider, Scrollbar, Dial, Positioner, Counter, Thumbwheel), Inputs, choice object classes (Menu, Choice, Browser), container object classes (Tabbed Folder, Form Browser, Menu bar) and, finally, other object classes (Timer, XYPlot, Canvas, Popup). Box Rectangular areas to visually group objects. Frame A box with an empty inside region. LabelFrame A frame with label on the frame. Text Simple one line labels. Bitmap Displays an X11 bitmap. Pixmap Displays a pixmap using the XPM library. Clock A clock. Chart Bar-charts, pie-charts, strip-charts, etc. Button Many different kinds and types of buttons that the user can push. Slider ValSlider Both vertical and horizontal sliders to let the user indicate some float value, possibly with a field showing the currently set value. Scrollbar Sliders plus two directional buttons. Dial A dial to let the user indicate a float value. Positioner Lets the user indicate an (x, y) position with the mouse. Counter A different way to let a user step through values. Thumbwheel Rolling a wheel to indicate float values. Input Lets the user type in an input string. Menu Both pop-up and drop-down menus can be created. Choice Can be used to let the user make a choice from a set of items. Browser A text browser with a slider. Can be used for making selections from sets of choices. Folder A (tabbed) folder is a compound object capable of holding multiple groups of objects. FormBrowser A browser you can drop forms into. Timer A timer that runs from a set time towards 0. Can e.g., be used to do default actions after some time has elapsed. XYPlot Shows simple 2D xy-plot from a tabulated function or a datafile. Data points can be interactively manipulated and retrieved. Canvas Canvases are managed plain X windows. It differs from a raw application window only in the way its geometry is managed, not in the way various interaction is set up. Popups Popup are mostly used by menus and choices, but they can also be used stand-alone to isplay context menus etc. 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 described what effect the routine `*note fl_set_object_color()::' has on the appearance of the object. Also some remarks on possible boxtypes are made.  File: xforms.info, Node: Part III Static Objects, Next: Part III Button-like Objects, Prev: Part III Introduction, Up: Top 15 Static Objects ***************** * Menu: * Box Object: Box Object * Frame Object: Frame Object * LabelFrame Object: LabelFrame Object * Text Object: Text Object * Bitmap Object: Bitmap Object * Pixmap Object: Pixmap Object * Clock Object: Clock Object * Chart Object: Chart Object  File: xforms.info, Node: Box Object, Next: Frame Object, Up: Part III Static Objects 15.1 Box Object =============== 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. * Menu: * Adding Box Objects: Adding Box Objects * Box Types: Box Types * Box Attributes: Box Attributes * Remarks: Box Remarks  File: xforms.info, Node: Adding Box Objects, Next: Box Types, Up: Box Object 15.1.1 Adding Box Objects ------------------------- 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 per default placed in the center of the box.  File: xforms.info, Node: Box Types, Next: Box Attributes, Prev: Adding Box Objects, Up: Box Object 15.1.2 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 just 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.  File: xforms.info, Node: Box Attributes, Next: Box Remarks, Prev: Box Types, Up: Box Object 15.1.3 Box Attributes --------------------- The first color argument (`col1') to `*note fl_set_object_color()::' controls the color of the box, the second (`col2') is not used.  File: xforms.info, Node: Box Remarks, Prev: Box Attributes, Up: Box Object 15.1.4 Remarks -------------- No interaction takes place with boxes. Do not use `FL_NO_BOX' type if the label is to change during the execution of the program.  File: xforms.info, Node: Frame Object, Next: LabelFrame Object, Prev: Box Object, Up: Part III Static Objects 15.2 Frame Object ================= 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. * Menu: * Adding Frame Objects: Adding Frame Objects * Frame Types: Frame Types * Frame Attributes: Frame Attributes * Remarks: Frame Remarks  File: xforms.info, Node: Adding Frame Objects, Next: Frame Types, Up: Frame Object 15.2.1 Adding Frame Objects --------------------------- 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.  File: xforms.info, Node: Frame Types, Next: Frame Attributes, Prev: Adding Frame Objects, Up: Frame Object 15.2.2 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.  File: xforms.info, Node: Frame Attributes, Next: Frame Remarks, Prev: Frame Types, Up: Frame Object 15.2.3 Frame Attributes ----------------------- The first color argument (`col1') of `*note fl_set_object_color()::' controls the color of the frame if applicable, the second (`col2') is not used. The boxtype attribute does not apply to the frame class.  File: xforms.info, Node: Frame Remarks, Prev: Frame Attributes, Up: Frame Object 15.2.4 Remarks -------------- No interaction takes place with frames. 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.  File: xforms.info, Node: LabelFrame Object, Next: Text Object, Prev: Frame Object, Up: Part III Static Objects 15.3 LabelFrame Object ====================== A label frame is almost the same as a frame except that the label is placed on the frame (See Fig. 15.1) instead of inside or outside of the bounding box as in a regular frame. * Menu: * Adding LabelFrame Objects: Adding LabelFrame Objects * LabelFrame Types: LabelFrame Types * LabelFrame Attributes: LabelFrame Attributes * Remarks: LabelFrames Remarks  File: xforms.info, Node: Adding LabelFrame Objects, Next: LabelFrame Types, Up: LabelFrame Object 15.3.1 Adding LabelFrame Objects -------------------------------- 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 on the upper left hand part of the frame. Its position can changed (within limits) via calls of `*note fl_set_object_lalign()::'. [image src="xforms_images/labelframe.png"]  File: xforms.info, Node: LabelFrame Types, Next: LabelFrame Attributes, Prev: Adding LabelFrame Objects, Up: LabelFrame Object 15.3.2 LabelFrame 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.  File: xforms.info, Node: LabelFrame Attributes, Next: LabelFrames Remarks, Prev: LabelFrame Types, Up: LabelFrame Object 15.3.3 Attributes ----------------- The first color in the call of `*note fl_set_object_color()::' controls the color of the frame if applicable. The second color controls the background color of the label. Boxtype attribute does not apply to the labelframe class  File: xforms.info, Node: LabelFrames Remarks, Prev: LabelFrame Attributes, Up: LabelFrame Object 15.3.4 Remarks -------------- No interaction takes place with labelframes. 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'.  File: xforms.info, Node: Text Object, Next: Bitmap Object, Prev: LabelFrame Object, Up: Part III Static Objects 15.4 Text Object ================ Text objects simply consist of a label possibly placed in a box. * Menu: * Adding Text Objects: Adding Text Objects * Text Types: Text Types * Text Attributes: Text Attributes * Remarks: Text Remarks  File: xforms.info, Node: Adding Text Objects, Next: Text Types, Up: Text Object 15.4.1 Adding Text Objects -------------------------- 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.  File: xforms.info, Node: Text Types, Next: Text Attributes, Prev: Adding Text Objects, Up: Text Object 15.4.2 Text Types ----------------- Only one type of text exists: `FL_NORMAL_TEXT'.  File: xforms.info, Node: Text Attributes, Next: Text Remarks, Prev: Text Types, Up: Text Object 15.4.3 Text Attributes ---------------------- To set or change the text shown, use `*note fl_set_object_label()::' or `*note fl_set_object_label_f()::'. Any boxtype can be used for text. The first color argument (`col1') of `*note fl_set_object_color()::' controls the color of the box the text is placed into, the second (`col2') is not used. The color of the text itself is controlled by calls of `*note fl_set_object_lcolor()::' as usual. If the text is to change dynamically, boxtype `NO_BOX' should not be used for the object.  File: xforms.info, Node: Text Remarks, Prev: Text Attributes, Up: Text Object 15.4.4 Remarks -------------- No interaction takes place with text objects. Don't use boxtype `FL_NO_BOX' if the text 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 `*note fl_set_object_lalign()::'. In contrast to boxes different alignments for text always place the text inside the box rather than outside the box.  File: xforms.info, Node: Bitmap Object, Next: Pixmap Object, Prev: Text Object, Up: Part III Static Objects 15.5 Bitmap Object ================== A bitmap is a simple bitmap shown on a form. * Menu: * Adding Bitmap Objects: Adding Bitmap Objects * Bitmap Types: Bitmap Types * Bitmap Interaction: Bitmap Interaction * Other Bitmap Routines: Other Bitmap Routines * Bitmap Attributes: Bitmap Attributes * Remarks: Bitmap Remarks  File: xforms.info, Node: Adding Bitmap Objects, Next: Bitmap Types, Up: Bitmap Object 15.5.1 Adding Bitmap Objects ---------------------------- 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 is empty on creation.  File: xforms.info, Node: Bitmap Types, Next: Bitmap Interaction, Prev: Adding Bitmap Objects, Up: Bitmap Object 15.5.2 Bitmap Types ------------------- Only the type `FL_NORMAL_BITMAP' is available.  File: xforms.info, Node: Bitmap Interaction, Next: Other Bitmap Routines, Prev: Bitmap Types, Up: Bitmap Object 15.5.3 Bitmap Interaction ------------------------- No interaction takes place with a bitmap. For bitmaps that interact see *note Adding Button Objects::, on how to create a button with a bitmap on top of it. (You can also place a hidden button over it if you want something to happen when pressing the mouse on a static bitmap.)  File: xforms.info, Node: Other Bitmap Routines, Next: Bitmap Attributes, Prev: Bitmap Interaction, Up: Bitmap Object 15.5.4 Other Bitmap Routines ---------------------------- To set the actual bitmap being displayed use void fl_set_bitmap_data(FL_OBJECT *obj, int w, int h, unsigned char *bits); void fl_set_bitmap_file(FL_OBJECT *obj, const char *file); `bits' contains the bitmap data as a character string. `file' is the name of the file that contains the 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 Bitmap 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 the other parameters have the obvious meanings. If there is no window created yet, the return value of `*note fl_default_window()::' may be used. Note: bitmaps created by the above routines have a depth of 1 and should be displayed using `XCopyPlane()'.  File: xforms.info, Node: Bitmap Attributes, Next: Bitmap Remarks, Prev: Other Bitmap Routines, Up: Bitmap Object 15.5.5 Bitmap Attributes ------------------------ The label color as set by `*note fl_set_object_lcolor()::' controls both the foreground color of the bitmap and the color of the label (i.e., they are always identical). The first color argument (`col1') to `*note fl_set_object_color()::' sets the background color of the bitmap (and the color of the box), the second (`col2') is not used.  File: xforms.info, Node: Bitmap Remarks, Prev: Bitmap Attributes, Up: Bitmap Object 15.5.6 Remarks -------------- See `demo33.c' for a demo of a bitmap.  File: xforms.info, Node: Pixmap Object, Next: Clock Object, Prev: Bitmap Object, Up: Part III Static Objects 15.6 Pixmap Object ================== A pixmap is a simple pixmap (color icon) shown on a form. * Menu: * Adding Pixmap Objects: Adding Pixmap Objects * Pixmap Types: Pixmap Types * Pixmap Interaction: Pixmap Interaction * Other Pixmap Routines: Other Pixmap Routines * Pixmap Attributes: Pixmap Attributes * Remarks: Pixmap Remarks  File: xforms.info, Node: Adding Pixmap Objects, Next: Pixmap Types, Up: Pixmap Object 15.6.1 Adding Pixmap Objects ---------------------------- To add a pixmap to a form 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 is empty on creation.  File: xforms.info, Node: Pixmap Types, Next: Pixmap Interaction, Prev: Adding Pixmap Objects, Up: Pixmap Object 15.6.2 Pixmap Types ------------------- Only the type `FL_NORMAL_PIXMAP' is available.  File: xforms.info, Node: Pixmap Interaction, Next: Other Pixmap Routines, Prev: Pixmap Types, Up: Pixmap Object 15.6.3 Pixmap Interaction ------------------------- No interaction takes place with a pixmap. For pixmap that interacts see *note Adding Button Objects::, on how to create a button with a pixmap on top of it. (You can also place a hidden button over it if you want something to happen when pressing the mouse on a static pixmap.)  File: xforms.info, Node: Other Pixmap Routines, Next: Pixmap Attributes, Prev: Pixmap Interaction, Up: Pixmap Object 15.6.4 Other Pixmap Routines ---------------------------- A pixmap file (usually with extension `.xpm') is an ASCII file that contains the definition of the pixmap as a `char' pointer array that can be included directly into a C (or C++) source file. To set the actual pixmap being displayed, use one of the following routines: void fl_set_pixmap_file(FL_OBJECT *obj, const char *file); void fl_set_pixmap_data(FL_OBJECT *obj, char **data); In the first routine, you specify the pixmap by the filename `file' that contains it. In the second routine, you `#include' the pixmap at compile time and use the pixmap data (an array of `char' pointers) directly. 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 by calling void fl_free_pixmap_pixmap(FL_OBJECT *obj); on the pixmap object prior to calling these two routines. This function, in addition to freeing the pixmap and the mask, also frees the colors the pixmap allocated. To obtain the pixmap ID currently being displayed, the following routine can be used Pixmap fl_get_pixmap_pixmap(FL_OBJECT *obj, Pixmap *id, Pixmap *mask); In some situations, you might already have a pixmap resource ID, e.g., from `*note fl_read_pixmapfile()::' (see below in the "Remarks" subsection). Then you can use the following routine to change the the pixmap void fl_set_pixmap_pixmap(FL_OBJECT *obj, Pixmap id, Pixmap mask); where `mask' is used for transparency (see `*note 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 function `*note fl_free_pixmap_pixmap()::'. 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 *obj, int align, int dx, int dy); where `align' is the same as that used for labels, *note Label Attributes and Fonts:: 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.  File: xforms.info, Node: Pixmap Attributes, Next: Pixmap Remarks, Prev: Other Pixmap Routines, Up: Pixmap Object 15.6.5 Pixmap 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 the 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. To change these defaults, use the following routine void fl_set_pixmap_colorcloseness(int red, int green, int blue);  File: xforms.info, Node: Pixmap Remarks, Prev: Pixmap Attributes, Up: Pixmap Object 15.6.6 Remarks -------------- The following routines may be handy for reading 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, returned by a call of `*note fl_default_window()::'. Parameter `shape_mask' is a pointer to an already existing `Pixmap', which, if not `NULL', is used as a clipping 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 not used. If you already have the pixmap data in memory, the following routine can 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 for `fl_read_pixmapfile'. Note that the Forms Library handles transparency, if specified in the pixmap file or data, for pixmap and pixmapbutton objects. However, when using `*note fl_read_pixmapfile()::' or `*note fl_create_from_pixmapdata()::', the application programmer is responsible to set the clip mask in an appropriate GC. 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)m developed by Arnaud Le Hors and Groupe Bull, to use pixmaps. The XPM library is avalialble as a package for most distributions, but can also be obtained from many X mirror sites, e.g., via anonymous FTP from (`ftp://ftp.x.org/contrib/libraries/'. Its home page is `http://old.koalateam.com/lehors/xpm.html'.  File: xforms.info, Node: Clock Object, Next: Chart Object, Prev: Pixmap Object, Up: Part III Static Objects 15.7 Clock Object ================= A clock object simply displays a clock on the form * Menu: * Adding Clock Objects: Adding Clock Objects * Clock Types: Clock Types * Clock Interaction: Clock Interaction * Other Clock Routines: Other Clock Routines * Clock Attributes: Clock Attributes * Remarks: Clock Remarks  File: xforms.info, Node: Adding Clock Objects, Next: Clock Types, Up: Clock Object 15.7.1 Adding Clock Objects --------------------------- 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 placed below the clock by default.  File: xforms.info, Node: Clock Types, Next: Clock Interaction, Prev: Adding Clock Objects, Up: Clock Object 15.7.2 Clock Types ------------------ The following types are available: `FL_ANALOG_CLOCK' An analog clock complete with the second hand. `FL_DIGITAL_CLOCK' A digital clock.  File: xforms.info, Node: Clock Interaction, Next: Other Clock Routines, Prev: Clock Types, Up: Clock Object 15.7.3 Clock Interaction ------------------------ No interaction takes place with clocks.  File: xforms.info, Node: Other Clock Routines, Next: Clock Attributes, Prev: Clock Interaction, Up: Clock Object 15.7.4 Other Clock Routines --------------------------- To get the displayed time (local time as modified by the adjustment described below) use the following routine void fl_get_clock(FL_OBJECT *obj, int *h, int *m, int *s); Upon function return the parameters are set as follows: `h' is between 0-23, indicating the hour, `m' is between 0-59, indicating the minutes, and `s' is between 0-59, indicating the seconds. To display a time other than the local time, use the following routine long fl_set_clock_adjustment(FL_OBJECT *obj, long adj); where `adj' is in seconds. For example, to display a time that is one hour behind the local time, an adjustment of `3600' can be used. The function returns the old adjustment value. By default, the digital clock uses 24hr system. You can switch the display to 12hr system (am-pm) by using the following routine void fl_set_clock_ampm(FL_OBJECT *obj, int yes_no)  File: xforms.info, Node: Clock Attributes, Next: Clock Remarks, Prev: Other Clock Routines, Up: Clock Object 15.7.5 Clock Attributes ----------------------- Never use `FL_NO_BOX' as the boxtype for a digital clock. The first color argument (`col1') of `*note fl_set_object_color()::' controls the color of the background, the second (`col2') is the color of the hands.  File: xforms.info, Node: Clock Remarks, Prev: Clock Attributes, Up: Clock Object 15.7.6 Remarks -------------- See `flclock.c' for an example of the use of clocks. *Note Misc. Functions::, for other time related routines.  File: xforms.info, Node: Chart Object, Prev: Clock Object, Up: Part III Static Objects 15.8 Chart Object ================= 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 processes. * Menu: * Adding Chart Objects: Adding Chart Objects * Chart Types: Chart Types * Chart Interaction: Chart Interaction * Other Chart Routines: Other Chart Routines * Chart Attributes: Chart Attributes * Remarks: Chart Remarks  File: xforms.info, Node: Adding Chart Objects, Next: Chart Types, Up: Chart Object 15.8.1 Adding Chart Objects --------------------------- 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.  File: xforms.info, Node: Chart Types, Next: Chart Interaction, Prev: Adding Chart Objects, Up: Chart Object 15.8.2 Chart 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 the 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 then or equal to 0. The maximum number of values displayed in the chart can be set using the routine `*note fl_set_chart_maxnumb()::'. The argument must be not larger than `FL_CHART_MAX' which currently is 512. Switching between different types can be done without any complications.  File: xforms.info, Node: Chart Interaction, Next: Other Chart Routines, Prev: Chart Types, Up: Chart Object 15.8.3 Chart Interaction ------------------------ No interaction takes place with charts.  File: xforms.info, Node: Other Chart Routines, Next: Chart Attributes, Prev: Chart Interaction, Up: Chart Object 15.8.4 Other Chart 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, FL_COLOR 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 into 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 calls of `*note fl_freeze_form()::' and `*note fl_unfreeze_form()::'. By default, the label is drawn in a tiny font in black. You can change the font style, size or color using the following routine void fl_set_chart_lstyle(FL_OBJECT *obj, int fontstyle); void fl_set_chart_lsize(FL_OBJECT *obj, int fontsize); void fl_set_chart_lcolor(FL_OBJECT *obj, FL_COLOR color); Note that `*note 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, FL_COLOR 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, FL_COLOR 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 call it with both `min' and `max' being set to `0.0'. To obtain the current bounds, use the following routine void fl_get_chart_bounds(FL_OBJECT *obj, double *min, double *max)' 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' being set to false (0). In this case the width of the bars will be such that the maximum number of items fits in the box. This maximal number (defaults to `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, which may not be larger than `FL_CHART_MAX'.  File: xforms.info, Node: Chart Attributes, Next: Chart Remarks, Prev: Other Chart Routines, Up: Chart Object 15.8.5 Chart Attributes ----------------------- Don't use boxtype `FL_NO_BOX' for a chart object if it changes value. Normally, for bar and line chart a baseline is drawn at 0. This can be switched on and off by the function void fl_set_chart_baseline(FL_OBJECT *ob, int yes_no); The first color argument (`col1') to `*note fl_set_object_color()::' controls the (background) color of the box, the second (`col2') the color of the baseline.  File: xforms.info, Node: Chart Remarks, Prev: Chart Attributes, Up: Chart Object 15.8.6 Remarks -------------- See `chartall.c' and `chartstrip.c' for examples of the use of chart objects.  File: xforms.info, Node: Part III Button-like Objects, Next: Part III Valuator Objects, Prev: Part III Static Objects, Up: Top 16 Button-like Objects ********************** A very important set of object classes are those for buttons. Buttons are placed on the form such that the user can push them with the mouse. The different button classes mostly are distinguished by the way they are displayed. Differences in behaviour can be achieved by using different types for a button: there exist button types that make them return to their normal state when the user releases the mouse, types for buttons that stay pushed until the user pushes them again, a radio button type for buttons that are grouped with other radio buttons and of which only one can be in the on state at a time and a touch button type for buttons that "fire" repeatedly while being pressed. [image src="xforms_images/buttontypes.png"] 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 these buttons switches the light on. Round buttons are simple circles and, when pushed, a colored circle appears inside of them. Bitmap and pixmap buttons are buttons with an image in addition to a text label. * Menu: * Adding Button Objects: Adding Button Objects * Button Types: Button Types * Button Interaction: Button Interaction * Other Button Routines: Other Button Routines * Button Attributes: Button Attributes * Remarks: Button Remarks  File: xforms.info, Node: Adding Button Objects, Next: Button Types, Up: Part III Button-like Objects 16.1 Adding Button Objects ========================== 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); FL_OBJECT *fl_add_labelbutton(int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label); FL_OBJECT *fl_add_scrollbutton(int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label); These finctions create buttons of the following classes: `FL_BUTTON' A standard normal button. `FL_LIGHTBUTTON' A button with a small embedded, colored area that changes color when the button is in the on state. `FL_ROUNDBUTTON' A circular button (with a label beside). The inner area of the circle changes color when the button is on. Often used for radio buttons. `FL_ROUND3DBUTTON' Just like the `*note FL_ROUNDBUTTON::' but the circle is dran in a 3D-fashion. `FL_CHECKBUTTON' Button shaped in the form of a rhombus slightly raised above the forms plane when off and slightly embossed (ypically with a different color) when on. `FL_BITMAPBUTTON' Button decorated with a bitmap (often read in from an X bitmap file with extension `xbm') in additional to a label. `FL_PIXMAPBUTTON' Button decorated with a pixmap (often read in from an X pixmap file with extension `xpm') in additional to a label. An additonal pixmap can be set for the case that the mouse hoovers over the button. `FL_LABELBUTTON' A button that does not appear to be a button, only its label is shown, can be used e.g., for hyperlinks. `FL_SCROLLBARBUTTON' A button mostly used at the ends of scrollbars - instead of a label it can only contain a triangle pointing up, down, left or right. 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. For scrollbutton, the label must be of some pre-determined string that indicates the direction of the scroll arrow.