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