themes: Workaround for bug where a background color of RGB 0,0,0 in Black color schem...
[ntk.git] / src / fl_boxtype.cxx
bloba069eb0ff8bd4dea0337ac91070148057ab9dabb
1 // "$Id: fl_boxtype.cxx 7903 2010-11-28 21:06:39Z matt $"
2 //
3 // Box drawing code for the Fast Light Tool Kit (FLTK).
4 //
5 // Copyright 1998-2010 by Bill Spitzak and others.
6 //
7 // This library is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Library General Public
9 // License as published by the Free Software Foundation; either
10 // version 2 of the License, or (at your option) any later version.
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // Library General Public License for more details.
17 // You should have received a copy of the GNU Library General Public
18 // License along with this library; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 // USA.
22 // Please report all bugs and problems on the following page:
24 // http://www.fltk.org/str.php
27 /**
28 \file fl_boxtype.cxx
29 \brief drawing code for common box types.
32 // Box drawing code for the common box types and the table of
33 // boxtypes. Other box types are in separate files so they are not
34 // linked in if not used.
36 #include <FL/Fl.H>
37 #include <FL/Fl_Widget.H>
38 #include <FL/fl_draw.H>
39 #include <config.h>
41 ////////////////////////////////////////////////////////////////
43 static uchar active_ramp[24] = {
44 FL_GRAY_RAMP+0, FL_GRAY_RAMP+1, FL_GRAY_RAMP+2, FL_GRAY_RAMP+3,
45 FL_GRAY_RAMP+4, FL_GRAY_RAMP+5, FL_GRAY_RAMP+6, FL_GRAY_RAMP+7,
46 FL_GRAY_RAMP+8, FL_GRAY_RAMP+9, FL_GRAY_RAMP+10,FL_GRAY_RAMP+11,
47 FL_GRAY_RAMP+12,FL_GRAY_RAMP+13,FL_GRAY_RAMP+14,FL_GRAY_RAMP+15,
48 FL_GRAY_RAMP+16,FL_GRAY_RAMP+17,FL_GRAY_RAMP+18,FL_GRAY_RAMP+19,
49 FL_GRAY_RAMP+20,FL_GRAY_RAMP+21,FL_GRAY_RAMP+22,FL_GRAY_RAMP+23};
50 static uchar inactive_ramp[24] = {
51 43, 43, 44, 44,
52 44, 45, 45, 46,
53 46, 46, 47, 47,
54 48, 48, 48, 49,
55 49, 49, 50, 50,
56 51, 51, 52, 52};
57 static int draw_it_active = 1;
59 /**
60 Determines if the current draw box is active or inactive.
61 If inactive, the box color is changed by the inactive color.
63 int Fl::draw_box_active() { return draw_it_active; }
65 uchar *fl_gray_ramp() {return (draw_it_active?active_ramp:inactive_ramp)-'A';}
67 /**
68 Draws a series of line segments around the given box.
69 The string \p s must contain groups of 4 letters which specify one of 24
70 standard grayscale values, where 'A' is black and 'X' is white.
71 The order of each set of 4 characters is: top, left, bottom, right.
72 The result of calling fl_frame() with a string that is not a multiple
73 of 4 characters in length is undefined.
74 The only difference between this function and fl_frame2() is the order
75 of the line segments.
76 \param[in] s sets of 4 grayscale values in top, left, bottom, right order
77 \param[in] x, y, w, h position and size
79 void fl_frame(const char* s, int x, int y, int w, int h) {
80 uchar *g = fl_gray_ramp();
81 if (h > 0 && w > 0) for (;*s;) {
82 // draw top line:
83 fl_color(g[(int)*s++]);
84 fl_xyline(x, y, x+w-1);
85 y++; if (--h <= 0) break;
86 // draw left line:
87 fl_color(g[(int)*s++]);
88 fl_yxline(x, y+h-1, y);
89 x++; if (--w <= 0) break;
90 // draw bottom line:
91 fl_color(g[(int)*s++]);
92 fl_xyline(x, y+h-1, x+w-1);
93 if (--h <= 0) break;
94 // draw right line:
95 fl_color(g[(int)*s++]);
96 fl_yxline(x+w-1, y+h-1, y);
97 if (--w <= 0) break;
102 Draws a series of line segments around the given box.
103 The string \p s must contain groups of 4 letters which specify one of 24
104 standard grayscale values, where 'A' is black and 'X' is white.
105 The order of each set of 4 characters is: bottom, right, top, left.
106 The result of calling fl_frame2() with a string that is not a multiple
107 of 4 characters in length is undefined.
108 The only difference between this function and fl_frame() is the order
109 of the line segments.
110 \param[in] s sets of 4 grayscale values in bottom, right, top, left order
111 \param[in] x, y, w, h position and size
113 void fl_frame2(const char* s, int x, int y, int w, int h) {
114 uchar *g = fl_gray_ramp();
115 if (h > 0 && w > 0) for (;*s;) {
116 // draw bottom line:
117 fl_color(g[(int)*s++]);
118 fl_xyline(x, y+h-1, x+w-1);
119 if (--h <= 0) break;
120 // draw right line:
121 fl_color(g[(int)*s++]);
122 fl_yxline(x+w-1, y+h-1, y);
123 if (--w <= 0) break;
124 // draw top line:
125 fl_color(g[(int)*s++]);
126 fl_xyline(x, y, x+w-1);
127 y++; if (--h <= 0) break;
128 // draw left line:
129 fl_color(g[(int)*s++]);
130 fl_yxline(x, y+h-1, y);
131 x++; if (--w <= 0) break;
135 /** Draws a box of type FL_NO_BOX */
136 void fl_no_box(int, int, int, int, Fl_Color) {}
138 /** Draws a frame of type FL_THIN_DOWN_FRAME */
139 void fl_thin_down_frame(int x, int y, int w, int h, Fl_Color) {
140 fl_frame2("WWHH",x,y,w,h);
143 /** Draws a box of type FL_THIN_DOWN_BOX */
144 void fl_thin_down_box(int x, int y, int w, int h, Fl_Color c) {
145 fl_thin_down_frame(x,y,w,h,c);
146 fl_color(draw_it_active ? c : fl_inactive(c));
147 fl_rectf(x+1, y+1, w-2, h-2);
150 /** Draws a frame of type FL_THIN_UP_FRAME */
151 void fl_thin_up_frame(int x, int y, int w, int h, Fl_Color) {
152 fl_frame2("HHWW",x,y,w,h);
155 /** Draws a box of type FL_THIN_UP_BOX */
156 void fl_thin_up_box(int x, int y, int w, int h, Fl_Color c) {
157 fl_thin_up_frame(x,y,w,h,c);
158 fl_color(draw_it_active ? c : fl_inactive(c));
159 fl_rectf(x+1, y+1, w-2, h-2);
162 /** Draws a frame of type FL_UP_FRAME */
163 void fl_up_frame(int x, int y, int w, int h, Fl_Color) {
164 #if BORDER_WIDTH == 1
165 fl_frame2("HHWW",x,y,w,h);
166 #else
167 #if BORDER_WIDTH == 2
168 fl_frame2("AAWWMMTT",x,y,w,h);
169 #else
170 fl_frame("AAAAWWJJUTNN",x,y,w,h);
171 #endif
172 #endif
175 #define D1 BORDER_WIDTH
176 #define D2 (BORDER_WIDTH+BORDER_WIDTH)
178 /** Draws a box of type FL_UP_BOX */
179 void fl_up_box(int x, int y, int w, int h, Fl_Color c) {
180 fl_up_frame(x,y,w,h,c);
181 fl_color(draw_it_active ? c : fl_inactive(c));
182 fl_rectf(x+D1, y+D1, w-D2, h-D2);
185 /** Draws a frame of type FL_DOWN_FRAME */
186 void fl_down_frame(int x, int y, int w, int h, Fl_Color) {
187 #if BORDER_WIDTH == 1
188 fl_frame2("WWHH",x,y,w,h);
189 #else
190 #if BORDER_WIDTH == 2
191 fl_frame2("WWMMPPAA",x,y,w,h);
192 #else
193 fl_frame("NNTUJJWWAAAA",x,y,w,h);
194 #endif
195 #endif
198 /** Draws a box of type FL_DOWN_BOX */
199 void fl_down_box(int x, int y, int w, int h, Fl_Color c) {
200 fl_down_frame(x,y,w,h,c);
201 fl_color(c); fl_rectf(x+D1, y+D1, w-D2, h-D2);
204 /** Draws a frame of type FL_ENGRAVED_FRAME */
205 void fl_engraved_frame(int x, int y, int w, int h, Fl_Color) {
206 fl_frame("HHWWWWHH",x,y,w,h);
209 /** Draws a box of type FL_ENGRAVED_BOX */
210 void fl_engraved_box(int x, int y, int w, int h, Fl_Color c) {
211 fl_engraved_frame(x,y,w,h,c);
212 fl_color(draw_it_active ? c : fl_inactive(c));
213 fl_rectf(x+2, y+2, w-4, h-4);
216 /** Draws a frame of type FL_EMBOSSED_FRAME */
217 void fl_embossed_frame(int x, int y, int w, int h, Fl_Color) {
218 fl_frame("WWHHHHWW",x,y,w,h);
221 /** Draws a box of type FL_EMBOSSED_BOX */
222 void fl_embossed_box(int x, int y, int w, int h, Fl_Color c) {
223 fl_embossed_frame(x,y,w,h,c);
224 fl_color(draw_it_active ? c : fl_inactive(c));
225 fl_rectf(x+2, y+2, w-4, h-4);
229 Draws a bounded rectangle with a given position, size and color.
230 Equivalent to drawing a box of type FL_BORDER_BOX.
232 void fl_rectbound(int x, int y, int w, int h, Fl_Color bgcolor) {
233 fl_color(draw_it_active ? FL_BLACK : fl_inactive(FL_BLACK));
234 fl_rect(x, y, w, h);
235 fl_color(draw_it_active ? bgcolor : fl_inactive(bgcolor));
236 fl_rectf(x+1, y+1, w-2, h-2);
238 #define fl_border_box fl_rectbound /**< allow consistent naming */
241 Draws a frame of type FL_BORDER_FRAME.
243 void fl_border_frame(int x, int y, int w, int h, Fl_Color c) {
244 fl_color(draw_it_active ? c : fl_inactive(c));
245 fl_rect(x, y, w, h);
249 void fl_focus_color();
251 void fl_focus_frame (int X, int Y, int W, int H, Fl_Color c )
253 fl_color(c);
255 #if defined(USE_X11) || defined(__APPLE_QUARTZ__)
256 fl_line_style(FL_DOT);
257 fl_rect(X, Y, W, H );
258 fl_line_style(FL_SOLID);
259 #elif defined(WIN32)
260 // Windows 95/98/ME do not implement the dotted line style, so draw
261 // every other pixel around the focus area...
263 // Also, QuickDraw (MacOS) does not support line styles specifically,
264 // and the hack we use in fl_line_style() will not draw horizontal lines
265 // on odd-numbered rows...
266 int i, xx, yy;
268 for (xx = 0, i = 1; xx < W; xx ++, i ++) if (i & 1) fl_point(X + xx, Y);
269 for (yy = 0; yy < H; yy ++, i ++) if (i & 1) fl_point(X + W, Y + yy);
270 for (xx = W; xx > 0; xx --, i ++) if (i & 1) fl_point(X + xx, Y + H);
271 for (yy = H; yy > 0; yy --, i ++) if (i & 1) fl_point(X, Y + yy);
272 #else
273 # error unsupported platform
274 #endif // WIN32
279 ////////////////////////////////////////////////////////////////
281 static struct {
282 Fl_Box_Draw_F *f;
283 uchar dx, dy, dw, dh;
284 int set;
285 } fl_box_table[256] = {
286 // must match list in Enumerations.H!!!
287 {fl_no_box, 0,0,0,0,1},
288 {fl_rectf, 0,0,0,0,1}, // FL_FLAT_BOX
289 {fl_up_box, D1,D1,D2,D2,1},
290 {fl_down_box, D1,D1,D2,D2,1},
291 {fl_up_frame, D1,D1,D2,D2,1},
292 {fl_down_frame, D1,D1,D2,D2,1},
293 {fl_thin_up_box, 1,1,2,2,1},
294 {fl_thin_down_box, 1,1,2,2,1},
295 {fl_thin_up_frame, 1,1,2,2,1},
296 {fl_thin_down_frame, 1,1,2,2,1},
297 {fl_engraved_box, 2,2,4,4,1},
298 {fl_embossed_box, 2,2,4,4,1},
299 {fl_engraved_frame, 2,2,4,4,1},
300 {fl_embossed_frame, 2,2,4,4,1},
301 {fl_border_box, 1,1,2,2,1},
302 {fl_border_box, 1,1,5,5,0}, // _FL_SHADOW_BOX,
303 {fl_border_frame, 1,1,2,2,1},
304 {fl_border_frame, 1,1,5,5,0}, // _FL_SHADOW_FRAME,
305 {fl_border_box, 1,1,2,2,0}, // _FL_ROUNDED_BOX,
306 {fl_border_box, 1,1,2,2,0}, // _FL_RSHADOW_BOX,
307 {fl_border_frame, 1,1,2,2,0}, // _FL_ROUNDED_FRAME
308 {fl_rectf, 0,0,0,0,0}, // _FL_RFLAT_BOX,
309 {fl_up_box, 3,3,6,6,0}, // _FL_ROUND_UP_BOX
310 {fl_down_box, 3,3,6,6,0}, // _FL_ROUND_DOWN_BOX,
311 {fl_up_box, 0,0,0,0,0}, // _FL_DIAMOND_UP_BOX
312 {fl_down_box, 0,0,0,0,0}, // _FL_DIAMOND_DOWN_BOX
313 {fl_border_box, 1,1,2,2,0}, // _FL_OVAL_BOX,
314 {fl_border_box, 1,1,2,2,0}, // _FL_OVAL_SHADOW_BOX,
315 {fl_border_frame, 1,1,2,2,0}, // _FL_OVAL_FRAME
316 {fl_rectf, 0,0,0,0,0}, // _FL_OVAL_FLAT_BOX,
317 {fl_focus_frame, 1,1,1,1,1}, // FL_FOCUS_FRAME
318 {fl_up_box, 1,1,1,1,0},
319 {fl_border_box, 1,1,1,1,0},
320 {fl_up_box, 3,3,6,6,0}, // FL_FREE_BOX+0
321 {fl_down_box, 3,3,6,6,0}, // FL_FREE_BOX+1
322 {fl_up_box, 3,3,6,6,0}, // FL_FREE_BOX+2
323 {fl_down_box, 3,3,6,6,0}, // FL_FREE_BOX+3
324 {fl_up_box, 3,3,6,6,0}, // FL_FREE_BOX+4
325 {fl_down_box, 3,3,6,6,0}, // FL_FREE_BOX+5
326 {fl_up_box, 3,3,6,6,0}, // FL_FREE_BOX+6
327 {fl_down_box, 3,3,6,6,0}, // FL_FREE_BOX+7
331 Returns the X offset for the given boxtype.
332 \see box_dy()
334 int Fl::box_dx(Fl_Boxtype t) {return fl_box_table[t].dx;}
337 Returns the Y offset for the given boxtype.
339 These functions return the offset values necessary for a given
340 boxtype, useful for computing the area inside a box's borders, to
341 prevent overdrawing the borders.
343 For instance, in the case of a boxtype like FL_DOWN_BOX
344 where the border width might be 2 pixels all around, the above
345 functions would return 2, 2, 4, and 4 for box_dx,
346 box_dy, box_dw, and box_dh respectively.
348 An example to compute the area inside a widget's box():
349 \code
350 int X = yourwidget->x() + Fl::box_dx(yourwidget->box());
351 int Y = yourwidget->y() + Fl::box_dy(yourwidget->box());
352 int W = yourwidget->w() - Fl::box_dw(yourwidget->box());
353 int H = yourwidget->h() - Fl::box_dh(yourwidget->box());
354 \endcode
355 These functions are mainly useful in the draw() code
356 for deriving custom widgets, where one wants to avoid drawing
357 over the widget's own border box().
359 int Fl::box_dy(Fl_Boxtype t) {return fl_box_table[t].dy;}
362 Returns the width offset for the given boxtype.
363 \see box_dy().
365 int Fl::box_dw(Fl_Boxtype t) {return fl_box_table[t].dw;}
368 Returns the height offset for the given boxtype.
369 \see box_dy().
371 int Fl::box_dh(Fl_Boxtype t) {return fl_box_table[t].dh;}
374 Sets the drawing function for a given box type.
375 \param[in] t box type
376 \param[in] f box drawing function
378 void fl_internal_boxtype(Fl_Boxtype t, Fl_Box_Draw_F* f) {
379 if (!fl_box_table[t].set) {
380 fl_box_table[t].f = f;
381 fl_box_table[t].set = 1;
385 /** Gets the current box drawing function for the specified box type. */
386 Fl_Box_Draw_F *Fl::get_boxtype(Fl_Boxtype t) {
387 return fl_box_table[t].f;
389 /** Sets the function to call to draw a specific boxtype. */
390 void Fl::set_boxtype(Fl_Boxtype t, Fl_Box_Draw_F* f,
391 uchar a, uchar b, uchar c, uchar d) {
392 fl_box_table[t].f = f;
393 fl_box_table[t].set = 1;
394 fl_box_table[t].dx = a;
395 fl_box_table[t].dy = b;
396 fl_box_table[t].dw = c;
397 fl_box_table[t].dh = d;
399 /** Copies the from boxtype. */
400 void Fl::set_boxtype(Fl_Boxtype to, Fl_Boxtype from) {
401 fl_box_table[to] = fl_box_table[from];
405 Draws a box using given type, position, size and color.
406 \param[in] t box type
407 \param[in] x, y, w, h position and size
408 \param[in] c color
410 void fl_draw_box(Fl_Boxtype t, int x, int y, int w, int h, Fl_Color c) {
411 if (t && fl_box_table[t].f) fl_box_table[t].f(x,y,w,h,c);
414 //extern Fl_Widget *fl_boxcheat; // hack set by Fl_Window.cxx
415 /** Draws the widget box according its box style */
416 void Fl_Widget::draw_box() const {
417 if (box_) draw_box((Fl_Boxtype)box_, x_, y_, w_, h_, color_);
420 static const Fl_Image *
421 get_backdrop_image ( const Fl_Widget *o )
423 if (o->align() & FL_ALIGN_IMAGE_BACKDROP ||
424 o->type() >= FL_WINDOW ) {
425 const Fl_Image *img = o->image();
426 // if there is no image, we will not draw the deimage either
427 if (img && o->deimage() && !o->active_r())
428 img = o->deimage();
430 return img;
433 return 0;
436 /** If FL_ALIGN_IMAGE_BACKDROP is set, the image or deimage will be drawn */
437 void Fl_Widget::draw_backdrop() const {
439 const Fl_Image *img = get_backdrop_image(this);
441 if (img)
443 if ( type() < FL_WINDOW )
445 /* FIXME: There's something broken about tiled images
446 * larger than some dimension of the space they're
447 * meant to tile over that this clipping is a
448 * hack for. */
449 fl_push_clip( x_, y_, w_, h_ );
450 ((Fl_Image*)img)->draw(x_, y_ );
451 fl_pop_clip();
453 else
455 ((Fl_Image*)img)->draw( 0, 0, w_, h_);
459 /** Draws a box of type t, of color c at the widget's position and size. */
460 void Fl_Widget::draw_box(Fl_Boxtype t, Fl_Color c) const {
461 draw_box(t, x_, y_, w_, h_, c);
463 /** Draws a box of type t, of color c at the position X,Y and size W,H. */
464 void Fl_Widget::draw_box(Fl_Boxtype t, int X, int Y, int W, int H, Fl_Color c) const {
465 draw_it_active = active_r();
467 if ( get_backdrop_image(this) )
469 draw_backdrop();
471 switch ( box() )
473 case FL_UP_FRAME:
474 case FL_DOWN_FRAME:
475 case FL_EMBOSSED_FRAME:
476 case FL_ENGRAVED_FRAME:
477 case FL_THIN_UP_FRAME:
478 case FL_THIN_DOWN_FRAME:
479 case FL_BORDER_FRAME:
480 case _FL_SHADOW_FRAME:
481 case _FL_ROUNDED_FRAME:
482 fl_box_table[t].f(X, Y, W, H, c);
483 break;
484 default:
485 break;
488 else
489 fl_box_table[t].f(X, Y, W, H, c);
491 draw_it_active = 1;
495 // End of "$Id: fl_boxtype.cxx 7903 2010-11-28 21:06:39Z matt $".