Improve contrast of check marks and radio buttons (#443)

- add fl_draw_radio(...) to standardize radio button drawing
- src/Fl_Light_Button.cxx: use fl_contrast() to determine color of
  radio button and check (light) button check marks, and use
  new fl_draw_radio() method
- src/Fl_Menu.cxx: same as src/Fl_Light_Button.cxx and use
  fl_draw_check() instead of "manually" drawing the check mark
  (forgotten in an earlier update)
This commit is contained in:
Albrecht Schlosser 2023-12-02 19:34:29 +01:00
parent 0aa8e28be0
commit 9950c8e082
4 changed files with 98 additions and 63 deletions

View File

@ -982,6 +982,10 @@ FL_EXPORT void fl_draw_arrow(Fl_Rect bb, Fl_Arrow_Type t, Fl_Orientation o, Fl_C
// Draw a potentially small, filled circle
FL_EXPORT void fl_draw_circle(int x, int y, int d, Fl_Color color);
// Draw the full "radio button" of a radio menu entry or radio button
// This requires scheme specific handling (particularly gtk+ scheme)
FL_EXPORT void fl_draw_radio(int x, int y, int d, Fl_Color color);
// images:
/**

View File

@ -32,6 +32,16 @@ void Fl_Light_Button::draw() {
Fl_Color col = value() ? (active_r() ? selection_color() :
fl_inactive(selection_color())) : color();
// determine the color of the check mark or radio button (circle)
Fl_Color check_color = selection_color(); // default = selection color
if (Fl::is_scheme("gtk+"))
check_color = FL_SELECTION_COLOR; // exception for gtk+
if (!active_r())
check_color = fl_inactive(check_color);
// select a color with enough contrast
check_color = fl_contrast(check_color, FL_BACKGROUND2_COLOR);
int W = labelsize(); // check mark box size
if (W > 25) W = 25; // limit box size
int bx = Fl::box_dx(box()); // box frame width
@ -42,8 +52,11 @@ void Fl_Light_Button::draw() {
int cy = y() + dy; // check mark box y-position
int cw = 0; // check mark box width and height
if (down_box()) {
// draw other down_box() styles:
// FIXME: the *box type* of the widget determines the drawing style:
// (a) down_box() == 0: Fl_Light_Button style
// (b) down_box() != 0: other button styles
if (down_box()) { // draw "other" button styles (b):
switch (down_box()) {
case FL_DOWN_BOX :
case FL_UP_BOX :
@ -53,14 +66,11 @@ void Fl_Light_Button::draw() {
draw_box(down_box(), cx, cy, W, W, FL_BACKGROUND2_COLOR);
if (value()) {
// Check mark...
if (Fl::is_scheme("gtk+")) {
col = FL_SELECTION_COLOR;
}
// Calculate box position and size
cx += Fl::box_dx(down_box());
cy += Fl::box_dy(down_box());
cw = W - Fl::box_dw(down_box());
fl_draw_check(Fl_Rect(cx, cy, cw, cw), col);
fl_draw_check(Fl_Rect(cx, cy, cw, cw), check_color);
}
break;
case _FL_ROUND_DOWN_BOX :
@ -68,27 +78,16 @@ void Fl_Light_Button::draw() {
// Radio button...
draw_box(down_box(), x()+dx, y()+dy, W, W, FL_BACKGROUND2_COLOR);
if (value()) {
// Draw round check mark of radio button
int tW = (W - Fl::box_dw(down_box())) / 2 + 1;
if ((W - tW) & 1) tW++; // Make sure difference is even to center
int tdx = dx + (W - tW) / 2;
int tdy = dy + (W - tW) / 2;
fl_draw_radio(x() + tdx - 1, y() + tdy - 1, tW + 2, check_color);
if (Fl::is_scheme("gtk+")) {
fl_color(FL_SELECTION_COLOR);
tW --;
fl_pie(x() + tdx - 1, y() + tdy - 1, tW + 3, tW + 3, 0.0, 360.0);
fl_color(fl_color_average(FL_WHITE, FL_SELECTION_COLOR, 0.2f));
} else {
fl_color(col);
}
fl_draw_circle(x() + tdx, y() + tdy, tW, fl_color());
if (Fl::is_scheme("gtk+")) {
fl_color(fl_color_average(FL_WHITE, FL_SELECTION_COLOR, 0.5));
fl_arc(x() + tdx, y() + tdy, tW + 1, tW + 1, 60.0, 180.0);
}
}
} // Radio button: if (value())
break;
default :
draw_box(down_box(), x()+dx, y()+dy, W, W, col);
@ -96,7 +95,7 @@ void Fl_Light_Button::draw() {
}
lx = dx + W + 2;
} else {
// if down_box() is zero, draw light button style:
// if down_box() is zero, draw light button style (a):
int hh = h()-2*dy - 2;
int ww = W/2+1;
int xx = dx;

View File

@ -290,7 +290,7 @@ void Fl_Menu_Item::draw(int x, int y, int w, int h, const Fl_Menu_* m,
if (selected) {
Fl_Color r = m ? m->selection_color() : FL_SELECTION_COLOR;
Fl_Boxtype b = m && m->down_box() ? m->down_box() : FL_FLAT_BOX;
if (fl_contrast(r,color)!=r) { // back compatibility boxtypes
if (fl_contrast(r, color) != r) { // back compatibility boxtypes
if (selected == 2) { // menu title
r = color;
b = m ? m->box() : FL_UP_BOX;
@ -314,45 +314,26 @@ void Fl_Menu_Item::draw(int x, int y, int w, int h, const Fl_Menu_* m,
int d = (h - FL_NORMAL_SIZE + 1) / 2;
int W = h - 2 * d;
Fl_Color check_color = labelcolor_;
if (Fl::is_scheme("gtk+"))
check_color = FL_SELECTION_COLOR;
check_color = fl_contrast(check_color, FL_BACKGROUND2_COLOR);
if (flags & FL_MENU_RADIO) {
fl_draw_box(FL_ROUND_DOWN_BOX, x+2, y+d, W, W, FL_BACKGROUND2_COLOR);
if (value()) {
int tW = (W - Fl::box_dw(FL_ROUND_DOWN_BOX)) / 2 + 1;
if ((W - tW) & 1) tW++; // Make sure difference is even to center
int td = (W - tW) / 2;
if (Fl::is_scheme("gtk+")) {
fl_color(FL_SELECTION_COLOR);
tW --;
fl_pie(x + td + 1, y + d + td - 1, tW + 3, tW + 3, 0.0, 360.0);
fl_color(fl_color_average(FL_WHITE, FL_SELECTION_COLOR, 0.2f));
} else {
fl_color(labelcolor_);
}
fl_draw_radio(x + td + 1, y + d + td - 1, tW + 2, check_color);
} // FL_MENU_RADIO && value()
fl_draw_circle(x + td + 2, y + d + td, tW, fl_color());
} else { // FL_MENU_TOGGLE && ! FL_MENU_RADIO
if (Fl::is_scheme("gtk+")) {
fl_color(fl_color_average(FL_WHITE, FL_SELECTION_COLOR, 0.5));
fl_arc(x + td + 2, y + d + td, tW + 1, tW + 1, 60.0, 180.0);
}
}
} else {
fl_draw_box(FL_DOWN_BOX, x+2, y+d, W, W, FL_BACKGROUND2_COLOR);
if (value()) {
if (Fl::is_scheme("gtk+")) {
fl_color(FL_SELECTION_COLOR);
} else {
fl_color(labelcolor_);
}
int tx = x + 5;
int tw = W - 6;
int d1 = tw/3;
int d2 = tw-d1;
int ty = y + d + (W+d2)/2-d1-2;
for (int n = 0; n < 3; n++, ty++) {
fl_line(tx, ty, tx+d1, ty+d1);
fl_line(tx+d1, ty+d1, tx+tw-1, ty+d1-d2+1);
}
fl_draw_check(Fl_Rect(x+3, y+d+1, W-2, W-2), check_color);
}
}
x += W + 3;

View File

@ -594,25 +594,76 @@ void fl_draw_check(Fl_Rect bb, Fl_Color col) {
/**
Draw a potentially small, filled circle using a given color.
This function draws using \p color a filled circle bounded by rectangle <tt>(x, y, d, d)</tt>.
This function draws a filled circle bounded by rectangle
<tt>(x, y, d, d)</tt> using color \p color
This function is the same as <tt>fl_pie(x, y, d, d, 0, 360)</tt> except with some systems
that don't draw small circles well. In that situation, the circle diameter \p d is converted
from FLTK units to pixels and this function approximates a filled circle by drawing several
filled rectangles if the converted diameter is 6 pixels.
This function is the same as <tt>fl_pie(x, y, d, d, 0, 360)</tt> except
with some systems that don't draw small circles well. In that situation,
the circle diameter \p d is converted from FLTK units to pixels and this
function approximates a filled circle by drawing several filled
rectangles if the converted diameter is 6 pixels.
\param[in] x,y coordinates of top left of the bounding box
\param[in] d diameter == width and height of the bounding box in FLTK units
\param[in] color drawing color
The current drawing color fl_color() is preserved across the call.
\param[in] x,y coordinates of top left of the bounding box
\param[in] d diameter == width and height of the bounding box in FLTK units
\param[in] color the color used to draw the circle
\since 1.4.0
*/
void fl_draw_circle(int x, int y, int d, Fl_Color color) {
#define DEBUG_DRAW_CIRCLE (0) // bit 1 = draw bounding box (green)
#if (DEBUG_DRAW_CIRCLE & 1)
#if (DEBUG_DRAW_CIRCLE & 0)
Fl_Color current = fl_color();
fl_rectf(x0, y0, d, d, FL_GREEN);
fl_rectf(x, y, d, d, FL_GREEN);
fl_color(current);
#endif
fl_graphics_driver->draw_circle(x, y, d, color);
}
/**
Draw a round check mark (circle) of a radio button.
This draws only the round "radio button mark", it does not draw the
(also typically round) box of the radio button.
Call this only if the radio button is \c ON.
This method draws a scheme specific "circle" with a particular light effect
if the scheme is gtk+. For all other schemes this function draws a simple,
small circle.
The \c color must be chosen by the caller so it has enough contrast with
the background.
The bounding box of the circle is the rectangle <tt>(x, y, d, d)</tt>.
The current drawing color fl_color() is preserved across the call.
\param[in] x,y coordinates of top left of the bounding box
\param[in] d diameter == width and height of the bounding box in FLTK units
\param[in] color the base color used to draw the circle
\since 1.4.0
*/
void fl_draw_radio(int x, int y, int d, Fl_Color color) {
Fl_Color current = fl_color();
#if (0) // DEBUG: draw bounding box
fl_color(fl_lighter(FL_RED));
fl_rectf(x, y, d, d);
#endif
if (Fl::is_scheme("gtk+")) {
fl_color(color);
fl_pie(x, y, d, d, 0.0, 360.0);
Fl_Color icol = fl_color_average(FL_WHITE, color, 0.2f);
fl_draw_circle(x + 2, y + 2, d - 4, icol);
fl_color(fl_color_average(FL_WHITE, color, 0.5));
fl_arc(x + 1, y + 1, d - 1, d - 1, 60.0, 180.0);
} else {
fl_draw_circle(x + 1, y + 1, d - 2, color);
}
fl_color(current);
}