From 7b28a7eebeb8cbe5d356fc9b24651a36d73ab1ad Mon Sep 17 00:00:00 2001
From: Alan Alpert <alan.alpert@nokia.com>
Date: Fri, 10 Jun 2011 16:07:33 +1000
Subject: [PATCH] Add delegate property to ItemParticle

Also add burst(n,x,y) to ParticleEmitter, and a demo that uses both.
---
 .../particles/custom/blurparticles.qml        |  40 +++++++
 .../particles/custom/content/particle.png     | Bin 0 -> 861 bytes
 .../particles/custom/fireworks.qml            | 101 ++++++++++++++++++
 src/declarative/particles/qsgitemparticle.cpp |  78 +++++++++-----
 src/declarative/particles/qsgitemparticle_p.h |  23 +++-
 .../particles/qsgmodelparticle.cpp            |   2 +
 .../particles/qsgparticleemitter.cpp          |   7 ++
 .../particles/qsgparticleemitter_p.h          |   1 +
 8 files changed, 224 insertions(+), 28 deletions(-)
 create mode 100644 examples/declarative/particles/custom/content/particle.png
 create mode 100644 examples/declarative/particles/custom/fireworks.qml

diff --git a/examples/declarative/particles/custom/blurparticles.qml b/examples/declarative/particles/custom/blurparticles.qml
index 8a3e9ad803..15da9ba9db 100644
--- a/examples/declarative/particles/custom/blurparticles.qml
+++ b/examples/declarative/particles/custom/blurparticles.qml
@@ -1,3 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
 import QtQuick 2.0
 import QtQuick.Particles 2.0
 
