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