summaryrefslogtreecommitdiff
path: root/FL/fl_draw.H
blob: b801c715d2eda4763167a29b140db736cbe1f656 (plain)
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
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
//
// Portable drawing function header file for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2021 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file.  If this
// file is missing or damaged, see the license at:
//
//     https://www.fltk.org/COPYING.php
//
// Please see the following page on how to report bugs and issues:
//
//     https://www.fltk.org/bugs.php
//

/**
  \file fl_draw.H
  \brief utility header to pull drawing functions together
*/

#ifndef fl_draw_H
#define fl_draw_H

#include <FL/Enumerations.H>       // color names
#include <FL/Fl_Graphics_Driver.H> // fl_graphics_driver + Fl_Region
#include <FL/Fl_Rect.H>

// Image class...
class Fl_Image;
class Fl_Window;

// Label flags...
FL_EXPORT extern char fl_draw_shortcut;

/** \addtogroup fl_attributes
    @{
*/

// Colors:
/**
  Set the color for all subsequent drawing operations.
  For colormapped displays, a color cell will be allocated out of
  \p fl_colormap the first time you use a color. If the colormap fills up
  then a least-squares algorithm is used to find the closest color.
  If no valid graphical context (fl_gc) is available,
  the foreground is not set for the current window.
  \param[in] c color
*/
inline void fl_color(Fl_Color c) {
  fl_graphics_driver->color(c);
} // select indexed color
/** for back compatibility - use fl_color(Fl_Color c) instead */
inline void fl_color(int c) {
  fl_color((Fl_Color)c);
}
/**
  Set the color for all subsequent drawing operations.
  The closest possible match to the RGB color is used.
  The RGB color is used directly on TrueColor displays.
  For colormap visuals the nearest index in the gray
  ramp or color cube is used.
  If no valid graphical context (fl_gc) is available,
  the foreground is not set for the current window.
  \param[in] r,g,b color components
*/
inline void fl_color(uchar r, uchar g, uchar b) {
  fl_graphics_driver->color(r, g, b);
}
/**
  Return the last fl_color() that was set.
  This can be used for state save/restore.
*/
inline Fl_Color fl_color() {
  return fl_graphics_driver->color();
}
/** @} */

/** \addtogroup fl_drawings
    @{
*/
// clip:
/**
  Intersect the current clip region with a rectangle and push this
  new region onto the stack.
  \param[in] x,y,w,h position and size
*/
inline void fl_push_clip(int x, int y, int w, int h) {
  fl_graphics_driver->push_clip(x, y, w, h);
}
/**
  Intersect the current clip region with a rectangle and push this
  new region onto the stack (deprecated).
  \param[in] x,y,w,h position and size
  \deprecated
    Please use fl_push_clip(int x, int y, int w, int h) instead.
    fl_clip(int, int, int, int) will be removed in FLTK 1.5.
*/
inline void fl_clip(int x, int y, int w, int h) {
  fl_graphics_driver->push_clip(x, y, w, h);
}
/**
  Push an empty clip region onto the stack so nothing will be clipped.
*/
inline void fl_push_no_clip() {
  fl_graphics_driver->push_no_clip();
}
/**
  Restore the previous clip region.

  You must call fl_pop_clip() once for every time you call fl_push_clip().
  Unpredictable results may occur if the clip stack is not empty when
  you return to FLTK.
*/
inline void fl_pop_clip() {
  fl_graphics_driver->pop_clip();
}

/**
  Does the rectangle intersect the current clip region?

  \param[in] x,y,w,h position and size of rectangle

  \returns non-zero if any of the rectangle intersects the current clip
    region. If this returns 0 you don't have to draw the object.

  \note Under X this returns 2 if the rectangle is partially clipped
    and 1 if it is entirely inside the clip region.

  \see fl_clip_box()
*/
inline int fl_not_clipped(int x, int y, int w, int h) {
  return fl_graphics_driver->not_clipped(x, y, w, h);
}

/**
  Intersect a rectangle with the current clip region and return the
  bounding box of the result.

  Returns non-zero if the resulting rectangle is different to the original.
  The given rectangle <tt>(x, y, w, h)</tt> \e should be entirely inside its
  window, otherwise the result may be unexpected, i.e. this function \e may
  not clip the rectangle to the window coordinates and size. In particular
  \p x and \p y \e should not be negative.

  The resulting bounding box can be used to limit the necessary drawing to
  this rectangle.

  Example:
  \code
    void MyGroup::draw() {
      int X = 0, Y = 0, W = 0, H = 0;
      int ret = fl_clip_box(x(), y(), w(), h(), X, Y, W, H);
      if (ret == 0) { // entire group is visible (not clipped)
        // full drawing code here
      } else { // parts of this group are clipped
        // partial drawing code here (uses X, Y, W, and H to test)
      }
    }
  \endcode

  \p W and \p H are set to zero if the rectangle is completely outside the
    clipping region. In this case \p X and \p Y are undefined and should
    not be used. Possible values are <tt>(0, 0)</tt>, <tt>(x, y)</tt>,
    or anything else (platform dependent).

  \note This function is platform-dependent. If the given rectangle is not
    entirely inside the window, the results are not guaranteed to be the
    same on all platforms.

  \param[in]  x,y,w,h position and size of rectangle
  \param[out] X,Y,W,H position and size of resulting bounding box.

  \returns Non-zero if the resulting rectangle is different to the original.

  \see fl_not_clipped()
*/
inline int fl_clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H) {
  return fl_graphics_driver->clip_box(x, y, w, h, X, Y, W, H);
}

