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