Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqc2qdrawutil.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include <private/qhexstring_p.h>
8#include <private/qpaintengineex_p.h>
9
10#include <QtGui/qbitmap.h>
11#include <QtGui/qpixmapcache.h>
12#include <QtGui/qpainter.h>
13#include <QtGui/qpalette.h>
14
15#include <QtCore/qmath.h>
16#include <QtCore/qvarlengtharray.h>
17
18QT_BEGIN_NAMESPACE
19
20namespace QQC2 {
21
22namespace {
23class PainterStateGuard {
24 Q_DISABLE_COPY_MOVE(PainterStateGuard)
25public:
26 explicit PainterStateGuard(QPainter *p) : m_painter(p) {}
27 ~PainterStateGuard()
28 {
29 for ( ; m_level > 0; --m_level)
30 m_painter->restore();
31 }
32
33 void save()
34 {
35 m_painter->save();
36 ++m_level;
37 }
38
39 void restore()
40 {
41 m_painter->restore();
42 --m_level;
43 }
44
45private:
46 QPainter *m_painter;
47 int m_level= 0;
48};
49} // namespace
50
51/*!
52 \internal
53 \headerfile <qqc2qdrawutil_p.h>
54 \title Drawing Utility Functions
55
56 \sa QPainter
57*/
58
59/*!
60 \internal
61 \fn void qDrawShadeLine(QPainter *painter, int x1, int y1, int x2, int y2,
62 const QPalette &palette, bool sunken,
63 int lineWidth, int midLineWidth)
64 \relates <qqc2qdrawutil_p.h>
65
66 Draws a horizontal (\a y1 == \a y2) or vertical (\a x1 == \a x2)
67 shaded line using the given \a painter. Note that nothing is
68 drawn if \a y1 != \a y2 and \a x1 != \a x2 (i.e. the line is
69 neither horizontal nor vertical).
70
71 The provided \a palette specifies the shading colors (\l
72 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
73 {QPalette::mid()}{middle} colors). The given \a lineWidth
74 specifies the line width for each of the lines; it is not the
75 total line width. The given \a midLineWidth specifies the width of
76 a middle line drawn in the QPalette::mid() color.
77
78 The line appears sunken if \a sunken is true, otherwise raised.
79
80 \warning This function does not look at QWidget::style() or
81 QApplication::style(). Use the drawing functions in QStyle to
82 make widgets that follow the current GUI style.
83
84
85 Alternatively you can use a QFrame widget and apply the
86 QFrame::setFrameStyle() function to display a shaded line.
87
88 \sa qDrawShadeRect(), qDrawShadePanel(), QStyle
89*/
90
91void qDrawShadeLine(QPainter *p, int x1, int y1, int x2, int y2,
92 const QPalette &pal, bool sunken,
93 int lineWidth, int midLineWidth)
94{
95 if (Q_UNLIKELY(!p || lineWidth < 0 || midLineWidth < 0)) {
96 qWarning("qDrawShadeLine: Invalid parameters");
97 return;
98 }
99 PainterStateGuard painterGuard(p);
100 const qreal devicePixelRatio = p->device()->devicePixelRatio();
101 if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
102 painterGuard.save();
103 const qreal inverseScale = qreal(1) / devicePixelRatio;
104 p->scale(inverseScale, inverseScale);
105 x1 = qRound(devicePixelRatio * x1);
106 y1 = qRound(devicePixelRatio * y1);
107 x2 = qRound(devicePixelRatio * x2);
108 y2 = qRound(devicePixelRatio * y2);
109 lineWidth = qRound(devicePixelRatio * lineWidth);
110 midLineWidth = qRound(devicePixelRatio * midLineWidth);
111 p->translate(0.5, 0.5);
112 }
113 int tlw = lineWidth*2 + midLineWidth; // total line width
114 QPen oldPen = p->pen(); // save pen
115 if (sunken)
116 p->setPen(pal.color(QPalette::Dark));
117 else
118 p->setPen(pal.light().color());
119 QPolygon a;
120 int i;
121 if (y1 == y2) { // horizontal line
122 int y = y1 - tlw/2;
123 if (x1 > x2) { // swap x1 and x2
124 int t = x1;
125 x1 = x2;
126 x2 = t;
127 }
128 x2--;
129 for (i=0; i<lineWidth; i++) { // draw top shadow
130 a.setPoints(3, x1+i, y+tlw-1-i,
131 x1+i, y+i,
132 x2-i, y+i);
133 p->drawPolyline(a);
134 }
135 if (midLineWidth > 0) {
136 p->setPen(pal.mid().color());
137 for (i=0; i<midLineWidth; i++) // draw lines in the middle
138 p->drawLine(x1+lineWidth, y+lineWidth+i,
139 x2-lineWidth, y+lineWidth+i);
140 }
141 if (sunken)
142 p->setPen(pal.light().color());
143 else
144 p->setPen(pal.dark().color());
145 for (i=0; i<lineWidth; i++) { // draw bottom shadow
146 a.setPoints(3, x1+i, y+tlw-i-1,
147 x2-i, y+tlw-i-1,
148 x2-i, y+i+1);
149 p->drawPolyline(a);
150 }
151 }
152 else if (x1 == x2) { // vertical line
153 int x = x1 - tlw/2;
154 if (y1 > y2) { // swap y1 and y2
155 int t = y1;
156 y1 = y2;
157 y2 = t;
158 }
159 y2--;
160 for (i=0; i<lineWidth; i++) { // draw left shadow
161 a.setPoints(3, x+i, y2,
162 x+i, y1+i,
163 x+tlw-1, y1+i);
164 p->drawPolyline(a);
165 }
166 if (midLineWidth > 0) {
167 p->setPen(pal.mid().color());
168 for (i=0; i<midLineWidth; i++) // draw lines in the middle
169 p->drawLine(x+lineWidth+i, y1+lineWidth, x+lineWidth+i, y2);
170 }
171 if (sunken)
172 p->setPen(pal.light().color());
173 else
174 p->setPen(pal.dark().color());
175 for (i=0; i<lineWidth; i++) { // draw right shadow
176 a.setPoints(3, x+lineWidth, y2-i,
177 x+tlw-i-1, y2-i,
178 x+tlw-i-1, y1+lineWidth);
179 p->drawPolyline(a);
180 }
181 }
182 p->setPen(oldPen);
183}
184
185/*!
186 \internal
187 \fn void qDrawShadeRect(QPainter *painter, int x, int y, int width, int height,
188 const QPalette &palette, bool sunken,
189 int lineWidth, int midLineWidth,
190 const QBrush *fill)
191 \relates <qqc2qdrawutil_p.h>
192
193 Draws the shaded rectangle beginning at (\a x, \a y) with the
194 given \a width and \a height using the provided \a painter.
195
196 The provide \a palette specifies the shading colors (\l
197 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
198 {QPalette::mid()}{middle} colors. The given \a lineWidth
199 specifies the line width for each of the lines; it is not the
200 total line width. The \a midLineWidth specifies the width of a
201 middle line drawn in the QPalette::mid() color. The rectangle's
202 interior is filled with the \a fill brush unless \a fill is 0.
203
204 The rectangle appears sunken if \a sunken is true, otherwise
205 raised.
206
207 \warning This function does not look at QWidget::style() or
208 QApplication::style(). Use the drawing functions in QStyle to make
209 widgets that follow the current GUI style.
210
211 Alternatively you can use a QFrame widget and apply the
212 QFrame::setFrameStyle() function to display a shaded rectangle.
213
214 \sa qDrawShadeLine(), qDrawShadePanel(), qDrawPlainRect(), QStyle
215*/
216
217void qDrawShadeRect(QPainter *p, int x, int y, int w, int h,
218 const QPalette &pal, bool sunken,
219 int lineWidth, int midLineWidth,
220 const QBrush *fill)
221{
222 if (w == 0 || h == 0)
223 return;
224 if (Q_UNLIKELY(w < 0 || h < 0 || lineWidth < 0 || midLineWidth < 0)) {
225 qWarning("qDrawShadeRect: Invalid parameters");
226 return;
227 }
228
229 PainterStateGuard painterGuard(p);
230 const qreal devicePixelRatio = p->device()->devicePixelRatioF();
231 if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
232 painterGuard.save();
233 const qreal inverseScale = qreal(1) / devicePixelRatio;
234 p->scale(inverseScale, inverseScale);
235 x = qRound(devicePixelRatio * x);
236 y = qRound(devicePixelRatio * y);
237 w = qRound(devicePixelRatio * w);
238 h = qRound(devicePixelRatio * h);
239 lineWidth = qRound(devicePixelRatio * lineWidth);
240 midLineWidth = qRound(devicePixelRatio * midLineWidth);
241 p->translate(0.5, 0.5);
242 }
243
244 QPen oldPen = p->pen();
245 if (sunken)
246 p->setPen(pal.dark().color());
247 else
248 p->setPen(pal.light().color());
249 int x1=x, y1=y, x2=x+w-1, y2=y+h-1;
250
251 if (lineWidth == 1 && midLineWidth == 0) {// standard shade rectangle
252 p->drawRect(x1, y1, w-2, h-2);
253 if (sunken)
254 p->setPen(pal.light().color());
255 else
256 p->setPen(pal.dark().color());
257 QLineF lines[4] = { QLineF(x1+1, y1+1, x2-2, y1+1),
258 QLineF(x1+1, y1+2, x1+1, y2-2),
259 QLineF(x1, y2, x2, y2),
260 QLineF(x2,y1, x2,y2-1) };
261 p->drawLines(lines, 4); // draw bottom/right lines
262 } else { // more complicated
263 int m = lineWidth+midLineWidth;
264 int i, j=0, k=m;
265 for (i=0; i<lineWidth; i++) { // draw top shadow
266 QLineF lines[4] = { QLineF(x1+i, y2-i, x1+i, y1+i),
267 QLineF(x1+i, y1+i, x2-i, y1+i),
268 QLineF(x1+k, y2-k, x2-k, y2-k),
269 QLineF(x2-k, y2-k, x2-k, y1+k) };
270 p->drawLines(lines, 4);
271 k++;
272 }
273 p->setPen(pal.mid().color());
274 j = lineWidth*2;
275 for (i=0; i<midLineWidth; i++) { // draw lines in the middle
276 p->drawRect(x1+lineWidth+i, y1+lineWidth+i, w-j-1, h-j-1);
277 j += 2;
278 }
279 if (sunken)
280 p->setPen(pal.light().color());
281 else
282 p->setPen(pal.dark().color());
283 k = m;
284 for (i=0; i<lineWidth; i++) { // draw bottom shadow
285 QLineF lines[4] = { QLineF(x1+1+i, y2-i, x2-i, y2-i),
286 QLineF(x2-i, y2-i, x2-i, y1+i+1),
287 QLineF(x1+k, y2-k, x1+k, y1+k),
288 QLineF(x1+k, y1+k, x2-k, y1+k) };
289 p->drawLines(lines, 4);
290 k++;
291 }
292 }
293 if (fill) {
294 QBrush oldBrush = p->brush();
295 int tlw = lineWidth + midLineWidth;
296 p->setPen(Qt::NoPen);
297 p->setBrush(*fill);
298 p->drawRect(x+tlw, y+tlw, w-2*tlw, h-2*tlw);
299 p->setBrush(oldBrush);
300 }
301 p->setPen(oldPen); // restore pen
302}
303
304
305/*!
306 \internal
307 \fn void qDrawShadePanel(QPainter *painter, int x, int y, int width, int height,
308 const QPalette &palette, bool sunken,
309 int lineWidth, const QBrush *fill)
310 \relates <qqc2qdrawutil_p.h>
311
312 Draws the shaded panel beginning at (\a x, \a y) with the given \a
313 width and \a height using the provided \a painter and the given \a
314 lineWidth.
315
316 The given \a palette specifies the shading colors (\l
317 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
318 {QPalette::mid()}{middle} colors). The panel's interior is filled
319 with the \a fill brush unless \a fill is 0.
320
321 The panel appears sunken if \a sunken is true, otherwise raised.
322
323 \warning This function does not look at QWidget::style() or
324 QApplication::style(). Use the drawing functions in QStyle to make
325 widgets that follow the current GUI style.
326
327 Alternatively you can use a QFrame widget and apply the
328 QFrame::setFrameStyle() function to display a shaded panel.
329
330 \sa qDrawWinPanel(), qDrawShadeLine(), qDrawShadeRect(), QStyle
331*/
332
333void qDrawShadePanel(QPainter *p, int x, int y, int w, int h,
334 const QPalette &pal, bool sunken,
335 int lineWidth, const QBrush *fill)
336{
337 if (w == 0 || h == 0)
338 return;
339 if (Q_UNLIKELY(w < 0 || h < 0 || lineWidth < 0)) {
340 qWarning("qDrawShadePanel: Invalid parameters");
341 }
342
343 PainterStateGuard painterGuard(p);
344 const qreal devicePixelRatio = p->device()->devicePixelRatioF();
345 bool isTranslated = false;
346 if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
347 painterGuard.save();
348 const qreal inverseScale = qreal(1) / devicePixelRatio;
349 p->scale(inverseScale, inverseScale);
350 x = qRound(devicePixelRatio * x);
351 y = qRound(devicePixelRatio * y);
352 w = qRound(devicePixelRatio * w);
353 h = qRound(devicePixelRatio * h);
354 lineWidth = qRound(devicePixelRatio * lineWidth);
355 p->translate(0.5, 0.5);
356 isTranslated = true;
357 }
358
359 QColor shade = pal.dark().color();
360 QColor light = pal.light().color();
361 if (fill) {
362 if (fill->color() == shade)
363 shade = pal.shadow().color();
364 if (fill->color() == light)
365 light = pal.midlight().color();
366 }
367 QPen oldPen = p->pen(); // save pen
368 QList<QLineF> lines;
369 lines.reserve(2*lineWidth);
370
371 if (sunken)
372 p->setPen(shade);
373 else
374 p->setPen(light);
375 int x1, y1, x2, y2;
376 int i;
377 x1 = x;
378 y1 = y2 = y;
379 x2 = x+w-2;
380 for (i=0; i<lineWidth; i++) { // top shadow
381 lines << QLineF(x1, y1++, x2--, y2++);
382 }
383 x2 = x1;
384 y1 = y+h-2;
385 for (i=0; i<lineWidth; i++) { // left shado
386 lines << QLineF(x1++, y1, x2++, y2--);
387 }
388 p->drawLines(lines);
389 lines.clear();
390 if (sunken)
391 p->setPen(light);
392 else
393 p->setPen(shade);
394 x1 = x;
395 y1 = y2 = y+h-1;
396 x2 = x+w-1;
397 for (i=0; i<lineWidth; i++) { // bottom shadow
398 lines << QLineF(x1++, y1--, x2, y2--);
399 }
400 x1 = x2;
401 y1 = y;
402 y2 = y+h-lineWidth-1;
403 for (i=0; i<lineWidth; i++) { // right shadow
404 lines << QLineF(x1--, y1++, x2--, y2);
405 }
406 p->drawLines(lines);
407 if (fill) { // fill with fill color
408 if (isTranslated)
409 p->translate(-0.5, -0.5);
410 p->fillRect(x+lineWidth, y+lineWidth, w-lineWidth*2, h-lineWidth*2, *fill);
411 }
412 p->setPen(oldPen); // restore pen
413}
414
415
416/*!
417 \internal
418 This function draws a rectangle with two pixel line width.
419 It is called from qDrawWinButton() and qDrawWinPanel().
420
421 c1..c4 and fill are used:
422
423 1 1 1 1 1 2
424 1 3 3 3 4 2
425 1 3 F F 4 2
426 1 3 F F 4 2
427 1 4 4 4 4 2
428 2 2 2 2 2 2
429*/
430
432 int x, int y, int w, int h,
433 const QColor &c1, const QColor &c2,
434 const QColor &c3, const QColor &c4,
435 const QBrush *fill)
436{
437 if (w < 2 || h < 2) // can't do anything with that
438 return;
439
440 PainterStateGuard painterGuard(p);
441 const qreal devicePixelRatio = p->device()->devicePixelRatioF();
442 bool isTranslated = false;
443 if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
444 painterGuard.save();
445 const qreal inverseScale = qreal(1) / devicePixelRatio;
446 p->scale(inverseScale, inverseScale);
447 x = qRound(devicePixelRatio * x);
448 y = qRound(devicePixelRatio * y);
449 w = qRound(devicePixelRatio * w);
450 h = qRound(devicePixelRatio * h);
451 p->translate(0.5, 0.5);
452 isTranslated = true;
453 }
454
455 QPen oldPen = p->pen();
456 QPoint a[3] = { QPoint(x, y+h-2), QPoint(x, y), QPoint(x+w-2, y) };
457 p->setPen(c1);
458 p->drawPolyline(a, 3);
459 QPoint b[3] = { QPoint(x, y+h-1), QPoint(x+w-1, y+h-1), QPoint(x+w-1, y) };
460 p->setPen(c2);
461 p->drawPolyline(b, 3);
462 if (w > 4 && h > 4) {
463 QPoint c[3] = { QPoint(x+1, y+h-3), QPoint(x+1, y+1), QPoint(x+w-3, y+1) };
464 p->setPen(c3);
465 p->drawPolyline(c, 3);
466 QPoint d[3] = { QPoint(x+1, y+h-2), QPoint(x+w-2, y+h-2), QPoint(x+w-2, y+1) };
467 p->setPen(c4);
468 p->drawPolyline(d, 3);
469 if (fill) {
470 if (isTranslated)
471 p->translate(-0.5, -0.5);
472 p->fillRect(QRect(x+2, y+2, w-4, h-4), *fill);
473 }
474 }
475 p->setPen(oldPen);
476}
477
478
479/*!
480 \internal
481 \fn void qDrawWinButton(QPainter *painter, int x, int y, int width, int height,
482 const QPalette &palette, bool sunken,
483 const QBrush *fill)
484 \relates <qqc2qdrawutil_p.h>
485
486 Draws the Windows-style button specified by the given point (\a x,
487 \a y}, \a width and \a height using the provided \a painter with a
488 line width of 2 pixels. The button's interior is filled with the
489 \a{fill} brush unless \a fill is 0.
490
491 The given \a palette specifies the shading colors (\l
492 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
493 {QPalette::mid()}{middle} colors).
494
495 The button appears sunken if \a sunken is true, otherwise raised.
496
497 \warning This function does not look at QWidget::style() or
498 QApplication::style()-> Use the drawing functions in QStyle to make
499 widgets that follow the current GUI style.
500
501 \sa qDrawWinPanel(), QStyle
502*/
503
504void qDrawWinButton(QPainter *p, int x, int y, int w, int h,
505 const QPalette &pal, bool sunken,
506 const QBrush *fill)
507{
508 if (sunken)
509 qDrawWinShades(p, x, y, w, h,
510 pal.shadow().color(), pal.light().color(), pal.dark().color(),
511 pal.button().color(), fill);
512 else
513 qDrawWinShades(p, x, y, w, h,
514 pal.light().color(), pal.shadow().color(), pal.button().color(),
515 pal.dark().color(), fill);
516}
517
518/*!
519 \internal
520 \fn void qDrawWinPanel(QPainter *painter, int x, int y, int width, int height,
521 const QPalette &palette, bool sunken,
522 const QBrush *fill)
523 \relates <qqc2qdrawutil_p.h>
524
525 Draws the Windows-style panel specified by the given point(\a x,
526 \a y), \a width and \a height using the provided \a painter with a
527 line width of 2 pixels. The button's interior is filled with the
528 \a fill brush unless \a fill is 0.
529
530 The given \a palette specifies the shading colors. The panel
531 appears sunken if \a sunken is true, otherwise raised.
532
533 \warning This function does not look at QWidget::style() or
534 QApplication::style(). Use the drawing functions in QStyle to make
535 widgets that follow the current GUI style.
536
537 Alternatively you can use a QFrame widget and apply the
538 QFrame::setFrameStyle() function to display a shaded panel.
539
540 \sa qDrawShadePanel(), qDrawWinButton(), QStyle
541*/
542
543void qDrawWinPanel(QPainter *p, int x, int y, int w, int h,
544 const QPalette &pal, bool sunken,
545 const QBrush *fill)
546{
547 if (sunken)
548 qDrawWinShades(p, x, y, w, h,
549 pal.dark().color(), pal.light().color(), pal.shadow().color(),
550 pal.midlight().color(), fill);
551 else
552 qDrawWinShades(p, x, y, w, h,
553 pal.light().color(), pal.shadow().color(), pal.midlight().color(),
554 pal.dark().color(), fill);
555}
556
557/*!
558 \internal
559 \fn void qDrawPlainRect(QPainter *painter, int x, int y, int width, int height, const QColor &lineColor,
560 int lineWidth, const QBrush *fill)
561 \relates <qqc2qdrawutil_p.h>
562
563 Draws the plain rectangle beginning at (\a x, \a y) with the given
564 \a width and \a height, using the specified \a painter, \a lineColor
565 and \a lineWidth. The rectangle's interior is filled with the \a
566 fill brush unless \a fill is 0.
567
568 \warning This function does not look at QWidget::style() or
569 QApplication::style(). Use the drawing functions in QStyle to make
570 widgets that follow the current GUI style.
571
572 Alternatively you can use a QFrame widget and apply the
573 QFrame::setFrameStyle() function to display a plain rectangle.
574
575 \sa qDrawShadeRect(), QStyle
576*/
577
578void qDrawPlainRect(QPainter *p, int x, int y, int w, int h, const QColor &c,
579 int lineWidth, const QBrush *fill)
580{
581 if (w == 0 || h == 0)
582 return;
583 if (Q_UNLIKELY(w < 0 || h < 0 || lineWidth < 0)) {
584 qWarning("qDrawPlainRect: Invalid parameters");
585 }
586
587 PainterStateGuard painterGuard(p);
588 const qreal devicePixelRatio = p->device()->devicePixelRatioF();
589 if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
590 painterGuard.save();
591 const qreal inverseScale = qreal(1) / devicePixelRatio;
592 p->scale(inverseScale, inverseScale);
593 x = qRound(devicePixelRatio * x);
594 y = qRound(devicePixelRatio * y);
595 w = qRound(devicePixelRatio * w);
596 h = qRound(devicePixelRatio * h);
597 lineWidth = qRound(devicePixelRatio * lineWidth);
598 p->translate(0.5, 0.5);
599 }
600
601 QPen oldPen = p->pen();
602 QBrush oldBrush = p->brush();
603 p->setPen(c);
604 p->setBrush(Qt::NoBrush);
605 for (int i=0; i<lineWidth; i++)
606 p->drawRect(x+i, y+i, w-i*2 - 1, h-i*2 - 1);
607 if (fill) { // fill with fill color
608 p->setPen(Qt::NoPen);
609 p->setBrush(*fill);
610 p->drawRect(x+lineWidth, y+lineWidth, w-lineWidth*2, h-lineWidth*2);
611 }
612 p->setPen(oldPen);
613 p->setBrush(oldBrush);
614}
615
616/*****************************************************************************
617 Overloaded functions.
618 *****************************************************************************/
619
620/*!
621 \internal
622 \fn void qDrawShadeLine(QPainter *painter, const QPoint &p1, const QPoint &p2,
623 const QPalette &palette, bool sunken, int lineWidth, int midLineWidth)
624 \relates <qqc2qdrawutil_p.h>
625 \overload
626
627 Draws a horizontal or vertical shaded line between \a p1 and \a p2
628 using the given \a painter. Note that nothing is drawn if the line
629 between the points would be neither horizontal nor vertical.
630
631 The provided \a palette specifies the shading colors (\l
632 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
633 {QPalette::mid()}{middle} colors). The given \a lineWidth
634 specifies the line width for each of the lines; it is not the
635 total line width. The given \a midLineWidth specifies the width of
636 a middle line drawn in the QPalette::mid() color.
637
638 The line appears sunken if \a sunken is true, otherwise raised.
639
640 \warning This function does not look at QWidget::style() or
641 QApplication::style(). Use the drawing functions in QStyle to
642 make widgets that follow the current GUI style.
643
644
645 Alternatively you can use a QFrame widget and apply the
646 QFrame::setFrameStyle() function to display a shaded line.
647
648 \sa qDrawShadeRect(), qDrawShadePanel(), QStyle
649*/
650
651void qDrawShadeLine(QPainter *p, const QPoint &p1, const QPoint &p2,
652 const QPalette &pal, bool sunken,
653 int lineWidth, int midLineWidth)
654{
655 qDrawShadeLine(p, p1.x(), p1.y(), p2.x(), p2.y(), pal, sunken,
656 lineWidth, midLineWidth);
657}
658
659/*!
660 \internal
661 \fn void qDrawShadeRect(QPainter *painter, const QRect &rect, const QPalette &palette,
662 bool sunken, int lineWidth, int midLineWidth, const QBrush *fill)
663 \relates <qqc2qdrawutil_p.h>
664 \overload
665
666 Draws the shaded rectangle specified by \a rect using the given \a painter.
667
668 The provide \a palette specifies the shading colors (\l
669 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
670 {QPalette::mid()}{middle} colors. The given \a lineWidth
671 specifies the line width for each of the lines; it is not the
672 total line width. The \a midLineWidth specifies the width of a
673 middle line drawn in the QPalette::mid() color. The rectangle's
674 interior is filled with the \a fill brush unless \a fill is 0.
675
676 The rectangle appears sunken if \a sunken is true, otherwise
677 raised.
678
679 \warning This function does not look at QWidget::style() or
680 QApplication::style(). Use the drawing functions in QStyle to make
681 widgets that follow the current GUI style.
682
683 Alternatively you can use a QFrame widget and apply the
684 QFrame::setFrameStyle() function to display a shaded rectangle.
685
686 \sa qDrawShadeLine(), qDrawShadePanel(), qDrawPlainRect(), QStyle
687*/
688
689void qDrawShadeRect(QPainter *p, const QRect &r,
690 const QPalette &pal, bool sunken,
691 int lineWidth, int midLineWidth,
692 const QBrush *fill)
693{
694 qDrawShadeRect(p, r.x(), r.y(), r.width(), r.height(), pal, sunken,
695 lineWidth, midLineWidth, fill);
696}
697
698/*!
699 \internal
700 \fn void qDrawShadePanel(QPainter *painter, const QRect &rect, const QPalette &palette,
701 bool sunken, int lineWidth, const QBrush *fill)
702 \relates <qqc2qdrawutil_p.h>
703 \overload
704
705 Draws the shaded panel at the rectangle specified by \a rect using the
706 given \a painter and the given \a lineWidth.
707
708 The given \a palette specifies the shading colors (\l
709 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
710 {QPalette::mid()}{middle} colors). The panel's interior is filled
711 with the \a fill brush unless \a fill is 0.
712
713 The panel appears sunken if \a sunken is true, otherwise raised.
714
715 \warning This function does not look at QWidget::style() or
716 QApplication::style(). Use the drawing functions in QStyle to make
717 widgets that follow the current GUI style.
718
719 Alternatively you can use a QFrame widget and apply the
720 QFrame::setFrameStyle() function to display a shaded panel.
721
722 \sa qDrawWinPanel(), qDrawShadeLine(), qDrawShadeRect(), QStyle
723*/
724
725void qDrawShadePanel(QPainter *p, const QRect &r,
726 const QPalette &pal, bool sunken,
727 int lineWidth, const QBrush *fill)
728{
729 qDrawShadePanel(p, r.x(), r.y(), r.width(), r.height(), pal, sunken,
730 lineWidth, fill);
731}
732
733/*!
734 \internal
735 \fn void qDrawWinButton(QPainter *painter, const QRect &rect, const QPalette &palette,
736 bool sunken, const QBrush *fill)
737 \relates <qqc2qdrawutil_p.h>
738 \overload
739
740 Draws the Windows-style button at the rectangle specified by \a rect using
741 the given \a painter with a line width of 2 pixels. The button's interior
742 is filled with the \a{fill} brush unless \a fill is 0.
743
744 The given \a palette specifies the shading colors (\l
745 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
746 {QPalette::mid()}{middle} colors).
747
748 The button appears sunken if \a sunken is true, otherwise raised.
749
750 \warning This function does not look at QWidget::style() or
751 QApplication::style()-> Use the drawing functions in QStyle to make
752 widgets that follow the current GUI style.
753
754 \sa qDrawWinPanel(), QStyle
755*/
756
757void qDrawWinButton(QPainter *p, const QRect &r,
758 const QPalette &pal, bool sunken, const QBrush *fill)
759{
760 qDrawWinButton(p, r.x(), r.y(), r.width(), r.height(), pal, sunken, fill);
761}
762
763/*!
764 \internal
765 \fn void qDrawWinPanel(QPainter *painter, const QRect &rect, const QPalette &palette,
766 bool sunken, const QBrush *fill)
767 \overload
768
769 Draws the Windows-style panel at the rectangle specified by \a rect using
770 the given \a painter with a line width of 2 pixels. The button's interior
771 is filled with the \a fill brush unless \a fill is 0.
772
773 The given \a palette specifies the shading colors. The panel
774 appears sunken if \a sunken is true, otherwise raised.
775
776 \warning This function does not look at QWidget::style() or
777 QApplication::style(). Use the drawing functions in QStyle to make
778 widgets that follow the current GUI style.
779
780 Alternatively you can use a QFrame widget and apply the
781 QFrame::setFrameStyle() function to display a shaded panel.
782
783 \sa qDrawShadePanel(), qDrawWinButton(), QStyle
784*/
785
786void qDrawWinPanel(QPainter *p, const QRect &r,
787 const QPalette &pal, bool sunken, const QBrush *fill)
788{
789 qDrawWinPanel(p, r.x(), r.y(), r.width(), r.height(), pal, sunken, fill);
790}
791
792/*!
793 \internal
794 \fn void qDrawPlainRect(QPainter *painter, const QRect &rect, const QColor &lineColor, int lineWidth, const QBrush *fill)
795 \relates <qqc2qdrawutil_p.h>
796 \overload
797
798 Draws the plain rectangle specified by \a rect using the given \a painter,
799 \a lineColor and \a lineWidth. The rectangle's interior is filled with the
800 \a fill brush unless \a fill is 0.
801
802 \warning This function does not look at QWidget::style() or
803 QApplication::style(). Use the drawing functions in QStyle to make
804 widgets that follow the current GUI style.
805
806 Alternatively you can use a QFrame widget and apply the
807 QFrame::setFrameStyle() function to display a plain rectangle.
808
809 \sa qDrawShadeRect(), QStyle
810*/
811
812void qDrawPlainRect(QPainter *p, const QRect &r, const QColor &c,
813 int lineWidth, const QBrush *fill)
814{
815 qDrawPlainRect(p, r.x(), r.y(), r.width(), r.height(), c,
816 lineWidth, fill);
817}
818
819
820/*!
821 \internal
822 \class QTileRules
823
824 \brief The QTileRules class provides the rules used to draw a
825 pixmap or image split into nine segments.
826
827 Spliiting is similar to \l{http://www.w3.org/TR/css3-background/}{CSS3 border-images}.
828
829 \sa Qt::TileRule, QMargins
830*/
831
832/*!
833 \internal
834
835 \fn QTileRules::QTileRules(Qt::TileRule horizontalRule, Qt::TileRule verticalRule)
836 Constructs a QTileRules with the given \a horizontalRule and
837 \a verticalRule.
838 */
839
840/*!
841 \internal
842
843 \fn QTileRules::QTileRules(Qt::TileRule rule)
844 Constructs a QTileRules with the given \a rule used for both
845 the horizontal rule and the vertical rule.
846 */
847
848/*!
849 \internal
850 \fn void qDrawBorderPixmap(QPainter *painter, const QRect &target, const QMargins &margins, const QPixmap &pixmap)
851
852 \brief The qDrawBorderPixmap function is for drawing a pixmap into
853 the margins of a rectangle.
854
855 Draws the given \a pixmap into the given \a target rectangle, using the
856 given \a painter. The pixmap will be split into nine segments and drawn
857 according to the \a margins structure.
858*/
859
861
862/*!
863 \internal
864
865 Draws the indicated \a sourceRect rectangle from the given \a pixmap into
866 the given \a targetRect rectangle, using the given \a painter. The pixmap
867 will be split into nine segments according to the given \a targetMargins
868 and \a sourceMargins structures. Finally, the pixmap will be drawn
869 according to the given \a rules.
870
871 This function is used to draw a scaled pixmap, similar to
872 \l{http://www.w3.org/TR/css3-background/}{CSS3 border-images}
873
874 \sa Qt::TileRule, QTileRules, QMargins
875*/
876
877void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargins &targetMargins,
878 const QPixmap &pixmap, const QRect &sourceRect,const QMargins &sourceMargins,
879 const QTileRules &rules
880#ifndef Q_QDOC
881 , QDrawBorderPixmap::DrawingHints hints
882#endif
883 )
884{
885 QPainter::PixmapFragment d;
886 d.opacity = 1.0;
887 d.rotation = 0.0;
888
889 QPixmapFragmentsArray opaqueData;
890 QPixmapFragmentsArray translucentData;
891
892 // source center
893 const int sourceCenterTop = sourceRect.top() + sourceMargins.top();
894 const int sourceCenterLeft = sourceRect.left() + sourceMargins.left();
895 const int sourceCenterBottom = sourceRect.bottom() - sourceMargins.bottom() + 1;
896 const int sourceCenterRight = sourceRect.right() - sourceMargins.right() + 1;
897 const int sourceCenterWidth = sourceCenterRight - sourceCenterLeft;
898 const int sourceCenterHeight = sourceCenterBottom - sourceCenterTop;
899 // target center
900 const int targetCenterTop = targetRect.top() + targetMargins.top();
901 const int targetCenterLeft = targetRect.left() + targetMargins.left();
902 const int targetCenterBottom = targetRect.bottom() - targetMargins.bottom() + 1;
903 const int targetCenterRight = targetRect.right() - targetMargins.right() + 1;
904 const int targetCenterWidth = targetCenterRight - targetCenterLeft;
905 const int targetCenterHeight = targetCenterBottom - targetCenterTop;
906
907 QVarLengthArray<qreal, 16> xTarget; // x-coordinates of target rectangles
908 QVarLengthArray<qreal, 16> yTarget; // y-coordinates of target rectangles
909
910 int columns = 3;
911 int rows = 3;
912 if (rules.horizontal != Qt::StretchTile && sourceCenterWidth != 0)
913 columns = qMax(3, 2 + qCeil(targetCenterWidth / qreal(sourceCenterWidth)));
914 if (rules.vertical != Qt::StretchTile && sourceCenterHeight != 0)
915 rows = qMax(3, 2 + qCeil(targetCenterHeight / qreal(sourceCenterHeight)));
916
917 xTarget.resize(columns + 1);
918 yTarget.resize(rows + 1);
919
920 bool oldAA = painter->testRenderHint(QPainter::Antialiasing);
921 if (painter->paintEngine()->type() != QPaintEngine::OpenGL
922 && painter->paintEngine()->type() != QPaintEngine::OpenGL2
923 && oldAA && painter->combinedTransform().type() != QTransform::TxNone) {
924 painter->setRenderHint(QPainter::Antialiasing, false);
925 }
926
927 xTarget[0] = targetRect.left();
928 xTarget[1] = targetCenterLeft;
929 xTarget[columns - 1] = targetCenterRight;
930 xTarget[columns] = targetRect.left() + targetRect.width();
931
932 yTarget[0] = targetRect.top();
933 yTarget[1] = targetCenterTop;
934 yTarget[rows - 1] = targetCenterBottom;
935 yTarget[rows] = targetRect.top() + targetRect.height();
936
937 qreal dx = targetCenterWidth;
938 qreal dy = targetCenterHeight;
939
940 switch (rules.horizontal) {
941 case Qt::StretchTile:
942 dx = targetCenterWidth;
943 break;
944 case Qt::RepeatTile:
945 dx = sourceCenterWidth;
946 break;
947 case Qt::RoundTile:
948 dx = targetCenterWidth / qreal(columns - 2);
949 break;
950 }
951
952 for (int i = 2; i < columns - 1; ++i)
953 xTarget[i] = xTarget[i - 1] + dx;
954
955 switch (rules.vertical) {
956 case Qt::StretchTile:
957 dy = targetCenterHeight;
958 break;
959 case Qt::RepeatTile:
960 dy = sourceCenterHeight;
961 break;
962 case Qt::RoundTile:
963 dy = targetCenterHeight / qreal(rows - 2);
964 break;
965 }
966
967 for (int i = 2; i < rows - 1; ++i)
968 yTarget[i] = yTarget[i - 1] + dy;
969
970 // corners
971 if (targetMargins.top() > 0 && targetMargins.left() > 0 && sourceMargins.top() > 0 && sourceMargins.left() > 0) { // top left
972 d.x = (0.5 * (xTarget[1] + xTarget[0]));
973 d.y = (0.5 * (yTarget[1] + yTarget[0]));
974 d.sourceLeft = sourceRect.left();
975 d.sourceTop = sourceRect.top();
976 d.width = sourceMargins.left();
977 d.height = sourceMargins.top();
978 d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width;
979 d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height;
981 opaqueData.append(d);
982 else
983 translucentData.append(d);
984 }
985 if (targetMargins.top() > 0 && targetMargins.right() > 0 && sourceMargins.top() > 0 && sourceMargins.right() > 0) { // top right
986 d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1]));
987 d.y = (0.5 * (yTarget[1] + yTarget[0]));
988 d.sourceLeft = sourceCenterRight;
989 d.sourceTop = sourceRect.top();
990 d.width = sourceMargins.right();
991 d.height = sourceMargins.top();
992 d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width;
993 d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height;
995 opaqueData.append(d);
996 else
997 translucentData.append(d);
998 }
999 if (targetMargins.bottom() > 0 && targetMargins.left() > 0 && sourceMargins.bottom() > 0 && sourceMargins.left() > 0) { // bottom left
1000 d.x = (0.5 * (xTarget[1] + xTarget[0]));
1001 d.y =(0.5 * (yTarget[rows] + yTarget[rows - 1]));
1002 d.sourceLeft = sourceRect.left();
1003 d.sourceTop = sourceCenterBottom;
1004 d.width = sourceMargins.left();
1005 d.height = sourceMargins.bottom();
1006 d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width;
1007 d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height;
1009 opaqueData.append(d);
1010 else
1011 translucentData.append(d);
1012 }
1013 if (targetMargins.bottom() > 0 && targetMargins.right() > 0 && sourceMargins.bottom() > 0 && sourceMargins.right() > 0) { // bottom right
1014 d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1]));
1015 d.y = (0.5 * (yTarget[rows] + yTarget[rows - 1]));
1016 d.sourceLeft = sourceCenterRight;
1017 d.sourceTop = sourceCenterBottom;
1018 d.width = sourceMargins.right();
1019 d.height = sourceMargins.bottom();
1020 d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width;
1021 d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height;
1023 opaqueData.append(d);
1024 else
1025 translucentData.append(d);
1026 }
1027
1028 // horizontal edges
1029 if (targetCenterWidth > 0 && sourceCenterWidth > 0) {
1030 if (targetMargins.top() > 0 && sourceMargins.top() > 0) { // top
1031 QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueTop ? opaqueData : translucentData;
1032 d.sourceLeft = sourceCenterLeft;
1033 d.sourceTop = sourceRect.top();
1034 d.width = sourceCenterWidth;
1035 d.height = sourceMargins.top();
1036 d.y = (0.5 * (yTarget[1] + yTarget[0]));
1037 d.scaleX = dx / d.width;
1038 d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height;
1039 for (int i = 1; i < columns - 1; ++i) {
1040 d.x = (0.5 * (xTarget[i + 1] + xTarget[i]));
1041 data.append(d);
1042 }
1043 if (rules.horizontal == Qt::RepeatTile)
1044 data[data.size() - 1].width = ((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX);
1045 }
1046 if (targetMargins.bottom() > 0 && sourceMargins.bottom() > 0) { // bottom
1047 QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueBottom ? opaqueData : translucentData;
1048 d.sourceLeft = sourceCenterLeft;
1049 d.sourceTop = sourceCenterBottom;
1050 d.width = sourceCenterWidth;
1051 d.height = sourceMargins.bottom();
1052 d.y = (0.5 * (yTarget[rows] + yTarget[rows - 1]));
1053 d.scaleX = dx / d.width;
1054 d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height;
1055 for (int i = 1; i < columns - 1; ++i) {
1056 d.x = (0.5 * (xTarget[i + 1] + xTarget[i]));
1057 data.append(d);
1058 }
1059 if (rules.horizontal == Qt::RepeatTile)
1060 data[data.size() - 1].width = ((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX);
1061 }
1062 }
1063
1064 // vertical edges
1065 if (targetCenterHeight > 0 && sourceCenterHeight > 0) {
1066 if (targetMargins.left() > 0 && sourceMargins.left() > 0) { // left
1067 QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueLeft ? opaqueData : translucentData;
1068 d.sourceLeft = sourceRect.left();
1069 d.sourceTop = sourceCenterTop;
1070 d.width = sourceMargins.left();
1071 d.height = sourceCenterHeight;
1072 d.x = (0.5 * (xTarget[1] + xTarget[0]));
1073 d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width;
1074 d.scaleY = dy / d.height;
1075 for (int i = 1; i < rows - 1; ++i) {
1076 d.y = (0.5 * (yTarget[i + 1] + yTarget[i]));
1077 data.append(d);
1078 }
1079 if (rules.vertical == Qt::RepeatTile)
1080 data[data.size() - 1].height = ((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY);
1081 }
1082 if (targetMargins.right() > 0 && sourceMargins.right() > 0) { // right
1083 QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueRight ? opaqueData : translucentData;
1084 d.sourceLeft = sourceCenterRight;
1085 d.sourceTop = sourceCenterTop;
1086 d.width = sourceMargins.right();
1087 d.height = sourceCenterHeight;
1088 d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1]));
1089 d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width;
1090 d.scaleY = dy / d.height;
1091 for (int i = 1; i < rows - 1; ++i) {
1092 d.y = (0.5 * (yTarget[i + 1] + yTarget[i]));
1093 data.append(d);
1094 }
1095 if (rules.vertical == Qt::RepeatTile)
1096 data[data.size() - 1].height = ((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY);
1097 }
1098 }
1099
1100 // center
1101 if (targetCenterWidth > 0 && targetCenterHeight > 0 && sourceCenterWidth > 0 && sourceCenterHeight > 0) {
1102 QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueCenter ? opaqueData : translucentData;
1103 d.sourceLeft = sourceCenterLeft;
1104 d.sourceTop = sourceCenterTop;
1105 d.width = sourceCenterWidth;
1106 d.height = sourceCenterHeight;
1107 d.scaleX = dx / d.width;
1108 d.scaleY = dy / d.height;
1109
1110 qreal repeatWidth = (xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX;
1111 qreal repeatHeight = (yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY;
1112
1113 for (int j = 1; j < rows - 1; ++j) {
1114 d.y = (0.5 * (yTarget[j + 1] + yTarget[j]));
1115 for (int i = 1; i < columns - 1; ++i) {
1116 d.x = (0.5 * (xTarget[i + 1] + xTarget[i]));
1117 data.append(d);
1118 }
1119 if (rules.horizontal == Qt::RepeatTile)
1120 data[data.size() - 1].width = repeatWidth;
1121 }
1122 if (rules.vertical == Qt::RepeatTile) {
1123 for (int i = 1; i < columns - 1; ++i)
1124 data[data.size() - i].height = repeatHeight;
1125 }
1126 }
1127
1128 if (opaqueData.size())
1129 painter->drawPixmapFragments(opaqueData.data(), opaqueData.size(), pixmap, QPainter::OpaqueHint);
1130 if (translucentData.size())
1131 painter->drawPixmapFragments(translucentData.data(), translucentData.size(), pixmap);
1132
1133 if (oldAA)
1134 painter->setRenderHint(QPainter::Antialiasing, true);
1135}
1136
1137} // namespace QQC2
1138
1139QT_END_NAMESPACE
friend class QPainter
\inmodule QtCore\reentrant
Definition qpoint.h:30
void qDrawPlainRect(QPainter *p, const QRect &r, const QColor &c, int lineWidth, const QBrush *fill)
void qDrawShadeRect(QPainter *p, int x, int y, int w, int h, const QPalette &pal, bool sunken, int lineWidth, int midLineWidth, const QBrush *fill)
void qDrawShadeLine(QPainter *p, int x1, int y1, int x2, int y2, const QPalette &pal, bool sunken, int lineWidth, int midLineWidth)
void qDrawShadeRect(QPainter *p, const QRect &r, const QPalette &pal, bool sunken, int lineWidth, int midLineWidth, const QBrush *fill)
void qDrawPlainRect(QPainter *p, int x, int y, int w, int h, const QColor &c, int lineWidth, const QBrush *fill)
void qDrawShadeLine(QPainter *p, const QPoint &p1, const QPoint &p2, const QPalette &pal, bool sunken, int lineWidth, int midLineWidth)
void qDrawWinButton(QPainter *p, const QRect &r, const QPalette &pal, bool sunken, const QBrush *fill)
static void qDrawWinShades(QPainter *p, int x, int y, int w, int h, const QColor &c1, const QColor &c2, const QColor &c3, const QColor &c4, const QBrush *fill)
void qDrawWinPanel(QPainter *p, const QRect &r, const QPalette &pal, bool sunken, const QBrush *fill)
void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargins &targetMargins, const QPixmap &pixmap, const QRect &sourceRect, const QMargins &sourceMargins, const QTileRules &rules, QDrawBorderPixmap::DrawingHints hints)
void qDrawShadePanel(QPainter *p, const QRect &r, const QPalette &pal, bool sunken, int lineWidth, const QBrush *fill)
QVarLengthArray< QPainter::PixmapFragment, 16 > QPixmapFragmentsArray
void qDrawWinPanel(QPainter *p, int x, int y, int w, int h, const QPalette &pal, bool sunken, const QBrush *fill)
void qDrawWinButton(QPainter *p, int x, int y, int w, int h, const QPalette &pal, bool sunken, const QBrush *fill)
void qDrawShadePanel(QPainter *p, int x, int y, int w, int h, const QPalette &pal, bool sunken, int lineWidth, const QBrush *fill)
The QTileRules class provides the rules used to draw a pixmap or image split into nine segments.