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

# 28. Drawing Objects

## 28.1 General Remarks

An important aspect of a new object class (or a free object) is how to draw it. As indicated above this should happen when the event `FL_DRAW` is received by the object. The place and size, i.e., the bounding box, of the object are indicated by the object tructure fields `obj->x`, `obj->y`, `obj->w` and `obj->h`. Forms are drawn in the Forms Library default visual or the user requested visual, which could be any of the X supported visuals. Hence, preferably your classes should run well in all visuals. The Forms Library tries to hide as much as possible the information about graphics mode and, in general, using the built-in drawing routines is the best approach. Here are some details about graphics state in case such information is needed.

All state information is kept in a global structure of type `FL_State` and there is a total of six such structures, `fl_state[6]`, each for every visual class.

The structure contains among others the following members:

`XVisualInfo *xvinfo`

  Many properties of the current visual can be obtained from this member.

`int depth`

  The depth of the visual. Same as what you get from `xvinfo`.

`int vclass`

  The visual class, `PseudoColor`, `TrueColor` etc.

`Colormap colormap`

  Current active colormap valid for the current visual for the entire Forms Library (except `FL_CANVAS`). You can allocate colors from this colormap, but you should never free it.

`Window trailblazer`

  This is a valid window resource ID created in the current visual with the colormap mentioned above. This member is useful if you have to call, before the form becomes active (thus does not have a window ID), some Xlib routines that require a valid window. A macro, `fl_default_window()`, is defined to return this member and use of the macro is encouraged.

`GC gc[16]`

  A total of 16 GCs appropriate for the current visual and depth. The first (`gc[0]`) is the default `GC` used by many internal routines and should be modified with care. It is a good idea to use only the top 8 `GC`s (8-15) for your free object so that future Forms Library extensions won't interfere with your program. Since many internal drawing routines use the Forms Library's default `GC` (`gc[0]`), it can change anytime whenever drawing occurs. Therefore, if you are using this GC for some of your own drawing routines make sure to always set the proper value before using it.

The currently active visual class (`TrueColor`, `PseudoColor` etc.) can be obtained by the following function/macro:

    int fl_get_form_vclass(FL_FORM *form);
    int fl_get_vclass(void);

The value returned can be used as an index into the array `fl_state` of `FL_State` structures. Note that `fl_get_vclass()` should only be used within a class/new object module where there can be no confusion what the "current" form is.

Other information about the graphics mode can be obtained by using visual class as an index into the `fl_state` structure array. For example, to print the current visual depth, code similar to the following can be used:

    int vmode = fl_get_vclass();
    printf("depth: %d\n", fl_state[vmode].depth);

Note that `fl_state[]` for indices other than the currently active visual class might not be valid. In almost all Xlib calls, the connection to the X server and current window ID are needed. The Forms Library comes with some utility functions/macros to facilitate easy utilization of Xlib calls. Since the current version of Forms Library only maintains a single connection, the global variable `fl_display` can be used where required. However, it is recommended that you use `fl_get_display()` or `FL_FormDisplay(Form *form)` instead since the function/macro version has the advantage that your program will remain compatible with future (possibly multi-connection) versions of the Forms Library.

There are a couple of ways to find out the "current" window ID, defined as the window ID the object receiving dispatcher's messages like `FL_DRAW` etc. belongs to. If the object's address is available, `FL_ObjWin(obj)` will suffice. Otherwise the function `fl_winget()` (see below) can be used.

There are other routines that might be useful:

    FL_FORM *fl_win_to_form(Window win);

This function takes a window ID win and returns the form the window belongs to or `None` on failure.

## 28.2 Color Handling

As mentioned earlier, Forms Library keeps an internal colormap, initialized to predefined colors. The predefined colors do not correspond to pixel values the server understands but are indexes into the colormap. Therefore, they can't be used in any of the `GC` altering or Xlib routines. To get the actual pixel value the X server understands, use the following routine

    unsigned long fl_get_pixel(FL_COLOR col);

To e.g., get the pixel value of the red color, use

    unsigned long red_pixel;
    red_pixel = fl_get_pixel(FL_RED);

To change the foreground color in the Forms Library's default `GC` (`gc[0]`) use

    void fl_color(FL_COLOR col);

To set the background color in the default `GC` use instead

    void fl_bk_color(FL_COLOR col);

