source: trunk/src/gui/painting/qdrawutil.cpp@ 659

Last change on this file since 659 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 51.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qdrawutil.h"
43#include "qbitmap.h"
44#include "qpixmapcache.h"
45#include "qapplication.h"
46#include "qpainter.h"
47#include "qpalette.h"
48#include <private/qpaintengineex_p.h>
49#include <qvarlengtharray.h>
50#include <qmath.h>
51
52QT_BEGIN_NAMESPACE
53
54/*!
55 \headerfile <qdrawutil.h>
56 \title Drawing Utility Functions
57
58 \sa QPainter
59*/
60
61/*!
62 \fn void qDrawShadeLine(QPainter *painter, int x1, int y1, int x2, int y2,
63 const QPalette &palette, bool sunken,
64 int lineWidth, int midLineWidth)
65 \relates <qdrawutil.h>
66
67 Draws a horizontal (\a y1 == \a y2) or vertical (\a x1 == \a x2)
68 shaded line using the given \a painter. Note that nothing is
69 drawn if \a y1 != \a y2 and \a x1 != \a x2 (i.e. the line is
70 neither horizontal nor vertical).
71
72 The provided \a palette specifies the shading colors (\l
73 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
74 {QPalette::mid()}{middle} colors). The given \a lineWidth
75 specifies the line width for each of the lines; it is not the
76 total line width. The given \a midLineWidth specifies the width of
77 a middle line drawn in the QPalette::mid() color.
78
79 The line appears sunken if \a sunken is true, otherwise raised.
80
81 \warning This function does not look at QWidget::style() or
82 QApplication::style(). Use the drawing functions in QStyle to
83 make widgets that follow the current GUI style.
84
85
86 Alternatively you can use a QFrame widget and apply the
87 QFrame::setFrameStyle() function to display a shaded line:
88
89 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 0
90
91 \sa qDrawShadeRect(), qDrawShadePanel(), QStyle
92*/
93
94void qDrawShadeLine(QPainter *p, int x1, int y1, int x2, int y2,
95 const QPalette &pal, bool sunken,
96 int lineWidth, int midLineWidth)
97{
98 if (!(p && lineWidth >= 0 && midLineWidth >= 0)) {
99 qWarning("qDrawShadeLine: Invalid parameters");
100 return;
101 }
102 int tlw = lineWidth*2 + midLineWidth; // total line width
103 QPen oldPen = p->pen(); // save pen
104 if (sunken)
105 p->setPen(pal.color(QPalette::Dark));
106 else
107 p->setPen(pal.light().color());
108 QPolygon a;
109 int i;
110 if (y1 == y2) { // horizontal line
111 int y = y1 - tlw/2;
112 if (x1 > x2) { // swap x1 and x2
113 int t = x1;
114 x1 = x2;
115 x2 = t;
116 }
117 x2--;
118 for (i=0; i<lineWidth; i++) { // draw top shadow
119 a.setPoints(3, x1+i, y+tlw-1-i,
120 x1+i, y+i,
121 x2-i, y+i);
122 p->drawPolyline(a);
123 }
124 if (midLineWidth > 0) {
125 p->setPen(pal.mid().color());
126 for (i=0; i<midLineWidth; i++) // draw lines in the middle
127 p->drawLine(x1+lineWidth, y+lineWidth+i,
128 x2-lineWidth, y+lineWidth+i);
129 }
130 if (sunken)
131 p->setPen(pal.light().color());
132 else
133 p->setPen(pal.dark().color());
134 for (i=0; i<lineWidth; i++) { // draw bottom shadow
135 a.setPoints(3, x1+i, y+tlw-i-1,
136 x2-i, y+tlw-i-1,
137 x2-i, y+i+1);
138 p->drawPolyline(a);
139 }
140 }
141 else if (x1 == x2) { // vertical line
142 int x = x1 - tlw/2;
143 if (y1 > y2) { // swap y1 and y2
144 int t = y1;
145 y1 = y2;
146 y2 = t;
147 }
148 y2--;
149 for (i=0; i<lineWidth; i++) { // draw left shadow
150 a.setPoints(3, x+i, y2,
151 x+i, y1+i,
152 x+tlw-1, y1+i);
153 p->drawPolyline(a);
154 }
155 if (midLineWidth > 0) {
156 p->setPen(pal.mid().color());
157 for (i=0; i<midLineWidth; i++) // draw lines in the middle
158 p->drawLine(x+lineWidth+i, y1+lineWidth, x+lineWidth+i, y2);
159 }
160 if (sunken)
161 p->setPen(pal.light().color());
162 else
163 p->setPen(pal.dark().color());
164 for (i=0; i<lineWidth; i++) { // draw right shadow
165 a.setPoints(3, x+lineWidth, y2-i,
166 x+tlw-i-1, y2-i,
167 x+tlw-i-1, y1+lineWidth);
168 p->drawPolyline(a);
169 }
170 }
171 p->setPen(oldPen);
172}
173
174/*!
175 \fn void qDrawShadeRect(QPainter *painter, int x, int y, int width, int height,
176 const QPalette &palette, bool sunken,
177 int lineWidth, int midLineWidth,
178 const QBrush *fill)
179 \relates <qdrawutil.h>
180
181 Draws the shaded rectangle beginning at (\a x, \a y) with the
182 given \a width and \a height using the provided \a painter.
183
184 The provide \a palette specifies the shading colors (\l
185 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
186 {QPalette::mid()}{middle} colors. The given \a lineWidth
187 specifies the line width for each of the lines; it is not the
188 total line width. The \a midLineWidth specifies the width of a
189 middle line drawn in the QPalette::mid() color. The rectangle's
190 interior is filled with the \a fill brush unless \a fill is 0.
191
192 The rectangle appears sunken if \a sunken is true, otherwise
193 raised.
194
195 \warning This function does not look at QWidget::style() or
196 QApplication::style(). Use the drawing functions in QStyle to make
197 widgets that follow the current GUI style.
198
199 Alternatively you can use a QFrame widget and apply the
200 QFrame::setFrameStyle() function to display a shaded rectangle:
201
202 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 1
203
204 \sa qDrawShadeLine(), qDrawShadePanel(), qDrawPlainRect(), QStyle
205*/
206
207void qDrawShadeRect(QPainter *p, int x, int y, int w, int h,
208 const QPalette &pal, bool sunken,
209 int lineWidth, int midLineWidth,
210 const QBrush *fill)
211{
212 if (w == 0 || h == 0)
213 return;
214 if (! (w > 0 && h > 0 && lineWidth >= 0 && midLineWidth >= 0)) {
215 qWarning("qDrawShadeRect: Invalid parameters");
216 return;
217 }
218 QPen oldPen = p->pen();
219 if (sunken)
220 p->setPen(pal.dark().color());
221 else
222 p->setPen(pal.light().color());
223 int x1=x, y1=y, x2=x+w-1, y2=y+h-1;
224
225 if (lineWidth == 1 && midLineWidth == 0) {// standard shade rectangle
226 p->drawRect(x1, y1, w-2, h-2);
227 if (sunken)
228 p->setPen(pal.light().color());
229 else
230 p->setPen(pal.dark().color());
231 QLineF lines[4] = { QLineF(x1+1, y1+1, x2-2, y1+1),
232 QLineF(x1+1, y1+2, x1+1, y2-2),
233 QLineF(x1, y2, x2, y2),
234 QLineF(x2,y1, x2,y2-1) };
235 p->drawLines(lines, 4); // draw bottom/right lines
236 } else { // more complicated
237 int m = lineWidth+midLineWidth;
238 int i, j=0, k=m;
239 for (i=0; i<lineWidth; i++) { // draw top shadow
240 QLineF lines[4] = { QLineF(x1+i, y2-i, x1+i, y1+i),
241 QLineF(x1+i, y1+i, x2-i, y1+i),
242 QLineF(x1+k, y2-k, x2-k, y2-k),
243 QLineF(x2-k, y2-k, x2-k, y1+k) };
244 p->drawLines(lines, 4);
245 k++;
246 }
247 p->setPen(pal.mid().color());
248 j = lineWidth*2;
249 for (i=0; i<midLineWidth; i++) { // draw lines in the middle
250 p->drawRect(x1+lineWidth+i, y1+lineWidth+i, w-j-1, h-j-1);
251 j += 2;
252 }
253 if (sunken)
254 p->setPen(pal.light().color());
255 else
256 p->setPen(pal.dark().color());
257 k = m;
258 for (i=0; i<lineWidth; i++) { // draw bottom shadow
259 QLineF lines[4] = { QLineF(x1+1+i, y2-i, x2-i, y2-i),
260 QLineF(x2-i, y2-i, x2-i, y1+i+1),
261 QLineF(x1+k, y2-k, x1+k, y1+k),
262 QLineF(x1+k, y1+k, x2-k, y1+k) };
263 p->drawLines(lines, 4);
264 k++;
265 }
266 }
267 if (fill) {
268 QBrush oldBrush = p->brush();
269 int tlw = lineWidth + midLineWidth;
270 p->setPen(Qt::NoPen);
271 p->setBrush(*fill);
272 p->drawRect(x+tlw, y+tlw, w-2*tlw, h-2*tlw);
273 p->setBrush(oldBrush);
274 }
275 p->setPen(oldPen); // restore pen
276}
277
278
279/*!
280 \fn void qDrawShadePanel(QPainter *painter, int x, int y, int width, int height,
281 const QPalette &palette, bool sunken,
282 int lineWidth, const QBrush *fill)
283 \relates <qdrawutil.h>
284
285 Draws the shaded panel beginning at (\a x, \a y) with the given \a
286 width and \a height using the provided \a painter and the given \a
287 lineWidth.
288
289 The given \a palette specifies the shading colors (\l
290 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
291 {QPalette::mid()}{middle} colors). The panel's interior is filled
292 with the \a fill brush unless \a fill is 0.
293
294 The panel appears sunken if \a sunken is true, otherwise raised.
295
296 \warning This function does not look at QWidget::style() or
297 QApplication::style(). Use the drawing functions in QStyle to make
298 widgets that follow the current GUI style.
299
300 Alternatively you can use a QFrame widget and apply the
301 QFrame::setFrameStyle() function to display a shaded panel:
302
303 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 2
304
305 \sa qDrawWinPanel(), qDrawShadeLine(), qDrawShadeRect(), QStyle
306*/
307
308void qDrawShadePanel(QPainter *p, int x, int y, int w, int h,
309 const QPalette &pal, bool sunken,
310 int lineWidth, const QBrush *fill)
311{
312 if (w == 0 || h == 0)
313 return;
314 if (!(w > 0 && h > 0 && lineWidth >= 0)) {
315 qWarning("qDrawShadePanel: Invalid parameters");
316 }
317 QColor shade = pal.dark().color();
318 QColor light = pal.light().color();
319 if (fill) {
320 if (fill->color() == shade)
321 shade = pal.shadow().color();
322 if (fill->color() == light)
323 light = pal.midlight().color();
324 }
325 QPen oldPen = p->pen(); // save pen
326 QVector<QLineF> lines;
327 lines.reserve(2*lineWidth);
328
329 if (sunken)
330 p->setPen(shade);
331 else
332 p->setPen(light);
333 int x1, y1, x2, y2;
334 int i;
335 x1 = x;
336 y1 = y2 = y;
337 x2 = x+w-2;
338 for (i=0; i<lineWidth; i++) { // top shadow
339 lines << QLineF(x1, y1++, x2--, y2++);
340 }
341 x2 = x1;
342 y1 = y+h-2;
343 for (i=0; i<lineWidth; i++) { // left shado
344 lines << QLineF(x1++, y1, x2++, y2--);
345 }
346 p->drawLines(lines);
347 lines.clear();
348 if (sunken)
349 p->setPen(light);
350 else
351 p->setPen(shade);
352 x1 = x;
353 y1 = y2 = y+h-1;
354 x2 = x+w-1;
355 for (i=0; i<lineWidth; i++) { // bottom shadow
356 lines << QLineF(x1++, y1--, x2, y2--);
357 }
358 x1 = x2;
359 y1 = y;
360 y2 = y+h-lineWidth-1;
361 for (i=0; i<lineWidth; i++) { // right shadow
362 lines << QLineF(x1--, y1++, x2--, y2);
363 }
364 p->drawLines(lines);
365 if (fill) // fill with fill color
366 p->fillRect(x+lineWidth, y+lineWidth, w-lineWidth*2, h-lineWidth*2, *fill);
367 p->setPen(oldPen); // restore pen
368}
369
370
371/*!
372 \internal
373 This function draws a rectangle with two pixel line width.
374 It is called from qDrawWinButton() and qDrawWinPanel().
375
376 c1..c4 and fill are used:
377
378 1 1 1 1 1 2
379 1 3 3 3 4 2
380 1 3 F F 4 2
381 1 3 F F 4 2
382 1 4 4 4 4 2
383 2 2 2 2 2 2
384*/
385
386static void qDrawWinShades(QPainter *p,
387 int x, int y, int w, int h,
388 const QColor &c1, const QColor &c2,
389 const QColor &c3, const QColor &c4,
390 const QBrush *fill)
391{
392 if (w < 2 || h < 2) // can't do anything with that
393 return;
394 QPen oldPen = p->pen();
395 QPoint a[3] = { QPoint(x, y+h-2), QPoint(x, y), QPoint(x+w-2, y) };
396 p->setPen(c1);
397 p->drawPolyline(a, 3);
398 QPoint b[3] = { QPoint(x, y+h-1), QPoint(x+w-1, y+h-1), QPoint(x+w-1, y) };
399 p->setPen(c2);
400 p->drawPolyline(b, 3);
401 if (w > 4 && h > 4) {
402 QPoint c[3] = { QPoint(x+1, y+h-3), QPoint(x+1, y+1), QPoint(x+w-3, y+1) };
403 p->setPen(c3);
404 p->drawPolyline(c, 3);
405 QPoint d[3] = { QPoint(x+1, y+h-2), QPoint(x+w-2, y+h-2), QPoint(x+w-2, y+1) };
406 p->setPen(c4);
407 p->drawPolyline(d, 3);
408 if (fill)
409 p->fillRect(QRect(x+2, y+2, w-4, h-4), *fill);
410 }
411 p->setPen(oldPen);
412}
413
414
415/*!
416 \fn void qDrawWinButton(QPainter *painter, int x, int y, int width, int height,
417 const QPalette &palette, bool sunken,
418 const QBrush *fill)
419 \relates <qdrawutil.h>
420
421 Draws the Windows-style button specified by the given point (\a x,
422 \a y}, \a width and \a height using the provided \a painter with a
423 line width of 2 pixels. The button's interior is filled with the
424 \a{fill} brush unless \a fill is 0.
425
426 The given \a palette specifies the shading colors (\l
427 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
428 {QPalette::mid()}{middle} colors).
429
430 The button appears sunken if \a sunken is true, otherwise raised.
431
432 \warning This function does not look at QWidget::style() or
433 QApplication::style()-> Use the drawing functions in QStyle to make
434 widgets that follow the current GUI style.
435
436 \sa qDrawWinPanel(), QStyle
437*/
438
439void qDrawWinButton(QPainter *p, int x, int y, int w, int h,
440 const QPalette &pal, bool sunken,
441 const QBrush *fill)
442{
443 if (sunken)
444 qDrawWinShades(p, x, y, w, h,
445 pal.shadow().color(), pal.light().color(), pal.dark().color(),
446 pal.button().color(), fill);
447 else
448 qDrawWinShades(p, x, y, w, h,
449 pal.light().color(), pal.shadow().color(), pal.button().color(),
450 pal.dark().color(), fill);
451}
452
453/*!
454 \fn void qDrawWinPanel(QPainter *painter, int x, int y, int width, int height,
455 const QPalette &palette, bool sunken,
456 const QBrush *fill)
457 \relates <qdrawutil.h>
458
459 Draws the Windows-style panel specified by the given point(\a x,
460 \a y), \a width and \a height using the provided \a painter with a
461 line width of 2 pixels. The button's interior is filled with the
462 \a fill brush unless \a fill is 0.
463
464 The given \a palette specifies the shading colors. The panel
465 appears sunken if \a sunken is true, otherwise raised.
466
467 \warning This function does not look at QWidget::style() or
468 QApplication::style(). Use the drawing functions in QStyle to make
469 widgets that follow the current GUI style.
470
471 Alternatively you can use a QFrame widget and apply the
472 QFrame::setFrameStyle() function to display a shaded panel:
473
474 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 3
475
476 \sa qDrawShadePanel(), qDrawWinButton(), QStyle
477*/
478
479void qDrawWinPanel(QPainter *p, int x, int y, int w, int h,
480 const QPalette &pal, bool sunken,
481 const QBrush *fill)
482{
483 if (sunken)
484 qDrawWinShades(p, x, y, w, h,
485 pal.dark().color(), pal.light().color(), pal.shadow().color(),
486 pal.midlight().color(), fill);
487 else
488 qDrawWinShades(p, x, y, w, h,
489 pal.light().color(), pal.shadow().color(), pal.midlight().color(),
490 pal.dark().color(), fill);
491}
492
493/*!
494 \fn void qDrawPlainRect(QPainter *painter, int x, int y, int width, int height, const QColor &lineColor,
495 int lineWidth, const QBrush *fill)
496 \relates <qdrawutil.h>
497
498 Draws the plain rectangle beginning at (\a x, \a y) with the given
499 \a width and \a height, using the specified \a painter, \a lineColor
500 and \a lineWidth. The rectangle's interior is filled with the \a
501 fill brush unless \a fill is 0.
502
503 \warning This function does not look at QWidget::style() or
504 QApplication::style(). Use the drawing functions in QStyle to make
505 widgets that follow the current GUI style.
506
507 Alternatively you can use a QFrame widget and apply the
508 QFrame::setFrameStyle() function to display a plain rectangle:
509
510 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 4
511
512 \sa qDrawShadeRect(), QStyle
513*/
514
515void qDrawPlainRect(QPainter *p, int x, int y, int w, int h, const QColor &c,
516 int lineWidth, const QBrush *fill)
517{
518 if (w == 0 || h == 0)
519 return;
520 if (!(w > 0 && h > 0 && lineWidth >= 0)) {
521 qWarning("qDrawPlainRect: Invalid parameters");
522 }
523 QPen oldPen = p->pen();
524 QBrush oldBrush = p->brush();
525 p->setPen(c);
526 p->setBrush(Qt::NoBrush);
527 for (int i=0; i<lineWidth; i++)
528 p->drawRect(x+i, y+i, w-i*2 - 1, h-i*2 - 1);
529 if (fill) { // fill with fill color
530 p->setPen(Qt::NoPen);
531 p->setBrush(*fill);
532 p->drawRect(x+lineWidth, y+lineWidth, w-lineWidth*2, h-lineWidth*2);
533 }
534 p->setPen(oldPen);
535 p->setBrush(oldBrush);
536}
537
538/*****************************************************************************
539 Overloaded functions.
540 *****************************************************************************/
541
542/*!
543 \fn void qDrawShadeLine(QPainter *painter, const QPoint &p1, const QPoint &p2,
544 const QPalette &palette, bool sunken, int lineWidth, int midLineWidth)
545 \relates <qdrawutil.h>
546 \overload
547
548 Draws a horizontal or vertical shaded line between \a p1 and \a p2
549 using the given \a painter. Note that nothing is drawn if the line
550 between the points would be neither horizontal nor vertical.
551
552 The provided \a palette specifies the shading colors (\l
553 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
554 {QPalette::mid()}{middle} colors). The given \a lineWidth
555 specifies the line width for each of the lines; it is not the
556 total line width. The given \a midLineWidth specifies the width of
557 a middle line drawn in the QPalette::mid() color.
558
559 The line appears sunken if \a sunken is true, otherwise raised.
560
561 \warning This function does not look at QWidget::style() or
562 QApplication::style(). Use the drawing functions in QStyle to
563 make widgets that follow the current GUI style.
564
565
566 Alternatively you can use a QFrame widget and apply the
567 QFrame::setFrameStyle() function to display a shaded line:
568
569 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 5
570
571 \sa qDrawShadeRect(), qDrawShadePanel(), QStyle
572*/
573
574void qDrawShadeLine(QPainter *p, const QPoint &p1, const QPoint &p2,
575 const QPalette &pal, bool sunken,
576 int lineWidth, int midLineWidth)
577{
578 qDrawShadeLine(p, p1.x(), p1.y(), p2.x(), p2.y(), pal, sunken,
579 lineWidth, midLineWidth);
580}
581
582/*!
583 \fn void qDrawShadeRect(QPainter *painter, const QRect &rect, const QPalette &palette,
584 bool sunken, int lineWidth, int midLineWidth, const QBrush *fill)
585 \relates <qdrawutil.h>
586 \overload
587
588 Draws the shaded rectangle specified by \a rect using the given \a painter.
589
590 The provide \a palette specifies the shading colors (\l
591 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
592 {QPalette::mid()}{middle} colors. The given \a lineWidth
593 specifies the line width for each of the lines; it is not the
594 total line width. The \a midLineWidth specifies the width of a
595 middle line drawn in the QPalette::mid() color. The rectangle's
596 interior is filled with the \a fill brush unless \a fill is 0.
597
598 The rectangle appears sunken if \a sunken is true, otherwise
599 raised.
600
601 \warning This function does not look at QWidget::style() or
602 QApplication::style(). Use the drawing functions in QStyle to make
603 widgets that follow the current GUI style.
604
605 Alternatively you can use a QFrame widget and apply the
606 QFrame::setFrameStyle() function to display a shaded rectangle:
607
608 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 6
609
610 \sa qDrawShadeLine(), qDrawShadePanel(), qDrawPlainRect(), QStyle
611*/
612
613void qDrawShadeRect(QPainter *p, const QRect &r,
614 const QPalette &pal, bool sunken,
615 int lineWidth, int midLineWidth,
616 const QBrush *fill)
617{
618 qDrawShadeRect(p, r.x(), r.y(), r.width(), r.height(), pal, sunken,
619 lineWidth, midLineWidth, fill);
620}
621
622/*!
623 \fn void qDrawShadePanel(QPainter *painter, const QRect &rect, const QPalette &palette,
624 bool sunken, int lineWidth, const QBrush *fill)
625 \relates <qdrawutil.h>
626 \overload
627
628 Draws the shaded panel at the rectangle specified by \a rect using the
629 given \a painter and the given \a lineWidth.
630
631 The given \a palette specifies the shading colors (\l
632 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
633 {QPalette::mid()}{middle} colors). The panel's interior is filled
634 with the \a fill brush unless \a fill is 0.
635
636 The panel appears sunken if \a sunken is true, otherwise raised.
637
638 \warning This function does not look at QWidget::style() or
639 QApplication::style(). Use the drawing functions in QStyle to make
640 widgets that follow the current GUI style.
641
642 Alternatively you can use a QFrame widget and apply the
643 QFrame::setFrameStyle() function to display a shaded panel:
644
645 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 7
646
647 \sa qDrawWinPanel(), qDrawShadeLine(), qDrawShadeRect(), QStyle
648*/
649
650void qDrawShadePanel(QPainter *p, const QRect &r,
651 const QPalette &pal, bool sunken,
652 int lineWidth, const QBrush *fill)
653{
654 qDrawShadePanel(p, r.x(), r.y(), r.width(), r.height(), pal, sunken,
655 lineWidth, fill);
656}
657
658/*!
659 \fn void qDrawWinButton(QPainter *painter, const QRect &rect, const QPalette &palette,
660 bool sunken, const QBrush *fill)
661 \relates <qdrawutil.h>
662 \overload
663
664 Draws the Windows-style button at the rectangle specified by \a rect using
665 the given \a painter with a line width of 2 pixels. The button's interior
666 is filled with the \a{fill} brush unless \a fill is 0.
667
668 The given \a palette specifies the shading colors (\l
669 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
670 {QPalette::mid()}{middle} colors).
671
672 The button appears sunken if \a sunken is true, otherwise raised.
673
674 \warning This function does not look at QWidget::style() or
675 QApplication::style()-> Use the drawing functions in QStyle to make
676 widgets that follow the current GUI style.
677
678 \sa qDrawWinPanel(), QStyle
679*/
680
681void qDrawWinButton(QPainter *p, const QRect &r,
682 const QPalette &pal, bool sunken, const QBrush *fill)
683{
684 qDrawWinButton(p, r.x(), r.y(), r.width(), r.height(), pal, sunken, fill);
685}
686
687/*!
688 \fn void qDrawWinPanel(QPainter *painter, const QRect &rect, const QPalette &palette,
689 bool sunken, const QBrush *fill)
690 \overload
691
692 Draws the Windows-style panel at the rectangle specified by \a rect using
693 the given \a painter with a line width of 2 pixels. The button's interior
694 is filled with the \a fill brush unless \a fill is 0.
695
696 The given \a palette specifies the shading colors. The panel
697 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 make
701 widgets that follow the current GUI style.
702
703 Alternatively you can use a QFrame widget and apply the
704 QFrame::setFrameStyle() function to display a shaded panel:
705
706 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 8
707
708 \sa qDrawShadePanel(), qDrawWinButton(), QStyle
709*/
710
711void qDrawWinPanel(QPainter *p, const QRect &r,
712 const QPalette &pal, bool sunken, const QBrush *fill)
713{
714 qDrawWinPanel(p, r.x(), r.y(), r.width(), r.height(), pal, sunken, fill);
715}
716
717/*!
718 \fn void qDrawPlainRect(QPainter *painter, const QRect &rect, const QColor &lineColor, int lineWidth, const QBrush *fill)
719 \relates <qdrawutil.h>
720 \overload
721
722 Draws the plain rectangle specified by \a rect using the given \a painter,
723 \a lineColor and \a lineWidth. The rectangle's interior is filled with the
724 \a fill brush unless \a fill is 0.
725
726 \warning This function does not look at QWidget::style() or
727 QApplication::style(). Use the drawing functions in QStyle to make
728 widgets that follow the current GUI style.
729
730 Alternatively you can use a QFrame widget and apply the
731 QFrame::setFrameStyle() function to display a plain rectangle:
732
733 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 9
734
735 \sa qDrawShadeRect(), QStyle
736*/
737
738void qDrawPlainRect(QPainter *p, const QRect &r, const QColor &c,
739 int lineWidth, const QBrush *fill)
740{
741 qDrawPlainRect(p, r.x(), r.y(), r.width(), r.height(), c,
742 lineWidth, fill);
743}
744
745#ifdef QT3_SUPPORT
746static void qDrawWinArrow(QPainter *p, Qt::ArrowType type, bool down,
747 int x, int y, int w, int h,
748 const QPalette &pal, bool enabled)
749{
750 QPolygon a; // arrow polygon
751 switch (type) {
752 case Qt::UpArrow:
753 a.setPoints(7, -3,1, 3,1, -2,0, 2,0, -1,-1, 1,-1, 0,-2);
754 break;
755 case Qt::DownArrow:
756 a.setPoints(7, -3,-1, 3,-1, -2,0, 2,0, -1,1, 1,1, 0,2);
757 break;
758 case Qt::LeftArrow:
759 a.setPoints(7, 1,-3, 1,3, 0,-2, 0,2, -1,-1, -1,1, -2,0);
760 break;
761 case Qt::RightArrow:
762 a.setPoints(7, -1,-3, -1,3, 0,-2, 0,2, 1,-1, 1,1, 2,0);
763 break;
764 default:
765 break;
766 }
767 if (a.isEmpty())
768 return;
769
770 if (down) {
771 x++;
772 y++;
773 }
774
775 QPen savePen = p->pen(); // save current pen
776 if (down)
777 p->setBrushOrigin(p->brushOrigin() + QPoint(1,1));
778 p->fillRect(x, y, w, h, pal.brush(QPalette::Button));
779 if (down)
780 p->setBrushOrigin(p->brushOrigin() - QPoint(1,1));
781 if (enabled) {
782 a.translate(x+w/2, y+h/2);
783 p->setPen(pal.foreground().color());
784 p->drawLine(a.at(0), a.at(1));
785 p->drawLine(a.at(2), a.at(2));
786 p->drawPoint(a[6]);
787 } else {
788 a.translate(x+w/2+1, y+h/2+1);
789 p->setPen(pal.light().color());
790 p->drawLine(a.at(0), a.at(1));
791 p->drawLine(a.at(2), a.at(2));
792 p->drawPoint(a[6]);
793 a.translate(-1, -1);
794 p->setPen(pal.mid().color());
795 p->drawLine(a.at(0), a.at(1));
796 p->drawLine(a.at(2), a.at(2));
797 p->drawPoint(a[6]);
798 }
799 p->setPen(savePen); // restore pen
800}
801#endif // QT3_SUPPORT
802
803#if defined(Q_CC_MSVC)
804#pragma warning(disable: 4244)
805#endif
806
807#ifdef QT3_SUPPORT
808#ifndef QT_NO_STYLE_MOTIF
809// motif arrows look the same whether they are used or not
810// is this correct?
811static void qDrawMotifArrow(QPainter *p, Qt::ArrowType type, bool down,
812 int x, int y, int w, int h,
813 const QPalette &pal, bool)
814{
815 QPolygon bFill; // fill polygon
816 QPolygon bTop; // top shadow.
817 QPolygon bBot; // bottom shadow.
818 QPolygon bLeft; // left shadow.
819 QTransform matrix; // xform matrix
820 bool vertical = type == Qt::UpArrow || type == Qt::DownArrow;
821 bool horizontal = !vertical;
822 int dim = w < h ? w : h;
823 int colspec = 0x0000; // color specification array
824
825 if (dim < 2) // too small arrow
826 return;
827
828 if (dim > 3) {
829 if (dim > 6)
830 bFill.resize(dim & 1 ? 3 : 4);
831 bTop.resize((dim/2)*2);
832 bBot.resize(dim & 1 ? dim + 1 : dim);
833 bLeft.resize(dim > 4 ? 4 : 2);
834 bLeft.putPoints(0, 2, 0,0, 0,dim-1);
835 if (dim > 4)
836 bLeft.putPoints(2, 2, 1,2, 1,dim-3);
837 bTop.putPoints(0, 4, 1,0, 1,1, 2,1, 3,1);
838 bBot.putPoints(0, 4, 1,dim-1, 1,dim-2, 2,dim-2, 3,dim-2);
839
840 for(int i=0; i<dim/2-2 ; i++) {
841 bTop.putPoints(i*2+4, 2, 2+i*2,2+i, 5+i*2, 2+i);
842 bBot.putPoints(i*2+4, 2, 2+i*2,dim-3-i, 5+i*2,dim-3-i);
843 }
844 if (dim & 1) // odd number size: extra line
845 bBot.putPoints(dim-1, 2, dim-3,dim/2, dim-1,dim/2);
846 if (dim > 6) { // dim>6: must fill interior
847 bFill.putPoints(0, 2, 1,dim-3, 1,2);
848 if (dim & 1) // if size is an odd number
849 bFill.setPoint(2, dim - 3, dim / 2);
850 else
851 bFill.putPoints(2, 2, dim-4,dim/2-1, dim-4,dim/2);
852 }
853 }
854 else {
855 if (dim == 3) { // 3x3 arrow pattern
856 bLeft.setPoints(4, 0,0, 0,2, 1,1, 1,1);
857 bTop .setPoints(2, 1,0, 1,0);
858 bBot .setPoints(2, 1,2, 2,1);
859 }
860 else { // 2x2 arrow pattern
861 bLeft.setPoints(2, 0,0, 0,1);
862 bTop .setPoints(2, 1,0, 1,0);
863 bBot .setPoints(2, 1,1, 1,1);
864 }
865 }
866
867 if (type == Qt::UpArrow || type == Qt::LeftArrow) {
868 matrix.translate(x, y);
869 if (vertical) {
870 matrix.translate(0, h - 1);
871 matrix.rotate(-90);
872 } else {
873 matrix.translate(w - 1, h - 1);
874 matrix.rotate(180);
875 }
876 if (down)
877 colspec = horizontal ? 0x2334 : 0x2343;
878 else
879 colspec = horizontal ? 0x1443 : 0x1434;
880 }
881 else if (type == Qt::DownArrow || type == Qt::RightArrow) {
882 matrix.translate(x, y);
883 if (vertical) {
884 matrix.translate(w-1, 0);
885 matrix.rotate(90);
886 }
887 if (down)
888 colspec = horizontal ? 0x2443 : 0x2434;
889 else
890 colspec = horizontal ? 0x1334 : 0x1343;
891 }
892
893 const QColor *cols[5];
894 cols[0] = 0;
895 cols[1] = &pal.button().color();
896 cols[2] = &pal.mid().color();
897 cols[3] = &pal.light().color();
898 cols[4] = &pal.dark().color();
899#define CMID *cols[(colspec>>12) & 0xf]
900#define CLEFT *cols[(colspec>>8) & 0xf]
901#define CTOP *cols[(colspec>>4) & 0xf]
902#define CBOT *cols[colspec & 0xf]
903
904 QPen savePen = p->pen(); // save current pen
905 QBrush saveBrush = p->brush(); // save current brush
906 QTransform wxm = p->transform();
907 QPen pen(Qt::NoPen);
908 const QBrush &brush = pal.brush(QPalette::Button);
909
910 p->setPen(pen);
911 p->setBrush(brush);
912 p->setTransform(matrix, true); // set transformation matrix
913 p->drawPolygon(bFill); // fill arrow
914 p->setBrush(Qt::NoBrush); // don't fill
915
916 p->setPen(CLEFT);
917 p->drawLines(bLeft);
918 p->setPen(CTOP);
919 p->drawLines(bTop);
920 p->setPen(CBOT);
921 p->drawLines(bBot);
922
923 p->setTransform(wxm);
924 p->setBrush(saveBrush); // restore brush
925 p->setPen(savePen); // restore pen
926
927#undef CMID
928#undef CLEFT
929#undef CTOP
930#undef CBOT
931}
932#endif // QT_NO_STYLE_MOTIF
933
934QRect qItemRect(QPainter *p, Qt::GUIStyle gs,
935 int x, int y, int w, int h,
936 int flags,
937 bool enabled,
938 const QPixmap *pixmap,
939 const QString& text, int len)
940{
941 QRect result;
942
943 if (pixmap) {
944 if ((flags & Qt::AlignVCenter) == Qt::AlignVCenter)
945 y += h/2 - pixmap->height()/2;
946 else if ((flags & Qt::AlignBottom) == Qt::AlignBottom)
947 y += h - pixmap->height();
948 if ((flags & Qt::AlignRight) == Qt::AlignRight)
949 x += w - pixmap->width();
950 else if ((flags & Qt::AlignHCenter) == Qt::AlignHCenter)
951 x += w/2 - pixmap->width()/2;
952 else if ((flags & Qt::AlignLeft) != Qt::AlignLeft && QApplication::isRightToLeft())
953 x += w - pixmap->width();
954 result = QRect(x, y, pixmap->width(), pixmap->height());
955 } else if (!text.isNull() && p) {
956 result = p->boundingRect(QRect(x, y, w, h), flags, text.left(len));
957 if (gs == Qt::WindowsStyle && !enabled) {
958 result.setWidth(result.width()+1);
959 result.setHeight(result.height()+1);
960 }
961 } else {
962 result = QRect(x, y, w, h);
963 }
964
965 return result;
966}
967
968void qDrawArrow(QPainter *p, Qt::ArrowType type, Qt::GUIStyle style, bool down,
969 int x, int y, int w, int h,
970 const QPalette &pal, bool enabled)
971{
972 switch (style) {
973 case Qt::WindowsStyle:
974 qDrawWinArrow(p, type, down, x, y, w, h, pal, enabled);
975 break;
976#ifndef QT_NO_STYLE_MOTIF
977 case Qt::MotifStyle:
978 qDrawMotifArrow(p, type, down, x, y, w, h, pal, enabled);
979 break;
980#endif
981 default:
982 qWarning("qDrawArrow: Requested unsupported GUI style");
983 }
984}
985
986void qDrawItem(QPainter *p, Qt::GUIStyle gs,
987 int x, int y, int w, int h,
988 int flags,
989 const QPalette &pal, bool enabled,
990 const QPixmap *pixmap,
991 const QString& text, int len , const QColor* penColor)
992{
993 p->setPen(penColor?*penColor:pal.foreground().color());
994 if (pixmap) {
995 QPixmap pm(*pixmap);
996 bool clip = (flags & Qt::TextDontClip) == 0;
997 if (clip) {
998 if (pm.width() < w && pm.height() < h)
999 clip = false;
1000 else
1001 p->setClipRect(x, y, w, h);
1002 }
1003 if ((flags & Qt::AlignVCenter) == Qt::AlignVCenter)
1004 y += h/2 - pm.height()/2;
1005 else if ((flags & Qt::AlignBottom) == Qt::AlignBottom)
1006 y += h - pm.height();
1007 if ((flags & Qt::AlignRight) == Qt::AlignRight)
1008 x += w - pm.width();
1009 else if ((flags & Qt::AlignHCenter) == Qt::AlignHCenter)
1010 x += w/2 - pm.width()/2;
1011 else if (((flags & Qt::AlignLeft) != Qt::AlignLeft) && QApplication::isRightToLeft()) // Qt::AlignAuto && rightToLeft
1012 x += w - pm.width();
1013
1014 if (!enabled) {
1015 if (pm.hasAlphaChannel()) { // pixmap with a mask
1016 pm = pm.mask();
1017 } else if (pm.depth() == 1) { // monochrome pixmap, no mask
1018 ;
1019#ifndef QT_NO_IMAGE_HEURISTIC_MASK
1020 } else { // color pixmap, no mask
1021 QString k = QString::fromLatin1("$qt-drawitem-%1").arg(pm.cacheKey());
1022 if (!QPixmapCache::find(k, pm)) {
1023 pm = pm.createHeuristicMask();
1024 pm.setMask((QBitmap&)pm);
1025 QPixmapCache::insert(k, pm);
1026 }
1027#endif
1028 }
1029 if (gs == Qt::WindowsStyle) {
1030 p->setPen(pal.light().color());
1031 p->drawPixmap(x+1, y+1, pm);
1032 p->setPen(pal.text().color());
1033 }
1034 }
1035 p->drawPixmap(x, y, pm);
1036 if (clip)
1037 p->setClipping(false);
1038 } else if (!text.isNull()) {
1039 if (gs == Qt::WindowsStyle && !enabled) {
1040 p->setPen(pal.light().color());
1041 p->drawText(x+1, y+1, w, h, flags, text.left(len));
1042 p->setPen(pal.text().color());
1043 }
1044 p->drawText(x, y, w, h, flags, text.left(len));
1045 }
1046}
1047
1048#endif
1049
1050/*!
1051 \class QTileRules
1052 \since 4.6
1053
1054 Holds the rules used to draw a pixmap or image split into nine segments,
1055 similar to \l{http://www.w3.org/TR/css3-background/}{CSS3 border-images}.
1056
1057 \sa Qt::TileRule, QMargins
1058*/
1059
1060/*! \fn QTileRules::QTileRules(Qt::TileRule horizontalRule, Qt::TileRule verticalRule)
1061 Constructs a QTileRules with the given \a horizontalRule and
1062 \a verticalRule.
1063 */
1064
1065/*! \fn QTileRules::QTileRules(Qt::TileRule rule)
1066 Constructs a QTileRules with the given \a rule used for both
1067 the horizontal rule and the vertical rule.
1068 */
1069
1070/*!
1071 \fn void qDrawBorderPixmap(QPainter *painter, const QRect &target, const QMargins &margins, const QPixmap &pixmap)
1072 \relates <qdrawutil.h>
1073 \since 4.6
1074 \overload
1075
1076 \brief The qDrawBorderPixmap function is for drawing a pixmap into
1077 the margins of a rectangle.
1078
1079 Draws the given \a pixmap into the given \a target rectangle, using the
1080 given \a painter. The pixmap will be split into nine segments and drawn
1081 according to the \a margins structure.
1082*/
1083
1084typedef QVarLengthArray<QDrawPixmaps::Data, 16> QDrawPixmapsDataArray;
1085
1086/*!
1087 \since 4.6
1088
1089 Draws the indicated \a sourceRect rectangle from the given \a pixmap into
1090 the given \a targetRect rectangle, using the given \a painter. The pixmap
1091 will be split into nine segments according to the given \a targetMargins
1092 and \a sourceMargins structures. Finally, the pixmap will be drawn
1093 according to the given \a rules.
1094
1095 This function is used to draw a scaled pixmap, similar to
1096 \l{http://www.w3.org/TR/css3-background/}{CSS3 border-images}
1097
1098 \sa Qt::TileRule, QTileRules, QMargins
1099*/
1100
1101void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargins &targetMargins,
1102 const QPixmap &pixmap, const QRect &sourceRect,const QMargins &sourceMargins,
1103 const QTileRules &rules, QDrawBorderPixmap::DrawingHints hints)
1104{
1105 QDrawPixmaps::Data d;
1106 d.opacity = 1.0;
1107 d.rotation = 0.0;
1108
1109 QDrawPixmapsDataArray opaqueData;
1110 QDrawPixmapsDataArray translucentData;
1111
1112 // source center
1113 const int sourceCenterTop = sourceRect.top() + sourceMargins.top();
1114 const int sourceCenterLeft = sourceRect.left() + sourceMargins.left();
1115 const int sourceCenterBottom = sourceRect.bottom() - sourceMargins.bottom() + 1;
1116 const int sourceCenterRight = sourceRect.right() - sourceMargins.right() + 1;
1117 const int sourceCenterWidth = sourceCenterRight - sourceCenterLeft;
1118 const int sourceCenterHeight = sourceCenterBottom - sourceCenterTop;
1119 // target center
1120 const int targetCenterTop = targetRect.top() + targetMargins.top();
1121 const int targetCenterLeft = targetRect.left() + targetMargins.left();
1122 const int targetCenterBottom = targetRect.bottom() - targetMargins.bottom() + 1;
1123 const int targetCenterRight = targetRect.right() - targetMargins.right() + 1;
1124 const int targetCenterWidth = targetCenterRight - targetCenterLeft;
1125 const int targetCenterHeight = targetCenterBottom - targetCenterTop;
1126
1127 QVarLengthArray<qreal, 16> xTarget; // x-coordinates of target rectangles
1128 QVarLengthArray<qreal, 16> yTarget; // y-coordinates of target rectangles
1129
1130 int columns = 3;
1131 int rows = 3;
1132 if (rules.horizontal != Qt::StretchTile && sourceCenterWidth != 0)
1133 columns = qMax(3, 2 + qCeil(targetCenterWidth / qreal(sourceCenterWidth)));
1134 if (rules.vertical != Qt::StretchTile && sourceCenterHeight != 0)
1135 rows = qMax(3, 2 + qCeil(targetCenterHeight / qreal(sourceCenterHeight)));
1136
1137 xTarget.resize(columns + 1);
1138 yTarget.resize(rows + 1);
1139
1140 xTarget[0] = targetRect.left();
1141 xTarget[1] = targetCenterLeft;
1142 xTarget[columns - 1] = targetCenterRight;
1143 xTarget[columns] = targetRect.left() + targetRect.width();
1144
1145 yTarget[0] = targetRect.top();
1146 yTarget[1] = targetCenterTop;
1147 yTarget[rows - 1] = targetCenterBottom;
1148 yTarget[rows] = targetRect.top() + targetRect.height();
1149
1150 qreal dx = targetCenterWidth;
1151 qreal dy = targetCenterHeight;
1152
1153 switch (rules.horizontal) {
1154 case Qt::StretchTile:
1155 dx = targetCenterWidth;
1156 break;
1157 case Qt::RepeatTile:
1158 dx = sourceCenterWidth;
1159 break;
1160 case Qt::RoundTile:
1161 dx = targetCenterWidth / qreal(columns - 2);
1162 break;
1163 }
1164
1165 for (int i = 2; i < columns - 1; ++i)
1166 xTarget[i] = xTarget[i - 1] + dx;
1167
1168 switch (rules.vertical) {
1169 case Qt::StretchTile:
1170 dy = targetCenterHeight;
1171 break;
1172 case Qt::RepeatTile:
1173 dy = sourceCenterHeight;
1174 break;
1175 case Qt::RoundTile:
1176 dy = targetCenterHeight / qreal(rows - 2);
1177 break;
1178 }
1179
1180 for (int i = 2; i < rows - 1; ++i)
1181 yTarget[i] = yTarget[i - 1] + dy;
1182
1183 // corners
1184 if (targetMargins.top() > 0 && targetMargins.left() > 0 && sourceMargins.top() > 0 && sourceMargins.left() > 0) { // top left
1185 d.point.setX(0.5 * (xTarget[1] + xTarget[0]));
1186 d.point.setY(0.5 * (yTarget[1] + yTarget[0]));
1187 d.source = QRectF(sourceRect.left(), sourceRect.top(), sourceMargins.left(), sourceMargins.top());
1188 d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.source.width();
1189 d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.source.height();
1190 if (hints & QDrawBorderPixmap::OpaqueTopLeft)
1191 opaqueData.append(d);
1192 else
1193 translucentData.append(d);
1194 }
1195 if (targetMargins.top() > 0 && targetMargins.right() > 0 && sourceMargins.top() > 0 && sourceMargins.right() > 0) { // top right
1196 d.point.setX(0.5 * (xTarget[columns] + xTarget[columns - 1]));
1197 d.point.setY(0.5 * (yTarget[1] + yTarget[0]));
1198 d.source = QRectF(sourceCenterRight, sourceRect.top(), sourceMargins.right(), sourceMargins.top());
1199 d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.source.width();
1200 d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.source.height();
1201 if (hints & QDrawBorderPixmap::OpaqueTopRight)
1202 opaqueData.append(d);
1203 else
1204 translucentData.append(d);
1205 }
1206 if (targetMargins.bottom() > 0 && targetMargins.left() > 0 && sourceMargins.bottom() > 0 && sourceMargins.left() > 0) { // bottom left
1207 d.point.setX(0.5 * (xTarget[1] + xTarget[0]));
1208 d.point.setY(0.5 * (yTarget[rows] + yTarget[rows - 1]));
1209 d.source = QRectF(sourceRect.left(), sourceCenterBottom, sourceMargins.left(), sourceMargins.bottom());
1210 d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.source.width();
1211 d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.source.height();
1212 if (hints & QDrawBorderPixmap::OpaqueBottomLeft)
1213 opaqueData.append(d);
1214 else
1215 translucentData.append(d);
1216 }
1217 if (targetMargins.bottom() > 0 && targetMargins.right() > 0 && sourceMargins.bottom() > 0 && sourceMargins.right() > 0) { // bottom right
1218 d.point.setX(0.5 * (xTarget[columns] + xTarget[columns - 1]));
1219 d.point.setY(0.5 * (yTarget[rows] + yTarget[rows - 1]));
1220 d.source = QRectF(sourceCenterRight, sourceCenterBottom, sourceMargins.right(), sourceMargins.bottom());
1221 d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.source.width();
1222 d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.source.height();
1223 if (hints & QDrawBorderPixmap::OpaqueBottomRight)
1224 opaqueData.append(d);
1225 else
1226 translucentData.append(d);
1227 }
1228
1229 // horizontal edges
1230 if (targetCenterWidth > 0 && sourceCenterWidth > 0) {
1231 if (targetMargins.top() > 0 && sourceMargins.top() > 0) { // top
1232 QDrawPixmapsDataArray &data = hints & QDrawBorderPixmap::OpaqueTop ? opaqueData : translucentData;
1233 d.source = QRectF(sourceCenterLeft, sourceRect.top(), sourceCenterWidth, sourceMargins.top());
1234 d.point.setY(0.5 * (yTarget[1] + yTarget[0]));
1235 d.scaleX = dx / d.source.width();
1236 d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.source.height();
1237 for (int i = 1; i < columns - 1; ++i) {
1238 d.point.setX(0.5 * (xTarget[i + 1] + xTarget[i]));
1239 data.append(d);
1240 }
1241 if (rules.horizontal == Qt::RepeatTile)
1242 data[data.size() - 1].source.setWidth((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX);
1243 }
1244 if (targetMargins.bottom() > 0 && sourceMargins.bottom() > 0) { // bottom
1245 QDrawPixmapsDataArray &data = hints & QDrawBorderPixmap::OpaqueBottom ? opaqueData : translucentData;
1246 d.source = QRectF(sourceCenterLeft, sourceCenterBottom, sourceCenterWidth, sourceMargins.bottom());;
1247 d.point.setY(0.5 * (yTarget[rows] + yTarget[rows - 1]));
1248 d.scaleX = dx / d.source.width();
1249 d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.source.height();
1250 for (int i = 1; i < columns - 1; ++i) {
1251 d.point.setX(0.5 * (xTarget[i + 1] + xTarget[i]));
1252 data.append(d);
1253 }
1254 if (rules.horizontal == Qt::RepeatTile)
1255 data[data.size() - 1].source.setWidth((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX);
1256 }
1257 }
1258
1259 // vertical edges
1260 if (targetCenterHeight > 0 && sourceCenterHeight > 0) {
1261 if (targetMargins.left() > 0 && sourceMargins.left() > 0) { // left
1262 QDrawPixmapsDataArray &data = hints & QDrawBorderPixmap::OpaqueLeft ? opaqueData : translucentData;
1263 d.source = QRectF(sourceRect.left(), sourceCenterTop, sourceMargins.left(), sourceCenterHeight);
1264 d.point.setX(0.5 * (xTarget[1] + xTarget[0]));
1265 d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.source.width();
1266 d.scaleY = dy / d.source.height();
1267 for (int i = 1; i < rows - 1; ++i) {
1268 d.point.setY(0.5 * (yTarget[i + 1] + yTarget[i]));
1269 data.append(d);
1270 }
1271 if (rules.vertical == Qt::RepeatTile)
1272 data[data.size() - 1].source.setHeight((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY);
1273 }
1274 if (targetMargins.right() > 0 && sourceMargins.right() > 0) { // right
1275 QDrawPixmapsDataArray &data = hints & QDrawBorderPixmap::OpaqueRight ? opaqueData : translucentData;
1276 d.source = QRectF(sourceCenterRight, sourceCenterTop, sourceMargins.right(), sourceCenterHeight);
1277 d.point.setX(0.5 * (xTarget[columns] + xTarget[columns - 1]));
1278 d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.source.width();
1279 d.scaleY = dy / d.source.height();
1280 for (int i = 1; i < rows - 1; ++i) {
1281 d.point.setY(0.5 * (yTarget[i + 1] + yTarget[i]));
1282 data.append(d);
1283 }
1284 if (rules.vertical == Qt::RepeatTile)
1285 data[data.size() - 1].source.setHeight((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY);
1286 }
1287 }
1288
1289 // center
1290 if (targetCenterWidth > 0 && targetCenterHeight > 0 && sourceCenterWidth > 0 && sourceCenterHeight > 0) {
1291 QDrawPixmapsDataArray &data = hints & QDrawBorderPixmap::OpaqueCenter ? opaqueData : translucentData;
1292 d.source = QRectF(sourceCenterLeft, sourceCenterTop, sourceCenterWidth, sourceCenterHeight);
1293 d.scaleX = dx / d.source.width();
1294 d.scaleY = dy / d.source.height();
1295
1296 qreal repeatWidth = (xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX;
1297 qreal repeatHeight = (yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY;
1298
1299 for (int j = 1; j < rows - 1; ++j) {
1300 d.point.setY(0.5 * (yTarget[j + 1] + yTarget[j]));
1301 for (int i = 1; i < columns - 1; ++i) {
1302 d.point.setX(0.5 * (xTarget[i + 1] + xTarget[i]));
1303 data.append(d);
1304 }
1305 if (rules.horizontal == Qt::RepeatTile)
1306 data[data.size() - 1].source.setWidth(repeatWidth);
1307 }
1308 if (rules.vertical == Qt::RepeatTile) {
1309 for (int i = 1; i < columns - 1; ++i)
1310 data[data.size() - i].source.setHeight(repeatHeight);
1311 }
1312 }
1313
1314 if (opaqueData.size())
1315 qDrawPixmaps(painter, opaqueData.data(), opaqueData.size(), pixmap, QDrawPixmaps::OpaqueHint);
1316 if (translucentData.size())
1317 qDrawPixmaps(painter, translucentData.data(), translucentData.size(), pixmap);
1318}
1319
1320/*!
1321 \class QDrawPixmaps::Data
1322 \since 4.6
1323 \internal
1324
1325 This structure is used with the qDrawPixmaps() function.
1326
1327 QPointF point: Specifies the center of the target rectangle.
1328 QRectF source: Specifies the source rectangle in the pixmap passed into the qDrawPixmaps() call.
1329 qreal scaleX: Specifies the horizontal scale of the target rectangle.
1330 qreal scaleY: Specifies the vertical scale of the target rectangle.
1331 qreal rotation: Specifies the rotation of the target rectangle in degrees.
1332 The target rectangle is rotated after scaling.
1333 qreal opacity: Specifies the opacity of the rectangle.
1334*/
1335
1336/*!
1337 \enum QDrawPixmaps::DrawingHint
1338 \internal
1339*/
1340
1341/*!
1342 \internal
1343 \since 4.6
1344
1345 This function is used to draw \a pixmap, or a sub-rectangle of \a pixmap, at multiple positions
1346 with different scale, rotation and opacity on \a painter. \a drawingData is an array of \a
1347 dataCount elements specifying the parameters used to draw each pixmap instance.
1348 This can be used for example to implement a particle system.
1349*/
1350void qDrawPixmaps(QPainter *painter, const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)
1351{
1352 QPaintEngine *engine = painter->paintEngine();
1353 if (!engine)
1354 return;
1355
1356 if (engine->isExtended()) {
1357 static_cast<QPaintEngineEx *>(engine)->drawPixmaps(drawingData, dataCount, pixmap, hints);
1358 } else {
1359 qreal oldOpacity = painter->opacity();
1360 QTransform oldTransform = painter->transform();
1361
1362 for (int i = 0; i < dataCount; ++i) {
1363 QTransform transform = oldTransform;
1364 transform.translate(drawingData[i].point.x(), drawingData[i].point.y());
1365 transform.rotate(drawingData[i].rotation);
1366 painter->setOpacity(oldOpacity * drawingData[i].opacity);
1367 painter->setTransform(transform);
1368
1369 qreal w = drawingData[i].scaleX * drawingData[i].source.width();
1370 qreal h = drawingData[i].scaleY * drawingData[i].source.height();
1371 painter->drawPixmap(QRectF(-0.5 * w, -0.5 * h, w, h), pixmap, drawingData[i].source);
1372 }
1373
1374 painter->setOpacity(oldOpacity);
1375 painter->setTransform(oldTransform);
1376 }
1377}
1378
1379QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.