]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/ColorHandler.C
remove defaults stuff, let Qt handle no toolbar
[lyx.git] / src / frontends / xforms / ColorHandler.C
1 /**
2  * \file ColorHandler.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author unknown
7  *
8  * Full author contact details are available in file CREDITS
9  */
10
11 #include <config.h>
12
13
14 #include "ColorHandler.h"
15 #include "LColor.h"
16 #include "gettext.h"
17 #include "debug.h"
18
19 #include <boost/scoped_array.hpp>
20 #include "support/BoostFormat.h"
21
22 #include <cmath>
23
24 #ifndef CXX_GLOBAL_CSTD
25 using std::pow;
26 #endif
27
28 using std::endl;
29
30 #include FORMS_H_LOCATION
31
32 LyXColorHandler::LyXColorHandler()
33 {
34         display = fl_get_display();
35         drawable = XCreatePixmap(display,
36                                  RootWindow(display, fl_screen),
37                                  10, 10, fl_get_visual_depth());
38
39         colormap = fl_state[fl_get_vclass()].colormap;
40         // Clear the GC cache
41         for (int i = 0; i <= LColor::ignore; ++i) {
42                 colorGCcache[i] = 0;
43         }
44 }
45
46
47 LyXColorHandler::~LyXColorHandler()
48 {
49         // Release all the registered GCs
50         for (int i = 0; i <= LColor::ignore; ++i) {
51                 if (colorGCcache[i] != 0) {
52                         XFreeGC(display, colorGCcache[i]);
53                 }
54         }
55         // Iterate over the line cache and Free the GCs
56         for (LineGCCache::iterator lit = lineGCcache.begin();
57              lit != lineGCcache.end(); ++lit) {
58                 XFreeGC(display, lit->second);
59         }
60 }
61
62
63 unsigned long LyXColorHandler::colorPixel(LColor::color c)
64 {
65         XGCValues val;
66         XGetGCValues(display, getGCForeground(c), GCForeground, &val);
67         return val.foreground;
68 }
69
70
71 // Gets GC according to color
72 // Uses caching
73 GC LyXColorHandler::getGCForeground(LColor::color c)
74 {
75         if (colorGCcache[c] != 0)
76                 return colorGCcache[c];
77
78         XColor xcol;
79         XColor ccol;
80         string const s = lcolor.getX11Name(c);
81         XGCValues val;
82
83         // Look up the RGB values for the color, and an approximate
84         // color that we can hope to get on this display.
85         if (XLookupColor(display, colormap, s.c_str(), &xcol, &ccol) == 0) {
86 #if USE_BOOST_FORMAT
87                 lyxerr << boost::format(
88                         _("LyX: Unknown X11 color %1$s for %2$s\n"
89                           "     Using black instead, sorry!"))
90                         % s
91                         % lcolor.getGUIName(c)
92                        << endl;
93 #else
94                 lyxerr << _("LyX: Unknown X11 color ") << s << _(" for ")
95                        << lcolor.getGUIName(c)
96                        << _("\n     Using black instead, sorry!") << endl;
97 #endif
98                 unsigned long bla = BlackPixel(display,
99                                                DefaultScreen(display));
100                 val.foreground = bla;
101         // Try the exact RGB values first, then the approximate.
102         } else if (XAllocColor(display, colormap, &xcol) != 0) {
103                 if (lyxerr.debugging(Debug::GUI)) {
104 #if USE_BOOST_FORMAT
105                         lyxerr << boost::format(
106                                 _("LyX: X11 color %1$s allocated for %2$s"))
107                                 % s
108                                 % lcolor.getGUIName(c)
109                                << endl;
110 #else
111                         lyxerr << _("LyX: X11 color ") << s
112                                << _(" allocated for ") << lcolor.getGUIName(c)
113                                << endl;
114 #endif
115                 }
116                 val.foreground = xcol.pixel;
117         } else if (XAllocColor(display, colormap, &ccol)) {
118 #if USE_BOOST_FORMAT
119                 lyxerr << boost::format(
120                         _("LyX: Using approximated X11 color %1$s"
121                           " allocated for %2$s"))
122                         % s
123                         % lcolor.getGUIName(c)
124                        << endl;
125 #else
126                 lyxerr << _("LyX: Using approximated X11 color ") << s
127                        << _(" allocated for ") << lcolor.getGUIName(c)
128                        << endl;
129 #endif
130                 val.foreground = xcol.pixel;
131         } else {
132                 // Here we are traversing the current colormap to find
133                 // the color closest to the one we want.
134                 Visual * vi = DefaultVisual(display, DefaultScreen(display));
135
136                 boost::scoped_array<XColor> cmap(new XColor[vi->map_entries]);
137
138                 for (int i = 0; i < vi->map_entries; ++i) {
139                         cmap[i].pixel = i;
140                 }
141                 XQueryColors(display, colormap, cmap.get(), vi->map_entries);
142
143                 // Walk through the cmap and look for close colors.
144                 int closest_pixel = 0;
145                 double closest_distance = 1e20; // we want to minimize this
146                 double distance = 0;
147                 for (int t = 0; t < vi->map_entries; ++t) {
148                         // The Euclidean distance between two points in
149                         // a three-dimensional space, the RGB color-cube,
150                         // is used as the distance measurement between two
151                         // colors.
152
153                         // Since square-root is monotonous, we don't have to
154                         // take the square-root to find the minimum, and thus
155                         // we use the squared distance instead to be faster.
156
157                         // If we want to get fancy, we could convert the RGB
158                         // coordinates to a different color-cube, maybe HSV,
159                         // but the RGB cube seems to work great.  (Asger)
160                         distance = pow(cmap[t].red   - xcol.red,   2.0) +
161                                    pow(cmap[t].green - xcol.green, 2.0) +
162                                    pow(cmap[t].blue  - xcol.blue,  2.0);
163                         if (distance < closest_distance) {
164                                 closest_distance = distance;
165                                 closest_pixel = t;
166                         }
167                 }
168
169 #if USE_BOOST_FORMAT
170                 lyxerr << boost::format(
171                         _("LyX: Couldn't allocate '%1$s' for %2$s"
172                           " with (r,g,b)=(%3$d,%4$d,%5$d).\n"
173                           "     Using closest allocated color"
174                           " with (r,g,b)=(%6$d,%7$d,%8$d) instead.\n"
175                           "Pixel [%9$d] is used."))
176                         % s
177                         % lcolor.getGUIName(c)
178                         % xcol.red % xcol.green % xcol.blue
179                         % cmap[closest_pixel].red
180                         % cmap[closest_pixel].green
181                         % cmap[closest_pixel].blue
182                         % closest_pixel
183                        << endl;
184 #else
185                 lyxerr << _("LyX: Couldn't allocate '") << s
186                        << _("' for ") << lcolor.getGUIName(c)
187                        << _(" with (r,g,b)=(")
188                        << xcol.red << ',' << xcol.green << ',' << xcol.blue
189                        << _(").\n")
190                        << _("     Using closest allocated color with (r,g,b)=(")
191                        << cmap[closest_pixel].red << ','
192                        << cmap[closest_pixel].green << ','
193                        << cmap[closest_pixel].blue
194                        << _(") instead.\nPixel [")
195                        << closest_pixel << _("] is used.")
196                        << endl;
197 #endif
198                 val.foreground = cmap[closest_pixel].pixel;
199         }
200
201         val.function = GXcopy;
202         return colorGCcache[c] = XCreateGC(display, drawable,
203                                            GCForeground | GCFunction, &val);
204 }
205
206
207 // Gets GC for line
208 GC LyXColorHandler::getGCLinepars(Painter::line_style ls,
209                                   Painter::line_width lw, LColor::color c)
210 {
211         //if (lyxerr.debugging()) {
212         //      lyxerr << "Painter drawable: " << drawable() << endl;
213         //}
214
215         int index = lw + (ls << 1) + (c << 6);
216
217         LineGCCache::iterator it = lineGCcache.find(index);
218         if (it != lineGCcache.end())
219                 return it->second;
220
221         XGCValues val;
222         XGetGCValues(display, getGCForeground(c), GCForeground, &val);
223
224         switch (lw) {
225         case Painter::line_thin:
226                 val.line_width = 0;
227                 break;
228         case Painter::line_thick:
229                 val.line_width = 2;
230                 break;
231         }
232
233         switch (ls) {
234         case Painter::line_solid:
235                 val.line_style = LineSolid;
236                 break;
237         case Painter::line_onoffdash:
238                 val.line_style = LineOnOffDash;
239                 break;
240         }
241
242
243         val.cap_style = CapRound;
244         val.join_style = JoinRound;
245         val.function = GXcopy;
246
247         return lineGCcache[index] =
248                 XCreateGC(display, drawable,
249                           GCForeground | GCLineStyle | GCLineWidth |
250                           GCCapStyle | GCJoinStyle | GCFunction, &val);
251 }
252
253
254 // update GC cache after color redefinition
255 void LyXColorHandler::updateColor (LColor::color c)
256 {
257         // color GC cache
258         GC gc = colorGCcache[c];
259         if (gc != 0) {
260                 XFreeGC(display, gc);
261                 colorGCcache[c] = NULL;
262                 getGCForeground(c);
263         }
264
265         // line GC cache
266
267         for (int ls = 0; ls < 3; ++ls)
268                 for (int lw = 0; lw < 2; ++lw) {
269                         int const index = lw + (ls << 1) + (c << 6);
270                         LineGCCache::iterator it = lineGCcache.find(index);
271                         if (it != lineGCcache.end()) {
272                                 gc = it->second;
273                                 XFreeGC(display, gc);
274                                 lineGCcache.erase(it);
275                                 getGCLinepars(Painter::line_style(ls),
276                                               Painter::line_width(lw), c);
277                         }
278                 }
279 }
280
281
282 //
283 boost::scoped_ptr<LyXColorHandler> lyxColorHandler;