diff options
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() |
