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