]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/QLPainter.C
8bec6aecec3254be5f2e025fbe9e56453fb7f4d4
[lyx.git] / src / frontends / qt4 / QLPainter.C
1 /**
2  * \file QLPainter.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author John Levon
7  * \author Abdelrazak Younes
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include <QTextLayout>
15
16 #include "QLPainter.h"
17
18 #include "GuiApplication.h"
19 #include "GuiFontMetrics.h"
20 #include "QLImage.h"
21
22 #include "GuiApplication.h"
23 #include "qt_helpers.h"
24
25 #include "debug.h"
26 #include "language.h"
27 #include "LColor.h"
28
29 #include "support/unicode.h"
30
31 using std::endl;
32 using std::string;
33
34 namespace lyx {
35 namespace frontend {
36
37 QLPainter::QLPainter(QPaintDevice * device)
38         : QPainter(device), Painter()
39 {
40         // new QPainter has default QPen:
41         current_color_ = LColor::black;
42         current_ls_ = line_solid;
43         current_lw_ = line_thin;
44 }
45
46
47 QLPainter::~QLPainter()
48 {
49         QPainter::end();
50         //lyxerr << "QLPainter::end()" << endl;
51 }
52
53
54 void QLPainter::setQPainterPen(LColor_color col,
55         Painter::line_style ls, Painter::line_width lw)
56 {
57         if (col == current_color_ && ls == current_ls_ && lw == current_lw_)
58                 return;
59
60         current_color_ = col;
61         current_ls_ = ls;
62         current_lw_ = lw;
63
64         QPen pen = QPainter::pen();
65
66         pen.setColor(guiApp->colorCache().get(col));
67
68         switch (ls) {
69                 case line_solid: pen.setStyle(Qt::SolidLine); break;
70                 case line_onoffdash: pen.setStyle(Qt::DotLine); break;
71         }
72
73         switch (lw) {
74                 case line_thin: pen.setWidth(0); break;
75                 case line_thick: pen.setWidth(3); break;
76         }
77
78         setPen(pen);
79 }
80
81
82 void QLPainter::point(int x, int y, LColor_color col)
83 {
84         if (!isDrawingEnabled())
85                 return;
86
87         setQPainterPen(col);
88         drawPoint(x, y);
89 }
90
91
92 void QLPainter::line(int x1, int y1, int x2, int y2,
93         LColor_color col,
94         line_style ls,
95         line_width lw)
96 {
97         if (!isDrawingEnabled())
98                 return;
99
100         setQPainterPen(col, ls, lw);
101         setRenderHint(Antialiasing, x1 != x2 && y1 != y2);
102         drawLine(x1, y1, x2, y2);
103         setRenderHint(Antialiasing, false);
104 }
105
106
107 void QLPainter::lines(int const * xp, int const * yp, int np,
108         LColor_color col,
109         line_style ls,
110         line_width lw)
111 {
112         // FIXME ?
113
114         // Must use new as np is not known at compile time.
115         boost::scoped_array<QPoint> points(new QPoint[np]);
116
117         bool antialias = false;
118         for (int i = 0; i < np; ++i) {
119                 points[i].setX(xp[i]);
120                 points[i].setY(yp[i]);
121                 if (i != 0) 
122                         antialias |= xp[i-1] != xp[i] && yp[i-1] != yp[i];
123         }
124
125         if (!isDrawingEnabled())
126                 return;
127
128         setQPainterPen(col, ls, lw);
129         setRenderHint(Antialiasing, antialias);
130         drawPolyline(points.get(), np);
131         setRenderHint(Antialiasing, false);
132 }
133
134
135 void QLPainter::rectangle(int x, int y, int w, int h,
136         LColor_color col,
137         line_style ls,
138         line_width lw)
139 {
140         if (!isDrawingEnabled())
141                 return;
142
143         setQPainterPen(col, ls, lw);
144         drawRect(x, y, w, h);
145 }
146
147
148 void QLPainter::fillRectangle(int x, int y, int w, int h, LColor_color col)
149 {
150         fillRect(x, y, w, h, guiApp->colorCache().get(col));
151 }
152
153
154 void QLPainter::arc(int x, int y, unsigned int w, unsigned int h,
155         int a1, int a2, LColor_color col)
156 {
157         if (!isDrawingEnabled())
158                 return;
159
160         // LyX usings 1/64ths degree, Qt usings 1/16th
161         setQPainterPen(col);
162         setRenderHint(Antialiasing, true);
163         drawArc(x, y, w, h, a1 / 4, a2 / 4);
164         setRenderHint(Antialiasing, false);
165 }
166
167
168 void QLPainter::image(int x, int y, int w, int h, graphics::Image const & i)
169 {
170         graphics::QLImage const & qlimage =
171                 static_cast<graphics::QLImage const &>(i);
172
173         fillRectangle(x, y, w, h, LColor::graphicsbg);
174
175         if (!isDrawingEnabled())
176                 return;
177
178         drawImage(x, y, qlimage.qimage(), 0, 0, w, h);
179 }
180
181
182 int QLPainter::text(int x, int y, char_type c, LyXFont const & f)
183 {
184         docstring s(1, c);
185         return text(x, y, s, f);
186 }
187
188
189 int QLPainter::smallCapsText(int x, int y,
190         QString const & s, LyXFont const & f)
191 {
192         LyXFont smallfont(f);
193         smallfont.decSize().decSize().setShape(LyXFont::UP_SHAPE);
194
195         QFont const & qfont = guiApp->guiFontLoader().get(f);
196         QFont const & qsmallfont = guiApp->guiFontLoader().get(smallfont);
197
198         setQPainterPen(f.realColor());
199         int textwidth = 0;
200         size_t const ls = s.length();
201         for (unsigned int i = 0; i < ls; ++i) {
202                 QChar const c = s[i].toUpper();
203                 if (c != s.at(i)) {
204                         setFont(qsmallfont);
205                 } else {
206                         setFont(qfont);
207                 }
208                 if (isDrawingEnabled())
209                         drawText(x + textwidth, y, c);
210                 textwidth += fontMetrics().width(c);
211         }
212         return textwidth;
213 }
214
215
216 int QLPainter::text(int x, int y, docstring const & s,
217                 LyXFont const & f)
218 {
219         /* Caution: The following ucs4 to QString conversions work for symbol fonts
220         only because they are no real conversions but simple casts in reality.
221         When we want to draw a symbol or calculate the metrics we pass the position
222         of the symbol in the font (as given in lib/symbols) as a char_type to the
223         frontend. This is just wrong, because the symbol is no UCS4 character at
224         all. You can think of this number as the code point of the symbol in a
225         custom symbol encoding. It works because this char_type is lateron again
226         interpreted as a position in the font again.
227         The correct solution would be to have extra functions for symbols, but that
228         would require to duplicate a lot of frontend and mathed support code.
229         */
230         QString str = toqstr(s);
231
232 #if 0
233         // HACK: QT3 refuses to show single compose characters
234         //       Still needed with Qt4?
235         if (ls == 1 && str[0].unicode() >= 0x05b0 && str[0].unicode() <= 0x05c2)
236                 str = ' ' + str;
237 #endif
238
239         QLFontInfo & fi = guiApp->guiFontLoader().fontinfo(f);
240
241         int textwidth;
242
243         if (f.realShape() != LyXFont::SMALLCAPS_SHAPE) {
244                 setQPainterPen(f.realColor());
245                 if (font() != fi.font)
246                         setFont(fi.font);
247                 // We need to draw the text as LTR as we use our own bidi code.
248                 setLayoutDirection(Qt::LeftToRight);
249                 if (isDrawingEnabled()) {
250                         LYXERR(Debug::PAINTING) << "draw " << std::string(str.toUtf8())
251                                 << " at " << x << "," << y << std::endl;
252                         // Qt4 does not display a glyph whose codepoint is the
253                         // same as that of a soft-hyphen (0x00ad), unless it
254                         // occurs at a line-break. As a kludge, we force Qt to
255                         // render this glyph using a one-column line.
256                         if (s.size() == 1 && str[0].unicode() == 0x00ad) {
257                                 QTextLayout adsymbol(str);
258                                 adsymbol.setFont(fi.font);
259                                 adsymbol.beginLayout();
260                                 QTextLine line = adsymbol.createLine();
261                                 line.setNumColumns(1);
262                                 line.setPosition(QPointF(0, -line.ascent()));
263                                 adsymbol.endLayout();
264                                 line.draw(this, QPointF(x, y));
265                         } else
266                                 drawText(x, y, str);
267                 }
268                 // Here we use the font width cache instead of
269                 //   textwidth = fontMetrics().width(str);
270                 // because the above is awfully expensive on MacOSX
271                 textwidth = fi.metrics->width(str);
272         } else {
273                 textwidth = smallCapsText(x, y, str, f);
274         }
275
276         if (f.underbar() == LyXFont::ON) {
277                 underline(f, x, y, textwidth);
278         }
279
280         return textwidth;
281 }
282
283
284 } // namespace frontend
285 } // namespace lyx
286