]> git.lyx.org Git - lyx.git/blob - src/Painter.C
update copyright year
[lyx.git] / src / Painter.C
1 // -*- C++ -*-
2 /* This file is part of
3  * ======================================================
4  * 
5  *           LyX, The Document Processor
6  *       
7  *          Copyright 1998-2001 The LyX Team
8  *
9  *======================================================*/
10
11 #include <config.h>
12
13 #ifdef __GNUG__
14 #pragma implementation
15 #endif
16
17 #ifdef USE_STL_MEMORY
18 #include <memory>
19 #endif
20
21 #include <cmath>
22
23 #include FORMS_H_LOCATION
24 #include "Painter.h"
25 #include "LString.h"
26 #include "debug.h"
27 #include "lyxfont.h"
28 #include "support/LAssert.h"
29 #include "support/lstrings.h"
30 #include "WorkArea.h"
31 #include "font.h"
32 #include "ColorHandler.h"
33 #include "lyxrc.h"
34 #include "encoding.h"
35 #include "language.h"
36
37 #include "frontends/support/LyXImage.h"
38
39 using std::endl;
40 using std::max;
41
42 Painter::Painter(WorkArea & wa)
43         : PainterBase(wa)
44 {
45         display = fl_get_display();
46 }
47
48
49 /* Basic drawing routines */
50
51 extern bool Lgb_bug_find_hack;
52
53 PainterBase & Painter::point(int x, int y, LColor::color c)
54 {
55         if (lyxerr.debugging(Debug::GUI)) {
56                 if (!Lgb_bug_find_hack)
57                         lyxerr << "point not called from "
58                                 "workarea::workhandler\n";
59                 lyxerr.debug() << "Painter drawable: "
60                                << owner.getPixmap() << endl;
61         }
62         
63         XDrawPoint(display, owner.getPixmap(),
64                    lyxColorHandler->getGCForeground(c), x, y);
65         return *this;
66 }
67
68
69 PainterBase & Painter::line(int x1, int y1, int x2, int y2,
70                         LColor::color col,
71                         enum line_style ls,
72                         enum line_width lw)
73 {
74         if (lyxerr.debugging(Debug::GUI)) {
75                 if (!Lgb_bug_find_hack)
76                         lyxerr << "line not called from "
77                                 "workarea::workhandler\n";
78                 lyxerr.debug() << "Painter drawable: "
79                                << owner.getPixmap() << endl;
80         }
81         
82         XDrawLine(display, owner.getPixmap(), 
83                   lyxColorHandler->getGCLinepars(ls, lw, col),
84                   x1, y1, x2, y2);
85         return *this;
86 }
87
88
89 PainterBase & Painter::lines(int const * xp, int const * yp, int np,
90                              LColor::color col,
91                              enum line_style ls,
92                              enum line_width lw)
93 {
94         if (lyxerr.debugging(Debug::GUI)) {
95                 if (!Lgb_bug_find_hack)
96                         lyxerr << "lines not called from "
97                                 "workarea::workhandler\n";
98                 lyxerr.debug() << "Painter drawable: "
99                                << owner.getPixmap() << endl;
100         }
101         
102 #ifndef HAVE_AUTO_PTR
103         XPoint * points = new XPoint[np];
104 #else
105         auto_ptr<XPoint> points(new Xpoint[np]);
106 #endif
107         for (int i = 0; i < np; ++i) {
108                 points[i].x = xp[i];
109                 points[i].y = yp[i];
110         }
111
112         XDrawLines(display, owner.getPixmap(),
113                    lyxColorHandler->getGCLinepars(ls, lw, col), 
114                    points, np, CoordModeOrigin);
115
116 #ifndef HAVE_AUTO_PTR
117         delete[] points;
118 #endif  
119         return *this;
120 }      
121
122
123 PainterBase & Painter::rectangle(int x, int y, int w, int h,
124                                  LColor::color col,
125                                  enum line_style ls,
126                                  enum line_width lw)
127 {
128         if (lyxerr.debugging(Debug::GUI)) {
129                 if (!Lgb_bug_find_hack)
130                         lyxerr << "rectangle not called from "
131                                 "workarea::workhandler\n";
132                 lyxerr << "Painter drawable: "
133                        << owner.getPixmap() << endl;
134         }
135         
136         XDrawRectangle(display, owner.getPixmap(),
137                        lyxColorHandler->getGCLinepars(ls, lw, col), 
138                        x, y, w, h);
139         return *this;
140 }
141
142
143 PainterBase & Painter::fillRectangle(int x, int y, int w, int h,
144                                  LColor::color col)
145 {
146         if (lyxerr.debugging(Debug::GUI)) {
147                 if (!Lgb_bug_find_hack)
148                         lyxerr << "fillrectangle not called from "
149                                 "workarea::workhandler\n";
150                 lyxerr << "Painter drawable: "
151                        << owner.getPixmap() << endl;
152         }
153         
154         XFillRectangle(display, owner.getPixmap(),
155                        lyxColorHandler->getGCForeground(col), x, y, w, h);
156         return *this;
157 }
158
159
160 PainterBase & Painter::fillPolygon(int const * xp, int const * yp, int np,
161                                LColor::color col)
162 {
163         if (lyxerr.debugging(Debug::GUI)) {
164                 if (!Lgb_bug_find_hack)
165                         lyxerr <<"fillpolygon not called from "
166                                 "workarea::workhandler\n";
167                 lyxerr << "Painter drawable: " << owner.getPixmap() << endl;
168         }
169         
170 #ifndef HAVE_AUTO_PTR
171         XPoint * points = new XPoint[np];
172 #else
173         auto_ptr<XPoint> points(new XPoint[np]);
174 #endif
175         for (int i=0; i < np; ++i) {
176                 points[i].x = xp[i];
177                 points[i].y = yp[i];
178         }
179
180         XFillPolygon(display, owner.getPixmap(),
181                      lyxColorHandler->getGCForeground(col), points, np, 
182                      Nonconvex, CoordModeOrigin);
183 #ifndef HAVE_AUTO_PTR
184         delete[] points;
185 #endif  
186         return *this;
187 }      
188
189
190 PainterBase & Painter::arc(int x, int y,
191                   unsigned int w, unsigned int h,
192                   int a1, int a2, LColor::color col)
193 {
194         if (lyxerr.debugging(Debug::GUI)) {
195                 if (!Lgb_bug_find_hack)
196                         lyxerr << "arc not called from "
197                                 "workarea::workhandler\n";
198                 lyxerr << "Painter drawable: " << owner.getPixmap() << endl;
199         }
200         
201         XDrawArc(display, owner.getPixmap(),
202                  lyxColorHandler->getGCForeground(col),
203                  x, y, w, h, a1, a2);
204         return *this;
205 }     
206
207
208 /// Draw lines from x1,y1 to x2,y2. They are arrays
209 PainterBase & Painter::segments(int const * x1, int const * y1, 
210                             int const * x2, int const * y2, int ns,
211                             LColor::color col,
212                             enum line_style ls, enum line_width lw)
213 {
214         if (lyxerr.debugging(Debug::GUI)) {
215                 if (!Lgb_bug_find_hack)
216                         lyxerr << "segments not called from "
217                                 "workarea::workhandler\n";
218                 lyxerr << "Painter drawable: " << owner.getPixmap() << endl;
219         }
220         
221 #ifndef HAVE_AUTO_PTR
222         XSegment * s= new XSegment[ns];
223 #else
224         auto_ptr<XSegment> s(new XSegment[ns]);
225 #endif
226         for (int i=0; i<ns; ++i) {
227                 s[i].x1 = x1[i];
228                 s[i].y1 = y1[i];
229                 s[i].x2 = x2[i];
230                 s[i].y2 = y2[i];
231         }
232         XDrawSegments(display, owner.getPixmap(),
233                       lyxColorHandler->getGCLinepars(ls, lw, col), s, ns);
234
235 #ifndef HAVE_AUTO_PTR
236         delete [] s;
237 #endif
238         return *this;
239 }
240
241 PainterBase & Painter::pixmap(int x, int y, int w, int h, Pixmap bitmap)
242 {
243         if (lyxerr.debugging(Debug::GUI)) {
244                 if (!Lgb_bug_find_hack)
245                         lyxerr << "workAreaExpose not called from "
246                                 "workarea::workhandler\n";
247                 lyxerr << "Painter drawable: " << owner.getPixmap() << endl;
248         }
249
250         XGCValues val;
251         val.function = GXcopy;
252         GC gc = XCreateGC(display, owner.getPixmap(),
253                           GCFunction, &val);
254         XCopyArea(display, bitmap, owner.getPixmap(), gc,
255                   0, 0, w, h, x, y);
256         XFreeGC(display, gc);
257         return *this;
258 }
259
260 PainterBase & Painter::image(int x, int y, int w, int h, LyXImage const * image)
261 {
262         Pixmap bitmap = image->getPixmap();
263
264         return pixmap(x, y, w, h, bitmap);
265 }
266
267
268 PainterBase & Painter::text(int x, int y, string const & s, LyXFont const & f)
269 {
270         return text(x, y, s.c_str(), s.length(), f);
271 }
272
273
274 PainterBase & Painter::text(int x, int y, char c, LyXFont const & f)
275 {
276         char s[2] = { c, '\0' };
277         return text(x, y, s, 1, f);
278 }
279
280
281 PainterBase & Painter::text(int x, int y, char const * s, size_t ls,
282                         LyXFont const & f)
283 {
284         if (lyxrc.font_norm_type == LyXRC::ISO_10646_1) {
285                 XChar2b * xs = new XChar2b[ls];
286                 Encoding const * encoding = f.language()->encoding();
287                 LyXFont font(f);
288                 if (f.family() == LyXFont::SYMBOL_FAMILY) {
289 #ifdef USE_UNICODE_FOR_SYMBOLS
290                         font.setFamily(LyXFont::ROMAN_FAMILY);
291                         font.setShape(LyXFont::UP_SHAPE);
292 #endif
293                         encoding = encodings.symbol_encoding();
294                 }
295                 for (size_t i = 0; i < ls; ++i) {
296                         Uchar c = encoding->ucs(s[i]);
297                         xs[i].byte1 = c >> 8;
298                         xs[i].byte2 = c & 0xff;
299                 }
300                 text(x , y, xs, ls, font);
301                 delete[] xs;
302                 return *this;
303         }
304
305         if (lyxerr.debugging(Debug::GUI)) {
306                 if (!Lgb_bug_find_hack)
307                         lyxerr << "text not called from "
308                                 "workarea::workhandler\n";
309                 lyxerr << "Painter drawable: " << owner.getPixmap() << endl;
310         }
311         GC gc = lyxColorHandler->getGCForeground(f.realColor());
312         if (f.realShape() != LyXFont::SMALLCAPS_SHAPE) {
313                 lyxfont::XSetFont(display, gc, f);
314                 XDrawString(display, owner.getPixmap(), gc, x, y, s, ls);
315         } else {
316                 LyXFont smallfont(f);
317                 smallfont.decSize().decSize().setShape(LyXFont::UP_SHAPE);
318                 char c;
319                 int tmpx = x;
320                 for (size_t i = 0; i < ls; ++i) {
321                         c = s[i];
322                         if (islower(static_cast<unsigned char>(c))) {
323                                 c = toupper(c);
324                                 lyxfont::XSetFont(display, gc, smallfont);
325                                 XDrawString(display, owner.getPixmap(),
326                                             gc, tmpx, y, &c, 1);
327                                 tmpx += lyxfont::XTextWidth(smallfont, &c, 1);
328                         } else {
329                                 lyxfont::XSetFont(display, gc, f);
330                                 XDrawString(display, owner.getPixmap(),
331                                             gc, tmpx, y, &c, 1);
332                                 tmpx += lyxfont::XTextWidth(f, &c, 1);
333                         }
334                 }
335         }
336         if (f.underbar() == LyXFont::ON && f.latex() != LyXFont::ON)
337                 underline(f, x, y, lyxfont::width(s, ls, f));
338         return *this;
339 }
340
341
342 PainterBase & Painter::text(int x, int y, XChar2b const * s, int ls,
343                         LyXFont const & f)
344 {
345         if (lyxerr.debugging(Debug::GUI)) {
346                 if (!Lgb_bug_find_hack)
347                         lyxerr << "text not called from "
348                                 "workarea::workhandler\n";
349                 lyxerr << "Painter drawable: " << owner.getPixmap() << endl;
350         }
351         GC gc = lyxColorHandler->getGCForeground(f.realColor());
352         if (f.realShape() != LyXFont::SMALLCAPS_SHAPE) {
353                 lyxfont::XSetFont(display, gc, f);
354                 XDrawString16(display, owner.getPixmap(), gc, x, y, s, ls);
355         } else {
356                 LyXFont smallfont(f);
357                 smallfont.decSize().decSize().setShape(LyXFont::UP_SHAPE);
358                 static XChar2b c = {0, 0};
359                 int tmpx = x;
360                 for (int i = 0; i < ls; ++i) {
361                         if (s[i].byte1 == 0 && islower(s[i].byte2)) {
362                                 c.byte2 = toupper(s[i].byte2);
363                                 lyxfont::XSetFont(display, gc, smallfont);
364                                 XDrawString16(display, owner.getPixmap(),
365                                             gc, tmpx, y, &c, 1);
366                                 tmpx += lyxfont::XTextWidth16(smallfont, &c, 1);
367                         } else {
368                                 lyxfont::XSetFont(display, gc, f);
369                                 XDrawString16(display, owner.getPixmap(),
370                                             gc, tmpx, y, &s[i], 1);
371                                 tmpx += lyxfont::XTextWidth16(f, const_cast<XChar2b *>(&s[i]), 1);
372                         }
373                 }
374         }
375         if (f.underbar() == LyXFont::ON && f.latex() != LyXFont::ON)
376                 underline(f, x, y, lyxfont::width(s, ls, f));
377         return *this;
378 }
379
380
381 void Painter::underline(LyXFont const & f, int x, int y, int width)
382 {
383         int below = max(lyxfont::maxDescent(f) / 2, 2);
384         int height = max((lyxfont::maxDescent(f) / 4) - 1, 1);
385         if (height < 2)
386                 line(x, y + below, x + width, y + below, f.color());
387         else
388                 fillRectangle(x, y + below, width, below + height,
389                               f.color());
390 }