/** Undo any clobbering of the clip region done by your program. */
inline void fl_restore_clip() {
  fl_graphics_driver->restore_clip();
}

/**
  Replace the top of the clipping stack with a clipping region of any shape.

  Fl_Region is an operating system specific type.
  \note This function is mostly intended for internal use by the FLTK library
  when drawing to the display.
  Its effect can be null if the current drawing surface is not the display.
  \param[in] r clipping region
*/
inline void fl_clip_region(Fl_Region r) {
  fl_graphics_driver->clip_region(r);
}

/**
  Return the current clipping region.
  \note This function is mostly intended for internal use by the FLTK library
  when drawing to the display.
  Its return value can be always NULL if the current drawing surface is not the display.
*/
inline Fl_Region fl_clip_region() {
  return fl_graphics_driver->clip_region();
}


// points:
/**
  Draw a single pixel at the given coordinates
*/
inline void fl_point(int x, int y) {
  fl_graphics_driver->point(x, y);
}

// line type:
/**
  Set how to draw lines (the "pen").

  If you change this it is your responsibility to set it back to the default
  using \c fl_line_style(0).

  \param[in] style A bitmask which is a bitwise-OR of a line style, a cap
    style, and a join style. If you don't specify a dash type you
    will get a solid line. If you don't specify a cap or join type
    you will get a system-defined default of whatever value is fastest.
  \param[in] width The thickness of the lines in pixels. Zero results in the
    system defined default, which on both X and Windows is somewhat
    different and nicer than 1.
  \param[in] dashes A pointer to an array of dash lengths, measured in pixels.
    The first location is how long to draw a solid portion, the next
    is how long to draw the gap, then the solid, etc. It is terminated
    with a zero-length entry. A \c NULL pointer or a zero-length
    array results in a solid line. Odd array sizes are not supported
    and result in undefined behavior.

  \note Because of how line styles are implemented on Win32 systems,
    you \e must set the line style \e after setting the drawing
    color. If you set the color after the line style you will lose
    the line style settings.

  \note The \p dashes array does not work under the (unsupported!) operating
    systems Windows 95, 98 or Me, since those operating systems do not
    support complex line styles.
*/
inline void fl_line_style(int style, int width = 0, char *dashes = 0) {
  fl_graphics_driver->line_style(style, width, dashes);
}
enum {
  FL_SOLID = 0,      ///< line style: <tt>___________</tt>
  FL_DASH = 1,       ///< line style: <tt>_ _ _ _ _ _</tt>
  FL_DOT = 2,        ///< line style: <tt>. . . . . .</tt>
  FL_DASHDOT = 3,    ///< line style: <tt>_ . _ . _ .</tt>
  FL_DASHDOTDOT = 4, ///< line style: <tt>_ . . _ . .</tt>

  FL_CAP_FLAT = 0x100,   ///< cap style: end is flat
  FL_CAP_ROUND = 0x200,  ///< cap style: end is round
  FL_CAP_SQUARE = 0x300, ///< cap style: end wraps end point

  FL_JOIN_MITER = 0x1000, ///< join style: line join extends to a point
  FL_JOIN_ROUND = 0x2000, ///< join style: line join is rounded
  FL_JOIN_BEVEL = 0x3000  ///< join style: line join is tidied
};

/**
  Turn antialiased line drawings ON or OFF, if supported by platform.
  Currently, only the Windows platform allows to change whether line drawings
  are antialiased. Turning it OFF may accelerate heavy drawing operations.
*/
inline void fl_antialias(int state) {
  fl_graphics_driver->antialias(state);
}

/** Return whether line drawings are currently antialiased. */
inline int fl_antialias() {
  return fl_graphics_driver->antialias();
}

// rectangles tweaked to exactly fill the pixel rectangle:

/**
  Draw a 1-pixel border \e inside the given bounding box.
  This function is meant for quick drawing of simple boxes. The behavior is
  undefined for line widths that are not 1.
*/
inline void fl_rect(int x, int y, int w, int h) {
  fl_graphics_driver->rect(x, y, w, h);
}

/**
  Draw a 1-pixel border \e inside the given bounding box.
  This is the same as fl_rect(int x, int y, int w, int h) but with
  Fl_Rect \p r as input argument.
*/
inline void fl_rect(Fl_Rect r) {
  fl_rect(r.x(), r.y(), r.w(), r.h());
}

/** Draw a dotted rectangle, used to indicate keyboard focus on a widget.

  This method draws the rectangle in the current color and independent of
  the Fl::visible_focus() option. You may need to set the current color
  with fl_color() before you call this.
*/
inline void fl_focus_rect(int x, int y, int w, int h) {
  fl_graphics_driver->focus_rect(x, y, w, h);
}

