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 return;
582 }
583
584 PainterStateGuard painterGuard(p);
585 painterGuard.save();
586 const qreal devicePixelRatio = p->device()->devicePixelRatio();
587 if (!qFuzzyCompare(p1: devicePixelRatio, p2: qreal(1))) {
588 const qreal inverseScale = qreal(1) / devicePixelRatio;
589 p->scale(sx: inverseScale, sy: inverseScale);
590 x = qRound(d: devicePixelRatio * x);
591 y = qRound(d: devicePixelRatio * y);
592 w = devicePixelRatio * w;
593 h = devicePixelRatio * h;
594 lineWidth = qRound(d: devicePixelRatio * lineWidth);
595 p->translate(dx: 0.5, dy: 0.5);
596 }
597
598 p->setPen(c);
599 p->setBrush(Qt::NoBrush);
600 for (int i=0; i<lineWidth; i++)
601 p->drawRect(x: x+i, y: y+i, w: w-i*2 - 1, h: h-i*2 - 1);
602 if (fill) { // fill with fill color
603 p->setPen(Qt::NoPen);
604 p->setBrush(*fill);
605 p->drawRect(x: x+lineWidth, y: y+lineWidth, w: w-lineWidth*2, h: h-lineWidth*2);
606 }
607}
608
609/*!
610 \fn void qDrawPlainRoundedRect(QPainter *painter, int x, int y,
611 int width, int height, qreal rx, qreal ry,
612 const QColor &lineColor, int lineWidth,
613 const QBrush *fill)
614 \since 6.7
615 \relates <qdrawutil.h>
616
617 Draws the plain rounded rectangle beginning at (\a x, \a y)
618 with the given \a width and \a height,
619 using the horizontal \a rx and vertical radius \a ry,
620 specified \a painter, \a lineColor and \a lineWidth.
621 The rectangle's interior is filled with the \a
622 fill brush unless \a fill is \nullptr.
623
624 \warning This function does not look at QWidget::style() or
625 QApplication::style(). Use the drawing functions in QStyle to make
626 widgets that follow the current GUI style.
627
628 Alternatively you can use a QFrame widget and apply the
629 QFrame::setFrameStyle() function to display a plain rectangle:
630
631 \snippet code/src_gui_painting_qdrawutil.cpp 4
632
633 \sa qDrawShadeRect(), QStyle
634*/
635
636// ### Qt7: Pass QPen instead of QColor for frame drawing
637void qDrawPlainRoundedRect(QPainter *p, int x, int y, int w, int h,
638 qreal rx, qreal ry, const QColor &c,
639 int lineWidth, const QBrush *fill)
640{
641 if (w == 0 || h == 0)
642 return;
643 if (Q_UNLIKELY(w < 0 || h < 0 || lineWidth < 0)) {
644 qWarning(msg: "qDrawPlainRect: Invalid parameters");
645 return;
646 }
647
648 PainterStateGuard painterGuard(p);
649 painterGuard.save();
650 const qreal devicePixelRatio = p->device()->devicePixelRatio();
651 if (!qFuzzyCompare(p1: devicePixelRatio, p2: qreal(1))) {
652 const qreal inverseScale = qreal(1) / devicePixelRatio;
653 p->scale(sx: inverseScale, sy: inverseScale);
654 x = qRound(d: devicePixelRatio * x);
655 y = qRound(d: devicePixelRatio * y);
656 w = devicePixelRatio * w;
657 h = devicePixelRatio * h;
658 lineWidth = qRound(d: devicePixelRatio * lineWidth);
659 p->translate(dx: 0.5, dy: 0.5);
660 }
661
662 p->setPen(c);
663 p->setBrush(Qt::NoBrush);
664 for (int i=0; i<lineWidth; i++) {
665 QRectF rect(x+i, y+i, w-i*2 - 1, h-i*2 - 1);
666 rect.marginsRemoved(margins: QMarginsF(0.5,0.5,0.5,0.5));
667 p->drawRoundedRect(rect, xRadius: rx, yRadius: ry);
668 }
669 if (fill) { // fill with fill color
670 p->setPen(Qt::NoPen);
671 p->setBrush(*fill);
672 p->drawRoundedRect(x: x+lineWidth, y: y+lineWidth, w: w-lineWidth*2, h: h-lineWidth*2, xRadius: rx, yRadius: ry);
673 }
674}
675
676/*****************************************************************************
677 Overloaded functions.
678 *****************************************************************************/
679
680/*!
681 \fn void qDrawShadeLine(QPainter *painter, const QPoint &p1, const QPoint &p2,
682 const QPalette &palette, bool sunken, int lineWidth, int midLineWidth)
683 \relates <qdrawutil.h>
684 \overload
685
686 Draws a horizontal or vertical shaded line between \a p1 and \a p2
687 using the given \a painter. Note that nothing is drawn if the line
688 between the points would be neither horizontal nor vertical.
689
690 The provided \a palette specifies the shading colors (\l
691 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
692 {QPalette::mid()}{middle} colors). The given \a lineWidth
693 specifies the line width for each of the lines; it is not the
694 total line width. The given \a midLineWidth specifies the width of
695 a middle line drawn in the QPalette::mid() color.
696
697 The line appears sunken if \a sunken is true, otherwise raised.
698
699 \warning This function does not look at QWidget::style() or
700 QApplication::style(). Use the drawing functions in QStyle to
701 make widgets that follow the current GUI style.
702
703
704 Alternatively you can use a QFrame widget and apply the
705 QFrame::setFrameStyle() function to display a shaded line:
706
707 \snippet code/src_gui_painting_qdrawutil.cpp 5
708
709 \sa qDrawShadeRect(), qDrawShadePanel(), QStyle
710*/
711
712void qDrawShadeLine(QPainter *p, const QPoint &p1, const QPoint &p2,
713 const QPalette &pal, bool sunken,
714 int lineWidth, int midLineWidth)
715{
716 qDrawShadeLine(p, x1: p1.x(), y1: p1.y(), x2: p2.x(), y2: p2.y(), pal, sunken,
717 lineWidth, midLineWidth);
718}
719
720/*!
721 \fn void qDrawShadeRect(QPainter *painter, const QRect &rect, const QPalette &palette,
722 bool sunken, int lineWidth, int midLineWidth, const QBrush *fill)
723 \relates <qdrawutil.h>
724 \overload
725
726 Draws the shaded rectangle specified by \a rect using the given \a painter.
727
728 The provide \a palette specifies the shading colors (\l
729 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
730 {QPalette::mid()}{middle} colors. The given \a lineWidth
731 specifies the line width for each of the lines; it is not the
732 total line width. The \a midLineWidth specifies the width of a
733 middle line drawn in the QPalette::mid() color. The rectangle's
734 interior is filled with the \a fill brush unless \a fill is \nullptr.
735
736 The rectangle appears sunken if \a sunken is true, otherwise
737 raised.
738
739 \warning This function does not look at QWidget::style() or
740 QApplication::style(). Use the drawing functions in QStyle to make
741 widgets that follow the current GUI style.
742
743 Alternatively you can use a QFrame widget and apply the
744 QFrame::setFrameStyle() function to display a shaded rectangle:
745
746 \snippet code/src_gui_painting_qdrawutil.cpp 6
747
748 \sa qDrawShadeLine(), qDrawShadePanel(), qDrawPlainRect(), QStyle
749*/
750
751void qDrawShadeRect(QPainter *p, const QRect &r,
752 const QPalette &pal, bool sunken,
753 int lineWidth, int midLineWidth,
754 const QBrush *fill)
755{
756 qDrawShadeRect(p, x: r.x(), y: r.y(), w: r.width(), h: r.height(), pal, sunken,
757 lineWidth, midLineWidth, fill);
758}
759
760/*!
761 \fn void qDrawShadePanel(QPainter *painter, const QRect &rect, const QPalette &palette,
762 bool sunken, int lineWidth, const QBrush *fill)
763 \relates <qdrawutil.h>
764 \overload
765
766 Draws the shaded panel at the rectangle specified by \a rect using the
767 given \a painter and the given \a lineWidth.
768
769 The given \a palette specifies the shading colors (\l
770 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
771 {QPalette::mid()}{middle} colors). The panel's interior is filled
772 with the \a fill brush unless \a fill is \nullptr.
773
774 The panel 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 \snippet code/src_gui_painting_qdrawutil.cpp 7
784
785 \sa qDrawWinPanel(), qDrawShadeLine(), qDrawShadeRect(), QStyle
786*/
787
788void qDrawShadePanel(QPainter *p, const QRect &r,
789 const QPalette &pal, bool sunken,
790 int lineWidth, const QBrush *fill)
791{
792 qDrawShadePanel(p, x: r.x(), y: r.y(), w: r.width(), h: r.height(), pal, sunken,
793 lineWidth, fill);
794}
795
796/*!
797 \fn void qDrawWinButton(QPainter *painter, const QRect &rect, const QPalette &palette,
798 bool sunken, const QBrush *fill)
799 \relates <qdrawutil.h>
800 \overload
801
802 Draws the Windows-style button at the rectangle specified by \a rect using
803 the given \a painter with a line width of 2 pixels. The button's interior
804 is filled with the \a{fill} brush unless \a fill is \nullptr.
805
806 The given \a palette specifies the shading colors (\l
807 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
808 {QPalette::mid()}{middle} colors).
809
810 The button appears sunken if \a sunken is true, otherwise raised.
811
812 \warning This function does not look at QWidget::style() or
813 QApplication::style()-> Use the drawing functions in QStyle to make
814 widgets that follow the current GUI style.
815
816 \sa qDrawWinPanel(), QStyle
817*/
818
819void qDrawWinButton(QPainter *p, const QRect &r,
820 const QPalette &pal, bool sunken, const QBrush *fill)
821{
822 qDrawWinButton(p, x: r.x(), y: r.y(), w: r.width(), h: r.height(), pal, sunken, fill);
823}
824
825/*!
826 \fn void qDrawWinPanel(QPainter *painter, const QRect &rect, const QPalette &palette,
827 bool sunken, const QBrush *fill)
828 \relates <qdrawutil.h>
829 \overload
830
831 Draws the Windows-style panel at the rectangle specified by \a rect using
832 the given \a painter with a line width of 2 pixels. The button's interior
833 is filled with the \a fill brush unless \a fill is \nullptr.
834
835 The given \a palette specifies the shading colors. The panel
836 appears sunken if \a sunken is true, otherwise raised.
837
838 \warning This function does not look at QWidget::style() or
839 QApplication::style(). Use the drawing functions in QStyle to make
840 widgets that follow the current GUI style.
841
842 Alternatively you can use a QFrame widget and apply the
843 QFrame::setFrameStyle() function to display a shaded panel:
844
845 \snippet code/src_gui_painting_qdrawutil.cpp 8
846
847 \sa qDrawShadePanel(), qDrawWinButton(), QStyle
848*/
849
850void qDrawWinPanel(QPainter *p, const QRect &r,
851 const QPalette &pal, bool sunken, const QBrush *fill)
852{
853 qDrawWinPanel(p, x: r.x(), y: r.y(), w: r.width(), h: r.height(), pal, sunken, fill);
854}
855
856/*!
857 \fn void qDrawPlainRect(QPainter *painter, const QRect &rect, const QColor &lineColor, int lineWidth, const QBrush *fill)
858 \relates <qdrawutil.h>
859 \overload
860
861 Draws the plain rectangle specified by \a rect using the given \a painter,
862 \a lineColor and \a lineWidth. The rectangle's interior is filled with the
863 \a fill brush unless \a fill is \nullptr.
864
865 \warning This function does not look at QWidget::style() or
866 QApplication::style(). Use the drawing functions in QStyle to make
867 widgets that follow the current GUI style.
868
869 Alternatively you can use a QFrame widget and apply the
870 QFrame::setFrameStyle() function to display a plain rectangle:
871
872 \snippet code/src_gui_painting_qdrawutil.cpp 9
873
874 \sa qDrawShadeRect(), QStyle
875*/
876
877void qDrawPlainRect(QPainter *p, const QRect &r, const QColor &c,
878 int lineWidth, const QBrush *fill)
879{
880 qDrawPlainRect(p, x: r.x(), y: r.y(), w: r.width(), h: r.height(), c,
881 lineWidth, fill);
882}
883
884/*!
885 \fn void qDrawPlainRoundedRect(QPainter *painter, const QRect &rect,
886 qreal rx, qreal ry,
887 const QColor &lineColor, int lineWidth,
888 const QBrush *fill)
889 \since 6.7
890 \relates <qdrawutil.h>
891 \overload
892
893 Draws the plain rectangle specified by \a rect using
894 the horizontal \a rx and vertical radius \a ry,
895 the given \a painter, \a lineColor and \a lineWidth.
896 The rectangle's interior is filled with the
897 \a fill brush unless \a fill is \nullptr.
898
899 \warning This function does not look at QWidget::style() or
900 QApplication::style(). Use the drawing functions in QStyle to make
901 widgets that follow the current GUI style.
902
903 Alternatively you can use a QFrame widget and apply the
904 QFrame::setFrameStyle() function to display a plain rectangle:
905
906 \snippet code/src_gui_painting_qdrawutil.cpp 9
907
908 \sa qDrawShadeRect(), QStyle
909*/
910
911/*!
912 \class QTileRules
913 \since 4.6
914
915 \inmodule QtWidgets
916
917 \brief The QTileRules class provides the rules used to draw a
918 pixmap or image split into nine segments.
919
920 Spliiting is similar to \l{http://www.w3.org/TR/css3-background/}{CSS3 border-images}.
921
922 \sa Qt::TileRule, QMargins
923*/
924
925/*! \fn QTileRules::QTileRules(Qt::TileRule horizontalRule, Qt::TileRule verticalRule)
926 Constructs a QTileRules with the given \a horizontalRule and
927 \a verticalRule.
928 */
929
930/*! \fn QTileRules::QTileRules(Qt::TileRule rule)
931 Constructs a QTileRules with the given \a rule used for both
932 the horizontal rule and the vertical rule.
933 */
934
935/*!
936 \fn void qDrawBorderPixmap(QPainter *painter, const QRect &target, const QMargins &margins, const QPixmap &pixmap)
937 \relates <qdrawutil.h>
938 \since 4.6
939
940 \brief The qDrawBorderPixmap function is for drawing a pixmap into
941 the margins of a rectangle.
942
943 Draws the given \a pixmap into the given \a target rectangle, using the
944 given \a painter. The pixmap will be split into nine segments and drawn
945 according to the \a margins structure.
946*/
947
948typedef QVarLengthArray<QPainter::PixmapFragment, 16> QPixmapFragmentsArray;
949
950/*!
951 \relates <qdrawutil.h>
952 \since 4.6
953
954 Draws the indicated \a sourceRect rectangle from the given \a pixmap into
955 the given \a targetRect rectangle, using the given \a painter. The pixmap
956 will be split into nine segments according to the given \a targetMargins
957 and \a sourceMargins structures. Finally, the pixmap will be drawn
958 according to the given \a rules.
959
960 This function is used to draw a scaled pixmap, similar to
961 \l{http://www.w3.org/TR/css3-background/}{CSS3 border-images}
962
963 \sa Qt::TileRule, QTileRules, QMargins
964*/
965
966void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargins &targetMargins,
967 const QPixmap &pixmap, const QRect &sourceRect,const QMargins &sourceMargins,
968 const QTileRules &rules
969#ifndef Q_QDOC
970 , QDrawBorderPixmap::DrawingHints hints
971#endif
972 )
973{
974 QPainter::PixmapFragment d;
975 d.opacity = 1.0;
976 d.rotation = 0.0;
977
978 QPixmapFragmentsArray opaqueData;
979 QPixmapFragmentsArray translucentData;
980
981 // source center
982 const int sourceCenterTop = sourceRect.top() + sourceMargins.top();
983 const int sourceCenterLeft = sourceRect.left() + sourceMargins.left();
984 const int sourceCenterBottom = sourceRect.bottom() - sourceMargins.bottom() + 1;
985 const int sourceCenterRight = sourceRect.right() - sourceMargins.right() + 1;
986 const int sourceCenterWidth = sourceCenterRight - sourceCenterLeft;
987 const int sourceCenterHeight = sourceCenterBottom - sourceCenterTop;
988 // target center
989 const int targetCenterTop = targetRect.top() + targetMargins.top();
990 const int targetCenterLeft = targetRect.left() + targetMargins.left();
991 const int targetCenterBottom = targetRect.bottom() - targetMargins.bottom() + 1;
992 const int targetCenterRight = targetRect.right() - targetMargins.right() + 1;
993 const int targetCenterWidth = targetCenterRight - targetCenterLeft;
994 const int targetCenterHeight = targetCenterBottom - targetCenterTop;
995
996 QVarLengthArray<qreal, 16> xTarget; // x-coordinates of target rectangles
997 QVarLengthArray<qreal, 16> yTarget; // y-coordinates of target rectangles
998
999 int columns = 3;
1000 int rows = 3;
1001 if (rules.horizontal != Qt::StretchTile && sourceCenterWidth != 0)
1002 columns = qMax(a: 3, b: 2 + qCeil(v: targetCenterWidth / qreal(sourceCenterWidth)));
1003 if (rules.vertical != Qt::StretchTile && sourceCenterHeight != 0)
1004 rows = qMax(a: 3, b: 2 + qCeil(v: targetCenterHeight / qreal(sourceCenterHeight)));
1005
1006 xTarget.resize(sz: columns + 1);
1007 yTarget.resize(sz: rows + 1);
1008
1009 bool oldAA = painter->testRenderHint(hint: QPainter::Antialiasing);
1010 if (painter->paintEngine()->type() != QPaintEngine::OpenGL
1011 && painter->paintEngine()->type() != QPaintEngine::OpenGL2
1012 && oldAA && painter->combinedTransform().type() != QTransform::TxNone) {
1013 painter->setRenderHint(hint: QPainter::Antialiasing, on: false);
1014 }
1015
1016 xTarget[0] = targetRect.left();
1017 xTarget[1] = targetCenterLeft;
1018 xTarget[columns - 1] = targetCenterRight;
1019 xTarget[columns] = targetRect.left() + targetRect.width();
1020
1021 yTarget[0] = targetRect.top();
1022 yTarget[1] = targetCenterTop;
1023 yTarget[rows - 1] = targetCenterBottom;
1024 yTarget[rows] = targetRect.top() + targetRect.height();
1025
1026 qreal dx = targetCenterWidth;
1027 qreal dy = targetCenterHeight;
1028
1029 switch (rules.horizontal) {
1030 case Qt::StretchTile:
1031 dx = targetCenterWidth;
1032 break;
1033 case Qt::RepeatTile:
1034 dx = sourceCenterWidth;
1035 break;
1036 case Qt::RoundTile:
1037 dx = targetCenterWidth / qreal(columns - 2);
1038 break;
1039 }
1040
1041 for (int i = 2; i < columns - 1; ++i)
1042 xTarget[i] = xTarget[i - 1] + dx;
1043
1044 switch (rules.vertical) {
1045 case Qt::StretchTile:
1046 dy = targetCenterHeight;
1047 break;
1048 case Qt::RepeatTile:
1049 dy = sourceCenterHeight;
1050 break;
1051 case Qt::RoundTile:
1052 dy = targetCenterHeight / qreal(rows - 2);
1053 break;
1054 }
1055
1056 for (int i = 2; i < rows - 1; ++i)
1057 yTarget[i] = yTarget[i - 1] + dy;
1058
1059 // corners
1060 if (targetMargins.top() > 0 && targetMargins.left() > 0 && sourceMargins.top() > 0 && sourceMargins.left() > 0) { // top left
1061 d.x = (0.5 * (xTarget[1] + xTarget[0]));
1062 d.y = (0.5 * (yTarget[1] + yTarget[0]));
1063 d.sourceLeft = sourceRect.left();
1064 d.sourceTop = sourceRect.top();
1065 d.width = sourceMargins.left();
1066 d.height = sourceMargins.top();
1067 d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width;
1068 d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height;
1069 if (hints & QDrawBorderPixmap::OpaqueTopLeft)
1070 opaqueData.append(t: d);
1071 else
1072 translucentData.append(t: d);
1073 }
1074 if (targetMargins.top() > 0 && targetMargins.right() > 0 && sourceMargins.top() > 0 && sourceMargins.right() > 0) { // top right
1075 d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1]));
1076 d.y = (0.5 * (yTarget[1] + yTarget[0]));
1077 d.sourceLeft = sourceCenterRight;
1078 d.sourceTop = sourceRect.top();
1079 d.width = sourceMargins.right();
1080 d.height = sourceMargins.top();
1081 d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width;
1082 d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height;
1083 if (hints & QDrawBorderPixmap::OpaqueTopRight)
1084 opaqueData.append(t: d);
1085 else
1086 translucentData.append(t: d);
1087 }
1088 if (targetMargins.bottom() > 0 && targetMargins.left() > 0 && sourceMargins.bottom() > 0 && sourceMargins.left() > 0) { // bottom left
1089 d.x = (0.5 * (xTarget[1] + xTarget[0]));
1090 d.y =(0.5 * (yTarget[rows] + yTarget[rows - 1]));
1091 d.sourceLeft = sourceRect.left();
1092 d.sourceTop = sourceCenterBottom;
1093 d.width = sourceMargins.left();
1094 d.height = sourceMargins.bottom();
1095 d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width;
1096 d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height;
1097 if (hints & QDrawBorderPixmap::OpaqueBottomLeft)
1098 opaqueData.append(t: d);
1099 else
1100 translucentData.append(t: d);
1101 }
1102 if (targetMargins.bottom() > 0 && targetMargins.right() > 0 && sourceMargins.bottom() > 0 && sourceMargins.right() > 0) { // bottom right
1103 d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1]));
1104 d.y = (0.5 * (yTarget[rows] + yTarget[rows - 1]));
1105 d.sourceLeft = sourceCenterRight;
1106 d.sourceTop = sourceCenterBottom;
1107 d.width = sourceMargins.right();
1108 d.height = sourceMargins.bottom();
1109 d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width;
1110 d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height;
1111 if (hints & QDrawBorderPixmap::OpaqueBottomRight)
1112 opaqueData.append(t: d);
1113 else
1114 translucentData.append(t: d);
1115 }
1116
1117 // horizontal edges
1118 if (targetCenterWidth > 0 && sourceCenterWidth > 0) {
1119 if (targetMargins.top() > 0 && sourceMargins.top() > 0) { // top
1120 QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueTop ? opaqueData : translucentData;
1121 d.sourceLeft = sourceCenterLeft;
1122 d.sourceTop = sourceRect.top();
1123 d.width = sourceCenterWidth;
1124 d.height = sourceMargins.top();
1125 d.y = (0.5 * (yTarget[1] + yTarget[0]));
1126 d.scaleX = dx / d.width;
1127 d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height;
1128 for (int i = 1; i < columns - 1; ++i) {
1129 d.x = (0.5 * (xTarget[i + 1] + xTarget[i]));
1130 data.append(t: d);
1131 }
1132 if (rules.horizontal == Qt::RepeatTile)
1133 data[data.size() - 1].width = ((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX);
1134 }
1135 if (targetMargins.bottom() > 0 && sourceMargins.bottom() > 0) { // bottom
1136 QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueBottom ? opaqueData : translucentData;
1137 d.sourceLeft = sourceCenterLeft;
1138 d.sourceTop = sourceCenterBottom;
1139 d.width = sourceCenterWidth;
1140 d.height = sourceMargins.bottom();
1141 d.y = (0.5 * (yTarget[rows] + yTarget[rows - 1]));
1142 d.scaleX = dx / d.width;
1143 d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height;
1144 for (int i = 1; i < columns - 1; ++i) {
1145 d.x = (0.5 * (xTarget[i + 1] + xTarget[i]));
1146 data.append(t: d);
1147 }
1148 if (rules.horizontal == Qt::RepeatTile)
1149 data[data.size() - 1].width = ((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX);
1150 }
1151 }
1152
1153 // vertical edges
1154 if (targetCenterHeight > 0 && sourceCenterHeight > 0) {
1155 if (targetMargins.left() > 0 && sourceMargins.left() > 0) { // left
1156 QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueLeft ? opaqueData : translucentData;
1157 d.sourceLeft = sourceRect.left();
1158 d.sourceTop = sourceCenterTop;
1159 d.width = sourceMargins.left();
1160 d.height = sourceCenterHeight;
1161 d.x = (0.5 * (xTarget[1] + xTarget[0]));
1162 d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width;
1163 d.scaleY = dy / d.height;
1164 for (int i = 1; i < rows - 1; ++i) {
1165 d.y = (0.5 * (yTarget[i + 1] + yTarget[i]));
1166 data.append(t: d);
1167 }
1168 if (rules.vertical == Qt::RepeatTile)
1169 data[data.size() - 1].height = ((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY);
1170 }
1171 if (targetMargins.right() > 0 && sourceMargins.right() > 0) { // right
1172 QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueRight ? opaqueData : translucentData;
1173 d.sourceLeft = sourceCenterRight;
1174 d.sourceTop = sourceCenterTop;
1175 d.width = sourceMargins.right();
1176 d.height = sourceCenterHeight;
1177 d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1]));
1178 d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width;
1179 d.scaleY = dy / d.height;
1180 for (int i = 1; i < rows - 1; ++i) {
1181 d.y = (0.5 * (yTarget[i + 1] + yTarget[i]));
1182 data.append(t: d);
1183 }
1184 if (rules.vertical == Qt::RepeatTile)
1185 data[data.size() - 1].height = ((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY);
1186 }
1187 }
1188
1189 // center
1190 if (targetCenterWidth > 0 && targetCenterHeight > 0 && sourceCenterWidth > 0 && sourceCenterHeight > 0) {
1191 QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueCenter ? opaqueData : translucentData;
1192 d.sourceLeft = sourceCenterLeft;
1193 d.sourceTop = sourceCenterTop;
1194 d.width = sourceCenterWidth;
1195 d.height = sourceCenterHeight;
1196 d.scaleX = dx / d.width;
1197 d.scaleY = dy / d.height;
1198
1199 qreal repeatWidth = (xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX;
1200 qreal repeatHeight = (yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY;
1201
1202 for (int j = 1; j < rows - 1; ++j) {
1203 d.y = (0.5 * (yTarget[j + 1] + yTarget[j]));
1204 for (int i = 1; i < columns - 1; ++i) {
1205 d.x = (0.5 * (xTarget[i + 1] + xTarget[i]));
1206 data.append(t: d);
1207 }
1208 if (rules.horizontal == Qt::RepeatTile)
1209 data[data.size() - 1].width = repeatWidth;
1210 }
1211 if (rules.vertical == Qt::RepeatTile) {
1212 for (int i = 1; i < columns - 1; ++i)
1213 data[data.size() - i].height = repeatHeight;
1214 }
1215 }
1216
1217 if (opaqueData.size())
1218 painter->drawPixmapFragments(fragments: opaqueData.data(), fragmentCount: opaqueData.size(), pixmap, hints: QPainter::OpaqueHint);
1219 if (translucentData.size())
1220 painter->drawPixmapFragments(fragments: translucentData.data(), fragmentCount: translucentData.size(), pixmap);
1221
1222 if (oldAA)
1223 painter->setRenderHint(hint: QPainter::Antialiasing, on: true);
1224}
1225
1226QT_END_NAMESPACE
1227

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