2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
19 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-wobble-effect-impl.h>
20 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h>
24 namespace // unnamed namespace
27 const float WOBBLEEFFECT_FRICTION_COEFFICIENT = 0.8f; ///< (deacc) - velocity multiplier per unit time (80%)
28 const float WOBBLEEFFECT_IMPULSE_DISTANCE_FACTOR = 0.1f; ///< (acc) - move by 10% of distance-delta per unit time
29 const float WOBBLEEFFECT_TIME_FACTOR = 30.0f; ///< (T) - 30 times faster (unit time = 1/30th sec)
30 const float WOBBLEEFFECT_ANIMATION_MAX_TIME = 60.0f; ///< Animation time (every time finishes, checks if it needs to go again)
31 const float WOBBLEEFFECT_STABLE_TIME_THRESHOLD = 0.5f; ///< Must be stable for more than half a second to stop animating.
32 const float STABILITY_DELTA_THRESHOLD = Math::MACHINE_EPSILON_10000; ///< When velocity delta is greater than this threshold it is considered in motion.
35 * Gets a property index. If the property doesn't already exist, then
36 * it will create the property.
37 * @param[in] handle The handle that owns or will own the property
38 * @param[in] name The name for this property
39 * @param[in] propertyValue The initial value for this property
40 * @return The property index for this property is returned.
42 Property::Index SafeRegisterProperty( Handle& handle, const std::string& name, Property::Value propertyValue )
44 Property::Index index = handle.GetPropertyIndex( name );
46 if(index == Property::INVALID_INDEX)
48 index = handle.RegisterProperty( name, propertyValue );
54 } // unnamed namespace
66 * ScrollView WobbleEffect constraint
67 * This constraint has a chase position and velocity, that chases
68 * a target position (scroll-position + scroll-offset). As it has a
69 * velocity. It will eventually pass it's target position, and chase back
70 * in the opposite direction. As it has a friction coefficient, it will
71 * gradually slow, and reach it's target position (stabilized).
73 struct ScrollViewWobbleEffectConstraint
76 * @param[in,out] wobbleEffect Reference to wobbleEffect instance
78 ScrollViewWobbleEffectConstraint(ScrollViewWobbleEffect& wobbleEffect)
79 : mChase(Vector3::ZERO),
80 mVelocity(Vector3::ZERO),
82 mStabilityTimeCounter(0),
84 mWobbleEffect(wobbleEffect),
91 * @param[out] current The new wobble value
92 * @param[in] propertyTime The current time since the wobble effect started
93 * @param[in] propertyPosition The scroll-position
94 * @param[in] propertyOffset The scroll-overshoot
96 Vector3 operator()(const Vector3& current,
97 const PropertyInput& propertyTime,
98 const PropertyInput& propertyPosition,
99 const PropertyInput& propertyOffsetX,
100 const PropertyInput& propertyOffsetY)
106 // check if animation cycle id has changed (if so then this spells
107 // the start of a new animation)
108 if(mAnimationCycleId != mWobbleEffect.GetAnimationCycleId())
115 // not stable (i.e. wobbling)
116 Vector3 offset(propertyOffsetX.GetFloat(), propertyOffsetY.GetFloat(), 0.0f);
117 const Vector3& position = propertyPosition.GetVector3() - offset;
118 const float time = propertyTime.GetFloat();
119 const float timePassed = time - mTime;
125 const Vector3 delta = position - mChase;
127 // Check to see if wobble has stabilized.
128 if( (fabsf(delta.x) < STABILITY_DELTA_THRESHOLD) &&
129 (fabsf(mVelocity.x) < STABILITY_DELTA_THRESHOLD) )
131 mStabilityTimeCounter+=timePassed;
133 if(mStabilityTimeCounter > WOBBLEEFFECT_STABLE_TIME_THRESHOLD)
135 mStabilityTimeCounter = 0.0f;
137 mWobbleEffect.IncrementStableCount();
138 mAnimationCycleId = mWobbleEffect.GetAnimationCycleId();
143 mStabilityTimeCounter = 0.0f;
148 float t = timePassed * WOBBLEEFFECT_TIME_FACTOR;
150 mVelocity *= pow( WOBBLEEFFECT_FRICTION_COEFFICIENT, t );
151 mVelocity += delta * 0.1f * t;
156 // stabilized, so chase should be exactly on position.
161 dir.x = propertyPosition.GetVector3().x - mChase.x;
162 dir.y = propertyPosition.GetVector3().y - mChase.y;
168 Vector3 mChase; ///< Chaser position
169 Vector3 mVelocity; ///< Velocity of Chaser
170 float mTime; ///< Current time.
171 float mStabilityTimeCounter; ///< Time in seconds that stable for.
172 bool mStabilized; ///< Stabilized flag.
173 ScrollViewWobbleEffect& mWobbleEffect; ///< Reference to Wobble Effect
174 unsigned int mAnimationCycleId; ///< Animation Cycle Id
177 ScrollViewWobbleEffect::ScrollViewWobbleEffect()
178 : mPropertyTime(Property::INVALID_INDEX),
184 ScrollViewWobbleEffect::~ScrollViewWobbleEffect()
188 void ScrollViewWobbleEffect::IncrementStableCount()
193 unsigned int ScrollViewWobbleEffect::GetAnimationCycleId() const
195 return mAnimationCycleId;
198 void ScrollViewWobbleEffect::OnAttach(Toolkit::ScrollView& scrollView)
201 mAnimationCycleId = 0;
203 // Create effect-time property if not already created.
204 if(mPropertyTime == Property::INVALID_INDEX)
206 mPropertyTime = SafeRegisterProperty( scrollView, Toolkit::ScrollViewWobbleEffect::EFFECT_TIME, 0.0f );
209 // Connect to the scroll view signals
210 scrollView.ScrollStartedSignal().Connect(this, &ScrollViewWobbleEffect::OnScrollStart);
211 scrollView.ScrollUpdatedSignal().Connect(this, &ScrollViewWobbleEffect::OnScrollUpdate);
212 scrollView.ScrollCompletedSignal().Connect(this, &ScrollViewWobbleEffect::OnScrollComplete);
214 AttachActor(scrollView);
217 void ScrollViewWobbleEffect::OnDetach(Toolkit::ScrollView& scrollView)
219 scrollView.ScrollStartedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnScrollStart);
220 scrollView.ScrollUpdatedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnScrollUpdate);
221 scrollView.ScrollCompletedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnScrollComplete);
225 mAnimation.FinishedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnAnimationFinished);
231 void ScrollViewWobbleEffect::AttachActor(Actor actor)
233 Property::Index propertyPosition = actor.GetPropertyIndex(Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME);
234 Property::Index propertyOvershootX = actor.GetPropertyIndex(Toolkit::ScrollView::SCROLL_OVERSHOOT_X_PROPERTY_NAME);
235 Property::Index propertyOvershootY = actor.GetPropertyIndex(Toolkit::ScrollView::SCROLL_OVERSHOOT_Y_PROPERTY_NAME);
237 // Create effect-overshoot property if not already created.
238 Property::Index propertyEffectOvershoot = actor.GetPropertyIndex(Toolkit::ScrollViewWobbleEffect::EFFECT_OVERSHOOT);
239 if(propertyEffectOvershoot == Property::INVALID_INDEX)
241 propertyEffectOvershoot = actor.RegisterProperty(Toolkit::ScrollViewWobbleEffect::EFFECT_OVERSHOOT, Vector3::ZERO);
244 Actor scrollView = GetScrollView();
246 Constraint constraint = Constraint::New<Vector3>( propertyEffectOvershoot,
247 Source(scrollView, mPropertyTime),
248 Source(actor, propertyPosition),
249 Source(actor, propertyOvershootX),
250 Source(actor, propertyOvershootY),
251 ScrollViewWobbleEffectConstraint(*this) );
252 actor.ApplyConstraint(constraint);
255 void ScrollViewWobbleEffect::DetachActor(Actor actor)
257 // TODO: remove the specific constraint defined in AttachActor (and possibly
258 // unregister property) - neither functionality exists in Dali.
261 void ScrollViewWobbleEffect::ContinueAnimation(float endTime)
264 // continue animating
267 mAnimation.FinishedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnAnimationFinished);
271 Actor scrollView = GetScrollView();
273 mAnimation = Animation::New(WOBBLEEFFECT_ANIMATION_MAX_TIME);
274 mAnimation.AnimateTo( Property(scrollView, mPropertyTime), endTime, AlphaFunctions::Linear );
275 mAnimation.FinishedSignal().Connect(this, &ScrollViewWobbleEffect::OnAnimationFinished);
280 void ScrollViewWobbleEffect::OnScrollStart( const Vector3& position )
282 // When animation starts, all constraints all unstable,
283 // and we change the animation cycle id.
287 GetScrollView().SetProperty(mPropertyTime, 0.0f);
289 ContinueAnimation(WOBBLEEFFECT_ANIMATION_MAX_TIME);
292 void ScrollViewWobbleEffect::OnScrollUpdate( const Vector3& position )
297 void ScrollViewWobbleEffect::OnScrollComplete( const Vector3& position )
302 void ScrollViewWobbleEffect::OnAnimationFinished( Animation& animation )
304 if(mStableCurrent!=1)
306 // still unstable, so continue animating.
307 float endTime = GetScrollView().GetProperty<float>(mPropertyTime) + WOBBLEEFFECT_ANIMATION_MAX_TIME;
308 ContinueAnimation(endTime);
312 } // namespace Internal
314 } // namespace Toolkit