/** Draw with passed color a 1-pixel border \e inside the given bounding box. */
inline void fl_rect(int x, int y, int w, int h, Fl_Color c) {
  fl_color(c);
  fl_rect(x, y, w, h);
}

/** Color with current color a rectangle that exactly fills the given bounding box. */
inline void fl_rectf(int x, int y, int w, int h) {
  fl_graphics_driver->rectf(x, y, w, h);
}

/** Color with passed color a rectangle that exactly fills the given bounding box. */
inline void fl_rectf(int x, int y, int w, int h, Fl_Color c) {
  fl_color(c);
  fl_rectf(x, y, w, h);
}

/** Color with current color a rectangle that exactly fills the given bounding box. */
inline void fl_rectf(Fl_Rect r) {
  fl_graphics_driver->rectf(r.x(), r.y(), r.w(), r.h());
}

/** Color with passed color a rectangle that exactly fills the given bounding box. */
inline void fl_rectf(Fl_Rect r, Fl_Color c) {
  fl_color(c);
  fl_rectf(r);
}

/**
  Color a rectangle with "exactly" the passed <tt>r,g,b</tt> color.
  On screens with less than 24 bits of color this is done by drawing a
  solid-colored block using fl_draw_image() so that the correct color
  shade is produced.
*/
inline void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) {
  fl_graphics_driver->colored_rectf(x, y, w, h, r, g, b);
}

/**
  Color a rectangle with "exactly" the passed <tt>r,g,b</tt> color.
  This is the same as fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b)
  but with Fl_Rect \p bb (bounding box) as argument instead of (x, y, w, h).
  \see fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b)
*/
inline void fl_rectf(Fl_Rect bb, uchar r, uchar g, uchar b) {
  fl_graphics_driver->colored_rectf(bb.x(), bb.y(), bb.w(), bb.h(), r, g, b);
}

// line segments:
/**
  Draw a line from (x,y) to (x1,y1)
*/
inline void fl_line(int x, int y, int x1, int y1) {
  fl_graphics_driver->line(x, y, x1, y1);
}
/**
  Draw a line from (x,y) to (x1,y1) and another from (x1,y1) to (x2,y2)
*/
inline void fl_line(int x, int y, int x1, int y1, int x2, int y2) {
  fl_graphics_driver->line(x, y, x1, y1, x2, y2);
}

// closed line segments:
/**
  Outline a 3-sided polygon with lines
*/
inline void fl_loop(int x, int y, int x1, int y1, int x2, int y2) {
  fl_graphics_driver->loop(x, y, x1, y1, x2, y2);
}
/**
  Outline a 4-sided polygon with lines
*/
inline void fl_loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) {
  fl_graphics_driver->loop(x, y, x1, y1, x2, y2, x3, y3);
}

// filled polygons
/**
  Fill a 3-sided polygon. The polygon must be convex.
*/
inline void fl_polygon(int x, int y, int x1, int y1, int x2, int y2) {
  fl_graphics_driver->polygon(x, y, x1, y1, x2, y2);
}
/**
  Fill a 4-sided polygon. The polygon must be convex.
*/
inline void fl_polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) {
  fl_graphics_driver->polygon(x, y, x1, y1, x2, y2, x3, y3);
}

// draw rectilinear lines, horizontal segment first:
/**
  Draw a horizontal line from (x,y) to (x1,y).
*/
inline void fl_xyline(int x, int y, int x1) {
  fl_graphics_driver->xyline(x, y, x1);
}
/**
  Draw a horizontal line from (x,y) to (x1,y), then vertical from (x1,y) to (x1,y2).
*/
inline void fl_xyline(int x, int y, int x1, int y2) {
  fl_graphics_driver->xyline(x, y, x1, y2);
}
/**
  Draw a horizontal line from (x,y) to (x1,y), then a vertical from (x1,y) to (x1,y2)
  and then another horizontal from (x1,y2) to (x3,y2).
*/
inline void fl_xyline(int x, int y, int x1, int y2, int x3) {
  fl_graphics_driver->xyline(x, y, x1, y2, x3);
}

// draw rectilinear lines, vertical segment first:
/**
  Draw a vertical line from (x,y) to (x,y1)
*/
inline void fl_yxline(int x, int y, int y1) {
  fl_graphics_driver->yxline(x, y, y1);
}
/**
  Draw a vertical line from (x,y) to (x,y1), then a horizontal from (x,y1) to (x2,y1).
*/
inline void fl_yxline(int x, int y, int y1, int x2) {
  fl_graphics_driver->yxline(x, y, y1, x2);
}
/**
  Draw a vertical line from (x,y) to (x,y1), then a horizontal from (x,y1)
  to (x2,y1), then another vertical from (x2,y1) to (x2,y3).
*/
inline void fl_yxline(int x, int y, int y1, int x2, int y3) {
  fl_graphics_driver->yxline(x, y, y1, x2, y3);
}

