FLTK logo

[master] ecc47d0 - Refactor and simplify "arrow drawing" in widgets

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 All Forums  |  Back to fltk.commit  ]
 
Previous Message ]Next Message ]

[master] ecc47d0 - Refactor and simplify "arrow drawing" in widgets "Albrecht Schlosser" Nov 22, 2022  
 
commit ecc47d0cc3e1784e17ac94829202f2bdbd38a682
Author:     Albrecht Schlosser <albrechts.fltk@online.de>
AuthorDate: Sun Nov 22 19:19:19 2020 +0100
Commit:     Albrecht Schlosser <albrechts.fltk@online.de>
CommitDate: Tue Nov 22 19:32:54 2022 +0100

    Refactor and simplify "arrow drawing" in widgets
    
    "Arrows" in widgets are those GUI elements mostly represented by
    triangles pointing in a particular direction as in scrollbars,
    choice widgets, some menus, valuators and Fl_Counter widgets.
    
    The code has been simplified and standardized such that all these
    GUI elements are drawn identically per FLTK scheme.
    
    Widget authors no longer need to write code to calculate arrow sizes
    and draw polygons etc.
    
    Different schemes can and do implement different drawing functions.
    
    Todo: see comments "FIXME_ARROW" in src/Fl_Menu_Button.cxx and
          src/Fl_Menu.cxx

 FL/Enumerations.H      |  55 ++++++++++-
 FL/Fl_Counter.H        |   4 +-
 FL/Fl_Spinner.H        |   4 +-
 FL/fl_draw.H           |  21 ++--
 src/CMakeLists.txt     |   1 +
 src/Fl_Choice.cxx      |  93 ++++++++++--------
 src/Fl_Counter.cxx     | 155 ++++++++++++++++++++----------
 src/Fl_Menu.cxx        |   3 +-
 src/Fl_Menu_Button.cxx |   3 +-
 src/Fl_Scrollbar.cxx   |  83 ++++++++--------
 src/Fl_Spinner.cxx     |  32 +++++--
 src/Makefile           |   1 +
 src/fl_boxtype.cxx     |   4 +-
 src/fl_draw.cxx        |   7 +-
 src/fl_draw_arrow.cxx  | 256 +++++++++++++++++++++++++++++++++++++++++++++++++
 15 files changed, 558 insertions(+), 164 deletions(-)

diff --git FL/Enumerations.H FL/Enumerations.H
index 365f3fa..11a7594 100644
--- FL/Enumerations.H
+++ FL/Enumerations.H
@@ -1,7 +1,7 @@
 //
 // Enumerations for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 1998-2020 by Bill Spitzak and others.
