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