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