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 QtDeclarative 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 "QtQuick1/private/qdeclarativerectangle_p.h"
43 #include "QtQuick1/private/qdeclarativerectangle_p_p.h"
46 #include <QStringBuilder>
47 #include <QtCore/qmath.h>
48 #include <QtWidgets/qdrawutil.h>
56 \class QDeclarative1Pen
57 \brief The QDeclarative1Pen class provides a pen used for drawing rectangle borders on a QDeclarative1View.
59 By default, the pen is invalid and nothing is drawn. You must either set a color (then the default
60 width is 1) or a width (then the default color is black).
62 A width of 1 indicates is a single-pixel line on the border of the item being painted.
73 void QDeclarative1Pen::setColor(const QColor &c)
76 _valid = (_color.alpha() && _width >= 1) ? true : false;
80 void QDeclarative1Pen::setWidth(int w)
82 if (_width == w && _valid)
86 _valid = (_color.alpha() && _width >= 1) ? true : false;
92 \qmlclass GradientStop QDeclarative1GradientStop
93 \inqmlmodule QtQuick 1
94 \ingroup qml-basic-visual-elements
96 \brief The GradientStop item defines the color at a position in a Gradient.
102 \qmlproperty real QtQuick1::GradientStop::position
103 \qmlproperty color QtQuick1::GradientStop::color
105 The position and color properties describe the color used at a given
106 position in a gradient, as represented by a gradient stop.
108 The default position is 0.0; the default color is black.
113 void QDeclarative1GradientStop::updateGradient()
115 if (QDeclarative1Gradient *grad = qobject_cast<QDeclarative1Gradient*>(parent()))
120 \qmlclass Gradient QDeclarative1Gradient
121 \inqmlmodule QtQuick 1
122 \ingroup qml-basic-visual-elements
124 \brief The Gradient item defines a gradient fill.
126 A gradient is defined by two or more colors, which will be blended seamlessly.
128 The colors are specified as a set of GradientStop child items, each of
129 which defines a position on the gradient from 0.0 to 1.0 and a color.
130 The position of each GradientStop is defined by setting its
131 \l{GradientStop::}{position} property; its color is defined using its
132 \l{GradientStop::}{color} property.
134 A gradient without any gradient stops is rendered as a solid white fill.
136 Note that this item is not a visual representation of a gradient. To display a
137 gradient, use a visual element (like \l Rectangle) which supports the use
140 \section1 Example Usage
142 \div {class="float-right"}
143 \inlineimage qml-gradient.png
146 The following example declares a \l Rectangle item with a gradient starting
147 with red, blending to yellow at one third of the height of the rectangle,
148 and ending with green:
150 \snippet doc/src/snippets/declarative/gradient.qml code
153 \section1 Performance and Limitations
155 Calculating gradients can be computationally expensive compared to the use
156 of solid color fills or images. Consider using gradients for static items
159 In Qt 4.7, only vertical, linear gradients can be applied to items. If you
160 need to apply different orientations of gradients, a combination of rotation
161 and clipping will need to be applied to the relevant items. This can
162 introduce additional performance requirements for your application.
164 The use of animations involving gradient stops may not give the desired
165 result. An alternative way to animate gradients is to use pre-generated
166 images or SVG drawings containing gradients.
172 \qmlproperty list<GradientStop> QtQuick1::Gradient::stops
175 This property holds the gradient stops describing the gradient.
177 By default, this property contains an empty list.
179 To set the gradient stops, define them as children of the Gradient element.
182 const QGradient *QDeclarative1Gradient::gradient() const
184 if (!m_gradient && !m_stops.isEmpty()) {
185 m_gradient = new QLinearGradient(0,0,0,1.0);
186 for (int i = 0; i < m_stops.count(); ++i) {
187 const QDeclarative1GradientStop *stop = m_stops.at(i);
188 m_gradient->setCoordinateMode(QGradient::ObjectBoundingMode);
189 m_gradient->setColorAt(stop->position(), stop->color());
196 void QDeclarative1Gradient::doUpdate()
205 \qmlclass Rectangle QDeclarative1Rectangle
206 \inqmlmodule QtQuick 1
207 \ingroup qml-basic-visual-elements
209 \brief The Rectangle item provides a filled rectangle with an optional border.
212 Rectangle items are used to fill areas with solid color or gradients, and are
213 often used to hold other items.
217 Each Rectangle item is painted using either a solid fill color, specified using
218 the \l color property, or a gradient, defined using a Gradient element and set
219 using the \l gradient property. If both a color and a gradient are specified,
220 the gradient is used.
222 You can add an optional border to a rectangle with its own color and thickness
223 by settting the \l border.color and \l border.width properties.
225 You can also create rounded rectangles using the \l radius property. Since this
226 introduces curved edges to the corners of a rectangle, it may be appropriate to
227 set the \l smooth property to improve its appearance.
229 \section1 Example Usage
231 \div {class="float-right"}
232 \inlineimage declarative-rect.png
235 The following example shows the effects of some of the common properties on a
236 Rectangle item, which in this case is used to create a square:
238 \snippet doc/src/snippets/declarative/rectangle/rectangle.qml document
241 \section1 Performance
243 Using the \l smooth property improves the appearance of a rounded rectangle at
244 the cost of rendering performance. You should consider unsetting this property
245 for rectangles in motion, and only set it when they are stationary.
250 int QDeclarative1RectanglePrivate::doUpdateSlotIdx = -1;
252 QDeclarative1Rectangle::QDeclarative1Rectangle(QDeclarativeItem *parent)
253 : QDeclarativeItem(*(new QDeclarative1RectanglePrivate), parent)
257 void QDeclarative1Rectangle::doUpdate()
259 Q_D(QDeclarative1Rectangle);
260 d->rectImage = QPixmap();
261 const int pw = d->pen && d->pen->isValid() ? d->pen->width() : 0;
262 d->setPaintMargin((pw+1)/2);
267 \qmlproperty int QtQuick1::Rectangle::border.width
268 \qmlproperty color QtQuick1::Rectangle::border.color
270 The width and color used to draw the border of the rectangle.
272 A width of 1 creates a thin line. For no line, use a width of 0 or a transparent color.
274 \note The width of the rectangle's border does not affect the geometry of the
275 rectangle itself or its position relative to other items if anchors are used.
277 If \c border.width is an odd number, the rectangle is painted at a half-pixel offset to retain
278 border smoothness. Also, the border is rendered evenly on either side of the
279 rectangle's boundaries, and the spare pixel is rendered to the right and below the
280 rectangle (as documented for QRect rendering). This can cause unintended effects if
281 \c border.width is 1 and the rectangle is \l{Item::clip}{clipped} by a parent item:
283 \div {class="float-right"}
284 \inlineimage rect-border-width.png
287 \snippet doc/src/snippets/declarative/rectangle/rect-border-width.qml 0
290 Here, the innermost rectangle's border is clipped on the bottom and right edges by its
291 parent. To avoid this, the border width can be set to two instead of one.
293 QDeclarative1Pen *QDeclarative1Rectangle::border()
295 Q_D(QDeclarative1Rectangle);
300 \qmlproperty Gradient QtQuick1::Rectangle::gradient
302 The gradient to use to fill the rectangle.
304 This property allows for the construction of simple vertical gradients.
305 Other gradients may by formed by adding rotation to the rectangle.
307 \div {class="float-left"}
308 \inlineimage declarative-rect_gradient.png
311 \snippet doc/src/snippets/declarative/rectangle/rectangle-gradient.qml rectangles
314 If both a gradient and a color are specified, the gradient will be used.
318 QDeclarative1Gradient *QDeclarative1Rectangle::gradient() const
320 Q_D(const QDeclarative1Rectangle);
324 void QDeclarative1Rectangle::setGradient(QDeclarative1Gradient *gradient)
326 Q_D(QDeclarative1Rectangle);
327 if (d->gradient == gradient)
329 static int updatedSignalIdx = -1;
330 if (updatedSignalIdx < 0)
331 updatedSignalIdx = QDeclarative1Gradient::staticMetaObject.indexOfSignal("updated()");
332 if (d->doUpdateSlotIdx < 0)
333 d->doUpdateSlotIdx = QDeclarative1Rectangle::staticMetaObject.indexOfSlot("doUpdate()");
335 QMetaObject::disconnect(d->gradient, updatedSignalIdx, this, d->doUpdateSlotIdx);
336 d->gradient = gradient;
338 QMetaObject::connect(d->gradient, updatedSignalIdx, this, d->doUpdateSlotIdx);
344 \qmlproperty real QtQuick1::Rectangle::radius
345 This property holds the corner radius used to draw a rounded rectangle.
347 If radius is non-zero, the rectangle will be painted as a rounded rectangle, otherwise it will be
348 painted as a normal rectangle. The same radius is used by all 4 corners; there is currently
349 no way to specify different radii for different corners.
351 qreal QDeclarative1Rectangle::radius() const
353 Q_D(const QDeclarative1Rectangle);
357 void QDeclarative1Rectangle::setRadius(qreal radius)
359 Q_D(QDeclarative1Rectangle);
360 if (d->radius == radius)
364 d->rectImage = QPixmap();
366 emit radiusChanged();
370 \qmlproperty color QtQuick1::Rectangle::color
371 This property holds the color used to fill the rectangle.
373 The default color is white.
375 \div {class="float-right"}
376 \inlineimage rect-color.png
379 The following example shows rectangles with colors specified
380 using hexadecimal and named color notation:
382 \snippet doc/src/snippets/declarative/rectangle/rectangle-colors.qml rectangles
385 If both a gradient and a color are specified, the gradient will be used.
389 QColor QDeclarative1Rectangle::color() const
391 Q_D(const QDeclarative1Rectangle);
395 void QDeclarative1Rectangle::setColor(const QColor &c)
397 Q_D(QDeclarative1Rectangle);
402 d->rectImage = QPixmap();
407 void QDeclarative1Rectangle::generateRoundedRect()
409 Q_D(QDeclarative1Rectangle);
410 if (d->rectImage.isNull()) {
411 const int pw = d->pen && d->pen->isValid() ? d->pen->width() : 0;
412 const int radius = qCeil(d->radius); //ensure odd numbered width/height so we get 1-pixel center
414 QString key = QLatin1String("q_") % QString::number(pw) % d->color.name() % QString::number(d->color.alpha(), 16) % QLatin1Char('_') % QString::number(radius);
415 if (d->pen && d->pen->isValid())
416 key += d->pen->color().name() % QString::number(d->pen->color().alpha(), 16);
418 if (!QPixmapCache::find(key, &d->rectImage)) {
419 d->rectImage = QPixmap(radius*2 + 3 + pw*2, radius*2 + 3 + pw*2);
420 d->rectImage.fill(Qt::transparent);
421 QPainter p(&(d->rectImage));
422 p.setRenderHint(QPainter::Antialiasing);
423 if (d->pen && d->pen->isValid()) {
424 QPen pn(QColor(d->pen->color()), d->pen->width());
429 p.setBrush(d->color);
431 p.drawRoundedRect(QRectF(qreal(pw)/2+1, qreal(pw)/2+1, d->rectImage.width()-(pw+1), d->rectImage.height()-(pw+1)), d->radius, d->radius);
433 p.drawRoundedRect(QRectF(qreal(pw)/2, qreal(pw)/2, d->rectImage.width()-pw, d->rectImage.height()-pw), d->radius, d->radius);
435 // end painting before inserting pixmap
436 // to pixmap cache to avoid a deep copy
438 QPixmapCache::insert(key, d->rectImage);
443 void QDeclarative1Rectangle::generateBorderedRect()
445 Q_D(QDeclarative1Rectangle);
446 if (d->rectImage.isNull()) {
447 const int pw = d->pen && d->pen->isValid() ? d->pen->width() : 0;
449 QString key = QLatin1String("q_") % QString::number(pw) % d->color.name() % QString::number(d->color.alpha(), 16);
450 if (d->pen && d->pen->isValid())
451 key += d->pen->color().name() % QString::number(d->pen->color().alpha(), 16);
453 if (!QPixmapCache::find(key, &d->rectImage)) {
454 // Adding 5 here makes qDrawBorderPixmap() paint correctly with smooth: true
455 // See QTBUG-7999 and QTBUG-10765 for more details.
456 d->rectImage = QPixmap(pw*2 + 5, pw*2 + 5);
457 d->rectImage.fill(Qt::transparent);
458 QPainter p(&(d->rectImage));
459 p.setRenderHint(QPainter::Antialiasing);
460 if (d->pen && d->pen->isValid()) {
461 QPen pn(QColor(d->pen->color()), d->pen->width());
462 pn.setJoinStyle(Qt::MiterJoin);
467 p.setBrush(d->color);
469 p.drawRect(QRectF(qreal(pw)/2+1, qreal(pw)/2+1, d->rectImage.width()-(pw+1), d->rectImage.height()-(pw+1)));
471 p.drawRect(QRectF(qreal(pw)/2, qreal(pw)/2, d->rectImage.width()-pw, d->rectImage.height()-pw));
473 // end painting before inserting pixmap
474 // to pixmap cache to avoid a deep copy
476 QPixmapCache::insert(key, d->rectImage);
481 void QDeclarative1Rectangle::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
483 Q_D(QDeclarative1Rectangle);
484 if (width() <= 0 || height() <= 0)
486 if (d->radius > 0 || (d->pen && d->pen->isValid())
487 || (d->gradient && d->gradient->gradient()) ) {
491 bool oldAA = p->testRenderHint(QPainter::Antialiasing);
493 p->setRenderHints(QPainter::Antialiasing, true);
494 p->fillRect(QRectF(0, 0, width(), height()), d->color);
496 p->setRenderHint(QPainter::Antialiasing, oldAA);
500 void QDeclarative1Rectangle::drawRect(QPainter &p)
502 Q_D(QDeclarative1Rectangle);
503 if ((d->gradient && d->gradient->gradient())
504 || d->radius > width()/2 || d->radius > height()/2
505 || width() < 3 || height() < 3) {
506 // XXX This path is still slower than the image path
507 // Image path won't work for gradients or invalid radius though
508 bool oldAA = p.testRenderHint(QPainter::Antialiasing);
510 p.setRenderHint(QPainter::Antialiasing);
511 if (d->pen && d->pen->isValid()) {
512 QPen pn(QColor(d->pen->color()), d->pen->width());
513 pn.setJoinStyle(Qt::MiterJoin);
518 if (d->gradient && d->gradient->gradient())
519 p.setBrush(*d->gradient->gradient());
521 p.setBrush(d->color);
522 const int pw = d->pen && d->pen->isValid() ? d->pen->width() : 0;
525 rect = QRectF(0.5, 0.5, width()-1, height()-1);
527 rect = QRectF(0, 0, width(), height());
528 qreal radius = d->radius;
529 if (radius > width()/2 || radius > height()/2)
530 radius = qMin(width()/2, height()/2);
532 p.drawRoundedRect(rect, radius, radius);
536 p.setRenderHint(QPainter::Antialiasing, oldAA);
538 bool oldAA = p.testRenderHint(QPainter::Antialiasing);
539 bool oldSmooth = p.testRenderHint(QPainter::SmoothPixmapTransform);
541 p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth);
543 const int pw = d->pen && d->pen->isValid() ? (d->pen->width()+1)/2*2 : 0;
546 generateRoundedRect();
548 generateBorderedRect();
550 int xOffset = (d->rectImage.width()-1)/2;
551 int yOffset = (d->rectImage.height()-1)/2;
552 Q_ASSERT(d->rectImage.width() == 2*xOffset + 1);
553 Q_ASSERT(d->rectImage.height() == 2*yOffset + 1);
555 // check whether we've eliminated the center completely
556 if (2*xOffset > width()+pw)
557 xOffset = (width()+pw)/2;
558 if (2*yOffset > height()+pw)
559 yOffset = (height()+pw)/2;
561 QMargins margins(xOffset, yOffset, xOffset, yOffset);
562 QTileRules rules(Qt::StretchTile, Qt::StretchTile);
563 //NOTE: even though our item may have qreal-based width and height, qDrawBorderPixmap only supports QRects
564 qDrawBorderPixmap(&p, QRect(-pw/2, -pw/2, width()+pw, height()+pw), margins, d->rectImage, d->rectImage.rect(), margins, rules);
567 p.setRenderHint(QPainter::Antialiasing, oldAA);
568 p.setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth);
574 \qmlproperty bool QtQuick1::Rectangle::smooth
576 Set this property if you want the item to be smoothly scaled or
577 transformed. Smooth filtering gives better visual quality, but is slower. If
578 the item is displayed at its natural size, this property has no visual or
581 \note Generally scaling artifacts are only visible if the item is stationary on
582 the screen. A common pattern when animating an item is to disable smooth
583 filtering at the beginning of the animation and reenable it at the conclusion.
585 \image rect-smooth.png
586 On this image, smooth is turned off on the top half and on on the bottom half.
589 QRectF QDeclarative1Rectangle::boundingRect() const
591 Q_D(const QDeclarative1Rectangle);
592 return QRectF(-d->paintmargin, -d->paintmargin, d->width()+d->paintmargin*2, d->height()+d->paintmargin*2);