+// Copyright 1998-2022 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
@@ -1223,4 +1223,57 @@ enum Fl_Damage {
 
 // FLTK 1.0.x compatibility definitions (FLTK_1_0_COMPAT) dropped in 1.4.0
 
+/** Arrow types define the type of arrow drawing function.
+
+  FLTK schemes can draw several graphical elements in their particular way.
+  One of these elements is an arrow type that can be in different GUI
+  elements like scrollbars, choice buttons, and FLTK's Fl_Return_Button.
+
+  \note This enum is not yet stable (as of FLTK 1.4.0) and may be changed
+    without notice as necessary.
+
+  \since 1.4.0
+*/
+
+enum Fl_Arrow_Type {
+  FL_ARROW_SINGLE = 0x01, ///< Single arrow, e.g. in Fl_Scrollbar
+  FL_ARROW_DOUBLE = 0x02, ///< Double arrow, e.g. in Fl_Counter
+  FL_ARROW_CHOICE = 0x03, ///< Dropdown box, e.g. in Fl_Choice
+  FL_ARROW_RETURN = 0x04  ///< Return arrow, e.g. in Fl_Return_Button
+};
+
+/** Fl_Orientation describes the orientation of a GUI element.
+
+  FLTK schemes can draw several graphical elements, for instance arrows,
+  pointing at different directions. This enum defines the direction
+  to use for drawing a particular GUI element.
+
+  The definition of this enum was chosen such that the enum value can
+  be multiplied by 45 to get a rotation angle in degrees starting
+  at the horizontal axis (0 = right, 1 = NE, 2 = up, ...) that can be
+  used with fl_rotate(). Note: angle is counter-clockwise in degrees.
+
+  The 'unspecified' value \b FL_ORIENT_NONE shall be used for elements
+  that would usually not be rotated, like the return arrow of the
+  Fl_Return_Button. It can still be used as an angle though since it is
+  the same value as \p FL_ORIENT_RIGHT (0 degrees).
+
+  \note This enum is not yet stable (as of FLTK 1.4.0) and may be changed
+    without notice as necessary.
+
+  \since 1.4.0
+*/
+
+enum Fl_Orientation {
+  FL_ORIENT_NONE  = 0x00, ///< GUI element direction is unspecified
+  FL_ORIENT_RIGHT = 0x00, ///< GUI element pointing right (  0°)
+  FL_ORIENT_NE    = 0x01, ///< GUI element pointing NE    ( 45°)
+  FL_ORIENT_UP    = 0x02, ///< GUI element pointing up    ( 90°)
+  FL_ORIENT_NW    = 0x03, ///< GUI element pointing NW    (135°)
+  FL_ORIENT_LEFT  = 0x04, ///< GUI element pointing left  (180°)
+  FL_ORIENT_SW    = 0x05, ///< GUI element pointing SW    (225°)
+  FL_ORIENT_DOWN  = 0x06, ///< GUI element pointing down  (270°)
+  FL_ORIENT_SE    = 0x07  ///< GUI element pointing SE    (315°)
+};
+
 #endif
diff --git FL/Fl_Counter.H FL/Fl_Counter.H
index 7553416..fc1ce48 100644
--- FL/Fl_Counter.H
+++ FL/Fl_Counter.H
@@ -49,7 +49,7 @@ class FL_EXPORT Fl_Counter : public Fl_Valuator {
   Fl_Fontsize textsize_;
   Fl_Color textcolor_;
   double lstep_;
-  uchar mouseobj;
+  uchar mouseobj_;
   static void repeat_callback(void *);
   int calc_mouseobj();
   void increment_cb();
@@ -57,6 +57,8 @@ class FL_EXPORT Fl_Counter : public Fl_Valuator {
 protected:
 
   void draw();
+  // compute widths of arrow boxes
+  void arrow_widths(int &w1, int &w2);
 
 public:
 
diff --git FL/Fl_Spinner.H FL/Fl_Spinner.H
index 541078a..aa5442f 100644
--- FL/Fl_Spinner.H
+++ FL/Fl_Spinner.H
@@ -1,7 +1,7 @@
 //
 // Spinner widget for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 1998-2017 by Bill Spitzak and others.
+// Copyright 1998-2022 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
@@ -66,6 +66,8 @@ protected:
                 up_button_,             // Up button
                 down_button_;           // Down button
 
+  virtual void draw();
+
 public:
 
   // Constructor
diff --git FL/fl_draw.H FL/fl_draw.H
index f30c338..359405b 100644
--- FL/fl_draw.H
+++ FL/fl_draw.H
@@ -1,7 +1,7 @@
 //
 // Portable drawing function header file for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 1998-2021 by Bill Spitzak and others.
+// Copyright 1998-2022 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
@@ -250,15 +250,15 @@ 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_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_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
@@ -939,6 +939,9 @@ FL_EXPORT void fl_draw_box(Fl_Boxtype, int x, int y, int w, int h, Fl_Color);
 // Draw a check mark in the given color inside the bounding box bb.
 void fl_draw_check(Fl_Rect bb, Fl_Color col);
 
+// Draw one or more "arrows" (triangles)
+FL_EXPORT void fl_draw_arrow(Fl_Rect bb, Fl_Arrow_Type t, Fl_Orientation o, Fl_Color color);
+
 // images:
 
 /**
diff --git src/CMakeLists.txt src/CMakeLists.txt
index b8b773d..a912dc5 100644
--- src/CMakeLists.txt
+++ src/CMakeLists.txt
@@ -136,6 +136,7 @@ set (CPPFILES
   fl_curve.cxx
   fl_diamond_box.cxx
   fl_draw.cxx
+  fl_draw_arrow.cxx
   fl_draw_pixmap.cxx
   fl_encoding_latin1.cxx
   fl_encoding_mac_roman.cxx
diff --git src/Fl_Choice.cxx src/Fl_Choice.cxx
index 20b3744..c23010c 100644
--- src/Fl_Choice.cxx
+++ src/Fl_Choice.cxx
@@ -1,7 +1,7 @@
 //
 // Choice widget for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 1998-2015 by Bill Spitzak and others.
+// Copyright 1998-2022 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
@@ -22,6 +22,11 @@
 // Emulates the Forms choice widget.  This is almost exactly the same
 // as an Fl_Menu_Button.  The only difference is the appearance of the
 // button: it draws the text of the current pick and a down-arrow.
+// The exact layout and the type of arrow can vary by FLTK scheme.
+
+// FIXME: all such variations should be implemented in the "scheme code",
+// hopefully in a future class derived from a base class Fl_Scheme or similar.
+// Albrecht
 
 void Fl_Choice::draw() {
   Fl_Boxtype btype = Fl::scheme() ? FL_UP_BOX           // non-default uses up box
@@ -32,70 +37,74 @@ void Fl_Choice::draw() {
   // Arrow area
   int H = h() - 2 * dy;
   int W = Fl::is_scheme("gtk+")    ? 20 :                       // gtk+  -- fixed size
-          Fl::is_scheme("gleam")   ? 20 :                       // gleam -- fixed size
-          Fl::is_scheme("plastic") ? ((H > 20) ? 20 : H)        // plastic: shrink if H<20
-                                   : ((H > 20) ? 20 : H);       // default: shrink if H<20
+          Fl::is_scheme("gleam")   ? 20                         // gleam -- fixed size
+                                   : ((H > 20) ? 20 : H);       // else: shrink if H<20
   int X = x() + w() - W - dx;
   int Y = y() + dy;
 
-  // Arrow object
-  int w1 = (W - 4) / 3; if (w1 < 1) w1 = 1;
-  int x1 = X + (W - 2 * w1 - 1) / 2;
-  int y1 = Y + (H - w1 - 1) / 2;
+  Fl_Rect ab(X, Y, W, H); // arrow box
+  int active = active_r();
+  Fl_Color arrow_color = active ? labelcolor() : fl_inactive(labelcolor());
+  Fl_Color box_color = color();
+
+  // From "original" code: modify the box color *only* for the default scheme.
+  // This is weird (why?). I believe we should either make sure that the text
+  // color contrasts well when the text is rendered *or* we should do this for
+  // *all* schemes. Anyway, adapting the old code... (Albrecht)
+
+  if (!Fl::scheme()) {            // default scheme only, see comment above
+    if (fl_contrast(textcolor(), FL_BACKGROUND2_COLOR) == textcolor())
+      box_color = FL_BACKGROUND2_COLOR;
+    else
+      box_color = fl_lighter(color());
+  }
 
-  if (Fl::scheme()) {
-    // NON-DEFAULT SCHEME
+  // Draw the widget box
 
-    // Draw widget box
-    draw_box(btype, color());
+  draw_box(btype, box_color);
 
-    // Draw arrow area
-    fl_color(active_r() ? labelcolor() : fl_inactive(labelcolor()));
-    if (Fl::is_scheme("plastic")) {
-      // Show larger up/down arrows...
-      fl_polygon(x1, y1 + 3, x1 + w1, y1 + w1 + 3, x1 + 2 * w1, y1 + 3);
-      fl_polygon(x1, y1 + 1, x1 + w1, y1 - w1 + 1, x1 + 2 * w1, y1 + 1);
-    } else {
-      // Show smaller up/down arrows with a divider...
-      x1 = x() + w() - 13 - dx;
-      y1 = y() + h() / 2;
-      fl_polygon(x1, y1 - 2, x1 + 3, y1 - 5, x1 + 6, y1 - 2);
-      fl_polygon(x1, y1 + 2, x1 + 3, y1 + 5, x1 + 6, y1 + 2);
+  // Arrow box or horizontal divider line, depending on the current scheme
+
+  // Scheme:          Box or divider line
+  // ----------------------------------------
+  // Default (None):  Arrow box (FL_UP_BOX)
+  // gtk+, gleam:     Divider line
+  // else:            Nothing (!)
+
+  if (Fl::scheme()) {
+    if (Fl::is_scheme("gtk+") ||
+        Fl::is_scheme("gleam")) {
+      // draw the divider
+      int x1 = x() + w() - 20 - dx;
+      int y1 = y() + h() / 2;
 
       fl_color(fl_darker(color()));
-      fl_yxline(x1 - 7, y1 - 8, y1 + 8);
+      fl_yxline(x1, y1 - 8, y1 + 8);
 
       fl_color(fl_lighter(color()));
-      fl_yxline(x1 - 6, y1 - 8, y1 + 8);
-    }
-  } else {
-    // DEFAULT SCHEME
-
-    // Draw widget box
-    if (fl_contrast(textcolor(), FL_BACKGROUND2_COLOR) == textcolor()) {
-      draw_box(btype, FL_BACKGROUND2_COLOR);
-    } else {
-      draw_box(btype, fl_lighter(color()));
+      fl_yxline(x1 + 1, y1 - 8, y1 + 8);
     }
-
-    // Draw arrow area
-    draw_box(FL_UP_BOX,X,Y,W,H,color());
-    fl_color(active_r() ? labelcolor() : fl_inactive(labelcolor()));
-    fl_polygon(x1, y1, x1 + w1, y1 + w1, x1 + 2 * w1, y1);
+  } else { // Default scheme ("None")
+    // Draw arrow box
+    draw_box(FL_UP_BOX, X, Y, W, H, color());
+    ab.inset(FL_UP_BOX);
   }
 
+  // Draw choice arrow(s)
+  fl_draw_arrow(ab, FL_ARROW_CHOICE, FL_ORIENT_NONE, arrow_color);
+
   W += 2 * dx;
 
   // Draw menu item's label
   if (mvalue()) {
     Fl_Menu_Item m = *mvalue();
-    if (active_r()) m.activate(); else m.deactivate();
+    if (active) m.activate(); else m.deactivate();
 
     // Clip
     int xx = x() + dx, yy = y() + dy + 1, ww = w() - W, hh = H - 2;
     fl_push_clip(xx, yy, ww, hh);
 
-    if ( Fl::scheme()) {
+    if (Fl::scheme()) {
       Fl_Label l;
       l.value = m.text;
       l.image = 0;
diff --git src/Fl_Counter.cxx src/Fl_Counter.cxx
index ed856c2..9a9b4bb 100644
--- src/Fl_Counter.cxx
+++ src/Fl_Counter.cxx
@@ -19,67 +19,118 @@
 #include <FL/Fl_Simple_Counter.H>
 #include <FL/fl_draw.H>
 
-void Fl_Counter::draw() {
-  int i; Fl_Boxtype boxtype[5];
-  Fl_Color selcolor;
-
-  boxtype[0] = box();
-  if (boxtype[0] == FL_UP_BOX) boxtype[0] = FL_DOWN_BOX;
-  if (boxtype[0] == FL_THIN_UP_BOX) boxtype[0] = FL_THIN_DOWN_BOX;
-  for (i=1; i<5; i++)
-    if (mouseobj == i)
-      boxtype[i] = fl_down(box());
-    else
-      boxtype[i] = box();
+// This struct describes the four arrow boxes
+struct arrow_box {
+  int width;
+  Fl_Arrow_Type arrow_type;
+  Fl_Boxtype boxtype;
+  Fl_Orientation orientation;
+  arrow_box() { // constructor
+    width = 0;
+    boxtype = FL_NO_BOX;
+    orientation = FL_ORIENT_RIGHT;
+    arrow_type = FL_ARROW_SINGLE;
+  }
+};
 
-  int xx[5], ww[5];
-  if (type() == FL_NORMAL_COUNTER) {
-    int W = w()*15/100;
-    xx[1] = x();         ww[1] = W;
-    xx[2] = x()+1*W;     ww[2] = W;
-    xx[0] = x()+2*W;     ww[0] = w()-4*W;
-    xx[3] = x()+w()-2*W; ww[3] = W;
-    xx[4] = x()+w()-1*W; ww[4] = W;
+/**
+  Compute sizes (widths) of arrow boxes.
+
+  This method computes the two sizes of the arrow boxes of Fl_Counter.
+  You can override it in a subclass if you want to draw fancy arrows
+  or change the layout. However, the basic layout is fixed and can't
+  be changed w/o overriding the draw() and handle() methods.
+
+  Basic layout:
+  \code
+    +------+-----+-------------+-----+------+
+    |  <<  |  <  |    value    |  >  |  >>  |
+    +------+-----+-------------+-----+------+
+  \endcode
+
+  The returned value \p w2 should be zero if the counter type() is FL_SIMPLE_COUNTER.
+
+  \param[out]   w1  width of single arrow box
+  \param[out]   w2  width of double arrow box
+*/
+void Fl_Counter::arrow_widths(int &w1, int &w2) {
+  if (type() == FL_SIMPLE_COUNTER) {
+    w1 = w() * 20/100;
+    w2 = 0;
   } else {
-    int W = w()*20/100;
-    xx[1] = 0;           ww[1] = 0;
-    xx[2] = x();         ww[2] = W;
-    xx[0] = x()+W;       ww[0] = w()-2*W;
-    xx[3] = x()+w()-1*W; ww[3] = W;
-    xx[4] = 0;           ww[4] = 0;
+    w1 = w() * 13/100;
+    w2 = w() * 17/100;
   }
+  // limit arrow box sizes to reserve more space for the text box
+  if (w1 > 18) w1 = 18;
+  if (w2 > 24) w2 = 24;
+}
+
+void Fl_Counter::draw() {
+  struct arrow_box ab[4];
+
+  // text box setup
+  Fl_Boxtype tbt = box();
+  if (tbt == FL_UP_BOX) tbt = FL_DOWN_BOX;
+  if (tbt == FL_THIN_UP_BOX) tbt = FL_THIN_DOWN_BOX;
 
-  draw_box(boxtype[0], xx[0], y(), ww[0], h(), FL_BACKGROUND2_COLOR);
+  // array boxes
+  for (int i = 0; i < 4; i++) {
+    if (mouseobj_ == i + 1)
+      ab[i].boxtype = fl_down(box());
+    else
+      ab[i].boxtype = box();
+  }
+
+  ab[0].arrow_type = ab[3].arrow_type = FL_ARROW_DOUBLE;      // first and last arrow
+  ab[0].orientation = ab[1].orientation = FL_ORIENT_LEFT;     // left arrows
+
+  int w1 = 0, w2 = 0;
+  arrow_widths(w1, w2);
+  if (type() == FL_SIMPLE_COUNTER)
+    w2 = 0;
+
+  ab[0].width = ab[3].width = w2;          // double arrows
+  ab[1].width = ab[2].width = w1;          // single arrows
+
+  int tw = w() - 2 * (w1 + w2); // text box width
+  int tx = x() + w1 + w2;       // text box position
+
+  // printf("w() = %3d, w1 = %3d, w2 = %3d, tw = %3d\n", w(), w1, w2, tw);
+
+  // always draw text box and text
+  draw_box(tbt, tx, y(), tw, h(), FL_BACKGROUND2_COLOR);
   fl_font(textfont(), textsize());
   fl_color(active_r() ? textcolor() : fl_inactive(textcolor()));
   char str[128]; format(str);
-  fl_draw(str, xx[0], y(), ww[0], h(), FL_ALIGN_CENTER);
-  if (Fl::focus() == this) draw_focus(boxtype[0], xx[0], y(), ww[0], h());
+  fl_draw(str, tx, y(), tw, h(), FL_ALIGN_CENTER);
+  if (Fl::focus() == this) draw_focus(tbt, tx, y(), tw, h());
   if (!(damage()&FL_DAMAGE_ALL)) return; // only need to redraw text
 
+  Fl_Color arrow_color;
   if (active_r())
-    selcolor = labelcolor();
+    arrow_color = labelcolor();
   else
-    selcolor = fl_inactive(labelcolor());
+    arrow_color = fl_inactive(labelcolor());
 
-  if (type() == FL_NORMAL_COUNTER) {
-    draw_box(boxtype[1], xx[1], y(), ww[1], h(), color());
-    fl_draw_symbol("@-4<<", xx[1], y(), ww[1], h(), selcolor);
-  }
-  draw_box(boxtype[2], xx[2], y(), ww[2], h(), color());
-  fl_draw_symbol("@-4<",  xx[2], y(), ww[2], h(), selcolor);
-  draw_box(boxtype[3], xx[3], y(), ww[3], h(), color());
-  fl_draw_symbol("@-4>",  xx[3], y(), ww[3], h(), selcolor);
-  if (type() == FL_NORMAL_COUNTER) {
-    draw_box(boxtype[4], xx[4], y(), ww[4], h(), color());
-    fl_draw_symbol("@-4>>", xx[4], y(), ww[4], h(), selcolor);
+  // draw arrow boxes
+  int xo = x();
+  for (int i = 0; i < 4; i++) {
+    if (ab[i].width > 0) {
+      draw_box(ab[i].boxtype, xo, y(), ab[i].width, h(), color());
+      Fl_Rect bb(xo, y(), ab[i].width, h(), ab[i].boxtype);
+      fl_draw_arrow(bb, ab[i].arrow_type, ab[i].orientation, arrow_color);
+      xo += ab[i].width;
+    }
+    if (i == 1) xo += tw;
   }
-}
+
+} // draw()
 
 void Fl_Counter::increment_cb() {
-  if (!mouseobj) return;
+  if (!mouseobj_) return;
   double v = value();
-  switch (mouseobj) {
+  switch (mouseobj_) {
   case 1: v -= lstep_; break;
   case 2: v = increment(v, -1); break;
   case 3: v = increment(v, 1); break;
@@ -95,7 +146,7 @@ void Fl_Counter::repeat_callback(void* v) {
   Fl_Counter* b = (Fl_Counter*)v;
   int buttons = Fl::event_state() & FL_BUTTONS; // any mouse button pressed
   int focus = (Fl::focus() == b);               // the widget has focus
-  if (b->mouseobj && buttons && focus) {
+  if (b->mouseobj_ && buttons && focus) {
     Fl::add_timeout(REPEAT, repeat_callback, b);
     b->increment_cb();
   }
@@ -120,9 +171,9 @@ int Fl_Counter::handle(int event) {
   int i;
   switch (event) {
   case FL_RELEASE:
-    if (mouseobj) {
+    if (mouseobj_) {
       Fl::remove_timeout(repeat_callback, this);
-      mouseobj = 0;
+      mouseobj_ = 0;
       redraw();
     }
     handle_release();
@@ -135,9 +186,9 @@ int Fl_Counter::handle(int event) {
     }
   case FL_DRAG:
     i = calc_mouseobj();
-    if (i != mouseobj) {
+    if (i != mouseobj_) {
       Fl::remove_timeout(repeat_callback, this);
-      mouseobj = (uchar)i;
+      mouseobj_ = (uchar)i;
       if (i > 0)
         Fl::add_timeout(INITIALREPEAT, repeat_callback, this);
       Fl_Widget_Tracker wp(this);
@@ -159,7 +210,7 @@ int Fl_Counter::handle(int event) {
     }
     // break not required because of switch...
   case FL_UNFOCUS :
-    mouseobj = 0;
+    mouseobj_ = 0;
     /* FALLTHROUGH */
   case FL_FOCUS :
     if (Fl::visible_focus()) {
@@ -195,7 +246,7 @@ Fl_Counter::Fl_Counter(int X, int Y, int W, int H, const char* L)
   bounds(-1000000.0, 1000000.0);
   Fl_Valuator::step(1, 10);
   lstep_ = 1.0;
-  mouseobj = 0;
+  mouseobj_ = 0;
   textfont_ = FL_HELVETICA;
   textsize_ = FL_NORMAL_SIZE;
   textcolor_ = FL_FOREGROUND_COLOR;
diff --git src/Fl_Menu.cxx src/Fl_Menu.cxx
index 20eabaf..06a7e92 100644
--- src/Fl_Menu.cxx
+++ src/Fl_Menu.cxx
@@ -1,7 +1,7 @@
 //
 // Menu code for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 1998-2015 by Bill Spitzak and others.
+// Copyright 1998-2022 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
@@ -496,6 +496,7 @@ void menuwindow::drawentry(const Fl_Menu_Item* m, int n, int eraseit) {
     int sz = (hh-7)&-2;
     int y1 = yy+(hh-sz)/2;
     int x1 = xx+ww-sz-3;
+    // FIXME_ARROW: use fl_draw_arrow()
     fl_polygon(x1+2, y1, x1+2, y1+sz, x1+sz/2+2, y1+sz/2);
   } else if (m->shortcut_) {
     Fl_Font f = m->labelsize_ || m->labelfont_ ? (Fl_Font)m->labelfont_ :
diff --git src/Fl_Menu_Button.cxx src/Fl_Menu_Button.cxx
index 5b69ea7..dadbaf5 100644
--- src/Fl_Menu_Button.cxx
+++ src/Fl_Menu_Button.cxx
@@ -1,7 +1,7 @@
 //
 // Menu button widget for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 1998-2019 by Bill Spitzak and others.
+// Copyright 1998-2022 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
@@ -31,6 +31,7 @@ void Fl_Menu_Button::draw() {
   draw_label(x()+Fl::box_dx(box()), y(), X-x()+2, h());
   if (Fl::focus() == this) draw_focus();
   // ** if (box() == FL_FLAT_BOX) return; // for XForms compatibility
+  // FIXME_ARROW: use fl_draw_arrow()
   fl_color(active_r() ? FL_DARK3 : fl_inactive(FL_DARK3));
   fl_line(X+H/2, Y+H, X, Y, X+H, Y);
   fl_color(active_r() ? FL_LIGHT3 : fl_inactive(FL_LIGHT3));
diff --git src/Fl_Scrollbar.cxx src/Fl_Scrollbar.cxx
index 64071db..d8d42ce 100644
--- src/Fl_Scrollbar.cxx
+++ src/Fl_Scrollbar.cxx
@@ -1,7 +1,7 @@
 //
 // Scroll bar widget for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 1998-2015 by Bill Spitzak and others.
+// Copyright 1998-2022 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
@@ -196,61 +196,56 @@ int Fl_Scrollbar::handle(int event) {
 }
 
 void Fl_Scrollbar::draw() {
-  if (damage()&FL_DAMAGE_ALL) draw_box();
-  int X = x()+Fl::box_dx(box());
-  int Y = y()+Fl::box_dy(box());
-  int W = w()-Fl::box_dw(box());
-  int H = h()-Fl::box_dh(box());
+  if (damage() & FL_DAMAGE_ALL) draw_box();
+  int X = x() + Fl::box_dx(box());
+  int Y = y() + Fl::box_dy(box());
+  int W = w() - Fl::box_dw(box());
+  int H = h() - Fl::box_dh(box());
+  Fl_Rect ab; // arrow box
+
+  int inset = 3;
+  if (W < 8 || H < 8)
+    inset = 2;
+
   if (horizontal()) {
-    if (W < 3*H) {Fl_Slider::draw(X,Y,W,H); return;}
-    Fl_Slider::draw(X+H,Y,W-2*H,H);
+    if (W < 3*H) {
+      Fl_Slider::draw(X, Y, W, H);
+      return;
+    }
+    Fl_Slider::draw(X+H, Y, W-2*H, H);
     if (damage()&FL_DAMAGE_ALL) {
       draw_box((pushed_==1) ? fl_down(slider()) : slider(),
                X, Y, H, H, selection_color());
       draw_box((pushed_==2) ? fl_down(slider()) : slider(),
                X+W-H, Y, H, H, selection_color());
-      if (active_r())
-        fl_color(labelcolor());
-      else
-        fl_color(fl_inactive(labelcolor()));
-      int w1 = (H-4)/3; if (w1 < 1) w1 = 1;
-      int x1 = X+(H-w1-1)/2;
-      int yy1 = Y+(H-2*w1-1)/2;
-      if (Fl::is_scheme("gtk+")) {
-        fl_polygon(x1, yy1+w1, x1+w1, yy1+2*w1, x1+w1-1, yy1+w1, x1+w1, yy1);
-        x1 += (W-H);
-        fl_polygon(x1, yy1, x1+1, yy1+w1, x1, yy1+2*w1, x1+w1, yy1+w1);
-      } else {
-        fl_polygon(x1, yy1+w1, x1+w1, yy1+2*w1, x1+w1, yy1);
-        x1 += (W-H);
-        fl_polygon(x1, yy1, x1, yy1+2*w1, x1+w1, yy1+w1);
-      }
+
+      Fl_Color arrowcolor = active_r() ? labelcolor() : fl_inactive(labelcolor());
+      ab = Fl_Rect(X, Y, H, H);
+      ab.inset(inset);
+      fl_draw_arrow(ab, FL_ARROW_SINGLE, FL_ORIENT_LEFT, arrowcolor); // left arrow
+      ab = Fl_Rect(X+W-H, Y, H, H);
+      ab.inset(inset);
+      fl_draw_arrow(ab, FL_ARROW_SINGLE, FL_ORIENT_RIGHT, arrowcolor); // right arrow
     }
   } else { // vertical
-    if (H < 3*W) {Fl_Slider::draw(X,Y,W,H); return;}
-    Fl_Slider::draw(X,Y+W,W,H-2*W);
-    if (damage()&FL_DAMAGE_ALL) {
+    if (H < 3*W) {
+      Fl_Slider::draw(X, Y, W, H);
+      return;
+    }
+    Fl_Slider::draw(X, Y+W, W, H-2*W);
+    if (damage() & FL_DAMAGE_ALL) {
       draw_box((pushed_==1) ? fl_down(slider()) : slider(),
                X, Y, W, W, selection_color());
       draw_box((pushed_==2) ? fl_down(slider()) : slider(),
                X, Y+H-W, W, W, selection_color());
-      if (active_r())
-        fl_color(labelcolor());
-      else
-        fl_color(fl_inactive(labelcolor()));
-      int w1 = (W-4)/3; if (w1 < 1) w1 = 1;
-      int x1 = X+(W-2*w1-1)/2;
-      int yy1 = Y+(W-w1-1)/2;
-      if (Fl::is_scheme("gtk+")) {
-        fl_polygon(x1, yy1+w1, x1+w1, yy1+w1-1, x1+2*w1, yy1+w1, x1+w1, yy1);
-        yy1 += H-W;
-        fl_polygon(x1, yy1, x1+w1, yy1+1, x1+w1, yy1+w1);
-        fl_polygon(x1+w1, yy1+1, x1+2*w1, yy1, x1+w1, yy1+w1);
-      } else {
-        fl_polygon(x1, yy1+w1, x1+2*w1, yy1+w1, x1+w1, yy1);
-        yy1 += H-W;
-        fl_polygon(x1, yy1, x1+w1, yy1+w1, x1+2*w1, yy1);
-      }
+
+      Fl_Color arrowcolor = active_r() ? labelcolor() : fl_inactive(labelcolor());
+      ab = Fl_Rect(X, Y, W, W);
+      ab.inset(inset);
+      fl_draw_arrow(ab, FL_ARROW_SINGLE, FL_ORIENT_UP, arrowcolor); // up arrow
+      ab = Fl_Rect(X, Y+H-W, W, W);
+      ab.inset(inset);
+      fl_draw_arrow(ab, FL_ARROW_SINGLE, FL_ORIENT_DOWN, arrowcolor); // down arrow
     }
   }
 }
diff --git src/Fl_Spinner.cxx src/Fl_Spinner.cxx
index 51657d8..a298d18 100644
--- src/Fl_Spinner.cxx
+++ src/Fl_Spinner.cxx
@@ -1,7 +1,7 @@
 //
 // Spinner widget for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 1998-2017 by Bill Spitzak and others.
+// Copyright 1998-2022 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
@@ -21,6 +21,8 @@
 #include <stdlib.h>
 
 #include <FL/Fl_Spinner.H>
+#include <FL/Fl_Rect.H>
+#include <FL/fl_draw.H>
 
 /*
   This widget is a combination of the input widget and repeat buttons.
@@ -91,9 +93,6 @@ void Fl_Spinner::update() {
   input_.value(s);
 }
 
-#define FL_UP_ARROW_TX "@-42<"
-#define FL_DOWN_ARROW_TX "@-42>"
-
 /**
   Creates a new Fl_Spinner widget using the given position, size,
   and label string.
@@ -104,9 +103,8 @@ void Fl_Spinner::update() {
 Fl_Spinner::Fl_Spinner(int X, int Y, int W, int H, const char *L)
 : Fl_Group(X, Y, W, H, L),
   input_(X, Y, W - H / 2 - 2, H),
-  up_button_(X + W - H / 2 - 2, Y, H / 2 + 2, H / 2, FL_UP_ARROW_TX),
-  down_button_(X + W - H / 2 - 2, Y + H - H / 2,
-               H / 2 + 2, H / 2, FL_DOWN_ARROW_TX)
+  up_button_(X + W - H / 2 - 2, Y, H / 2 + 2, H / 2),
+  down_button_(X + W - H / 2 - 2, Y + H - H / 2, H / 2 + 2, H / 2)
 {
   end();
 
@@ -129,6 +127,26 @@ Fl_Spinner::Fl_Spinner(int X, int Y, int W, int H, const char *L)
   down_button_.callback((Fl_Callback *)sb_cb, this);
 }
 
+void Fl_Spinner::draw() {
+
+  // draw the box and the input widget
+
+  draw_box();
+  ((Fl_Widget&)input_).draw();
+
+  // draw the buttons and the up and down arrows as their "labels"
+
+  ((Fl_Widget&)up_button_).draw();
+  Fl_Rect up(up_button_);
+  up.inset(up_button_.box());
+  fl_draw_arrow(up, FL_ARROW_SINGLE, FL_ORIENT_UP, labelcolor());
+
+  ((Fl_Widget&)down_button_).draw();
+  Fl_Rect down(down_button_);
+  down.inset(down_button_.box());
+  fl_draw_arrow(down, FL_ARROW_SINGLE, FL_ORIENT_DOWN, labelcolor());
+}
+
 int Fl_Spinner::handle(int event) {
 
   switch (event) {
diff --git src/Makefile src/Makefile
index 0964f7b..388f69b 100644
--- src/Makefile
+++ src/Makefile
@@ -139,6 +139,7 @@ CPPFILES = \
 	fl_curve.cxx \
 	fl_diamond_box.cxx \
 	fl_draw.cxx \
+	fl_draw_arrow.cxx \
 	fl_draw_pixmap.cxx \
 	fl_encoding_latin1.cxx \
 	fl_encoding_mac_roman.cxx \
diff --git src/fl_boxtype.cxx src/fl_boxtype.cxx
index ae60727..920205b 100644
--- src/fl_boxtype.cxx
+++ src/fl_boxtype.cxx
@@ -1,7 +1,7 @@
 //
 // Box drawing code for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 1998-2020 by Bill Spitzak and others.
+// Copyright 1998-2022 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
@@ -415,7 +415,7 @@ Fl_Box_Draw_F *Fl::get_boxtype(Fl_Boxtype t) {
 }
 /** Sets the function to call to draw a specific boxtype. */
 void Fl::set_boxtype(Fl_Boxtype t, Fl_Box_Draw_F* f,
-                      uchar a, uchar b, uchar c, uchar d) {
+                     uchar a, uchar b, uchar c, uchar d) {
   fl_box_table[t].f   = f;
   fl_box_table[t].set = 1;
   fl_box_table[t].dx  = a;
diff --git src/fl_draw.cxx src/fl_draw.cxx
index 2f91243..468d032 100644
--- src/fl_draw.cxx
+++ src/fl_draw.cxx
@@ -1,7 +1,7 @@
 //
 // Label drawing code for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 1998-2020 by Bill Spitzak and others.
+// Copyright 1998-2022 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
@@ -249,8 +249,9 @@ void fl_draw(
   if (str) {
     int desc = fl_descent();
     for (p=str; ; ypos += height) {
-      if (lines>1) e = expand_text_(p, linebuf, 0, w - symtotal - imgtotal, buflen,
-                                width, align&FL_ALIGN_WRAP, draw_symbols);
+      if (lines>1)
+        e = expand_text_(p, linebuf, 0, w - symtotal - imgtotal, buflen,
+                         width, align&FL_ALIGN_WRAP, draw_symbols);
       else e = "";
 
       if (width > symoffset) symoffset = (int)(width + 0.5);
diff --git src/fl_draw_arrow.cxx src/fl_draw_arrow.cxx
new file mode 100644
index 0000000..2aef438
--- /dev/null
+++ src/fl_draw_arrow.cxx
@@ -0,0 +1,256 @@
+//
+// Arrow drawing code for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2022 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
+//
+
+// These functions implement drawing of all "arrow like" GUI elements in scrollbars,
+// choice widgets, menus, etc.
+
+// Implementation of fl_draw_arrow(...) dependent on the active FLTK Scheme.
+
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+#include <FL/fl_utf8.h>
+
+#ifndef DEBUG_ARROW
+#define DEBUG_ARROW (0)         // 0 = off, 1 = green background, 2 = red frame, 3 = both
+#endif
+
+void debug_arrow(Fl_Rect r) {
+
+#if (DEBUG_ARROW & 1)
+  fl_color(fl_lighter(FL_GREEN));
+  fl_rectf(r);
+#endif
+
+#if (DEBUG_ARROW & 2)
+  fl_color(FL_RED);
+  fl_line_style(FL_SOLID, 1);  // work around X11 bug with default line width 0
+  fl_rect(r);
+  fl_line_style(FL_SOLID, 0);  // reset line style
+#endif
+
+} // debug_arrow
+
+// Calculate the applicable arrow size.
+// Imagine an arrow pointing to the right side:
+// - the calculated size s is the width of the arrow,
+// - the height of the arrow is 2 * s.
+// The calculation takes into account that we need one pixel padding at
+// all sides and that the available space doesn't need to be a square,
+// i.e. it's possible that r.w() != r.h().
+
+static int arrow_size(Fl_Rect r, Fl_Orientation o, int num = 1) {
+
+  int s, d1, d2;
+
+  switch(o) {
+    case FL_ORIENT_LEFT:
+    case FL_ORIENT_RIGHT:
+      d1 = (r.w() - 2) / num;
+      d2 = (r.h() - 2) / 2;
+      break;
+    default:  // up or down arrow
+      d1 = (r.h() - 2) / num;
+      d2 = (r.w() - 2) / 2;
+      break;
+  }
+  s = d1 < d2 ? d1 : d2;
+  if (s < 2) s = 2;
+  else if (s > 6) s = 6;
+  return s;
+}
+
+// Draw a "Single Arrow" in an arbitrary direction (0°, 90°, 180°, 270°).
+// This is the basic arrow drawing function for all "standard" widgets.
+// It is used in Fl_Scrollbars and similar and in all combinations, for
+// instance when "Double Arrows" or other combinations are needed.
+
+static int fl_draw_arrow_single(Fl_Rect r, Fl_Orientation o, Fl_Color col, int d = -1) {
+
+  int x1, y1;
+
+  x1 = r.x();
+  y1 = r.y();
+  if (d < 0)
+    d = arrow_size(r, o);
+
+  fl_color(col);
+
+  switch(o) {
+
+    case FL_ORIENT_LEFT:
+      x1 += (r.w()-d)/2 - 1;
+      y1 += r.h()/2;
+      if (Fl::is_scheme("gtk+"))
+        fl_polygon(x1, y1, x1+d, y1-d, x1+d-1, y1, x1+d, y1+d);
+      else
+        fl_polygon(x1, y1, x1+d, y1-d, x1+d, y1+d);
+      return 1;
+
+    case FL_ORIENT_RIGHT:
+      x1 += (r.w()-d)/2;
+      y1 += r.h()/2;
+      if (Fl::is_scheme("gtk+"))
+        fl_polygon(x1, y1-d, x1+1, y1, x1, y1+d, x1+d, y1);
+      else
+        fl_polygon(x1, y1-d, x1, y1+d, x1+d, y1);
+      return 1;
+
+    case FL_ORIENT_UP:
+      x1 += r.w()/2;
+      y1 += (r.h()-d)/2 - 1;
+      if (Fl::is_scheme("gtk+"))
+        fl_polygon(x1, y1, x1+d, y1+d, x1, y1+d-1, x1-d, y1+d);
+      else
+        fl_polygon(x1, y1, x1+d, y1+d, x1-d, y1+d);
+      return 1;
+
+    case FL_ORIENT_DOWN:
+      x1 += r.w()/2-d;
+      y1 += (r.h()-d)/2;
+      if (Fl::is_scheme("gtk+")) {
+        fl_polygon(x1, y1, x1+d, y1+1, x1+d, y1+d);
+        fl_polygon(x1+d, y1+1, x1+2*d, y1, x1+d, y1+d);
+      } else {
+        fl_polygon(x1, y1, x1+d, y1+d, x1+2*d, y1);
+      }
+      return 1;
+
+    default:            // orientation not handled: return error
+      return 0;
+  }
+  return 0;
+} // fl_draw_arrow_single()
+
+
+// Draw a "Double Arrow" in an arbitrary direction (0°, 90°, 180°, 270°).
+// This is the basic arrow drawing function for all "standard" widgets.
+// It is used in Fl_Scrollbars and similar and in all combinations, for
+// instance when "Double Arrows" or other combinations are needed.
+
+static int fl_draw_arrow_double(Fl_Rect r, Fl_Orientation o, Fl_Color col) {
+
+  int d = arrow_size(r, o, 2);
+  int x1 = r.x();
+  int y1 = r.y();
+  int da = (d+1)/2;
+
+  switch(o) {
+
+    case FL_ORIENT_LEFT:
+    case FL_ORIENT_RIGHT:
+      r.x(x1 - da);
+      fl_draw_arrow_single(r, o, col, d);
+      r.x(x1 + da);
+      return fl_draw_arrow_single(r, o, col, d);
+
+    case FL_ORIENT_UP:
+    case FL_ORIENT_DOWN:
+      r.y(y1 - da);
+      fl_draw_arrow_single(r, o, col, d);
+      r.y(y1 + da);
+      return fl_draw_arrow_single(r, o, col, d);
+
+    default:            // orientation not handled: return error
+      return 0;
+  }
+  return 0;
+} // fl_draw_arrow_double()
+
+
+// Draw a "Choice Arrow". The direction and type is determined by the scheme.
+
+static int fl_draw_arrow_choice(Fl_Rect r, Fl_Color col) {
+
+  int w1 = (r.w() - 4) / 3; if (w1 < 1) w1 = 1;
+  int x1 = r.x() + (r.w() - 2 * w1 - 1) / 2;
+  int y1 = r.y() + (r.h() - w1 - 1) / 2;
+
+  if (Fl::is_scheme("gtk+") ||
+      Fl::is_scheme("gleam")) {
+    // Show smaller up/down arrows ...
+    int x1 = r.x() + (r.w() - 6)/2;
+    int y1 = r.y() + r.h() / 2;
+    fl_color(col);
+    fl_polygon(x1, y1 - 2, x1 + 3, y1 - 5, x1 + 6, y1 - 2);
+    fl_polygon(x1, y1 + 2, x1 + 3, y1 + 5, x1 + 6, y1 + 2);
+    return 1;
+  }
+  else if (Fl::is_scheme("plastic")) {
+    // Show larger up/down arrows...
+    fl_color(col);
+    fl_polygon(x1, y1 + 3, x1 + w1, y1 + w1 + 3, x1 + 2 * w1, y1 + 3);
+    fl_polygon(x1, y1 + 1, x1 + w1, y1 - w1 + 1, x1 + 2 * w1, y1 + 1);
+    return 1;
+  }
+  else { // none, default             // single down arrow
+    return fl_draw_arrow_single(r, FL_ORIENT_DOWN, col);
+  }
+  return 0;
+} // fl_draw_arrow_double()
+
+
+/**
+  Draw an "arrow like" GUI element for the selected scheme.
+
+  In the future this function should be integrated in Fl_Scheme
+  as a virtual method, i.e. it would call a method like ...
+  \code
+    Fl_Scheme::current()->draw_arrow(r, t, o, col);
+  \endcode
+
+  \param[in]  r    bounding box
+  \param[in]  t    arrow type
+  \param[in]  o    orientation
+  \param[in]  col  arrow color
+*/
+
+void fl_draw_arrow(Fl_Rect r, Fl_Arrow_Type t, Fl_Orientation o, Fl_Color col) {
+
+  int ret = 0;
+  debug_arrow(r);
+
+  // implementation of all arrow types
+
+  switch(t) {
+    case FL_ARROW_SINGLE:
+      ret = fl_draw_arrow_single(r, o, col);
+      break;
+
+    case FL_ARROW_DOUBLE:
+      ret = fl_draw_arrow_double(r, o, col);
+      break;
+
+    case FL_ARROW_CHOICE:
+      ret = fl_draw_arrow_choice(r, col);
+      break;
+
+    default:        // unknown arrow type
+      ret = 0;
+      break;
+  }
+
+  // draw an error flag (red rectangle with cross) if not successful
+
+  if (!ret) {
+    fl_color(FL_RED);
+    fl_rectf(r);
+    fl_color(FL_BLACK);
+    fl_rect(r);
+    fl_line(r.x(), r.y(), r.r(), r.b());
+    fl_line(r.x(), r.b(), r.r(), r.y());
+  }
+
+} // fl_draw_arrow()
Direct Link to Message ]
 
     
Previous Message ]Next Message ]
 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.