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