1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qdrawutil.h"
44 #include "qpixmapcache.h"
45 #include "qapplication.h"
48 #include <private/qpaintengineex_p.h>
49 #include <qvarlengtharray.h>
51 #include <private/qstylehelper_p.h>
56 \headerfile <qdrawutil.h>
57 \title Drawing Utility Functions
63 \fn void qDrawShadeLine(QPainter *painter, int x1, int y1, int x2, int y2,
64 const QPalette &palette, bool sunken,
65 int lineWidth, int midLineWidth)
66 \relates <qdrawutil.h>
68 Draws a horizontal (\a y1 == \a y2) or vertical (\a x1 == \a x2)
69 shaded line using the given \a painter. Note that nothing is
70 drawn if \a y1 != \a y2 and \a x1 != \a x2 (i.e. the line is
71 neither horizontal nor vertical).
73 The provided \a palette specifies the shading colors (\l
74 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
75 {QPalette::mid()}{middle} colors). The given \a lineWidth
76 specifies the line width for each of the lines; it is not the
77 total line width. The given \a midLineWidth specifies the width of
78 a middle line drawn in the QPalette::mid() color.
80 The line appears sunken if \a sunken is true, otherwise raised.
82 \warning This function does not look at QWidget::style() or
83 QApplication::style(). Use the drawing functions in QStyle to
84 make widgets that follow the current GUI style.
87 Alternatively you can use a QFrame widget and apply the
88 QFrame::setFrameStyle() function to display a shaded line:
90 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 0
92 \sa qDrawShadeRect(), qDrawShadePanel(), QStyle
95 void qDrawShadeLine(QPainter *p, int x1, int y1, int x2, int y2,
96 const QPalette &pal, bool sunken,
97 int lineWidth, int midLineWidth)
99 if (!(p && lineWidth >= 0 && midLineWidth >= 0)) {
100 qWarning("qDrawShadeLine: Invalid parameters");
103 int tlw = lineWidth*2 + midLineWidth; // total line width
104 QPen oldPen = p->pen(); // save pen
106 p->setPen(pal.color(QPalette::Dark));
108 p->setPen(pal.light().color());
111 if (y1 == y2) { // horizontal line
113 if (x1 > x2) { // swap x1 and x2
119 for (i=0; i<lineWidth; i++) { // draw top shadow
120 a.setPoints(3, x1+i, y+tlw-1-i,
125 if (midLineWidth > 0) {
126 p->setPen(pal.mid().color());
127 for (i=0; i<midLineWidth; i++) // draw lines in the middle
128 p->drawLine(x1+lineWidth, y+lineWidth+i,
129 x2-lineWidth, y+lineWidth+i);
132 p->setPen(pal.light().color());
134 p->setPen(pal.dark().color());
135 for (i=0; i<lineWidth; i++) { // draw bottom shadow
136 a.setPoints(3, x1+i, y+tlw-i-1,
142 else if (x1 == x2) { // vertical line
144 if (y1 > y2) { // swap y1 and y2
150 for (i=0; i<lineWidth; i++) { // draw left shadow
151 a.setPoints(3, x+i, y2,
156 if (midLineWidth > 0) {
157 p->setPen(pal.mid().color());
158 for (i=0; i<midLineWidth; i++) // draw lines in the middle
159 p->drawLine(x+lineWidth+i, y1+lineWidth, x+lineWidth+i, y2);
162 p->setPen(pal.light().color());
164 p->setPen(pal.dark().color());
165 for (i=0; i<lineWidth; i++) { // draw right shadow
166 a.setPoints(3, x+lineWidth, y2-i,
168 x+tlw-i-1, y1+lineWidth);
176 \fn void qDrawShadeRect(QPainter *painter, int x, int y, int width, int height,
177 const QPalette &palette, bool sunken,
178 int lineWidth, int midLineWidth,
180 \relates <qdrawutil.h>
182 Draws the shaded rectangle beginning at (\a x, \a y) with the
183 given \a width and \a height using the provided \a painter.
185 The provide \a palette specifies the shading colors (\l
186 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
187 {QPalette::mid()}{middle} colors. The given \a lineWidth
188 specifies the line width for each of the lines; it is not the
189 total line width. The \a midLineWidth specifies the width of a
190 middle line drawn in the QPalette::mid() color. The rectangle's
191 interior is filled with the \a fill brush unless \a fill is 0.
193 The rectangle appears sunken if \a sunken is true, otherwise
196 \warning This function does not look at QWidget::style() or
197 QApplication::style(). Use the drawing functions in QStyle to make
198 widgets that follow the current GUI style.
200 Alternatively you can use a QFrame widget and apply the
201 QFrame::setFrameStyle() function to display a shaded rectangle:
203 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 1
205 \sa qDrawShadeLine(), qDrawShadePanel(), qDrawPlainRect(), QStyle
208 void qDrawShadeRect(QPainter *p, int x, int y, int w, int h,
209 const QPalette &pal, bool sunken,
210 int lineWidth, int midLineWidth,
213 if (w == 0 || h == 0)
215 if (! (w > 0 && h > 0 && lineWidth >= 0 && midLineWidth >= 0)) {
216 qWarning("qDrawShadeRect: Invalid parameters");
219 QPen oldPen = p->pen();
221 p->setPen(pal.dark().color());
223 p->setPen(pal.light().color());
224 int x1=x, y1=y, x2=x+w-1, y2=y+h-1;
226 if (lineWidth == 1 && midLineWidth == 0) {// standard shade rectangle
227 p->drawRect(x1, y1, w-2, h-2);
229 p->setPen(pal.light().color());
231 p->setPen(pal.dark().color());
232 QLineF lines[4] = { QLineF(x1+1, y1+1, x2-2, y1+1),
233 QLineF(x1+1, y1+2, x1+1, y2-2),
234 QLineF(x1, y2, x2, y2),
235 QLineF(x2,y1, x2,y2-1) };
236 p->drawLines(lines, 4); // draw bottom/right lines
237 } else { // more complicated
238 int m = lineWidth+midLineWidth;
240 for (i=0; i<lineWidth; i++) { // draw top shadow
241 QLineF lines[4] = { QLineF(x1+i, y2-i, x1+i, y1+i),
242 QLineF(x1+i, y1+i, x2-i, y1+i),
243 QLineF(x1+k, y2-k, x2-k, y2-k),
244 QLineF(x2-k, y2-k, x2-k, y1+k) };
245 p->drawLines(lines, 4);
248 p->setPen(pal.mid().color());
250 for (i=0; i<midLineWidth; i++) { // draw lines in the middle
251 p->drawRect(x1+lineWidth+i, y1+lineWidth+i, w-j-1, h-j-1);
255 p->setPen(pal.light().color());
257 p->setPen(pal.dark().color());
259 for (i=0; i<lineWidth; i++) { // draw bottom shadow
260 QLineF lines[4] = { QLineF(x1+1+i, y2-i, x2-i, y2-i),
261 QLineF(x2-i, y2-i, x2-i, y1+i+1),
262 QLineF(x1+k, y2-k, x1+k, y1+k),
263 QLineF(x1+k, y1+k, x2-k, y1+k) };
264 p->drawLines(lines, 4);
269 QBrush oldBrush = p->brush();
270 int tlw = lineWidth + midLineWidth;
271 p->setPen(Qt::NoPen);
273 p->drawRect(x+tlw, y+tlw, w-2*tlw, h-2*tlw);
274 p->setBrush(oldBrush);
276 p->setPen(oldPen); // restore pen
281 \fn void qDrawShadePanel(QPainter *painter, int x, int y, int width, int height,
282 const QPalette &palette, bool sunken,
283 int lineWidth, const QBrush *fill)
284 \relates <qdrawutil.h>
286 Draws the shaded panel beginning at (\a x, \a y) with the given \a
287 width and \a height using the provided \a painter and the given \a
290 The given \a palette specifies the shading colors (\l
291 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
292 {QPalette::mid()}{middle} colors). The panel's interior is filled
293 with the \a fill brush unless \a fill is 0.
295 The panel appears sunken if \a sunken is true, otherwise raised.
297 \warning This function does not look at QWidget::style() or
298 QApplication::style(). Use the drawing functions in QStyle to make
299 widgets that follow the current GUI style.
301 Alternatively you can use a QFrame widget and apply the
302 QFrame::setFrameStyle() function to display a shaded panel:
304 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 2
306 \sa qDrawWinPanel(), qDrawShadeLine(), qDrawShadeRect(), QStyle
309 void qDrawShadePanel(QPainter *p, int x, int y, int w, int h,
310 const QPalette &pal, bool sunken,
311 int lineWidth, const QBrush *fill)
313 if (w == 0 || h == 0)
315 if (!(w > 0 && h > 0 && lineWidth >= 0)) {
316 qWarning("qDrawShadePanel: Invalid parameters");
318 QColor shade = pal.dark().color();
319 QColor light = pal.light().color();
321 if (fill->color() == shade)
322 shade = pal.shadow().color();
323 if (fill->color() == light)
324 light = pal.midlight().color();
326 QPen oldPen = p->pen(); // save pen
327 QVector<QLineF> lines;
328 lines.reserve(2*lineWidth);
339 for (i=0; i<lineWidth; i++) { // top shadow
340 lines << QLineF(x1, y1++, x2--, y2++);
344 for (i=0; i<lineWidth; i++) { // left shado
345 lines << QLineF(x1++, y1, x2++, y2--);
356 for (i=0; i<lineWidth; i++) { // bottom shadow
357 lines << QLineF(x1++, y1--, x2, y2--);
361 y2 = y+h-lineWidth-1;
362 for (i=0; i<lineWidth; i++) { // right shadow
363 lines << QLineF(x1--, y1++, x2--, y2);
366 if (fill) // fill with fill color
367 p->fillRect(x+lineWidth, y+lineWidth, w-lineWidth*2, h-lineWidth*2, *fill);
368 p->setPen(oldPen); // restore pen
374 This function draws a rectangle with two pixel line width.
375 It is called from qDrawWinButton() and qDrawWinPanel().
377 c1..c4 and fill are used:
387 static void qDrawWinShades(QPainter *p,
388 int x, int y, int w, int h,
389 const QColor &c1, const QColor &c2,
390 const QColor &c3, const QColor &c4,
393 if (w < 2 || h < 2) // can't do anything with that
395 QPen oldPen = p->pen();
396 QPoint a[3] = { QPoint(x, y+h-2), QPoint(x, y), QPoint(x+w-2, y) };
398 p->drawPolyline(a, 3);
399 QPoint b[3] = { QPoint(x, y+h-1), QPoint(x+w-1, y+h-1), QPoint(x+w-1, y) };
401 p->drawPolyline(b, 3);
402 if (w > 4 && h > 4) {
403 QPoint c[3] = { QPoint(x+1, y+h-3), QPoint(x+1, y+1), QPoint(x+w-3, y+1) };
405 p->drawPolyline(c, 3);
406 QPoint d[3] = { QPoint(x+1, y+h-2), QPoint(x+w-2, y+h-2), QPoint(x+w-2, y+1) };
408 p->drawPolyline(d, 3);
410 p->fillRect(QRect(x+2, y+2, w-4, h-4), *fill);
417 \fn void qDrawWinButton(QPainter *painter, int x, int y, int width, int height,
418 const QPalette &palette, bool sunken,
420 \relates <qdrawutil.h>
422 Draws the Windows-style button specified by the given point (\a x,
423 \a y}, \a width and \a height using the provided \a painter with a
424 line width of 2 pixels. The button's interior is filled with the
425 \a{fill} brush unless \a fill is 0.
427 The given \a palette specifies the shading colors (\l
428 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
429 {QPalette::mid()}{middle} colors).
431 The button appears sunken if \a sunken is true, otherwise raised.
433 \warning This function does not look at QWidget::style() or
434 QApplication::style()-> Use the drawing functions in QStyle to make
435 widgets that follow the current GUI style.
437 \sa qDrawWinPanel(), QStyle
440 void qDrawWinButton(QPainter *p, int x, int y, int w, int h,
441 const QPalette &pal, bool sunken,
445 qDrawWinShades(p, x, y, w, h,
446 pal.shadow().color(), pal.light().color(), pal.dark().color(),
447 pal.button().color(), fill);
449 qDrawWinShades(p, x, y, w, h,
450 pal.light().color(), pal.shadow().color(), pal.button().color(),
451 pal.dark().color(), fill);
455 \fn void qDrawWinPanel(QPainter *painter, int x, int y, int width, int height,
456 const QPalette &palette, bool sunken,
458 \relates <qdrawutil.h>
460 Draws the Windows-style panel specified by the given point(\a x,
461 \a y), \a width and \a height using the provided \a painter with a
462 line width of 2 pixels. The button's interior is filled with the
463 \a fill brush unless \a fill is 0.
465 The given \a palette specifies the shading colors. The panel
466 appears sunken if \a sunken is true, otherwise raised.
468 \warning This function does not look at QWidget::style() or
469 QApplication::style(). Use the drawing functions in QStyle to make
470 widgets that follow the current GUI style.
472 Alternatively you can use a QFrame widget and apply the
473 QFrame::setFrameStyle() function to display a shaded panel:
475 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 3
477 \sa qDrawShadePanel(), qDrawWinButton(), QStyle
480 void qDrawWinPanel(QPainter *p, int x, int y, int w, int h,
481 const QPalette &pal, bool sunken,
485 qDrawWinShades(p, x, y, w, h,
486 pal.dark().color(), pal.light().color(), pal.shadow().color(),
487 pal.midlight().color(), fill);
489 qDrawWinShades(p, x, y, w, h,
490 pal.light().color(), pal.shadow().color(), pal.midlight().color(),
491 pal.dark().color(), fill);
495 \fn void qDrawPlainRect(QPainter *painter, int x, int y, int width, int height, const QColor &lineColor,
496 int lineWidth, const QBrush *fill)
497 \relates <qdrawutil.h>
499 Draws the plain rectangle beginning at (\a x, \a y) with the given
500 \a width and \a height, using the specified \a painter, \a lineColor
501 and \a lineWidth. The rectangle's interior is filled with the \a
502 fill brush unless \a fill is 0.
504 \warning This function does not look at QWidget::style() or
505 QApplication::style(). Use the drawing functions in QStyle to make
506 widgets that follow the current GUI style.
508 Alternatively you can use a QFrame widget and apply the
509 QFrame::setFrameStyle() function to display a plain rectangle:
511 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 4
513 \sa qDrawShadeRect(), QStyle
516 void qDrawPlainRect(QPainter *p, int x, int y, int w, int h, const QColor &c,
517 int lineWidth, const QBrush *fill)
519 if (w == 0 || h == 0)
521 if (!(w > 0 && h > 0 && lineWidth >= 0)) {
522 qWarning("qDrawPlainRect: Invalid parameters");
524 QPen oldPen = p->pen();
525 QBrush oldBrush = p->brush();
527 p->setBrush(Qt::NoBrush);
528 for (int i=0; i<lineWidth; i++)
529 p->drawRect(x+i, y+i, w-i*2 - 1, h-i*2 - 1);
530 if (fill) { // fill with fill color
531 p->setPen(Qt::NoPen);
533 p->drawRect(x+lineWidth, y+lineWidth, w-lineWidth*2, h-lineWidth*2);
536 p->setBrush(oldBrush);
539 /*****************************************************************************
540 Overloaded functions.
541 *****************************************************************************/
544 \fn void qDrawShadeLine(QPainter *painter, const QPoint &p1, const QPoint &p2,
545 const QPalette &palette, bool sunken, int lineWidth, int midLineWidth)
546 \relates <qdrawutil.h>
549 Draws a horizontal or vertical shaded line between \a p1 and \a p2
550 using the given \a painter. Note that nothing is drawn if the line
551 between the points would be neither horizontal nor vertical.
553 The provided \a palette specifies the shading colors (\l
554 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
555 {QPalette::mid()}{middle} colors). The given \a lineWidth
556 specifies the line width for each of the lines; it is not the
557 total line width. The given \a midLineWidth specifies the width of
558 a middle line drawn in the QPalette::mid() color.
560 The line appears sunken if \a sunken is true, otherwise raised.
562 \warning This function does not look at QWidget::style() or
563 QApplication::style(). Use the drawing functions in QStyle to
564 make widgets that follow the current GUI style.
567 Alternatively you can use a QFrame widget and apply the
568 QFrame::setFrameStyle() function to display a shaded line:
570 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 5
572 \sa qDrawShadeRect(), qDrawShadePanel(), QStyle
575 void qDrawShadeLine(QPainter *p, const QPoint &p1, const QPoint &p2,
576 const QPalette &pal, bool sunken,
577 int lineWidth, int midLineWidth)
579 qDrawShadeLine(p, p1.x(), p1.y(), p2.x(), p2.y(), pal, sunken,
580 lineWidth, midLineWidth);
584 \fn void qDrawShadeRect(QPainter *painter, const QRect &rect, const QPalette &palette,
585 bool sunken, int lineWidth, int midLineWidth, const QBrush *fill)
586 \relates <qdrawutil.h>
589 Draws the shaded rectangle specified by \a rect using the given \a painter.
591 The provide \a palette specifies the shading colors (\l
592 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
593 {QPalette::mid()}{middle} colors. The given \a lineWidth
594 specifies the line width for each of the lines; it is not the
595 total line width. The \a midLineWidth specifies the width of a
596 middle line drawn in the QPalette::mid() color. The rectangle's
597 interior is filled with the \a fill brush unless \a fill is 0.
599 The rectangle appears sunken if \a sunken is true, otherwise
602 \warning This function does not look at QWidget::style() or
603 QApplication::style(). Use the drawing functions in QStyle to make
604 widgets that follow the current GUI style.
606 Alternatively you can use a QFrame widget and apply the
607 QFrame::setFrameStyle() function to display a shaded rectangle:
609 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 6
611 \sa qDrawShadeLine(), qDrawShadePanel(), qDrawPlainRect(), QStyle
614 void qDrawShadeRect(QPainter *p, const QRect &r,
615 const QPalette &pal, bool sunken,
616 int lineWidth, int midLineWidth,
619 qDrawShadeRect(p, r.x(), r.y(), r.width(), r.height(), pal, sunken,
620 lineWidth, midLineWidth, fill);
624 \fn void qDrawShadePanel(QPainter *painter, const QRect &rect, const QPalette &palette,
625 bool sunken, int lineWidth, const QBrush *fill)
626 \relates <qdrawutil.h>
629 Draws the shaded panel at the rectangle specified by \a rect using the
630 given \a painter and the given \a lineWidth.
632 The given \a palette specifies the shading colors (\l
633 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
634 {QPalette::mid()}{middle} colors). The panel's interior is filled
635 with the \a fill brush unless \a fill is 0.
637 The panel appears sunken if \a sunken is true, otherwise raised.
639 \warning This function does not look at QWidget::style() or
640 QApplication::style(). Use the drawing functions in QStyle to make
641 widgets that follow the current GUI style.
643 Alternatively you can use a QFrame widget and apply the
644 QFrame::setFrameStyle() function to display a shaded panel:
646 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 7
648 \sa qDrawWinPanel(), qDrawShadeLine(), qDrawShadeRect(), QStyle
651 void qDrawShadePanel(QPainter *p, const QRect &r,
652 const QPalette &pal, bool sunken,
653 int lineWidth, const QBrush *fill)
655 qDrawShadePanel(p, r.x(), r.y(), r.width(), r.height(), pal, sunken,
660 \fn void qDrawWinButton(QPainter *painter, const QRect &rect, const QPalette &palette,
661 bool sunken, const QBrush *fill)
662 \relates <qdrawutil.h>
665 Draws the Windows-style button at the rectangle specified by \a rect using
666 the given \a painter with a line width of 2 pixels. The button's interior
667 is filled with the \a{fill} brush unless \a fill is 0.
669 The given \a palette specifies the shading colors (\l
670 {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
671 {QPalette::mid()}{middle} colors).
673 The button appears sunken if \a sunken is true, otherwise raised.
675 \warning This function does not look at QWidget::style() or
676 QApplication::style()-> Use the drawing functions in QStyle to make
677 widgets that follow the current GUI style.
679 \sa qDrawWinPanel(), QStyle
682 void qDrawWinButton(QPainter *p, const QRect &r,
683 const QPalette &pal, bool sunken, const QBrush *fill)
685 qDrawWinButton(p, r.x(), r.y(), r.width(), r.height(), pal, sunken, fill);
689 \fn void qDrawWinPanel(QPainter *painter, const QRect &rect, const QPalette &palette,
690 bool sunken, const QBrush *fill)
693 Draws the Windows-style panel at the rectangle specified by \a rect using
694 the given \a painter with a line width of 2 pixels. The button's interior
695 is filled with the \a fill brush unless \a fill is 0.
697 The given \a palette specifies the shading colors. The panel
698 appears sunken if \a sunken is true, otherwise raised.
700 \warning This function does not look at QWidget::style() or
701 QApplication::style(). Use the drawing functions in QStyle to make
702 widgets that follow the current GUI style.
704 Alternatively you can use a QFrame widget and apply the
705 QFrame::setFrameStyle() function to display a shaded panel:
707 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 8
709 \sa qDrawShadePanel(), qDrawWinButton(), QStyle
712 void qDrawWinPanel(QPainter *p, const QRect &r,
713 const QPalette &pal, bool sunken, const QBrush *fill)
715 qDrawWinPanel(p, r.x(), r.y(), r.width(), r.height(), pal, sunken, fill);
719 \fn void qDrawPlainRect(QPainter *painter, const QRect &rect, const QColor &lineColor, int lineWidth, const QBrush *fill)
720 \relates <qdrawutil.h>
723 Draws the plain rectangle specified by \a rect using the given \a painter,
724 \a lineColor and \a lineWidth. The rectangle's interior is filled with the
725 \a fill brush unless \a fill is 0.
727 \warning This function does not look at QWidget::style() or
728 QApplication::style(). Use the drawing functions in QStyle to make
729 widgets that follow the current GUI style.
731 Alternatively you can use a QFrame widget and apply the
732 QFrame::setFrameStyle() function to display a plain rectangle:
734 \snippet doc/src/snippets/code/src_gui_painting_qdrawutil.cpp 9
736 \sa qDrawShadeRect(), QStyle
739 void qDrawPlainRect(QPainter *p, const QRect &r, const QColor &c,
740 int lineWidth, const QBrush *fill)
742 qDrawPlainRect(p, r.x(), r.y(), r.width(), r.height(), c,
747 static void qDrawWinArrow(QPainter *p, Qt::ArrowType type, bool down,
748 int x, int y, int w, int h,
749 const QPalette &pal, bool enabled)
751 QPolygon a; // arrow polygon
754 a.setPoints(7, -3,1, 3,1, -2,0, 2,0, -1,-1, 1,-1, 0,-2);
757 a.setPoints(7, -3,-1, 3,-1, -2,0, 2,0, -1,1, 1,1, 0,2);
760 a.setPoints(7, 1,-3, 1,3, 0,-2, 0,2, -1,-1, -1,1, -2,0);
763 a.setPoints(7, -1,-3, -1,3, 0,-2, 0,2, 1,-1, 1,1, 2,0);
776 QPen savePen = p->pen(); // save current pen
778 p->setBrushOrigin(p->brushOrigin() + QPoint(1,1));
779 p->fillRect(x, y, w, h, pal.brush(QPalette::Button));
781 p->setBrushOrigin(p->brushOrigin() - QPoint(1,1));
783 a.translate(x+w/2, y+h/2);
784 p->setPen(pal.foreground().color());
785 p->drawLine(a.at(0), a.at(1));
786 p->drawLine(a.at(2), a.at(2));
789 a.translate(x+w/2+1, y+h/2+1);
790 p->setPen(pal.light().color());
791 p->drawLine(a.at(0), a.at(1));
792 p->drawLine(a.at(2), a.at(2));
795 p->setPen(pal.mid().color());
796 p->drawLine(a.at(0), a.at(1));
797 p->drawLine(a.at(2), a.at(2));
800 p->setPen(savePen); // restore pen
802 #endif // QT3_SUPPORT
804 #if defined(Q_CC_MSVC)
805 #pragma warning(disable: 4244)
809 #ifndef QT_NO_STYLE_MOTIF
810 // motif arrows look the same whether they are used or not
812 static void qDrawMotifArrow(QPainter *p, Qt::ArrowType type, bool down,
813 int x, int y, int w, int h,
814 const QPalette &pal, bool)
816 QPolygon bFill; // fill polygon
817 QPolygon bTop; // top shadow.
818 QPolygon bBot; // bottom shadow.
819 QPolygon bLeft; // left shadow.
820 QTransform matrix; // xform matrix
821 bool vertical = type == Qt::UpArrow || type == Qt::DownArrow;
822 bool horizontal = !vertical;
823 int dim = w < h ? w : h;
824 int colspec = 0x0000; // color specification array
826 if (dim < 2) // too small arrow
831 bFill.resize(dim & 1 ? 3 : 4);
832 bTop.resize((dim/2)*2);
833 bBot.resize(dim & 1 ? dim + 1 : dim);
834 bLeft.resize(dim > 4 ? 4 : 2);
835 bLeft.putPoints(0, 2, 0,0, 0,dim-1);
837 bLeft.putPoints(2, 2, 1,2, 1,dim-3);
838 bTop.putPoints(0, 4, 1,0, 1,1, 2,1, 3,1);
839 bBot.putPoints(0, 4, 1,dim-1, 1,dim-2, 2,dim-2, 3,dim-2);
841 for(int i=0; i<dim/2-2 ; i++) {
842 bTop.putPoints(i*2+4, 2, 2+i*2,2+i, 5+i*2, 2+i);
843 bBot.putPoints(i*2+4, 2, 2+i*2,dim-3-i, 5+i*2,dim-3-i);
845 if (dim & 1) // odd number size: extra line
846 bBot.putPoints(dim-1, 2, dim-3,dim/2, dim-1,dim/2);
847 if (dim > 6) { // dim>6: must fill interior
848 bFill.putPoints(0, 2, 1,dim-3, 1,2);
849 if (dim & 1) // if size is an odd number
850 bFill.setPoint(2, dim - 3, dim / 2);
852 bFill.putPoints(2, 2, dim-4,dim/2-1, dim-4,dim/2);
856 if (dim == 3) { // 3x3 arrow pattern
857 bLeft.setPoints(4, 0,0, 0,2, 1,1, 1,1);
858 bTop .setPoints(2, 1,0, 1,0);
859 bBot .setPoints(2, 1,2, 2,1);
861 else { // 2x2 arrow pattern
862 bLeft.setPoints(2, 0,0, 0,1);
863 bTop .setPoints(2, 1,0, 1,0);
864 bBot .setPoints(2, 1,1, 1,1);
868 if (type == Qt::UpArrow || type == Qt::LeftArrow) {
869 matrix.translate(x, y);
871 matrix.translate(0, h - 1);
874 matrix.translate(w - 1, h - 1);
878 colspec = horizontal ? 0x2334 : 0x2343;
880 colspec = horizontal ? 0x1443 : 0x1434;
882 else if (type == Qt::DownArrow || type == Qt::RightArrow) {
883 matrix.translate(x, y);
885 matrix.translate(w-1, 0);
889 colspec = horizontal ? 0x2443 : 0x2434;
891 colspec = horizontal ? 0x1334 : 0x1343;
894 const QColor *cols[5];
896 cols[1] = &pal.button().color();
897 cols[2] = &pal.mid().color();
898 cols[3] = &pal.light().color();
899 cols[4] = &pal.dark().color();
900 #define CMID *cols[(colspec>>12) & 0xf]
901 #define CLEFT *cols[(colspec>>8) & 0xf]
902 #define CTOP *cols[(colspec>>4) & 0xf]
903 #define CBOT *cols[colspec & 0xf]
905 QPen savePen = p->pen(); // save current pen
906 QBrush saveBrush = p->brush(); // save current brush
907 QTransform wxm = p->transform();
909 const QBrush &brush = pal.brush(QPalette::Button);
913 p->setTransform(matrix, true); // set transformation matrix
914 p->drawPolygon(bFill); // fill arrow
915 p->setBrush(Qt::NoBrush); // don't fill
924 p->setTransform(wxm);
925 p->setBrush(saveBrush); // restore brush
926 p->setPen(savePen); // restore pen
933 #endif // QT_NO_STYLE_MOTIF
935 QRect qItemRect(QPainter *p, Qt::GUIStyle gs,
936 int x, int y, int w, int h,
939 const QPixmap *pixmap,
940 const QString& text, int len)
945 if ((flags & Qt::AlignVCenter) == Qt::AlignVCenter)
946 y += h/2 - pixmap->height()/2;
947 else if ((flags & Qt::AlignBottom) == Qt::AlignBottom)
948 y += h - pixmap->height();
949 if ((flags & Qt::AlignRight) == Qt::AlignRight)
950 x += w - pixmap->width();
951 else if ((flags & Qt::AlignHCenter) == Qt::AlignHCenter)
952 x += w/2 - pixmap->width()/2;
953 else if ((flags & Qt::AlignLeft) != Qt::AlignLeft && QApplication::isRightToLeft())
954 x += w - pixmap->width();
955 result = QRect(x, y, pixmap->width(), pixmap->height());
956 } else if (!text.isNull() && p) {
957 result = p->boundingRect(QRect(x, y, w, h), flags, text.left(len));
958 if (gs == Qt::WindowsStyle && !enabled) {
959 result.setWidth(result.width()+1);
960 result.setHeight(result.height()+1);
963 result = QRect(x, y, w, h);
969 void qDrawArrow(QPainter *p, Qt::ArrowType type, Qt::GUIStyle style, bool down,
970 int x, int y, int w, int h,
971 const QPalette &pal, bool enabled)
974 case Qt::WindowsStyle:
975 qDrawWinArrow(p, type, down, x, y, w, h, pal, enabled);
977 #ifndef QT_NO_STYLE_MOTIF
979 qDrawMotifArrow(p, type, down, x, y, w, h, pal, enabled);
983 qWarning("qDrawArrow: Requested unsupported GUI style");
987 void qDrawItem(QPainter *p, Qt::GUIStyle gs,
988 int x, int y, int w, int h,
990 const QPalette &pal, bool enabled,
991 const QPixmap *pixmap,
992 const QString& text, int len , const QColor* penColor)
994 p->setPen(penColor?*penColor:pal.foreground().color());
997 bool clip = (flags & Qt::TextDontClip) == 0;
999 if (pm.width() < w && pm.height() < h)
1002 p->setClipRect(x, y, w, h);
1004 if ((flags & Qt::AlignVCenter) == Qt::AlignVCenter)
1005 y += h/2 - pm.height()/2;
1006 else if ((flags & Qt::AlignBottom) == Qt::AlignBottom)
1007 y += h - pm.height();
1008 if ((flags & Qt::AlignRight) == Qt::AlignRight)
1009 x += w - pm.width();
1010 else if ((flags & Qt::AlignHCenter) == Qt::AlignHCenter)
1011 x += w/2 - pm.width()/2;
1012 else if (((flags & Qt::AlignLeft) != Qt::AlignLeft) && QApplication::isRightToLeft()) // Qt::AlignAuto && rightToLeft
1013 x += w - pm.width();
1016 if (pm.hasAlphaChannel()) { // pixmap with a mask
1018 } else if (pm.depth() == 1) { // monochrome pixmap, no mask
1020 #ifndef QT_NO_IMAGE_HEURISTIC_MASK
1021 } else { // color pixmap, no mask
1022 QString k = QLatin1Literal("$qt-drawitem")
1023 % HexString<qint64>(pm.cacheKey());
1025 if (!QPixmapCache::find(k, pm)) {
1026 pm = pm.createHeuristicMask();
1027 pm.setMask((QBitmap&)pm);
1028 QPixmapCache::insert(k, pm);
1032 if (gs == Qt::WindowsStyle) {
1033 p->setPen(pal.light().color());
1034 p->drawPixmap(x+1, y+1, pm);
1035 p->setPen(pal.text().color());
1038 p->drawPixmap(x, y, pm);
1040 p->setClipping(false);
1041 } else if (!text.isNull()) {
1042 if (gs == Qt::WindowsStyle && !enabled) {
1043 p->setPen(pal.light().color());
1044 p->drawText(x+1, y+1, w, h, flags, text.left(len));
1045 p->setPen(pal.text().color());
1047 p->drawText(x, y, w, h, flags, text.left(len));
1057 Holds the rules used to draw a pixmap or image split into nine segments,
1058 similar to \l{http://www.w3.org/TR/css3-background/}{CSS3 border-images}.
1060 \sa Qt::TileRule, QMargins
1063 /*! \fn QTileRules::QTileRules(Qt::TileRule horizontalRule, Qt::TileRule verticalRule)
1064 Constructs a QTileRules with the given \a horizontalRule and
1068 /*! \fn QTileRules::QTileRules(Qt::TileRule rule)
1069 Constructs a QTileRules with the given \a rule used for both
1070 the horizontal rule and the vertical rule.
1074 \fn void qDrawBorderPixmap(QPainter *painter, const QRect &target, const QMargins &margins, const QPixmap &pixmap)
1075 \relates <qdrawutil.h>
1079 \brief The qDrawBorderPixmap function is for drawing a pixmap into
1080 the margins of a rectangle.
1082 Draws the given \a pixmap into the given \a target rectangle, using the
1083 given \a painter. The pixmap will be split into nine segments and drawn
1084 according to the \a margins structure.
1087 typedef QVarLengthArray<QPainter::PixmapFragment, 16> QPixmapFragmentsArray;
1092 Draws the indicated \a sourceRect rectangle from the given \a pixmap into
1093 the given \a targetRect rectangle, using the given \a painter. The pixmap
1094 will be split into nine segments according to the given \a targetMargins
1095 and \a sourceMargins structures. Finally, the pixmap will be drawn
1096 according to the given \a rules.
1098 This function is used to draw a scaled pixmap, similar to
1099 \l{http://www.w3.org/TR/css3-background/}{CSS3 border-images}
1101 \sa Qt::TileRule, QTileRules, QMargins
1104 void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargins &targetMargins,
1105 const QPixmap &pixmap, const QRect &sourceRect,const QMargins &sourceMargins,
1106 const QTileRules &rules, QDrawBorderPixmap::DrawingHints hints)
1108 QPainter::PixmapFragment d;
1112 QPixmapFragmentsArray opaqueData;
1113 QPixmapFragmentsArray translucentData;
1116 const int sourceCenterTop = sourceRect.top() + sourceMargins.top();
1117 const int sourceCenterLeft = sourceRect.left() + sourceMargins.left();
1118 const int sourceCenterBottom = sourceRect.bottom() - sourceMargins.bottom() + 1;
1119 const int sourceCenterRight = sourceRect.right() - sourceMargins.right() + 1;
1120 const int sourceCenterWidth = sourceCenterRight - sourceCenterLeft;
1121 const int sourceCenterHeight = sourceCenterBottom - sourceCenterTop;
1123 const int targetCenterTop = targetRect.top() + targetMargins.top();
1124 const int targetCenterLeft = targetRect.left() + targetMargins.left();
1125 const int targetCenterBottom = targetRect.bottom() - targetMargins.bottom() + 1;
1126 const int targetCenterRight = targetRect.right() - targetMargins.right() + 1;
1127 const int targetCenterWidth = targetCenterRight - targetCenterLeft;
1128 const int targetCenterHeight = targetCenterBottom - targetCenterTop;
1130 QVarLengthArray<qreal, 16> xTarget; // x-coordinates of target rectangles
1131 QVarLengthArray<qreal, 16> yTarget; // y-coordinates of target rectangles
1135 if (rules.horizontal != Qt::StretchTile && sourceCenterWidth != 0)
1136 columns = qMax(3, 2 + qCeil(targetCenterWidth / qreal(sourceCenterWidth)));
1137 if (rules.vertical != Qt::StretchTile && sourceCenterHeight != 0)
1138 rows = qMax(3, 2 + qCeil(targetCenterHeight / qreal(sourceCenterHeight)));
1140 xTarget.resize(columns + 1);
1141 yTarget.resize(rows + 1);
1143 bool oldAA = painter->testRenderHint(QPainter::Antialiasing);
1144 if (painter->paintEngine()->type() != QPaintEngine::OpenGL
1145 && painter->paintEngine()->type() != QPaintEngine::OpenGL2
1146 && oldAA && painter->combinedTransform().type() != QTransform::TxNone) {
1147 painter->setRenderHint(QPainter::Antialiasing, false);
1150 xTarget[0] = targetRect.left();
1151 xTarget[1] = targetCenterLeft;
1152 xTarget[columns - 1] = targetCenterRight;
1153 xTarget[columns] = targetRect.left() + targetRect.width();
1155 yTarget[0] = targetRect.top();
1156 yTarget[1] = targetCenterTop;
1157 yTarget[rows - 1] = targetCenterBottom;
1158 yTarget[rows] = targetRect.top() + targetRect.height();
1160 qreal dx = targetCenterWidth;
1161 qreal dy = targetCenterHeight;
1163 switch (rules.horizontal) {
1164 case Qt::StretchTile:
1165 dx = targetCenterWidth;
1167 case Qt::RepeatTile:
1168 dx = sourceCenterWidth;
1171 dx = targetCenterWidth / qreal(columns - 2);
1175 for (int i = 2; i < columns - 1; ++i)
1176 xTarget[i] = xTarget[i - 1] + dx;
1178 switch (rules.vertical) {
1179 case Qt::StretchTile:
1180 dy = targetCenterHeight;
1182 case Qt::RepeatTile:
1183 dy = sourceCenterHeight;
1186 dy = targetCenterHeight / qreal(rows - 2);
1190 for (int i = 2; i < rows - 1; ++i)
1191 yTarget[i] = yTarget[i - 1] + dy;
1194 if (targetMargins.top() > 0 && targetMargins.left() > 0 && sourceMargins.top() > 0 && sourceMargins.left() > 0) { // top left
1195 d.x = (0.5 * (xTarget[1] + xTarget[0]));
1196 d.y = (0.5 * (yTarget[1] + yTarget[0]));
1197 d.sourceLeft = sourceRect.left();
1198 d.sourceTop = sourceRect.top();
1199 d.width = sourceMargins.left();
1200 d.height = sourceMargins.top();
1201 d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width;
1202 d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height;
1203 if (hints & QDrawBorderPixmap::OpaqueTopLeft)
1204 opaqueData.append(d);
1206 translucentData.append(d);
1208 if (targetMargins.top() > 0 && targetMargins.right() > 0 && sourceMargins.top() > 0 && sourceMargins.right() > 0) { // top right
1209 d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1]));
1210 d.y = (0.5 * (yTarget[1] + yTarget[0]));
1211 d.sourceLeft = sourceCenterRight;
1212 d.sourceTop = sourceRect.top();
1213 d.width = sourceMargins.right();
1214 d.height = sourceMargins.top();
1215 d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width;
1216 d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height;
1217 if (hints & QDrawBorderPixmap::OpaqueTopRight)
1218 opaqueData.append(d);
1220 translucentData.append(d);
1222 if (targetMargins.bottom() > 0 && targetMargins.left() > 0 && sourceMargins.bottom() > 0 && sourceMargins.left() > 0) { // bottom left
1223 d.x = (0.5 * (xTarget[1] + xTarget[0]));
1224 d.y =(0.5 * (yTarget[rows] + yTarget[rows - 1]));
1225 d.sourceLeft = sourceRect.left();
1226 d.sourceTop = sourceCenterBottom;
1227 d.width = sourceMargins.left();
1228 d.height = sourceMargins.bottom();
1229 d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width;
1230 d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height;
1231 if (hints & QDrawBorderPixmap::OpaqueBottomLeft)
1232 opaqueData.append(d);
1234 translucentData.append(d);
1236 if (targetMargins.bottom() > 0 && targetMargins.right() > 0 && sourceMargins.bottom() > 0 && sourceMargins.right() > 0) { // bottom right
1237 d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1]));
1238 d.y = (0.5 * (yTarget[rows] + yTarget[rows - 1]));
1239 d.sourceLeft = sourceCenterRight;
1240 d.sourceTop = sourceCenterBottom;
1241 d.width = sourceMargins.right();
1242 d.height = sourceMargins.bottom();
1243 d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width;
1244 d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height;
1245 if (hints & QDrawBorderPixmap::OpaqueBottomRight)
1246 opaqueData.append(d);
1248 translucentData.append(d);
1252 if (targetCenterWidth > 0 && sourceCenterWidth > 0) {
1253 if (targetMargins.top() > 0 && sourceMargins.top() > 0) { // top
1254 QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueTop ? opaqueData : translucentData;
1255 d.sourceLeft = sourceCenterLeft;
1256 d.sourceTop = sourceRect.top();
1257 d.width = sourceCenterWidth;
1258 d.height = sourceMargins.top();
1259 d.y = (0.5 * (yTarget[1] + yTarget[0]));
1260 d.scaleX = dx / d.width;
1261 d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height;
1262 for (int i = 1; i < columns - 1; ++i) {
1263 d.x = (0.5 * (xTarget[i + 1] + xTarget[i]));
1266 if (rules.horizontal == Qt::RepeatTile)
1267 data[data.size() - 1].width = ((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX);
1269 if (targetMargins.bottom() > 0 && sourceMargins.bottom() > 0) { // bottom
1270 QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueBottom ? opaqueData : translucentData;
1271 d.sourceLeft = sourceCenterLeft;
1272 d.sourceTop = sourceCenterBottom;
1273 d.width = sourceCenterWidth;
1274 d.height = sourceMargins.bottom();
1275 d.y = (0.5 * (yTarget[rows] + yTarget[rows - 1]));
1276 d.scaleX = dx / d.width;
1277 d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height;
1278 for (int i = 1; i < columns - 1; ++i) {
1279 d.x = (0.5 * (xTarget[i + 1] + xTarget[i]));
1282 if (rules.horizontal == Qt::RepeatTile)
1283 data[data.size() - 1].width = ((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX);
1288 if (targetCenterHeight > 0 && sourceCenterHeight > 0) {
1289 if (targetMargins.left() > 0 && sourceMargins.left() > 0) { // left
1290 QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueLeft ? opaqueData : translucentData;
1291 d.sourceLeft = sourceRect.left();
1292 d.sourceTop = sourceCenterTop;
1293 d.width = sourceMargins.left();
1294 d.height = sourceCenterHeight;
1295 d.x = (0.5 * (xTarget[1] + xTarget[0]));
1296 d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width;
1297 d.scaleY = dy / d.height;
1298 for (int i = 1; i < rows - 1; ++i) {
1299 d.y = (0.5 * (yTarget[i + 1] + yTarget[i]));
1302 if (rules.vertical == Qt::RepeatTile)
1303 data[data.size() - 1].height = ((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY);
1305 if (targetMargins.right() > 0 && sourceMargins.right() > 0) { // right
1306 QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueRight ? opaqueData : translucentData;
1307 d.sourceLeft = sourceCenterRight;
1308 d.sourceTop = sourceCenterTop;
1309 d.width = sourceMargins.right();
1310 d.height = sourceCenterHeight;
1311 d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1]));
1312 d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width;
1313 d.scaleY = dy / d.height;
1314 for (int i = 1; i < rows - 1; ++i) {
1315 d.y = (0.5 * (yTarget[i + 1] + yTarget[i]));
1318 if (rules.vertical == Qt::RepeatTile)
1319 data[data.size() - 1].height = ((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY);
1324 if (targetCenterWidth > 0 && targetCenterHeight > 0 && sourceCenterWidth > 0 && sourceCenterHeight > 0) {
1325 QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueCenter ? opaqueData : translucentData;
1326 d.sourceLeft = sourceCenterLeft;
1327 d.sourceTop = sourceCenterTop;
1328 d.width = sourceCenterWidth;
1329 d.height = sourceCenterHeight;
1330 d.scaleX = dx / d.width;
1331 d.scaleY = dy / d.height;
1333 qreal repeatWidth = (xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX;
1334 qreal repeatHeight = (yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY;
1336 for (int j = 1; j < rows - 1; ++j) {
1337 d.y = (0.5 * (yTarget[j + 1] + yTarget[j]));
1338 for (int i = 1; i < columns - 1; ++i) {
1339 d.x = (0.5 * (xTarget[i + 1] + xTarget[i]));
1342 if (rules.horizontal == Qt::RepeatTile)
1343 data[data.size() - 1].width = repeatWidth;
1345 if (rules.vertical == Qt::RepeatTile) {
1346 for (int i = 1; i < columns - 1; ++i)
1347 data[data.size() - i].height = repeatHeight;
1351 if (opaqueData.size())
1352 painter->drawPixmapFragments(opaqueData.data(), opaqueData.size(), pixmap, QPainter::OpaqueHint);
1353 if (translucentData.size())
1354 painter->drawPixmapFragments(translucentData.data(), translucentData.size(), pixmap);
1357 painter->setRenderHint(QPainter::Antialiasing, true);