2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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.
17 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
18 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-wobble-effect-impl.h>
19 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h>
23 namespace // unnamed namespace
26 const float WOBBLEEFFECT_FRICTION_COEFFICIENT = 0.8f; ///< (deacc) - velocity multiplier per unit time (80%)
27 const float WOBBLEEFFECT_IMPULSE_DISTANCE_FACTOR = 0.1f; ///< (acc) - move by 10% of distance-delta per unit time
28 const float WOBBLEEFFECT_TIME_FACTOR = 30.0f; ///< (T) - 30 times faster (unit time = 1/30th sec)
29 const float WOBBLEEFFECT_ANIMATION_MAX_TIME = 60.0f; ///< Animation time (every time finishes, checks if it needs to go again)
30 const float WOBBLEEFFECT_STABLE_TIME_THRESHOLD = 0.5f; ///< Must be stable for more than half a second to stop animating.
31 const float STABILITY_DELTA_THRESHOLD = Math::MACHINE_EPSILON_10000; ///< When velocity delta is greater than this threshold it is considered in motion.
34 * Gets a property index. If the property doesn't already exist, then
35 * it will create the property.
36 * @param[in] handle The handle that owns or will own the property
37 * @param[in] name The name for this property
38 * @param[in] propertyValue The initial value for this property
39 * @return The property index for this property is returned.
41 Property::Index SafeRegisterProperty( Handle& handle, const std::string& name, Property::Value propertyValue )
43 Property::Index index = handle.GetPropertyIndex( name );
45 if(index == Property::INVALID_INDEX)
47 index = handle.RegisterProperty( name, propertyValue );
53 } // unnamed namespace
65 * ScrollView WobbleEffect constraint
66 * This constraint has a chase position and velocity, that chases
67 * a target position (scroll-position + scroll-offset). As it has a
68 * velocity. It will eventually pass it's target position, and chase back
69 * in the opposite direction. As it has a friction coefficient, it will
70 * gradually slow, and reach it's target position (stabilized).
72 struct ScrollViewWobbleEffectConstraint
75 * @param[in,out] wobbleEffect Reference to wobbleEffect instance
77 ScrollViewWobbleEffectConstraint(ScrollViewWobbleEffect& wobbleEffect)
78 : mChase(Vector3::ZERO),
79 mVelocity(Vector3::ZERO),
81 mStabilityTimeCounter(0),
83 mWobbleEffect(wobbleEffect),
90 * @param[out] current The new wobble value
91 * @param[in] propertyTime The current time since the wobble effect started
92 * @param[in] propertyPosition The scroll-position
93 * @param[in] propertyOffset The scroll-overshoot
95 Vector3 operator()(const Vector3& current,
96 const PropertyInput& propertyTime,
97 const PropertyInput& propertyPosition,
98 const PropertyInput& propertyOffsetX,
99 const PropertyInput& propertyOffsetY)
105 // check if animation cycle id has changed (if so then this spells
106 // the start of a new animation)
107 if(mAnimationCycleId != mWobbleEffect.GetAnimationCycleId())
114 // not stable (i.e. wobbling)
115 Vector3 offset(propertyOffsetX.GetFloat(), propertyOffsetY.GetFloat(), 0.0f);
116 const Vector3& position = propertyPosition.GetVector3() - offset;
117 const float time = propertyTime.GetFloat();
118 const float timePassed = time - mTime;
124 const Vector3 delta = position - mChase;
126 // Check to see if wobble has stabilized.
127 if( (fabsf(delta.x) < STABILITY_DELTA_THRESHOLD) &&
128 (fabsf(mVelocity.x) < STABILITY_DELTA_THRESHOLD) )
130 mStabilityTimeCounter+=timePassed;
132 if(mStabilityTimeCounter > WOBBLEEFFECT_STABLE_TIME_THRESHOLD)
134 mStabilityTimeCounter = 0.0f;
136 mWobbleEffect.IncrementStableCount();
137 mAnimationCycleId = mWobbleEffect.GetAnimationCycleId();
142 mStabilityTimeCounter = 0.0f;
147 float t = timePassed * WOBBLEEFFECT_TIME_FACTOR;
149 mVelocity *= pow( WOBBLEEFFECT_FRICTION_COEFFICIENT, t );
150 mVelocity += delta * 0.1f * t;
155 // stabilized, so chase should be exactly on position.
160 dir.x = propertyPosition.GetVector3().x - mChase.x;
161 dir.y = propertyPosition.GetVector3().y - mChase.y;
167 Vector3 mChase; ///< Chaser position
168 Vector3 mVelocity; ///< Velocity of Chaser
169 float mTime; ///< Current time.
170 float mStabilityTimeCounter; ///< Time in seconds that stable for.
171 bool mStabilized; ///< Stabilized flag.
172 ScrollViewWobbleEffect& mWobbleEffect; ///< Reference to Wobble Effect
173 unsigned int mAnimationCycleId; ///< Animation Cycle Id
176 ScrollViewWobbleEffect::ScrollViewWobbleEffect()
177 : mPropertyTime(Property::INVALID_INDEX)
182 ScrollViewWobbleEffect::~ScrollViewWobbleEffect()
186 void ScrollViewWobbleEffect::IncrementStableCount()
191 unsigned int ScrollViewWobbleEffect::GetAnimationCycleId() const
193 return mAnimationCycleId;
196 void ScrollViewWobbleEffect::OnAttach(Toolkit::ScrollView& scrollView)
199 mAnimationCycleId = 0;
201 // Create effect-time property if not already created.
202 if(mPropertyTime == Property::INVALID_INDEX)
204 mPropertyTime = SafeRegisterProperty( scrollView, Toolkit::ScrollViewWobbleEffect::EFFECT_TIME, 0.0f );
207 // Connect to the scroll view signals
208 scrollView.ScrollStartedSignal().Connect(this, &ScrollViewWobbleEffect::OnScrollStart);
209 scrollView.ScrollUpdatedSignal().Connect(this, &ScrollViewWobbleEffect::OnScrollUpdate);
210 scrollView.ScrollCompletedSignal().Connect(this, &ScrollViewWobbleEffect::OnScrollComplete);
212 AttachActor(scrollView);
215 void ScrollViewWobbleEffect::OnDetach(Toolkit::ScrollView& scrollView)
217 scrollView.ScrollStartedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnScrollStart);
218 scrollView.ScrollUpdatedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnScrollUpdate);
219 scrollView.ScrollCompletedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnScrollComplete);
223 mAnimation.FinishedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnAnimationFinished);
229 void ScrollViewWobbleEffect::AttachActor(Actor actor)
231 Property::Index propertyPosition = actor.GetPropertyIndex(Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME);
232 Property::Index propertyOvershootX = actor.GetPropertyIndex(Toolkit::ScrollView::SCROLL_OVERSHOOT_X_PROPERTY_NAME);
233 Property::Index propertyOvershootY = actor.GetPropertyIndex(Toolkit::ScrollView::SCROLL_OVERSHOOT_Y_PROPERTY_NAME);
235 // Create effect-overshoot property if not already created.
236 Property::Index propertyEffectOvershoot = actor.GetPropertyIndex(Toolkit::ScrollViewWobbleEffect::EFFECT_OVERSHOOT);
237 if(propertyEffectOvershoot == Property::INVALID_INDEX)
239 propertyEffectOvershoot = actor.RegisterProperty(Toolkit::ScrollViewWobbleEffect::EFFECT_OVERSHOOT, Vector3::ZERO);
242 Actor scrollView = GetScrollView();
244 Constraint constraint = Constraint::New<Vector3>( propertyEffectOvershoot,
245 Source(scrollView, mPropertyTime),
246 Source(actor, propertyPosition),
247 Source(actor, propertyOvershootX),
248 Source(actor, propertyOvershootY),
249 ScrollViewWobbleEffectConstraint(*this) );
250 actor.ApplyConstraint(constraint);
253 void ScrollViewWobbleEffect::DetachActor(Actor actor)
255 // TODO: remove the specific constraint defined in AttachActor (and possibly
256 // unregister property) - neither functionality exists in Dali.
259 void ScrollViewWobbleEffect::ContinueAnimation(float endTime)
262 // continue animating
265 mAnimation.FinishedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnAnimationFinished);
269 Actor scrollView = GetScrollView();
271 mAnimation = Animation::New(WOBBLEEFFECT_ANIMATION_MAX_TIME);
272 mAnimation.AnimateTo( Property(scrollView, mPropertyTime), endTime, AlphaFunctions::Linear );
273 mAnimation.FinishedSignal().Connect(this, &ScrollViewWobbleEffect::OnAnimationFinished);
278 void ScrollViewWobbleEffect::OnScrollStart( const Vector3& position )
280 // When animation starts, all constraints all unstable,
281 // and we change the animation cycle id.
285 GetScrollView().SetProperty(mPropertyTime, 0.0f);
287 ContinueAnimation(WOBBLEEFFECT_ANIMATION_MAX_TIME);
290 void ScrollViewWobbleEffect::OnScrollUpdate( const Vector3& position )
295 void ScrollViewWobbleEffect::OnScrollComplete( const Vector3& position )
300 void ScrollViewWobbleEffect::OnAnimationFinished( Animation& animation )
302 if(mStableCurrent!=1)
304 // still unstable, so continue animating.
305 float endTime = GetScrollView().GetProperty<float>(mPropertyTime) + WOBBLEEFFECT_ANIMATION_MAX_TIME;
306 ContinueAnimation(endTime);
310 } // namespace Internal
312 } // namespace Toolkit