// circular lines and pie slices (code in fl_arci.C):
/**
  Draw ellipse sections using integer coordinates.

  These functions match the rather limited circle drawing code provided by X
  and Windows. The advantage over using fl_arc with floating point coordinates
  is that they are faster because they often use the hardware, and they draw
  much nicer small circles, since the small sizes are often hard-coded bitmaps.

  If a complete circle is drawn it will fit inside the passed bounding box.
  The two angles are measured in degrees counter-clockwise from 3 o'clock and
  are the starting and ending angle of the arc, \p a2 must be greater or equal
  to \p a1.

  fl_arc() draws a series of lines to approximate the arc. Notice that the
  integer version of fl_arc() has a different number of arguments than the
  double version fl_arc(double x, double y, double r, double start, double end)

  \param[in] x,y,w,h bounding box of complete circle
  \param[in] a1,a2 start and end angles of arc measured in degrees
  counter-clockwise from 3 o'clock. \p a2 must be greater
  than or equal to \p a1.

  \image html  fl_pie_arc_diagram.png "fl_pie() and fl_arc()"
  \image latex fl_pie_arc_diagram.png "fl_pie() and fl_arc()" width=4cm
*/
inline void fl_arc(int x, int y, int w, int h, double a1, double a2) {
  fl_graphics_driver->arc(x, y, w, h, a1, a2);
}
/**
  Draw filled ellipse sections using integer coordinates.

  Like fl_arc(), but fl_pie() draws a filled-in pie slice.
  This slice may extend outside the line drawn by fl_arc();
  to avoid this use w - 1 and h - 1.

  \param[in] x,y,w,h bounding box of complete circle
  \param[in] a1,a2 start and end angles of arc measured in degrees
    counter-clockwise from 3 o'clock. \p a2 must be greater
    than or equal to \p a1.

  \image html  fl_pie_arc_diagram.png "fl_pie() and fl_arc()"
  \image latex fl_pie_arc_diagram.png "fl_pie() and fl_arc()" width=4cm
*/
inline void fl_pie(int x, int y, int w, int h, double a1, double a2) {
  fl_graphics_driver->pie(x, y, w, h, a1, a2);
}
/** fl_chord declaration is a place holder - the function does not yet exist */
FL_EXPORT void fl_chord(int x, int y, int w, int h, double a1, double a2); // nyi

