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