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