// scalable drawing code (code in fl_vertex.cxx and fl_arc.cxx):
/**
  Save the current transformation matrix on the stack.
  The maximum depth of the stack is 32.
*/
inline void fl_push_matrix() {
  fl_graphics_driver->push_matrix();
}
/**
  Restore the current transformation matrix from the stack.
*/
inline void fl_pop_matrix() {
  fl_graphics_driver->pop_matrix();
}
/**
  Concatenate scaling transformation onto the current one.
  \param[in] x,y scale factors in x-direction and y-direction
*/
inline void fl_scale(double x, double y) {
  fl_graphics_driver->mult_matrix(x, 0, 0, y, 0, 0);
}
/**
  Concatenate scaling transformation onto the current one.
  \param[in] x scale factor in both x-direction and y-direction
*/
inline void fl_scale(double x) {
  fl_graphics_driver->mult_matrix(x, 0, 0, x, 0, 0);
}
/**
  Concatenate translation transformation onto the current one.
  \param[in] x,y translation factor in x-direction and y-direction
*/
inline void fl_translate(double x, double y) {
  fl_graphics_driver->translate(x, y);
}
/**
  Concatenate rotation transformation onto the current one.
  \param[in] d - rotation angle, counter-clockwise in degrees (not radians)
*/
inline void fl_rotate(double d) {
  fl_graphics_driver->rotate(d);
}
/**
  Concatenate another transformation onto the current one.

  \param[in] a,b,c,d,x,y transformation matrix elements such that
 <tt> X' = aX + cY + x </tt> and <tt> Y' = bX +dY + y </tt>
*/
inline void fl_mult_matrix(double a, double b, double c, double d, double x, double y) {
  fl_graphics_driver->mult_matrix(a, b, c, d, x, y);
}
/**
  Start drawing a list of points. Points are added to the list with fl_vertex().
*/
inline void fl_begin_points() {
  fl_graphics_driver->begin_points();
}
/**
  Start drawing a list of lines.
*/
inline void fl_begin_line() {
  fl_graphics_driver->begin_line();
}
/**
  Start drawing a closed sequence of lines.
*/
inline void fl_begin_loop() {
  fl_graphics_driver->begin_loop();
}
/**
  Start drawing a convex filled polygon.
*/
inline void fl_begin_polygon() {
  fl_graphics_driver->begin_polygon();
}
/**
  Add a single vertex to the current path.
  \param[in] x,y coordinate
*/
inline void fl_vertex(double x, double y) {
  fl_graphics_driver->vertex(x, y);
}
/**
  Add a series of points on a Bézier curve to the path.
  The curve ends (and two of the points) are at X0,Y0 and X3,Y3.
  \param[in] X0,Y0 curve start point
  \param[in] X1,Y1 curve control point
  \param[in] X2,Y2 curve control point
  \param[in] X3,Y3 curve end point
*/
inline void fl_curve(double X0, double Y0, double X1, double Y1, double X2, double Y2, double X3, double Y3) {
  fl_graphics_driver->curve(X0, Y0, X1, Y1, X2, Y2, X3, Y3);
}
/**
  Add a series of points to the current path on the arc of a circle.
  You can get elliptical paths by using scale and rotate before calling fl_arc().
  \param[in] x,y,r center and radius of circular arc
  \param[in] start,end angles of start and end of arc measured in degrees
    counter-clockwise from 3 o'clock. If \p end is less than \p start
    then it draws the arc in a clockwise direction.

  \image html  fl_arc_xyr_diagram.png "fl_arc(x,y,r,a1,a2)"
  \image latex fl_arc_xyr_diagram.png "fl_arc(x,y,r,a1,a2)" width=6cm

  Examples:
  \code
    // Draw an arc of points
    fl_begin_points();
    fl_arc(100.0, 100.0, 50.0, 0.0, 180.0);
    fl_end_points();

    // Draw arc with a line
    fl_begin_line();
    fl_arc(200.0, 100.0, 50.0, 0.0, 180.0);
    fl_end_line();

    // Draw filled arc
    fl_begin_polygon();
    fl_arc(300.0, 100.0, 50.0, 0.0, 180.0);
    fl_end_polygon();
  \endcode
*/
inline void fl_arc(double x, double y, double r, double start, double end) {
  fl_graphics_driver->arc(x, y, r, start, end);
}
/**
  fl_circle(x,y,r) is equivalent to fl_arc(x,y,r,0,360), but may be faster.

  It must be the \e only thing in the path: if you want a circle as part of
  a complex polygon you must use fl_arc().
  \param[in] x,y,r center and radius of circle
*/
inline void fl_circle(double x, double y, double r) {
  fl_graphics_driver->circle(x, y, r);
}
/**
  End list of points, and draw.
*/
inline void fl_end_points() {
  fl_graphics_driver->end_points();
}
/**
  End list of lines, and draw.
*/
inline void fl_end_line() {
  fl_graphics_driver->end_line();
}
/**
  End closed sequence of lines, and draw.
*/
inline void fl_end_loop() {
  fl_graphics_driver->end_loop();
}
/**
  End convex filled polygon, and draw.
*/
inline void fl_end_polygon() {
  fl_graphics_driver->end_polygon();
}
/**
  Start drawing a complex filled polygon.

  The polygon may be concave, may have holes in it, or may be several
  disconnected pieces. Call fl_gap() to separate loops of the path.

  To outline the polygon, use fl_begin_loop() and replace each fl_gap()
  with fl_end_loop();fl_begin_loop() pairs.

  \note For portability, you should only draw polygons that appear the same
    whether "even/odd" or "non-zero" winding rules are used to fill them.
    Holes should be drawn in the opposite direction to the outside loop.
*/
inline void fl_begin_complex_polygon() {
  fl_graphics_driver->begin_complex_polygon();
}
/**
  Separate loops of the path.

  It is unnecessary but harmless to call fl_gap() before the first vertex,
  after the last vertex, or several times in a row.
*/
inline void fl_gap() {
  fl_graphics_driver->gap();
}
/**
  End complex filled polygon, and draw.
*/
inline void fl_end_complex_polygon() {
  fl_graphics_driver->end_complex_polygon();
}
// get and use transformed positions:
/**
  Transform coordinate using the current transformation matrix.
  \param[in] x,y coordinate
*/
inline double fl_transform_x(double x, double y) {
  return fl_graphics_driver->transform_x(x, y);
}
/**
  Transform coordinate using the current transformation matrix.
  \param[in] x,y coordinate
*/
inline double fl_transform_y(double x, double y) {
  return fl_graphics_driver->transform_y(x, y);
}
/**
  Transform distance using current transformation matrix.
  \param[in] x,y coordinate
*/
inline double fl_transform_dx(double x, double y) {
  return fl_graphics_driver->transform_dx(x, y);
}
/**
  Transform distance using current transformation matrix.
  \param[in] x,y coordinate
*/
inline double fl_transform_dy(double x, double y) {
  return fl_graphics_driver->transform_dy(x, y);
}
/**
  Add coordinate pair to the vertex list without further transformations.
  \param[in] xf,yf transformed coordinate
*/
inline void fl_transformed_vertex(double xf, double yf) {
  fl_graphics_driver->transformed_vertex(xf, yf);
}

/** Copy a rectangular area of the given offscreen buffer into the current drawing destination.
  \param x,y        position where to draw the copied rectangle
  \param w,h        size of the copied rectangle
  \param pixmap     offscreen buffer containing the rectangle to copy
  \param srcx,srcy  origin in offscreen buffer of rectangle to copy
*/
inline void fl_copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy) {
  fl_graphics_driver->copy_offscreen(x, y, w, h, pixmap, srcx, srcy);
}

FL_EXPORT Fl_Offscreen fl_create_offscreen(int w, int h);
FL_EXPORT void fl_begin_offscreen(Fl_Offscreen b);
FL_EXPORT void fl_end_offscreen(void);
FL_EXPORT void fl_delete_offscreen(Fl_Offscreen bitmap);
FL_EXPORT void fl_rescale_offscreen(Fl_Offscreen &ctx);

/** @} */

/** \addtogroup  fl_attributes
    @{ */
/* NOTE: doxygen comments here to avoid triplication in os-specific sources */

