|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 // 00002 // "$Id: fl_color.cxx 8129 2010-12-28 15:33:36Z manolo $" 00003 // 00004 // Color functions for the Fast Light Tool Kit (FLTK). 00005 // 00006 // Copyright 1998-2010 by Bill Spitzak and others. 00007 // 00008 // This library is free software; you can redistribute it and/or 00009 // modify it under the terms of the GNU Library General Public 00010 // License as published by the Free Software Foundation; either 00011 // version 2 of the License, or (at your option) any later version. 00012 // 00013 // This library is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 // Library General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Library General Public 00019 // License along with this library; if not, write to the Free Software 00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00021 // USA. 00022 // 00023 // Please report all bugs and problems on the following page: 00024 // 00025 // http://www.fltk.org/str.php 00026 // 00027 00033 // Implementation of fl_color(i), fl_color(r,g,b). 00034 00035 #ifdef WIN32 00036 # include "fl_color_win32.cxx" 00037 #elif defined(__APPLE__) 00038 # include "fl_color_mac.cxx" 00039 #else 00040 00041 // Also code to look at the X visual and figure out the best way to turn 00042 // a color into a pixel value. 00043 00044 // SGI compiler seems to have problems with unsigned char arguments 00045 // being used to index arrays. So I always copy them to an integer 00046 // before use. 00047 00048 # include "Fl_XColor.H" 00049 # include <FL/Fl.H> 00050 # include <FL/x.H> 00051 # include <FL/fl_draw.H> 00052 00054 // figure_out_visual() calculates masks & shifts for generating 00055 // pixels in true-color visuals: 00056 00057 uchar fl_redmask; 00058 uchar fl_greenmask; 00059 uchar fl_bluemask; 00061 int fl_redshift; 00062 int fl_greenshift; 00063 int fl_blueshift; 00064 int fl_extrashift; 00066 static uchar beenhere; 00067 00068 static void figure_out_visual() { 00069 beenhere = 1; 00070 if (!fl_visual->red_mask || !fl_visual->green_mask || !fl_visual->blue_mask){ 00071 # if USE_COLORMAP 00072 fl_redmask = 0; 00073 return; 00074 # else 00075 Fl::fatal("Requires true color visual"); 00076 # endif 00077 } 00078 00079 // get the bit masks into a more useful form: 00080 int i,j,m; 00081 00082 for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->red_mask & m) break; 00083 for (j = i; m; j++, m<<=1) if (!(fl_visual->red_mask & m)) break; 00084 fl_redshift = j-8; 00085 fl_redmask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i)); 00086 00087 for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->green_mask & m) break; 00088 for (j = i; m; j++, m<<=1) if (!(fl_visual->green_mask & m)) break; 00089 fl_greenshift = j-8; 00090 fl_greenmask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i)); 00091 00092 for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->blue_mask & m) break; 00093 for (j = i; m; j++, m<<=1) if (!(fl_visual->blue_mask & m)) break; 00094 fl_blueshift = j-8; 00095 fl_bluemask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i)); 00096 00097 i = fl_redshift; 00098 if (fl_greenshift < i) i = fl_greenshift; 00099 if (fl_blueshift < i) i = fl_blueshift; 00100 if (i < 0) { 00101 fl_extrashift = -i; 00102 fl_redshift -= i; fl_greenshift -= i; fl_blueshift -= i; 00103 } else 00104 fl_extrashift = 0; 00105 00106 } 00107 00108 static unsigned fl_cmap[256] = { 00109 #include "fl_cmap.h" // this is a file produced by "cmap.cxx": 00110 }; 00111 00112 # if HAVE_OVERLAY 00113 00114 Fl_XColor fl_xmap[2][256]; 00116 uchar fl_overlay; 00117 Colormap fl_overlay_colormap; 00118 XVisualInfo* fl_overlay_visual; 00119 ulong fl_transparent_pixel; 00120 # else 00121 00122 Fl_XColor fl_xmap[1][256]; 00124 # define fl_overlay 0 00125 # endif 00126 00128 Fl_Color fl_color_; 00129 00130 void Fl_Xlib_Graphics_Driver::color(Fl_Color i) { 00131 if (i & 0xffffff00) { 00132 unsigned rgb = (unsigned)i; 00133 fl_color((uchar)(rgb >> 24), (uchar)(rgb >> 16), (uchar)(rgb >> 8)); 00134 } else { 00135 fl_color_ = i; 00136 if(!fl_gc) return; // don't get a default gc if current window is not yet created/valid 00137 XSetForeground(fl_display, fl_gc, fl_xpixel(i)); 00138 } 00139 } 00140 00141 void Fl_Xlib_Graphics_Driver::color(uchar r,uchar g,uchar b) { 00142 fl_color_ = fl_rgb_color(r, g, b); 00143 if(!fl_gc) return; // don't get a default gc if current window is not yet created/valid 00144 XSetForeground(fl_display, fl_gc, fl_xpixel(r,g,b)); 00145 } 00146 00149 00150 // Get an rgb color. This is easy for a truecolor visual. For 00151 // colormapped it picks the closest color out of the cube in the 00152 // fltk colormap. However if this color cube entry has been 00153 // requested before, you will get the earlier requested color, and 00154 // even this may be approximated if the X colormap was full. 00155 00162 ulong fl_xpixel(uchar r,uchar g,uchar b) { 00163 if (!beenhere) figure_out_visual(); 00164 # if USE_COLORMAP 00165 if (!fl_redmask) { 00166 // find closest entry in the colormap: 00167 Fl_Color i = 00168 fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256); 00169 Fl_XColor &xmap = fl_xmap[fl_overlay][i]; 00170 if (xmap.mapped) return xmap.pixel; 00171 // if not black or white, change the entry to be an exact match: 00172 if (i != FL_COLOR_CUBE && i != 0xFF) 00173 fl_cmap[i] = (r<<24)|(g<<16)|(b<<8); 00174 return fl_xpixel(i); // allocate an X color 00175 } 00176 # endif 00177 return 00178 (((r&fl_redmask) << fl_redshift)+ 00179 ((g&fl_greenmask)<<fl_greenshift)+ 00180 ((b&fl_bluemask)<< fl_blueshift) 00181 ) >> fl_extrashift; 00182 } 00183 00185 // Get a color out of the fltk colormap. Again for truecolor 00186 // visuals this is easy. For colormap this actually tries to allocate 00187 // an X color, and does a least-squares match to find the closest 00188 // color if X cannot allocate that color. 00189 00190 // calculate what color is actually on the screen for a mask: 00191 static inline uchar realcolor(uchar color, uchar mask) { 00192 # if 0 00193 // accurate version if the display has linear gamma, but fl_draw_image 00194 // works better with the simpler version on most screens... 00195 uchar m = mask; 00196 uchar result = color&m; 00197 for (;;) { 00198 while (m&mask) {m>>=1; color>>=1;} 00199 if (!m) break; 00200 mask = m; 00201 result |= color&m; 00202 } 00203 return result; 00204 # else 00205 return (color&mask) | ( (~mask)&(mask>>1) ); 00206 # endif 00207 } 00208 00215 ulong fl_xpixel(Fl_Color i) { 00216 if (i & 0xffffff00) { 00217 return fl_xpixel((i >> 24) & 255, (i >> 16) & 255, (i >> 8) & 255); 00218 } 00219 00220 Fl_XColor &xmap = fl_xmap[fl_overlay][i]; 00221 if (xmap.mapped) return xmap.pixel; 00222 00223 if (!beenhere) figure_out_visual(); 00224 00225 uchar r,g,b; 00226 {unsigned c = fl_cmap[i]; r=uchar(c>>24); g=uchar(c>>16); b=uchar(c>>8);} 00227 00228 # if USE_COLORMAP 00229 Colormap colormap = fl_colormap; 00230 # if HAVE_OVERLAY 00231 if (fl_overlay) colormap = fl_overlay_colormap; else 00232 # endif 00233 if (fl_redmask) { 00234 # endif 00235 // return color for a truecolor visual: 00236 xmap.mapped = 2; // 2 prevents XFreeColor from being called 00237 xmap.r = realcolor(r, fl_redmask); 00238 xmap.g = realcolor(g, fl_greenmask); 00239 xmap.b = realcolor(b, fl_bluemask); 00240 return xmap.pixel = 00241 (((r&fl_redmask) << fl_redshift)+ 00242 ((g&fl_greenmask)<<fl_greenshift)+ 00243 ((b&fl_bluemask)<< fl_blueshift) 00244 ) >> fl_extrashift; 00245 # if USE_COLORMAP 00246 } 00247 # if HAVE_OVERLAY 00248 static XColor* ac[2]; 00249 XColor*& allcolors = ac[fl_overlay]; 00250 static int nc[2]; 00251 int& numcolors = nc[fl_overlay]; 00252 # else 00253 static XColor *allcolors; 00254 static int numcolors; 00255 # endif 00256 00257 // I don't try to allocate colors with XAllocColor once it fails 00258 // with any color. It is possible that it will work, since a color 00259 // may have been freed, but some servers are extremely slow and this 00260 // avoids one round trip: 00261 if (!numcolors) { // don't try after a failure 00262 XColor xcol; 00263 xcol.red = r<<8; xcol.green = g<<8; xcol.blue = b<<8; 00264 if (XAllocColor(fl_display, colormap, &xcol)) { 00265 xmap.mapped = 1; 00266 xmap.r = xcol.red>>8; 00267 xmap.g = xcol.green>>8; 00268 xmap.b = xcol.blue>>8; 00269 return xmap.pixel = xcol.pixel; 00270 } 00271 00272 // I only read the colormap once. Again this is due to the slowness 00273 // of round-trips to the X server, even though other programs may alter 00274 // the colormap after this and make decisions here wrong. 00275 # if HAVE_OVERLAY 00276 if (fl_overlay) numcolors = fl_overlay_visual->colormap_size; else 00277 # endif 00278 numcolors = fl_visual->colormap_size; 00279 if (!allcolors) allcolors = new XColor[numcolors]; 00280 for (int p = numcolors; p--;) allcolors[p].pixel = p; 00281 XQueryColors(fl_display, colormap, allcolors, numcolors); 00282 } 00283 00284 // find least-squares match: 00285 int mindist = 0x7FFFFFFF; 00286 unsigned int bestmatch = 0; 00287 for (unsigned int n = numcolors; n--;) { 00288 # if HAVE_OVERLAY 00289 if (fl_overlay && n == fl_transparent_pixel) continue; 00290 # endif 00291 XColor &a = allcolors[n]; 00292 int d, t; 00293 t = int(r)-int(a.red>>8); d = t*t; 00294 t = int(g)-int(a.green>>8); d += t*t; 00295 t = int(b)-int(a.blue>>8); d += t*t; 00296 if (d <= mindist) {bestmatch = n; mindist = d;} 00297 } 00298 XColor &p = allcolors[bestmatch]; 00299 00300 // It appears to "work" to not call this XAllocColor, which will 00301 // avoid another round-trip to the server. But then X does not 00302 // know that this program "owns" this value, and can (and will) 00303 // change it when the program that did allocate it exits: 00304 if (XAllocColor(fl_display, colormap, &p)) { 00305 xmap.mapped = 1; 00306 xmap.pixel = p.pixel; 00307 } else { 00308 // However, if that XAllocColor fails, I have to give up and 00309 // assume the pixel is ok for the duration of the program. This 00310 // is due to bugs (?) in the Solaris X and some X terminals 00311 // where XAllocColor *always* fails when the colormap is full, 00312 // even if we ask for a color already in it... 00313 xmap.mapped = 2; // 2 prevents XFreeColor from being called 00314 xmap.pixel = bestmatch; 00315 } 00316 xmap.r = p.red>>8; 00317 xmap.g = p.green>>8; 00318 xmap.b = p.blue>>8; 00319 return xmap.pixel; 00320 # endif 00321 } 00322 00328 void Fl::free_color(Fl_Color i, int overlay) { 00329 # if HAVE_OVERLAY 00330 # else 00331 if (overlay) return; 00332 # endif 00333 if (fl_xmap[overlay][i].mapped) { 00334 # if USE_COLORMAP 00335 # if HAVE_OVERLAY 00336 Colormap colormap = overlay ? fl_overlay_colormap : fl_colormap; 00337 # else 00338 Colormap colormap = fl_colormap; 00339 # endif 00340 if (fl_xmap[overlay][i].mapped == 1) 00341 XFreeColors(fl_display, colormap, &(fl_xmap[overlay][i].pixel), 1, 0); 00342 # endif 00343 fl_xmap[overlay][i].mapped = 0; 00344 } 00345 } 00346 00352 void Fl::set_color(Fl_Color i, unsigned c) { 00353 if (fl_cmap[i] != c) { 00354 free_color(i,0); 00355 # if HAVE_OVERLAY 00356 free_color(i,1); 00357 # endif 00358 fl_cmap[i] = c; 00359 } 00360 } 00361 00362 #endif // end of X-specific code 00363 00371 unsigned Fl::get_color(Fl_Color i) { 00372 if (i & 0xffffff00) return (i); 00373 else return fl_cmap[i]; 00374 } 00380 void Fl::set_color(Fl_Color i, uchar red, uchar green, uchar blue) { 00381 Fl::set_color((Fl_Color)(i & 255), 00382 ((unsigned)red<<24)+((unsigned)green<<16)+((unsigned)blue<<8)); 00383 } 00392 void Fl::get_color(Fl_Color i, uchar &red, uchar &green, uchar &blue) { 00393 unsigned c; 00394 00395 if (i & 0xffffff00) c = (unsigned)i; 00396 else c = fl_cmap[i]; 00397 00398 red = uchar(c>>24); 00399 green = uchar(c>>16); 00400 blue = uchar(c>>8); 00401 } 00402 00414 Fl_Color fl_color_average(Fl_Color color1, Fl_Color color2, float weight) { 00415 unsigned rgb1; 00416 unsigned rgb2; 00417 uchar r, g, b; 00418 00419 if (color1 & 0xffffff00) rgb1 = color1; 00420 else rgb1 = fl_cmap[color1 & 255]; 00421 00422 if (color2 & 0xffffff00) rgb2 = color2; 00423 else rgb2 = fl_cmap[color2 & 255]; 00424 00425 r = (uchar)(((uchar)(rgb1>>24))*weight + ((uchar)(rgb2>>24))*(1-weight)); 00426 g = (uchar)(((uchar)(rgb1>>16))*weight + ((uchar)(rgb2>>16))*(1-weight)); 00427 b = (uchar)(((uchar)(rgb1>>8))*weight + ((uchar)(rgb2>>8))*(1-weight)); 00428 00429 return fl_rgb_color(r, g, b); 00430 } 00431 00435 Fl_Color fl_inactive(Fl_Color c) { 00436 return fl_color_average(c, FL_GRAY, .33f); 00437 } 00438 00447 Fl_Color fl_contrast(Fl_Color fg, Fl_Color bg) { 00448 unsigned c1, c2; // RGB colors 00449 int l1, l2; // Luminosities 00450 00451 00452 // Get the RGB values for each color... 00453 if (fg & 0xffffff00) c1 = (unsigned)fg; 00454 else c1 = fl_cmap[fg]; 00455 00456 if (bg & 0xffffff00) c2 = (unsigned)bg; 00457 else c2 = fl_cmap[bg]; 00458 00459 // Compute the luminosity... 00460 l1 = ((c1 >> 24) * 30 + ((c1 >> 16) & 255) * 59 + ((c1 >> 8) & 255) * 11) / 100; 00461 l2 = ((c2 >> 24) * 30 + ((c2 >> 16) & 255) * 59 + ((c2 >> 8) & 255) * 11) / 100; 00462 00463 // Compare and return the contrasting color... 00464 if ((l1 - l2) > 99) return fg; 00465 else if ((l2 - l1) > 99) return fg; 00466 else if (l2 > 127) return FL_BLACK; 00467 else return FL_WHITE; 00468 } 00472 // 00473 // End of "$Id: fl_color.cxx 8129 2010-12-28 15:33:36Z manolo $". 00474 //