]> git.lyx.org Git - lyx.git/blob - src/Color.cpp
Changed references as to where/how known issues are shown, i.e. added reference to...
[lyx.git] / src / Color.cpp
1 /**
2  * \file Color.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Asger Alstrup
7  * \author Lars Gullik Bjønnes
8  * \author Matthias Ettrich
9  * \author Jean-Marc Lasgouttes
10  * \author John Levon
11  * \author André Pönitz
12  * \author Martin Vermeer
13  *
14  * Full author contact details are available in file CREDITS.
15  */
16
17 #include <config.h>
18
19 #include "debug.h"
20 #include "gettext.h"
21 #include "Color.h"
22 #include "support/lstrings.h"
23
24 #include <map>
25 #include <cmath>
26 #include <sstream>
27 #include <iomanip>
28
29
30 #ifndef CXX_GLOBAL_CSTD
31 using std::floor;
32 #endif
33
34 using std::max;
35 using std::min;
36 using std::setw;
37
38 using std::istringstream;
39 using std::ostringstream;
40 using std::string;
41 using std::endl;
42
43 using lyx::support::compare_ascii_no_case;
44 using lyx::support::ascii_lowercase;
45
46
47 namespace {
48
49 struct ColorEntry {
50         lyx::Color::color lcolor;
51         char const * guiname;
52         char const * latexname;
53         char const * x11name;
54         char const * lyxname;
55 };
56
57 int const nohue = -1;
58
59 int hexstrToInt(string const & str)
60 {
61         int val = 0;
62         istringstream is(str);
63         is >> std::setbase(16) >> val;
64         return val;
65 }
66
67 } // namespace anon
68
69
70
71 namespace lyx {
72
73
74 /////////////////////////////////////////////////////////////////////
75 //
76 // RGBColor
77 //
78 /////////////////////////////////////////////////////////////////////
79
80
81 string const X11hexname(RGBColor const & col)
82 {
83         ostringstream ostr;
84
85         ostr << '#' << std::setbase(16) << std::setfill('0')
86              << setw(2) << col.r
87              << setw(2) << col.g
88              << setw(2) << col.b;
89
90         return ostr.str();
91 }
92
93
94 RGBColor::RGBColor(string const & x11hexname)
95         : r(0), g(0), b(0)
96 {
97         BOOST_ASSERT(x11hexname.size() == 7 && x11hexname[0] == '#');
98         r = hexstrToInt(x11hexname.substr(1,2));
99         g = hexstrToInt(x11hexname.substr(3,2));
100         b = hexstrToInt(x11hexname.substr(5,2));
101 }
102
103
104 RGBColor::RGBColor(HSVColor const & hsv)
105 {
106         double h = hsv.h;
107         double const s = hsv.s;
108         double const v = hsv.v;
109
110         double rd, gd, bd;
111
112         if (h == nohue || s == 0.0) {
113                 rd = gd = bd = v;
114         } else {
115                 if (h == 360.0) h = 0.0;
116                 h /= 60.0;
117
118                 int const j = max(0, static_cast<int>(::floor(h)));
119                 //if (j < 0) j = 0;
120
121                 double const f = h - j;
122                 double const p = v * (1.0 - s);
123                 double const q = v * (1.0 - (s * f));
124                 double const t = v * (1.0 - (s * (1.0 - f)));
125
126                 switch (j) {
127                 case 0:
128                         rd = v;
129                         gd = t;
130                         bd = p;
131                         break;
132                 case 1:
133                         rd = q;
134                         gd = v;
135                         bd = p;
136                         break;
137                 case 2:
138                         rd = p;
139                         gd = v;
140                         bd = t;
141                         break;
142                 case 3:
143                         rd = p;
144                         gd = q;
145                         bd = v;
146                         break;
147                 case 4:
148                         rd = t;
149                         gd = p;
150                         bd = v;
151                         break;
152                 case 5:
153                         rd = v;
154                         gd = p;
155                         bd = q;
156                         break;
157                 default:
158                         rd = v;
159                         gd = t;
160                         bd = p;
161                         break;  // should never happen.
162                 }
163         }
164
165         r = static_cast<int>(::floor((rd * 255.0) + 0.5));
166         g = static_cast<int>(::floor((gd * 255.0) + 0.5));
167         b = static_cast<int>(::floor((bd * 255.0) + 0.5));
168 }
169
170
171 /////////////////////////////////////////////////////////////////////
172 //
173 // HSVColor
174 //
175 /////////////////////////////////////////////////////////////////////
176
177 HSVColor::HSVColor(RGBColor const & rgb)
178 {
179         double const r = rgb.r / 255.0;
180         double const g = rgb.g / 255.0;
181         double const b = rgb.b / 255.0;
182
183         double const maxval = max(max(r, g), b);
184         double const minval = min(min(r, g), b);
185
186         v = maxval;
187
188         double const diff = maxval - minval;
189         if (maxval != 0.0)
190                 s = diff / maxval;
191         else
192                 s = 0.0;
193
194         h = nohue;
195         if (s != 0.0) {
196                 double const rc = (maxval - r) / diff;
197                 double const gc = (maxval - g) / diff;
198                 double const bc = (maxval - b) / diff;
199
200                 if (r == maxval)
201                         h = bc - gc;
202                 else if (g == maxval)
203                         h = 2.0 + rc - bc;
204                 else if (b == maxval)
205                         h = 4.0 + gc - rc;
206
207                 h *= 60.0;
208                 if (h < 0)
209                         h += 360;
210         }
211 }
212
213
214
215 /////////////////////////////////////////////////////////////////////
216 //
217 // Color::Pimpl
218 //
219 /////////////////////////////////////////////////////////////////////
220
221 class Color::Pimpl {
222 public:
223         ///
224         class information {
225         public:
226                 /// the name as it appears in the GUI
227                 string guiname;
228                 /// the name used in LaTeX
229                 string latexname;
230                 /// the name for X11
231                 string x11name;
232                 /// the name for LyX
233                 string lyxname;
234         };
235
236         /// initialise a color entry
237         void fill(ColorEntry const & entry)
238         {
239                 information in;
240                 in.lyxname   = entry.lyxname;
241                 in.latexname = entry.latexname;
242                 in.x11name   = entry.x11name;
243                 in.guiname   = entry.guiname;
244                 infotab[entry.lcolor] = in;
245                 lyxcolors[entry.lyxname] = entry.lcolor;
246                 latexcolors[entry.latexname] = entry.lcolor;
247         }
248
249         ///
250         typedef std::map<Color::color, information> InfoTab;
251         /// the table of color information
252         InfoTab infotab;
253
254         typedef std::map<string, Color::color> Transform;
255         /// the transform between LyX color name string and integer code.
256         Transform lyxcolors;
257         /// the transform between LaTeX color name string and integer code.
258         Transform latexcolors;
259
260 };
261
262
263 Color::Color()
264         : pimpl_(new Pimpl)
265 {
266         //  Color::color, gui, latex, x11, lyx
267         static ColorEntry const items[] = {
268         { none, N_("none"), "none", "black", "none" },
269         { black, N_("black"), "black", "black", "black" },
270         { white, N_("white"), "white", "white", "white" },
271         { red, N_("red"), "red", "red", "red" },
272         { green, N_("green"), "green", "green", "green" },
273         { blue, N_("blue"), "blue", "blue", "blue" },
274         { cyan, N_("cyan"), "cyan", "cyan", "cyan" },
275         { magenta, N_("magenta"), "magenta", "magenta", "magenta" },
276         { yellow, N_("yellow"), "yellow", "yellow", "yellow" },
277         { cursor, N_("cursor"), "cursor", "black", "cursor" },
278         { background, N_("background"), "background", "linen", "background" },
279         { foreground, N_("text"), "foreground", "black", "foreground" },
280         { selection, N_("selection"), "selection", "LightBlue", "selection" },
281         { latex, N_("LaTeX text"), "latex", "DarkRed", "latex" },
282         { preview, N_("previewed snippet"), "preview", "black", "preview" },
283         { note, N_("note"), "note", "blue", "note" },
284         { notebg, N_("note background"), "notebg", "yellow", "notebg" },
285         { comment, N_("comment"), "comment", "magenta", "comment" },
286         { commentbg, N_("comment background"), "commentbg", "linen", "commentbg" },
287         { greyedout, N_("greyedout inset"), "greyedout", "red", "greyedout" },
288         { greyedoutbg, N_("greyedout inset background"), "greyedoutbg", "linen", "greyedoutbg" },
289         { shadedbg, N_("shaded box"), "shaded", "#ff0000", "shaded" },
290         { depthbar, N_("depth bar"), "depthbar", "IndianRed", "depthbar" },
291         { language, N_("language"), "language", "Blue", "language" },
292         { command, N_("command inset"), "command", "black", "command" },
293         { commandbg, N_("command inset background"), "commandbg", "azure", "commandbg" },
294         { commandframe, N_("command inset frame"), "commandframe", "black", "commandframe" },
295         { special, N_("special character"), "special", "RoyalBlue", "special" },
296         { math, N_("math"), "math", "DarkBlue", "math" },
297         { mathbg, N_("math background"), "mathbg", "linen", "mathbg" },
298         { graphicsbg, N_("graphics background"), "graphicsbg", "linen", "graphicsbg" },
299         { mathmacrobg, N_("Math macro background"), "mathmacrobg", "linen", "mathmacrobg" },
300         { mathframe, N_("math frame"), "mathframe", "Magenta", "mathframe" },
301         { mathline, N_("math line"), "mathline", "Blue", "mathline" },
302         { captionframe, N_("caption frame"), "captionframe", "DarkRed", "captionframe" },
303         { collapsable, N_("collapsable inset text"), "collapsable", "DarkRed", "collapsable" },
304         { collapsableframe, N_("collapsable inset frame"), "collapsableframe", "IndianRed", "collapsableframe" },
305         { insetbg, N_("inset background"), "insetbg", "grey80", "insetbg" },
306         { insetframe, N_("inset frame"), "insetframe", "IndianRed", "insetframe" },
307         { error, N_("LaTeX error"), "error", "Red", "error" },
308         { eolmarker, N_("end-of-line marker"), "eolmarker", "Brown", "eolmarker" },
309         { appendix, N_("appendix marker"), "appendix", "Brown", "appendix" },
310         { changebar, N_("change bar"), "changebar", "Blue", "changebar" },
311         { strikeout, N_("Deleted text"), "strikeout", "Red", "strikeout" },
312         { newtext, N_("Added text"), "newtext", "Blue", "newtext" },
313         { added_space, N_("added space markers"), "added_space", "Brown", "added_space" },
314         { topline, N_("top/bottom line"), "topline", "Brown", "topline" },
315         { tabularline, N_("table line"), "tabularline", "black",
316              "tabularline" },
317         { tabularonoffline, N_("table on/off line"), "tabularonoffline",
318              "LightSteelBlue", "tabularonoffline" },
319         { bottomarea, N_("bottom area"), "bottomarea", "grey40", "bottomarea" },
320         { pagebreak, N_("page break"), "pagebreak", "RoyalBlue", "pagebreak" },
321         { buttonframe, N_("frame of button"), "buttonframe", "#dcd2c8", "buttonframe" },
322         { buttonbg, N_("button background"), "buttonbg", "#dcd2c8", "buttonbg" },
323         { buttonhoverbg, N_("button background under focus"), "buttonhoverbg", "#C7C7CA", "buttonhoverbg" },
324         { inherit, N_("inherit"), "inherit", "black", "inherit" },
325         { ignore, N_("ignore"), "ignore", "black", "ignore" },
326         { ignore, 0, 0, 0, 0 }
327         };
328
329         for (int i = 0; items[i].guiname; ++i)
330                 pimpl_->fill(items[i]);
331 }
332
333
334 Color::Color(Color const & c)
335         : pimpl_(new Pimpl(*c.pimpl_))
336 {}
337
338
339 Color::~Color()
340 {}
341
342
343 Color & Color::operator=(Color tmp)
344 {
345         boost::swap(pimpl_, tmp.pimpl_);
346         return *this;
347 }
348
349
350 docstring const Color::getGUIName(Color::color c) const
351 {
352         Pimpl::InfoTab::const_iterator it = pimpl_->infotab.find(c);
353         if (it != pimpl_->infotab.end())
354                 return _(it->second.guiname);
355         return from_ascii("none");
356 }
357
358
359 string const Color::getX11Name(Color::color c) const
360 {
361         Pimpl::InfoTab::const_iterator it = pimpl_->infotab.find(c);
362         if (it != pimpl_->infotab.end())
363                 return it->second.x11name;
364
365         lyxerr << "LyX internal error: Missing color"
366                   " entry in Color.cpp for " << c << '\n'
367                << "Using black." << endl;
368         return "black";
369 }
370
371
372 string const Color::getLaTeXName(Color::color c) const
373 {
374         Pimpl::InfoTab::const_iterator it = pimpl_->infotab.find(c);
375         if (it != pimpl_->infotab.end())
376                 return it->second.latexname;
377         return "black";
378 }
379
380
381 string const Color::getLyXName(Color::color c) const
382 {
383         Pimpl::InfoTab::const_iterator it = pimpl_->infotab.find(c);
384         if (it != pimpl_->infotab.end())
385                 return it->second.lyxname;
386         return "black";
387 }
388
389
390 bool Color::setColor(Color::color col, string const & x11name)
391 {
392         Pimpl::InfoTab::iterator it = pimpl_->infotab.find(col);
393         if (it == pimpl_->infotab.end()) {
394                 lyxerr << "Color " << col << " not found in database."
395                        << std::endl;
396                 return false;
397         }
398
399         // "inherit" is returned for colors not in the database
400         // (and anyway should not be redefined)
401         if (col == none || col == inherit || col == ignore) {
402                 lyxerr << "Color " << getLyXName(col)
403                        << " may not be redefined" << endl;
404                 return false;
405         }
406
407         it->second.x11name = x11name;
408         return true;
409 }
410
411
412 bool Color::setColor(string const & lyxname, string const &x11name)
413 {
414         string const lcname = ascii_lowercase(lyxname);
415         if (pimpl_->lyxcolors.find(lcname) == pimpl_->lyxcolors.end()) {
416                 LYXERR(Debug::GUI)
417                         << "Color::setColor: Unknown color \""
418                        << lyxname << '"' << endl;
419                 addColor(static_cast<color>(pimpl_->infotab.size()), lcname);
420         }
421
422         return setColor(pimpl_->lyxcolors[lcname], x11name);
423 }
424
425
426 void Color::addColor(Color::color c, string const & lyxname) const
427 {
428         ColorEntry ce = { c, "", "", "", lyxname.c_str() };
429         pimpl_->fill(ce);
430 }
431
432
433 Color::color Color::getFromLyXName(string const & lyxname) const
434 {
435         string const lcname = ascii_lowercase(lyxname);
436         if (pimpl_->lyxcolors.find(lcname) == pimpl_->lyxcolors.end()) {
437                 lyxerr << "Color::getFromLyXName: Unknown color \""
438                        << lyxname << '"' << endl;
439                 return none;
440         }
441
442         return pimpl_->lyxcolors[lcname];
443 }
444
445
446 Color::color Color::getFromLaTeXName(string const & latexname) const
447 {
448         if (pimpl_->latexcolors.find(latexname) == pimpl_->latexcolors.end()) {
449                 lyxerr << "Color::getFromLaTeXName: Unknown color \""
450                        << latexname << '"' << endl;
451                 return none;
452         }
453
454         return pimpl_->latexcolors[latexname];
455 }
456
457
458 // The evil global Color instance
459 Color lcolor;
460 // An equally evil global system Color instance
461 Color system_lcolor;
462
463
464 } // namespace lyx