From 239c3581bb84b6484547918fbb1672fed08970dd Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 8 Jul 2009 16:11:21 +1000 Subject: Add a modulus property to Follow to allow "wrapping". Also add clock example to demonstrate. --- examples/declarative/clock/Clock.qml | 78 ++++++++++++++++++++++++++++++ examples/declarative/clock/background.png | Bin 0 -> 46895 bytes examples/declarative/clock/display.qml | 5 ++ examples/declarative/clock/hour.png | Bin 0 -> 391 bytes examples/declarative/clock/minute.png | Bin 0 -> 445 bytes examples/declarative/clock/second.png | Bin 0 -> 345 bytes src/declarative/util/qmlfollow.cpp | 57 ++++++++++++++++++++-- src/declarative/util/qmlfollow.h | 4 ++ 8 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 examples/declarative/clock/Clock.qml create mode 100644 examples/declarative/clock/background.png create mode 100644 examples/declarative/clock/display.qml create mode 100644 examples/declarative/clock/hour.png create mode 100644 examples/declarative/clock/minute.png create mode 100644 examples/declarative/clock/second.png diff --git a/examples/declarative/clock/Clock.qml b/examples/declarative/clock/Clock.qml new file mode 100644 index 0000000..4779bd5 --- /dev/null +++ b/examples/declarative/clock/Clock.qml @@ -0,0 +1,78 @@ +Item { + id: Clock + width: 200; height: 200 + property var time + property var hours + property var minutes + property var seconds + onTimeChanged: { + var date = new Date; + hours = date.getHours(); + minutes = date.getMinutes(); + seconds = date.getSeconds(); + } + Timer { + interval: 500; running: true; repeat: true; triggeredOnStart: true + onTriggered: Clock.time = new Date() + } + + Image { source: "background.png" } + Image { + x: 95 + y: 54 + source: "hour.png" + smooth: true + transform: Rotation { + id: HourRotation + originX: 4; originY: 45 + angle: 0 + angle: Follow { + spring: 2 + damping: .2 + source: Clock.hours * 50 * 3 + Clock.minutes / 2 + } + } + } + Image { + x: 95 + y: 30 + source: "minute.png" + smooth: true + transform: Rotation { + id: MinuteRotation + originX: 4; originY: 70 + angle: 0 + angle: Follow { + spring: 2 + damping: .2 + source: Clock.minutes * 6 + } + } + } + Image { + x: 96 + y: 40 + source: "second.png" + smooth: true + transform: Rotation { + id: SecondRotation + originX: 2; originY: 60 + angle: 0 + angle: Follow { + spring: 5 + damping: .25 + modulus: 360 + source: Clock.seconds * 6 + } + } + } + + Rect { + x: 93 + y: 94 + width: 11 + height: 11 + radius: 5 + color: "black" + } +} diff --git a/examples/declarative/clock/background.png b/examples/declarative/clock/background.png new file mode 100644 index 0000000..a885950 Binary files /dev/null and b/examples/declarative/clock/background.png differ diff --git a/examples/declarative/clock/display.qml b/examples/declarative/clock/display.qml new file mode 100644 index 0000000..0187a7e --- /dev/null +++ b/examples/declarative/clock/display.qml @@ -0,0 +1,5 @@ +Rect { + width: contents.width + height: contents.height + Clock { id: Clock } +} diff --git a/examples/declarative/clock/hour.png b/examples/declarative/clock/hour.png new file mode 100644 index 0000000..603466b Binary files /dev/null and b/examples/declarative/clock/hour.png differ diff --git a/examples/declarative/clock/minute.png b/examples/declarative/clock/minute.png new file mode 100644 index 0000000..0207405 Binary files /dev/null and b/examples/declarative/clock/minute.png differ diff --git a/examples/declarative/clock/second.png b/examples/declarative/clock/second.png new file mode 100644 index 0000000..bfcef68 Binary files /dev/null and b/examples/declarative/clock/second.png differ diff --git a/src/declarative/util/qmlfollow.cpp b/src/declarative/util/qmlfollow.cpp index c6d806a..b8e6685 100644 --- a/src/declarative/util/qmlfollow.cpp +++ b/src/declarative/util/qmlfollow.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include +#include #include #include "private/qobject_p.h" #include "qmlfollow.h" @@ -55,7 +56,7 @@ class QmlFollowPrivate : public QObjectPrivate public: QmlFollowPrivate() : sourceValue(0), maxVelocity(0), lastTime(0) - , mass(1.0), spring(0.), damping(0.), velocity(0), epsilon(0.005), enabled(true), mode(Track), clock(this) {} + , mass(1.0), spring(0.), damping(0.), velocity(0), epsilon(0.005), modulus(0.0), enabled(true), mode(Track), clock(this) {} QmlMetaProperty property; qreal currentValue; @@ -68,6 +69,7 @@ public: qreal damping; qreal velocity; qreal epsilon; + qreal modulus; bool enabled; enum Mode { @@ -92,6 +94,11 @@ void QmlFollowPrivate::tick(int time) int elapsed = time - lastTime; if (!elapsed) return; + qreal srcVal = sourceValue; + if (modulus != 0.0) { + currentValue = fmod(currentValue, modulus); + srcVal = fmod(srcVal, modulus); + } if (mode == Spring) { if (elapsed < 16) // capped at 62fps. return; @@ -99,7 +106,13 @@ void QmlFollowPrivate::tick(int time) // We'll do something much simpler which gives a result that looks fine. int count = (elapsed+8) / 16; for (int i = 0; i < count; ++i) { - qreal diff = sourceValue - currentValue; + qreal diff = srcVal - currentValue; + if (modulus != 0.0 && qAbs(diff) > modulus / 2) { + if (diff < 0) + diff += modulus; + else + diff -= modulus; + } velocity = velocity + spring * diff - damping * velocity; // The following line supports mass. Not sure its worth the extra divisions. // velocity = velocity + spring / mass * diff - damping / mass * velocity; @@ -111,24 +124,39 @@ void QmlFollowPrivate::tick(int time) velocity = -maxVelocity; } currentValue += velocity * 16.0 / 1000.0; + if (modulus != 0.0) { + currentValue = fmod(currentValue, modulus); + if (currentValue < 0.0) + currentValue += modulus; + } } - if (qAbs(velocity) < epsilon && qAbs(sourceValue - currentValue) < epsilon) { + if (qAbs(velocity) < epsilon && qAbs(srcVal - currentValue) < epsilon) { velocity = 0.0; - currentValue = sourceValue; + currentValue = srcVal; clock.stop(); } lastTime = time - (elapsed - count * 16); } else { qreal moveBy = elapsed * velocityms; - qreal diff = sourceValue - currentValue; + qreal diff = srcVal - currentValue; + if (modulus != 0.0 && qAbs(diff) > modulus / 2) { + if (diff < 0) + diff += modulus; + else + diff -= modulus; + } if (diff > 0) { currentValue += moveBy; + if (modulus != 0.0) + currentValue = fmod(currentValue, modulus); if (currentValue > sourceValue) { currentValue = sourceValue; clock.stop(); } } else { currentValue -= moveBy; + if (modulus != 0.0 && currentValue < 0.0) + currentValue = fmod(currentValue, modulus) + modulus; if (currentValue < sourceValue) { currentValue = sourceValue; clock.stop(); @@ -326,6 +354,25 @@ void QmlFollow::setEpsilon(qreal epsilon) } /*! + \qmlproperty qreal Follow::modulus + This property holds the modulus value. + + Setting a \a modulus forces the target value to "wrap around" at the modulus. + For example, setting the modulus to 360 will cause a value of 370 to wrap around to 10. +*/ +qreal QmlFollow::modulus() const +{ + Q_D(const QmlFollow); + return d->modulus; +} + +void QmlFollow::setModulus(qreal modulus) +{ + Q_D(QmlFollow); + d->modulus = modulus; +} + +/*! \qmlproperty qreal Follow::followValue The current value. */ diff --git a/src/declarative/util/qmlfollow.h b/src/declarative/util/qmlfollow.h index 0953f2c..07e15e9 100644 --- a/src/declarative/util/qmlfollow.h +++ b/src/declarative/util/qmlfollow.h @@ -64,8 +64,10 @@ class Q_DECLARATIVE_EXPORT QmlFollow : public QmlPropertyValueSource, Q_PROPERTY(qreal spring READ spring WRITE setSpring) Q_PROPERTY(qreal damping READ damping WRITE setDamping) Q_PROPERTY(qreal epsilon READ epsilon WRITE setEpsilon) + Q_PROPERTY(qreal modulus READ modulus WRITE setModulus) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled) Q_PROPERTY(qreal followValue READ value NOTIFY valueChanged) + Q_PROPERTY(qreal modulus READ modulus WRITE setModulus NOTIFY modulusChanged) public: QmlFollow(QObject *parent=0); @@ -83,6 +85,8 @@ public: void setDamping(qreal damping); qreal epsilon() const; void setEpsilon(qreal epsilon); + qreal modulus() const; + void setModulus(qreal modulus); bool enabled() const; void setEnabled(bool enabled); -- cgit v0.12