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 | |
14 | QT_BEGIN_NAMESPACE |
15 | |
16 | namespace { |
17 | class PainterStateGuard { |
18 | Q_DISABLE_COPY_MOVE(PainterStateGuard) |
19 | public: |
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 | |
39 | private: |
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 | |
86 | void 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 | |
213 | void 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 | /*! |
302 | \fn void qDrawShadePanel(QPainter *painter, int x, int y, int width, int height, |
303 | const QPalette &palette, bool sunken, |
304 | int lineWidth, const QBrush *fill) |
305 | \relates <qdrawutil.h> |
306 | |
307 | Draws the shaded panel beginning at (\a x, \a y) with the given \a |
308 | width and \a height using the provided \a painter and the given \a |
309 | lineWidth. |
310 | |
311 | The given \a palette specifies the shading colors (\l |
312 | {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l |
313 | {QPalette::mid()}{middle} colors). The panel's interior is filled |
314 | with the \a fill brush unless \a fill is \nullptr. |
315 | |
316 | The panel appears sunken if \a sunken is true, otherwise raised. |
317 | |
318 | \warning This function does not look at QWidget::style() or |
319 | QApplication::style(). Use the drawing functions in QStyle to make |
320 | widgets that follow the current GUI style. |
321 | |
322 | Alternatively you can use a QFrame widget and apply the |
323 | QFrame::setFrameStyle() function to display a shaded panel: |
324 | |
325 | \snippet code/src_gui_painting_qdrawutil.cpp 2 |
326 | |
327 | \sa qDrawWinPanel(), qDrawShadeLine(), qDrawShadeRect(), QStyle |
328 | */ |
329 | |
330 | void qDrawShadePanel(QPainter *p, int x, int y, int w, int h, |
331 | const QPalette &pal, bool sunken, |
332 | int lineWidth, const QBrush *fill) |
333 | { |
334 | if (w == 0 || h == 0) |
335 | return; |
336 | if (Q_UNLIKELY(w < 0 || h < 0 || lineWidth < 0)) { |
337 | qWarning(msg: "qDrawShadePanel: Invalid parameters" ); |
338 | } |
339 | |
340 | PainterStateGuard painterGuard(p); |
341 | const qreal devicePixelRatio = p->device()->devicePixelRatio(); |
342 | bool isTranslated = false; |
343 | if (!qFuzzyCompare(p1: devicePixelRatio, p2: qreal(1))) { |
344 | painterGuard.save(); |
345 | const qreal inverseScale = qreal(1) / devicePixelRatio; |
346 | p->scale(sx: inverseScale, sy: inverseScale); |
347 | x = qRound(d: devicePixelRatio * x); |
348 | y = qRound(d: devicePixelRatio * y); |
349 | w = devicePixelRatio * w; |
350 | h = devicePixelRatio * h; |
351 | lineWidth = qRound(d: devicePixelRatio * lineWidth); |
352 | p->translate(dx: 0.5, dy: 0.5); |
353 | isTranslated = true; |
354 | } |
355 | |
356 | QColor shade = pal.dark().color(); |
357 | QColor light = pal.light().color(); |
358 | if (fill) { |
359 | if (fill->color() == shade) |
360 | shade = pal.shadow().color(); |
361 | if (fill->color() == light) |
362 | light = pal.midlight().color(); |
363 | } |
364 | QPen oldPen = p->pen(); // save pen |
365 | QList<QLineF> lines; |
366 | lines.reserve(asize: 2*lineWidth); |
367 | |
368 | if (sunken) |
369 | p->setPen(shade); |
370 | else |
371 | p->setPen(light); |
372 | int x1, y1, x2, y2; |
373 | int i; |
374 | x1 = x; |
375 | y1 = y2 = y; |
376 | x2 = x+w-2; |
377 | for (i=0; i<lineWidth; i++) { // top shadow |
378 | lines << QLineF(x1, y1++, x2--, y2++); |
379 | } |
380 | x2 = x1; |
381 | y1 = y+h-2; |
382 | for (i=0; i<lineWidth; i++) { // left shado |
383 | lines << QLineF(x1++, y1, x2++, y2--); |
384 | } |
385 | p->drawLines(lines); |
386 | lines.clear(); |
387 | if (sunken) |
388 | p->setPen(light); |
389 | else |
390 | p->setPen(shade); |
391 | x1 = x; |
392 | y1 = y2 = y+h-1; |
393 | x2 = x+w-1; |
394 | for (i=0; i<lineWidth; i++) { // bottom shadow |
395 | lines << QLineF(x1++, y1--, x2, y2--); |
396 | } |
397 | x1 = x2; |
398 | y1 = y; |
399 | y2 = y+h-lineWidth-1; |
400 | for (i=0; i<lineWidth; i++) { // right shadow |
401 | lines << QLineF(x1--, y1++, x2--, y2); |
402 | } |
403 | p->drawLines(lines); |
404 | if (fill) { // fill with fill color |
405 | if (isTranslated) |
406 | p->translate(dx: -0.5, dy: -0.5); |
407 | p->fillRect(x: x+lineWidth, y: y+lineWidth, w: w-lineWidth*2, h: h-lineWidth*2, b: *fill); |
408 | } |
409 | p->setPen(oldPen); // restore pen |
410 | } |
411 | |
412 | |
413 | /*! |
414 | \internal |
415 | This function draws a rectangle with two pixel line width. |
416 | It is called from qDrawWinButton() and qDrawWinPanel(). |
417 | |
418 | c1..c4 and fill are used: |
419 | |
420 | 1 1 1 1 1 2 |
421 | 1 3 3 3 4 2 |
422 | 1 3 F F 4 2 |
423 | 1 3 F F 4 2 |
424 | 1 4 4 4 4 2 |
425 | 2 2 2 2 2 2 |
426 | */ |
427 | |
428 | static void qDrawWinShades(QPainter *p, |
429 | int x, int y, int w, int h, |
430 | const QColor &c1, const QColor &c2, |
431 | const QColor &c3, const QColor &c4, |
432 | const QBrush *fill) |
433 | { |
434 | if (w < 2 || h < 2) // can't do anything with that |
435 | return; |
436 | |
437 | PainterStateGuard painterGuard(p); |
438 | const qreal devicePixelRatio = p->device()->devicePixelRatio(); |
439 | bool isTranslated = false; |
440 | if (!qFuzzyCompare(p1: devicePixelRatio, p2: qreal(1))) { |
441 | painterGuard.save(); |
442 | const qreal inverseScale = qreal(1) / devicePixelRatio; |
443 | p->scale(sx: inverseScale, sy: inverseScale); |
444 | x = qRound(d: devicePixelRatio * x); |
445 | y = qRound(d: devicePixelRatio * y); |
446 | w = devicePixelRatio * w; |
447 | h = devicePixelRatio * h; |
448 | p->translate(dx: 0.5, dy: 0.5); |
449 | isTranslated = true; |
450 | } |
451 | |
452 | QPen oldPen = p->pen(); |
453 | QPoint a[3] = { QPoint(x, y+h-2), QPoint(x, y), QPoint(x+w-2, y) }; |
454 | p->setPen(c1); |
455 | p->drawPolyline(points: a, pointCount: 3); |
456 | QPoint b[3] = { QPoint(x, y+h-1), QPoint(x+w-1, y+h-1), QPoint(x+w-1, y) }; |
457 | p->setPen(c2); |
458 | p->drawPolyline(points: b, pointCount: 3); |
459 | if (w > 4 && h > 4) { |
460 | QPoint c[3] = { QPoint(x+1, y+h-3), QPoint(x+1, y+1), QPoint(x+w-3, y+1) }; |
461 | p->setPen(c3); |
462 | p->drawPolyline(points: c, pointCount: 3); |
463 | QPoint d[3] = { QPoint(x+1, y+h-2), QPoint(x+w-2, y+h-2), QPoint(x+w-2, y+1) }; |
464 | p->setPen(c4); |
465 | p->drawPolyline(points: d, pointCount: 3); |
466 | if (fill) { |
467 | if (isTranslated) |
468 | p->translate(dx: -0.5, dy: -0.5); |
469 | p->fillRect(QRect(x+2, y+2, w-4, h-4), *fill); |
470 | } |
471 | } |
472 | p->setPen(oldPen); |
473 | } |
474 | |
475 | |
476 | /*! |
477 | \fn void qDrawWinButton(QPainter *painter, int x, int y, int width, int height, |
478 | const QPalette &palette, bool sunken, |
479 | const QBrush *fill) |
480 | \relates <qdrawutil.h> |
481 | |
482 | Draws the Windows-style button specified by the given point (\a x, |
483 | \a y}, \a width and \a height using the provided \a painter with a |
484 | line width of 2 pixels. The button's interior is filled with the |
485 | \a{fill} brush unless \a fill is \nullptr. |
486 | |
487 | The given \a palette specifies the shading colors (\l |
488 | {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l |
489 | {QPalette::mid()}{middle} colors). |
490 | |
491 | The button appears sunken if \a sunken is true, otherwise raised. |
492 | |
493 | \warning This function does not look at QWidget::style() or |
494 | QApplication::style()-> Use the drawing functions in QStyle to make |
495 | widgets that follow the current GUI style. |
496 | |
497 | \sa qDrawWinPanel(), QStyle |
498 | */ |
499 | |
500 | void qDrawWinButton(QPainter *p, int x, int y, int w, int h, |
501 | const QPalette &pal, bool sunken, |
502 | const QBrush *fill) |
503 | { |
504 | if (sunken) |
505 | qDrawWinShades(p, x, y, w, h, |
506 | c1: pal.shadow().color(), c2: pal.light().color(), c3: pal.dark().color(), |
507 | c4: pal.button().color(), fill); |
508 | else |
509 | qDrawWinShades(p, x, y, w, h, |
510 | c1: pal.light().color(), c2: pal.shadow().color(), c3: pal.button().color(), |
511 | c4: pal.dark().color(), fill); |
512 | } |
513 | |
514 | /*! |
515 | \fn void qDrawWinPanel(QPainter *painter, int x, int y, int width, int height, |
516 | const QPalette &palette, bool sunken, |
517 | const QBrush *fill) |
518 | \relates <qdrawutil.h> |
519 | |
520 | Draws the Windows-style panel specified by the given point(\a x, |
521 | \a y), \a width and \a height using the provided \a painter with a |
522 | line width of 2 pixels. The button's interior is filled with the |
523 | \a fill brush unless \a fill is \nullptr. |
524 | |
525 | The given \a palette specifies the shading colors. The panel |
526 | appears sunken if \a sunken is true, otherwise raised. |
527 | |
528 | \warning This function does not look at QWidget::style() or |
529 | QApplication::style(). Use the drawing functions in QStyle to make |
530 | widgets that follow the current GUI style. |
531 | |
532 | Alternatively you can use a QFrame widget and apply the |
533 | QFrame::setFrameStyle() function to display a shaded panel: |
534 | |
535 | \snippet code/src_gui_painting_qdrawutil.cpp 3 |
536 | |
537 | \sa qDrawShadePanel(), qDrawWinButton(), QStyle |
538 | */ |
539 | |
540 | void qDrawWinPanel(QPainter *p, int x, int y, int w, int h, |
541 | const QPalette &pal, bool sunken, |
542 | const QBrush *fill) |
543 | { |
544 | if (sunken) |
545 | qDrawWinShades(p, x, y, w, h, |
546 | c1: pal.dark().color(), c2: pal.light().color(), c3: pal.shadow().color(), |
547 | c4: pal.midlight().color(), fill); |
548 | else |
549 | qDrawWinShades(p, x, y, w, h, |
550 | c1: pal.light().color(), c2: pal.shadow().color(), c3: pal.midlight().color(), |
551 | c4: pal.dark().color(), fill); |
552 | } |
553 | |
554 | /*! |
555 | \fn void qDrawPlainRect(QPainter *painter, int x, int y, int width, int height, const QColor &lineColor, |
556 | int lineWidth, const QBrush *fill) |
557 | \relates <qdrawutil.h> |
558 | |
559 | Draws the plain rectangle beginning at (\a x, \a y) with the given |
560 | \a width and \a height, using the specified \a painter, \a lineColor |
561 | and \a lineWidth. The rectangle's interior is filled with the \a |
562 | fill brush unless \a fill is \nullptr. |
563 | |
564 | \warning This function does not look at QWidget::style() or |
565 | QApplication::style(). Use the drawing functions in QStyle to make |
566 | widgets that follow the current GUI style. |
567 | |
568 | Alternatively you can use a QFrame widget and apply the |
569 | QFrame::setFrameStyle() function to display a plain rectangle: |
570 | |
571 | \snippet code/src_gui_painting_qdrawutil.cpp 4 |
572 | |
573 | \sa qDrawShadeRect(), QStyle |
574 | */ |
575 | |
576 | void qDrawPlainRect(QPainter *p, int x, int y, int w, int h, const QColor &c, |
577 | int lineWidth, const QBrush *fill) |
578 | { |
579 | if (w == 0 || h == 0) |
580 | return; |
581 | if (Q_UNLIKELY(w < 0 || h < 0 || lineWidth < 0)) { |
582 | qWarning(msg: "qDrawPlainRect: Invalid parameters" ); |
583 | } |
584 | |
585 | PainterStateGuard painterGuard(p); |
586 | const qreal devicePixelRatio = p->device()->devicePixelRatio(); |
587 | if (!qFuzzyCompare(p1: devicePixelRatio, p2: qreal(1))) { |
588 | painterGuard.save(); |
589 | const qreal inverseScale = qreal(1) / devicePixelRatio; |
590 | p->scale(sx: inverseScale, sy: inverseScale); |
591 | x = qRound(d: devicePixelRatio * x); |
592 | y = qRound(d: devicePixelRatio * y); |
593 | w = devicePixelRatio * w; |
594 | h = devicePixelRatio * h; |
595 | lineWidth = qRound(d: devicePixelRatio * lineWidth); |
596 | p->translate(dx: 0.5, dy: 0.5); |
597 | } |
598 | |
599 | QPen oldPen = p->pen(); |
600 | QBrush oldBrush = p->brush(); |
601 | p->setPen(c); |
602 | p->setBrush(Qt::NoBrush); |
603 | for (int i=0; i<lineWidth; i++) |
604 | p->drawRect(x: x+i, y: y+i, w: w-i*2 - 1, h: h-i*2 - 1); |
605 | if (fill) { // fill with fill color |
606 | p->setPen(Qt::NoPen); |
607 | p->setBrush(*fill); |
608 | p->drawRect(x: x+lineWidth, y: y+lineWidth, w: w-lineWidth*2, h: h-lineWidth*2); |
609 | } |
610 | p->setPen(oldPen); |
611 | p->setBrush(oldBrush); |
612 | } |
613 | |
614 | /***************************************************************************** |
615 | Overloaded functions. |
616 | *****************************************************************************/ |
617 | |
618 | /*! |
619 | \fn void qDrawShadeLine(QPainter *painter, const QPoint &p1, const QPoint &p2, |
620 | const QPalette &palette, bool sunken, int lineWidth, int midLineWidth) |
621 | \relates <qdrawutil.h> |
622 | \overload |
623 | |
624 | Draws a horizontal or vertical shaded line between \a p1 and \a p2 |
625 | using the given \a painter. Note that nothing is drawn if the line |
626 | between the points would be neither horizontal nor vertical. |
627 | |
628 | The provided \a palette specifies the shading colors (\l |
629 | {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l |
630 | {QPalette::mid()}{middle} colors). The given \a lineWidth |
631 | specifies the line width for each of the lines; it is not the |
632 | total line width. The given \a midLineWidth specifies the width of |
633 | a middle line drawn in the QPalette::mid() color. |
634 | |
635 | The line appears sunken if \a sunken is true, otherwise raised. |
636 | |
637 | \warning This function does not look at QWidget::style() or |
638 | QApplication::style(). Use the drawing functions in QStyle to |
639 | make widgets that follow the current GUI style. |
640 | |
641 | |
642 | Alternatively you can use a QFrame widget and apply the |
643 | QFrame::setFrameStyle() function to display a shaded line: |
644 | |
645 | \snippet code/src_gui_painting_qdrawutil.cpp 5 |
646 | |
647 | \sa qDrawShadeRect(), qDrawShadePanel(), QStyle |
648 | */ |
649 | |
650 | void qDrawShadeLine(QPainter *p, const QPoint &p1, const QPoint &p2, |
651 | const QPalette &pal, bool sunken, |
652 | int lineWidth, int midLineWidth) |
653 | { |
654 | qDrawShadeLine(p, x1: p1.x(), y1: p1.y(), x2: p2.x(), y2: p2.y(), pal, sunken, |
655 | lineWidth, midLineWidth); |
656 | } |
657 | |
658 | /*! |
659 | \fn void qDrawShadeRect(QPainter *painter, const QRect &rect, const QPalette &palette, |
660 | bool sunken, int lineWidth, int midLineWidth, const QBrush *fill) |
661 | \relates <qdrawutil.h> |
662 | \overload |
663 | |
664 | Draws the shaded rectangle specified by \a rect using the given \a painter. |
665 | |
666 | The provide \a palette specifies the shading colors (\l |
667 | {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l |
668 | {QPalette::mid()}{middle} colors. The given \a lineWidth |
669 | specifies the line width for each of the lines; it is not the |
670 | total line width. The \a midLineWidth specifies the width of a |
671 | middle line drawn in the QPalette::mid() color. The rectangle's |
672 | interior is filled with the \a fill brush unless \a fill is \nullptr. |
673 | |
674 | The rectangle appears sunken if \a sunken is true, otherwise |
675 | raised. |
676 | |
677 | \warning This function does not look at QWidget::style() or |
678 | QApplication::style(). Use the drawing functions in QStyle to make |
679 | widgets that follow the current GUI style. |
680 | |
681 | Alternatively you can use a QFrame widget and apply the |
682 | QFrame::setFrameStyle() function to display a shaded rectangle: |
683 | |
684 | \snippet code/src_gui_painting_qdrawutil.cpp 6 |
685 | |
686 | \sa qDrawShadeLine(), qDrawShadePanel(), qDrawPlainRect(), QStyle |
687 | */ |
688 | |
689 | void qDrawShadeRect(QPainter *p, const QRect &r, |
690 | const QPalette &pal, bool sunken, |
691 | int lineWidth, int midLineWidth, |
692 | const QBrush *fill) |
693 | { |
694 | qDrawShadeRect(p, x: r.x(), y: r.y(), w: r.width(), h: r.height(), pal, sunken, |
695 | lineWidth, midLineWidth, fill); |
696 | } |
697 | |
698 | /*! |
699 | \fn void qDrawShadePanel(QPainter *painter, const QRect &rect, const QPalette &palette, |
700 | bool sunken, int lineWidth, const QBrush *fill) |
701 | \relates <qdrawutil.h> |
702 | \overload |
703 | |
704 | Draws the shaded panel at the rectangle specified by \a rect using the |
705 | given \a painter and the given \a lineWidth. |
706 | |
707 | The given \a palette specifies the shading colors (\l |
708 | {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l |
709 | {QPalette::mid()}{middle} colors). The panel's interior is filled |
710 | with the \a fill brush unless \a fill is \nullptr. |
711 | |
712 | The panel appears sunken if \a sunken is true, otherwise raised. |
713 | |
714 | \warning This function does not look at QWidget::style() or |
715 | QApplication::style(). Use the drawing functions in QStyle to make |
716 | widgets that follow the current GUI style. |
717 | |
718 | Alternatively you can use a QFrame widget and apply the |
719 | QFrame::setFrameStyle() function to display a shaded panel: |
720 | |
721 | \snippet code/src_gui_painting_qdrawutil.cpp 7 |
722 | |
723 | \sa qDrawWinPanel(), qDrawShadeLine(), qDrawShadeRect(), QStyle |
724 | */ |
725 | |
726 | void qDrawShadePanel(QPainter *p, const QRect &r, |
727 | const QPalette &pal, bool sunken, |
728 | int lineWidth, const QBrush *fill) |
729 | { |
730 | qDrawShadePanel(p, x: r.x(), y: r.y(), w: r.width(), h: r.height(), pal, sunken, |
731 | lineWidth, fill); |
732 | } |
733 | |
734 | /*! |
735 | \fn void qDrawWinButton(QPainter *painter, const QRect &rect, const QPalette &palette, |
736 | bool sunken, const QBrush *fill) |
737 | \relates <qdrawutil.h> |
738 | \overload |
739 | |
740 | Draws the Windows-style button at the rectangle specified by \a rect using |
741 | the given \a painter with a line width of 2 pixels. The button's interior |
742 | is filled with the \a{fill} brush unless \a fill is \nullptr. |
743 | |
744 | The given \a palette specifies the shading colors (\l |
745 | {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l |
746 | {QPalette::mid()}{middle} colors). |
747 | |
748 | The button appears sunken if \a sunken is true, otherwise raised. |
749 | |
750 | \warning This function does not look at QWidget::style() or |
751 | QApplication::style()-> Use the drawing functions in QStyle to make |
752 | widgets that follow the current GUI style. |
753 | |
754 | \sa qDrawWinPanel(), QStyle |
755 | */ |
756 | |
757 | void qDrawWinButton(QPainter *p, const QRect &r, |
758 | const QPalette &pal, bool sunken, const QBrush *fill) |
759 | { |
760 | qDrawWinButton(p, x: r.x(), y: r.y(), w: r.width(), h: r.height(), pal, sunken, fill); |
761 | } |
762 | |
763 | /*! |
764 | \fn void qDrawWinPanel(QPainter *painter, const QRect &rect, const QPalette &palette, |
765 | bool sunken, const QBrush *fill) |
766 | \relates <qdrawutil.h> |
767 | \overload |
768 | |
769 | Draws the Windows-style panel at the rectangle specified by \a rect using |
770 | the given \a painter with a line width of 2 pixels. The button's interior |
771 | is filled with the \a fill brush unless \a fill is \nullptr. |
772 | |
773 | The given \a palette specifies the shading colors. The panel |
774 | appears sunken if \a sunken is true, otherwise raised. |
775 | |
776 | \warning This function does not look at QWidget::style() or |
777 | QApplication::style(). Use the drawing functions in QStyle to make |
778 | widgets that follow the current GUI style. |
779 | |
780 | Alternatively you can use a QFrame widget and apply the |
781 | QFrame::setFrameStyle() function to display a shaded panel: |
782 | |
783 | \snippet code/src_gui_painting_qdrawutil.cpp 8 |
784 | |
785 | \sa qDrawShadePanel(), qDrawWinButton(), QStyle |
786 | */ |
787 | |
788 | void qDrawWinPanel(QPainter *p, const QRect &r, |
789 | const QPalette &pal, bool sunken, const QBrush *fill) |
790 | { |
791 | qDrawWinPanel(p, x: r.x(), y: r.y(), w: r.width(), h: r.height(), pal, sunken, fill); |
792 | } |
793 | |
794 | /*! |
795 | \fn void qDrawPlainRect(QPainter *painter, const QRect &rect, const QColor &lineColor, int lineWidth, const QBrush *fill) |
796 | \relates <qdrawutil.h> |
797 | \overload |
798 | |
799 | Draws the plain rectangle specified by \a rect using the given \a painter, |
800 | \a lineColor and \a lineWidth. The rectangle's interior is filled with the |
801 | \a fill brush unless \a fill is \nullptr. |
802 | |
803 | \warning This function does not look at QWidget::style() or |
804 | QApplication::style(). Use the drawing functions in QStyle to make |
805 | widgets that follow the current GUI style. |
806 | |
807 | Alternatively you can use a QFrame widget and apply the |
808 | QFrame::setFrameStyle() function to display a plain rectangle: |
809 | |
810 | \snippet code/src_gui_painting_qdrawutil.cpp 9 |
811 | |
812 | \sa qDrawShadeRect(), QStyle |
813 | */ |
814 | |
815 | void qDrawPlainRect(QPainter *p, const QRect &r, const QColor &c, |
816 | int lineWidth, const QBrush *fill) |
817 | { |
818 | qDrawPlainRect(p, x: r.x(), y: r.y(), w: r.width(), h: r.height(), c, |
819 | lineWidth, fill); |
820 | } |
821 | |
822 | |
823 | /*! |
824 | \class QTileRules |
825 | \since 4.6 |
826 | |
827 | \inmodule QtWidgets |
828 | |
829 | \brief The QTileRules class provides the rules used to draw a |
830 | pixmap or image split into nine segments. |
831 | |
832 | Spliiting is similar to \l{http://www.w3.org/TR/css3-background/}{CSS3 border-images}. |
833 | |
834 | \sa Qt::TileRule, QMargins |
835 | */ |
836 | |
837 | /*! \fn QTileRules::QTileRules(Qt::TileRule horizontalRule, Qt::TileRule verticalRule) |
838 | Constructs a QTileRules with the given \a horizontalRule and |
839 | \a verticalRule. |
840 | */ |
841 | |
842 | /*! \fn QTileRules::QTileRules(Qt::TileRule rule) |
843 | Constructs a QTileRules with the given \a rule used for both |
844 | the horizontal rule and the vertical rule. |
845 | */ |
846 | |
847 | /*! |
848 | \fn void qDrawBorderPixmap(QPainter *painter, const QRect &target, const QMargins &margins, const QPixmap &pixmap) |
849 | \relates <qdrawutil.h> |
850 | \since 4.6 |
851 | |
852 | \brief The qDrawBorderPixmap function is for drawing a pixmap into |
853 | the margins of a rectangle. |
854 | |
855 | Draws the given \a pixmap into the given \a target rectangle, using the |
856 | given \a painter. The pixmap will be split into nine segments and drawn |
857 | according to the \a margins structure. |
858 | */ |
859 | |
860 | typedef QVarLengthArray<QPainter::PixmapFragment, 16> QPixmapFragmentsArray; |
861 | |
862 | /*! |
863 | \relates <qdrawutil.h> |
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 | QT_END_NAMESPACE |
1139 | |