1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
7 ** This file is part of the Declarative 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 "qquickitemparticle_p.h"
43 #include <private/qquickvisualitemmodel_p.h>
44 #include <QtQuick/qsgnode.h>
46 #include <QDeclarativeComponent>
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, this);
111 void QQuickItemParticle::freeze(QQuickItem* item)
117 void QQuickItemParticle::unfreeze(QQuickItem* item)
119 m_stasis.remove(item);
122 void QQuickItemParticle::take(QQuickItem *item, bool prioritize)
125 m_pendingItems.push_front(item);
127 m_pendingItems.push_back(item);
130 void QQuickItemParticle::give(QQuickItem *item)
136 void QQuickItemParticle::initialize(int gIdx, int pIdx)
138 m_loadables << m_system->groupData[gIdx]->data[pIdx];//defer to other thread
141 void QQuickItemParticle::commit(int, int)
145 void QQuickItemParticle::tick(int time)
147 Q_UNUSED(time);//only needed because QTickAnimationProxy expects one
148 foreach (QQuickItem* item, m_deletables){
150 item->setOpacity(0.);
151 item->setVisible(false);
152 QQuickItemParticleAttached* mpa;
153 if ((mpa = qobject_cast<QQuickItemParticleAttached*>(qmlAttachedPropertiesObject<QQuickItemParticle>(item))))
154 mpa->detach();//reparent as well?
155 //TODO: Delete iff we created it
158 m_deletables.clear();
160 foreach (QQuickParticleData* d, m_loadables){
161 if (m_stasis.contains(d->delegate))
162 qWarning() << "Current model particles prefers overwrite:false";
163 //remove old item from the particle that is dying to make room for this one
165 m_deletables << d->delegate;
167 if (!m_pendingItems.isEmpty()){
168 d->delegate = m_pendingItems.front();
169 m_pendingItems.pop_front();
170 }else if (m_delegate){
171 d->delegate = qobject_cast<QQuickItem*>(m_delegate->create(qmlContext(this)));
173 if (d->delegate && d){//###Data can be zero if creating an item leads to a reset - this screws things up.
174 d->delegate->setX(d->curX() - d->delegate->width()/2);//TODO: adjust for system?
175 d->delegate->setY(d->curY() - d->delegate->height()/2);
176 QQuickItemParticleAttached* mpa = qobject_cast<QQuickItemParticleAttached*>(qmlAttachedPropertiesObject<QQuickItemParticle>(d->delegate));
181 d->delegate->setParentItem(this);
183 d->delegate->setOpacity(0.);
184 d->delegate->setVisible(false);//Will be set to true when we prepare the next frame
191 void QQuickItemParticle::reset()
193 QQuickParticlePainter::reset();
195 //TODO: Cleanup items?
200 QSGNode* QQuickItemParticle::updatePaintNode(QSGNode* n, UpdatePaintNodeData* d)
202 //Dummy update just to get painting tick
204 m_pleaseReset = false;
205 //Refill loadables, delayed here so as to only happen once per frame max
206 //### Constant resetting might lead to m_loadables never being populated when tick() occurs
207 foreach (const QString group, m_groups){
208 int gIdx = m_system->groupIds[group];
209 foreach (QQuickParticleData* d, m_system->groupData[gIdx]->data)
210 if (!d->delegate && d->t != -1 && d->stillAlive())
216 update();//Get called again
218 n->markDirty(QSGNode::DirtyMaterial);
219 return QQuickItem::updatePaintNode(n,d);
222 void QQuickItemParticle::prepareNextFrame()
226 qint64 timeStamp = m_system->systemSync(this);
227 qreal curT = timeStamp/1000.0;
228 qreal dt = curT - m_lastT;
233 //TODO: Size, better fade?
234 foreach (const QString &str, m_groups){
235 int gIdx = m_system->groupIds[str];
236 int count = m_system->groupData[gIdx]->size();
238 for (int i=0; i<count; i++){
239 QQuickParticleData* data = m_system->groupData[gIdx]->data[i];
240 QQuickItem* item = data->delegate;
243 qreal t = ((timeStamp/1000.0) - data->t) / data->lifeSpan;
244 if (m_stasis.contains(item)) {
245 data->t += dt;//Stasis effect
248 if (t >= 1.0){//Usually happens from load
249 m_deletables << item;
252 data->delegate->setVisible(true);
262 item->setX(data->curX() - item->width()/2 - m_systemOffset.x());
263 item->setY(data->curY() - item->height()/2 - m_systemOffset.y());
268 QQuickItemParticleAttached *QQuickItemParticle::qmlAttachedProperties(QObject *object)
270 return new QQuickItemParticleAttached(object);