To set foreground or background in `GC`s other than the Forms Library's default, the following functions exist:

    void fl_set_foreground(GC gc, FL_COLOR col);
    void fl_set_background(GC gc, FL_COLOR col);

which is equivalent to the following Xlib calls

    XSetForeground(fl_get_display(), gc, fl_get_pixel(color));
    XSetBackground(fl_get_display(), gc, fl_get_pixel(color));

To free allocated colors from the default colormap, use the following routine

    void fl_free_colors(FL_COLOR *cols, int n);

This function frees the `n` colors stored in the array of colormap indices `cols`. You shouldn't do that for the reserved colors, i.e., colors with indices below `FL_FREE_COL1`.

In case the pixel values (instead of the index into the colormap) are known, the following routine can be used to free the colors from the default colormap

    void fl_free_pixels(unsigned long *pixels, int n);

Note that the internal colormap maintained by the Forms Library is not updated. This is in general harmless.

To modify or query the internal colormap, use the following routines:

    unsigned long fl_mapcolor(FL_COLOR col, int red, int green, int blue)
    long fl_mapcolorname(FL_COLOR col, const char *name);
    unsigned long fl_getmcolor(FL_COLOR col,
                               int *red, int *green, int *blue);

The first function, `fl_mapcolor()` sets a the color indexed by `color` to the color given by the `red`, `green` and `blue`, returning the colors pixel value.

The second function, `fl_mapcolorname()`, sets the color in the colormap indexed by `color` to the color named `name`, where `name` must be a valid name from the system's color database file ``rgb.txt`'. It also returns the colors pixel value or -1 on failure.

The last function, `fl_getmcolor()`, returns the RGB values of the color indexed by `color` in the second to third argument pointers and the pixel value as the return value (or -1, cast to `unsigned long`, on failure).

## 28.3 Mouse Handling

The coordinate system used corresponds directly to that of the screen. But object coordinates are relative to the upper-left corner of the form the object belongs to.

To obtain the position of the mouse relative to a certain form or window, use the routines

    Window fl_get_form_mouse(FL_FORM *form, FL_Coord *x, FL_Coord *y,
                             unsigned *keymask)
    Window fl_get_win_mouse(Window win, FL_Coord *x, FL_Coord *y,
                            unsigned *keymask);

The functions return the ID of the window the mouse is in. Upon return `x` and `y` are set to the mouse position relative to the form or window and `keymask` contains information on modifier keys (same as the the corresponding `XQueryPointer()` argument).

A similar routine exists that can be used to obtain the mouse location relative to the root window

    Window fl_get_mouse(FL_Coord *x, FL_Coord *y, unsigned *keymask);

The function returns the ID of the window the mouse is in.

To move the mouse to a specific location relative to the root window, use the following routine

    void fl_set_mouse(FL_Coord x, FL_Coord y);

Use this function sparingly, it can be extremely annoying for the user if the mouse position is changed by a program.

## 28.4 Clipping

To avoid drawing outside a box the following routine exists:

    void fl_set_clipping(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h);

It sets a clipping region in the Forms Library's default `GC` used for drawing (but not for output of text, see below). `x`, `y`, `w` and `h` define the area drawing is to restrict to and are relative to the window/form that will be drawn to. In this way you can prevent drawing over other objects.

Under some circumstances XForms also does it's own clipping, i.e., while drawing due to a exposure event. This is called "global clipping". Thus the clipping area you have set via a call of `fl_set_clipping()` may get restricted even further due this global clipping.

You can check if there's clipping set for the default `GC` using the function

    int fl_is_clipped(int include_global);

which returns `1` if clipping is switched on and `0` otherwise. The `include_global` argument tells the function if global clipping is to be included in the answer or not (i.e., if the argument is `0` only clipping set via `fl_set_clipping()` is reported).

The area currently clipped to is returned by the function

    int fl_get_clipping(int include_global, FL_Coord *x,FL_Coord *y,
                            FL_Coord *width, FL_Coord *height);

On return the four pointer arguments are set to the position and size of the clipping rectangle (at least if clipping is switched on) and the qreturn value of this function is the same as that of `fl_is_clipped()`. The `include_global` argument has the same meaning as for `fl_is_clipped()`, i.e., it controls if the effects of global clipping is included in the results.

When finished with drawing always use

    void fl_unset_clipping(void);

to switch clipping of again.

