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"
32 Painter::Painter(WorkArea & wa)
35 colormap = fl_state[fl_get_vclass()].colormap;
37 for (int i = 0; i <= LColor::ignore; ++i) {
44 // Release all the registered GCs
45 for (int i = 0; i <= LColor::ignore; ++i) {
46 if (colorGCcache[i] != 0) {
47 XFreeGC(display, colorGCcache[i]);
50 // Iterate over the line cache and Free the GCs
51 for (LineGCCache::iterator lit = lineGCcache.begin();
52 lit != lineGCcache.end(); ++lit) {
53 XFreeGC(display, (*lit).second);
58 Drawable Painter::drawable() const
60 return owner.getPixmap();
64 /* Basic drawing routines */
66 extern bool Lgb_bug_find_hack;
68 PainterBase & Painter::point(int x, int y, LColor::color c)
70 if (lyxerr.debugging()) {
71 if (!Lgb_bug_find_hack)
72 lyxerr << "point not called from "
73 "workarea::workhandler\n";
74 lyxerr.debug() << "Painter drawable: " << drawable() << endl;
77 XDrawPoint(display, drawable(), getGCForeground(c), x, y);
82 PainterBase & Painter::line(int x1, int y1, int x2, int y2,
87 if (lyxerr.debugging()) {
88 if (!Lgb_bug_find_hack)
89 lyxerr << "line not called from "
90 "workarea::workhandler\n";
91 lyxerr.debug() << "Painter drawable: " << drawable() << endl;
94 XDrawLine(display, drawable(),
95 getGCLinepars(ls, lw, col), x1, y1, x2, y2);
100 PainterBase & Painter::lines(int const * xp, int const * yp, int np,
105 if (lyxerr.debugging()) {
106 if (!Lgb_bug_find_hack)
107 lyxerr << "lines not called from "
108 "workarea::workhandler\n";
109 lyxerr.debug() << "Painter drawable: " << drawable() << endl;
112 #ifndef HAVE_AUTO_PTR
113 XPoint * points = new XPoint[np];
115 auto_ptr<XPoint> points(new Xpoint[np]);
117 for (int i=0; i<np; ++i) {
122 XDrawLines(display, drawable(), getGCLinepars(ls, lw, col),
123 points, np, CoordModeOrigin);
125 #ifndef HAVE_AUTO_PTR
132 PainterBase & Painter::rectangle(int x, int y, int w, int h,
137 if (lyxerr.debugging()) {
138 if (!Lgb_bug_find_hack)
139 lyxerr << "rectangle not called from "
140 "workarea::workhandler\n";
141 lyxerr << "Painter drawable: " << drawable() << endl;
144 XDrawRectangle(display, drawable(), getGCLinepars(ls, lw, col),
150 PainterBase & Painter::fillRectangle(int x, int y, int w, int h,
153 if (lyxerr.debugging()) {
154 if (!Lgb_bug_find_hack)
155 lyxerr << "fillrectangle not called from "
156 "workarea::workhandler\n";
157 lyxerr << "Painter drawable: " << drawable() << endl;
160 XFillRectangle(display, drawable(), getGCForeground(col), x, y, w, h);
165 PainterBase & Painter::fillPolygon(int const * xp, int const * yp, int np,
168 if (lyxerr.debugging()) {
169 if (!Lgb_bug_find_hack)
170 lyxerr <<"fillpolygon not called from "
171 "workarea::workhandler\n";
172 lyxerr << "Painter drawable: " << drawable() << endl;
175 #ifndef HAVE_AUTO_PTR
176 XPoint * points = new XPoint[np];
178 auto_ptr<XPoint> points(new XPoint[np]);
180 for (int i=0; i<np; ++i) {
185 XFillPolygon(display, drawable(), getGCForeground(col), points, np,
186 Nonconvex, CoordModeOrigin);
187 #ifndef HAVE_AUTO_PTR
194 PainterBase & Painter::arc(int x, int y,
195 unsigned int w, unsigned int h,
196 int a1, int a2, LColor::color col)
198 if (lyxerr.debugging()) {
199 if (!Lgb_bug_find_hack)
200 lyxerr << "arc not called from "
201 "workarea::workhandler\n";
202 lyxerr << "Painter drawable: " << drawable() << endl;
205 XDrawArc(display, drawable(), getGCForeground(col),
211 /// Draw lines from x1,y1 to x2,y2. They are arrays
212 PainterBase & Painter::segments(int const * x1, int const * y1,
213 int const * x2, int const * y2, int ns,
215 enum line_style ls, enum line_width lw)
217 if (lyxerr.debugging()) {
218 if (!Lgb_bug_find_hack)
219 lyxerr << "segments not called from "
220 "workarea::workhandler\n";
221 lyxerr << "Painter drawable: " << drawable() << endl;
224 #ifndef HAVE_AUTO_PTR
225 XSegment * s= new XSegment[ns];
227 auto_ptr<XSegment> s(new XSegment[ns]);
229 for (int i=0; i<ns; ++i) {
235 XDrawSegments(display, drawable(), getGCLinepars(ls, lw, col), s, ns);
237 #ifndef HAVE_AUTO_PTR
244 PainterBase & Painter::pixmap(int x, int y, int w, int h, Pixmap bitmap)
246 if (lyxerr.debugging()) {
247 if (!Lgb_bug_find_hack)
248 lyxerr << "workAreaExpose not called from "
249 "workarea::workhandler\n";
250 lyxerr << "Painter drawable: " << drawable() << endl;
254 val.function = GXcopy;
255 GC gc = XCreateGC(display, drawable(),
257 XCopyArea(display, bitmap, drawable(), gc,
259 XFreeGC(display, gc);
264 PainterBase & Painter::text(int x, int y, string const & s, LyXFont const & f)
266 return text(x, y, s.c_str(), s.length(), f);
270 PainterBase & Painter::text(int x, int y, char c, LyXFont const & f)
272 char s[2] = { c, '\0' };
273 return text(x, y, s, 1, f);
277 PainterBase & Painter::text(int x, int y, char const * s, int ls,
280 if (lyxerr.debugging()) {
281 if (!Lgb_bug_find_hack)
282 lyxerr << "text not called from "
283 "workarea::workhandler\n";
284 lyxerr << "Painter drawable: " << drawable() << endl;
287 GC gc = getGCForeground(f.realColor());
288 XSetFont(display, gc, f.getFontID());
289 XDrawString(display, drawable(), gc, x, y, s, ls);
290 underline(f, x, y, this->width(s, ls, f));
295 void Painter::underline(LyXFont const & f, int x, int y, int width)
297 // What about underbars?
298 if (f.underbar() == LyXFont::ON && f.latex() != LyXFont::ON) {
299 int below = f.maxDescent() / 2;
300 if (below < 2) below = 2;
301 int height = (f.maxDescent() / 4) - 1;
302 if (height < 0) height = 0;
303 fillRectangle(x, y + below, width, below + height, f.color());
308 // Gets GC according to color
310 GC Painter::getGCForeground(LColor::color c)
312 if (lyxerr.debugging()) {
313 lyxerr << "Painter drawable: " << drawable() << endl;
316 if (colorGCcache[c] != 0) return colorGCcache[c];
319 string s = lcolor.getX11Name(c);
322 // Look up the RGB values for the color, and an approximate
323 // color that we can hope to get on this display.
324 if (XLookupColor(display, colormap, s.c_str(), &xcol, &ccol) == 0) {
325 lyxerr << _("LyX: Unknown X11 color ") << s
326 << _(" for ") << lcolor.getGUIName(c) << '\n'
327 << _(" Using black instead, sorry!.") << endl;
328 unsigned long bla = BlackPixel(display,
329 DefaultScreen(display));
330 val.foreground = bla;
331 // Try the exact RGB values first, then the approximate.
332 } else if (XAllocColor(display, colormap, &xcol) != 0) {
333 if (lyxerr.debugging()) {
334 lyxerr << _("LyX: X11 color ") << s
335 << _(" allocated for ")
336 << lcolor.getGUIName(c) << endl;
338 val.foreground = xcol.pixel;
339 } else if (XAllocColor(display, colormap, &ccol)) {
340 lyxerr << _("LyX: Using approximated X11 color ") << s
341 << _(" allocated for ")
342 << lcolor.getGUIName(c) << endl;
343 val.foreground = xcol.pixel;
345 // Here we are traversing the current colormap to find
346 // the color closest to the one we want.
347 Visual * vi = DefaultVisual(display, DefaultScreen(display));
349 XColor * cmap = new XColor[vi->map_entries];
351 for(int i = 0; i < vi->map_entries; ++i) {
354 XQueryColors(display, colormap, cmap, vi->map_entries);
356 // Walk through the cmap and look for close colors.
357 int closest_pixel = 0;
358 double closest_distance = 1e20; // we want to minimize this
360 for(int t = 0; t < vi->map_entries; ++t) {
361 // The Euclidean distance between two points in
362 // a three-dimensional space, the RGB color-cube,
363 // is used as the distance measurement between two
366 // Since square-root is monotonous, we don't have to
367 // take the square-root to find the minimum, and thus
368 // we use the squared distance instead to be faster.
370 // If we want to get fancy, we could convert the RGB
371 // coordinates to a different color-cube, maybe HSV,
372 // but the RGB cube seems to work great. (Asger)
373 distance = pow(cmap[t].red - xcol.red, 2.0) +
374 pow(cmap[t].green - xcol.green, 2.0) +
375 pow(cmap[t].blue - xcol.blue, 2.0);
376 if (distance < closest_distance) {
377 closest_distance = distance;
381 lyxerr << _("LyX: Couldn't allocate '") << s
382 << _("' for ") << lcolor.getGUIName(c)
383 << _(" with (r,g,b)=(")
384 << xcol.red << "," << xcol.green << ","
385 << xcol.blue << ").\n"
386 << _(" Using closest allocated "
387 "color with (r,g,b)=(")
388 << cmap[closest_pixel].red << ","
389 << cmap[closest_pixel].green << ","
390 << cmap[closest_pixel].blue << ") instead.\n"
391 << "Pixel [" << closest_pixel << "] is used." << endl;
392 val.foreground = cmap[closest_pixel].pixel;
396 val.function = GXcopy;
397 return colorGCcache[c] = XCreateGC(display, drawable(),
398 GCForeground | GCFunction, &val);
403 GC Painter::getGCLinepars(enum line_style ls,
404 enum line_width lw, LColor::color c)
406 if (lyxerr.debugging()) {
407 lyxerr << "Painter drawable: " << drawable() << endl;
410 int index = lw + (ls << 1) + (c << 3);
412 if (lineGCcache.find(index) != lineGCcache.end())
413 return lineGCcache[index];
416 XGetGCValues(display, getGCForeground(c), GCForeground, &val);
419 case line_thin: val.line_width = 0; break;
420 case line_thick: val.line_width = 2; break;
424 case line_solid: val.line_style = LineSolid; break;
425 case line_onoffdash: val.line_style = LineOnOffDash; break;
426 case line_doubledash: val.line_style = LineDoubleDash; break;
430 val.cap_style = CapRound;
431 val.join_style = JoinRound;
432 val.function = GXcopy;
434 return lineGCcache[index] =
435 XCreateGC(display, drawable(),
436 GCForeground | GCLineStyle | GCLineWidth |
437 GCCapStyle | GCJoinStyle | GCFunction, &val);