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