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.
19 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
20 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-wobble-effect-impl.h>
21 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h>
25 namespace // unnamed namespace
28 const float WOBBLEEFFECT_FRICTION_COEFFICIENT = 0.8f; ///< (deacc) - velocity multiplier per unit time (80%)
29 const float WOBBLEEFFECT_IMPULSE_DISTANCE_FACTOR = 0.1f; ///< (acc) - move by 10% of distance-delta per unit time
30 const float WOBBLEEFFECT_TIME_FACTOR = 30.0f; ///< (T) - 30 times faster (unit time = 1/30th sec)
31 const float WOBBLEEFFECT_ANIMATION_MAX_TIME = 60.0f; ///< Animation time (every time finishes, checks if it needs to go again)
32 const float WOBBLEEFFECT_STABLE_TIME_THRESHOLD = 0.5f; ///< Must be stable for more than half a second to stop animating.
33 const float STABILITY_DELTA_THRESHOLD = Math::MACHINE_EPSILON_10000; ///< When velocity delta is greater than this threshold it is considered in motion.
36 * Gets a property index. If the property doesn't already exist, then
37 * it will create the property.
38 * @param[in] handle The handle that owns or will own the property
39 * @param[in] name The name for this property
40 * @param[in] propertyValue The initial value for this property
41 * @return The property index for this property is returned.
43 Property::Index SafeRegisterProperty( Handle& handle, const std::string& name, Property::Value propertyValue )
45 Property::Index index = handle.GetPropertyIndex( name );
47 if(index == Property::INVALID_INDEX)
49 index = handle.RegisterProperty( name, propertyValue );
55 } // unnamed namespace
67 * ScrollView WobbleEffect constraint
68 * This constraint has a chase position and velocity, that chases
69 * a target position (scroll-position + scroll-offset). As it has a
70 * velocity. It will eventually pass it's target position, and chase back
71 * in the opposite direction. As it has a friction coefficient, it will
72 * gradually slow, and reach it's target position (stabilized).
74 struct ScrollViewWobbleEffectConstraint
77 * @param[in,out] wobbleEffect Reference to wobbleEffect instance
79 ScrollViewWobbleEffectConstraint(ScrollViewWobbleEffect& wobbleEffect)
80 : mChase(Vector3::ZERO),
81 mVelocity(Vector3::ZERO),
83 mStabilityTimeCounter(0),
85 mWobbleEffect(wobbleEffect),
92 * @param[out] current The new wobble value
93 * @param[in] propertyTime The current time since the wobble effect started
94 * @param[in] propertyPosition The scroll-position
95 * @param[in] propertyOffset The scroll-overshoot
97 Vector3 operator()(const Vector3& current,
98 const PropertyInput& propertyTime,
99 const PropertyInput& propertyPosition,
100 const PropertyInput& propertyOffsetX,
101 const PropertyInput& propertyOffsetY)
107 // check if animation cycle id has changed (if so then this spells
108 // the start of a new animation)
109 if(mAnimationCycleId != mWobbleEffect.GetAnimationCycleId())
116 // not stable (i.e. wobbling)
117 Vector3 offset(propertyOffsetX.GetFloat(), propertyOffsetY.GetFloat(), 0.0f);
118 const Vector3& position = propertyPosition.GetVector3() - offset;
119 const float time = propertyTime.GetFloat();
120 const float timePassed = time - mTime;
126 const Vector3 delta = position - mChase;
128 // Check to see if wobble has stabilized.
129 if( (fabsf(delta.x) < STABILITY_DELTA_THRESHOLD) &&
130 (fabsf(mVelocity.x) < STABILITY_DELTA_THRESHOLD) )
132 mStabilityTimeCounter+=timePassed;
134 if(mStabilityTimeCounter > WOBBLEEFFECT_STABLE_TIME_THRESHOLD)
136 mStabilityTimeCounter = 0.0f;
138 mWobbleEffect.IncrementStableCount();
139 mAnimationCycleId = mWobbleEffect.GetAnimationCycleId();
144 mStabilityTimeCounter = 0.0f;
149 float t = timePassed * WOBBLEEFFECT_TIME_FACTOR;
151 mVelocity *= pow( WOBBLEEFFECT_FRICTION_COEFFICIENT, t );
152 mVelocity += delta * 0.1f * t;
157 // stabilized, so chase should be exactly on position.
162 dir.x = propertyPosition.GetVector3().x - mChase.x;
163 dir.y = propertyPosition.GetVector3().y - mChase.y;
169 Vector3 mChase; ///< Chaser position
170 Vector3 mVelocity; ///< Velocity of Chaser
171 float mTime; ///< Current time.
172 float mStabilityTimeCounter; ///< Time in seconds that stable for.
173 bool mStabilized; ///< Stabilized flag.
174 ScrollViewWobbleEffect& mWobbleEffect; ///< Reference to Wobble Effect
175 unsigned int mAnimationCycleId; ///< Animation Cycle Id
178 ScrollViewWobbleEffect::ScrollViewWobbleEffect()
179 : mPropertyTime(Property::INVALID_INDEX),
185 ScrollViewWobbleEffect::~ScrollViewWobbleEffect()
189 void ScrollViewWobbleEffect::IncrementStableCount()
194 unsigned int ScrollViewWobbleEffect::GetAnimationCycleId() const
196 return mAnimationCycleId;
199 void ScrollViewWobbleEffect::OnAttach(Toolkit::ScrollView& scrollView)
202 mAnimationCycleId = 0;
204 // Create effect-time property if not already created.
205 if(mPropertyTime == Property::INVALID_INDEX)
207 mPropertyTime = SafeRegisterProperty( scrollView, Toolkit::ScrollViewWobbleEffect::EFFECT_TIME, 0.0f );
210 // Connect to the scroll view signals
211 scrollView.ScrollStartedSignal().Connect(this, &ScrollViewWobbleEffect::OnScrollStart);
212 scrollView.ScrollUpdatedSignal().Connect(this, &ScrollViewWobbleEffect::OnScrollUpdate);
213 scrollView.ScrollCompletedSignal().Connect(this, &ScrollViewWobbleEffect::OnScrollComplete);
215 AttachActor(scrollView);
218 void ScrollViewWobbleEffect::OnDetach(Toolkit::ScrollView& scrollView)
220 scrollView.ScrollStartedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnScrollStart);
221 scrollView.ScrollUpdatedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnScrollUpdate);
222 scrollView.ScrollCompletedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnScrollComplete);
226 mAnimation.FinishedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnAnimationFinished);
232 void ScrollViewWobbleEffect::AttachActor(Actor actor)
234 Property::Index propertyPosition = actor.GetPropertyIndex(Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME);
235 Property::Index propertyOvershootX = actor.GetPropertyIndex(Toolkit::ScrollView::SCROLL_OVERSHOOT_X_PROPERTY_NAME);
236 Property::Index propertyOvershootY = actor.GetPropertyIndex(Toolkit::ScrollView::SCROLL_OVERSHOOT_Y_PROPERTY_NAME);
238 // Create effect-overshoot property if not already created.
239 Property::Index propertyEffectOvershoot = actor.GetPropertyIndex(Toolkit::ScrollViewWobbleEffect::EFFECT_OVERSHOOT);
240 if(propertyEffectOvershoot == Property::INVALID_INDEX)
242 propertyEffectOvershoot = actor.RegisterProperty(Toolkit::ScrollViewWobbleEffect::EFFECT_OVERSHOOT, Vector3::ZERO);
245 Actor scrollView = GetScrollView();
247 Constraint constraint = Constraint::New<Vector3>( propertyEffectOvershoot,
248 Source(scrollView, mPropertyTime),
249 Source(actor, propertyPosition),
250 Source(actor, propertyOvershootX),
251 Source(actor, propertyOvershootY),
252 ScrollViewWobbleEffectConstraint(*this) );
253 actor.ApplyConstraint(constraint);
256 void ScrollViewWobbleEffect::DetachActor(Actor actor)
258 // TODO: remove the specific constraint defined in AttachActor (and possibly
259 // unregister property) - neither functionality exists in Dali.
262 void ScrollViewWobbleEffect::ContinueAnimation(float endTime)
265 // continue animating
268 mAnimation.FinishedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnAnimationFinished);
272 Actor scrollView = GetScrollView();
274 mAnimation = Animation::New(WOBBLEEFFECT_ANIMATION_MAX_TIME);
275 mAnimation.AnimateTo( Property(scrollView, mPropertyTime), endTime, AlphaFunctions::Linear );
276 mAnimation.FinishedSignal().Connect(this, &ScrollViewWobbleEffect::OnAnimationFinished);
281 void ScrollViewWobbleEffect::OnScrollStart( const Vector3& position )
283 // When animation starts, all constraints all unstable,
284 // and we change the animation cycle id.
288 GetScrollView().SetProperty(mPropertyTime, 0.0f);
290 ContinueAnimation(WOBBLEEFFECT_ANIMATION_MAX_TIME);
293 void ScrollViewWobbleEffect::OnScrollUpdate( const Vector3& position )
298 void ScrollViewWobbleEffect::OnScrollComplete( const Vector3& position )
303 void ScrollViewWobbleEffect::OnAnimationFinished( Animation& animation )
305 if(mStableCurrent!=1)
307 // still unstable, so continue animating.
308 float endTime = GetScrollView().GetProperty<float>(mPropertyTime) + WOBBLEEFFECT_ANIMATION_MAX_TIME;
309 ContinueAnimation(endTime);
313 } // namespace Internal
315 } // namespace Toolkit