File: part4_drawing_objects.texi

package info (click to toggle)
libforms 1.0.93sp1-1
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 11,548 kB
  • ctags: 9,107
  • sloc: ansic: 97,227; sh: 9,236; makefile: 858
file content (846 lines) | stat: -rw-r--r-- 31,849 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
@node Part IV Drawing Objects
@chapter Drawing Objects

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
@code{FL_DRAW} is received by the object. The place, i.e.@: bounding
box, where the object has to be drawn is indicated by the fields
@code{obj->x}, @code{obj->y}, @code{obj->w} and @code{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
@tindex FL_State
@code{FL_State} and there is a total of six such structures,
@code{fl_state[6]}, each for every visual class.

The structure contains among others the following members:
@table @code
@item XVisualInfo *xvinfo
Many properties of the current visual can be obtained from this
member.
@item int depth
The depth of the visual. Same as what you get from @code{xvinfo}.
@item int vclass
The visual class, @code{PseudoColor}, @code{TrueColor} etc.
@item Colormap colormap
Current active colormap valid for the current visual for the entire
Forms Library (except @code{FL_CANVAS}). You can allocate colors from
this colormap, but you should never free it.
@item 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 don't have a window ID),
some Xlib routines that require a valid window. A macro,
@findex fl_default_window()
@anchor{fl_default_window()}
@code{fl_default_window()}, is defined to return this member and use
of the macro is encouraged.
@item GC gc[16 ]
A total of 16 GCs appropriate for the current visual and depth. The
first (@code{gc[0]}) is the default @code{GC} used by many internal
routines and should be modified with care. It is a good idea to use
only the top 8 @code{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 @code{GC}
(@code{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.
@end table

The currently active visual class (@code{TrueColor},
@code{PseudoColor} etc.) can be obtained by the following
function/macro:
@findex fl_get_form_vclass()
@anchor{fl_get_form_vclass()}
@findex fl_get_vclass()
@anchor{fl_get_vclass()}
@example
int fl_get_form_vclass(FL_FORM *form);
int fl_get_vclass(void);
@end example
@noindent
The value returned can be used as an index into the array
@code{fl_state} of @code{FL_State} structures. Note that
@code{@ref{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 @code{fl_state} structure array. For
example, to print the current visual depth, code similar to the
following can be used:
@example
int vmode = fl_get_vclass();
printf("depth: %d\n", fl_state[vmode].depth);
@end example
@noindent
Note that @code{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
@w{@code{Display *fl_display}} can be used where required. However, it
is recommended that you use
@findex fl_get_display()
@anchor{fl_get_display()}
@code{fl_get_display()} or
@findex FL_FormDisplay(form)
@anchor{FL_FormDisplay(form)}
@code{FL_FormDisplay(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 @code{FL_DRAW} etc.@: belongs to. If the object's address is
available, @code{FL_ObjWin(obj)} will suffice. Otherwise the function
@code{@ref{fl_winget()}} (see below) can be used.

There are other routines that might be useful:
@findex fl_win_to_form()
@anchor{fl_win_to_form()}
@example
FL_FORM *fl_win_to_form(Window win);
@end example
@noindent
This function takes a window ID win and returns the form the window
belongs to or @code{None} on failure.

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 @code{GC}
altering or Xlib routines. To get the actual pixel value the X server
understands, use the following routine
@findex fl_get_pixel()
@anchor{fl_get_pixel()}
@example
FL_COLOR fl_get_pixel(FL_COLOR color);
@end example
@noindent
To e.g.@: get the pixel value of the red color, use
@example
unsigned long red_pixel;
red_pixel = fl_get_pixel(FL_RED);
@end example

To change the foreground color in the Forms Library's default
@code{GC} (@code{gc[0]}) use
@findex fl_color()
@anchor{fl_color()}
@example
void fl_color(FL_COLOR col);
@end example

To set the background color in the default @code{GC} use instead
@findex fl_bk_color()
@anchor{fl_bk_color()}
@example
void fl_bk_color(FL_COLOR color);
@end example

To set foreground or background in @code{GC}s other than the Forms
Library's default, the following functions exist:
@findex fl_set_foreground()
@anchor{fl_set_foreground()}
@findex fl_set_background()
@anchor{fl_set_background()}
@example
void fl_set_foreground(GC gc, FL_COLOR color);
void fl_set_background(GC gc, FL_COLOR color);
@end example
@noindent
which is equivalent to the following Xlib calls
@example
XSetForeground(fl_get_display(), gc, fl_get_pixel(color));
XSetBackground(fl_get_display(), gc, fl_get_pixel(color));
@end example

To free allocated colors from the default colormap, use the following
routine
@findex fl_free_colors()
@anchor{fl_free_colors()}
@example
void fl_free_colors(FL_COLOR *cols, int n);
@end example
@noindent
This function frees the @code{n} colors stored in the array of
colormap indices @code{cols}. You shouldn't do that for the reserved
colors, i.e.@: colors with indices below @code{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
@findex fl_free_pixels()
@anchor{fl_free_pixels()}
@example
void fl_free_pixels(unsigned long *pixels, int n);
@end example
@noindent
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:
@findex fl_mapcolor()
@anchor{fl_mapcolor()}
@findex fl_mapcolorname()
@anchor{fl_mapcolorname()}
@findex fl_getmcolor()
@anchor{fl_getmcolor()}
@example
unsigned long fl_mapcolor(FL_COLOR color, int red, int green, int blue)
long fl_mapcolorname(FL_COLOR color, const char *name);
unsigned long fl_getmcolor(FL_COLOR color,
                           int *red, int *green, int *blue);
@end example
@noindent
The first function, @code{@ref{fl_mapcolor()}} sets a the color
indexed by @code{color} to the color given by the @code{red},
@code{green} and @code{blue}, returning the colors pixel value.

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

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


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
@findex fl_get_form_mouse()
@anchor{fl_get_form_mouse()}
@findex fl_get_win_mouse()
@anchor{fl_get_win_mouse()}
@example
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);
@end example
@noindent
The functions return the ID of the window the mouse is in. Upon return
@code{x} and @code{y} are set to the mouse position relative to the
form or window and @code{keymask} contains information on modifier
keys (same as the the corresponding @code{XQueryPointer()} argument).

A similar routine exists that can be used to obtain the mouse location
relative to the root window
@findex fl_get_mouse()
@anchor{fl_get_mouse()}
@example
Window fl_get_mouse(FL_Coord *x, FL_Coord *y, unsigned *keymask);
@end example
@noindent
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
@findex fl_set_mouse()
@anchor{fl_set_mouse()}
@example
void fl_set_mouse(FL_Coord x, FL_Coord y);
@end example
@noindent
Use this function sparingly, it can be extremely annoying for the user
if the mouse position is changed by a program.

To avoid drawing outside a box the following routine exists:
@findex fl_set_clipping()
@anchor{fl_set_clipping()}
@example
void fl_set_clipping(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h);
@end example
@noindent
It sets a clipping region in the Forms Library's default @code{GC}.
@code{x}, @code{y}, @code{w} and @code{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.

When finished with drawing always use
@findex fl_unset_clipping()
@anchor{fl_unset_clipping()}
@example
void fl_unset_clipping(void);
@end example
@noindent
to stop clipping.

Similar functions are available to set the clipping for a specific @code{GC}:
@findex fl_set_gc_clipping()
@anchor{fl_set_gc_clipping()}
@findex fl_unset_gc_clipping()
@anchor{fl_unset_gc_clipping()}
@example
void fl_set_gc_clipping(GC gc, FL_Coord x, FL_Coord y,
                        FL_Coord w, FL_Coord h);
void fl_unset_gc_clipping(GC gc);
@end example

To obtain the bounding box of an object with the dimension and
location of the label taken into account (compare with
@code{@ref{fl_get_object_geometry()}} the following routine exists:
@findex fl_get_object_bbox()
@example
void fl_get_object_bbox(FL_OBJECT *obj, FL_Coord *x, FL_Coord *y,
                        FL_Coord *w, FL_Coord *h);
@end example

To set clippings for text, which uses a different GC, the following
routine should be used
@findex fl_set_text_clipping()
@anchor{fl_set_text_clipping()}
@findex fl_set_untext_clipping()
@anchor{fl_set_untext_clipping()}
@example
void fl_set_text_clipping(FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h);
void wfl_unset_text_clipping(void);
@end example

For drawing text at the correct places you will need some information
about the sizes of characters and strings. The following routines are
provided:
@findex fl_get_char_height()
@anchor{fl_get_char_height()}
@findex fl_get_char_width()
@anchor{fl_get_char_width()}
@example
int fl_get_char_height(int style, int size, int *ascend, int *descend)
int fl_get_char_width(int style, int size);
@end example
@noindent
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,
@code{@ref{fl_get_char_height()}}, also returns the height above and
below the baseline of the font via the @code{ascend} and
@code{descend} arguments. A list of valid styles can be found in
Section 3.11.3.

To obtain the width and height information on a specific string, use
the following routines
@findex fl_get_string_width()
@anchor{fl_get_string_width()}
@findex fl_get_string_height()
@anchor{fl_get_string_height()}
@example
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 *ascend, int *descend);
@end example
where @code{len} is the length of the string @code{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.

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 @code{'\n'} and the routine will make
proper adjustment so the values returned are (just) large enough to
contain the multiple lines of text
@findex fl_get_string_dimension()
@anchor{fl_get_string_dimension()}
@example
void fl_get_string_dimension(int style, int size, const char *str,
                             int len, int *width, int *height);
@end example

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:
@findex fl_get_fontstruct()
@anchor{fl_get_fontstruct()}
@example
[const] XFontStruct *fl_get_fontstruct(int style, int size);
@end example
@noindent
The structure returned can be used in, say, setting the font in a
particular @code{GC}:
@example
XFontStruct *xfs = fl_get_fontstruct(FL_TIMESBOLD_STYLE, FL_HUGE_SIZE);
XSetFont(fl_get_display(), mygc, xfs->fid);
@end example
@noindent
The caller should not free the structure returned by
@code{@ref{fl_get_fontstruct()}}.

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:
@findex fl_winset()
@anchor{fl_winset()}
@findex fl_winget()
@anchor{fl_winget()}
@example
void fl_winset(Window win);
Window fl_winget(void);
@end example
@noindent
One caveat about @code{@ref{fl_winget()}} is that it can return
@code{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 handler.

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

The most basic drawing routines are for drawing rectangles:
@findex fl_rectf()
@anchor{fl_rectf()}
@findex fl_rect()
@anchor{fl_rect()}
@example
void fl_rectf(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
              FL_COLOR c);
void fl_rect(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
             FL_COLOR c);
@end example
@noindent
Both draw a rectangle on the screen in color @code{col}. The
difference is that @code{@ref{fl_rectf()}} draws a filled rectangle
while @code{@ref{fl_rect()}} just draws an outline.

To draw a filled rectangle with a black border use
@findex fl_rectbound()
@anchor{fl_rectbound()}
@example
void fl_rectbound(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
                  FL_COLOR c);
@end example

To draw a rectangle with rounded corners (filled or just the outline)
employ
@findex fl_roundrectf()
@anchor{fl_roundrectf()}
@findex fl_roundrect()
@anchor{fl_roundrect()}
@example
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);
@end example


To draw a general polygon, use one of the following routines
@tindex FL_POINT
@findex fl_polyf()
@anchor{fl_polyf()}
@findex fl_polyl()
@anchor{fl_polyl()}
@findex fl_polybound()
@anchor{fl_polybound()}
@example
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);
@end example
@noindent
@code{@ref{fl_polyf()}} draws a filled polygon defined by @code{n}
points, @code{@ref{fl_polyl()}} the ouline of a polygon and
@code{@ref{fl_polybound()}} a filled polygon with a black outline.
Note all polygon routines @strong{require} that the array
@code{xpoint} has to have enough spaces to hold @code{n+1} points!

To draw an ellipse. either filled or open, the following routines can
be used (use @code{w} equal to @code{h} to get a circle):
@findex fl_ovalf()
@anchor{fl_ovalf()}
@findex fl_ovall()
@anchor{fl_ovall()}
@findex fl_ovalbound()
@anchor{fl_ovalbound()}
@example
void fl_ovalf(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
              FL_COLOR c);
void fl_ovall(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
              FL_COLOR c);
void fl_ovalbound(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
                  FL_COLOR c);
@end example

To draw circular arcs, either open or filled, the following routines
can be used
@findex fl_arc()
@anchor{fl_arc()}
@findex fl_arcf()
@anchor{fl_arcf()}
@example
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);
@end example
where @code{start_theta} and @code{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 @code{x} and @code{y} are the center of the arc. If the
difference between @code{theta_end} and @code{theta_start} is larger
than 3600 (360 degrees), drawing is truncated to 360 degrees.

To draw elliptical arcs the following routine should be used:
@findex fl_pieslice()
@anchor{fl_pieslice()}
@example
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);
@end example
@noindent
The center of the arc is the center of the bounding box specified by
@code{x}, @code{y}, @code{w}, @code{h}, @code{w} and @code{h}
specifing the axes of the ellipse.. @code{start_theta} and
@code{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
@findex fl_ovalarc(
@anchor{fl_ovalarc(}
@example
void fl_ovalarc(int fill, FL_Coord x, FL_Coord y, FL_Coord w,
                FL_Coord h, int theta, int dtheta, FL_COLOR col);
@end example
@noindent
Here @code{theta} specifies the starting angle (again measured in
tenth of a degree and with 0 at the 3 o'clock position), and
@code{dtheta} specifies both the direction and extent of the arc. If
@code{dtheta} is positive the arc is drawn in counter-clockwise
direction from the starting point defined by @code{theta}, otherwise
in clockwise direction. If @code{dtheta} is larger than 3600 it is
truncated to 3600.

To connect two points with a straight line, use
@findex fl_line()
@anchor{fl_line()}
@example
void fl_line(FL_Coord x1, FL_Coord y1,
             FL_Coord x2, FL_Coord y2, FL_COLOR col);
@end example

There is also a routine to draw a line along the diagonal of a box (to
draw a horizontal line set @code{h} to 1, not to 0):
@findex fl_diagline()
@anchor{fl_diagline()}
@example
void fl_diagline(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
                 FL_COLOR col);
@end example

To draw connected line segments between @code{n} points use
@findex fl_lines()
@anchor{fl_lines()}
@example
void fl_lines(FL_POINT *points, int n, FL_COLOR col);
@end example
@noindent
All coordinates in points are relative to the origin of the drawable.

There are also routines to draw one or more pixels
@findex fl_point()
@anchor{fl_point()}
@findex fl_points()
@anchor{fl_points()}
@example
void fl_point(FL_Coord x, FL_Coord y, FL_COLOR col);
void fl_points(FL_POINT *p, int np, FL_COLOR col);
@end example
@noindent
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 @code{XPutImage(3)} should be used. Or better
yet, use the image support in the Forms Library (see @ref{Part VI
Images, , 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
@findex fl_linewidth()
@anchor{fl_linewidth()}
@findex fl_linestyle()
@anchor{fl_linestyle()}
@example
void fl_linewidth(int lw);
void fl_linestyle(int style);
@end example
@noindent
Set @code{lw} to 0 to reset the line width to the servers default.
Line styles can take on the following values (also see
@code{XChangeGC(3)})
@table @code
@tindex FL SOLID
@item FL SOLID
Solid line. Default and most efficient.
@tindex FL DOT
@item FL DOT
Dotted line.
@tindex FL DASH
@item FL DASH
Dashed line.
@tindex FL DOTDASH
@item FL DOTDASH
Dash-dot-dash line.
@tindex FL LONGDASH
@item FL LONGDASH
Long dashed line.
@tindex FL USERDASH
@item FL USERDASH
Dashed line, but the dash pattern is user definable via
@code{@ref{fl_dashedlinestyle()}}. Only the odd numbered segments are
drawn with the foreground color.
@tindex FL USERDOUBLEDASH
@item FL USERDOUBLEDASH
Similar to @code{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 @code{@ref{fl_bk_color()}}).
@end table

The following routine can be used to change the dash pattern
for @code{FL_USERDASH} and @code{FL USERDOUBLEDASH}:
@findex fl_dashedlinestyle()
@anchor{fl_dashedlinestyle()}
@example
void fl_dashedlinestyle(const char *dash, int ndashes)
@end example
Each element of the array @code{dash} is the length of a segment of
the pattern in pixels. Dashed lines are drawn as alternating segments,
each with the length of an element in @code{dash}. Thus the overall
length of the dash pattern, in pixels, is the sum of all elements of
@code{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.
@example
char ldash_sdash[] = @{9, 3, 2, 3@};
fl_dashedlinestyle(ldash_sdash, 4);
@end example

It is important to remember to call @code{@ref{fl_dashedlinestyle()}}
whenever @code{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 @code{NULL} as the dash parameter to
@code{@ref{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.
@findex fl_drawmode()
@anchor{fl_drawmode()}
@example
void fl_drawmode(int mode);
@end example
@noindent
There are 16 different possible settings for @code{mode} (see a Xlib
programming manual for all the gory details). A of the more useful
ones are
@table @code
@item GXcopy
Default overwrite mode. Final pixel value = Src
@item GXxor
Bitwise XOR (exclusive-or) of the pixel value to be drawn with the
pixel value already on the screen. Useful for rubber-banding.
@item GXand
Bitwise AND of the pixel value to be drawn with the
pixel value already on the screen.
@item GXor
Bitwise OR of the pixel value to be drawn with the
pixel value already on the screen.
@item GXinvert
Just invert the pixel values already on the screen.
@end table

To obtain the current settings of the line drawing attributes use the
following routines
@findex fl_get_linewidth()
@anchor{fl_get_linewidth()}
@findex fl_get_linestyle(()
@anchor{fl_get_linestyle(()}
@findex fl_get_drawmode(()
@anchor{fl_get_drawmode(()}
@example
int fl_get_linewidth(void);
int fl_get_linestyle(void);
int fl_get_drawmode(void);
@end example

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.
@findex fl_drw_box()
@anchor{fl_drw_box()}
@example
void fl_drw_box(int style, FL_Coord x, FL_Coord y,
                FL_Coord w, FL_Coord h,
                FL_COLOR col, int bw);
@end example
@noindent
@code{style} is the type of the box, e.g.@: @code{FL_DOWN_BOX}.
@code{x}, @code{y}, @code{w}, and @code{h} indicate the size of the
box. @code{col} is the color and @code{bw} is the width of the
boundary, which typically should be given the value @code{obj->bw} or
@code{FL_BOUND_WIDTH}. Note that a negative border width indicates a
"softer" up box. See the demo program @file{borderwidth.c} for the
visual effect of different border widths.

There is also a routine for drawing a frame:
@findex fl_drw_frame()
@anchor{fl_drw_frame()}
@example
void fl_drw_frame(int style, FL_Coord x, FL_Coord y,
                  FL_Coord w, FL_Coord h, FL_COLOR col, int bw)
@end example
@noindent
All parameters have the usual meaning except that the frame is drawn
outside of the bounding box specified.

To draw a slider of various types and shapes use
@findex fl_drw_slider)
@anchor{fl_drw_slider)}
@example
void fl_drw_slider(int boxtype, FL_Coord x, FL_Coord y,
                   FL_Coord w, FL_Coord h, FL_COLOR col1,
                   FL_COLOR col2, int slider_type,
                   double slider_size, double slider_value,
                   char *label, int parts, int inverted, FL_Coord bw);
@end example
@noindent
where @code{slider_type} is one of the different slider types like
@code{FL_VERT_SLIDER} etc., see @ref{Slider Object}, for a complete list.
Other parameters have the obvious meaning except for @code{parts},
which can be one of the following
@table @code
@item FL_SLIDER_NONE
Don't draw anything.
@item FL_SLIDER_BOX
Draw the bounding box only.
@item FL_SLIDER_KNOB
Draw the knob only.
@item FL_SLIDER_ALL
Draw the entire slider.
@end table

For drawing text there are two routines:
@findex fl_drw_text()
@anchor{fl_drw_text()}
@findex fl_drw_text_beside()
@anchor{fl_drw_text_beside()}
@example
void fl_drw_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_drw_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);
@end example
@noindent
where @code{align} is the alignment, namely, @code{FL ALIGN LEFT},
@code{FL ALIGN CENTER} etc. @code{x}, @code{y}, @code{w} and @code{h}
indicate the bounding box, @code{col} is the color of the text,
@code{size} is the size of the font to use (in points) and
@code{style} is the font style to be used (see @ref{Label Attributes
and Fonts}, for valid styles). Finally, @code{str} is the string
itself, possibly containing embedded newline characters.

@code{@ref{fl_drw_text()}} draws the text inside the bounding box
according to the alignment requested while
@code{@ref{fl_drw_text_beside()}} draws the text aligned outside of
the box. These two routines interpret a text string starting with the
character @code{@@} differently in drawing some symbols instead. Note
that @code{@ref{fl_drw_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
@findex fl_drw_text_cursor()
@anchor{fl_drw_text_cursor()}
@example
void fl_drw_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,
                        int FL_COLOR ccol, int pos);
@end example
@noindent
where @code{ccol} is the color of the cursor and @code{pos} is its
position which indicates the index of the character in @code{str}
before which to draw the cursor (-1 means show no cursor). This
routine does no interpretion of the special character @code{@@} 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:
@findex fl_get_align_xy()
@anchor{fl_get_align_xy()}
@example
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);
@end example
@noindent
This routine works regardless if the object is to be drawn inside or
outside of the bounding box specified by @code{x}, @code{y}, @code{w}
and @code{h}. @code{obj_xsize} and @code{obj->ysize} are the width
and height of the object to be drawn and @code{xmargin} and
@code{ymargin} is the additional padding to use. @code{xpos} and
@code{ypos} return the position to be used for drawing the object.

For drawing object labels the following routines might be more convenient:
@findex fl_draw_object_label()
@anchor{fl_draw_object_label()}
@findex fl_draw_object_label_outside()
@anchor{fl_draw_object_label_outside()}
@example
void fl_draw_object_label(FL_OBJECT *obj)
void fl_draw_object_label_outside(FL_OBJECT *obj);
@end example
@noindent
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 of 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.