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