src/fl_draw.cxx: improve documentation, add \since 1.4.0, simplify scaling code, use forgotten 'color' argument to set the circle color. src/fl_draw_arrow.cxx: add doxygen \since statement
275 lines
7.1 KiB
C++
275 lines
7.1 KiB
C++
//
|
|
// Arrow drawing code for the Fast Light Tool Kit (FLTK).
|
|
//
|
|
// Copyright 1998-2023 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>
|
|
#include "fl_oxy.h"
|
|
|
|
// Debug mode: if you design a widget or want to check its layout,
|
|
// then enable one or both flags of DEBUG_ARROW (below) so you can
|
|
// see where the arrows (i.e. their bounding boxes) are positioned
|
|
|
|
#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
|
|
|
|
\since 1.4.0
|
|
*/
|
|
|
|
void fl_draw_arrow(Fl_Rect r, Fl_Arrow_Type t, Fl_Orientation o, Fl_Color col) {
|
|
|
|
int ret = 0;
|
|
Fl_Color saved_color = fl_color();
|
|
|
|
debug_arrow(r);
|
|
|
|
// special case: arrows for the "oxy" scheme
|
|
|
|
if (Fl::is_scheme("oxy")) {
|
|
oxy_arrow(r, t, o, col);
|
|
return;
|
|
}
|
|
|
|
// implementation of all arrow types for other schemes
|
|
|
|
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_color(saved_color);
|
|
|
|
} // fl_draw_arrow()
|