Applied patch [ 828303 ] Slight wxColour cleanup
[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 void wxColour::Init()
38 {
39 m_isInit = false;
40 m_red =
41 m_blue =
42 m_green = 0;
43 m_pixel = -1;
44 }
45
46 wxColour::wxColour()
47 {
48 Init();
49 }
50
51 wxColour::wxColour(const wxColour& col)
52 {
53 *this = col;
54 }
55
56 wxColour& wxColour::operator =(const wxColour& col)
57 {
58 m_red = col.m_red;
59 m_green = col.m_green;
60 m_blue = col.m_blue;
61 m_isInit = col.m_isInit;
62 m_pixel = col.m_pixel;
63 return *this;
64 }
65
66 void wxColour::InitFromName(const wxString& name)
67 {
68 if ( wxTheColourDatabase )
69 {
70 wxColour col = wxTheColourDatabase->Find(name);
71 if ( col.Ok() )
72 {
73 *this = col;
74 return;
75 }
76 }
77
78 // leave invalid
79 Init();
80 }
81
82 /* static */
83 wxColour wxColour::CreateByName(const wxString& name)
84 {
85 wxColour col;
86
87 Display *dpy = wxGlobalDisplay();
88 WXColormap colormap = wxTheApp->GetMainColormap( dpy );
89 XColor xcol;
90 if ( XParseColor( dpy, (Colormap)colormap, name.mb_str(), &xcol ) )
91 {
92 col.m_red = xcol.red & 0xff;
93 col.m_green = xcol.green & 0xff;
94 col.m_blue = xcol.blue & 0xff;
95 col.m_isInit = TRUE;
96 col.m_pixel = -1;
97 }
98
99 return col;
100 }
101
102 wxColour::~wxColour()
103 {
104 }
105
106 void wxColour::Set(unsigned char r, unsigned char g, unsigned char b)
107 {
108 m_red = r;
109 m_green = g;
110 m_blue = b;
111 m_isInit = true;
112 m_pixel = -1;
113 }
114
115 // Allocate a colour, or nearest colour, using the given display.
116 // If realloc is true, ignore the existing pixel, otherwise just return
117 // the existing one.
118 // Returns the old or allocated pixel.
119
120 // TODO: can this handle mono displays? If not, we should have an extra
121 // flag to specify whether this should be black or white by default.
122
123 int wxColour::AllocColour(WXDisplay* display, bool realloc)
124 {
125 if ((m_pixel != -1) && !realloc)
126 return m_pixel;
127
128 XColor color;
129 color.red = (unsigned short) Red ();
130 color.red |= color.red << 8;
131 color.green = (unsigned short) Green ();
132 color.green |= color.green << 8;
133 color.blue = (unsigned short) Blue ();
134 color.blue |= color.blue << 8;
135
136 color.flags = DoRed | DoGreen | DoBlue;
137
138 WXColormap cmap = wxTheApp->GetMainColormap(display);
139
140 if (!XAllocColor ((Display*) display, (Colormap) cmap, &color))
141 {
142 m_pixel = wxGetBestMatchingPixel((Display*) display, &color,(Colormap) cmap);
143 return m_pixel;
144 }
145 else
146 {
147 m_pixel = (int) color.pixel;
148 return m_pixel;
149 }
150 }
151
152 /*-------------------------------------------
153 Markus Emmenegger <mege@iqe.ethz.ch>
154 Find the pixel value with an assigned color closest to the desired color
155 Used if color cell allocation fails
156 As the returned pixel value may be in use by another application,
157 the color might change anytime.
158 But in many cases, that is still better than always using black.
159 --
160 Chris Breeze <chris@hel.co.uk>
161 Improvements:
162 1) More efficient calculation of RGB distance of colour cell from
163 the desired colour. There is no need to take the sqrt of 'dist', and
164 since we are only interested in the top 8-bits of R, G and B we
165 can perform integer arithmetic.
166 2) Attempt to allocate a read-only colour when a close match is found.
167 A read-only colour will not change.
168 3) Fall back to the closest match if no read-only colours are available.
169
170 Possible further improvements:
171 1) Scan the lookup table and sort the colour cells in order of
172 increasing
173 distance from the desired colour. Then attempt to allocate a
174 read-only
175 colour starting from the nearest match.
176 2) Linear RGB distance is not a particularly good method of colour
177 matching
178 (though it is quick). Converting the colour to HLS and then comparing
179 may give better matching.
180 -------------------------------------------*/
181
182 int wxGetBestMatchingPixel(Display *display, XColor *desiredColor, Colormap cmap)
183 {
184 if (cmap == (Colormap) NULL)
185 cmap = (Colormap) wxTheApp->GetMainColormap(display);
186
187 int numPixVals = XDisplayCells(display, DefaultScreen (display));
188 int mindist = 256 * 256 * 3;
189 int bestpixel = (int) BlackPixel (display, DefaultScreen (display));
190 int red = desiredColor->red >> 8;
191 int green = desiredColor->green >> 8;
192 int blue = desiredColor->blue >> 8;
193 const int threshold = 2 * 2 * 3; // allow an error of up to 2 in R,G & B
194
195 for (int pixelcount = 0; pixelcount < numPixVals; pixelcount++)
196 {
197 XColor matching_color;
198 matching_color.pixel = pixelcount;
199 XQueryColor(display,cmap,&matching_color);
200
201 int delta_red = red - (matching_color.red >> 8);
202 int delta_green = green - (matching_color.green >> 8);
203 int delta_blue = blue - (matching_color.blue >> 8);
204
205 int dist = delta_red * delta_red +
206 delta_green * delta_green +
207 delta_blue * delta_blue;
208
209 if (dist <= threshold)
210 {
211 // try to allocate a read-only colour...
212 if (XAllocColor (display, cmap, &matching_color))
213 {
214 return matching_color.pixel;
215 }
216 }
217 if (dist < mindist)
218 {
219 bestpixel = pixelcount;
220 mindist = dist;
221 }
222 }
223 return bestpixel;
224 }