2 /* This file is part of
3 * ======================================================
5 * LyX, The Document Processor
7 * Copyright 1998-2000 The LyX Team
9 *======================================================*/
14 #pragma implementation
23 #include FORMS_H_LOCATION
28 #include "support/LAssert.h"
29 #include "support/lstrings.h"
31 Painter::Painter(WorkArea & wa)
34 colormap = fl_state[fl_get_vclass()].colormap;
36 for (int i = 0; i <= LColor::ignore; ++i) {
43 // Release all the registered GCs
44 for (int i = 0; i <= LColor::ignore; ++i) {
45 if (colorGCcache[i] != 0) {
46 XFreeGC(display, colorGCcache[i]);
49 // Iterate over the line cache and Free the GCs
50 for (LineGCCache::iterator lit = lineGCcache.begin();
51 lit != lineGCcache.end(); ++lit) {
52 XFreeGC(display, (*lit).second);
57 /* Basic drawing routines */
59 extern bool Lgb_bug_find_hack;
61 PainterBase & Painter::point(int x, int y, LColor::color c)
63 if (lyxerr.debugging()) {
64 if (!Lgb_bug_find_hack)
65 lyxerr << "point not called from "
66 "workarea::workhandler\n";
67 lyxerr.debug() << "Painter drawable: " << drawable << endl;
70 XDrawPoint(display, drawable, getGCForeground(c), x, y);
75 PainterBase & Painter::line(int x1, int y1, int x2, int y2,
80 if (lyxerr.debugging()) {
81 if (!Lgb_bug_find_hack)
82 lyxerr << "line not called from "
83 "workarea::workhandler\n";
84 lyxerr.debug() << "Painter drawable: " << drawable << endl;
87 XDrawLine(display, drawable,
88 getGCLinepars(ls, lw, col), x1, y1, x2, y2);
93 PainterBase & Painter::lines(int const * xp, int const * yp, int np,
98 if (lyxerr.debugging()) {
99 if (!Lgb_bug_find_hack)
100 lyxerr << "lines not called from "
101 "workarea::workhandler\n";
102 lyxerr.debug() << "Painter drawable: " << drawable << endl;
105 #ifndef HAVE_AUTO_PTR
106 XPoint * points = new XPoint[np];
108 auto_ptr<XPoint> points(new Xpoint[np]);
110 for (int i=0; i<np; ++i) {
115 XDrawLines(display, drawable, getGCLinepars(ls, lw, col),
116 points, np, CoordModeOrigin);
118 #ifndef HAVE_AUTO_PTR
125 PainterBase & Painter::rectangle(int x, int y, int w, int h,
130 if (lyxerr.debugging()) {
131 if (!Lgb_bug_find_hack)
132 lyxerr << "rectangle not called from "
133 "workarea::workhandler\n";
134 lyxerr << "Painter drawable: " << drawable << endl;
137 XDrawRectangle(display, drawable, getGCLinepars(ls, lw, col),
143 PainterBase & Painter::fillRectangle(int x, int y, int w, int h,
146 if (lyxerr.debugging()) {
147 if (!Lgb_bug_find_hack)
148 lyxerr << "fillrectangle not called from "
149 "workarea::workhandler\n";
150 lyxerr << "Painter drawable: " << drawable << endl;
153 XFillRectangle(display, drawable, getGCForeground(col), x, y, w, h);
158 PainterBase & Painter::fillPolygon(int const * xp, int const * yp, int np,
161 if (lyxerr.debugging()) {
162 if (!Lgb_bug_find_hack)
163 lyxerr <<"fillpolygon not called from "
164 "workarea::workhandler\n";
165 lyxerr << "Painter drawable: " << drawable << endl;
168 #ifndef HAVE_AUTO_PTR
169 XPoint * points = new XPoint[np];
171 auto_ptr<XPoint> points(new XPoint[np]);
173 for (int i=0; i<np; ++i) {
178 XFillPolygon(display, drawable, getGCForeground(col), points, np,
179 Nonconvex, CoordModeOrigin);
180 #ifndef HAVE_AUTO_PTR
187 PainterBase & Painter::arc(int x, int y,
188 unsigned int w, unsigned int h,
189 int a1, int a2, LColor::color col)
191 if (lyxerr.debugging()) {
192 if (!Lgb_bug_find_hack)
193 lyxerr << "arc not called from "
194 "workarea::workhandler\n";
195 lyxerr << "Painter drawable: " << drawable << endl;
198 XDrawArc(display, drawable, getGCForeground(col),
204 /// Draw lines from x1,y1 to x2,y2. They are arrays
205 PainterBase & Painter::segments(int const * x1, int const * y1,
206 int const * x2, int const * y2, int ns,
208 enum line_style ls, enum line_width lw)
210 if (lyxerr.debugging()) {
211 if (!Lgb_bug_find_hack)
212 lyxerr << "segments not called from "
213 "workarea::workhandler\n";
214 lyxerr << "Painter drawable: " << drawable << endl;
217 #ifndef HAVE_AUTO_PTR
218 XSegment * s= new XSegment[ns];
220 auto_ptr<XSegment> s(new XSegment[ns]);
222 for (int i=0; i<ns; ++i) {
228 XDrawSegments(display, drawable, getGCLinepars(ls, lw, col), s, ns);
230 #ifndef HAVE_AUTO_PTR
237 PainterBase & Painter::pixmap(int x, int y, int w, int h, Pixmap bitmap)
239 if (lyxerr.debugging()) {
240 if (!Lgb_bug_find_hack)
241 lyxerr << "workAreaExpose not called from "
242 "workarea::workhandler\n";
243 lyxerr << "Painter drawable: " << drawable << endl;
247 val.function = GXcopy;
248 GC gc = XCreateGC(display, drawable,
250 XCopyArea(display, bitmap, drawable, gc,
252 XFreeGC(display, gc);
257 PainterBase & Painter::text(int x, int y, string const & s, LyXFont const & f)
259 return text(x, y, s.c_str(), s.length(), f);
263 PainterBase & Painter::text(int x, int y, char c, LyXFont const & f)
265 char s[2] = { c, '\0' };
266 return text(x, y, s, 1, f);
270 PainterBase & Painter::text(int x, int y, char const * s, int ls,
273 if (lyxerr.debugging()) {
274 if (!Lgb_bug_find_hack)
275 lyxerr << "text not called from "
276 "workarea::workhandler\n";
277 lyxerr << "Painter drawable: " << drawable << endl;
280 GC gc = getGCForeground(f.realColor());
281 XSetFont(display, gc, f.getFontID());
282 XDrawString(display, drawable, gc, x, y, s, ls);
283 underline(f, x, y, this->width(s, ls, f));
288 void Painter::underline(LyXFont const & f, int x, int y, int width)
290 // What about underbars?
291 if (f.underbar() == LyXFont::ON && f.latex() != LyXFont::ON) {
292 int below = f.maxDescent() / 2;
293 if (below < 2) below = 2;
294 int height = (f.maxDescent() / 4) - 1;
295 if (height < 0) height = 0;
296 fillRectangle(x, y + below, width, below + height, f.color());
301 // Gets GC according to color
303 GC Painter::getGCForeground(LColor::color c)
305 if (lyxerr.debugging()) {
306 lyxerr << "Painter drawable: " << drawable << endl;
309 if (colorGCcache[c] != 0) return colorGCcache[c];
312 string s = lcolor.getX11Name(c);
315 // Look up the RGB values for the color, and an approximate
316 // color that we can hope to get on this display.
317 if (XLookupColor(display, colormap, s.c_str(), &xcol, &ccol) == 0) {
318 lyxerr << _("LyX: Unknown X11 color ") << s
319 << _(" for ") << lcolor.getGUIName(c) << '\n'
320 << _(" Using black instead, sorry!.") << endl;
321 unsigned long bla = BlackPixel(display,
322 DefaultScreen(display));
323 val.foreground = bla;
324 // Try the exact RGB values first, then the approximate.
325 } else if (XAllocColor(display, colormap, &xcol) != 0) {
326 if (lyxerr.debugging()) {
327 lyxerr << _("LyX: X11 color ") << s
328 << _(" allocated for ")
329 << lcolor.getGUIName(c) << endl;
331 val.foreground = xcol.pixel;
332 } else if (XAllocColor(display, colormap, &ccol)) {
333 lyxerr << _("LyX: Using approximated X11 color ") << s
334 << _(" allocated for ")
335 << lcolor.getGUIName(c) << endl;
336 val.foreground = xcol.pixel;
338 // Here we are traversing the current colormap to find
339 // the color closest to the one we want.
340 Visual * vi = DefaultVisual(display, DefaultScreen(display));
342 XColor * cmap = new XColor[vi->map_entries];
344 for(int i = 0; i < vi->map_entries; ++i) {
347 XQueryColors(display, colormap, cmap, vi->map_entries);
349 // Walk through the cmap and look for close colors.
350 int closest_pixel = 0;
351 double closest_distance = 1e20; // we want to minimize this
353 for(int t = 0; t < vi->map_entries; ++t) {
354 // The Euclidean distance between two points in
355 // a three-dimensional space, the RGB color-cube,
356 // is used as the distance measurement between two
359 // Since square-root is monotonous, we don't have to
360 // take the square-root to find the minimum, and thus
361 // we use the squared distance instead to be faster.
363 // If we want to get fancy, we could convert the RGB
364 // coordinates to a different color-cube, maybe HSV,
365 // but the RGB cube seems to work great. (Asger)
366 distance = pow(cmap[t].red - xcol.red, 2.0) +
367 pow(cmap[t].green - xcol.green, 2.0) +
368 pow(cmap[t].blue - xcol.blue, 2.0);
369 if (distance < closest_distance) {
370 closest_distance = distance;
374 lyxerr << _("LyX: Couldn't allocate '") << s
375 << _("' for ") << lcolor.getGUIName(c)
376 << _(" with (r,g,b)=(")
377 << xcol.red << "," << xcol.green << ","
378 << xcol.blue << ").\n"
379 << _(" Using closest allocated "
380 "color with (r,g,b)=(")
381 << cmap[closest_pixel].red << ","
382 << cmap[closest_pixel].green << ","
383 << cmap[closest_pixel].blue << ") instead.\n"
384 << "Pixel [" << closest_pixel << "] is used." << endl;
385 val.foreground = cmap[closest_pixel].pixel;
389 val.function = GXcopy;
390 return colorGCcache[c] = XCreateGC(display, drawable,
391 GCForeground | GCFunction, &val);
396 GC Painter::getGCLinepars(enum line_style ls,
397 enum line_width lw, LColor::color c)
399 if (lyxerr.debugging()) {
400 lyxerr << "Painter drawable: " << drawable << endl;
403 int index = lw + (ls << 1) + (c << 3);
405 if (lineGCcache.find(index) != lineGCcache.end())
406 return lineGCcache[index];
409 XGetGCValues(display, getGCForeground(c), GCForeground, &val);
412 case line_thin: val.line_width = 0; break;
413 case line_thick: val.line_width = 2; break;
417 case line_solid: val.line_style = LineSolid; break;
418 case line_onoffdash: val.line_style = LineOnOffDash; break;
419 case line_doubledash: val.line_style = LineDoubleDash; break;
423 val.cap_style = CapRound;
424 val.join_style = JoinRound;
425 val.function = GXcopy;
427 return lineGCcache[index] =
428 XCreateGC(display, drawable,
429 GCForeground | GCLineStyle | GCLineWidth |
430 GCCapStyle | GCJoinStyle | GCFunction, &val);