// Fonts:
/*
  Set the current font, which is then used in various drawing routines.
  Implemented and documented in src/fl_draw.cxx
*/
FL_EXPORT void fl_font(Fl_Font face, Fl_Fontsize fsize);

/**
  Return the \p face set by the most recent call to fl_font().
  This can be used to save/restore the font.
*/
inline Fl_Font fl_font() {
  return fl_graphics_driver->font();
}
/**
  Return the \p size set by the most recent call to fl_font().
  This can be used to save/restore the font.
*/
inline Fl_Fontsize fl_size() {
  return fl_graphics_driver->size();
}

// Information you can get about the current font:
/**
  Return the recommended minimum line spacing for the current font.
  You can also use the value of \p size passed to fl_font().
*/
inline int fl_height() {
  return fl_graphics_driver->height();
}
FL_EXPORT int fl_height(int font, int size);
/**
  Return the recommended distance above the bottom of a fl_height() tall
  box to draw the text at so it looks centered vertically in that box.
*/
inline int fl_descent() {
  return fl_graphics_driver->descent();
}
/** Return the typographical width of a nul-terminated string
    using the current font face and size.
*/
FL_EXPORT double fl_width(const char *txt);

/** Return the typographical width of a sequence of \p n characters
    using the current font face and size.
*/
inline double fl_width(const char *txt, int n) {
  return fl_graphics_driver->width(txt, n);
}
/** Return the typographical width of a single character
    using the current font face and size.

  \note If a valid fl_gc is NOT found then it uses the first window gc,
  or the screen gc if no fltk window is available when called.
*/
inline double fl_width(unsigned int c) {
  return fl_graphics_driver->width(c);
}
/** Determine the minimum pixel dimensions of a nul-terminated string
    using the current fl_font().

  Usage: given a string "txt" drawn using fl_draw(txt, x, y) you would determine
  its pixel extents on the display using fl_text_extents(txt, dx, dy, wo, ho)
  such that a bounding box that exactly fits around the text could be drawn with
  fl_rect(x+dx, y+dy, wo, ho). Note the dx, dy values hold the offset of the first
  "colored in" pixel of the string, from the draw origin.

  Note the desired font and font size must be set with fl_font() before calling
  this function.

  This differs slightly from fl_measure() in that the dx/dy values are also
  returned.

  No FLTK symbol expansion will be performed.

  Example use:
  \code
    int dx,dy,W,H;
    fl_font(FL_HELVETICA, 12);                   // set font face+size first
    fl_text_extents("Some text", dx, dy, W, H);  // get width and height of string
    printf("text's width=%d, height=%d\n", W, H);
  \endcode
*/
FL_EXPORT void fl_text_extents(const char *, int &dx, int &dy, int &w, int &h);

/** Determine the minimum pixel dimensions of a sequence of \p n characters
    (bytes) using the current fl_font().

  \note The string length is measured in bytes, not (UTF-8) characters.
  \see fl_text_extents(const char*, int& dx, int& dy, int& w, int& h)
*/
inline void fl_text_extents(const char *t, int n, int &dx, int &dy, int &w, int &h) {
  fl_graphics_driver->text_extents(t, n, dx, dy, w, h);
}

// font encoding:
// Note: doxygen comments here to avoid duplication for os-sepecific cases
/**
  Convert text from Windows/X11 latin1 character set to local encoding.
  \param[in] t character string (latin1 encoding)
  \param[in] n optional number of characters (bytes) to convert (default is all)
  \returns pointer to internal buffer containing converted characters
*/
FL_EXPORT const char *fl_latin1_to_local(const char *t, int n = -1);
/**
  Convert text from local encoding to Windows/X11 latin1 character set.
  \param[in] t character string (local encoding)
  \param[in] n optional number of characters (bytes) to convert (default is all)
  \returns pointer to internal buffer containing converted characters
*/
FL_EXPORT const char *fl_local_to_latin1(const char *t, int n = -1);
/**
  Convert text from Mac Roman character set to local encoding.
  \param[in] t character string (Mac Roman encoding)
  \param[in] n optional number of characters to convert (default is all)
  \returns pointer to internal buffer containing converted characters
*/
FL_EXPORT const char *fl_mac_roman_to_local(const char *t, int n = -1);
/**
  Convert text from local encoding to Mac Roman character set.
  \param[in] t character string (local encoding)
  \param[in] n optional number of characters to convert (default is all)
  \returns pointer to internal buffer containing converted characters
*/
FL_EXPORT const char *fl_local_to_mac_roman(const char *t, int n = -1);
/** @} */

/** \addtogroup  fl_drawings
    @{ */

FL_EXPORT float fl_override_scale();

FL_EXPORT void fl_restore_scale(float s);

