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