You also can check and obtain the current settings for global clipping using the functions

    int fl_is_global_clipped(void);
    int fl_get_global_clipping(FL_Coord *x,FL_Coord *y,
                               FL_Coord *width, FL_Coord *height);

Clipping for text is controlled via a different `GC` and thus needs to be set, tested for and unset using a different set of functions:

    void fl_set_text_clipping(FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h);
    int fl_is_text_clipped(int include_global);
    int fl_get_text_clipping(int include_global, FL_Coord *x,FL_Coord *y,
                             FL_Coord *width, FL_Coord *height);
    void fl_unset_text_clipping(void);

Finally, there are functions to set and unset the clipping for a specific `GC`:

    void fl_set_gc_clipping(GC gc, FL_Coord x, FL_Coord y,
                            FL_Coord width, FL_Coord height);
    void fl_unset_gc_clipping(GC gc);

Please note that setting clipping for a `GC` will always further restrict the region to the region of global clipping (if it is on at the moment the function is called) and unsetting clipping will still retain global clipping if this is on at the moment the second function is invoked (if it is currently on can be checked using the `fl_is_global_clipped()`).

## 28.5 Getting the Size

To obtain the bounding box of an object with the label taken into account (in contrast to the result of the `fl_get_object_geometry() function which doesn't include a label that isn't inside the object` the following routine exists:

    void fl_get_object_bbox(FL_OBJECT *obj, FL_Coord *x, FL_Coord *y,
                            FL_Coord *w, FL_Coord *h);

For drawing text at the correct places you will need some information about the sizes of characters and strings. The following routines are provided:

    int fl_get_char_height(int style, int size, int *ascent, int *descent)
    int fl_get_char_width(int style, int size);

These two routines return the maximum height and width of the font used, where `size` indicates the point size for the font and `style` is the style in which the text is to be drawn. The first function, `fl_get_char_height()`, also returns the height above and below the baseline of the font via the `ascent` and `descent` arguments (if they aren't `NULL` pointers). A list of valid styles can be found in Section 3.11.3.

To obtain the width and height information for a specific string use the following routines:

    int fl_get_string_width(int style, int size, const char *str,
                            int len);
    int fl_get_string_height(int style, int size, const char *str,
                             int len, int *ascent, int *descent);

where `len` is the length of the string `str`. The functions return the width and height of the string, respectively. The second function also returns the height above and below the fonts baseline if `ascent` and `descent` aren't `NULL` pointers. Note that the string may not contain newline characters `'\n'` and that the height calculated from the ascent and descent of those characters in the string that extend the most above and below the fonts baseline. It thus may not be suitable for calculating line spacings, for that use the `fl_get_char_height()` or `fl_get_string_dimension()` function.

There exists also a routine that returns the width and height of a string in one call. In addition, the string passed can contain embedded newline characters `'\n'` and the routine will make proper adjustment so the values returned are large enough to contain the multiple lines of text. The height of each of the lines is the fonts height.

    void fl_get_string_dimension(int style, int size, const char *str,
                                 int len, int *width, int *height);

## 28.6 Font Handling

Sometimes it can be useful to get the X font structure for a particular size and style as used in the Forms Library. For this purpose, the following routine exists:

    [const] XFontStruct *fl_get_fontstruct(int style, int size);

The structure returned can be used in, say, setting the font in a particular `GC`:

    XFontStruct *xfs = fl_get_fontstruct(FL_TIMESBOLD_STYLE, FL_HUGE_SIZE);
    XSetFont(fl_get_display(), mygc, xfs->fid);

The caller is not allowed to free the structure returned by `fl_get_fontstruct()`, it's just a pointer to an internal structure!

## 28.7 Drawing Functions

There are a number of routines that help you draw objects on the screen. All XForms's internal drawing routine draws into the "current window", defined as the window the object that uses the drawing routine belongs to. If that's not what you need, the following routines can be used to set or query the current window:

    void fl_winset(Window win);
    Window fl_winget(void);

One caveat about `fl_winget()` is that it can return `None` if called outside of an object's event handler, depending on where the mouse is. Thus, the return value of this function should be checked when called outside of an object's event handler.

It is important to remember that unless the following drawing commands are issued while handling the `FL_DRAW` or `FL_DRAWLABEL` event (which is not generally recommended), it is the application's responsibility to set the proper drawable using `fl_winset()`.

The most basic drawing routines are for drawing rectangles:

    void fl_rectf(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
                  FL_COLOR col);
    void fl_rect(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
                 FL_COLOR col);

Both functions draw a rectangle on the screen in color `col`. While `fl_rectf()` draws a filled rectangle, `fl_rect()` just draws the outline in the given color.

To draw a filled (with color `col`) rectangle with a black border use

    void fl_rectbound(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
                      FL_COLOR col);

To draw a rectangle with rounded corners (filled or just the outlined) employ

    void fl_roundrectf(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
                       FL_COLOR col);
    void fl_roundrect(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
                      FL_COLOR col);

To draw a general polygon, use one of the following routines

    typedef struct {
        short x,
              y;
    } FL_POINT;

    void fl_polyf(FL_POINT *xpoint, int n, FL_COLOR col);
    void fl_polyl(FL_POINT *xpoint, int n, FL_COLOR col);
    void fl_polybound(FL_POINT *xpoint, int n, FL_COLOR col);

`fl_polyf()` draws a filled polygon defined by `n` points, `fl_polyl()` the ouline of a polygon and `fl_polybound()` a filled polygon with a black outline.

Note: all polygon routines require that the array `xpoint` has spaces for `n+1` points, i.e., one more than then number of points you intend to draw!

To draw an ellipse. either filled, open (with the outline drawn in the given color), or filled with a black border the following routines can be used (use `w` equal to `h` to get a circle):

    void fl_ovalf(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
                  FL_COLOR col);
    void fl_ovall(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
                  FL_COLOR col);
    void fl_ovalbound(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
                      FL_COLOR col);

The `x` and `y` arguments are the upper left hand corner of the ellipse, while `w` and `h` are its width and height.

Note: `fl_ovall()` (with two 'l') isn't a typo, the trailing 'l' it's meant indicate that only a line will be drawn. And there's also the function

    void fl_ovalf(int fill, FL_Coord x, FL_Coord y, FL_Coord w,
                  FL_Coord h, FL_COLOR col);

which is invoked by both (the macros) `fl_ovalf()` and `fl_ovall()` with the first argument `fill` set to either `1` or `0`.

To simplify drawing circles there are three additional functions. The first one draws an (open) circle (with the circumfence in the given color), the second one a filled circle, and the last one a filled circle with a black circumfence:

    void fl_circ(FL_Coord x, FL_Coord y, FL_Coord r, FL_COLOR col);
    void fl_circf(FL_Coord x, FL_Coord y, FL_Coord r, FL_COLOR col);
    void fl_circbound(FL_Coord x, FL_Coord y, FL_Coord r, FL_COLOR col);

Here `x` and `y` are the coordinates of the center of the circle, `r` is its radius and `col` the color to be used.

To draw circular arcs, either open or filled, the following routines can be used

    void fl_arc(FL_Coord x, FL_Coord y, FL_Coord radius,
                int start_theta, int end_theta, FL_COLOR col);
    void fl_arcf(FL_Coord x, FL_Coord y, FL_Coord radius,
                 int start_theta, int end_theta, FL_COLOR col);

`x` and `y` are the coordinates of the center and `r` is the radius. `start_theta` and `end_theta` are the starting and ending angles of the arc in units of tenths of a degree (where 0 stands for a direction of 3 o'clock, i.e., the right-most point of a circle), and `x` and `y` are the center of the arc. If the difference between `theta_end` and `theta_start` is larger than 3600 (360 degrees), drawing is truncated to 360 degrees.

To draw elliptical arcs the following routine can be used:

    void fl_pieslice(int fill, FL_Coord x, FL_Coord y, FL_Coord w,
                     FL_Coord h, int start_theta, int end_theta,
                     FL_COLOR col);

`x` and `y` are the upper left hand corner of the box enclosing the ellipse that the pieslice is part of and `w` and `h` the width and height of that box. `start_theta` and `end_theta`, to be given in tenth of a degree, specify the starting and ending angles measured from zero degrees (3 o'clock).

Depending on circumstance, elliptical arc may be more easily drawn using the following routine

    void fl_ovalarc(int fill, FL_Coord x, FL_Coord y, FL_Coord w,
                    FL_Coord h, int theta, int dtheta, FL_COLOR col);

Here `theta` specifies the starting angle (again measured in tenth of a degree and with 0 at the 3 o'clock position), and `dtheta` specifies both the direction and extent of the arc. If `dtheta` is positive the arc is drawn in counter-clockwise direction from the starting point defined by `theta`, otherwise in clockwise direction. If `dtheta` is larger than 3600 it is truncated to 3600.

To connect two points with a straight line, use

    void fl_line(FL_Coord x1, FL_Coord y1,
                 FL_Coord x2, FL_Coord y2, FL_COLOR col);

There is also a macro for drawing a line along the diagonal of a box (to draw a horizontal line set `h` to 1, not to 0):

    void fl_diagline(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
                     FL_COLOR col);

To draw connected line segments between `n` points use

    void fl_lines(FL_POINT *points, int n, FL_COLOR col);

All coordinates in points are relative to the origin of the drawable.

There are also routines to draw one or more pixels

    void fl_point(FL_Coord x, FL_Coord y, FL_COLOR col);
    void fl_points(FL_POINT *p, int np, FL_COLOR col);

As usual, all coordinates are relative to the origin of the drawable. Note that these routines are meant for you to draw a few pixels, not images consisting of tens of thousands of pixels of varying colors. For that kind of drawing `XPutImage(3)` should be used. Or better yet, use the image support in the Forms Library (see Images). Also it's usually better when drawing multiple points to use fl_points(), even if that means that the application program has to pre-sort and group the pixels of the same color.

To change the line width or style, the following convenience functions are available

    void fl_linewidth(int lw);
    void fl_linestyle(int style);

Set `lw` to 0 to reset the line width to the servers default. Line styles can take on the following values (also see `XChangeGC(3)`)

`FL SOLID`

  Solid line. Default and most efficient.

`FL DOT`

  Dotted line.

`FL DASH`

  Dashed line.

`FL DOTDASH`

  Dash-dot-dash line.

`FL LONGDASH`

  Long dashed line.

`FL USERDASH`

  Dashed line, but the dash pattern is user definable via `fl_dashedlinestyle()`. Only the odd numbered segments are drawn with the foreground color.

`FL USERDOUBLEDASH`

  Similar to `FL_LINE_USERDASH` but both even and odd numbered segments are drawn, with the even numbered segments drawn in the background color (as set by `fl_bk_color()`).

The following routine can be used to change the dash pattern for `FL_USERDASH` and `FL USERDOUBLEDASH`:

    void fl_dashedlinestyle(const char *dash, int ndashes)

Each element of the array `dash` is the length of a segment of the pattern in pixels (0 is not allowed). Dashed lines are drawn as alternating segments, each with the length of an element in `dash`. Thus the overall length of the dash pattern, in pixels, is the sum of all elements of `dash`. When the pattern is used up but the line to draw is longer it used from the start again. The following example code specifies a long dash (9 pixels) to come first, then a skip (3 pixels), a short dash (2 pixels) and then again a skip (3 pixels). After this sequence, the pattern repeats.

    char ldash_sdash[] = {9, 3, 2, 3};
    fl_dashedlinestyle(ldash_sdash, 4);

If `dash` is `NULL` or `ndashes` is `0` (or the `dash` array contains an element set to `0`) a default pattern of 4 pixels on and 4 fixels off is set.

It is important to remember to call `fl_dashedlinestyle()` whenever `FL_USERDASH` is used to set the dash pattern, otherwise whatever the last pattern was will be used. To use the default dash pattern you can pass `NULL` as the dash parameter to `fl_dashedlinestyle()`.

By default, all lines are drawn so they overwrite the destination pixel values. It is possible to change the drawing mode so the destination pixel values play a role in the final pixel value.

    void fl_drawmode(int mode);

There are 16 different possible settings for `mode` (see a Xlib programming manual for all the gory details). A of the more useful ones are

`GXcopy`

  Default overwrite mode. Final pixel value = Src

`GXxor`

  Bitwise XOR (exclusive-or) of the pixel value to be drawn with the pixel value already on the screen. Useful for rubber-banding.

`GXand`

  Bitwise AND of the pixel value to be drawn with the pixel value already on the screen.

`GXor`

  Bitwise OR of the pixel value to be drawn with the pixel value already on the screen.

`GXinvert`

  Just invert the pixel values already on the screen.

To obtain the current settings of the line drawing attributes use the following routines

    int fl_get_linewidth(void);
    int fl_get_linestyle(void);
    int fl_get_drawmode(void);

There are also a number of high-level drawing routines available. To draw boxes the following routine exists. Almost any object class will use it to draw the bounding box of the object.

    void fl_draw_box(int style, FL_Coord x, FL_Coord y,
                     FL_Coord w, FL_Coord h,
                     FL_COLOR col, int bw);

`style` is the type of the box, e.g., `FL_DOWN_BOX`. `x`, `y`, `w`, and `h` indicate the size of the box. `col` is the color and `bw` is the width of the boundary, which typically should be given the value `obj->bw` or `FL_BOUND_WIDTH`. Note that a negative border width indicates a "softer" up box. See the demo program ``borderwidth.c`' for the visual effect of different border widths.

There is also a routine for drawing a frame:

    void fl_draw_frame(int style, FL_Coord x, FL_Coord y,
                       FL_Coord w, FL_Coord h, FL_COLOR col, int bw)

All parameters have the usual meaning except that the frame is drawn outside of the bounding box specified.

For drawing text there are two routines:

    void fl_draw_text(int align, FL_Coord x, FL_Coord y, FL_Coord w,
                      FL_Coord h, FL_COLOR col, int style, int size,
                      const char *str);
    void fl_draw_text_beside(int align, FL_Coord x, FL_Coord y,
                             FL_Coord w, FL_Coord h, FL_COLOR col,
                             int style, int size, const char *str);

where `align` is the alignment, namely, `FL ALIGN LEFT`, `FL ALIGN CENTER` etc. `x`, `y`, `w` and `h` indicate the bounding box, `col` is the color of the text, `size` is the size of the font to use (in points) and `style` is the font style to be used (see Label Attributes and Fonts, for valid styles). Finally, `str` is the string itself, possibly containing embedded newline characters.

`fl_draw_text()` draws the text inside the bounding box according to the alignment requested while `fl_draw_text_beside()` draws the text aligned outside of the box. These two routines interpret a text string starting with the character `@` differently in drawing some symbols instead. Note that `fl_draw_text()` puts a padding of 5 pixels in vertical direction and 4 in horizontal around the text. Thus the bounding box should be 10 pixels wider and 8 pixels higher than required for the text to be drawn.

The following routine can also be used to draw text and, in addition, a cursor can optionally be drawn

    void fl_draw_text_cursor(int align, FL_Coord x, FL_Coord y,
                             FL_Coord w, FL_Coord h, FL_COLOR col,
                             int style, int size, char *str,
                             FL_COLOR ccol, int pos);

where `ccol` is the color of the cursor and `pos` is its position which indicates the index of the character in `str` before which to draw the cursor (-1 means show no cursor). This routine does no interpretion of the special character `@` nor does it add padding around the text.

Given a bounding box and the size of an object (e.g., a label) to draw, the following routine can be used to obtain the position of where to draw it with a certain alignment and including padding:

    void fl_get_align_xy(int align, int x, int y, int w, int h,
                         int obj_xsize, int obj_ysize,
                         int xmargin, int ymargin,
                         int *xpos, int *ypos);

This routine works regardless if the object is to be drawn inside or outside of the bounding box specified by `x`, `y`, `w` and `h`. `obj_xsize` and `obj->ysize` are the width and height of the object to be drawn and `xmargin` and `ymargin` is the additional padding to use. `xpos` and `ypos` return the position to be used for drawing the object.

For drawing object labels the following routines might be more convenient:

    void fl_draw_object_label(FL_OBJECT *obj)
    void fl_draw_object_label_outside(FL_OBJECT *obj);

Both routines assume that the alignment is relative to the full bounding box of the object. The first routine draws the label according to the alignment, which could be inside or outside of the bounding box. The second routine will always draw the label outside of the bounding box.

An important aspect of (re)drawing an object is efficiency which can result in flicker and non-responsiveness if not handled with care. For simple objects like buttons or objects that do not have "movable parts", drawing efficiency is not a serious issue although you can never be too fast. For complex objects, especially those that a user can interactively change, special care should be taken.

The most important rule for efficient drawing is not to draw if you don't have to, regardless how simple the drawing is. Given the networking nature of X, simple or not depends not only on the host/server speed but also the connection. What this strategy entails is that the drawing should be broken into blocks and depending on the context, draw/update only those parts that need to.

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

This document was generated on January 5, 2026 using texi2html 1.82.