Fix, optimize, and comment "gleam" scheme box drawing.

Some border lines were too short or too long, the shading code would draw
too many shaded lines, and the code was hard to understand.

With this commit all background pixels of the box are drawn exactly once.
The border lines are consistent, but some pixels of the border are not
drawn at all so the background shines through. This is intended for
backwards compatibility.

A minor change is that the drawn background does no longer overlap the
border lines. Hence undrawn pixels that previously displayed the colored
box background are now transparent and show the parent's background color.

This commit adds comments and implementation notes to make the code
easier to understand and better maintainable (hopefully).


git-svn-id: file:///fltk/svn/fltk/branches/branch-1.4@12779 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Albrecht Schlosser 2018-03-20 16:30:58 +00:00
parent 3b4c3e3295
commit f3b0598ee4
1 changed files with 93 additions and 43 deletions

View File

@ -1,9 +1,9 @@
//
// "$Id$"
//
// "Gleam" drawing routines for the Fast Light Tool Kit (FLTK).
// "Gleam" scheme box drawing routines for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2010 by Bill Spitzak and others.
// Copyright 1998-2018 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
@ -22,97 +22,148 @@
//
// Modified 2012-2013 by Edmanuel Torres
// This is a new version of the fl_gleam. The gradients are on the top
// an the bottom, the text area looks like in the classic FLTK way.
// and the bottom, the text area looks like in the classic FLTK way.
//
#include <FL/Fl.H>
#include <FL/fl_draw.H>
/*
Implementation notes:
All box types have 2 pixel wide borders, there is no distinction
of "thin" box types, hence Fl::box_dx() = Fl::box_dy() = 2,
Fl::box_dw() = Fl::box_dh() = 4 for all box types.
All coordinates of function calls (x, y, w, h) describe the full
box size with borders, i.e. the original box coordinates.
The interior (background) of the box is drawn with reduced size.
This is adjusted only in function shade_rect_top_bottom().
Note: There is one pixel "leaking" out of the box border at each
corner which is currently not drawn in a full box redraw.
*/
// Standard box drawing code
static void gleam_color(Fl_Color c) {
Fl::set_box_color(c);
}
/* Draw the shaded background of the box.
This is called before the box frame (border) is drawn.
The interior of the box (shaded background) should be inset by two
pixels, hence width and height should be reduced by 4 (border size).
Since not all pixels of the border are drawn (border lines are shorter
by one or two pixels on each side) setting other offsets (+1, -2 instead
of +2, -4) would leak the box background color instead of the parent
widget's background color.
Note: the original implementation was maybe equivalent to using +1 and -2
for offset and width, respectively instead of +2 and -4. It is not clear
whether this was intended or by accident.
*/
static void shade_rect_top_bottom(int x, int y, int w, int h, Fl_Color fg1, Fl_Color fg2, float th) {
// Draws the shiny using maximum limits
int h_top = ((h/2) < (20) ? (h/2) : (20)); // min(h/2,20);
int h_bottom = ((h/6) < (15) ? (h/6) : (15)); // min(h/6,15);
int h_flat = h-(h_top+h_bottom);
int j = 0;
float step_size_top = h_top>1?(0.999f/(float)(h_top)):1;
float step_size_bottom = h_bottom>1?(0.999f/(float)(h_bottom)):1;
// This loop generates the gradient at the top of the widget
for (float k = 1; k >= 0; k -= step_size_top){
// calculate background size w/o borders
x += 2; y += 2; w -= 4; h -= 4;
// draw the shiny background using maximum limits
int h_top = ((h/2) < (20) ? (h/2) : (20)); // min(h/2, 20);
int h_bottom = ((h/6) < (15) ? (h/6) : (15)); // min(h/6, 15);
int h_flat = h - h_top - h_bottom;
float step_size_top = h_top > 1 ? (0.999f/float(h_top)) : 1;
float step_size_bottom = h_bottom > 1 ? (0.999f/float(h_bottom)) : 1;
// draw the gradient at the top of the widget
float k = 1;
for (int i = 0; i < h_top; i++, k -= step_size_top) {
gleam_color(fl_color_average(fl_color_average(fg1, fg2, th), fg1, k));
fl_xyline(x, y+j, x+w);
j++;
fl_xyline(x, y+i, x+w-1);
}
// draw a "flat" rectangle in the middle area of the box
gleam_color(fg1);
fl_rectf(x, y+h_top, w+1, h_flat);
// This loop generates the gradient at the bottom of the widget
for (float k = 1; k >= 0; k -= step_size_bottom){
gleam_color(fl_color_average(fg1,fl_color_average(fg1, fg2, th), k));
fl_xyline(x, y+j+h_flat-1, x+w);
j++;
fl_rectf(x, y + h_top, w, h_flat);
// draw the gradient at the bottom of the widget
k = 1;
for (int i = 0; i < h_bottom; i++, k -= step_size_bottom) {
gleam_color(fl_color_average(fg1, fl_color_average(fg1, fg2, th), k));
fl_xyline(x, y+h_top+h_flat+i, x+w-1);
}
}
// See shade_rect_top_bottom()
static void shade_rect_top_bottom_up(int x, int y, int w, int h, Fl_Color bc, float th) {
shade_rect_top_bottom(x,y,w,h,bc,FL_WHITE,th);
shade_rect_top_bottom(x, y, w, h, bc, FL_WHITE, th);
}
// See shade_rect_top_bottom()
static void shade_rect_top_bottom_down(int x, int y, int w, int h, Fl_Color bc, float th) {
shade_rect_top_bottom(x,y,w,h,bc,FL_BLACK,th);
shade_rect_top_bottom(x, y, w, h, bc, FL_BLACK, th);
}
// Draw box borders. Color arguments:
// - fg1: outer border line (left, right, top, bottom)
// - fg2: inner border line (left, right)
// - lc : inner border line (top, bottom)
static void frame_rect(int x, int y, int w, int h, Fl_Color fg1, Fl_Color fg2, Fl_Color lc) {
// outer border line:
gleam_color(fg1);
fl_yxline(x, y+h-1, y+1); //Go from bottom to top left side
fl_yxline(x+w, y+h-1, y+1); //Go from bottom to top right side
fl_xyline(x+1, y, x+w-1); //Go across the top
fl_xyline(x+1, y+h, x+w-1); //Go across the bottom
fl_xyline(x+1, y, x+w-2); // top
fl_yxline(x+w-1, y+1, y+h-2); // right
fl_xyline(x+1, y+h-1, x+w-2); // bottom
fl_yxline(x, y+1, y+h-2); // left
// inner border line (left, right):
gleam_color(fg2);
fl_yxline(x+1, y+h-2, y+2); //Go from bottom to top left side
fl_yxline(x+w-1, y+h-2, y+2); //Go from bottom to top right side
fl_yxline(x+1, y+2, y+h-3); // left
fl_yxline(x+w-2, y+2, y+h-3); // right
// inner border line (top, bottom):
gleam_color(lc);
fl_xyline(x+2, y+1, x+w-3); //Go across the top
fl_xyline(x+2, y+h-1, x+w-3); //Go across the bottom
fl_xyline(x+2, y+1, x+w-3); // top
fl_xyline(x+2, y+h-2, x+w-3); // bottom
}
// Draw box borders with different colors (up/down effect).
static void frame_rect_up(int x, int y, int w, int h, Fl_Color bc, Fl_Color lc, float th1, float th2) {
frame_rect(x,y,w,h,fl_color_average(fl_darker(bc), FL_BLACK, th1),fl_color_average(bc, FL_WHITE, th2),lc);
frame_rect(x, y, w, h, fl_color_average(fl_darker(bc), FL_BLACK, th1), fl_color_average(bc, FL_WHITE, th2), lc);
}
static void frame_rect_down(int x, int y, int w, int h, Fl_Color bc, Fl_Color lc, float th1, float th2) {
frame_rect(x,y,w,h,fl_color_average(bc, FL_WHITE, th1),fl_color_average(FL_BLACK, bc, th2),lc);
frame_rect(x,y,w,h,fl_color_average(bc, FL_WHITE, th1), fl_color_average(FL_BLACK, bc, th2), lc);
}
// Draw the different box types. These are the actual box drawing functions.
static void up_frame(int x, int y, int w, int h, Fl_Color c) {
frame_rect_up(x, y, w-1, h-1, c, fl_color_average(c, FL_WHITE, .25f), .55f, .05f);
frame_rect_up(x, y, w, h, c, fl_color_average(c, FL_WHITE, .25f), .55f, .05f);
}
static void up_box(int x, int y, int w, int h, Fl_Color c) {
shade_rect_top_bottom_up(x+2, y+1, w-5, h-3, c, .15f);
frame_rect_up(x, y, w-1, h-1, c, fl_color_average(c, FL_WHITE, .05f), .15f, .05f);
shade_rect_top_bottom_up(x, y, w, h, c, .15f);
frame_rect_up(x, y, w, h, c, fl_color_average(c, FL_WHITE, .05f), .15f, .05f);
}
static void thin_up_box(int x, int y, int w, int h, Fl_Color c) {
shade_rect_top_bottom_up(x+2, y+1, w-5, h-3, c, .25f);
frame_rect_up(x, y, w-1, h-1, c, fl_color_average(c, FL_WHITE, .45f), .25f, .15f);
shade_rect_top_bottom_up(x, y, w, h, c, .25f);
frame_rect_up(x, y, w, h, c, fl_color_average(c, FL_WHITE, .45f), .25f, .15f);
}
static void down_frame(int x, int y, int w, int h, Fl_Color c) {
frame_rect_down(x, y, w-1, h-1, fl_darker(c), fl_darker(c), .25f, .95f);
frame_rect_down(x, y, w, h, fl_darker(c), fl_darker(c), .25f, .95f);
}
static void down_box(int x, int y, int w, int h, Fl_Color c) {
shade_rect_top_bottom_down(x+1, y+1, w-3, h-3, c, .65f);
frame_rect_down(x, y, w-1, h-1, c, fl_color_average(c, FL_BLACK, .05f), .05f, .95f);
shade_rect_top_bottom_down(x, y, w, h, c, .65f);
frame_rect_down(x, y, w, h, c, fl_color_average(c, FL_BLACK, .05f), .05f, .95f);
}
static void thin_down_box(int x, int y, int w, int h, Fl_Color c) {
shade_rect_top_bottom_down(x+1, y+1, w-3, h-3, c, .85f);
frame_rect_down(x, y, w-1, h-1, c, fl_color_average(c, FL_BLACK, .45f), .35f, 0.85f);
shade_rect_top_bottom_down(x, y, w, h, c, .85f);
frame_rect_down(x, y, w, h, c, fl_color_average(c, FL_BLACK, .45f), .35f, 0.85f);
}
extern void fl_internal_boxtype(Fl_Boxtype, Fl_Box_Draw_F*);
@ -133,4 +184,3 @@ Fl_Boxtype fl_define_FL_GLEAM_UP_BOX() {
//
// End of "$Id$".
//