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 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979
|
@node Part IV Drawing Objects
@chapter Drawing Objects
@ifnottex
@menu
* General Remarks: General Remarks
* Color Handling: Color Handling
* Mouse Handling: Mouse Handling
* Clipping: Clipping
* Getting the Size: Getting the Size
* Font Handling: Font Handling
* Drawing Functions: Drawing Functions
@end menu
@end ifnottex
@node General Remarks
@section 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
@code{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 @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
@anchor{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 does not 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{@ref{fl_state}} of @code{@ref{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
@code{@ref{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()
@anchor{FL_FormDisplay()}
@code{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 @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.
@node Color Handling
@section 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 @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
unsigned long fl_get_pixel(FL_COLOR col);
@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 col);
@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 col);
void fl_set_background(GC gc, FL_COLOR col);
@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 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);
@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).
@node Mouse Handling
@section 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
@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.
@node Clipping
@section Clipping
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}
used for drawing (but not for output of text, see below). @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.
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
@code{@ref{fl_set_clipping()}} may get restricted even further due
this global clipping.
You can check if there's clipping set for the default @code{GC}
using the function
@findex fl_is_clipped()
@anchor{fl_is_clipped()}
@example
int fl_is_clipped(int include_global);
@end example
@noindent
which returns @code{1} if clipping is switched on and @code{0}
otherwise. The @code{include_global} argument tells the function
if global clipping is to be included in the answer or not (i.e.,
if the argument is @code{0} only clipping set via
@code{@ref{fl_set_clipping()}} is reported).
The area currently clipped to is returned by the function
@findex fl_get_clipping()
@anchor{fl_get_clipping()}
@example
int fl_get_clipping(int include_global, FL_Coord *x,FL_Coord *y,
FL_Coord *width, FL_Coord *height);
@end example
@noindent
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
@code{@ref{fl_is_clipped()}}. The @code{include_global} argument has
the same meaning as for @code{@ref{fl_is_clipped()}}, i.e., it
controls if the effects of global clipping is included in the results.
When finished with drawing always use
@findex fl_unset_clipping()
@anchor{fl_unset_clipping()}
@example
void fl_unset_clipping(void);
@end example
@noindent
to switch clipping of again.
You also can check and obtain the current settings for global clipping
using the functions
@findex fl_is_global_clipped()
@anchor{fl_is_global_clipped()}
@findex fl_get_global_clipping()
@anchor{fl_get_global_clipping()}
@example
int fl_is_global_clipped(void);
int fl_get_global_clipping(FL_Coord *x,FL_Coord *y,
FL_Coord *width, FL_Coord *height);
@end example
Clipping for text is controlled via a different @code{GC} and thus
needs to be set, tested for and unset using a different set of functions:
@findex fl_set_text_clipping()
@anchor{fl_set_text_clipping()}
@findex fl_is_text_clipped(
@anchor{fl_is_text_clipped()}
@findex fl_get_text_clipping(
@anchor{fl_get_text_clipping()}
@findex fl_unset_text_clipping()
@anchor{fl_unset_text_clipping()}
@example
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);
@end example
Finally, there are functions to set and unset 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 width, FL_Coord height);
void fl_unset_gc_clipping(GC gc);
@end example
@noindent
Please note that setting clipping for a @code{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
@code{@ref{fl_is_global_clipped()}}).
@node Getting the Size
@section Getting the Size
To obtain the bounding box of an object with the label taken into
account (in contrast to the result of the
@code{@ref{fl_get_object_geometry()} function which doesn't include a
label that isn't inside the object} 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
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 *ascent, int *descent)
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 @code{size} indicates the point size for the font and
@code{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{ascent} and
@code{descent} arguments (if they aren't @code{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:
@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 *ascent, int *descent);
@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
if @code{ascent} and @code{descent} aren't @code{NULL} pointers.
Note that the string may not contain newline characters @code{'\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 @code{@ref{fl_get_char_height()}} or
@code{@ref{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 @code{'\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.
@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
@node Font Handling
@section 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:
@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 is not allowed to free the structure returned by
@code{@ref{fl_get_fontstruct()}}, it's just a pointer to an
internal structure!
@node Drawing Functions
@section 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:
@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's event 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 col);
void fl_rect(FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
FL_COLOR col);
@end example
@noindent
Both functions draw a rectangle on the screen in color @code{col}.
While @code{@ref{fl_rectf()}} draws a filled rectangle,
@code{@ref{fl_rect()}} just draws the outline in the given color.
To draw a filled (with color @code{col}) 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 col);
@end example
To draw a rectangle with rounded corners (filled or just the outlined)
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: @strong{all} polygon routines require that the array
@code{xpoint} has spaces for @strong{@code{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 @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 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);
@end example
@noindent
The @code{x} and @code{y} arguments are the upper left hand corner
of the ellipse, while @code{w} and @code{h} are its width and height.
Note: @code{@ref{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
@findex fl_oval()
@example
void fl_ovalf(int fill, FL_Coord x, FL_Coord y, FL_Coord w,
FL_Coord h, FL_COLOR col);
@end example
which is invoked by both (the macros) @code{@ref{fl_ovalf()}}
and @code{@ref{fl_ovall()}} with the first argument @code{fill}
set to either @code{1} or @code{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:
@findex fl_circ()
@anchor{fl_circ()}
@findex fl_circf()
@anchor{fl_circf()}
@findex fl_circbound()
@anchor{fl_circbound()}
@example
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);
@end example
@noindent
Here @code{x} and @code{y} are the coordinates of the center of the
circle, @code{r} is its radius and @code{col} the color to be used.
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
@code{x} and @code{y} are the coordinates of the center and @code{r}
is the radius. @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 can 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
@code{x} and @code{y} are the upper left hand corner of the box
enclosing the ellipse that the pieslice is part of and @code{w} and
@code{h} the width and height of that box. @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 macro for drawing 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 (0 is not allowed). 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
@noindent
If @code{dash} is @code{NULL} or @code{ndashes} is @code{0} (or
the @code{dash} array contains an element set to @code{0}) a default
pattern of 4 pixels on and 4 fixels off is set.
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_draw_box()
@anchor{fl_draw_box()}
@example
void fl_draw_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_draw_frame()
@anchor{fl_draw_frame()}
@example
void fl_draw_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.
For drawing text there are two routines:
@findex fl_draw_text()
@anchor{fl_draw_text()}
@findex fl_draw_text_beside()
@anchor{fl_draw_text_beside()}
@example
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);
@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_draw_text()}} draws the text inside the bounding box
according to the alignment requested while
@code{@ref{fl_draw_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_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
@findex fl_draw_text_cursor()
@anchor{fl_draw_text_cursor()}
@example
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);
@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 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.
|