summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlbrecht Schlosser <albrechts.fltk@online.de>2020-11-22 19:19:19 +0100
committerAlbrecht Schlosser <albrechts.fltk@online.de>2022-11-22 19:32:54 +0100
commitecc47d0cc3e1784e17ac94829202f2bdbd38a682 (patch)
tree2519c9b11a598ed4ad1faf9d07c205da5c4903c7 /src
parent4daec2a9408c674f8d62f8770ec8c035c25f2294 (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/Fl_Choice.cxx93
-rw-r--r--src/Fl_Counter.cxx155
-rw-r--r--src/Fl_Menu.cxx3
-rw-r--r--src/Fl_Menu_Button.cxx3
-rw-r--r--src/Fl_Scrollbar.cxx83
-rw-r--r--src/Fl_Spinner.cxx32
-rw-r--r--src/Makefile1
-rw-r--r--src/fl_boxtype.cxx4
-rw-r--r--src/fl_draw.cxx7
-rw-r--r--src/fl_draw_arrow.cxx256
11 files changed, 486 insertions, 152 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b8b773d53..a912dc5c3 100644
--- a/src/CMakeLists.txt
+++ b/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 a/src/Fl_Choice.cxx b/src/Fl_Choice.cxx
index 20b374442..c23010c07 100644
--- a/src/Fl_Choice.cxx
+++ b/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 a/src/Fl_Counter.cxx b/src/Fl_Counter.cxx
index ed856c208..9a9b4bbfc 100644
--- a/src/Fl_Counter.cxx
+++ b/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 a/src/Fl_Menu.cxx b/src/Fl_Menu.cxx
index 20eabaf41..06a7e9278 100644
--- a/src/Fl_Menu.cxx
+++ b/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 a/src/Fl_Menu_Button.cxx b/src/Fl_Menu_Button.cxx
index 5b69ea703..dadbaf55c 100644
--- a/src/Fl_Menu_Button.cxx
+++ b/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 a/src/Fl_Scrollbar.cxx b/src/Fl_Scrollbar.cxx
index 64071dbe2..d8d42ce80 100644
--- a/src/Fl_Scrollbar.cxx
+++ b/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 a/src/Fl_Spinner.cxx b/src/Fl_Spinner.cxx
index 51657d87b..a298d189e 100644
--- a/src/Fl_Spinner.cxx
+++ b/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 a/src/Makefile b/src/Makefile
index 0964f7b00..388f69b23 100644
--- a/src/Makefile
+++ b/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 a/src/fl_boxtype.cxx b/src/fl_boxtype.cxx
index ae60727f1..920205b07 100644
--- a/src/fl_boxtype.cxx
+++ b/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 a/src/fl_draw.cxx b/src/fl_draw.cxx
index 2f91243a2..468d03251 100644
--- a/src/fl_draw.cxx
+++ b/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 a/src/fl_draw_arrow.cxx b/src/fl_draw_arrow.cxx
new file mode 100644
index 000000000..2aef43889
--- /dev/null
+++ b/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()