/**
  Draw a nul-terminated UTF-8 string starting at the given \p x, \p y location.

  Text is aligned to the left and to the baseline of the font.
  To align to the bottom, subtract fl_descent() from \p y.
  To align to the top, subtract fl_descent() and add fl_height().
  This version of fl_draw provides direct access to the text drawing
  function of the underlying OS. It does not apply any special handling
  to control characters.
*/
FL_EXPORT void fl_draw(const char *str, int x, int y);
/**
  Draw a nul-terminated UTF-8 string starting at the given \p x, \p y
  location and rotating \p angle degrees counter-clockwise.
  This version of fl_draw provides direct access to the text drawing
  function of the underlying OS and is supported by all fltk platforms except
  X11 without Xft.
*/
FL_EXPORT void fl_draw(int angle, const char *str, int x, int y);
/**
  Draws starting at the given \p x, \p y location a UTF-8 string of length \p n bytes.
*/
inline void fl_draw(const char *str, int n, int x, int y) {
  fl_graphics_driver->draw(str, n, x, y);
}
/**
  Draw at the given \p x, \p y location a UTF-8 string of length \p n bytes
  rotating \p angle degrees counter-clockwise.

  \note When using X11 (Unix, Linux, Cygwin et al.) this needs Xft to work.
        Under plain X11 (w/o Xft) rotated text is not supported by FLTK.
        A warning will be issued to stderr at runtime (only once) if you
        use this method with an angle other than 0.
*/
inline void fl_draw(int angle, const char *str, int n, int x, int y) {
  fl_graphics_driver->draw(angle, str, n, x, y);
}
/**
  Draw a UTF-8 string of length \p n bytes right to left starting at the given \p x, \p y location.
*/
inline void fl_rtl_draw(const char *str, int n, int x, int y) {
  fl_graphics_driver->rtl_draw(str, n, x, y);
}
FL_EXPORT void fl_measure(const char *str, int &x, int &y, int draw_symbols = 1);
FL_EXPORT void fl_draw(const char *str, int x, int y, int w, int h, Fl_Align align, Fl_Image *img = 0,
                       int draw_symbols = 1);
FL_EXPORT void fl_draw(const char *str, int x, int y, int w, int h, Fl_Align align,
                       void (*callthis)(const char *, int, int, int), Fl_Image *img = 0, int draw_symbols = 1);

// boxtypes:

FL_EXPORT void fl_frame(const char *s, int x, int y, int w, int h);
FL_EXPORT void fl_frame2(const char *s, int x, int y, int w, int h);
FL_EXPORT void fl_draw_box(Fl_Boxtype, int x, int y, int w, int h, Fl_Color);

// basic GUI objects (check marks, arrows, more to come ...):

// Draw a check mark in the given color inside the bounding box bb.
void fl_draw_check(Fl_Rect bb, Fl_Color col);

// images:

/**
  Draw an 8-bit per color RGB or luminance image.
  \param[in] buf points at the "r" data of the top-left pixel.
                 Color data must be in <tt>r,g,b</tt> order.
                 Luminance data is only one <tt>gray</tt> byte.
  \param[in] X,Y position where to put top-left corner of image
  \param[in] W,H size of the image
  \param[in] D   delta to add to the pointer between pixels. It may be
                 any value greater than or equal to 1, or it can be
                 negative to flip the image horizontally
  \param[in] L   delta to add to the pointer between lines (if 0 is
                 passed it uses \p W * \p D), and may be larger than
                 \p W * \p D to crop data, or negative to flip the
                 image vertically

  It is highly recommended that you put the following code before the
  first <tt>show()</tt> of \e any window in your program to get rid of
  the dithering if possible:
  \code
  Fl::visual(FL_RGB);
  \endcode

  Gray scale (1-channel) images may be drawn. This is done if
  <tt>abs(D)</tt> is less than 3, or by calling fl_draw_image_mono().
  Only one 8-bit sample is used for each pixel, and on screens with
  different numbers of bits for red, green, and blue only gray colors
  are used. Setting \p D greater than 1 will let you display one channel
  of a color image.

  \par Note:
  The X version does not support all possible visuals. If FLTK cannot
  draw the image in the current visual it will abort. FLTK supports
  any visual of 8 bits or less, and all common TrueColor visuals up
  to 32 bits.
*/
inline void fl_draw_image(const uchar *buf, int X, int Y, int W, int H, int D = 3, int L = 0) {
  fl_graphics_driver->draw_image(buf, X, Y, W, H, D, L);
}

/**
  Draw a gray-scale (1 channel) image.
  \see fl_draw_image(const uchar* buf, int X,int Y,int W,int H, int D, int L)
*/
inline void fl_draw_image_mono(const uchar *buf, int X, int Y, int W, int H, int D = 1, int L = 0) {
  fl_graphics_driver->draw_image_mono(buf, X, Y, W, H, D, L);
}

