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 | \fn void qDrawShadePanel(QPainter *painter, int x, int y, int width, int height, |
302 | const QPalette &palette, bool sunken, |
303 | int lineWidth, const QBrush *fill) |
304 | \relates <qdrawutil.h> |
305 | |
306 | Draws the shaded panel beginning at (\a x, \a y) with the given \a |
307 | width and \a height using the provided \a painter and the given \a |
308 | lineWidth. |
309 | |
310 | The given \a palette specifies the shading colors (\l |
311 | {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l |
312 | {QPalette::mid()}{middle} colors). The panel's interior is filled |
313 | with the \a fill brush unless \a fill is \nullptr. |
314 | |
315 | The panel appears sunken if \a sunken is true, otherwise raised. |
316 | |
317 | \warning This function does not look at QWidget::style() or |
318 | QApplication::style(). Use the drawing functions in QStyle to make |
319 | widgets that follow the current GUI style. |
320 | |
321 | Alternatively you can use a QFrame widget and apply the |
322 | QFrame::setFrameStyle() function to display a shaded panel: |
323 | |
324 | \snippet code/src_gui_painting_qdrawutil.cpp 2 |
325 | |
326 | \sa qDrawWinPanel(), qDrawShadeLine(), qDrawShadeRect(), QStyle |
327 | */ |
328 | |
329 | void qDrawShadePanel(QPainter *p, int x, int y, int w, int h, |
330 | const QPalette &pal, bool sunken, |
331 | int lineWidth, const QBrush *fill) |
332 | { |
333 | if (w == 0 || h == 0) |
334 | return; |
335 | if (Q_UNLIKELY(w < 0 || h < 0 || lineWidth < 0)) { |
336 | qWarning(msg: "qDrawShadePanel: Invalid parameters" ); |
337 | } |
338 | |
339 | PainterStateGuard painterGuard(p); |
340 | const qreal devicePixelRatio = p->device()->devicePixelRatio(); |
341 | bool isTranslated = false; |
342 | if (!qFuzzyCompare(p1: devicePixelRatio, p2: qreal(1))) { |
343 | painterGuard.save(); |
344 | const qreal inverseScale = qreal(1) / devicePixelRatio; |
345 | p->scale(sx: inverseScale, sy: inverseScale); |
346 | x = qRound(d: devicePixelRatio * x); |
347 | y = qRound(d: devicePixelRatio * y); |
348 | w = devicePixelRatio * w; |
349 | h = devicePixelRatio * h; |
350 | lineWidth = qRound(d: devicePixelRatio * lineWidth); |
351 | p->translate(dx: 0.5, dy: 0.5); |
352 | isTranslated = true; |
353 | } |
354 | |
355 | QColor shade = pal.dark().color(); |
356 | QColor light = pal.light().color(); |
357 | if (fill) { |
358 | if (fill->color() == shade) |
359 | shade = pal.shadow().color(); |
360 | if (fill->color() == light) |
361 | light = pal.midlight().color(); |
362 | } |
363 | QPen oldPen = p->pen(); // save pen |
364 | QList<QLineF> lines; |
365 | lines.reserve(asize: 2*lineWidth); |
366 | |
367 | if (sunken) |
368 | p->setPen(shade); |
369 | else |
370 | p->setPen(light); |
371 | int x1, y1, x2, y2; |
372 | int i; |
373 | x1 = x; |
374 | y1 = y2 = y; |
375 | x2 = x+w-2; |
376 | for (i=0; i<lineWidth; i++) { // top shadow |
377 | lines << QLineF(x1, y1++, x2--, y2++); |
378 | } |
379 | x2 = x1; |
380 | y1 = y+h-2; |
381 | for (i=0; i<lineWidth; i++) { // left shado |
382 | lines << QLineF(x1++, y1, x2++, y2--); |
383 | } |
384 | p->drawLines(lines); |
385 | lines.clear(); |
386 | if (sunken) |
387 | p->setPen(light); |
388 | else |
389 | p->setPen(shade); |
390 | x1 = x; |
391 | y1 = y2 = y+h-1; |
392 | x2 = x+w-1; |
393 | for (i=0; i<lineWidth; i++) { // bottom shadow |
394 | lines << QLineF(x1++, y1--, x2, y2--); |
395 | } |
396 | x1 = x2; |
397 | y1 = y; |
398 | y2 = y+h-lineWidth-1; |
399 | for (i=0; i<lineWidth; i++) { // right shadow |
400 | lines << QLineF(x1--, y1++, x2--, y2); |
401 | } |
402 | p->drawLines(lines); |
403 | if (fill) { // fill with fill color |
404 | if (isTranslated) |
405 | p->translate(dx: -0.5, dy: -0.5); |
406 | p->fillRect(x: x+lineWidth, y: y+lineWidth, w: w-lineWidth*2, h: h-lineWidth*2, b: *fill); |
407 | } |
408 | p->setPen(oldPen); // restore pen |
409 | } |
410 | |
411 | /*! |
412 | \internal |
413 | This function draws a rectangle with two pixel line width. |
414 | It is called from qDrawWinButton() and qDrawWinPanel(). |
415 | |
416 | c1..c4 and fill are used: |
417 | |
418 | 1 1 1 1 1 2 |
419 | 1 3 3 3 4 2 |
420 | 1 3 F F 4 2 |
421 | 1 3 F F 4 2 |
422 | 1 4 4 4 4 2 |
423 | 2 2 2 2 2 2 |
424 | */ |
425 | |
426 | static void qDrawWinShades(QPainter *p, |
427 | int x, int y, int w, int h, |
428 | const QColor &c1, const QColor &c2, |
429 | const QColor &c3, const QColor &c4, |
430 | const QBrush *fill) |
431 | { |
432 | if (w < 2 || h < 2) // can't do anything with that |
433 | return; |
434 | |
435 | PainterStateGuard painterGuard(p); |
436 | const qreal devicePixelRatio = p->device()->devicePixelRatio(); |
437 | bool isTranslated = false; |
438 | if (!qFuzzyCompare(p1: devicePixelRatio, p2: qreal(1))) { |
439 | painterGuard.save(); |
440 | const qreal inverseScale = qreal(1) / devicePixelRatio; |
441 | p->scale(sx: inverseScale, sy: inverseScale); |
442 | x = qRound(d: devicePixelRatio * x); |
443 | y = qRound(d: devicePixelRatio * y); |
444 | w = devicePixelRatio * w; |
445 | h = devicePixelRatio * h; |
446 | p->translate(dx: 0.5, dy: 0.5); |
447 | isTranslated = true; |
448 | } |
449 | |
450 | QPen oldPen = p->pen(); |
451 | QPoint a[3] = { QPoint(x, y+h-2), QPoint(x, y), QPoint(x+w-2, y) }; |
452 | p->setPen(c1); |
453 | p->drawPolyline(points: a, pointCount: 3); |
454 | QPoint b[3] = { QPoint(x, y+h-1), QPoint(x+w-1, y+h-1), QPoint(x+w-1, y) }; |
455 | p->setPen(c2); |
456 | p->drawPolyline(points: b, pointCount: 3); |
457 | if (w > 4 && h > 4) { |
458 | QPoint c[3] = { QPoint(x+1, y+h-3), QPoint(x+1, y+1), QPoint(x+w-3, y+1) }; |
459 | p->setPen(c3); |
460 | p->drawPolyline(points: c, pointCount: 3); |
461 | QPoint d[3] = { QPoint(x+1, y+h-2), QPoint(x+w-2, y+h-2), QPoint(x+w-2, y+1) }; |
462 | p->setPen(c4); |
463 | p->drawPolyline(points: d, pointCount: 3); |
464 | if (fill) { |
465 | if (isTranslated) |
466 | p->translate(dx: -0.5, dy: -0.5); |
467 | p->fillRect(QRect(x+2, y+2, w-4, h-4), *fill); |
468 | } |
469 | } |
470 | p->setPen(oldPen); |
471 | } |
472 | |
473 | |
474 | /*! |
475 | \fn void qDrawWinButton(QPainter *painter, int x, int y, int width, int height, |
476 | const QPalette &palette, bool sunken, |
477 | const QBrush *fill) |
478 | \relates <qdrawutil.h> |
479 | |
480 | Draws the Windows-style button specified by the given point (\a x, |
481 | \a y}, \a width and \a height using the provided \a painter with a |
482 | line width of 2 pixels. The button's interior is filled with the |
483 | \a{fill} brush unless \a fill is \nullptr. |
484 | |
485 | The given \a palette specifies the shading colors (\l |
486 | {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l |
487 | {QPalette::mid()}{middle} colors). |
488 | |
489 | The button appears sunken if \a sunken is true, otherwise raised. |
490 | |
491 | \warning This function does not look at QWidget::style() or |
492 | QApplication::style()-> Use the drawing functions in QStyle to make |
493 | widgets that follow the current GUI style. |
494 | |
495 | \sa qDrawWinPanel(), QStyle |
496 | */ |
497 | |
498 | void qDrawWinButton(QPainter *p, int x, int y, int w, int h, |
499 | const QPalette &pal, bool sunken, |
500 | const QBrush *fill) |
501 | { |
502 | if (sunken) |
503 | qDrawWinShades(p, x, y, w, h, |
504 | c1: pal.shadow().color(), c2: pal.light().color(), c3: pal.dark().color(), |
505 | c4: pal.button().color(), fill); |
506 | else |
507 | qDrawWinShades(p, x, y, w, h, |
508 | c1: pal.light().color(), c2: pal.shadow().color(), c3: pal.button().color(), |
509 | c4: pal.dark().color(), fill); |
510 | } |
511 | |
512 | /*! |
513 | \fn void qDrawWinPanel(QPainter *painter, int x, int y, int width, int height, |
514 | const QPalette &palette, bool sunken, |
515 | const QBrush *fill) |
516 | \relates <qdrawutil.h> |
517 | |
518 | Draws the Windows-style panel specified by the given point(\a x, |
519 | \a y), \a width and \a height using the provided \a painter with a |
520 | line width of 2 pixels. The button's interior is filled with the |
521 | \a fill brush unless \a fill is \nullptr. |
522 | |
523 | The given \a palette specifies the shading colors. The panel |
524 | appears sunken if \a sunken is true, otherwise raised. |
525 | |
526 | \warning This function does not look at QWidget::style() or |
527 | QApplication::style(). Use the drawing functions in QStyle to make |
528 | widgets that follow the current GUI style. |
529 | |
530 | Alternatively you can use a QFrame widget and apply the |
531 | QFrame::setFrameStyle() function to display a shaded panel: |
532 | |
533 | \snippet code/src_gui_painting_qdrawutil.cpp 3 |
534 | |
535 | \sa qDrawShadePanel(), qDrawWinButton(), QStyle |
536 | */ |
537 | |
538 | void qDrawWinPanel(QPainter *p, int x, int y, int w, int h, |
539 | const QPalette &pal, bool sunken, |
540 | const QBrush *fill) |
541 | { |
542 | if (sunken) |
543 | qDrawWinShades(p, x, y, w, h, |
544 | c1: pal.dark().color(), c2: pal.light().color(), c3: pal.shadow().color(), |
545 | c4: pal.midlight().color(), fill); |
546 | else |
547 | qDrawWinShades(p, x, y, w, h, |
548 | c1: pal.light().color(), c2: pal.shadow().color(), c3: pal.midlight().color(), |
549 | c4: pal.dark().color(), fill); |
550 | } |
551 | |
552 | /*! |
553 | \fn void qDrawPlainRect(QPainter *painter, int x, int y, int width, int height, const QColor &lineColor, |
554 | int lineWidth, const QBrush *fill) |
555 | \relates <qdrawutil.h> |
556 | |
557 | Draws the plain rectangle beginning at (\a x, \a y) with the given |
558 | \a width and \a height, using the specified \a painter, \a lineColor |
559 | and \a lineWidth. The rectangle's interior is filled with the \a |
560 | fill brush unless \a fill is \nullptr. |
561 | |
562 | \warning This function does not look at QWidget::style() or |
563 | QApplication::style(). Use the drawing functions in QStyle to make |
564 | widgets that follow the current GUI style. |
565 | |
566 | Alternatively you can use a QFrame widget and apply the |
567 | QFrame::setFrameStyle() function to display a plain rectangle: |
568 | |
569 | \snippet code/src_gui_painting_qdrawutil.cpp 4 |
570 | |
571 | \sa qDrawShadeRect(), QStyle |
572 | */ |
573 | |
574 | void qDrawPlainRect(QPainter *p, int x, int y, int w, int h, const QColor &c, |
575 | int lineWidth, const QBrush *fill) |
576 | { |
577 | if (w == 0 || h == 0) |
578 | return; |
579 | if (Q_UNLIKELY(w < 0 || h < 0 || lineWidth < 0)) { |
580 | qWarning(msg: "qDrawPlainRect: Invalid parameters" ); |
581 | return; |
582 | } |
583 | |
584 | PainterStateGuard painterGuard(p); |
585 | painterGuard.save(); |
586 | const qreal devicePixelRatio = p->device()->devicePixelRatio(); |
587 | if (!qFuzzyCompare(p1: devicePixelRatio, p2: qreal(1))) { |
588 | const qreal inverseScale = qreal(1) / devicePixelRatio; |
589 | p->scale(sx: inverseScale, sy: inverseScale); |
590 | x = qRound(d: devicePixelRatio * x); |
591 | y = qRound(d: devicePixelRatio * y); |
592 | w = devicePixelRatio * w; |
593 | h = devicePixelRatio * h; |
594 | lineWidth = qRound(d: devicePixelRatio * lineWidth); |
595 | p->translate(dx: 0.5, dy: 0.5); |
596 | } |
597 | |
598 | p->setPen(c); |
599 | p->setBrush(Qt::NoBrush); |
600 | for (int i=0; i<lineWidth; i++) |
601 | p->drawRect(x: x+i, y: y+i, w: w-i*2 - 1, h: h-i*2 - 1); |
602 | if (fill) { // fill with fill color |
603 | p->setPen(Qt::NoPen); |
604 | p->setBrush(*fill); |
605 | p->drawRect(x: x+lineWidth, y: y+lineWidth, w: w-lineWidth*2, h: h-lineWidth*2); |
606 | } |
607 | } |
608 | |
609 | /*! |
610 | \fn void qDrawPlainRoundedRect(QPainter *painter, int x, int y, |
611 | int width, int height, qreal rx, qreal ry, |
612 | const QColor &lineColor, int lineWidth, |
613 | const QBrush *fill) |
614 | \since 6.7 |
615 | \relates <qdrawutil.h> |
616 | |
617 | Draws the plain rounded rectangle beginning at (\a x, \a y) |
618 | with the given \a width and \a height, |
619 | using the horizontal \a rx and vertical radius \a ry, |
620 | specified \a painter, \a lineColor and \a lineWidth. |
621 | The rectangle's interior is filled with the \a |
622 | fill brush unless \a fill is \nullptr. |
623 | |
624 | \warning This function does not look at QWidget::style() or |
625 | QApplication::style(). Use the drawing functions in QStyle to make |
626 | widgets that follow the current GUI style. |
627 | |
628 | Alternatively you can use a QFrame widget and apply the |
629 | QFrame::setFrameStyle() function to display a plain rectangle: |
630 | |
631 | \snippet code/src_gui_painting_qdrawutil.cpp 4 |
632 | |
633 | \sa qDrawShadeRect(), QStyle |
634 | */ |
635 | |
636 | // ### Qt7: Pass QPen instead of QColor for frame drawing |
637 | void qDrawPlainRoundedRect(QPainter *p, int x, int y, int w, int h, |
638 | qreal rx, qreal ry, const QColor &c, |
639 | int lineWidth, const QBrush *fill) |
640 | { |
641 | if (w == 0 || h == 0) |
642 | return; |
643 | if (Q_UNLIKELY(w < 0 || h < 0 || lineWidth < 0)) { |
644 | qWarning(msg: "qDrawPlainRect: Invalid parameters" ); |
645 | return; |
646 | } |
647 | |
648 | PainterStateGuard painterGuard(p); |
649 | painterGuard.save(); |
650 | const qreal devicePixelRatio = p->device()->devicePixelRatio(); |
651 | if (!qFuzzyCompare(p1: devicePixelRatio, p2: qreal(1))) { |
652 | const qreal inverseScale = qreal(1) / devicePixelRatio; |
653 | p->scale(sx: inverseScale, sy: inverseScale); |
654 | x = qRound(d: devicePixelRatio * x); |
655 | y = qRound(d: devicePixelRatio * y); |
656 | w = devicePixelRatio * w; |
657 | h = devicePixelRatio * h; |
658 | lineWidth = qRound(d: devicePixelRatio * lineWidth); |
659 | p->translate(dx: 0.5, dy: 0.5); |
660 | } |
661 | |
662 | p->setPen(c); |
663 | p->setBrush(Qt::NoBrush); |
664 | for (int i=0; i<lineWidth; i++) { |
665 | QRectF rect(x+i, y+i, w-i*2 - 1, h-i*2 - 1); |
666 | rect.marginsRemoved(margins: QMarginsF(0.5,0.5,0.5,0.5)); |
667 | p->drawRoundedRect(rect, xRadius: rx, yRadius: ry); |
668 | } |
669 | if (fill) { // fill with fill color |
670 | p->setPen(Qt::NoPen); |
671 | p->setBrush(*fill); |
672 | p->drawRoundedRect(x: x+lineWidth, y: y+lineWidth, w: w-lineWidth*2, h: h-lineWidth*2, xRadius: rx, yRadius: ry); |
673 | } |
674 | } |
675 | |
676 | /***************************************************************************** |
677 | Overloaded functions. |
678 | *****************************************************************************/ |
679 | |
680 | /*! |
681 | \fn void qDrawShadeLine(QPainter *painter, const QPoint &p1, const QPoint &p2, |
682 | const QPalette &palette, bool sunken, int lineWidth, int midLineWidth) |
683 | \relates <qdrawutil.h> |
684 | \overload |
685 | |
686 | Draws a horizontal or vertical shaded line between \a p1 and \a p2 |
687 | using the given \a painter. Note that nothing is drawn if the line |
688 | between the points would be neither horizontal nor vertical. |
689 | |
690 | The provided \a palette specifies the shading colors (\l |
691 | {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l |
692 | {QPalette::mid()}{middle} colors). The given \a lineWidth |
693 | specifies the line width for each of the lines; it is not the |
694 | total line width. The given \a midLineWidth specifies the width of |
695 | a middle line drawn in the QPalette::mid() color. |
696 | |
697 | The line appears sunken if \a sunken is true, otherwise raised. |
698 | |
699 | \warning This function does not look at QWidget::style() or |
700 | QApplication::style(). Use the drawing functions in QStyle to |
701 | make widgets that follow the current GUI style. |
702 | |
703 | |
704 | Alternatively you can use a QFrame widget and apply the |
705 | QFrame::setFrameStyle() function to display a shaded line: |
706 | |
707 | \snippet code/src_gui_painting_qdrawutil.cpp 5 |
708 | |
709 | \sa qDrawShadeRect(), qDrawShadePanel(), QStyle |
710 | */ |
711 | |
712 | void qDrawShadeLine(QPainter *p, const QPoint &p1, const QPoint &p2, |
713 | const QPalette &pal, bool sunken, |
714 | int lineWidth, int midLineWidth) |
715 | { |
716 | qDrawShadeLine(p, x1: p1.x(), y1: p1.y(), x2: p2.x(), y2: p2.y(), pal, sunken, |
717 | lineWidth, midLineWidth); |
718 | } |
719 | |
720 | /*! |
721 | \fn void qDrawShadeRect(QPainter *painter, const QRect &rect, const QPalette &palette, |
722 | bool sunken, int lineWidth, int midLineWidth, const QBrush *fill) |
723 | \relates <qdrawutil.h> |
724 | \overload |
725 | |
726 | Draws the shaded rectangle specified by \a rect using the given \a painter. |
727 | |
728 | The provide \a palette specifies the shading colors (\l |
729 | {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l |
730 | {QPalette::mid()}{middle} colors. The given \a lineWidth |
731 | specifies the line width for each of the lines; it is not the |
732 | total line width. The \a midLineWidth specifies the width of a |
733 | middle line drawn in the QPalette::mid() color. The rectangle's |
734 | interior is filled with the \a fill brush unless \a fill is \nullptr. |
735 | |
736 | The rectangle appears sunken if \a sunken is true, otherwise |
737 | raised. |
738 | |
739 | \warning This function does not look at QWidget::style() or |
740 | QApplication::style(). Use the drawing functions in QStyle to make |
741 | widgets that follow the current GUI style. |
742 | |
743 | Alternatively you can use a QFrame widget and apply the |
744 | QFrame::setFrameStyle() function to display a shaded rectangle: |
745 | |
746 | \snippet code/src_gui_painting_qdrawutil.cpp 6 |
747 | |
748 | \sa qDrawShadeLine(), qDrawShadePanel(), qDrawPlainRect(), QStyle |
749 | */ |
750 | |
751 | void qDrawShadeRect(QPainter *p, const QRect &r, |
752 | const QPalette &pal, bool sunken, |
753 | int lineWidth, int midLineWidth, |
754 | const QBrush *fill) |
755 | { |
756 | qDrawShadeRect(p, x: r.x(), y: r.y(), w: r.width(), h: r.height(), pal, sunken, |
757 | lineWidth, midLineWidth, fill); |
758 | } |
759 | |
760 | /*! |
761 | \fn void qDrawShadePanel(QPainter *painter, const QRect &rect, const QPalette &palette, |
762 | bool sunken, int lineWidth, const QBrush *fill) |
763 | \relates <qdrawutil.h> |
764 | \overload |
765 | |
766 | Draws the shaded panel at the rectangle specified by \a rect using the |
767 | given \a painter and the given \a lineWidth. |
768 | |
769 | The given \a palette specifies the shading colors (\l |
770 | {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l |
771 | {QPalette::mid()}{middle} colors). The panel's interior is filled |
772 | with the \a fill brush unless \a fill is \nullptr. |
773 | |
774 | The panel appears sunken if \a sunken is true, otherwise raised. |
775 | |
776 | \warning This function does not look at QWidget::style() or |
777 | QApplication::style(). Use the drawing functions in QStyle to make |
778 | widgets that follow the current GUI style. |
779 | |
780 | Alternatively you can use a QFrame widget and apply the |
781 | QFrame::setFrameStyle() function to display a shaded panel: |
782 | |
783 | \snippet code/src_gui_painting_qdrawutil.cpp 7 |
784 | |
785 | \sa qDrawWinPanel(), qDrawShadeLine(), qDrawShadeRect(), QStyle |
786 | */ |
787 | |
788 | void qDrawShadePanel(QPainter *p, const QRect &r, |
789 | const QPalette &pal, bool sunken, |
790 | int lineWidth, const QBrush *fill) |
791 | { |
792 | qDrawShadePanel(p, x: r.x(), y: r.y(), w: r.width(), h: r.height(), pal, sunken, |
793 | lineWidth, fill); |
794 | } |
795 | |
796 | /*! |
797 | \fn void qDrawWinButton(QPainter *painter, const QRect &rect, const QPalette &palette, |
798 | bool sunken, const QBrush *fill) |
799 | \relates <qdrawutil.h> |
800 | \overload |
801 | |
802 | Draws the Windows-style button at the rectangle specified by \a rect using |
803 | the given \a painter with a line width of 2 pixels. The button's interior |
804 | is filled with the \a{fill} brush unless \a fill is \nullptr. |
805 | |
806 | The given \a palette specifies the shading colors (\l |
807 | {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l |
808 | {QPalette::mid()}{middle} colors). |
809 | |
810 | The button appears sunken if \a sunken is true, otherwise raised. |
811 | |
812 | \warning This function does not look at QWidget::style() or |
813 | QApplication::style()-> Use the drawing functions in QStyle to make |
814 | widgets that follow the current GUI style. |
815 | |
816 | \sa qDrawWinPanel(), QStyle |
817 | */ |
818 | |
819 | void qDrawWinButton(QPainter *p, const QRect &r, |
820 | const QPalette &pal, bool sunken, const QBrush *fill) |
821 | { |
822 | qDrawWinButton(p, x: r.x(), y: r.y(), w: r.width(), h: r.height(), pal, sunken, fill); |
823 | } |
824 | |
825 | /*! |
826 | \fn void qDrawWinPanel(QPainter *painter, const QRect &rect, const QPalette &palette, |
827 | bool sunken, const QBrush *fill) |
828 | \relates <qdrawutil.h> |
829 | \overload |
830 | |
831 | Draws the Windows-style panel at the rectangle specified by \a rect using |
832 | the given \a painter with a line width of 2 pixels. The button's interior |
833 | is filled with the \a fill brush unless \a fill is \nullptr. |
834 | |
835 | The given \a palette specifies the shading colors. The panel |
836 | appears sunken if \a sunken is true, otherwise raised. |
837 | |
838 | \warning This function does not look at QWidget::style() or |
839 | QApplication::style(). Use the drawing functions in QStyle to make |
840 | widgets that follow the current GUI style. |
841 | |
842 | Alternatively you can use a QFrame widget and apply the |
843 | QFrame::setFrameStyle() function to display a shaded panel: |
844 | |
845 | \snippet code/src_gui_painting_qdrawutil.cpp 8 |
846 | |
847 | \sa qDrawShadePanel(), qDrawWinButton(), QStyle |
848 | */ |
849 | |
850 | void qDrawWinPanel(QPainter *p, const QRect &r, |
851 | const QPalette &pal, bool sunken, const QBrush *fill) |
852 | { |
853 | qDrawWinPanel(p, x: r.x(), y: r.y(), w: r.width(), h: r.height(), pal, sunken, fill); |
854 | } |
855 | |
856 | /*! |
857 | \fn void qDrawPlainRect(QPainter *painter, const QRect &rect, const QColor &lineColor, int lineWidth, const QBrush *fill) |
858 | \relates <qdrawutil.h> |
859 | \overload |
860 | |
861 | Draws the plain rectangle specified by \a rect using the given \a painter, |
862 | \a lineColor and \a lineWidth. The rectangle's interior is filled with the |
863 | \a fill brush unless \a fill is \nullptr. |
864 | |
865 | \warning This function does not look at QWidget::style() or |
866 | QApplication::style(). Use the drawing functions in QStyle to make |
867 | widgets that follow the current GUI style. |
868 | |
869 | Alternatively you can use a QFrame widget and apply the |
870 | QFrame::setFrameStyle() function to display a plain rectangle: |
871 | |
872 | \snippet code/src_gui_painting_qdrawutil.cpp 9 |
873 | |
874 | \sa qDrawShadeRect(), QStyle |
875 | */ |
876 | |
877 | void qDrawPlainRect(QPainter *p, const QRect &r, const QColor &c, |
878 | int lineWidth, const QBrush *fill) |
879 | { |
880 | qDrawPlainRect(p, x: r.x(), y: r.y(), w: r.width(), h: r.height(), c, |
881 | lineWidth, fill); |
882 | } |
883 | |
884 | /*! |
885 | \fn void qDrawPlainRoundedRect(QPainter *painter, const QRect &rect, |
886 | qreal rx, qreal ry, |
887 | const QColor &lineColor, int lineWidth, |
888 | const QBrush *fill) |
889 | \since 6.7 |
890 | \relates <qdrawutil.h> |
891 | \overload |
892 | |
893 | Draws the plain rectangle specified by \a rect using |
894 | the horizontal \a rx and vertical radius \a ry, |
895 | the given \a painter, \a lineColor and \a lineWidth. |
896 | The rectangle's interior is filled with the |
897 | \a fill brush unless \a fill is \nullptr. |
898 | |
899 | \warning This function does not look at QWidget::style() or |
900 | QApplication::style(). Use the drawing functions in QStyle to make |
901 | widgets that follow the current GUI style. |
902 | |
903 | Alternatively you can use a QFrame widget and apply the |
904 | QFrame::setFrameStyle() function to display a plain rectangle: |
905 | |
906 | \snippet code/src_gui_painting_qdrawutil.cpp 9 |
907 | |
908 | \sa qDrawShadeRect(), QStyle |
909 | */ |
910 | |
911 | /*! |
912 | \class QTileRules |
913 | \since 4.6 |
914 | |
915 | \inmodule QtWidgets |
916 | |
917 | \brief The QTileRules class provides the rules used to draw a |
918 | pixmap or image split into nine segments. |
919 | |
920 | Spliiting is similar to \l{http://www.w3.org/TR/css3-background/}{CSS3 border-images}. |
921 | |
922 | \sa Qt::TileRule, QMargins |
923 | */ |
924 | |
925 | /*! \fn QTileRules::QTileRules(Qt::TileRule horizontalRule, Qt::TileRule verticalRule) |
926 | Constructs a QTileRules with the given \a horizontalRule and |
927 | \a verticalRule. |
928 | */ |
929 | |
930 | /*! \fn QTileRules::QTileRules(Qt::TileRule rule) |
931 | Constructs a QTileRules with the given \a rule used for both |
932 | the horizontal rule and the vertical rule. |
933 | */ |
934 | |
935 | /*! |
936 | \fn void qDrawBorderPixmap(QPainter *painter, const QRect &target, const QMargins &margins, const QPixmap &pixmap) |
937 | \relates <qdrawutil.h> |
938 | \since 4.6 |
939 | |
940 | \brief The qDrawBorderPixmap function is for drawing a pixmap into |
941 | the margins of a rectangle. |
942 | |
943 | Draws the given \a pixmap into the given \a target rectangle, using the |
944 | given \a painter. The pixmap will be split into nine segments and drawn |
945 | according to the \a margins structure. |
946 | */ |
947 | |
948 | typedef QVarLengthArray<QPainter::PixmapFragment, 16> QPixmapFragmentsArray; |
949 | |
950 | /*! |
951 | \relates <qdrawutil.h> |
952 | \since 4.6 |
953 | |
954 | Draws the indicated \a sourceRect rectangle from the given \a pixmap into |
955 | the given \a targetRect rectangle, using the given \a painter. The pixmap |
956 | will be split into nine segments according to the given \a targetMargins |
957 | and \a sourceMargins structures. Finally, the pixmap will be drawn |
958 | according to the given \a rules. |
959 | |
960 | This function is used to draw a scaled pixmap, similar to |
961 | \l{http://www.w3.org/TR/css3-background/}{CSS3 border-images} |
962 | |
963 | \sa Qt::TileRule, QTileRules, QMargins |
964 | */ |
965 | |
966 | void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargins &targetMargins, |
967 | const QPixmap &pixmap, const QRect &sourceRect,const QMargins &sourceMargins, |
968 | const QTileRules &rules |
969 | #ifndef Q_QDOC |
970 | , QDrawBorderPixmap::DrawingHints hints |
971 | #endif |
972 | ) |
973 | { |
974 | QPainter::PixmapFragment d; |
975 | d.opacity = 1.0; |
976 | d.rotation = 0.0; |
977 | |
978 | QPixmapFragmentsArray opaqueData; |
979 | QPixmapFragmentsArray translucentData; |
980 | |
981 | // source center |
982 | const int sourceCenterTop = sourceRect.top() + sourceMargins.top(); |
983 | const int sourceCenterLeft = sourceRect.left() + sourceMargins.left(); |
984 | const int sourceCenterBottom = sourceRect.bottom() - sourceMargins.bottom() + 1; |
985 | const int sourceCenterRight = sourceRect.right() - sourceMargins.right() + 1; |
986 | const int sourceCenterWidth = sourceCenterRight - sourceCenterLeft; |
987 | const int sourceCenterHeight = sourceCenterBottom - sourceCenterTop; |
988 | // target center |
989 | const int targetCenterTop = targetRect.top() + targetMargins.top(); |
990 | const int targetCenterLeft = targetRect.left() + targetMargins.left(); |
991 | const int targetCenterBottom = targetRect.bottom() - targetMargins.bottom() + 1; |
992 | const int targetCenterRight = targetRect.right() - targetMargins.right() + 1; |
993 | const int targetCenterWidth = targetCenterRight - targetCenterLeft; |
994 | const int targetCenterHeight = targetCenterBottom - targetCenterTop; |
995 | |
996 | QVarLengthArray<qreal, 16> xTarget; // x-coordinates of target rectangles |
997 | QVarLengthArray<qreal, 16> yTarget; // y-coordinates of target rectangles |
998 | |
999 | int columns = 3; |
1000 | int rows = 3; |
1001 | if (rules.horizontal != Qt::StretchTile && sourceCenterWidth != 0) |
1002 | columns = qMax(a: 3, b: 2 + qCeil(v: targetCenterWidth / qreal(sourceCenterWidth))); |
1003 | if (rules.vertical != Qt::StretchTile && sourceCenterHeight != 0) |
1004 | rows = qMax(a: 3, b: 2 + qCeil(v: targetCenterHeight / qreal(sourceCenterHeight))); |
1005 | |
1006 | xTarget.resize(sz: columns + 1); |
1007 | yTarget.resize(sz: rows + 1); |
1008 | |
1009 | bool oldAA = painter->testRenderHint(hint: QPainter::Antialiasing); |
1010 | if (painter->paintEngine()->type() != QPaintEngine::OpenGL |
1011 | && painter->paintEngine()->type() != QPaintEngine::OpenGL2 |
1012 | && oldAA && painter->combinedTransform().type() != QTransform::TxNone) { |
1013 | painter->setRenderHint(hint: QPainter::Antialiasing, on: false); |
1014 | } |
1015 | |
1016 | xTarget[0] = targetRect.left(); |
1017 | xTarget[1] = targetCenterLeft; |
1018 | xTarget[columns - 1] = targetCenterRight; |
1019 | xTarget[columns] = targetRect.left() + targetRect.width(); |
1020 | |
1021 | yTarget[0] = targetRect.top(); |
1022 | yTarget[1] = targetCenterTop; |
1023 | yTarget[rows - 1] = targetCenterBottom; |
1024 | yTarget[rows] = targetRect.top() + targetRect.height(); |
1025 | |
1026 | qreal dx = targetCenterWidth; |
1027 | qreal dy = targetCenterHeight; |
1028 | |
1029 | switch (rules.horizontal) { |
1030 | case Qt::StretchTile: |
1031 | dx = targetCenterWidth; |
1032 | break; |
1033 | case Qt::RepeatTile: |
1034 | dx = sourceCenterWidth; |
1035 | break; |
1036 | case Qt::RoundTile: |
1037 | dx = targetCenterWidth / qreal(columns - 2); |
1038 | break; |
1039 | } |
1040 | |
1041 | for (int i = 2; i < columns - 1; ++i) |
1042 | xTarget[i] = xTarget[i - 1] + dx; |
1043 | |
1044 | switch (rules.vertical) { |
1045 | case Qt::StretchTile: |
1046 | dy = targetCenterHeight; |
1047 | break; |
1048 | case Qt::RepeatTile: |
1049 | dy = sourceCenterHeight; |
1050 | break; |
1051 | case Qt::RoundTile: |
1052 | dy = targetCenterHeight / qreal(rows - 2); |
1053 | break; |
1054 | } |
1055 | |
1056 | for (int i = 2; i < rows - 1; ++i) |
1057 | yTarget[i] = yTarget[i - 1] + dy; |
1058 | |
1059 | // corners |
1060 | if (targetMargins.top() > 0 && targetMargins.left() > 0 && sourceMargins.top() > 0 && sourceMargins.left() > 0) { // top left |
1061 | d.x = (0.5 * (xTarget[1] + xTarget[0])); |
1062 | d.y = (0.5 * (yTarget[1] + yTarget[0])); |
1063 | d.sourceLeft = sourceRect.left(); |
1064 | d.sourceTop = sourceRect.top(); |
1065 | d.width = sourceMargins.left(); |
1066 | d.height = sourceMargins.top(); |
1067 | d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width; |
1068 | d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height; |
1069 | if (hints & QDrawBorderPixmap::OpaqueTopLeft) |
1070 | opaqueData.append(t: d); |
1071 | else |
1072 | translucentData.append(t: d); |
1073 | } |
1074 | if (targetMargins.top() > 0 && targetMargins.right() > 0 && sourceMargins.top() > 0 && sourceMargins.right() > 0) { // top right |
1075 | d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1])); |
1076 | d.y = (0.5 * (yTarget[1] + yTarget[0])); |
1077 | d.sourceLeft = sourceCenterRight; |
1078 | d.sourceTop = sourceRect.top(); |
1079 | d.width = sourceMargins.right(); |
1080 | d.height = sourceMargins.top(); |
1081 | d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width; |
1082 | d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height; |
1083 | if (hints & QDrawBorderPixmap::OpaqueTopRight) |
1084 | opaqueData.append(t: d); |
1085 | else |
1086 | translucentData.append(t: d); |
1087 | } |
1088 | if (targetMargins.bottom() > 0 && targetMargins.left() > 0 && sourceMargins.bottom() > 0 && sourceMargins.left() > 0) { // bottom left |
1089 | d.x = (0.5 * (xTarget[1] + xTarget[0])); |
1090 | d.y =(0.5 * (yTarget[rows] + yTarget[rows - 1])); |
1091 | d.sourceLeft = sourceRect.left(); |
1092 | d.sourceTop = sourceCenterBottom; |
1093 | d.width = sourceMargins.left(); |
1094 | d.height = sourceMargins.bottom(); |
1095 | d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width; |
1096 | d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height; |
1097 | if (hints & QDrawBorderPixmap::OpaqueBottomLeft) |
1098 | opaqueData.append(t: d); |
1099 | else |
1100 | translucentData.append(t: d); |
1101 | } |
1102 | if (targetMargins.bottom() > 0 && targetMargins.right() > 0 && sourceMargins.bottom() > 0 && sourceMargins.right() > 0) { // bottom right |
1103 | d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1])); |
1104 | d.y = (0.5 * (yTarget[rows] + yTarget[rows - 1])); |
1105 | d.sourceLeft = sourceCenterRight; |
1106 | d.sourceTop = sourceCenterBottom; |
1107 | d.width = sourceMargins.right(); |
1108 | d.height = sourceMargins.bottom(); |
1109 | d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width; |
1110 | d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height; |
1111 | if (hints & QDrawBorderPixmap::OpaqueBottomRight) |
1112 | opaqueData.append(t: d); |
1113 | else |
1114 | translucentData.append(t: d); |
1115 | } |
1116 | |
1117 | // horizontal edges |
1118 | if (targetCenterWidth > 0 && sourceCenterWidth > 0) { |
1119 | if (targetMargins.top() > 0 && sourceMargins.top() > 0) { // top |
1120 | QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueTop ? opaqueData : translucentData; |
1121 | d.sourceLeft = sourceCenterLeft; |
1122 | d.sourceTop = sourceRect.top(); |
1123 | d.width = sourceCenterWidth; |
1124 | d.height = sourceMargins.top(); |
1125 | d.y = (0.5 * (yTarget[1] + yTarget[0])); |
1126 | d.scaleX = dx / d.width; |
1127 | d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height; |
1128 | for (int i = 1; i < columns - 1; ++i) { |
1129 | d.x = (0.5 * (xTarget[i + 1] + xTarget[i])); |
1130 | data.append(t: d); |
1131 | } |
1132 | if (rules.horizontal == Qt::RepeatTile) |
1133 | data[data.size() - 1].width = ((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX); |
1134 | } |
1135 | if (targetMargins.bottom() > 0 && sourceMargins.bottom() > 0) { // bottom |
1136 | QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueBottom ? opaqueData : translucentData; |
1137 | d.sourceLeft = sourceCenterLeft; |
1138 | d.sourceTop = sourceCenterBottom; |
1139 | d.width = sourceCenterWidth; |
1140 | d.height = sourceMargins.bottom(); |
1141 | d.y = (0.5 * (yTarget[rows] + yTarget[rows - 1])); |
1142 | d.scaleX = dx / d.width; |
1143 | d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height; |
1144 | for (int i = 1; i < columns - 1; ++i) { |
1145 | d.x = (0.5 * (xTarget[i + 1] + xTarget[i])); |
1146 | data.append(t: d); |
1147 | } |
1148 | if (rules.horizontal == Qt::RepeatTile) |
1149 | data[data.size() - 1].width = ((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX); |
1150 | } |
1151 | } |
1152 | |
1153 | // vertical edges |
1154 | if (targetCenterHeight > 0 && sourceCenterHeight > 0) { |
1155 | if (targetMargins.left() > 0 && sourceMargins.left() > 0) { // left |
1156 | QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueLeft ? opaqueData : translucentData; |
1157 | d.sourceLeft = sourceRect.left(); |
1158 | d.sourceTop = sourceCenterTop; |
1159 | d.width = sourceMargins.left(); |
1160 | d.height = sourceCenterHeight; |
1161 | d.x = (0.5 * (xTarget[1] + xTarget[0])); |
1162 | d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width; |
1163 | d.scaleY = dy / d.height; |
1164 | for (int i = 1; i < rows - 1; ++i) { |
1165 | d.y = (0.5 * (yTarget[i + 1] + yTarget[i])); |
1166 | data.append(t: d); |
1167 | } |
1168 | if (rules.vertical == Qt::RepeatTile) |
1169 | data[data.size() - 1].height = ((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY); |
1170 | } |
1171 | if (targetMargins.right() > 0 && sourceMargins.right() > 0) { // right |
1172 | QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueRight ? opaqueData : translucentData; |
1173 | d.sourceLeft = sourceCenterRight; |
1174 | d.sourceTop = sourceCenterTop; |
1175 | d.width = sourceMargins.right(); |
1176 | d.height = sourceCenterHeight; |
1177 | d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1])); |
1178 | d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width; |
1179 | d.scaleY = dy / d.height; |
1180 | for (int i = 1; i < rows - 1; ++i) { |
1181 | d.y = (0.5 * (yTarget[i + 1] + yTarget[i])); |
1182 | data.append(t: d); |
1183 | } |
1184 | if (rules.vertical == Qt::RepeatTile) |
1185 | data[data.size() - 1].height = ((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY); |
1186 | } |
1187 | } |
1188 | |
1189 | // center |
1190 | if (targetCenterWidth > 0 && targetCenterHeight > 0 && sourceCenterWidth > 0 && sourceCenterHeight > 0) { |
1191 | QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueCenter ? opaqueData : translucentData; |
1192 | d.sourceLeft = sourceCenterLeft; |
1193 | d.sourceTop = sourceCenterTop; |
1194 | d.width = sourceCenterWidth; |
1195 | d.height = sourceCenterHeight; |
1196 | d.scaleX = dx / d.width; |
1197 | d.scaleY = dy / d.height; |
1198 | |
1199 | qreal repeatWidth = (xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX; |
1200 | qreal repeatHeight = (yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY; |
1201 | |
1202 | for (int j = 1; j < rows - 1; ++j) { |
1203 | d.y = (0.5 * (yTarget[j + 1] + yTarget[j])); |
1204 | for (int i = 1; i < columns - 1; ++i) { |
1205 | d.x = (0.5 * (xTarget[i + 1] + xTarget[i])); |
1206 | data.append(t: d); |
1207 | } |
1208 | if (rules.horizontal == Qt::RepeatTile) |
1209 | data[data.size() - 1].width = repeatWidth; |
1210 | } |
1211 | if (rules.vertical == Qt::RepeatTile) { |
1212 | for (int i = 1; i < columns - 1; ++i) |
1213 | data[data.size() - i].height = repeatHeight; |
1214 | } |
1215 | } |
1216 | |
1217 | if (opaqueData.size()) |
1218 | painter->drawPixmapFragments(fragments: opaqueData.data(), fragmentCount: opaqueData.size(), pixmap, hints: QPainter::OpaqueHint); |
1219 | if (translucentData.size()) |
1220 | painter->drawPixmapFragments(fragments: translucentData.data(), fragmentCount: translucentData.size(), pixmap); |
1221 | |
1222 | if (oldAA) |
1223 | painter->setRenderHint(hint: QPainter::Antialiasing, on: true); |
1224 | } |
1225 | |
1226 | QT_END_NAMESPACE |
1227 | |