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[in,out] direction The new wobble value
93 * @param[in] inputs Contains:
94 * The current time since the wobble effect started
96 * The scroll-overshoot x & y
98 void operator()( Vector3& direction, const PropertyInputContainer& inputs )
102 // check if animation cycle id has changed (if so then this spells
103 // the start of a new animation)
104 if(mAnimationCycleId != mWobbleEffect.GetAnimationCycleId())
111 // not stable (i.e. wobbling)
112 Vector3 offset(inputs[2]->GetFloat(), inputs[3]->GetFloat(), 0.0f);
113 const Vector3& position = inputs[1]->GetVector3() - offset;
114 const float time = inputs[0]->GetFloat();
115 const float timePassed = time - mTime;
121 const Vector3 delta = position - mChase;
123 // Check to see if wobble has stabilized.
124 if( (fabsf(delta.x) < STABILITY_DELTA_THRESHOLD) &&
125 (fabsf(mVelocity.x) < STABILITY_DELTA_THRESHOLD) )
127 mStabilityTimeCounter+=timePassed;
129 if(mStabilityTimeCounter > WOBBLEEFFECT_STABLE_TIME_THRESHOLD)
131 mStabilityTimeCounter = 0.0f;
133 mWobbleEffect.IncrementStableCount();
134 mAnimationCycleId = mWobbleEffect.GetAnimationCycleId();
139 mStabilityTimeCounter = 0.0f;
144 float t = timePassed * WOBBLEEFFECT_TIME_FACTOR;
146 mVelocity *= pow( WOBBLEEFFECT_FRICTION_COEFFICIENT, t );
147 mVelocity += delta * 0.1f * t;
152 // stabilized, so chase should be exactly on position.
157 direction.x = position.x - mChase.x;
158 direction.y = position.y - mChase.y;
162 Vector3 mChase; ///< Chaser position
163 Vector3 mVelocity; ///< Velocity of Chaser
164 float mTime; ///< Current time.
165 float mStabilityTimeCounter; ///< Time in seconds that stable for.
166 bool mStabilized; ///< Stabilized flag.
167 ScrollViewWobbleEffect& mWobbleEffect; ///< Reference to Wobble Effect
168 unsigned int mAnimationCycleId; ///< Animation Cycle Id
171 ScrollViewWobbleEffect::ScrollViewWobbleEffect()
172 : mPropertyTime(Property::INVALID_INDEX),
178 ScrollViewWobbleEffect::~ScrollViewWobbleEffect()
182 void ScrollViewWobbleEffect::IncrementStableCount()
187 unsigned int ScrollViewWobbleEffect::GetAnimationCycleId() const
189 return mAnimationCycleId;
192 void ScrollViewWobbleEffect::OnAttach(Toolkit::ScrollView& scrollView)
195 mAnimationCycleId = 0;
197 // Create effect-time property if not already created.
198 if(mPropertyTime == Property::INVALID_INDEX)
200 mPropertyTime = SafeRegisterProperty( scrollView, Toolkit::ScrollViewWobbleEffect::EFFECT_TIME, 0.0f );
203 // Connect to the scroll view signals
204 scrollView.ScrollStartedSignal().Connect(this, &ScrollViewWobbleEffect::OnScrollStart);
205 scrollView.ScrollUpdatedSignal().Connect(this, &ScrollViewWobbleEffect::OnScrollUpdate);
206 scrollView.ScrollCompletedSignal().Connect(this, &ScrollViewWobbleEffect::OnScrollComplete);
208 AttachActor(scrollView);
211 void ScrollViewWobbleEffect::OnDetach(Toolkit::ScrollView& scrollView)
213 scrollView.ScrollStartedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnScrollStart);
214 scrollView.ScrollUpdatedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnScrollUpdate);
215 scrollView.ScrollCompletedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnScrollComplete);
219 mAnimation.FinishedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnAnimationFinished);
225 void ScrollViewWobbleEffect::AttachActor(Actor actor)
227 // Create effect-overshoot property if not already created.
228 Property::Index propertyEffectOvershoot = actor.GetPropertyIndex(Toolkit::ScrollViewWobbleEffect::EFFECT_OVERSHOOT);
229 if(propertyEffectOvershoot == Property::INVALID_INDEX)
231 propertyEffectOvershoot = actor.RegisterProperty(Toolkit::ScrollViewWobbleEffect::EFFECT_OVERSHOOT, Vector3::ZERO);
234 Actor scrollView = GetScrollView();
236 Constraint constraint = Constraint::New<Vector3>( actor, propertyEffectOvershoot, ScrollViewWobbleEffectConstraint(*this) );
237 constraint.AddSource( Source( scrollView, mPropertyTime ) );
238 constraint.AddSource( Source( actor, Toolkit::ScrollView::Property::SCROLL_POSITION ) );
239 constraint.AddSource( Source( actor, Toolkit::ScrollView::Property::OVERSHOOT_X ) );
240 constraint.AddSource( Source( actor, Toolkit::ScrollView::Property::OVERSHOOT_Y ) );
244 void ScrollViewWobbleEffect::DetachActor(Actor actor)
246 // TODO: remove the specific constraint defined in AttachActor (and possibly
247 // unregister property) - neither functionality exists in Dali.
250 void ScrollViewWobbleEffect::ContinueAnimation(float endTime)
253 // continue animating
256 mAnimation.FinishedSignal().Disconnect(this, &ScrollViewWobbleEffect::OnAnimationFinished);
260 Actor scrollView = GetScrollView();
262 mAnimation = Animation::New(WOBBLEEFFECT_ANIMATION_MAX_TIME);
263 mAnimation.AnimateTo( Property(scrollView, mPropertyTime), endTime, AlphaFunctions::Linear );
264 mAnimation.FinishedSignal().Connect(this, &ScrollViewWobbleEffect::OnAnimationFinished);
269 void ScrollViewWobbleEffect::OnScrollStart( const Vector3& position )
271 // When animation starts, all constraints all unstable,
272 // and we change the animation cycle id.
276 GetScrollView().SetProperty(mPropertyTime, 0.0f);
278 ContinueAnimation(WOBBLEEFFECT_ANIMATION_MAX_TIME);
281 void ScrollViewWobbleEffect::OnScrollUpdate( const Vector3& position )
286 void ScrollViewWobbleEffect::OnScrollComplete( const Vector3& position )
291 void ScrollViewWobbleEffect::OnAnimationFinished( Animation& animation )
293 if(mStableCurrent!=1)
295 // still unstable, so continue animating.
296 float endTime = GetScrollView().GetProperty<float>(mPropertyTime) + WOBBLEEFFECT_ANIMATION_MAX_TIME;
297 ContinueAnimation(endTime);
301 } // namespace Internal
303 } // namespace Toolkit