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

source code of qtbase/src/widgets/styles/qdrawutil.cpp