diff options
author | Erik Verbruggen <erik.verbruggen@nokia.com> | 2009-06-25 07:33:13 (GMT) |
---|---|---|
committer | Erik Verbruggen <erik.verbruggen@nokia.com> | 2009-06-25 07:33:13 (GMT) |
commit | 5b52c348243e6459cc7faa4ee76a23c7fadcd299 (patch) | |
tree | be4bee855e535651b5fa22e9554ce1732f6ece70 /src/declarative | |
parent | 2020c692803a8a7839d85860d05174a193d9a848 (diff) | |
parent | 0362832c16f95c2909e2a68351e15242b7d1b795 (diff) | |
download | Qt-5b52c348243e6459cc7faa4ee76a23c7fadcd299.zip Qt-5b52c348243e6459cc7faa4ee76a23c7fadcd299.tar.gz Qt-5b52c348243e6459cc7faa4ee76a23c7fadcd299.tar.bz2 |
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
Diffstat (limited to 'src/declarative')
26 files changed, 432 insertions, 104 deletions
diff --git a/src/declarative/canvas/qsimplecanvas.cpp b/src/declarative/canvas/qsimplecanvas.cpp index cb46f94..a4998dc 100644 --- a/src/declarative/canvas/qsimplecanvas.cpp +++ b/src/declarative/canvas/qsimplecanvas.cpp @@ -883,9 +883,9 @@ QRect QSimpleCanvasPrivate::resetDirty() dirtyItems.clear(); oldDirty = QRect(); - if (fullUpdate()) + /*if (fullUpdate()) return QRect(); - else + else*/ return r; } else { return QRect(); @@ -934,7 +934,7 @@ bool QSimpleCanvas::event(QEvent *e) QRect r = d->resetDirty(); #if defined(QFX_RENDER_QPAINTER) - if (r.isEmpty() || fullUpdate()) + if (fullUpdate()) repaint(); else repaint(r); diff --git a/src/declarative/extra/qmltimer.cpp b/src/declarative/extra/qmltimer.cpp index 1e1a6de..4af83d3 100644 --- a/src/declarative/extra/qmltimer.cpp +++ b/src/declarative/extra/qmltimer.cpp @@ -39,6 +39,7 @@ ** ****************************************************************************/ +#include "QtCore/qcoreapplication.h" #include "QtCore/qpauseanimation.h" #include "private/qobject_p.h" #include "qmltimer.h" @@ -52,27 +53,59 @@ class QmlTimerPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QmlTimer) public: - QmlTimerPrivate() : interval(1000) {} + QmlTimerPrivate() + : interval(1000), running(false), repeating(false), triggeredOnStart(false) + , componentComplete(false) {} int interval; + bool running; + bool repeating; + bool triggeredOnStart; QPauseAnimation pause; + bool componentComplete; }; +/*! + \qmlclass Timer QFxTimer + \brief The Timer item triggers a handler at a specified interval. + + A timer can be used to trigger an action either once, or repeatedly + at a given interval. + + \qml + Timer { + interval: 500; running: true; repeat: true + onTriggered: Time.text = Date().toString() + } + Text { + id: Time + } + \endqml + +*/ + QmlTimer::QmlTimer(QObject *parent) : QObject(*(new QmlTimerPrivate), parent) { Q_D(QmlTimer); connect(&d->pause, SIGNAL(currentLoopChanged(int)), this, SLOT(ticked())); - d->pause.setLoopCount(-1); + connect(&d->pause, SIGNAL(finished()), this, SLOT(ticked())); + connect(&d->pause, SIGNAL(stateChanged(QAbstractAnimation::State,QAbstractAnimation::State)) + , this, SLOT(stateChanged(QAbstractAnimation::State,QAbstractAnimation::State))); + d->pause.setLoopCount(1); d->pause.setDuration(d->interval); } +/*! + \qmlproperty int Timer::interval + + Sets the \a interval in milliseconds between triggering. +*/ void QmlTimer::setInterval(int interval) { Q_D(QmlTimer); if (interval != d->interval) { d->interval = interval; - d->pause.setDuration(d->interval); - d->pause.start(); + update(); } } @@ -82,16 +115,119 @@ int QmlTimer::interval() const return d->interval; } -void QmlTimer::componentComplete() +/*! + \qmlproperty bool Timer::running + + If set to true, starts the timer; otherwise stops the timer. + For a non-repeating timer, \a running will be set to false after the + timer has been triggered. + + \sa repeat +*/ +bool QmlTimer::isRunning() const +{ + Q_D(const QmlTimer); + return d->running; +} + +void QmlTimer::setRunning(bool running) +{ + Q_D(QmlTimer); + if (d->running != running) { + d->running = running; + emit runningChanged(); + update(); + } +} + +/*! + \qmlproperty bool Timer::repeat + + If \a repeat is true the timer will be triggered repeatedly at the + specified interval; otherwise, the timer will trigger once at the + specified interval and then stop (i.e. running will be set to false). + + \sa running +*/ +bool QmlTimer::isRepeating() const +{ + Q_D(const QmlTimer); + return d->repeating; +} + +void QmlTimer::setRepeating(bool repeating) +{ + Q_D(QmlTimer); + if (repeating != d->repeating) { + d->repeating = repeating; + update(); + } +} + +/*! + \qmlproperty bool Timer::triggeredOnStart + + If \a triggeredOnStart is true, the timer will be triggered immediately + when started, and subsequently at the specified interval. + + \sa running +*/ +bool QmlTimer::triggeredOnStart() const +{ + Q_D(const QmlTimer); + return d->triggeredOnStart; +} + +void QmlTimer::setTriggeredOnStart(bool triggeredOnStart) +{ + Q_D(QmlTimer); + if (d->triggeredOnStart != triggeredOnStart) { + d->triggeredOnStart = triggeredOnStart; + update(); + } +} + +void QmlTimer::update() { Q_D(QmlTimer); - if (d->pause.state() != QAbstractAnimation::Running) + if (!d->componentComplete) + return; + d->pause.stop(); + if (d->running) { + d->pause.setLoopCount(d->repeating ? -1 : 1); + d->pause.setDuration(d->interval); d->pause.start(); + if (d->triggeredOnStart) { + QCoreApplication::removePostedEvents(this, QEvent::MetaCall); + QMetaObject::invokeMethod(this, "ticked", Qt::QueuedConnection); + } + } +} + +void QmlTimer::componentComplete() +{ + Q_D(QmlTimer); + d->componentComplete = true; + update(); } +/*! + \qmlsignal Timer::onTriggered + + This handler is called when the Timer is triggered. +*/ void QmlTimer::ticked() { - emit timeout(); + emit triggered(); +} + +void QmlTimer::stateChanged(QAbstractAnimation::State, QAbstractAnimation::State state) +{ + Q_D(QmlTimer); + if (d->running && state != QAbstractAnimation::Running) { + d->running = false; + emit runningChanged(); + } } QT_END_NAMESPACE diff --git a/src/declarative/extra/qmltimer.h b/src/declarative/extra/qmltimer.h index 75603c6..8171385 100644 --- a/src/declarative/extra/qmltimer.h +++ b/src/declarative/extra/qmltimer.h @@ -44,6 +44,7 @@ #include <QtDeclarative/qfxglobal.h> #include <QtCore/qobject.h> +#include <QtCore/qabstractanimation.h> #include <QtDeclarative/qml.h> QT_BEGIN_HEADER @@ -56,7 +57,11 @@ class Q_DECLARATIVE_EXPORT QmlTimer : public QObject, public QmlParserStatus { Q_OBJECT Q_DECLARE_PRIVATE(QmlTimer) + Q_INTERFACES(QmlParserStatus) Q_PROPERTY(int interval READ interval WRITE setInterval) + Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged) + Q_PROPERTY(bool repeat READ isRepeating WRITE setRepeating) + Q_PROPERTY(bool triggeredOnStart READ triggeredOnStart WRITE setTriggeredOnStart) public: QmlTimer(QObject *parent=0); @@ -64,14 +69,28 @@ public: void setInterval(int interval); int interval() const; + bool isRunning() const; + void setRunning(bool running); + + bool isRepeating() const; + void setRepeating(bool repeating); + + bool triggeredOnStart() const; + void setTriggeredOnStart(bool triggeredOnStart); + protected: void componentComplete(); Q_SIGNALS: - void timeout(); + void triggered(); + void runningChanged(); + +private: + void update(); private Q_SLOTS: void ticked(); + void stateChanged(QAbstractAnimation::State,QAbstractAnimation::State); }; QML_DECLARE_TYPE(QmlTimer) diff --git a/src/declarative/fx/qfxflowview.cpp b/src/declarative/fx/qfxflowview.cpp index e02e186..77cd6df 100644 --- a/src/declarative/fx/qfxflowview.cpp +++ b/src/declarative/fx/qfxflowview.cpp @@ -128,10 +128,11 @@ void QFxFlowView::refresh() { if (m_model && m_columns >= 1) { for (int ii = 0; ii < m_model->count(); ++ii) { - QFxItem *item = m_model->item(ii); - item->setParent(this); - item->setZ(0); - m_items << item; + if (QFxItem *item = m_model->item(ii)) { + item->setParent(this); + item->setZ(0); + m_items << item; + } } reflow(); diff --git a/src/declarative/fx/qfxgridview.cpp b/src/declarative/fx/qfxgridview.cpp index 0ca9393..a6ffbb9 100644 --- a/src/declarative/fx/qfxgridview.cpp +++ b/src/declarative/fx/qfxgridview.cpp @@ -234,6 +234,8 @@ public: int count = columns - 1 - (modelIndex - visibleItems.last()->index - 1) % columns; return visibleItems.last()->colPos() - count * colSize(); } + } else { + return (modelIndex % columns) * colSize(); } return 0; } @@ -252,6 +254,8 @@ public: int rows = col / (columns * colSize()); return visibleItems.last()->rowPos() + rows * rowSize(); } + } else { + return (modelIndex / columns) * rowSize(); } return 0; } diff --git a/src/declarative/fx/qfximage.cpp b/src/declarative/fx/qfximage.cpp index 40389c4..58d597a 100644 --- a/src/declarative/fx/qfximage.cpp +++ b/src/declarative/fx/qfximage.cpp @@ -336,7 +336,8 @@ void QFxImage::paintContents(QPainter &p) if (d->pix.isNull()) return; - QPainter::RenderHints oldHints = p.renderHints(); + bool oldAA = p.testRenderHint(QPainter::Antialiasing); + bool oldSmooth = p.testRenderHint(QPainter::SmoothPixmapTransform); if (d->smooth) p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth); @@ -428,8 +429,10 @@ void QFxImage::paintContents(QPainter &p) QRect(pix.width()-sgr, pix.height() - sgb, sgr, sgb)); } - if (d->smooth) - p.setRenderHints(oldHints); + if (d->smooth) { + p.setRenderHint(QPainter::Antialiasing, oldAA); + p.setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth); + } } #elif defined(QFX_RENDER_OPENGL) uint QFxImage::glSimpleItemData(float *vertices, float *texVertices, diff --git a/src/declarative/fx/qfxitem.cpp b/src/declarative/fx/qfxitem.cpp index 0c4d97b..73786a8 100644 --- a/src/declarative/fx/qfxitem.cpp +++ b/src/declarative/fx/qfxitem.cpp @@ -897,7 +897,16 @@ void QFxItem::qmlLoaded() QmlContext *ctxt = new QmlContext(qmlContext(this)); ctxt->addDefaultObject(this); + if (!d->_qmlcomp->errors().isEmpty()) { + qWarning() << d->_qmlcomp->errors(); + delete d->_qmlcomp; + d->_qmlcomp = 0; + emit qmlChanged(); + return; + } QObject *obj = d->_qmlcomp->create(ctxt); + if (!d->_qmlcomp->errors().isEmpty()) + qWarning() << d->_qmlcomp->errors(); QFxItem *qmlChild = qobject_cast<QFxItem *>(obj); if (qmlChild) { qmlChild->setItemParent(this); diff --git a/src/declarative/fx/qfxpainteditem.cpp b/src/declarative/fx/qfxpainteditem.cpp index 29d11ff..65589f2 100644 --- a/src/declarative/fx/qfxpainteditem.cpp +++ b/src/declarative/fx/qfxpainteditem.cpp @@ -156,7 +156,6 @@ void QFxPaintedItem::setSmooth(bool smooth) Q_D(QFxPaintedItem); if (d->smooth == smooth) return; d->smooth = smooth; - clearCache(); update(); } @@ -304,7 +303,8 @@ void QFxPaintedItem::paintGLContents(GLPainter &p) for (int i = 0; i < rects.count(); ++i) { const QRect &r = rects.at(i); QPixmap img(r.size()); - img.fill(Qt::transparent); + if (d->fillColor.isValid()) + img.fill(d->fillColor); { QPainter qp(&img); qp.translate(-r.x(),-r.y()); @@ -384,4 +384,30 @@ void QFxPaintedItem::setCacheSize(int pixels) d->max_imagecache_size = pixels; } +/*! + \property QFxPaintedItem::fillColor + + The color to be used to fill the item prior to calling drawContents(). + By default, this is Qt::transparent. + + Performance improvements can be achieved if subclasses call this with either an + invalid color (QColor()), or an appropriate solid color. +*/ +void QFxPaintedItem::setFillColor(const QColor& c) +{ + Q_D(QFxPaintedItem); + if (d->fillColor == c) + return; + d->fillColor = c; + emit fillColorChanged(); + update(); +} + +QColor QFxPaintedItem::fillColor() const +{ + Q_D(const QFxPaintedItem); + return d->fillColor; +} + + QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxpainteditem.h b/src/declarative/fx/qfxpainteditem.h index b7db2d9..6cb8fe7 100644 --- a/src/declarative/fx/qfxpainteditem.h +++ b/src/declarative/fx/qfxpainteditem.h @@ -59,6 +59,7 @@ class Q_DECLARATIVE_EXPORT QFxPaintedItem : public QFxItem Q_PROPERTY(QSize contentsSize READ contentsSize WRITE setContentsSize) Q_PROPERTY(bool smooth READ isSmooth WRITE setSmooth) + Q_PROPERTY(QColor fillColor READ fillColor WRITE setFillColor NOTIFY fillColorChanged) Q_PROPERTY(int cacheSize READ cacheSize WRITE setCacheSize) public: @@ -80,11 +81,17 @@ public: int cacheSize() const; void setCacheSize(int pixels); + QColor fillColor() const; + void setFillColor(const QColor&); + protected: QFxPaintedItem(QFxPaintedItemPrivate &dd, QFxItem *parent); virtual void drawContents(QPainter *p, const QRect &) = 0; +Q_SIGNALS: + void fillColorChanged(); + protected Q_SLOTS: void dirtyCache(const QRect &); void clearCache(); diff --git a/src/declarative/fx/qfxpainteditem_p.h b/src/declarative/fx/qfxpainteditem_p.h index 21ac556..4e953a0 100644 --- a/src/declarative/fx/qfxpainteditem_p.h +++ b/src/declarative/fx/qfxpainteditem_p.h @@ -68,7 +68,7 @@ class QFxPaintedItemPrivate : public QFxItemPrivate public: QFxPaintedItemPrivate() - : max_imagecache_size(100000), smooth(false) + : max_imagecache_size(100000), smooth(false), fillColor(Qt::transparent) { } @@ -89,6 +89,7 @@ public: int max_imagecache_size; bool smooth; QSize contentsSize; + QColor fillColor; }; QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxwebview.cpp b/src/declarative/fx/qfxwebview.cpp index adb33e8..f4a06ce 100644 --- a/src/declarative/fx/qfxwebview.cpp +++ b/src/declarative/fx/qfxwebview.cpp @@ -428,12 +428,6 @@ void QFxWebView::setInteractive(bool i) emit interactiveChanged(); } -void QFxWebView::updateCacheForVisibility() -{ - if (!isVisible()) - clearCache(); -} - void QFxWebView::expandToWebPage() { Q_D(QFxWebView); @@ -845,7 +839,6 @@ void QFxWebView::setPage(QWebPage *page) d->idealheight>0 ? d->idealheight : -1)); d->page->mainFrame()->setScrollBarPolicy(Qt::Horizontal,Qt::ScrollBarAlwaysOff); d->page->mainFrame()->setScrollBarPolicy(Qt::Vertical,Qt::ScrollBarAlwaysOff); - connect(this,SIGNAL(visibleChanged()),this,SLOT(updateCacheForVisibility())); connect(d->page,SIGNAL(repaintRequested(QRect)),this,SLOT(paintPage(QRect))); connect(d->page->mainFrame(),SIGNAL(urlChanged(QUrl)),this,SIGNAL(urlChanged())); connect(d->page->mainFrame(), SIGNAL(titleChanged(QString)), this, SIGNAL(titleChanged(QString))); diff --git a/src/declarative/fx/qfxwebview.h b/src/declarative/fx/qfxwebview.h index c9a62cc..0ac1895 100644 --- a/src/declarative/fx/qfxwebview.h +++ b/src/declarative/fx/qfxwebview.h @@ -179,7 +179,6 @@ Q_SIGNALS: void doubleClick(); private Q_SLOTS: - void updateCacheForVisibility(); void expandToWebPage(); void paintPage(const QRect&); void doLoadProgress(int p); diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp index a679532..f02a176 100644 --- a/src/declarative/qml/qmlbasicscript.cpp +++ b/src/declarative/qml/qmlbasicscript.cpp @@ -830,7 +830,8 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c if (n.type == QmlBasicScriptNodeCache::Invalid || state == Reset) { context->engine()->d_func()->loadCache(n, QLatin1String(id), static_cast<QmlContextPrivate*>(context->d_ptr)); - state = Incremental; + if (state != Reset) + state = Incremental; } if(!n.isValid()) @@ -855,7 +856,8 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c } else if (n.type == QmlBasicScriptNodeCache::Invalid || state == Reset) { context->engine()->d_func()->fetchCache(n, QLatin1String(id), obj); guard(n); - state = Incremental; + if (state != Reset) + state = Incremental; } else if (!valid(n, obj)) { clearCache(dataCache); *cached = Reset; diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 8297ac4..cb0c571 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -570,7 +570,10 @@ void QmlCompiler::compileTree(Object *tree) bool QmlCompiler::compileObject(Object *obj, const BindingContext &ctxt) { Q_ASSERT (obj->type != -1); - obj->metatype = output->types.at(obj->type).metaObject(); + const QmlCompiledData::TypeReference &tr = output->types.at(obj->type); + obj->metatype = tr.metaObject(); + if (tr.component) + obj->url = tr.component->url(); if (output->types.at(obj->type).className == "Component") { COMPILE_CHECK(compileComponent(obj, ctxt)); diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index f90af4a..3429813 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -296,6 +296,7 @@ QmlComponent::QmlComponent(QmlEngine *engine, QmlCompiledComponent *cc, int star cc->addref(); d->start = start; d->count = count; + d->url = cc->url; } /*! diff --git a/src/declarative/qml/qmldom.cpp b/src/declarative/qml/qmldom.cpp index d2608c8..42b40b6 100644 --- a/src/declarative/qml/qmldom.cpp +++ b/src/declarative/qml/qmldom.cpp @@ -791,6 +791,16 @@ int QmlDomObject::length() const return 0; } +// Returns the URL of the type, if it is an external type, or an empty URL if +// not +QUrl QmlDomObject::url() const +{ + if (d && d->object) + return d->object->url; + else + return QUrl(); +} + QmlDomBasicValuePrivate::QmlDomBasicValuePrivate() : value(0) { diff --git a/src/declarative/qml/qmldom.h b/src/declarative/qml/qmldom.h index fde35a8..ab3e39f 100644 --- a/src/declarative/qml/qmldom.h +++ b/src/declarative/qml/qmldom.h @@ -143,6 +143,7 @@ public: int position() const; int length() const; + QUrl url() const; private: friend class QmlDomDocument; friend class QmlDomComponent; diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 36b6424..8c926b7 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -1160,14 +1160,26 @@ QVariant QmlExpression::value() } rv = QVariant::fromValue(list); } - } else if (svalue.isObject()) { + } else if (svalue.isObject() && + !svalue.isNumber() && + !svalue.isString() && + !svalue.isDate() && + !svalue.isError() && + !svalue.isFunction() && + !svalue.isNull() && + !svalue.isQMetaObject() && + !svalue.isQObject() && + !svalue.isRegExp()) { QScriptValue objValue = svalue.data(); - if (objValue.isValid()) - rv = objValue.toVariant(); + if (objValue.isValid()) { + QVariant var = objValue.toVariant(); + if (var.userType() >= (int)QVariant::UserType && + QmlMetaType::isObject(var.userType())) + rv = var; + } } - if (rv.isNull()) { + if (rv.isNull()) rv = svalue.toVariant(); - } for (int i = 0; i < context()->d_func()->scopeChain.size(); ++i) { scriptEngine->currentContext()->popScope(); diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index a38ce69..78040da 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -102,6 +102,8 @@ namespace QmlParser // QmlCompiledData::types array, or -1 if the object is a fetched // object. int type; + // The url of this object if it is an external type. Used by the DOM + QUrl url; // The name of this type QByteArray typeName; // The id assigned to the object (if any). diff --git a/src/declarative/util/qmlanimation.cpp b/src/declarative/util/qmlanimation.cpp index 7df249e..2a6cad9 100644 --- a/src/declarative/util/qmlanimation.cpp +++ b/src/declarative/util/qmlanimation.cpp @@ -255,6 +255,44 @@ void QmlAbstractAnimation::setRunning(bool r) emit runningChanged(d->running); } +/*! + \qmlproperty bool Animation::paused + This property holds whether the animation is currently paused. + + The \c paused property can be set to declaratively control whether or not + an animation is paused. + + Animations can also be paused and resumed imperatively from JavaScript + using the \c pause() and \c resume() methods. + + By default, animations are not paused. +*/ +bool QmlAbstractAnimation::isPaused() const +{ + Q_D(const QmlAbstractAnimation); + return d->paused; +} + +void QmlAbstractAnimation::setPaused(bool p) +{ + Q_D(QmlAbstractAnimation); + if (d->paused == p) + return; + + if (d->group) { + qWarning("QmlAbstractAnimation: setPaused() cannot be used on non-root animation nodes"); + return; + } + + d->paused = p; + if (d->paused) + qtAnimation()->pause(); + else + qtAnimation()->resume(); + + emit pausedChanged(d->running); +} + void QmlAbstractAnimation::classBegin() { Q_D(QmlAbstractAnimation); @@ -430,6 +468,30 @@ void QmlAbstractAnimation::start() } /*! + \qmlmethod Animation::pause() + \brief Pauses the animation. + + If the animation is already paused, calling this method has no effect. The + \c paused property will be true following a call to \c pause(). +*/ +void QmlAbstractAnimation::pause() +{ + setPaused(true); +} + +/*! + \qmlmethod Animation::resume() + \brief Resumes a paused animation. + + If the animation is not paused, calling this method has no effect. The + \c paused property will be false following a call to \c resume(). +*/ +void QmlAbstractAnimation::resume() +{ + setPaused(false); +} + +/*! \qmlmethod Animation::stop() \brief Stops the animation. diff --git a/src/declarative/util/qmlanimation.h b/src/declarative/util/qmlanimation.h index 5ab9dda..0452159 100644 --- a/src/declarative/util/qmlanimation.h +++ b/src/declarative/util/qmlanimation.h @@ -65,6 +65,7 @@ class QmlAbstractAnimation : public QmlPropertyValueSource, public QmlParserStat Q_INTERFACES(QmlParserStatus) Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged) + Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged) Q_PROPERTY(bool finishPlaying READ finishPlaying WRITE setFinishPlaying NOTIFY finishPlayingChanged()) Q_PROPERTY(bool repeat READ repeat WRITE setRepeat NOTIFY repeatChanged) Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged) @@ -78,6 +79,8 @@ public: bool isRunning() const; void setRunning(bool); + bool isPaused() const; + void setPaused(bool); bool finishPlaying() const; void setFinishPlaying(bool); bool repeat() const; @@ -100,6 +103,7 @@ Q_SIGNALS: void started(); void completed(); void runningChanged(bool); + void pausedChanged(bool); void repeatChanged(bool); void targetChanged(QObject *, const QString &); void finishPlayingChanged(bool); @@ -107,6 +111,8 @@ Q_SIGNALS: public Q_SLOTS: void restart(); void start(); + void pause(); + void resume(); void stop(); void complete(); diff --git a/src/declarative/util/qmlanimation_p.h b/src/declarative/util/qmlanimation_p.h index e5a7384..f09ab88 100644 --- a/src/declarative/util/qmlanimation_p.h +++ b/src/declarative/util/qmlanimation_p.h @@ -172,11 +172,12 @@ class QmlAbstractAnimationPrivate : public QObjectPrivate Q_DECLARE_PUBLIC(QmlAbstractAnimation) public: QmlAbstractAnimationPrivate() - : running(false), finishPlaying(false), repeat(false), + : running(false), paused(false), finishPlaying(false), repeat(false), connectedTimeLine(false), componentComplete(true), startOnCompletion(false), target(0), group(0) {} bool running; + bool paused; bool finishPlaying; bool repeat; bool connectedTimeLine; diff --git a/src/declarative/util/qmlfollow.cpp b/src/declarative/util/qmlfollow.cpp index d1ecac4..cf3d629 100644 --- a/src/declarative/util/qmlfollow.cpp +++ b/src/declarative/util/qmlfollow.cpp @@ -93,11 +93,11 @@ void QmlFollowPrivate::tick(int time) if (!elapsed) return; if (mode == Spring) { - if (elapsed < 10) // capped at 100fps. + if (elapsed < 16) // capped at 62fps. return; // Real men solve the spring DEs using RK4. // We'll do something much simpler which gives a result that looks fine. - int count = (elapsed+5) / 10; + int count = (elapsed+8) / 16; for (int i = 0; i < count; ++i) { qreal diff = sourceValue - currentValue; velocity = velocity + spring * diff - damping * velocity; @@ -110,14 +110,14 @@ void QmlFollowPrivate::tick(int time) else if (velocity < -maxVelocity) velocity = -maxVelocity; } - currentValue += velocity * 10.0 / 1000.0; + currentValue += velocity * 16.0 / 1000.0; } if (qAbs(velocity) < epsilon && qAbs(sourceValue - currentValue) < epsilon) { velocity = 0.0; currentValue = sourceValue; clock.stop(); } - lastTime = time - (elapsed - count * 10); + lastTime = time - (elapsed - count * 16); } else { qreal moveBy = elapsed * velocityms; qreal diff = sourceValue - currentValue; diff --git a/src/declarative/util/qmlstate.cpp b/src/declarative/util/qmlstate.cpp index abe8301..0574224 100644 --- a/src/declarative/util/qmlstate.cpp +++ b/src/declarative/util/qmlstate.cpp @@ -234,19 +234,6 @@ QmlState &QmlState::operator<<(QmlStateOperation *op) return *this; } -#if 0 -static void dump(const QmlStateOperation::ActionList &list) -{ - if (!QString(getenv("STATE_DEBUG")).isEmpty()) - return; - - for (int ii = 0; ii < list.count(); ++ii) { - const Action &action = list.at(ii); - qWarning() << action.property.object << action.property.name << action.toValue; - } -} -#endif - void QmlStatePrivate::applyBindings() { foreach(const Action &action, bindingsList) { @@ -282,12 +269,16 @@ void QmlStatePrivate::complete() emit q->completed(); } -QmlStateOperation::ActionList QmlStatePrivate::generateActionList(QmlStateGroup *group) const +// Generate a list of actions for this state. This includes coelescing state +// actions that this state "extends" +QmlStateOperation::ActionList +QmlStatePrivate::generateActionList(QmlStateGroup *group) const { QmlStateOperation::ActionList applyList; if (inState) return applyList; + // Prevent "extends" recursion inState = true; if (!extends.isEmpty()) { @@ -336,12 +327,19 @@ void QmlState::apply(QmlStateGroup *group, QmlTransition *trans, QmlState *rever d->reverting.clear(); d->bindingsList.clear(); - if (revert) - d->revertList = static_cast<QmlStatePrivate*>(revert->d_ptr)->revertList; - QmlStateOperation::RevertActionList additionalReverts; + if (revert) { + QmlStatePrivate *revertPrivate = + static_cast<QmlStatePrivate*>(revert->d_ptr); + d->revertList = revertPrivate->revertList; + revertPrivate->revertList.clear(); + } + // List of actions caused by this state QmlStateOperation::ActionList applyList = d->generateActionList(group); + // List of actions that need to be reverted to roll back (just) this state + QmlStatePrivate::SimpleActionList additionalReverts; + // First add the reverse of all the applyList actions for (int ii = 0; ii < applyList.count(); ++ii) { const Action &action = applyList.at(ii); if (action.event || !action.restore) @@ -353,10 +351,15 @@ void QmlState::apply(QmlStateGroup *group, QmlTransition *trans, QmlState *rever found = true; } if (!found) { - RevertAction r(action); + // Only need to revert the applyList action if the previous + // state doesn't have a higher priority revert already + SimpleAction r(action); additionalReverts << r; } } + + // Any reverts from a previous state that aren't carried forth + // into this state need to be translated into apply actions for (int ii = 0; ii < d->revertList.count(); ++ii) { bool found = false; for (int jj = 0; !found && jj < applyList.count(); ++jj) { @@ -376,26 +379,41 @@ void QmlState::apply(QmlStateGroup *group, QmlTransition *trans, QmlState *rever a.bv = d->revertList.at(ii).bv; } applyList << a; + // Store these special reverts in the reverting list d->reverting << d->revertList.at(ii).property; } } + // All the local reverts now become part of the ongoing revertList d->revertList << additionalReverts; - //apply all changes, and work out any ending positions for bindings - //then rewind all changes and proceed as normal - //### 4 foreach loops! - //////////////////////////////////////////////////////////////////// - foreach(const Action &action, applyList) { - if (stateChangeDebug()) - qWarning() << " Action:" << action.property.object() << action.property.name() << action.toValue; + // Output for debugging + if (stateChangeDebug()) { + foreach(const Action &action, applyList) { + qWarning() << " Action:" << action.property.object() + << action.property.name() << action.toValue; + } + } + // Determine which actions are binding changes. + foreach(const Action &action, applyList) { if (action.bv && !action.toBinding.isEmpty()) { d->bindingsList << action; action.bv->clearExpression(); } } + // Animated transitions need both the start and the end value for + // each property change. In the presence of bindings, the end values + // are non-trivial to calculate. As a "best effort" attempt, we first + // apply all the property and binding changes, then read all the actual + // final values, then roll back the changes and proceed as normal. + // + // This doesn't catch everything, and it might be a little fragile in + // some cases - but whatcha going to do? + if (!d->bindingsList.isEmpty()) { + + // Apply all the property and binding changes foreach(const Action &action, applyList) { if (action.bv && !action.toBinding.isEmpty()) { action.bv->setExpression(action.toBinding); @@ -404,6 +422,7 @@ void QmlState::apply(QmlStateGroup *group, QmlTransition *trans, QmlState *rever } } + // Read all the end values for binding changes for (int ii = 0; ii < applyList.size(); ++ii) { Action *action = &applyList[ii]; if (action->event) @@ -415,6 +434,7 @@ void QmlState::apply(QmlStateGroup *group, QmlTransition *trans, QmlState *rever } } + // Revert back to the original values foreach(const Action &action, applyList) { if (action.event) continue; @@ -424,36 +444,44 @@ void QmlState::apply(QmlStateGroup *group, QmlTransition *trans, QmlState *rever action.property.write(action.fromValue); } } - //////////////////////////////////////////////////////////////////// - QmlStateOperation::ActionList modList = applyList; - QList<QmlMetaProperty> touched; + d->completeList.clear(); + if (trans) { + QList<QmlMetaProperty> touched; d->transition = trans; - trans->prepare(modList, touched, this); - for (int ii = 0; ii < modList.count(); ++ii) { - const Action &action = modList.at(ii); + trans->prepare(applyList, touched, this); + + // Modify the action list to remove actions handled in the transition + for (int ii = 0; ii < applyList.count(); ++ii) { + const Action &action = applyList.at(ii); if (action.event) { + if (action.actionDone) { - modList.removeAt(ii); + applyList.removeAt(ii); --ii; } + } else { - if (action.toValue != action.fromValue) { - d->completeList << RevertAction(action, false); - } if (touched.contains(action.property)) { - modList.removeAt(ii); + if (action.toValue != action.fromValue) + d->completeList << SimpleAction(action, + SimpleAction::EndState); + + applyList.removeAt(ii); --ii; } + } } } - foreach(const Action &action, modList) { + // Any actions remaining have not been handled by the transition and should + // be applied immediately + foreach(const Action &action, applyList) { if (action.event) action.event->execute(); else diff --git a/src/declarative/util/qmlstate.h b/src/declarative/util/qmlstate.h index 0b8d82a..59ef812 100644 --- a/src/declarative/util/qmlstate.h +++ b/src/declarative/util/qmlstate.h @@ -79,28 +79,6 @@ public: virtual void execute(); }; -class RevertAction -{ -public: - RevertAction(const Action &a, bool from = true) : bv(0) - { - property = a.property; - if (from) { - value = a.fromValue; - binding = a.fromBinding; - } else { - value = a.toValue; - binding = a.toBinding; - } - bv = a.bv; - } - - QmlMetaProperty property; - QVariant value; - QString binding; - QmlBindableValue *bv; -}; - class QmlStateGroup; class Q_DECLARATIVE_EXPORT QmlStateOperation : public QObject { @@ -109,7 +87,6 @@ public: QmlStateOperation(QObject *parent = 0) : QObject(parent) {} typedef QList<Action> ActionList; - typedef QList<RevertAction> RevertActionList; virtual ActionList actions(); diff --git a/src/declarative/util/qmlstate_p.h b/src/declarative/util/qmlstate_p.h index da8fdcd..7fcbcd7 100644 --- a/src/declarative/util/qmlstate_p.h +++ b/src/declarative/util/qmlstate_p.h @@ -48,6 +48,29 @@ QT_BEGIN_NAMESPACE +class SimpleAction +{ +public: + enum State { StartState, EndState }; + SimpleAction(const Action &a, State state = StartState) : bv(0) + { + property = a.property; + if (state == StartState) { + value = a.fromValue; + binding = a.fromBinding; + } else { + value = a.toValue; + binding = a.toBinding; + } + bv = a.bv; + } + + QmlMetaProperty property; + QVariant value; + QString binding; + QmlBindableValue *bv; +}; + class QmlStatePrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QmlState) @@ -56,13 +79,15 @@ public: QmlStatePrivate() : when(0), transition(0), inState(false), group(0) {} + typedef QList<SimpleAction> SimpleActionList; + QString name; QmlBindableValue *when; QmlConcreteList<QmlStateOperation *> operations; QmlTransition *transition; - QmlStateOperation::RevertActionList revertList; + SimpleActionList revertList; QList<QmlMetaProperty> reverting; - QmlStateOperation::RevertActionList completeList; + SimpleActionList completeList; QmlStateOperation::ActionList bindingsList; QString extends; mutable bool inState; |