2 // "$Id: fl_color.cxx 8384 2011-02-06 12:32:23Z manolo $"
4 // Color functions for the Fast Light Tool Kit (FLTK).
6 // Copyright 1998-2010 by Bill Spitzak and others.
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
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
33 // Implementation of fl_color(i), fl_color(r,g,b).
36 # include "fl_color_win32.cxx"
37 #elif defined(__APPLE__)
38 # include "fl_color_mac.cxx"
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
48 # include "Fl_XColor.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() {
70 if (!fl_visual
->red_mask
|| !fl_visual
->green_mask
|| !fl_visual
->blue_mask
){
75 Fl::fatal("Requires true color visual");
79 // get the bit masks into a more useful form:
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;
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;
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;
95 fl_bluemask
= (j
-i
>= 8) ? 0xFF : 0xFF-(255>>(j
-i
));
98 if (fl_greenshift
< i
) i
= fl_greenshift
;
99 if (fl_blueshift
< i
) i
= fl_blueshift
;
102 fl_redshift
-= i
; fl_greenshift
-= i
; fl_blueshift
-= i
;
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));
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
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();
151 // find closest entry in the colormap:
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
163 (((r
&fl_redmask
) << fl_redshift
)+
164 ((g
&fl_greenmask
)<<fl_greenshift
)+
165 ((b
&fl_bluemask
)<< fl_blueshift
)
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
) {
178 // accurate version if the display has linear gamma, but fl_draw_image
179 // works better with the simpler version on most screens...
181 uchar result
= color
&m
;
183 while (m
&mask
) {m
>>=1; color
>>=1;}
190 return (color
&mask
) | ( (~mask
)&(mask
>>1) );
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();
211 {unsigned c
= fl_cmap
[i
]; r
=uchar(c
>>24); g
=uchar(c
>>16); b
=uchar(c
>>8);}
214 Colormap colormap
= fl_colormap
;
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
);
223 (((r
&fl_redmask
) << fl_redshift
)+
224 ((g
&fl_greenmask
)<<fl_greenshift
)+
225 ((b
&fl_bluemask
)<< fl_blueshift
)
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
238 xcol
.red
= r
<<8; xcol
.green
= g
<<8; xcol
.blue
= b
<<8;
239 if (XAllocColor(fl_display
, colormap
, &xcol
)) {
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
];
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
)) {
275 xmap
.pixel
= p
.pixel
;
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
;
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
) {
299 if (fl_xmap
[overlay
][i
].mapped
) {
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);
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
314 void Fl::set_color(Fl_Color i
, unsigned c
) {
315 if (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)
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
) {
354 if (i
& 0xffffff00) c
= (unsigned)i
;
358 green
= uchar(c
>>16);
363 Returns the weighted average color between the two given colors.
364 The red, green and blue values are averages using the following formula:
366 color = color1 * weight + color2 * (1 - weight)
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
) {
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
;
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 $".