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.
|