Part IV An Example (XForms (Forms Library) - Version 1.2 (Rev. 4) A Graphical User Interface Toolkit for X)

Next: Part IV New Buttons, Previous: Part IV Drawing Objects, Up: Top [Contents][Index]

## 29 An Example

Let us work through an example of how to create a simple object class named `colorbox`. Assume that we want a class with the following behavior: it should normally be red. When the user presses the mouse on it it should turn blue. When the user releases the mouse button the object should turn red again and be returned to the application program. Further, the class module should keep a total count how many times the box got pushed.

The first thing to do is to define some constants in a file named `colbox.h`. This file should at least contain the class number and one or more types:

    /* Class number must be between FL_USER_CLASS_START
        and FL_USER_CLASS_END */

    #define FL_COLBOX        (FL_USER_CLASS_START + 1)

    #define FL_NORMAL_COLBOX 0          /* The only type */

Note that the type must start from zero onward. Normally it should also contain some defaults for the boxtype and label alignment etc. The include file also has to declare all the functions available for this object class. I.e., it should contain:

    extern FL_OBJECT *fl_create_colbox(int, FL_Coord, FL_Coord, FL_Coord,
                                       FL_Coord, const char *);
    extern FL_OBJECT *fl_add_colbox(int, FL_Coord, FL_Coord, FL_Coord,
                                    FL_Coord, const char *);
    extern int fl_get_colorbox(FL_OBJECT *);

Now we have to write a module `colbox.c` that contains the different routines. First of all we need routines to create an object of the new type and to add it to the current form. We also need to have a counter that keeps track of number of times the colbox is pushed. They would look as follows:

    typedef struct {
        int counter;         /* no. of times pushed */
    } COLBOX_SPEC;

    FL_OBJECT *fl_create_colbox(int type, FL_Coord x, FL_Coord y,
                                FL_Coord w, FL_Coord h,
                                const char *label) {
        FL_OBJECT *obj;

        /* create a generic object class with an appropriate ID */
        obj = fl_make_object(FL_COLBOX, type, x, y, w, h, label,
                             handle_colbox);

        /* initialize some members */
        obj->col1 = FL_RED;
        obj->col2 = FL_BLUE;

        /* create class specific structures and initialize */
        obj->spec = fl_malloc(sizeof *obj->spec);
        obj->spec->counter = 0;
        return obj;
    }

    FL_OBJECT *fl_add_colbox(int type, FL_Coord x, FL_Coord y,
                             FL_Coord w, FL_Coord h, const char *label) {
        FL_OBJECT *obj = fl_create_colbox(type, x, y, w, h, label);
        fl_add_object(fl_current_form, obj);
        return obj;
    }

The fields `col1` and `col2` are used to store the two colors red and blue such that the user can change them when required with the routine `fl_set_object_color()`. What remains is to write the handling routine `handle_colbox()`. It has to react to three types of events: `FL_DRAW`, `FL_PUSH` and `FL_RELEASE`. Also, when the box is pushed, the counter should be incremented to keep a total count. Note that whether or not the mouse is pushed on the object is indicated in the field `obj->pushed`. Hence, when pushing and releasing the mouse the only thing that needs to be done is redrawing the object. This leads to the following piece of code:

    static int handle_colbox(FL_OBJECT *obj, int event,
                             FL_Coord mx, FL_Coord my,
                             int key, void *xev) {
        switch (event) {
            case FL_DRAW:              /* Draw box */
                fl_draw_box(obj->boxtype, obj->x,obj->y, obj->w, obj->h,
                            obj->pushed ? obj->col2 : obj->col1, obj->bw);
                /* fall through */

            case FL_DRAWLABEL:         /* Draw label */
                 fl_draw_object_label(obj);
                 break;

            case FL_PUSH:
                ((COLBOX_SPEC *) obj->spec)->counter++;
                fl_redraw_object(obj);
                break;

            case FL_RELEASE:
                fl_redraw_object(obj);
                return 1;             /* report back to application! */

             case FL_FREEMEM:
                 fl_free(obj->spec);
                 break;
        }

        return 0;
    }

That is the whole piece of code. Of course, since the `COLBOX_SPEC` structure is invisible outside of `colbox.c`, the following routine should be provided to return the total number of times the colbox was pushed:

    int fl_get_colbox(FL_OBJECT *obj) {
        if (!obj || obj->objclass != FL_COLBOX) {
            fprintf(stderr, "fl_get_colbox: Bad argument or wrong type);
            return -1;
        }

        return ((COLBOX_SPEC *) obj->spec)->counter;
    }

To use it, compile it into a file `colbox.o`. An application program that wants to use the new object class simply should include `colbox.h` and link with `colbox.o` when compiling the program. It can then use the routine `fl_add_colbox()` to add objects of the new type to a form.

Next: Part IV New Buttons, Previous: Part IV Drawing Objects, Up: Top [Contents][Index]