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