]> git.lyx.org Git - features.git/blob - src/frontends/qt4/QLPainter.cpp
Whitespace cleanup
[features.git] / src / frontends / qt4 / QLPainter.cpp
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 "Color.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_ = Color::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(Color_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, Color_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         Color_color col,
94         line_style ls,
95         line_width lw)
96 {
97         if (!isDrawingEnabled())
98                 return;
99
100         setQPainterPen(col, ls, lw);
101         bool const do_antialiasing = renderHints() & TextAntialiasing
102                 && x1 != x2 && y1 != y2;
103         setRenderHint(Antialiasing, do_antialiasing);
104         drawLine(x1, y1, x2, y2);
105         setRenderHint(Antialiasing, false);
106 }
107
108
109 void QLPainter::lines(int const * xp, int const * yp, int np,
110         Color_color col,
111         line_style ls,
112         line_width lw)
113 {
114         if (!isDrawingEnabled())
115                 return;
116
117         // double the size if needed
118         static QVector<QPoint> points(32);
119         if (np > points.size())
120                 points.resize(2 * np);
121
122         bool antialias = false;
123         for (int i = 0; i < np; ++i) {
124                 points[i].setX(xp[i]);
125                 points[i].setY(yp[i]);
126                 if (i != 0)
127                         antialias |= xp[i-1] != xp[i] && yp[i-1] != yp[i];
128         }
129         setQPainterPen(col, ls, lw);
130         bool const text_is_antialiased = renderHints() & TextAntialiasing;
131         setRenderHint(Antialiasing, antialias && text_is_antialiased);
132         drawPolyline(points.data(), np);
133         setRenderHint(Antialiasing, false);
134 }
135
136
137 void QLPainter::rectangle(int x, int y, int w, int h,
138         Color_color col,
139         line_style ls,
140         line_width lw)
141 {
142         if (!isDrawingEnabled())
143                 return;
144
145         setQPainterPen(col, ls, lw);
146         drawRect(x, y, w, h);
147 }
148
149
150 void QLPainter::fillRectangle(int x, int y, int w, int h, Color_color col)
151 {
152         fillRect(x, y, w, h, guiApp->colorCache().get(col));
153 }
154
155
156 void QLPainter::arc(int x, int y, unsigned int w, unsigned int h,
157         int a1, int a2, Color_color col)
158 {
159         if (!isDrawingEnabled())
160                 return;
161
162         // LyX usings 1/64ths degree, Qt usings 1/16th
163         setQPainterPen(col);
164         bool const do_antialiasing = renderHints() & TextAntialiasing;
165         setRenderHint(Antialiasing, do_antialiasing);
166         drawArc(x, y, w, h, a1 / 4, a2 / 4);
167         setRenderHint(Antialiasing, false);
168 }
169
170
171 void QLPainter::image(int x, int y, int w, int h, graphics::Image const & i)
172 {
173         graphics::QLImage const & qlimage =
174                 static_cast<graphics::QLImage const &>(i);
175
176         fillRectangle(x, y, w, h, Color::graphicsbg);
177
178         if (!isDrawingEnabled())
179                 return;
180
181         drawImage(x, y, qlimage.qimage(), 0, 0, w, h);
182 }
183
184
185 int QLPainter::text(int x, int y, char_type c, Font const & f)
186 {
187         docstring s(1, c);
188         return text(x, y, s, f);
189 }
190
191
192 int QLPainter::smallCapsText(int x, int y,
193         QString const & s, Font const & f)
194 {
195         Font smallfont(f);
196         smallfont.decSize().decSize().setShape(Font::UP_SHAPE);
197
198         QFont const & qfont = guiApp->guiFontLoader().get(f);
199         QFont const & qsmallfont = guiApp->guiFontLoader().get(smallfont);
200
201         setQPainterPen(f.realColor());
202         int textwidth = 0;
203         size_t const ls = s.length();
204         for (unsigned int i = 0; i < ls; ++i) {
205                 QChar const c = s[i].toUpper();
206                 if (c != s.at(i)) {
207                         setFont(qsmallfont);
208                 } else {
209                         setFont(qfont);
210                 }
211                 if (isDrawingEnabled())
212                         drawText(x + textwidth, y, c);
213                 textwidth += fontMetrics().width(c);
214         }
215         return textwidth;
216 }
217
218
219 int QLPainter::text(int x, int y, docstring const & s,
220                 Font const & f)
221 {
222         /* Caution: The following ucs4 to QString conversions work for symbol fonts
223         only because they are no real conversions but simple casts in reality.
224         When we want to draw a symbol or calculate the metrics we pass the position
225         of the symbol in the font (as given in lib/symbols) as a char_type to the
226         frontend. This is just wrong, because the symbol is no UCS4 character at
227         all. You can think of this number as the code point of the symbol in a
228         custom symbol encoding. It works because this char_type is lateron again
229         interpreted as a position in the font again.
230         The correct solution would be to have extra functions for symbols, but that
231         would require to duplicate a lot of frontend and mathed support code.
232         */
233         QString str = toqstr(s);
234
235 #if 0
236         // HACK: QT3 refuses to show single compose characters
237         //       Still needed with Qt4?
238         if (ls == 1 && str[0].unicode() >= 0x05b0 && str[0].unicode() <= 0x05c2)
239                 str = ' ' + str;
240 #endif
241
242         QLFontInfo & fi = guiApp->guiFontLoader().fontinfo(f);
243
244         int textwidth;
245
246         if (f.realShape() != Font::SMALLCAPS_SHAPE) {
247                 setQPainterPen(f.realColor());
248                 if (font() != fi.font)
249                         setFont(fi.font);
250                 // We need to draw the text as LTR as we use our own bidi code.
251                 setLayoutDirection(Qt::LeftToRight);
252                 if (isDrawingEnabled()) {
253                         LYXERR(Debug::PAINTING) << "draw " << std::string(str.toUtf8())
254                                 << " at " << x << "," << y << std::endl;
255                         // Qt4 does not display a glyph whose codepoint is the
256                         // same as that of a soft-hyphen (0x00ad), unless it
257                         // occurs at a line-break. As a kludge, we force Qt to
258                         // render this glyph using a one-column line.
259                         if (s.size() == 1 && str[0].unicode() == 0x00ad) {
260                                 QTextLayout adsymbol(str);
261                                 adsymbol.setFont(fi.font);
262                                 adsymbol.beginLayout();
263                                 QTextLine line = adsymbol.createLine();
264                                 line.setNumColumns(1);
265                                 line.setPosition(QPointF(0, -line.ascent()));
266                                 adsymbol.endLayout();
267                                 line.draw(this, QPointF(x, y));
268                         } else
269                                 drawText(x, y, str);
270                 }
271                 // Here we use the font width cache instead of
272                 //   textwidth = fontMetrics().width(str);
273                 // because the above is awfully expensive on MacOSX
274                 textwidth = fi.metrics->width(str);
275         } else {
276                 textwidth = smallCapsText(x, y, str, f);
277         }
278
279         if (f.underbar() == Font::ON) {
280                 underline(f, x, y, textwidth);
281         }
282
283         return textwidth;
284 }
285
286
287 } // namespace frontend
288 } // namespace lyx