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