diff options
| author | Albrecht Schlosser <albrechts.fltk@online.de> | 2020-11-22 19:19:19 +0100 |
|---|---|---|
| committer | Albrecht Schlosser <albrechts.fltk@online.de> | 2022-11-22 19:32:54 +0100 |
| commit | ecc47d0cc3e1784e17ac94829202f2bdbd38a682 (patch) | |
| tree | 2519c9b11a598ed4ad1faf9d07c205da5c4903c7 /src/fl_draw_arrow.cxx | |
| parent | 4daec2a9408c674f8d62f8770ec8c035c25f2294 (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/fl_draw_arrow.cxx')
| -rw-r--r-- | src/fl_draw_arrow.cxx | 256 |
1 files changed, 256 insertions, 0 deletions
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() |
