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