Bump version.
[ntk.git] / src / fl_color.cxx
blob5ea9036e218d5fe400957fb39b4f8f69d9d985b3
1 //
2 // "$Id: fl_color.cxx 8384 2011-02-06 12:32:23Z manolo $"
3 //
4 // Color functions for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2010 by Bill Spitzak and others.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 // USA.
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
28 /**
29 \file fl_color.cxx
30 \brief Color handling
33 // Implementation of fl_color(i), fl_color(r,g,b).
35 #ifdef WIN32
36 # include "fl_color_win32.cxx"
37 #elif defined(__APPLE__)
38 # include "fl_color_mac.cxx"
39 #else
41 // Also code to look at the X visual and figure out the best way to turn
42 // a color into a pixel value.
44 // SGI compiler seems to have problems with unsigned char arguments
45 // being used to index arrays. So I always copy them to an integer
46 // before use.
48 # include "Fl_XColor.H"
49 # include <FL/Fl.H>
50 # include <FL/x.H>
51 # include <FL/fl_draw.H>
53 ////////////////////////////////////////////////////////////////
54 // figure_out_visual() calculates masks & shifts for generating
55 // pixels in true-color visuals:
57 uchar fl_redmask; /**< color mask used in current color map handling */
58 uchar fl_greenmask; /**< color mask used in current color map handling */
59 uchar fl_bluemask; /**< color mask used in current color map handling */
61 int fl_redshift; /**< color shift used in current color map handling */
62 int fl_greenshift; /**< color shift used in current color map handling */
63 int fl_blueshift; /**< color shift used in current color map handling */
64 int fl_extrashift; /**< color shift used in current color map handling */
66 static uchar beenhere;
68 static void figure_out_visual() {
69 beenhere = 1;
70 if (!fl_visual->red_mask || !fl_visual->green_mask || !fl_visual->blue_mask){
71 # if USE_COLORMAP
72 fl_redmask = 0;
73 return;
74 # else
75 Fl::fatal("Requires true color visual");
76 # endif
79 // get the bit masks into a more useful form:
80 int i,j,m;
82 for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->red_mask & m) break;
83 for (j = i; m; j++, m<<=1) if (!(fl_visual->red_mask & m)) break;
84 fl_redshift = j-8;
85 fl_redmask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i));
87 for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->green_mask & m) break;
88 for (j = i; m; j++, m<<=1) if (!(fl_visual->green_mask & m)) break;
89 fl_greenshift = j-8;
90 fl_greenmask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i));
92 for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->blue_mask & m) break;
93 for (j = i; m; j++, m<<=1) if (!(fl_visual->blue_mask & m)) break;
94 fl_blueshift = j-8;
95 fl_bluemask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i));
97 i = fl_redshift;
98 if (fl_greenshift < i) i = fl_greenshift;
99 if (fl_blueshift < i) i = fl_blueshift;
100 if (i < 0) {
101 fl_extrashift = -i;
102 fl_redshift -= i; fl_greenshift -= i; fl_blueshift -= i;
103 } else
104 fl_extrashift = 0;
108 static unsigned fl_cmap[256] = {
109 #include "fl_cmap.h" // this is a file produced by "cmap.cxx":
112 Fl_XColor fl_xmap[1][256];
113 # define fl_overlay 0
115 void Fl_Xlib_Graphics_Driver::color(Fl_Color i) {
116 if (i & 0xffffff00) {
117 unsigned rgb = (unsigned)i;
118 fl_color((uchar)(rgb >> 24), (uchar)(rgb >> 16), (uchar)(rgb >> 8));
119 } else {
120 Fl_Graphics_Driver::color(i);
121 if(!fl_gc) return; // don't get a default gc if current window is not yet created/valid
122 XSetForeground(fl_display, fl_gc, fl_xpixel(i));
126 void Fl_Xlib_Graphics_Driver::color(uchar r,uchar g,uchar b) {
127 Fl_Graphics_Driver::color( fl_rgb_color(r, g, b) );
128 if(!fl_gc) return; // don't get a default gc if current window is not yet created/valid
129 XSetForeground(fl_display, fl_gc, fl_xpixel(r,g,b));
132 /** \addtogroup fl_attributes
133 @{ */
134 ////////////////////////////////////////////////////////////////
135 // Get an rgb color. This is easy for a truecolor visual. For
136 // colormapped it picks the closest color out of the cube in the
137 // fltk colormap. However if this color cube entry has been
138 // requested before, you will get the earlier requested color, and
139 // even this may be approximated if the X colormap was full.
142 Returns the X pixel number used to draw the given rgb color.
143 This is the X pixel that fl_color() would use.
144 \param[in] r,g,b color components
145 \return X pixel number
147 ulong fl_xpixel(uchar r,uchar g,uchar b) {
148 if (!beenhere) figure_out_visual();
149 # if USE_COLORMAP
150 if (!fl_redmask) {
151 // find closest entry in the colormap:
152 Fl_Color i =
153 fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256);
154 Fl_XColor &xmap = fl_xmap[fl_overlay][i];
155 if (xmap.mapped) return xmap.pixel;
156 // if not black or white, change the entry to be an exact match:
157 if (i != FL_COLOR_CUBE && i != 0xFF)
158 fl_cmap[i] = (r<<24)|(g<<16)|(b<<8);
159 return fl_xpixel(i); // allocate an X color
161 # endif
162 return
163 (((r&fl_redmask) << fl_redshift)+
164 ((g&fl_greenmask)<<fl_greenshift)+
165 ((b&fl_bluemask)<< fl_blueshift)
166 ) >> fl_extrashift;
169 ////////////////////////////////////////////////////////////////
170 // Get a color out of the fltk colormap. Again for truecolor
171 // visuals this is easy. For colormap this actually tries to allocate
172 // an X color, and does a least-squares match to find the closest
173 // color if X cannot allocate that color.
175 // calculate what color is actually on the screen for a mask:
176 static inline uchar realcolor(uchar color, uchar mask) {
177 # if 0
178 // accurate version if the display has linear gamma, but fl_draw_image
179 // works better with the simpler version on most screens...
180 uchar m = mask;
181 uchar result = color&m;
182 for (;;) {
183 while (m&mask) {m>>=1; color>>=1;}
184 if (!m) break;
185 mask = m;
186 result |= color&m;
188 return result;
189 # else
190 return (color&mask) | ( (~mask)&(mask>>1) );
191 # endif
195 Returns the X pixel number used to draw the given FLTK color index.
196 This is the X pixel that fl_color() would use.
197 \param[in] i color index
198 \return X pixel number
200 ulong fl_xpixel(Fl_Color i) {
201 if (i & 0xffffff00) {
202 return fl_xpixel((i >> 24) & 255, (i >> 16) & 255, (i >> 8) & 255);
205 Fl_XColor &xmap = fl_xmap[fl_overlay][i];
206 if (xmap.mapped) return xmap.pixel;
208 if (!beenhere) figure_out_visual();
210 uchar r,g,b;
211 {unsigned c = fl_cmap[i]; r=uchar(c>>24); g=uchar(c>>16); b=uchar(c>>8);}
213 # if USE_COLORMAP
214 Colormap colormap = fl_colormap;
215 if (fl_redmask) {
216 # endif
217 // return color for a truecolor visual:
218 xmap.mapped = 2; // 2 prevents XFreeColor from being called
219 xmap.r = realcolor(r, fl_redmask);
220 xmap.g = realcolor(g, fl_greenmask);
221 xmap.b = realcolor(b, fl_bluemask);
222 return xmap.pixel =
223 (((r&fl_redmask) << fl_redshift)+
224 ((g&fl_greenmask)<<fl_greenshift)+
225 ((b&fl_bluemask)<< fl_blueshift)
226 ) >> fl_extrashift;
227 # if USE_COLORMAP
229 static XColor *allcolors;
230 static int numcolors;
232 // I don't try to allocate colors with XAllocColor once it fails
233 // with any color. It is possible that it will work, since a color
234 // may have been freed, but some servers are extremely slow and this
235 // avoids one round trip:
236 if (!numcolors) { // don't try after a failure
237 XColor xcol;
238 xcol.red = r<<8; xcol.green = g<<8; xcol.blue = b<<8;
239 if (XAllocColor(fl_display, colormap, &xcol)) {
240 xmap.mapped = 1;
241 xmap.r = xcol.red>>8;
242 xmap.g = xcol.green>>8;
243 xmap.b = xcol.blue>>8;
244 return xmap.pixel = xcol.pixel;
247 // I only read the colormap once. Again this is due to the slowness
248 // of round-trips to the X server, even though other programs may alter
249 // the colormap after this and make decisions here wrong.
250 numcolors = fl_visual->colormap_size;
251 if (!allcolors) allcolors = new XColor[numcolors];
252 for (int p = numcolors; p--;) allcolors[p].pixel = p;
253 XQueryColors(fl_display, colormap, allcolors, numcolors);
256 // find least-squares match:
257 int mindist = 0x7FFFFFFF;
258 unsigned int bestmatch = 0;
259 for (unsigned int n = numcolors; n--;) {
260 XColor &a = allcolors[n];
261 int d, t;
262 t = int(r)-int(a.red>>8); d = t*t;
263 t = int(g)-int(a.green>>8); d += t*t;
264 t = int(b)-int(a.blue>>8); d += t*t;
265 if (d <= mindist) {bestmatch = n; mindist = d;}
267 XColor &p = allcolors[bestmatch];
269 // It appears to "work" to not call this XAllocColor, which will
270 // avoid another round-trip to the server. But then X does not
271 // know that this program "owns" this value, and can (and will)
272 // change it when the program that did allocate it exits:
273 if (XAllocColor(fl_display, colormap, &p)) {
274 xmap.mapped = 1;
275 xmap.pixel = p.pixel;
276 } else {
277 // However, if that XAllocColor fails, I have to give up and
278 // assume the pixel is ok for the duration of the program. This
279 // is due to bugs (?) in the Solaris X and some X terminals
280 // where XAllocColor *always* fails when the colormap is full,
281 // even if we ask for a color already in it...
282 xmap.mapped = 2; // 2 prevents XFreeColor from being called
283 xmap.pixel = bestmatch;
285 xmap.r = p.red>>8;
286 xmap.g = p.green>>8;
287 xmap.b = p.blue>>8;
288 return xmap.pixel;
289 # endif
293 Free color \p i if used, and clear mapping table entry.
294 \param[in] i color index
295 \param[in] overlay 0 for normal, 1 for overlay color
297 void Fl::free_color(Fl_Color i, int overlay) {
298 if (overlay) return;
299 if (fl_xmap[overlay][i].mapped) {
300 # if USE_COLORMAP
301 Colormap colormap = fl_colormap;
302 if (fl_xmap[overlay][i].mapped == 1)
303 XFreeColors(fl_display, colormap, &(fl_xmap[overlay][i].pixel), 1, 0);
304 # endif
305 fl_xmap[overlay][i].mapped = 0;
310 Set color mapping table entry \p i to color \p c
311 \param[in] i color index
312 \param[in] c color
314 void Fl::set_color(Fl_Color i, unsigned c) {
315 if (fl_cmap[i] != c) {
316 free_color(i,0);
317 fl_cmap[i] = c;
321 #endif // end of X-specific code
323 Returns the RGB value(s) for the given FLTK color index.
325 This form returns the RGB values packed in a 32-bit unsigned
326 integer with the red value in the upper 8 bits, the green value
327 in the next 8 bits, and the blue value in bits 8-15. The lower
328 8 bits will always be 0.
330 unsigned Fl::get_color(Fl_Color i) {
331 if (i & 0xffffff00) return (i);
332 else return fl_cmap[i];
335 Sets an entry in the fl_color index table. You can set it to
336 any 8-bit RGB color. The color is not allocated until fl_color(i)
337 is used.
339 void Fl::set_color(Fl_Color i, uchar red, uchar green, uchar blue) {
340 Fl::set_color((Fl_Color)(i & 255),
341 ((unsigned)red<<24)+((unsigned)green<<16)+((unsigned)blue<<8));
344 Returns the RGB value(s) for the given FLTK color index.
346 This form returns the red, green, and blue values
347 separately in referenced variables.
349 See also unsigned get_color(Fl_Color c)
351 void Fl::get_color(Fl_Color i, uchar &red, uchar &green, uchar &blue) {
352 unsigned c;
354 if (i & 0xffffff00) c = (unsigned)i;
355 else c = fl_cmap[i];
357 red = uchar(c>>24);
358 green = uchar(c>>16);
359 blue = uchar(c>>8);
363 Returns the weighted average color between the two given colors.
364 The red, green and blue values are averages using the following formula:
365 \code
366 color = color1 * weight + color2 * (1 - weight)
367 \endcode
368 Thus, a \p weight value of 1.0 will return the first color, while a
369 value of 0.0 will return the second color.
370 \param[in] color1, color2 boundary colors
371 \param[in] weight weighting factor
373 Fl_Color fl_color_average(Fl_Color color1, Fl_Color color2, float weight) {
374 unsigned rgb1;
375 unsigned rgb2;
376 uchar r, g, b;
378 if (color1 & 0xffffff00) rgb1 = color1;
379 else rgb1 = fl_cmap[color1 & 255];
381 if (color2 & 0xffffff00) rgb2 = color2;
382 else rgb2 = fl_cmap[color2 & 255];
384 r = (uchar)(((uchar)(rgb1>>24))*weight + ((uchar)(rgb2>>24))*(1-weight));
385 g = (uchar)(((uchar)(rgb1>>16))*weight + ((uchar)(rgb2>>16))*(1-weight));
386 b = (uchar)(((uchar)(rgb1>>8))*weight + ((uchar)(rgb2>>8))*(1-weight));
388 return fl_rgb_color(r, g, b);
392 Returns the inactive, dimmed version of the given color
394 Fl_Color fl_inactive(Fl_Color c) {
395 return fl_color_average(c, FL_GRAY, .33f);
399 static int get_luminosity ( Fl_Color c1 )
401 return ((c1 >> 24) * 30 + ((c1 >> 16) & 255) * 59 + ((c1 >> 8) & 255) * 11) / 100;
405 Returns a color that contrasts with the background color.
406 This will be the foreground color if it contrasts sufficiently with the
407 background color. Otherwise, returns \p FL_WHITE or \p FL_BLACK depending
408 on which color provides the best contrast.
409 \param[in] fg,bg foreground and background colors
410 \return contrasting color
412 Fl_Color fl_contrast(Fl_Color fg, Fl_Color bg) {
413 unsigned c1, c2, flbg, flfg; // RGB colors
414 int l1, l2, l3, l4; // Luminosities
417 // Get the RGB values for each color...
418 if (fg & 0xffffff00) c1 = (unsigned)fg;
419 else c1 = fl_cmap[fg];
421 if (bg & 0xffffff00) c2 = (unsigned)bg;
422 else c2 = fl_cmap[bg];
424 if (FL_BACKGROUND_COLOR & 0xffffff00) flbg = (unsigned)FL_BACKGROUND_COLOR;
425 else flbg = fl_cmap[FL_BACKGROUND_COLOR];
427 if (FL_FOREGROUND_COLOR & 0xffffff00) flfg = (unsigned)FL_FOREGROUND_COLOR;
428 else flfg = fl_cmap[FL_FOREGROUND_COLOR];
430 // Compute the luminosity...
431 l1 = get_luminosity(c1);
432 l2 = get_luminosity(c2);
433 l3 = get_luminosity(flbg);
434 l4 = get_luminosity(flfg);
436 // Compare and return the contrasting color...
437 if ((l1 - l2) > 99) return fg;
438 else if ((l2 - l1) > 99) return fg;
439 else
441 return abs( l2 - l3 ) > abs( l2 - l4 ) ? FL_BACKGROUND_COLOR : FL_FOREGROUND_COLOR;
448 // End of "$Id: fl_color.cxx 8384 2011-02-06 12:32:23Z manolo $".