1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQuick module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qquickitemparticle_p.h"
43 #include <private/qquickvisualitemmodel_p.h>
44 #include <QtQuick/qsgnode.h>
46 #include <QQmlComponent>
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.
61 \qmlmethod void QtQuick.Particles2::ItemParticle::freeze(Item item)
63 Suspends the flow of time for the logical particle which item represents, allowing you to control its movement.
67 \qmlmethod void QtQuick.Particles2::ItemParticle::unfreeze(Item item)
69 Restarts the flow of time for the logical particle which item represents, allowing it to be moved by the particle system again.
73 \qmlmethod void QtQuick.Particles2::ItemParticle::take(Item item, bool prioritize)
75 Asks the ItemParticle to take over control of item. It will be emitted when there is a logical particle available.
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
81 \qmlmethod void QtQuick.Particles2::ItemParticle::give(Item item)
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.
87 \qmlproperty bool QtQuick.Particles2::ItemParticle::fade
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.
96 \qmlproperty Component QtQuick.Particles2::ItemParticle::delegate
98 An instance of the delegate will be created for every logical
99 particle, and moved along with it.
102 QQuickItemParticle::QQuickItemParticle(QQuickItem *parent) :
103 QQuickParticlePainter(parent), m_fade(true), m_delegate(0)
105 setFlag(QQuickItem::ItemHasContents);
106 clock = new Clock(this);
110 QQuickItemParticle::~QQuickItemParticle()
115 void QQuickItemParticle::freeze(QQuickItem* item)
121 void QQuickItemParticle::unfreeze(QQuickItem* item)
123 m_stasis.remove(item);
126 void QQuickItemParticle::take(QQuickItem *item, bool prioritize)
129 m_pendingItems.push_front(item);
131 m_pendingItems.push_back(item);
134 void QQuickItemParticle::give(QQuickItem *item)
140 void QQuickItemParticle::initialize(int gIdx, int pIdx)
142 m_loadables << m_system->groupData[gIdx]->data[pIdx];//defer to other thread
145 void QQuickItemParticle::commit(int, int)
149 void QQuickItemParticle::tick(int time)
151 Q_UNUSED(time);//only needed because QTickAnimationProxy expects one
152 foreach (QQuickItem* item, m_deletables){
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
162 m_deletables.clear();
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
169 m_deletables << d->delegate;
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)));
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));
185 d->delegate->setParentItem(this);
187 d->delegate->setOpacity(0.);
188 d->delegate->setVisible(false);//Will be set to true when we prepare the next frame
195 void QQuickItemParticle::reset()
197 QQuickParticlePainter::reset();
199 //TODO: Cleanup items?
204 QSGNode* QQuickItemParticle::updatePaintNode(QSGNode* n, UpdatePaintNodeData* d)
206 //Dummy update just to get painting tick
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())
220 update();//Get called again
222 n->markDirty(QSGNode::DirtyMaterial);
223 return QQuickItem::updatePaintNode(n,d);
226 void QQuickItemParticle::prepareNextFrame()
230 qint64 timeStamp = m_system->systemSync(this);
231 qreal curT = timeStamp/1000.0;
232 qreal dt = curT - m_lastT;
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();
242 for (int i=0; i<count; i++){
243 QQuickParticleData* data = m_system->groupData[gIdx]->data[i];
244 QQuickItem* item = data->delegate;
247 qreal t = ((timeStamp/1000.0) - data->t) / data->lifeSpan;
248 if (m_stasis.contains(item)) {
249 data->t += dt;//Stasis effect
252 if (t >= 1.0){//Usually happens from load
253 m_deletables << item;
256 data->delegate->setVisible(true);
266 item->setX(data->curX() - item->width()/2 - m_systemOffset.x());
267 item->setY(data->curY() - item->height()/2 - m_systemOffset.y());
272 QQuickItemParticleAttached *QQuickItemParticle::qmlAttachedProperties(QObject *object)
274 return new QQuickItemParticleAttached(object);