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)
183 ScrollViewWobbleEffect::~ScrollViewWobbleEffect()
187 void ScrollViewWobbleEffect::IncrementStableCount()
192 unsigned int ScrollViewWobbleEffect::GetAnimationCycleId() const
194 return mAnimationCycleId;
197 void ScrollViewWobbleEffect::OnAttach(Toolkit::ScrollView& scrollView)
200 mAnimationCycleId = 0;
202 // Create effect-time property if not already created.
203 if(mPropertyTime == Property::INVALID_INDEX)
205 mPropertyTime = SafeRegisterProperty( scrollView, Toolkit::ScrollViewWobbleEffect::EFFECT_TIME, 0.0f );
208 // Connect to the scroll view signals
209 scrollView.ScrollStartedSignal().Connect(this, &ScrollViewWobbleEffect::OnScrollStart);
210 scrollView.ScrollUpdatedSignal().Connect(this, &ScrollViewWobbleEffect::OnScrollUpdate);
211 scrollView.ScrollCompletedSignal().Connect(this, &ScrollViewWobbleEffect::OnScrollComplete);
213 AttachActor(scrollView);
216 void ScrollViewWobbleEffect::OnDetach(Toolkit::ScrollView& scrollView)
218 scrollView.ScrollStartedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnScrollStart);
219 scrollView.ScrollUpdatedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnScrollUpdate);
220 scrollView.ScrollCompletedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnScrollComplete);
224 mAnimation.FinishedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnAnimationFinished);
230 void ScrollViewWobbleEffect::AttachActor(Actor actor)
232 Property::Index propertyPosition = actor.GetPropertyIndex(Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME);
233 Property::Index propertyOvershootX = actor.GetPropertyIndex(Toolkit::ScrollView::SCROLL_OVERSHOOT_X_PROPERTY_NAME);
234 Property::Index propertyOvershootY = actor.GetPropertyIndex(Toolkit::ScrollView::SCROLL_OVERSHOOT_Y_PROPERTY_NAME);
236 // Create effect-overshoot property if not already created.
237 Property::Index propertyEffectOvershoot = actor.GetPropertyIndex(Toolkit::ScrollViewWobbleEffect::EFFECT_OVERSHOOT);
238 if(propertyEffectOvershoot == Property::INVALID_INDEX)
240 propertyEffectOvershoot = actor.RegisterProperty(Toolkit::ScrollViewWobbleEffect::EFFECT_OVERSHOOT, Vector3::ZERO);
243 Actor scrollView = GetScrollView();
245 Constraint constraint = Constraint::New<Vector3>( propertyEffectOvershoot,
246 Source(scrollView, mPropertyTime),
247 Source(actor, propertyPosition),
248 Source(actor, propertyOvershootX),
249 Source(actor, propertyOvershootY),
250 ScrollViewWobbleEffectConstraint(*this) );
251 actor.ApplyConstraint(constraint);
254 void ScrollViewWobbleEffect::DetachActor(Actor actor)
256 // TODO: remove the specific constraint defined in AttachActor (and possibly
257 // unregister property) - neither functionality exists in Dali.
260 void ScrollViewWobbleEffect::ContinueAnimation(float endTime)
263 // continue animating
266 mAnimation.FinishedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnAnimationFinished);
270 Actor scrollView = GetScrollView();
272 mAnimation = Animation::New(WOBBLEEFFECT_ANIMATION_MAX_TIME);
273 mAnimation.AnimateTo( Property(scrollView, mPropertyTime), endTime, AlphaFunctions::Linear );
274 mAnimation.FinishedSignal().Connect(this, &ScrollViewWobbleEffect::OnAnimationFinished);
279 void ScrollViewWobbleEffect::OnScrollStart( const Vector3& position )
281 // When animation starts, all constraints all unstable,
282 // and we change the animation cycle id.
286 GetScrollView().SetProperty(mPropertyTime, 0.0f);
288 ContinueAnimation(WOBBLEEFFECT_ANIMATION_MAX_TIME);
291 void ScrollViewWobbleEffect::OnScrollUpdate( const Vector3& position )
296 void ScrollViewWobbleEffect::OnScrollComplete( const Vector3& position )
301 void ScrollViewWobbleEffect::OnAnimationFinished( Animation& animation )
303 if(mStableCurrent!=1)
305 // still unstable, so continue animating.
306 float endTime = GetScrollView().GetProperty<float>(mPropertyTime) + WOBBLEEFFECT_ANIMATION_MAX_TIME;
307 ContinueAnimation(endTime);
311 } // namespace Internal
313 } // namespace Toolkit