replaced all occurences of wxColourDatabase::FindColour() with Find(); minor code...
[wxWidgets.git] / src / motif / colour.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: colour.cpp
3 // Purpose: wxColour class
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 17/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 //// TODO: make wxColour a ref-counted object,
13 //// so pixel values get shared.
14
15 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
16 #pragma implementation "colour.h"
17 #endif
18
19 #include "wx/gdicmn.h"
20 #include "wx/colour.h"
21 #include "wx/app.h"
22
23 #ifdef __VMS__
24 #pragma message disable nosimpint
25 #endif
26 #include <Xm/Xm.h>
27 #ifdef __VMS__
28 #pragma message enable nosimpint
29 #endif
30
31 #include "wx/motif/private.h"
32
33 IMPLEMENT_DYNAMIC_CLASS(wxColour, wxObject)
34
35 // Colour
36
37 wxColour::wxColour ()
38 {
39 m_isInit = FALSE;
40 m_red =
41 m_blue =
42 m_green = 0;
43 m_pixel = -1;
44 }
45
46 wxColour::wxColour (const wxColour& col)
47 {
48 *this = col;
49 }
50
51 wxColour& wxColour::operator =(const wxColour& col)
52 {
53 m_red = col.m_red;
54 m_green = col.m_green;
55 m_blue = col.m_blue;
56 m_isInit = col.m_isInit;
57 m_pixel = col.m_pixel;
58 return *this;
59 }
60
61 void wxColour::InitFromName(const wxString& name)
62 {
63 *this = wxTheColourDatabase->Find(name);
64 }
65
66 wxColour::~wxColour ()
67 {
68 }
69
70 void wxColour::Set (unsigned char r, unsigned char g, unsigned char b)
71 {
72 m_red = r;
73 m_green = g;
74 m_blue = b;
75 m_isInit = TRUE;
76 m_pixel = -1;
77 }
78
79 // Allocate a colour, or nearest colour, using the given display.
80 // If realloc is TRUE, ignore the existing pixel, otherwise just return
81 // the existing one.
82 // Returns the old or allocated pixel.
83
84 // TODO: can this handle mono displays? If not, we should have an extra
85 // flag to specify whether this should be black or white by default.
86
87 int wxColour::AllocColour(WXDisplay* display, bool realloc)
88 {
89 if ((m_pixel != -1) && !realloc)
90 return m_pixel;
91
92 XColor color;
93 color.red = (unsigned short) Red ();
94 color.red |= color.red << 8;
95 color.green = (unsigned short) Green ();
96 color.green |= color.green << 8;
97 color.blue = (unsigned short) Blue ();
98 color.blue |= color.blue << 8;
99
100 color.flags = DoRed | DoGreen | DoBlue;
101
102 WXColormap cmap = wxTheApp->GetMainColormap(display);
103
104 if (!XAllocColor ((Display*) display, (Colormap) cmap, &color))
105 {
106 m_pixel = wxGetBestMatchingPixel((Display*) display, &color,(Colormap) cmap);
107 return m_pixel;
108 }
109 else
110 {
111 m_pixel = (int) color.pixel;
112 return m_pixel;
113 }
114 }
115
116 /*-------------------------------------------
117 Markus Emmenegger <mege@iqe.ethz.ch>
118 Find the pixel value with an assigned color closest to the desired color
119 Used if color cell allocation fails
120 As the returned pixel value may be in use by another application,
121 the color might change anytime.
122 But in many cases, that is still better than always using black.
123 --
124 Chris Breeze <chris@hel.co.uk>
125 Improvements:
126 1) More efficient calculation of RGB distance of colour cell from
127 the desired colour. There is no need to take the sqrt of 'dist', and
128 since we are only interested in the top 8-bits of R, G and B we
129 can perform integer arithmetic.
130 2) Attempt to allocate a read-only colour when a close match is found.
131 A read-only colour will not change.
132 3) Fall back to the closest match if no read-only colours are available.
133
134 Possible further improvements:
135 1) Scan the lookup table and sort the colour cells in order of
136 increasing
137 distance from the desired colour. Then attempt to allocate a
138 read-only
139 colour starting from the nearest match.
140 2) Linear RGB distance is not a particularly good method of colour
141 matching
142 (though it is quick). Converting the colour to HLS and then comparing
143 may give better matching.
144 -------------------------------------------*/
145
146 int wxGetBestMatchingPixel(Display *display, XColor *desiredColor, Colormap cmap)
147 {
148 if (cmap == (Colormap) NULL)
149 cmap = (Colormap) wxTheApp->GetMainColormap(display);
150
151 int numPixVals = XDisplayCells(display, DefaultScreen (display));
152 int mindist = 256 * 256 * 3;
153 int bestpixel = (int) BlackPixel (display, DefaultScreen (display));
154 int red = desiredColor->red >> 8;
155 int green = desiredColor->green >> 8;
156 int blue = desiredColor->blue >> 8;
157 const int threshold = 2 * 2 * 3; // allow an error of up to 2 in R,G & B
158
159 for (int pixelcount = 0; pixelcount < numPixVals; pixelcount++)
160 {
161 XColor matching_color;
162 matching_color.pixel = pixelcount;
163 XQueryColor(display,cmap,&matching_color);
164
165 int delta_red = red - (matching_color.red >> 8);
166 int delta_green = green - (matching_color.green >> 8);
167 int delta_blue = blue - (matching_color.blue >> 8);
168
169 int dist = delta_red * delta_red +
170 delta_green * delta_green +
171 delta_blue * delta_blue;
172
173 if (dist <= threshold)
174 {
175 // try to allocate a read-only colour...
176 if (XAllocColor (display, cmap, &matching_color))
177 {
178 return matching_color.pixel;
179 }
180 }
181 if (dist < mindist)
182 {
183 bestpixel = pixelcount;
184 mindist = dist;
185 }
186 }
187 return bestpixel;
188 }