Implemented contentsSize and contentsScale for QSGPaintedItem.
[profile/ivi/qtdeclarative.git] / src / declarative / items / qsgpainteditem.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
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 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qsgpainteditem.h"
43 #include <private/qsgpainteditem_p.h>
44 #include <private/qsgpainternode_p.h>
45
46 #include <private/qsgcontext_p.h>
47 #include <private/qsgadaptationlayer_p.h>
48 #include <qmath.h>
49
50 QT_BEGIN_NAMESPACE
51
52 /*!
53     \class QSGPaintedItem
54     \brief The QSGPaintedItem class provides a way to use the QPainter API in the
55     QML Scene Graph.
56
57     The QSGPaintedItem makes it possible to use the QPainter API with the QML Scene Graph.
58     It sets up a textured rectangle in the Scene Graph and uses a QPainter to paint
59     onto the texture. The render target can be either a QImage or a QGLFramebufferObject.
60     When the render target is a QImage, QPainter first renders into the image then
61     the content is uploaded to the texture.
62     When a QGLFramebufferObject is used, QPainter paints directly onto the texture.
63     Call update() to trigger a repaint.
64
65     To enable QPainter to do anti-aliased rendering, use setAntialiasing().
66
67     QSGPaintedItem is meant to make it easier to port old code that is using the
68     QPainter API to the QML Scene Graph API and it should be used only for that purpose.
69
70     To write your own painted item, you first create a subclass of QSGPaintedItem, and then
71     start by implementing its only pure virtual public function: paint(), which implements
72     the actual painting. To get the size of the area painted by the item, use
73     contentsBoundingRect().
74 */
75
76 /*!
77     \enum QSGPaintedItem::RenderTarget
78
79     This enum describes QSGPaintedItem's render targets. The render target is the
80     surface QPainter paints onto before the item is rendered on screen.
81
82     \value Image The default; QPainter paints into a QImage using the raster paint engine.
83     The image's content needs to be uploaded to graphics memory afterward, this operation
84     can potentially be slow if the item is large. This render target allows high quality
85     anti-aliasing and fast item resizing.
86
87     \value FramebufferObject QPainter paints into a QGLFramebufferObject using the GL
88     paint engine. Painting can be faster as no texture upload is required, but anti-aliasing
89     quality is not as good as if using an image. This render target allows faster rendering
90     in some cases, but you should avoid using it if the item is resized often.
91
92     \sa setRenderTarget()
93 */
94
95 /*!
96     \internal
97 */
98 QSGPaintedItemPrivate::QSGPaintedItemPrivate()
99     : QSGItemPrivate()
100     , contentsScale(1.0)
101     , fillColor(Qt::transparent)
102     , renderTarget(QSGPaintedItem::Image)
103     , geometryDirty(false)
104     , contentsDirty(false)
105     , opaquePainting(false)
106 {
107 }
108
109 /*!
110     Constructs a QSGPaintedItem with the given \a parent item.
111  */
112 QSGPaintedItem::QSGPaintedItem(QSGItem *parent)
113     : QSGItem(*(new QSGPaintedItemPrivate), parent)
114 {
115     setFlag(ItemHasContents);
116 }
117
118 /*!
119     \internal
120 */
121 QSGPaintedItem::QSGPaintedItem(QSGPaintedItemPrivate &dd, QSGItem *parent)
122     : QSGItem(dd, parent)
123 {
124     setFlag(ItemHasContents);
125 }
126
127 /*!
128     Destroys the QSGPaintedItem.
129 */
130 QSGPaintedItem::~QSGPaintedItem()
131 {
132 }
133
134 /*!
135     Schedules a redraw of the area covered by \a rect in this item. You can call this function
136     whenever your item needs to be redrawn, such as if it changes appearance or size.
137
138     This function does not cause an immediate paint; instead it schedules a paint request that
139     is processed by the QML Scene Graph when the next frame is rendered. The item will only be
140     redrawn if it is visible.
141
142     Note that calling this function will trigger a repaint of the whole scene.
143
144     \sa paint()
145 */
146 void QSGPaintedItem::update(const QRect &rect)
147 {
148     Q_D(QSGPaintedItem);
149     d->contentsDirty = true;
150
151     QRect srect(qCeil(rect.x()*d->contentsScale),
152             qCeil(rect.y()*d->contentsScale),
153             qCeil(rect.width()*d->contentsScale),
154             qCeil(rect.height()*d->contentsScale));
155
156     if (srect.isNull() && !d->dirtyRect.isNull())
157         d->dirtyRect = contentsBoundingRect().toAlignedRect();
158     else
159         d->dirtyRect |= (contentsBoundingRect() & srect).toAlignedRect();
160     QSGItem::update();
161 }
162
163 /*!
164     Returns true if this item is opaque; otherwise, false is returned.
165
166     By default, painted items are not opaque.
167
168     \sa setOpaquePainting()
169 */
170 bool QSGPaintedItem::opaquePainting() const
171 {
172     Q_D(const QSGPaintedItem);
173     return d->opaquePainting;
174 }
175
176 /*!
177     If \a opaque is true, the item is opaque; otherwise, it is considered as translucent.
178
179     Opaque items are not blended with the rest of the scene, you should set this to true
180     if the content of the item is opaque to speed up rendering.
181
182     By default, painted items are not opaque.
183
184     \sa opaquePainting()
185 */
186 void QSGPaintedItem::setOpaquePainting(bool opaque)
187 {
188     Q_D(QSGPaintedItem);
189
190     if (d->opaquePainting == opaque)
191         return;
192
193     d->opaquePainting = opaque;
194     QSGItem::update();
195 }
196
197 /*!
198     Returns true if antialiased painting is enabled; otherwise, false is returned.
199
200     By default, antialiasing is not enabled.
201
202     \sa setAntialiasing()
203 */
204 bool QSGPaintedItem::antialiasing() const
205 {
206     Q_D(const QSGPaintedItem);
207     return d->antialiasing;
208 }
209
210 /*!
211     If \a enable is true, antialiased painting is enabled.
212
213     By default, antialiasing is not enabled.
214
215     \sa antialiasing()
216 */
217 void QSGPaintedItem::setAntialiasing(bool enable)
218 {
219     Q_D(QSGPaintedItem);
220
221     if (d->antialiasing == enable)
222         return;
223
224     d->antialiasing = enable;
225     update();
226 }
227
228 /*!
229     This function returns the outer bounds of the item as a rectangle; all painting must be
230     restricted to inside an item's bounding rect.
231
232     If the contents size has not been set it reflects the size of the item; otherwise
233     it reflects the contents size scaled by the contents scale.
234
235     Use this function to know the area painted by the item.
236
237     \sa QSGItem::width(), QSGItem::height(), contentsSize(), contentsScale()
238 */
239 QRectF QSGPaintedItem::contentsBoundingRect() const
240 {
241     Q_D(const QSGPaintedItem);
242
243     qreal w = d->width;
244     QSizeF sz = d->contentsSize * d->contentsScale;
245     if (w < sz.width())
246         w = sz.width();
247     qreal h = d->height;
248     if (h < sz.height())
249         h = sz.height();
250
251     return QRectF(0, 0, w, h);
252 }
253
254 /*!
255     \property QSGPaintedItem::contentsSize
256     \brief The size of the contents
257
258     The contents size is the size of the item in regards to how it is painted
259     using the paint() function.  This is distinct from the size of the
260     item in regards to height() and width().
261 */
262 QSize QSGPaintedItem::contentsSize() const
263 {
264     Q_D(const QSGPaintedItem);
265     return d->contentsSize;
266 }
267
268 void QSGPaintedItem::setContentsSize(const QSize &size)
269 {
270     Q_D(QSGPaintedItem);
271
272     if (d->contentsSize == size)
273         return;
274
275     d->contentsSize = size;
276     update();
277 }
278
279 /*!
280     This convenience function is equivalent to calling setContentsSize(QSize()).
281 */
282 void QSGPaintedItem::resetContentsSize()
283 {
284     setContentsSize(QSize());
285 }
286
287 /*!
288     \property QSGPaintedItem::contentsScale
289     \brief The scale of the contents
290
291     All painting happening in paint() is scaled by the contents scale. This is distinct
292     from the scale of the item in regards to scale().
293
294     The default value is 1.
295 */
296 qreal QSGPaintedItem::contentsScale() const
297 {
298     Q_D(const QSGPaintedItem);
299     return d->contentsScale;
300 }
301
302 void QSGPaintedItem::setContentsScale(qreal scale)
303 {
304     Q_D(QSGPaintedItem);
305
306     if (d->contentsScale == scale)
307         return;
308
309     d->contentsScale = scale;
310     update();
311 }
312
313 /*!
314     \property QSGPaintedItem::fillColor
315     \brief The item's background fill color.
316
317     By default, the fill color is set to Qt::transparent.
318 */
319 QColor QSGPaintedItem::fillColor() const
320 {
321     Q_D(const QSGPaintedItem);
322     return d->fillColor;
323 }
324
325 void QSGPaintedItem::setFillColor(const QColor &c)
326 {
327     Q_D(QSGPaintedItem);
328
329     if (d->fillColor == c)
330         return;
331
332     d->fillColor = c;
333     update();
334
335     emit fillColorChanged();
336 }
337
338 /*!
339     \property QSGPaintedItem::renderTarget
340     \brief The item's render target.
341
342     This property defines which render target the QPainter renders into, it can be either
343     QSGPaintedItem::Image or QSGPaintedItem::FramebufferObject. Both have certains benefits,
344     typically performance versus quality. Using a framebuffer object avoids a costly upload
345     of the image contents to the texture in graphics memory, while using an image enables
346     high quality anti-aliasing.
347
348     \warning Resizing a framebuffer object is a costly operation, avoid using
349     the QSGPaintedItem::FramebufferObject render target if the item gets resized often.
350
351     By default, the render target is QSGPaintedItem::Image.
352 */
353 QSGPaintedItem::RenderTarget QSGPaintedItem::renderTarget() const
354 {
355     Q_D(const QSGPaintedItem);
356     return d->renderTarget;
357 }
358
359 void QSGPaintedItem::setRenderTarget(RenderTarget target)
360 {
361     Q_D(QSGPaintedItem);
362
363     if (d->renderTarget == target)
364         return;
365
366     d->renderTarget = target;
367     update();
368
369     emit renderTargetChanged();
370 }
371
372 /*!
373     \fn virtual void QSGPaintedItem::paint(QPainter *painter) = 0
374
375     This function, which is usually called by the QML Scene Graph, paints the
376     contents of an item in local coordinates.
377
378     The function is called after the item has been filled with the fillColor.
379
380     Reimplement this function in a QSGPaintedItem subclass to provide the
381     item's painting implementation, using \a painter.
382 */
383
384 /*!
385     This function is called after the item's geometry has changed.
386 */
387 void QSGPaintedItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
388 {
389     Q_D(QSGPaintedItem);
390     d->geometryDirty = true;
391     QSGItem::geometryChanged(newGeometry, oldGeometry);
392 }
393
394
395 /*!
396     This function is called when the Scene Graph node associated to the item needs to
397     be updated.
398 */
399 QSGNode *QSGPaintedItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
400 {
401     Q_UNUSED(data);
402     Q_D(QSGPaintedItem);
403
404     if (width() <= 0 || height() <= 0) {
405         delete oldNode;
406         return 0;
407     }
408
409     QSGPainterNode *node = static_cast<QSGPainterNode *>(oldNode);
410     if (!node)
411         node = new QSGPainterNode(this);
412
413     QRectF br = contentsBoundingRect();
414
415     node->setPreferredRenderTarget(d->renderTarget);
416     node->setSize(QSize(qRound(br.width()), qRound(br.height())));
417     node->setSmoothPainting(d->antialiasing);
418     node->setLinearFiltering(d->smooth);
419     node->setOpaquePainting(d->opaquePainting);
420     node->setFillColor(d->fillColor);
421     node->setContentsScale(d->contentsScale);
422     node->setDirty(d->contentsDirty || d->geometryDirty, d->dirtyRect);
423     node->update();
424
425     d->contentsDirty = false;
426     d->geometryDirty = false;
427     d->dirtyRect = QRect();
428
429     return node;
430 }
431
432 QT_END_NAMESPACE