Skip to content

Commit

Permalink
Refactor and simplify "arrow drawing" in widgets
Browse files Browse the repository at this point in the history
"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
  • Loading branch information
Albrecht Schlosser committed Nov 22, 2022
1 parent 4daec2a commit ecc47d0
Show file tree
Hide file tree
Showing 15 changed files with 558 additions and 164 deletions.
55 changes: 54 additions & 1 deletion FL/Enumerations.H
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
4 changes: 3 additions & 1 deletion FL/Fl_Counter.H
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,16 @@ 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();

protected:

void draw();
// compute widths of arrow boxes
void arrow_widths(int &w1, int &w2);

public:

Expand Down
4 changes: 3 additions & 1 deletion FL/Fl_Spinner.H
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -66,6 +66,8 @@ protected:
up_button_, // Up button
down_button_; // Down button

virtual void draw();

public:

// Constructor
Expand Down
21 changes: 12 additions & 9 deletions FL/fl_draw.H
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:

/**
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
93 changes: 51 additions & 42 deletions src/Fl_Choice.cxx
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -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;
Expand Down

0 comments on commit ecc47d0

Please sign in to comment.