Back to index

plt-scheme  4.2.1
Colour.cc
Go to the documentation of this file.
00001 /*                                                      -*- C++ -*-
00002  *
00003  * Purpose: classes to cover colours and colourmaps
00004  *
00005  * Authors: Markus Holzem and Julian Smart
00006  *
00007  * Copyright: (C) 2004-2009 PLT Scheme Inc.
00008  * Copyright: (C) 1995, AIAI, University of Edinburgh (Julian)
00009  * Copyright: (C) 1995, GNU (Markus)
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00024  * 02110-1301 USA.
00025  */
00026 
00027 #ifdef __GNUG__
00028 #pragma implementation "Colour.h"
00029 #endif
00030 
00031 #define  Uses_XLib
00032 #define  Uses_wxColour
00033 #define  Uses_wxHashTable
00034 #include "wx.h"
00035 
00036 #include <ctype.h>
00037 
00038 // shift between wxWindows RGB- and XColor RGB-values
00039 // (necessary because the values specify an intensity)
00040 #define SHIFT (8*(sizeof(short int)-sizeof(char)))
00041 
00042 extern "C" { 
00043 #include "XWidgets/wxAllocColor.h"
00044 };
00045 
00046 extern Colormap wx_default_colormap;
00047 
00048 //-----------------------------------------------------------------------------
00049 // private data of wxColour and wxColourMap
00050 //-----------------------------------------------------------------------------
00051 
00052 class wxColour_Xintern : public gc {
00053 public:
00054     XColor   xcolor;
00055     Bool     have_pixel;
00056     Colormap xcolormap;
00057 };
00058 
00059 class wxColourMap_Xintern : public gc {
00060 public:
00061     Colormap xcolormap;
00062     Bool     priv;
00063 };
00064 
00065 //-----------------------------------------------------------------------------
00066 // wxColour
00067 //-----------------------------------------------------------------------------
00068 
00069 /* Since destructor doesn't do anything: */
00070 #define COLOR_CLEANUP WXGC_NO_CLEANUP
00071 
00072 wxColour::wxColour(void)
00073 : wxObject(COLOR_CLEANUP)
00074 {
00075     __type = wxTYPE_COLOUR;
00076 
00077     X = NULL; // not Ok
00078     locked = 0;
00079 }
00080 
00081 wxColour::wxColour(wxColour *col)
00082 : wxObject(COLOR_CLEANUP)
00083 {
00084   __type = wxTYPE_COLOUR;
00085   
00086   locked = 0;
00087   
00088   CopyFrom(col);
00089 }
00090 
00091 wxColour::wxColour(const char *col)
00092 : wxObject(COLOR_CLEANUP)
00093 {
00094     __type = wxTYPE_COLOUR;
00095 
00096     locked = 0;
00097 
00098     CopyFrom(col);
00099 }
00100 
00101 wxColour::wxColour(unsigned char r, unsigned char g, unsigned char b)
00102 : wxObject(COLOR_CLEANUP)
00103 {
00104     __type = wxTYPE_COLOUR;
00105 
00106     locked = 0;
00107     X = NULL; Set(r, g, b); // set RGB-values
00108 }
00109 
00110 wxColour::~wxColour(void)
00111 {
00112   /* If you do anything important here, be sure to change
00113      COLOR_CLEANUP */
00114 
00115   /* This doesn't count as important, because the MrEd
00116      color manage never frees colors: */
00117   FreePixel(TRUE);
00118 }
00119 
00120 //--- assignment -------------------------------------------------------------
00121 
00122 wxColour* wxColour::CopyFrom(wxColour *col)
00123 {
00124   if (col->Ok()) {
00125     FreePixel(FALSE);
00126     if (!X) {
00127       X  = new wxColour_Xintern; // create new X representation;
00128     }
00129     *X = *(col->X);         // assign data
00130     X->have_pixel = FALSE;
00131   } else
00132     FreePixel(TRUE);
00133 
00134   return this;
00135 }
00136 
00137 wxColour* wxColour::CopyFrom(const char *col)
00138 {
00139   wxColour *the_colour;
00140 
00141   the_colour = wxTheColourDatabase->FindColour(col); // find colour by name
00142   
00143   if (the_colour) {
00144     FreePixel(FALSE);
00145     if (!X) {
00146        X = new wxColour_Xintern; // create new X representation
00147      }
00148     *X = *(the_colour->X);     // assign data
00149     X->have_pixel = FALSE;
00150   } else
00151     FreePixel(TRUE); // free pixel before assignment
00152 
00153   return this;
00154 }
00155 
00156 //--- get and set RGB values --------------------------------------------------
00157 
00158 void wxColour::Set(unsigned char r, unsigned char g, unsigned char b)
00159 {
00160     FreePixel(FALSE);
00161 
00162     if (!X) {
00163        X = new wxColour_Xintern; // create new X representation
00164      }
00165 
00166     X->xcolor.red   = ((unsigned short)r) << SHIFT; // init XColor structure
00167     X->xcolor.green = ((unsigned short)g) << SHIFT;
00168     X->xcolor.blue  = ((unsigned short)b) << SHIFT;
00169     X->xcolor.flags = DoRed | DoGreen | DoBlue;
00170     X->have_pixel   = FALSE; // no pixel value assigned
00171 }
00172 
00173 void wxColour::Get(unsigned char *r, unsigned char *g, unsigned char *b)
00174 {
00175   if (X) {
00176     *r = (unsigned char)(X->xcolor.red   >> SHIFT);
00177     *g = (unsigned char)(X->xcolor.green >> SHIFT);
00178     *b = (unsigned char)(X->xcolor.blue  >> SHIFT);
00179   } else {
00180     *r = *g = *b = 0;
00181   }
00182 }
00183 
00184 unsigned char wxColour::Red(void)
00185 {
00186   return ( X ? (unsigned char)(X->xcolor.red >> SHIFT) : 0 );
00187 }
00188 
00189 unsigned char wxColour::Green(void)
00190 {
00191   return ( X ? (unsigned char)(X->xcolor.green >> SHIFT) : 0 );
00192 }
00193 
00194 unsigned char wxColour::Blue(void)
00195 {
00196   return ( X ? (unsigned char)(X->xcolor.blue >> SHIFT) : 0 );
00197 }
00198 
00199 //--- allocate and free X pixel values ----------------------------------------
00200 
00201 static int alloc_close_color(Display *display, Colormap cmap, XColor *xc)
00202 {
00203   XColor ctab[256];
00204   int ncells, j;
00205   int d, mdist, close;
00206   
00207 
00208   ncells = DisplayCells(display, DefaultScreen(display));
00209 
00210   ncells = (ncells < 256) ? ncells : 256;
00211   
00212   for (j = 0; j < ncells; j++) {
00213     ctab[j].pixel = j;
00214   }
00215 
00216   XQueryColors(display, cmap, ctab, ncells);
00217 
00218   mdist = 0;   close = -1;
00219   
00220   for (j = 0; j < ncells; j++) {
00221     d = (abs((int)(xc->red - ctab[j].red)) +
00222         abs((int)(xc->green - ctab[j].green)) +
00223         abs((int)(xc->blue - ctab[j].blue)));
00224     if (!mdist || (d < mdist)) { 
00225       mdist = d; 
00226       close = j;
00227     }
00228   }
00229 
00230   if (wxAllocColor(display, cmap, &ctab[close])) { 
00231     static int approxmsg = 1;
00232     if (approxmsg) {
00233       wxError("Cannot allocate color, using approximate match.\n"
00234              "(Future allocations may be approximate without report.)",
00235              "MrEd Warning");
00236       
00237       approxmsg = 0;
00238     }
00239 
00240     xc->pixel = ctab[close].pixel;
00241     return 1;
00242   } else
00243     return 0;
00244 }
00245 
00246 unsigned long wxColour::GetPixel(wxColourMap *cmap, Bool is_color, Bool fg)
00247 {
00248   if (!is_color) {
00249     int white;
00250     if (!X) {
00251       white = 1;
00252     } else if (fg) {
00253       /* foreground: white = white, all else = black */
00254       white = (((X->xcolor.red >> SHIFT) == 255)
00255               && ((X->xcolor.green >> SHIFT) == 255)
00256               && ((X->xcolor.blue >> SHIFT) == 255));
00257     } else {
00258       /* background: black = black, all else = white */
00259       white = (X->xcolor.red || X->xcolor.green || X->xcolor.blue);
00260     }
00261 
00262     if (white)
00263       return 0; /* WhitePixelOfScreen(wxAPP_SCREEN); */
00264     else
00265       return 1; /* BlackPixelOfScreen(wxAPP_SCREEN); */
00266   }
00267 
00268     if (X) {
00269        if (!X->have_pixel) {
00270          XColor xcol;
00271          Colormap cm;
00272 
00273            // no pixel value or wrong colourmap
00274            FreePixel(FALSE); // free pixel value if any
00275            cm = GETCOLORMAP(cmap); // colourmap to use
00276            X->xcolormap = cm;
00277 
00278            // allocate pixel
00279            /* Copy color b/c XAllocColour sets RGB values */
00280            xcol.red = X->xcolor.red;
00281            xcol.green = X->xcolor.green;
00282            xcol.blue = X->xcolor.blue;
00283            xcol.flags = DoRed | DoBlue | DoGreen;
00284 
00285            if (!wxAllocColor(wxAPP_DISPLAY, X->xcolormap, &xcol)
00286               && !alloc_close_color(wxAPP_DISPLAY, X->xcolormap, &xcol)) {
00287              // failed => used default
00288              static int message_printed = FALSE;
00289              if (!message_printed) {
00290               wxError("Colour allocation failed, using black.\n(Future allocations may fail without reports.)", 
00291                      "wxColour");
00292               message_printed = TRUE;
00293              } 
00294              return BlackPixelOfScreen(wxAPP_SCREEN);
00295            } else {
00296              X->xcolor.pixel = xcol.pixel;
00297              X->have_pixel = TRUE; // allocation successful
00298            }
00299        }
00300     } else {
00301        // use something as a default value
00302        wxDebugMsg("wxColour: no colour specified, using white\n");
00303        return(WhitePixelOfScreen(wxAPP_SCREEN));
00304     }
00305     return (X->xcolor.pixel);
00306 }
00307 
00308 void wxColour::FreePixel(Bool del)
00309 {
00310     if (X) {
00311        if (X->have_pixel) {
00312            // free allocated colour
00313            // -- currently don't free colours, because the ownership of
00314            // -- the pixel-value is not specified!
00315            // XFreeColors(wxAPP_DISPLAY, X->xcolormap, &(X->xcolor.pixel), 1, 0);
00316            X->have_pixel = FALSE;
00317        }
00318        if (del) {
00319            DELETE_OBJ X; // destroy X representation;
00320            X = NULL; // not Ok
00321        }
00322     }
00323 }
00324 
00325 //-----------------------------------------------------------------------------
00326 // wxColourDatabase
00327 //-----------------------------------------------------------------------------
00328 
00329 wxColourDatabase::wxColourDatabase()
00330 : wxList(wxKEY_STRING)
00331 {
00332   
00333 }
00334 
00335 wxColourDatabase::~wxColourDatabase (void)
00336 {
00337   wxNode *node;
00338   node = First();
00339   while (node) {
00340     wxColour *col;
00341     wxNode *next;
00342     col  = (wxColour*)node->Data();
00343     next = node->Next();
00344     DELETE_OBJ col;
00345     node = next;
00346   }
00347 }
00348 
00349 wxColour *wxColourDatabase::FindColour(const char *colour)
00350 {
00351   wxNode *node;
00352   wxColour *col;
00353 #if 0
00354   XColor xcolor;
00355   Colormap cm;
00356 #endif
00357 
00358   // Force capital so lc matches as in X
00359   char uc_colour[256];
00360   int i;
00361 
00362   for (i = 0; colour[i] && i < 255; i++) {
00363     uc_colour[i] = colour[i];
00364     if ((uc_colour[i] >= 'a') && (uc_colour[i] <= 'z'))
00365       uc_colour[i] -= ('a' - 'A');
00366   }
00367   uc_colour[i] = 0;
00368   colour = uc_colour;
00369 
00370   if ((node = Find(colour)))
00371     return (wxColour*)node->Data(); // colour already defined
00372 
00373   /* Define the standard set: */
00374   static wxHashTable *aux = NULL;
00375   if (!aux) {
00376     wxColour *tmpc;
00377     wxREGGLOB(aux);
00378     aux = new wxHashTable(wxKEY_STRING, 20);
00379 #define APPEND_C(name, c) tmpc = c; tmpc->Lock(1); aux->Put(name, tmpc);
00380 #include "../../../wxcommon/DBColors.inc"
00381   }
00382 
00383 #if 0
00384   // use wxAPP_DISPLAY and wxAPP_COLOURMAP as default
00385   cm = GETCOLORMAP(wxAPP_COLOURMAP);
00386   if (XParseColor(wxAPP_DISPLAY, cm, colour, &xcolor)) {
00387     // new colour found: add to list as found, but only if it's in the standard set
00388     col = (wxColour *)aux->Get(colour);
00389     if (col) {
00390       col = DEBUG_NEW wxColour((unsigned char)(xcolor.red >> SHIFT),
00391                             (unsigned char)(xcolor.green >> SHIFT),
00392                             (unsigned char)(xcolor.blue >> SHIFT));
00393       col->Lock(1);
00394     }
00395   } else 
00396 #endif
00397     {
00398       col = (wxColour *)aux->Get(colour);
00399     }
00400 
00401   if (col)
00402     Append(colour, col);
00403 
00404   return col;
00405 }
00406 
00407 char *wxColourDatabase::FindName(wxColour *colour)
00408 {
00409   if (colour->Ok()) {
00410     wxNode *node;
00411     unsigned char red, green, blue;
00412 
00413     red   = colour->Red();
00414     green = colour->Green();
00415     blue  = colour->Blue();
00416     
00417     for (node = First(); node; node = node->Next()) {
00418       wxColour *col;
00419       col = (wxColour*)node->Data ();
00420       if (col->Red()==red && col->Green()==green && col->Blue()==blue) {
00421        char *found = node->string_key;
00422        if (found)
00423          return found;
00424       }
00425     }
00426   }
00427   return NULL;
00428 }
00429 
00430 //-----------------------------------------------------------------------------
00431 // wxColourMap
00432 //-----------------------------------------------------------------------------
00433 
00434 wxColourMap::wxColourMap(Bool priv)
00435 {
00436     __type = wxTYPE_COLOURMAP;
00437 
00438     X  = new wxColourMap_Xintern; // create new X representation
00439     X->xcolormap = wx_default_colormap;
00440     X->priv      = priv;
00441     // if (X->priv) {
00442     //     X = NULL; // create colourmap;
00443     // } else
00444     //      X->xcolormap = DefaultColormapOfScreen(wxAPP_SCREEN);
00445 }
00446 
00447 wxColourMap::~wxColourMap(void)
00448 {
00449     if (X) {
00450        if (X->priv) {
00451            // free colourmap
00452        }
00453        DELETE_OBJ X;
00454     }
00455 }
00456 
00457 void *wxColourMap::GetHandle(void)
00458 {
00459     if (X)
00460        return (&(X->xcolormap));
00461     return &(wxAPP_COLOURMAP->X->xcolormap); // just to return somthing
00462 }
00463