3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
7 * \author Abdelrazak Younes
9 * Full author contact details are available in file CREDITS.
14 #include <QTextLayout>
16 #include "QLPainter.h"
18 #include "GuiApplication.h"
19 #include "GuiFontMetrics.h"
22 #include "GuiApplication.h"
23 #include "qt_helpers.h"
29 #include "support/unicode.h"
37 QLPainter::QLPainter(QPaintDevice * device)
38 : QPainter(device), Painter()
40 // new QPainter has default QPen:
41 current_color_ = Color::black;
42 current_ls_ = line_solid;
43 current_lw_ = line_thin;
47 QLPainter::~QLPainter()
50 //lyxerr << "QLPainter::end()" << endl;
54 void QLPainter::setQPainterPen(Color_color col,
55 Painter::line_style ls, Painter::line_width lw)
57 if (col == current_color_ && ls == current_ls_ && lw == current_lw_)
64 QPen pen = QPainter::pen();
66 pen.setColor(guiApp->colorCache().get(col));
69 case line_solid: pen.setStyle(Qt::SolidLine); break;
70 case line_onoffdash: pen.setStyle(Qt::DotLine); break;
74 case line_thin: pen.setWidth(0); break;
75 case line_thick: pen.setWidth(3); break;
82 void QLPainter::point(int x, int y, Color_color col)
84 if (!isDrawingEnabled())
92 void QLPainter::line(int x1, int y1, int x2, int y2,
97 if (!isDrawingEnabled())
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);
109 void QLPainter::lines(int const * xp, int const * yp, int np,
114 if (!isDrawingEnabled())
117 // double the size if needed
118 static QVector<QPoint> points(32);
119 if (np > points.size())
120 points.resize(2 * np);
122 bool antialias = false;
123 for (int i = 0; i < np; ++i) {
124 points[i].setX(xp[i]);
125 points[i].setY(yp[i]);
127 antialias |= xp[i-1] != xp[i] && yp[i-1] != yp[i];
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);
137 void QLPainter::rectangle(int x, int y, int w, int h,
142 if (!isDrawingEnabled())
145 setQPainterPen(col, ls, lw);
146 drawRect(x, y, w, h);
150 void QLPainter::fillRectangle(int x, int y, int w, int h, Color_color col)
152 fillRect(x, y, w, h, guiApp->colorCache().get(col));
156 void QLPainter::arc(int x, int y, unsigned int w, unsigned int h,
157 int a1, int a2, Color_color col)
159 if (!isDrawingEnabled())
162 // LyX usings 1/64ths degree, Qt usings 1/16th
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);
171 void QLPainter::image(int x, int y, int w, int h, graphics::Image const & i)
173 graphics::QLImage const & qlimage =
174 static_cast<graphics::QLImage const &>(i);
176 fillRectangle(x, y, w, h, Color::graphicsbg);
178 if (!isDrawingEnabled())
181 drawImage(x, y, qlimage.qimage(), 0, 0, w, h);
185 int QLPainter::text(int x, int y, char_type c, Font const & f)
188 return text(x, y, s, f);
192 int QLPainter::smallCapsText(int x, int y,
193 QString const & s, Font const & f)
196 smallfont.decSize().decSize().setShape(Font::UP_SHAPE);
198 QFont const & qfont = guiApp->guiFontLoader().get(f);
199 QFont const & qsmallfont = guiApp->guiFontLoader().get(smallfont);
201 setQPainterPen(f.realColor());
203 size_t const ls = s.length();
204 for (unsigned int i = 0; i < ls; ++i) {
205 QChar const c = s[i].toUpper();
211 if (isDrawingEnabled())
212 drawText(x + textwidth, y, c);
213 textwidth += fontMetrics().width(c);
219 int QLPainter::text(int x, int y, docstring const & s,
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.
233 QString str = toqstr(s);
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)
242 QLFontInfo & fi = guiApp->guiFontLoader().fontinfo(f);
246 if (f.realShape() != Font::SMALLCAPS_SHAPE) {
247 setQPainterPen(f.realColor());
248 if (font() != 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));
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);
276 textwidth = smallCapsText(x, y, str, f);
279 if (f.underbar() == Font::ON) {
280 underline(f, x, y, textwidth);
287 } // namespace frontend