diff options
| author | Albrecht Schlosser <albrechts.fltk@online.de> | 2022-12-28 17:50:00 +0100 |
|---|---|---|
| committer | Albrecht Schlosser <albrechts.fltk@online.de> | 2022-12-28 18:16:23 +0100 |
| commit | 78cf29ba29aede2f0463e1747dc728787428d543 (patch) | |
| tree | 8970367f542bd08e595072c1b9c2ce3cd49624d3 /test | |
| parent | 31327cd649b8ad5a6271057d823abe59a5362c60 (diff) | |
Improve and extend fl_contrast() (#370)
- Add internal fl_contrast_cielab() as the new default.
- Keep old function as internal fl_contrast_legacy().
- Add fl_contrast_mode() to switch between fl_contrast() functions.
- Add fl_contrast_level() to fine tune fl_contrast() per mode.
- Add option to register and use a custom contrast function.
- Add test/contrast.cxx test program.
- Move all fl_contrast() related code to a new file src/fl_contrast.cxx.
- Add fl_lightness() convenience function for perceived lightness.
- Add fl_luminance() convenience function for physical luminance.
Diffstat (limited to 'test')
| -rw-r--r-- | test/.gitignore | 1 | ||||
| -rw-r--r-- | test/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | test/Makefile | 4 | ||||
| -rw-r--r-- | test/contrast.cxx | 454 | ||||
| -rw-r--r-- | test/demo.menu | 11 | ||||
| -rw-r--r-- | test/makedepend | 45 |
6 files changed, 511 insertions, 5 deletions
diff --git a/test/.gitignore b/test/.gitignore index 49b1817e0..1e43541ac 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -30,6 +30,7 @@ clipboard clock colbrowser color_chooser +contrast coordinates cube CubeView diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 05333ee81..fc8e26ed1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -72,6 +72,7 @@ CREATE_EXAMPLE (clipboard clipboard.cxx "fltk_images;fltk") CREATE_EXAMPLE (clock clock.cxx fltk) CREATE_EXAMPLE (colbrowser colbrowser.cxx fltk) CREATE_EXAMPLE (color_chooser color_chooser.cxx fltk) +CREATE_EXAMPLE (contrast contrast.cxx fltk) CREATE_EXAMPLE (coordinates coordinates.cxx fltk) CREATE_EXAMPLE (cursor cursor.cxx fltk) CREATE_EXAMPLE (curve curve.cxx fltk) diff --git a/test/Makefile b/test/Makefile index 3b9afa5eb..df0aee017 100644 --- a/test/Makefile +++ b/test/Makefile @@ -65,6 +65,7 @@ CPPFILES =\ clock.cxx \ colbrowser.cxx \ color_chooser.cxx \ + contrast.cxx \ cube.cxx \ CubeMain.cxx \ CubeView.cxx \ @@ -159,6 +160,7 @@ ALL = \ clock$(EXEEXT) \ colbrowser$(EXEEXT) \ color_chooser$(EXEEXT) \ + contrast$(EXEEXT) \ cursor$(EXEEXT) \ curve$(EXEEXT) \ demo$(EXEEXT) \ @@ -394,6 +396,8 @@ colbrowser$(EXEEXT): colbrowser.o color_chooser$(EXEEXT): color_chooser.o +contrast$(EXEEXT): contrast.o + cursor$(EXEEXT): cursor.o curve$(EXEEXT): curve.o diff --git a/test/contrast.cxx b/test/contrast.cxx new file mode 100644 index 000000000..5cd340d13 --- /dev/null +++ b/test/contrast.cxx @@ -0,0 +1,454 @@ +// +// Contrast function test program for the Fast Light Tool Kit (FLTK). +// +// Copyright 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 +// + +// Note: this test and demo program is work in progress. It is published +// because it is helpful but it needs some more work to be "perfect" ;-) +// AlbrechtS + +#include <FL/Fl.H> +#include <FL/Fl_Double_Window.H> +#include <FL/Fl_Box.H> +#include <FL/Fl_Button.H> +#include <FL/Fl_Radio_Round_Button.H> +#include <FL/Fl_Color_Chooser.H> +#include <FL/Fl_Output.H> +#include <FL/Fl_Hor_Value_Slider.H> +#include <FL/Fl_Simple_Terminal.H> +#include <FL/fl_draw.H> + +#include <math.h> +#include <stdlib.h> +#include <string.h> + +// program version + +const char *version = "0.9.0"; + +// prototypes and forward declarations + +static void button_cb(Fl_Widget *w, void *v); +static Fl_Color calc_contrast(Fl_Color fg, Fl_Color bg, Fl_Fontsize fs); + +// class Button + +class Button : public Fl_Button { + char lbuf[20]; // private label buffer + Fl_Color ocol_; // "original" (label) color + int idx_; // button index (0 - 255) +public: + Button(int X, int Y, int W, int H, int n) + : Fl_Button(X, Y, W, H, "") { + idx_ = n; + box(FL_THIN_DOWN_BOX); + label(lbuf); + callback(button_cb); + color((Fl_Color)n); + sprintf(lbuf, "%03d", n); + set_labelcolor(n); + labelsize(15); + labelfont(FL_HELVETICA); + } + + void set_labelcolor(Fl_Color col) { + ocol_ = col; + labelcolor(calc_contrast(col, color(), labelsize())); + } + + Fl_Color ocol() { + return ocol_; + } + + int idx() { + return idx_; + } + + virtual void draw() { + draw_box(); + // draw small filled rectangle with "original" color + fl_color(ocol_); + fl_rectf(x() + 5, y() + 5, 10, h() - 10); + // measure and draw label + int lw = 0, lh = 0; + fl_font(labelfont(), labelsize()); + fl_measure(lbuf, lw, lh); + fl_color(labelcolor()); + fl_draw(lbuf, x() + 15 + (w() - lw - 15) / 2, y() + h() - (h() - lh) / 2 - lh/4); + fl_color(FL_BLACK); + } + +}; // class Button + +// global variables + +Fl_Simple_Terminal *term = 0; + +double g_lfg; // perceived lightness of foreground color +double g_lbg; // perceived lightness of background color +double g_lcref; // calculated contrast reference (CIELAB, L*a*b*) +int g_selected = -1; // selected button: -1 = none, 0 - 255 = valid button + +Fl_Fontsize g_fs = 15; // fontsize for button labels +int g_level = 0; // *init* fl_contrast_level (sensitivity) + +int g_algo = FL_CONTRAST_LEGACY;// contrast algorithm: 0 = none, 1 = legacy (1.3.x), 2 = CIELAB, 3 = custom +const char *alch = ""; // algorithm as char: "LEGACY", "CIELAB" , or "CUSTOM" + +Fl_Color lcolor = FL_BLACK; // label color, set by slider callback +Button *buttons[256]; // array of color buttons +Fl_Value_Slider *sliders[6]; // array of sliders (gray, red, green, blue, level, fontsize) +Fl_Output *color_out = 0; // color output (RRGGBB) + +// Custom contrast algorithm: currently a dummy function (returns fg). +// This may be used to define a "better" contrast function in user code + +static Fl_Color custom_contrast(Fl_Color fg, Fl_Color bg, Fl_Fontsize fs, int) { + return fg; +} + +/* + Local function to calculate the contrast and store it in some + global variables for display purposes and logging. + + This function is a wrapper around fl_contrast() in this demo program. +*/ +static Fl_Color calc_contrast(Fl_Color fg, Fl_Color bg, Fl_Fontsize fs) { + + // Compute and set global *perceived* lightness L* (Lstar) and contrast for display + + g_lfg = fl_lightness(fg); + g_lbg = fl_lightness(bg); + g_lcref = g_lfg - g_lbg; // perceived contrast (light on dark = positive) + + switch (g_algo) { + case FL_CONTRAST_NONE: // 0 = none (return fg) + case FL_CONTRAST_LEGACY: // 1 = legacy (FLTK 1.3.x) + case FL_CONTRAST_CIELAB: // 2 = CIELAB (L*a*b*) + case FL_CONTRAST_CUSTOM: // 3 = Custom + return fl_contrast(fg, bg, fs); + default: + break; + } + return fg; +} + +// set all button label colors and adjust fontsize (labelsize) + +static void update_labels() { + for (int i = 0; i < 256; i++) { + buttons[i]->set_labelcolor(lcolor); + buttons[i]->labelsize(g_fs); + } +} + +static void button_cb(Fl_Widget *w, void *v) { + Button *b = (Button *)w; + g_selected = b->idx(); // selected button index + Fl_Color ocol = Fl::get_color(b->ocol()); // button's "original" label color (RGB0) + Fl_Color fg = Fl::get_color(b->labelcolor()); // button's label color (RGB0) + Fl_Color bg = Fl::get_color(b->color()); // button's background color (RGB0) + calc_contrast(ocol, bg, g_fs); // calculate values to be displayed + const char *color = ""; // calculated label color (text) + if (fg == ocol) color = "fg"; + else if (fg == 0xffffff00) color = "WHITE"; + else if (fg == 0x0) color = "BLACK"; + term->printf("[%s] fg: %06x, bg: %06x, lfg: %6.2f, lbg: %6.2f, lc: %7.2f, %s => %-5s", + b->label(), ocol >> 8, bg >> 8, g_lfg, g_lbg, g_lcref, alch, color); + if (g_algo == FL_CONTRAST_LEGACY || + g_algo == FL_CONTRAST_CIELAB) + term->printf(" (level = %3d)\n", g_level); + else + term->printf("\n"); +} + +void lf_cb(Fl_Widget *w, void *v) { + term->printf("\n"); +} + +// callback for color (gray and R, G, B) sliders + +void color_slider_cb(Fl_Widget *w, void *v) { + int n = fl_int(v); // slider type: 0 = gray, 1 = color + unsigned int r, g, b; + if (n == 0) { // gray slider + int val = (int)sliders[0]->value(); + lcolor = fl_rgb_color(val, val, val); // set gray value + sliders[1]->value(val); // set r/g/b values as well + sliders[2]->value(val); + sliders[3]->value(val); + r = g = b = val; + } else { // any color slider + r = (unsigned int)sliders[1]->value(); + g = (unsigned int)sliders[2]->value(); + b = (unsigned int)sliders[3]->value(); + lcolor = fl_rgb_color(r, g, b); // set color value + } + // update button label colors + update_labels(); + // output label color + char color_buf[10]; + sprintf(color_buf, "%02X %02X %02X", r, g, b); + color_out->value(color_buf); + w->window()->redraw(); +} + +// callback for "level" and "fontsize" sliders + +void slider_cb(Fl_Widget *w, void *v) { + int n = fl_int(v); // slider type: 1 = level, 2 = fontsize + switch (n) { + case 1: // fl_contrast_level() + g_level = (int)sliders[n + 3]->value(); + fl_contrast_level(g_level); // set/store current contrast level + break; + case 2: // 2nd slider: fontsize (labelsize) + g_fs = (int)sliders[n + 3]->value(); + break; + default: + break; + } + // update button label colors + update_labels(); + w->window()->redraw(); +} + +// callback for contrast algorithm (radio buttons) + +void algo_cb(Fl_Widget *w, void *v) { + int val = fl_int(v); + g_algo = val; + switch(val) { + case FL_CONTRAST_LEGACY: alch = "LEGACY"; fl_contrast_mode(val); break; // legacy 1.3.x + case FL_CONTRAST_CIELAB: alch = "CIELAB"; fl_contrast_mode(val); break; // CIELAB L*a*b* + case FL_CONTRAST_CUSTOM: alch = "CUSTOM"; fl_contrast_mode(val); break; // custom + case FL_CONTRAST_NONE: + default: + alch = "none "; + fl_contrast_mode(FL_CONTRAST_NONE); + break; + } + g_level = fl_contrast_level(); // get current contrast level (per mode) + sliders[4]->value(g_level); // set level slider value + update_labels(); // update all button labels + + // print selected button's attributes + if (g_selected >= 0) { + button_cb(buttons[g_selected], (void *)0); + } + if (w) + w->window()->redraw(); +} + +// color chooser callback +void color_cb(Fl_Widget *w, void *v) { + Fl_Color_Chooser *cc = (Fl_Color_Chooser *)w; + int r = (int)(cc->r() * 255); + int g = (int)(cc->g() * 255); + int b = (int)(cc->b() * 255); + Fl_Color c = fl_rgb_color(r, g, b); + Button *bt = buttons[255]; // last button + bt->color(c); + bt->set_labelcolor(lcolor); + bt->redraw(); +} + +// =============================================================== +// ====================== main() program ====================== +// =============================================================== + +int main(int argc, char **argv) { + + const int bw = 58; + const int bh = 30; + int cw = 16 * bw + 10; + int ch = 16 * bh + 10; + int ww = cw + 10; + int wh = 16 * bh + 135 + 10 + 150 /* terminal */ + 10; + Fl_Double_Window window(ww, wh, "fl_contrast test"); + + int n = 0; + Button **b = buttons; + for (int y = 0; y < 16; y++) { + for (int x = 0; x < 16; x++) { + *b = new Button(x * bw + 10, y * bh + 10, bw, bh, n); + (*b)->set_labelcolor(n); + b++; + n++; + } + } + + // sliders for label color (gray, red, green, blue) + + const int sx = 10 + bw; + const int sw = 5 * bw; + const int sh = 25; + int sy = ch + 10; + + Fl_Hor_Value_Slider *gray = new Fl_Hor_Value_Slider(sx, sy, sw, sh, "gray"); + gray->color(0xdddddd00); + gray->textsize(13); + gray->align(FL_ALIGN_LEFT); + gray->value(0); + gray->bounds(0, 255); + gray->step(1); + gray->callback(color_slider_cb, (void *)0); + sy += sh + 10; + + Fl_Hor_Value_Slider *red = new Fl_Hor_Value_Slider(sx, sy, sw, sh, "red"); + red->color(FL_RED); + red->textcolor(FL_WHITE); + red->textsize(13); + red->align(FL_ALIGN_LEFT); + red->value(0); + red->bounds(0, 255); + red->step(1); + red->callback(color_slider_cb, (void *)1); + sy += sh + 5; + + Fl_Hor_Value_Slider *green = new Fl_Hor_Value_Slider(sx, sy, sw, sh, "green"); + green->color(FL_GREEN); + green->textsize(13); + green->align(FL_ALIGN_LEFT); + green->value(0); + green->bounds(0, 255); + green->step(1); + green->callback(color_slider_cb, (void *)1); + sy += sh + 5; + + Fl_Hor_Value_Slider *blue = new Fl_Hor_Value_Slider(sx, sy, sw, sh, "blue"); + blue->color(FL_BLUE); + blue->textcolor(FL_WHITE); + blue->textsize(13); + blue->align(FL_ALIGN_LEFT); + blue->value(0); + blue->bounds(0, 255); + blue->step(1); + blue->callback(color_slider_cb, (void *)1); + + sliders[0] = gray; + sliders[1] = red; + sliders[2] = green; + sliders[3] = blue; + + // contrast algorithm selection group + + int cgx = 10 + 6*bw + 10; + int cgy = ch + 30; + int cgw = 90; + int cgh = 100; + int abh = 25; + + Fl_Group *cg = new Fl_Group(cgx, cgy, cgw, cgh, "fl_contrast:"); + cg->align(FL_ALIGN_TOP); + cg->box(FL_FRAME); + + Fl_Radio_Round_Button *anon = new Fl_Radio_Round_Button(cgx, cgy, cgw, abh, "none"); + Fl_Radio_Round_Button *aleg = new Fl_Radio_Round_Button(cgx, cgy + 25, cgw, abh, "LEGACY"); + Fl_Radio_Round_Button *acie = new Fl_Radio_Round_Button(cgx, cgy + 50, cgw, abh, "CIELAB"); + Fl_Radio_Round_Button *aapc = new Fl_Radio_Round_Button(cgx, cgy + 75, cgw, abh, "CUSTOM"); + aleg->value(1); + anon->callback(algo_cb, (void *)0); + aleg->callback(algo_cb, (void *)1); + acie->callback(algo_cb, (void *)2); + aapc->callback(algo_cb, (void *)3); + + cg->end(); + + color_out = new Fl_Output(10 + 10 * bw, ch + 10, 100, 30, "label color:"); + color_out->align(FL_ALIGN_LEFT); + color_out->textfont(FL_COURIER); + color_out->textsize(16); + color_out->value("00 00 00"); + + // light blue "level" slider + + Fl_Hor_Value_Slider *s_level = new Fl_Hor_Value_Slider(10 + 9 * bw, red->y(), 3 * bw - 15, sh, "level"); + s_level->color(231); + s_level->textcolor(224); + s_level->textsize(13); + s_level->align(FL_ALIGN_LEFT); + s_level->step(1); + s_level->bounds(0, 100); + s_level->value(g_level); + s_level->callback(slider_cb, (void *)1); + s_level->tooltip("set contrast sensitivity level (0-100), default: 50"); + + // labelsize slider + + Fl_Hor_Value_Slider *s_fs = new Fl_Hor_Value_Slider(10 + 9 * bw, green->y(), 3 * bw - 15, sh, "labelsize"); + s_fs->color(231); + s_fs->textcolor(224); + s_fs->textsize(13); + s_fs->align(FL_ALIGN_LEFT); + s_fs->step(1); + s_fs->bounds(8, 24); + s_fs->value(15); + s_fs->callback(slider_cb, (void *)2); + s_fs->tooltip("set label/text fontsize"); + + sliders[4] = s_level; + sliders[5] = s_fs; + + // line feed (LF) button + + Fl_Button *lf = new Fl_Button(10 + 8 * bw, blue->y(), bw, sh, "LF"); + lf->tooltip("Click to output a linefeed to the log."); + lf->callback(lf_cb); + + // color chooser for field #255 + + int ccx = 10 + 12 * bw; + int ccy = ch + 10; + int ccw = 4 * bw; + int cch = 120; + + Fl_Color_Chooser *color_chooser = new Fl_Color_Chooser(ccx, ccy, ccw, cch); + color_chooser->callback(color_cb); + color_chooser->label("bg color [255] @->"); + color_chooser->rgb(1, 1, 1); + color_chooser->mode(1); // byte mode + color_chooser->align(FL_ALIGN_LEFT_BOTTOM); + + // simple terminal for output (FLTK 1.4 only) + + int ttx = 10; + int tty = color_chooser->y() + cch + 10; + int ttw = window.w() - 20; + int tth = window.h() - tty - 10; + + term = new Fl_Simple_Terminal(ttx, tty, ttw, tth); + term->color(FL_WHITE); + term->textcolor(FL_BLACK); + term->textsize(13); + + term->printf("FLTK fl_contrast() test program with different contrast algorithms, version %s\n", version); + term->printf("FLTK version %d.%d.%d\n", FL_MAJOR_VERSION, FL_MINOR_VERSION, FL_PATCH_VERSION); + term->printf(" - Select a foreground (text) color with the gray or red/green/blue sliders (displayed inside each field).\n"); + term->printf(" - Select an arbitrary background color for field #255 with the color chooser.\n"); + term->printf(" - Select a colored field (by clicking on it) to display its attributes.\n"); + term->printf(" - Select the contrast algorithm by clicking on the radio buttons.\n"); + term->printf(" - Tune the contrast algorithm with the light blue \"level\" slider (default: 50).\n"); + + // set contrast mode and level, update button label colors + + fl_contrast_mode(g_algo); + fl_contrast_function(custom_contrast); // dummy function + algo_cb(NULL, fl_voidptr(g_algo)); // updates button labels + + window.resizable(window); + window.end(); + window.show(argc, argv); + return Fl::run(); +} diff --git a/test/demo.menu b/test/demo.menu index 2d5750634..16cce02da 100644 --- a/test/demo.menu +++ b/test/demo.menu @@ -61,7 +61,6 @@ @main:Fluid\n(UI design tool):fluid valuators.fl @main:Cool\nDemos...:@e - @e:X Color\nBrowser:colbrowser rgb.txt @e:Mandelbrot:mandelbrot @e:Fractals:fractals @e:Puzzle:glpuzzle @@ -72,17 +71,19 @@ @e:Clipboard\nViewer:clipboard @main:Other\nTests...:@o - @o:Color Choosers:color_chooser @o:File Chooser:file_chooser @o:Native File Chooser:native-filechooser - @o:Font Tests...:@of - @of:Fonts:fonts - @of:UTF-8:utf8 @o:HelpDialog:help_dialog help_dialog.html @o:Input Choice:input_choice @o:Preferences:preferences @o:Threading:threads @o:XForms Emulation:forms + @o:Colors and Fonts...:@of + @of:X Color\nBrowser:colbrowser rgb.txt + @of:Color Chooser:color_chooser + @of:Color Contrast:contrast + @of:Fonts:fonts + @of:UTF-8 Fonts:utf8 @main:Tutorial\nfrom\nManual...:@j @j:ask\n(modified):ask diff --git a/test/makedepend b/test/makedepend index a013aae50..f51a7416a 100644 --- a/test/makedepend +++ b/test/makedepend @@ -459,6 +459,51 @@ color_chooser.o: ../FL/platform.H color_chooser.o: ../FL/platform_types.h color_chooser.o: ../FL/x11.H color_chooser.o: list_visuals.cxx +contrast.o: ../FL/Enumerations.H +contrast.o: ../FL/Fl.H +contrast.o: ../FL/Fl_Bitmap.H +contrast.o: ../FL/Fl_Box.H +contrast.o: ../FL/Fl_Button.H +contrast.o: ../FL/Fl_Cairo.H +contrast.o: ../FL/fl_casts.H +contrast.o: ../FL/Fl_Choice.H +contrast.o: ../FL/Fl_Color_Chooser.H +contrast.o: ../FL/fl_config.h +contrast.o: ../FL/Fl_Device.H +contrast.o: ../FL/Fl_Double_Window.H +contrast.o: ../FL/fl_draw.H +contrast.o: ../FL/Fl_Export.H +contrast.o: ../FL/Fl_Graphics_Driver.H +contrast.o: ../FL/Fl_Group.H +contrast.o: ../FL/Fl_Hor_Value_Slider.H +contrast.o: ../FL/Fl_Image.H +contrast.o: ../FL/Fl_Input.H +contrast.o: ../FL/Fl_Input_.H +contrast.o: ../FL/Fl_Light_Button.H +contrast.o: ../FL/Fl_Menu_.H +contrast.o: ../FL/Fl_Menu_Item.H +contrast.o: ../FL/Fl_Output.H +contrast.o: ../FL/Fl_Pixmap.H +contrast.o: ../FL/Fl_Plugin.H +contrast.o: ../FL/Fl_Preferences.H +contrast.o: ../FL/Fl_Radio_Round_Button.H +contrast.o: ../FL/Fl_Rect.H +contrast.o: ../FL/Fl_Return_Button.H +contrast.o: ../FL/Fl_RGB_Image.H +contrast.o: ../FL/Fl_Round_Button.H +contrast.o: ../FL/Fl_Scrollbar.H +contrast.o: ../FL/Fl_Simple_Terminal.H +contrast.o: ../FL/Fl_Slider.H +contrast.o: ../FL/Fl_Text_Buffer.H +contrast.o: ../FL/Fl_Text_Display.H +contrast.o: ../FL/fl_types.h +contrast.o: ../FL/fl_utf8.h +contrast.o: ../FL/Fl_Valuator.H +contrast.o: ../FL/Fl_Value_Input.H +contrast.o: ../FL/Fl_Value_Slider.H +contrast.o: ../FL/Fl_Widget.H +contrast.o: ../FL/Fl_Window.H +contrast.o: ../FL/platform_types.h cube.o: ../config.h cube.o: ../FL/Enumerations.H cube.o: ../FL/Fl.H |