/**
  Draw an image using a callback function to generate image data.

  You can generate the image as it is being drawn, or do arbitrary
  decompression of stored data, provided it can be decompressed to
  individual scan lines.

  \param[in] cb   callback function to generate scan line data
  \param[in] data user data passed to callback function
  \param[in] X,Y  screen position of top left pixel
  \param[in] W,H  image width and height
  \param[in] D    data size per pixel in bytes (must be greater than 0)

  \see fl_draw_image(const uchar* buf, int X, int Y, int W, int H, int D, int L)

  The callback function \p cb is called with the <tt>void*</tt> \p data
  user data pointer to allow access to a structure of information about
  the image, and the \p x, \p y, and \p w of the scan line desired from
  the image. 0,0 is the upper-left corner of the image, not \p x, \p y.
  A pointer to a buffer to put the data into is passed. You must copy
  \p w pixels from scanline \p y, starting at pixel \p x, to this buffer.

  Due to cropping, less than the whole image may be requested. So \p x
  may be greater than zero, the first \p y may be greater than zero,
  and \p w may be less than \p W. The buffer is long enough to store
  the entire \p W * \p D pixels, this is for convenience with some
  decompression schemes where you must decompress the entire line at
  once: decompress it into the buffer, and then if \p x is not zero,
  copy the data over so the \p x'th pixel is at the start of the buffer.

  You can assume the \p y's will be consecutive, except the first one
  may be greater than zero.

  If \p D is 4 or more, you must fill in the unused bytes with zero.
*/
inline void fl_draw_image(Fl_Draw_Image_Cb cb, void *data, int X, int Y, int W, int H, int D = 3) {
  fl_graphics_driver->draw_image(cb, data, X, Y, W, H, D);
}

/**
  Draw a gray-scale image using a callback function to generate image data.
  \see fl_draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D)
*/
inline void fl_draw_image_mono(Fl_Draw_Image_Cb cb, void *data, int X, int Y, int W, int H, int D = 1) {
  fl_graphics_driver->draw_image_mono(cb, data, X, Y, W, H, D);
}

/**
  Check whether platform supports true alpha blending for RGBA images.
  \returns 1 if true alpha blending supported by platform
  \returns 0 not supported so FLTK will use screen door transparency
*/
inline char fl_can_do_alpha_blending() {
  return Fl_Graphics_Driver::default_driver().can_do_alpha_blending();
}

FL_EXPORT uchar *fl_read_image(uchar *p, int X, int Y, int W, int H, int alpha = 0);
FL_EXPORT Fl_RGB_Image *fl_capture_window(Fl_Window *win, int x, int y, int w, int h);

// pixmaps:
/**
  Draw XPM image data, with the top-left corner at the given position.
  The image is dithered on 8-bit displays so you won't lose color
  space for programs displaying both images and pixmaps.

  \param[in] data pointer to XPM image data
  \param[in] x,y  position of top-left corner
  \param[in] bg   background color

  \returns 0 if there was any error decoding the XPM data.
*/
FL_EXPORT int fl_draw_pixmap(const char *const *data, int x, int y, Fl_Color bg = FL_GRAY);
/**
  Draw XPM image data, with the top-left corner at the given position.
  \see fl_draw_pixmap(const char* const* data, int x, int y, Fl_Color bg)
*/
inline int fl_draw_pixmap(/*const*/ char *const *data, int x, int y, Fl_Color bg = FL_GRAY) {
  return fl_draw_pixmap((const char *const *)data, x, y, bg);
}
FL_EXPORT int fl_measure_pixmap(/*const*/ char *const *data, int &w, int &h);
FL_EXPORT int fl_measure_pixmap(const char *const *cdata, int &w, int &h);

// other:
FL_EXPORT void fl_scroll(int X, int Y, int W, int H, int dx, int dy,
                         void (*draw_area)(void *, int, int, int, int), void *data);
FL_EXPORT const char *fl_shortcut_label(unsigned int shortcut);
FL_EXPORT const char *fl_shortcut_label(unsigned int shortcut, const char **eom);
FL_EXPORT unsigned int fl_old_shortcut(const char *s);
FL_EXPORT void fl_overlay_rect(int x, int y, int w, int h);
FL_EXPORT void fl_overlay_clear();
FL_EXPORT void fl_cursor(Fl_Cursor);
FL_EXPORT void fl_cursor(Fl_Cursor, Fl_Color fg, Fl_Color bg = FL_WHITE);
FL_EXPORT const char *fl_expand_text(const char *from, char *buf, int maxbuf, double maxw,
                                     int &n, double &width, int wrap, int draw_symbols = 0);

// XIM:
/** \todo provide user documentation for fl_set_status function */
FL_EXPORT void fl_set_status(int X, int Y, int W, int H);
/** Inform text input methods about the current text insertion cursor.
 \param font Font currently in use in text input.
 \param size Size of the current font.
 \param X,Y Position of the bottom of the current text insertion cursor.
 \param W,H Width and height of the current text insertion cursor.
 \param win Points to the Fl_Window object containing the current text widget, or NULL.
 */
FL_EXPORT void fl_set_spot(int font, int size, int X, int Y, int W, int H, Fl_Window *win = 0);
/** Resets marked text.

 In many languages, typing a character can involve multiple keystrokes. For
 example, the Ä can be composed of two dots (¨) on top of the
 character, followed by the letter A (on a Mac with U.S. keyboard, you'd
 type Alt-U, Shift-A. To inform the user that the dots may be followed by
 another character, the ¨ is underlined).

 Call this function if character composition needs to be aborted for some
 reason. One such example would be the text input widget losing focus.
 */
FL_EXPORT void fl_reset_spot(void);


// XForms symbols:
FL_EXPORT int fl_draw_symbol(const char *label, int x, int y, int w, int h, Fl_Color);
FL_EXPORT int fl_add_symbol(const char *name, void (*drawit)(Fl_Color), int scalable);
/** @} */

#endif