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)  

fl_color.cxx

Go to the documentation of this file.
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 //