More documentation about importing LocalStorage module from Javascript
[profile/ivi/qtdeclarative.git] / src / quick / particles / qquickitemparticle.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the Declarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickitemparticle_p.h"
43 #include <private/qquickvisualitemmodel_p.h>
44 #include <QtQuick/qsgnode.h>
45 #include <QTimer>
46 #include <QDeclarativeComponent>
47 #include <QDebug>
48
49 QT_BEGIN_NAMESPACE
50
51 /*!
52     \qmlclass ItemParticle QQuickItemParticle
53     \inqmlmodule QtQuick.Particles 2
54     \inherits ParticlePainter
55     \brief The ItemParticle element allows you to specify your own delegate to paint particles.
56
57 */
58
59
60 /*!
61     \qmlmethod void QtQuick.Particles2::ItemParticle::freeze(Item item)
62
63     Suspends the flow of time for the logical particle which item represents, allowing you to control its movement.
64 */
65
66 /*!
67     \qmlmethod void QtQuick.Particles2::ItemParticle::unfreeze(Item item)
68
69     Restarts the flow of time for the logical particle which item represents, allowing it to be moved by the particle system again.
70 */
71
72 /*!
73     \qmlmethod void QtQuick.Particles2::ItemParticle::take(Item item, bool prioritize)
74
75     Asks the ItemParticle to take over control of item. It will be emitted when there is a logical particle available.
76
77     By default items form a queue when waiting for a logical particle, but if prioritize is true then it will go immediately to the
78     head of the queue.
79 */
80 /*!
81     \qmlmethod void QtQuick.Particles2::ItemParticle::give(Item item)
82
83     Orders the ItemParticle to give you control of the item. It will cease controlling it and the item will lose its association to the logical particle.
84 */
85
86 /*!
87     \qmlproperty bool QtQuick.Particles2::ItemParticle::fade
88
89     If true, the item will automatically be faded in and out
90     at the ends of its lifetime. If false, you will have to
91     implement any entry effect yourself.
92
93     Default is true.
94 */
95 /*!
96     \qmlproperty Component QtQuick.Particles2::ItemParticle::delegate
97
98     An instance of the delegate will be created for every logical
99     particle, and moved along with it.
100 */
101
102 QQuickItemParticle::QQuickItemParticle(QQuickItem *parent) :
103     QQuickParticlePainter(parent), m_fade(true), m_delegate(0)
104 {
105     setFlag(QQuickItem::ItemHasContents);
106     clock = new Clock(this);
107     clock->start();
108 }
109
110 QQuickItemParticle::~QQuickItemParticle()
111 {
112     delete clock;
113 }
114
115 void QQuickItemParticle::freeze(QQuickItem* item)
116 {
117     m_stasis << item;
118 }
119
120
121 void QQuickItemParticle::unfreeze(QQuickItem* item)
122 {
123     m_stasis.remove(item);
124 }
125
126 void QQuickItemParticle::take(QQuickItem *item, bool prioritize)
127 {
128     if (prioritize)
129         m_pendingItems.push_front(item);
130     else
131         m_pendingItems.push_back(item);
132 }
133
134 void QQuickItemParticle::give(QQuickItem *item)
135 {
136     //TODO: This
137     Q_UNUSED(item);
138 }
139
140 void QQuickItemParticle::initialize(int gIdx, int pIdx)
141 {
142     m_loadables << m_system->groupData[gIdx]->data[pIdx];//defer to other thread
143 }
144
145 void QQuickItemParticle::commit(int, int)
146 {
147 }
148
149 void QQuickItemParticle::tick(int time)
150 {
151     Q_UNUSED(time);//only needed because QTickAnimationProxy expects one
152     foreach (QQuickItem* item, m_deletables){
153         if (m_fade)
154             item->setOpacity(0.);
155         item->setVisible(false);
156         QQuickItemParticleAttached* mpa;
157         if ((mpa = qobject_cast<QQuickItemParticleAttached*>(qmlAttachedPropertiesObject<QQuickItemParticle>(item))))
158             mpa->detach();//reparent as well?
159         //TODO: Delete iff we created it
160         m_activeCount--;
161     }
162     m_deletables.clear();
163
164     foreach (QQuickParticleData* d, m_loadables){
165         if (m_stasis.contains(d->delegate))
166             qWarning() << "Current model particles prefers overwrite:false";
167         //remove old item from the particle that is dying to make room for this one
168         if (d->delegate)
169             m_deletables << d->delegate;
170         d->delegate = 0;
171         if (!m_pendingItems.isEmpty()){
172             d->delegate = m_pendingItems.front();
173             m_pendingItems.pop_front();
174         }else if (m_delegate){
175             d->delegate = qobject_cast<QQuickItem*>(m_delegate->create(qmlContext(this)));
176         }
177         if (d->delegate && d){//###Data can be zero if creating an item leads to a reset - this screws things up.
178             d->delegate->setX(d->curX() - d->delegate->width()/2);//TODO: adjust for system?
179             d->delegate->setY(d->curY() - d->delegate->height()/2);
180             QQuickItemParticleAttached* mpa = qobject_cast<QQuickItemParticleAttached*>(qmlAttachedPropertiesObject<QQuickItemParticle>(d->delegate));
181             if (mpa){
182                 mpa->m_mp = this;
183                 mpa->attach();
184             }
185             d->delegate->setParentItem(this);
186             if (m_fade)
187                 d->delegate->setOpacity(0.);
188             d->delegate->setVisible(false);//Will be set to true when we prepare the next frame
189             m_activeCount++;
190         }
191     }
192     m_loadables.clear();
193 }
194
195 void QQuickItemParticle::reset()
196 {
197     QQuickParticlePainter::reset();
198     m_loadables.clear();
199     //TODO: Cleanup items?
200     //deletables?
201 }
202
203
204 QSGNode* QQuickItemParticle::updatePaintNode(QSGNode* n, UpdatePaintNodeData* d)
205 {
206     //Dummy update just to get painting tick
207     if (m_pleaseReset){
208         m_pleaseReset = false;
209         //Refill loadables, delayed here so as to only happen once per frame max
210         //### Constant resetting might lead to m_loadables never being populated when tick() occurs
211         foreach (const QString group, m_groups){
212             int gIdx = m_system->groupIds[group];
213             foreach (QQuickParticleData* d, m_system->groupData[gIdx]->data)
214                 if (!d->delegate && d->t != -1  && d->stillAlive())
215                     m_loadables << d;
216         }
217     }
218     prepareNextFrame();
219
220     update();//Get called again
221     if (n)
222         n->markDirty(QSGNode::DirtyMaterial);
223     return QQuickItem::updatePaintNode(n,d);
224 }
225
226 void QQuickItemParticle::prepareNextFrame()
227 {
228     if (!m_system)
229         return;
230     qint64 timeStamp = m_system->systemSync(this);
231     qreal curT = timeStamp/1000.0;
232     qreal dt = curT - m_lastT;
233     m_lastT = curT;
234     if (!m_activeCount)
235         return;
236
237     //TODO: Size, better fade?
238     foreach (const QString &str, m_groups){
239         int gIdx = m_system->groupIds[str];
240         int count = m_system->groupData[gIdx]->size();
241
242         for (int i=0; i<count; i++){
243             QQuickParticleData* data = m_system->groupData[gIdx]->data[i];
244             QQuickItem* item = data->delegate;
245             if (!item)
246                 continue;
247             qreal t = ((timeStamp/1000.0) - data->t) / data->lifeSpan;
248             if (m_stasis.contains(item)) {
249                 data->t += dt;//Stasis effect
250                 continue;
251             }
252             if (t >= 1.0){//Usually happens from load
253                 m_deletables << item;
254                 data->delegate = 0;
255             }else{//Fade
256                 data->delegate->setVisible(true);
257                 if (m_fade){
258                     qreal o = 1.;
259                     if (t<0.2)
260                         o = t*5;
261                     if (t>0.8)
262                         o = (1-t)*5;
263                     item->setOpacity(o);
264                 }
265             }
266             item->setX(data->curX() - item->width()/2 - m_systemOffset.x());
267             item->setY(data->curY() - item->height()/2 - m_systemOffset.y());
268         }
269     }
270 }
271
272 QQuickItemParticleAttached *QQuickItemParticle::qmlAttachedProperties(QObject *object)
273 {
274     return new QQuickItemParticleAttached(object);
275 }
276
277 QT_END_NAMESPACE