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