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