diff --git a/examples/declarative/particles/custom/content/particle.png b/examples/declarative/particles/custom/content/particle.png
new file mode 100644
index 0000000000000000000000000000000000000000..5c83896d22cdc3c352ff8db97b0b1f2cd2b27125
GIT binary patch
literal 861
zcmV-j1ETziP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!|4BqaRCwByS51%9Fbqx7be0e8!eRFS
z2Yvzn|DSN;zy*YakXV7l4%;>+uAJ)4!|9fhtYq5Mes-Q6Cx`#|iAbtLlW1enS0*|y
zF-AG6Gn?YQHEL+EwV9p=GaO)E)yZ7P#iXw|#tVf#fLG>e0M8MG5RhWevjLdwSw8|D
zuhsAfhEd!df^ArA-nL0W%try}N6#(n2}a&~HjZ3K1|mYlq5;_jfW`*`(KwJuF^0aF
zr|o?q9tcN*0bGIM4C4r3BJqHu(7x$~T@X|zFe7+8*#8m!?`2AGwkkTtGl1Oy=)z}^
za?OjA&6)WL6h>fq1P)}{8Ug2Y{)hlFC`Rwu^8|a|n->6<ftUj8wj$O5jPNi4;n;Yj
zRE(5<V&5$At~pUCGgbh}$}6YZKt|Yj+DTI{IvKXNjcPmQj-kP+dT2yb^<9-)WBd0i
zpR4>P9tZ))^CJcdb95FnFqIco-dA~TBvoZEtK3xiQ00Nnht$!z>dj77iw^4%*jqDp
zZD1CAt~vjv$|vGRaP<8{tX^>mj-pqPqBoYlt$tiP2UO4awgu8L>g9a^HftXLG|wl<
z_dubRj^6csCNE_t0!@Bc=vDb2Gx}h14<LlLf{$%!0E%;{VBx?zuL{2!>1K;yv1t6N
z@~vY~yv9W(!@+<H7vcwkQ%^ruxidaYW?WP8+%Z&W+}>w;iAO4L4;GiR<^30@7ZB=z
zn!ZBk!aAnfmthA}fMheB<pugYp0f@i<1>+Tv7T@{3nr@9t&K{~=@$rCk7(@3;zVH!
zvloHbj!dUC%TCG`;L#&_FJ$XtpU+m~XD1CuI<k8$nNXd;2zVU0=!n`!C+O=qoP$%>
zc@2l1<)Sa-o^Ue7qb+KR6O3Nz=1lO&iqE=DX=|0Rn@J7;KJ%G;oE1#M-Frdf!wD`X
z?0tf5l1|YPARrR`(9I|SiAL&X!V~vHCYyK{k|O{Dgl?cqi8vhSmEQ8??O1QAM}TM#
nN5v_UffYd2w;a8m{}o^W-^qmk*A=;y00000NkvXXu0mjf5*>;S

literal 0
HcmV?d00001

diff --git a/examples/declarative/particles/custom/fireworks.qml b/examples/declarative/particles/custom/fireworks.qml
new file mode 100644
index 0000000000..edd4accfdf
--- /dev/null
+++ b/examples/declarative/particles/custom/fireworks.qml
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+**     the names of its contributors may be used to endorse or promote
+**     products derived from this software without specific prior written
+**     permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQuick.Particles 2.0
+
+Rectangle{
+    width: 360
+    height: 600
+    color: "black"
+    ParticleSystem{
+        id: otherSys
+        anchors.fill: parent
+        Emitter{
+            id: emitter
+            emitting: false
+            emitRate: 100
+            lifeSpan: 1000
+            emitCap: 1000
+            speed: AngledDirection{angleVariation:180; magnitudeVariation: 60}
+        }
+
+        ImageParticle{
+            source: "content/particle.png"
+        }
+    }
+    Component{
+        id: firework
+        Item{
+            id: container
+            width: 48
+            height: 48
+            Image{
+                width: 48
+                height: 48
+                id: img
+                source: "content/particle.png"
+            }
+            Timer{
+                interval: 1000 + 4000*Math.random()
+                running: true
+                repeat: false
+                onTriggered: {
+                    img.visible = false;
+                    emitter.burst(100, container.x+24, container.y+24);
+                }
+            }
+        }
+    }
+    ParticleSystem{
+        anchors.fill: parent
+        Emitter{
+            width: parent.width
+            y: parent.height
+            emitRate: 2
+            lifeSpan: 6000
+            speed: PointDirection{y:-100}
+        }
+        ItemParticle{
+            delegate: firework
+        }
+    }
+}
+
diff --git a/src/declarative/particles/qsgitemparticle.cpp b/src/declarative/particles/qsgitemparticle.cpp
index 819c823155..498dd90a87 100644
--- a/src/declarative/particles/qsgitemparticle.cpp
+++ b/src/declarative/particles/qsgitemparticle.cpp
@@ -42,14 +42,22 @@
 #include "qsgitemparticle_p.h"
 #include <QtDeclarative/private/qsgvisualitemmodel_p.h>
 #include <qsgnode.h>
+#include <QTimer>
+#include <QDeclarativeComponent>
 #include <QDebug>
 
 QT_BEGIN_NAMESPACE
 
 QSGItemParticle::QSGItemParticle(QSGItem *parent) :
-    QSGParticlePainter(parent), m_fade(true)
+    QSGParticlePainter(parent), m_fade(true), m_delegate(0)
 {
     setFlag(QSGItem::ItemHasContents);
+    QTimer* manageDelegates = new QTimer(this);//TODO: don't leak
+    connect(manageDelegates, SIGNAL(timeout()),
+            this, SLOT(tick()));
+    manageDelegates->setInterval(16);
+    manageDelegates->setSingleShot(false);
+    manageDelegates->start();
 }
 
 
@@ -79,33 +87,54 @@ void QSGItemParticle::give(QSGItem *item)
 
 void QSGItemParticle::load(QSGParticleData* d)
 {
-    if(m_pendingItems.isEmpty())
-        return;
     int pos = particleTypeIndex(d);
-    if(m_items[pos]){
-        if(m_stasis.contains(m_items[pos]))
-            qWarning() << "Current model particles prefers overwrite:false";
-        //remove old item from the particle that is dying to make room for this one
-        m_items[pos]->setOpacity(0.);
+    m_data[pos] = d;
+    m_loadables << pos;
+}
+
+void QSGItemParticle::tick()
+{
+    foreach(QSGItem* item, m_deletables){
+        if(m_fade)
+            item->setOpacity(0.);
         QSGItemParticleAttached* mpa;
-        if((mpa = qobject_cast<QSGItemParticleAttached*>(qmlAttachedPropertiesObject<QSGItemParticle>(m_items[pos], false))))
+        if((mpa = qobject_cast<QSGItemParticleAttached*>(qmlAttachedPropertiesObject<QSGItemParticle>(item))))
             mpa->detach();//reparent as well?
-        m_items[pos] = 0;
-        m_data[pos] = 0;
+        //TODO: Delete iff we created it
         m_activeCount--;
+        m_deletables.removeAll(item);
     }
-    m_items[pos] = m_pendingItems.front();
-    m_pendingItems.pop_front();
-    m_items[pos]->setX(d->curX() - m_items[pos]->width()/2);
-    m_items[pos]->setY(d->curY() - m_items[pos]->height()/2);
-    QSGItemParticleAttached* mpa = qobject_cast<QSGItemParticleAttached*>(qmlAttachedPropertiesObject<QSGItemParticle>(m_items[pos]));
-    if(mpa){
-        mpa->m_mp = this;
-        mpa->attach();
+
+    foreach(int pos, m_loadables){
+        if(m_stasis.contains(m_items[pos]))
+            qWarning() << "Current model particles prefers overwrite:false";
+        //remove old item from the particle that is dying to make room for this one
+        if(m_items[pos]){
+            m_deletables << m_items[pos];
+            m_activeCount--;
+        }
+        m_items[pos] = 0;
+        if(!m_pendingItems.isEmpty()){
+            m_items[pos] = m_pendingItems.front();
+            m_pendingItems.pop_front();
+        }else if(m_delegate){
+            m_items[pos] = qobject_cast<QSGItem*>(m_delegate->create(qmlContext(this)));
+        }
+        if(m_items[pos]){
+            m_items[pos]->setX(m_data[pos]->curX() - m_items[pos]->width()/2);//TODO: adjust for system?
+            m_items[pos]->setY(m_data[pos]->curY() - m_items[pos]->height()/2);
+            QSGItemParticleAttached* mpa = qobject_cast<QSGItemParticleAttached*>(qmlAttachedPropertiesObject<QSGItemParticle>(m_items[pos]));
+            if(mpa){
+                mpa->m_mp = this;
+                mpa->attach();
+            }
+            m_items[pos]->setParentItem(this);
+            if(m_fade)
+                m_items[pos]->setOpacity(0.);
+            m_activeCount++;
+        }
+        m_loadables.removeAll(pos);
     }
-    m_items[pos]->setParentItem(this);
-    m_data[pos] = d;
-    m_activeCount++;
 }
 
 void QSGItemParticle::reload(QSGParticleData* d)
@@ -173,10 +202,7 @@ void QSGItemParticle::prepareNextFrame()
             continue;
         }
         if(t >= 1.0){//Usually happens from load
-            item->setOpacity(0.);
-            QSGItemParticleAttached* mpa;
-            if((mpa = qobject_cast<QSGItemParticleAttached*>(qmlAttachedPropertiesObject<QSGItemParticle>(m_items[i]))))
-                mpa->detach();//reparent as well?
+            m_deletables << item;
             m_items[i] = 0;
             m_data[i] = 0;
             m_activeCount--;
diff --git a/src/declarative/particles/qsgitemparticle_p.h b/src/declarative/particles/qsgitemparticle_p.h
index fa3516b631..3b7db519de 100644
--- a/src/declarative/particles/qsgitemparticle_p.h
+++ b/src/declarative/particles/qsgitemparticle_p.h
@@ -55,8 +55,8 @@ class QSGItemParticleAttached;
 class QSGItemParticle : public QSGParticlePainter
 {
     Q_OBJECT
-
     Q_PROPERTY(bool fade READ fade WRITE setFade NOTIFY fadeChanged)
+    Q_PROPERTY(QDeclarativeComponent* delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
 public:
     explicit QSGItemParticle(QSGItem *parent = 0);
 
@@ -69,9 +69,16 @@ public:
     virtual int count();
 
     static QSGItemParticleAttached *qmlAttachedProperties(QObject *object);
+    QDeclarativeComponent* delegate() const
+    {
+        return m_delegate;
+    }
+
 signals:
     void fadeChanged();
 
+    void delegateChanged(QDeclarativeComponent* arg);
+
 public slots:
     //TODO: Add a follow mode, where moving the delegate causes the logical particle to go with it?
     void freeze(QSGItem* item);
@@ -80,11 +87,22 @@ public slots:
     void give(QSGItem* item);//give from modelparticle
 
     void setFade(bool arg){if(arg == m_fade) return; m_fade = arg; emit fadeChanged();}
+    void setDelegate(QDeclarativeComponent* arg)
+    {
+        if (m_delegate != arg) {
+            m_delegate = arg;
+            emit delegateChanged(arg);
+        }
+    }
+
 protected:
     virtual void reset();
     void prepareNextFrame();
+private slots:
+    void tick();
 private:
-    QList<QPointer<QSGItem> > m_deletables;
+    QList<QSGItem* > m_deletables;
+    QList< int > m_loadables;
     int m_particleCount;
     bool m_fade;
 
@@ -96,6 +114,7 @@ private:
     QSet<QSGItem*> m_stasis;
     qreal m_lastT;
     int m_activeCount;
+    QDeclarativeComponent* m_delegate;
 };
 
 class QSGItemParticleAttached : public QObject
diff --git a/src/declarative/particles/qsgmodelparticle.cpp b/src/declarative/particles/qsgmodelparticle.cpp
index 704b9a298c..b0b4fa4ad2 100644
--- a/src/declarative/particles/qsgmodelparticle.cpp
+++ b/src/declarative/particles/qsgmodelparticle.cpp
@@ -177,6 +177,7 @@ void QSGModelParticle::processPending()
     foreach(QSGItem* item, m_deletables){
         item->setOpacity(0.);
         m_model->release(item);
+        m_deletables.removeAll(item);
     }
 
     foreach(int pos, m_requests){
@@ -189,6 +190,7 @@ void QSGModelParticle::processPending()
             mpa->attach();
         }
         m_items[pos]->setParentItem(this);
+        m_requests.removeAll(pos);
     }
 }
 
diff --git a/src/declarative/particles/qsgparticleemitter.cpp b/src/declarative/particles/qsgparticleemitter.cpp
index 20f3c6bb4b..143338f798 100644
--- a/src/declarative/particles/qsgparticleemitter.cpp
+++ b/src/declarative/particles/qsgparticleemitter.cpp
@@ -121,6 +121,13 @@ void QSGParticleEmitter::burst(int num)
     m_burstQueue << qMakePair(num, QPointF(x(), y()));
 }
 
+void QSGParticleEmitter::burst(int num, qreal x, qreal y)
+{
+    if(!particleCount())
+        qWarning() << "burst called on an emitter with a particle count of zero";
+    m_burstQueue << qMakePair(num, QPointF(x, y));
+}
+
 void QSGParticleEmitter::setMaxParticleCount(int arg)
 {
     if (m_maxParticleCount != arg) {
diff --git a/src/declarative/particles/qsgparticleemitter_p.h b/src/declarative/particles/qsgparticleemitter_p.h
index 9fafd9d43d..65aca0c83e 100644
--- a/src/declarative/particles/qsgparticleemitter_p.h
+++ b/src/declarative/particles/qsgparticleemitter_p.h
@@ -142,6 +142,7 @@ signals:
 public slots:
     void pulse(qreal seconds);
     void burst(int num);
+    void burst(int num, qreal x, qreal y);
 
     void setEmitting(bool arg);
 
-- 
GitLab