(ScrollView) Remove unused functions
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / scrollable / scroll-view / scroll-overshoot-indicator-impl.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.h>
19
20 // EXTERNAL INCLUDES
21 #include <boost/bind.hpp>
22
23 #include <dali-toolkit/internal/controls/scrollable/scrollable-impl.h>
24 #include <dali-toolkit/internal/controls/scrollable/bouncing-effect-actor.h>
25 #include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
26
27 using namespace Dali;
28
29 namespace
30 {
31 const float DEFAULT_MAX_OVERSHOOT_HEIGHT = 36.0f;  // 36 pixels
32 const Vector2 OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE( 720.0f, 42.0f );
33 const float OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD = 180.0f;
34
35 // local helper function to resize the height of the bounce actor
36 float GetBounceActorHeight( float width )
37 {
38   return (width > OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD) ? OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height : OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height * 0.5f;
39 }
40
41 const float DEFAULT_OVERSHOOT_ANIMATION_DURATION = 0.35f;  // time in seconds
42 const float MAX_OVERSHOOT_NOTIFY_AMOUNT = 0.9f;                     // maximum amount to set notification for increased overshoot, beyond this we just wait for it to reduce again
43 const float MIN_OVERSHOOT_NOTIFY_AMOUNT = Math::MACHINE_EPSILON_1;  // minimum amount to set notification for reduced overshoot, beyond this we just wait for it to increase again
44 const float OVERSHOOT_NOTIFY_STEP = 0.1f;                           // amount to set notifications beyond current overshoot value
45
46 }
47
48 namespace Dali
49 {
50
51 namespace Toolkit
52 {
53
54 namespace Internal
55 {
56
57 ScrollOvershootIndicator::ScrollOvershootIndicator() :
58   mEffectX(NULL),
59   mEffectY(NULL)
60 {
61 }
62
63 ScrollOvershootIndicator::~ScrollOvershootIndicator()
64 {
65
66 }
67
68 ScrollOvershootIndicator* ScrollOvershootIndicator::New()
69 {
70   ScrollOvershootIndicator* scrollOvershootPtr = new ScrollOvershootIndicator();
71   return scrollOvershootPtr;
72 }
73
74 void ScrollOvershootIndicator::AttachToScrollable(Scrollable& scrollable)
75 {
76   if(!mEffectX)
77   {
78     mEffectX = ScrollOvershootEffectRipple::New(false, scrollable);
79   }
80   mEffectX->Apply();
81   if(!mEffectY)
82   {
83     mEffectY = ScrollOvershootEffectRipple::New(true, scrollable);
84   }
85   mEffectY->Apply();
86 }
87
88 void ScrollOvershootIndicator::DetachFromScrollable(Scrollable& scrollable)
89 {
90   if(mEffectX)
91   {
92     mEffectX->Remove(scrollable);
93   }
94   if(mEffectY)
95   {
96     mEffectY->Remove(scrollable);
97   }
98 }
99
100 void ScrollOvershootIndicator::Reset()
101 {
102   mEffectX->Reset();
103   mEffectY->Reset();
104 }
105
106 void ScrollOvershootIndicator::SetOvershootEffectColor( const Vector4& color )
107 {
108   if(mEffectX)
109   {
110     mEffectX->SetOvershootEffectColor(color);
111   }
112   if(mEffectY)
113   {
114     mEffectY->SetOvershootEffectColor(color);
115   }
116 }
117
118 void ScrollOvershootIndicator::ClearOvershoot()
119 {
120   if(mEffectX)
121   {
122     mEffectX->SetOvershoot(0.0f);
123   }
124   if(mEffectY)
125   {
126     mEffectY->SetOvershoot(0.0f);
127   }
128 }
129
130 ScrollOvershootEffect::ScrollOvershootEffect( bool vertical ) :
131     mVertical(vertical)
132 {
133
134 }
135
136 bool ScrollOvershootEffect::IsVertical() const
137 {
138   return mVertical;
139 }
140
141 ScrollOvershootEffectRipple::ScrollOvershootEffectRipple( bool vertical, Scrollable& scrollable ) :
142     ScrollOvershootEffect( vertical ),
143     mAttachedScrollView(scrollable),
144     mCanScrollPropertyIndex(Property::INVALID_INDEX),
145     mOvershootProperty(Property::INVALID_INDEX),
146     mEffectOvershootProperty(Property::INVALID_INDEX),
147     mMaxOvershootImageSize(DEFAULT_MAX_OVERSHOOT_HEIGHT),
148     mOvershootAnimationDuration(DEFAULT_OVERSHOOT_ANIMATION_DURATION),
149     mOvershoot(0.0f),
150     mAnimationStateFlags(0)
151 {
152   mOvershootOverlay = CreateBouncingEffectActor(mEffectOvershootProperty);
153   mOvershootOverlay.SetColor(mAttachedScrollView.GetOvershootEffectColor());
154   mOvershootOverlay.SetParentOrigin(ParentOrigin::TOP_LEFT);
155   mOvershootOverlay.SetAnchorPoint(AnchorPoint::TOP_LEFT);
156   mOvershootOverlay.SetDrawMode(DrawMode::OVERLAY);
157   mOvershootOverlay.SetVisible(false);
158
159 }
160
161 void ScrollOvershootEffectRipple::Apply()
162 {
163   Actor self = mAttachedScrollView.Self();
164   mOvershootProperty = self.GetPropertyIndex(IsVertical() ? Toolkit::ScrollView::SCROLL_OVERSHOOT_Y_PROPERTY_NAME : Toolkit::ScrollView::SCROLL_OVERSHOOT_X_PROPERTY_NAME);
165   mCanScrollPropertyIndex = self.GetPropertyIndex(IsVertical() ? Scrollable::SCROLLABLE_CAN_SCROLL_VERTICAL : Scrollable::SCROLLABLE_CAN_SCROLL_HORIZONTAL);
166
167   // make sure height is set, since we only create a constraint for image width
168   mOvershootOverlay.SetSize(OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.width, OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height);
169
170   mAttachedScrollView.AddOverlay(mOvershootOverlay);
171
172   UpdatePropertyNotifications();
173 }
174
175 void ScrollOvershootEffectRipple::Remove( Scrollable& scrollable )
176 {
177   if(mOvershootOverlay)
178   {
179     if(mOvershootIncreaseNotification)
180     {
181       scrollable.Self().RemovePropertyNotification(mOvershootIncreaseNotification);
182       mOvershootIncreaseNotification.Reset();
183     }
184     if(mOvershootDecreaseNotification)
185     {
186       scrollable.Self().RemovePropertyNotification(mOvershootDecreaseNotification);
187       mOvershootDecreaseNotification.Reset();
188     }
189     scrollable.RemoveOverlay(mOvershootOverlay);
190   }
191 }
192
193 void ScrollOvershootEffectRipple::Reset()
194 {
195   mOvershootOverlay.SetVisible(false);
196   mOvershootOverlay.SetProperty( mEffectOvershootProperty, 0.f);
197 }
198
199 void ScrollOvershootEffectRipple::UpdatePropertyNotifications()
200 {
201   float absOvershoot = fabsf(mOvershoot);
202
203   Actor self = mAttachedScrollView.Self();
204   // update overshoot increase notify
205   if( mOvershootIncreaseNotification )
206   {
207     self.RemovePropertyNotification( mOvershootIncreaseNotification );
208     mOvershootIncreaseNotification.Reset();
209   }
210   if( absOvershoot < MAX_OVERSHOOT_NOTIFY_AMOUNT )
211   {
212     float increaseStep = absOvershoot + OVERSHOOT_NOTIFY_STEP;
213     if( increaseStep > MAX_OVERSHOOT_NOTIFY_AMOUNT )
214     {
215       increaseStep = MAX_OVERSHOOT_NOTIFY_AMOUNT;
216     }
217     mOvershootIncreaseNotification = self.AddPropertyNotification( mOvershootProperty, OutsideCondition(-increaseStep, increaseStep) );
218     mOvershootIncreaseNotification.SetNotifyMode(PropertyNotification::NotifyOnTrue);
219     mOvershootIncreaseNotification.NotifySignal().Connect(this, &ScrollOvershootEffectRipple::OnOvershootNotification);
220   }
221
222   // update overshoot decrease notify
223   if( mOvershootDecreaseNotification )
224   {
225     self.RemovePropertyNotification( mOvershootDecreaseNotification );
226     mOvershootDecreaseNotification.Reset();
227   }
228   if( absOvershoot > MIN_OVERSHOOT_NOTIFY_AMOUNT )
229   {
230     float reduceStep = absOvershoot - OVERSHOOT_NOTIFY_STEP;
231     if( reduceStep < MIN_OVERSHOOT_NOTIFY_AMOUNT )
232     {
233       reduceStep = MIN_OVERSHOOT_NOTIFY_AMOUNT;
234     }
235     mOvershootDecreaseNotification = self.AddPropertyNotification( mOvershootProperty, InsideCondition(-reduceStep, reduceStep) );
236     mOvershootDecreaseNotification.SetNotifyMode(PropertyNotification::NotifyOnTrue);
237     mOvershootDecreaseNotification.NotifySignal().Connect(this, &ScrollOvershootEffectRipple::OnOvershootNotification);
238   }
239 }
240
241 void ScrollOvershootEffectRipple::SetOvershootEffectColor( const Vector4& color )
242 {
243   if(mOvershootOverlay)
244   {
245     mOvershootOverlay.SetColor(color);
246   }
247 }
248
249 void ScrollOvershootEffectRipple::UpdateVisibility( bool visible )
250 {
251   mOvershootOverlay.SetVisible(visible);
252   // make sure overshoot image is correctly placed
253   if( visible )
254   {
255     Actor self = mAttachedScrollView.Self();
256     if(mOvershoot > 0.0f)
257     {
258       // positive overshoot
259       const Vector3 size = mOvershootOverlay.GetCurrentSize();
260       Vector3 relativeOffset;
261       const Vector3 parentSize = self.GetCurrentSize();
262       if(IsVertical())
263       {
264         mOvershootOverlay.SetRotation(Quaternion(0.0f, Vector3::ZAXIS));
265         mOvershootOverlay.SetSize(parentSize.width, GetBounceActorHeight(parentSize.width), size.depth);
266       }
267       else
268       {
269         mOvershootOverlay.SetRotation(Quaternion(1.5f * Math::PI, Vector3::ZAXIS));
270         mOvershootOverlay.SetSize(parentSize.height, GetBounceActorHeight(parentSize.height), size.depth);
271         relativeOffset = Vector3(0.0f, 1.0f, 0.0f);
272       }
273       mOvershootOverlay.SetPosition(relativeOffset * parentSize);
274     }
275     else
276     {
277       // negative overshoot
278       const Vector3 size = mOvershootOverlay.GetCurrentSize();
279       Vector3 relativeOffset;
280       const Vector3 parentSize = self.GetCurrentSize();
281       if(IsVertical())
282       {
283         mOvershootOverlay.SetRotation(Quaternion(Math::PI, Vector3::ZAXIS));
284         mOvershootOverlay.SetSize(parentSize.width, GetBounceActorHeight(parentSize.width), size.depth);
285         relativeOffset = Vector3(1.0f, 1.0f, 0.0f);
286       }
287       else
288       {
289         mOvershootOverlay.SetRotation(Quaternion(0.5f * Math::PI, Vector3::ZAXIS));
290         mOvershootOverlay.SetSize(parentSize.height, GetBounceActorHeight(parentSize.height), size.depth);
291         relativeOffset = Vector3(1.0f, 0.0f, 0.0f);
292       }
293       mOvershootOverlay.SetPosition(relativeOffset * parentSize);
294     }
295   }
296 }
297
298 void ScrollOvershootEffectRipple::OnOvershootNotification(PropertyNotification& source)
299 {
300   Actor self = mAttachedScrollView.Self();
301   mOvershoot = self.GetProperty<float>(mOvershootProperty);
302   if( source == mOvershootIncreaseNotification )
303   {
304     if( mOvershoot > Math::MACHINE_EPSILON_0 )
305     {
306       SetOvershoot(1.0f);
307     }
308     else if ( mOvershoot < -Math::MACHINE_EPSILON_0 )
309     {
310       SetOvershoot(-1.0f);
311     }
312   }
313   else if( source == mOvershootDecreaseNotification )
314   {
315     SetOvershoot(0.0f);
316     // overshoot reducing
317   }
318   UpdatePropertyNotifications();
319 }
320
321 void ScrollOvershootEffectRipple::SetOvershoot(float amount, bool animate)
322 {
323   float absAmount = fabsf(amount);
324   bool animatingOn = absAmount > Math::MACHINE_EPSILON_0;
325   if( (animatingOn && (mAnimationStateFlags & AnimatingIn)) )
326   {
327     // trying to do what we are already doing
328     if( mAnimationStateFlags & AnimateBack )
329     {
330       mAnimationStateFlags &= ~AnimateBack;
331     }
332     return;
333   }
334   if( (!animatingOn && (mAnimationStateFlags & AnimatingOut)) )
335   {
336     // trying to do what we are already doing
337     return;
338   }
339   if( !animatingOn && (mAnimationStateFlags & AnimatingIn) )
340   {
341     // dont interrupt while animating on
342     mAnimationStateFlags |= AnimateBack;
343     return;
344   }
345   // When we need to animate overshoot to 0
346   if( mOvershootAnimationDuration > Math::MACHINE_EPSILON_1 )
347   {
348     // setup the new overshoot to 0 animation
349     float currentOvershoot = fabsf( mOvershootOverlay.GetProperty( mEffectOvershootProperty ).Get<float>() );
350     float duration = mOvershootAnimationDuration * (animatingOn ? (1.0f - currentOvershoot) : currentOvershoot);
351
352     if( duration > Math::MACHINE_EPSILON_0 )
353     {
354       if(mScrollOvershootAnimation)
355       {
356         mScrollOvershootAnimation.FinishedSignal().Disconnect( this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished );
357         mScrollOvershootAnimation.Stop();
358         mScrollOvershootAnimation.Clear();
359         mScrollOvershootAnimation = NULL;
360       }
361       mScrollOvershootAnimation = Animation::New(duration);
362       mScrollOvershootAnimation.FinishedSignal().Connect( this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished );
363       mScrollOvershootAnimation.AnimateTo( Property(mOvershootOverlay, mEffectOvershootProperty), amount, TimePeriod(duration) );
364       mScrollOvershootAnimation.Play();
365       mAnimationStateFlags = animatingOn ? AnimatingIn : AnimatingOut;
366     }
367   }
368   else
369   {
370     mOvershootOverlay.SetProperty( mEffectOvershootProperty, amount);
371   }
372   if( absAmount > Math::MACHINE_EPSILON_1 )
373   {
374     UpdateVisibility(true);
375   }
376 }
377
378 void ScrollOvershootEffectRipple::OnOvershootAnimFinished(Animation& animation)
379 {
380   bool animateOff = false;
381   if( mAnimationStateFlags & AnimatingOut )
382   {
383     // should now be offscreen
384     mOvershootOverlay.SetVisible(false);
385   }
386   if( (mAnimationStateFlags & AnimateBack) )
387   {
388     animateOff = true;
389   }
390   mScrollOvershootAnimation.FinishedSignal().Disconnect( this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished );
391   mScrollOvershootAnimation.Stop();
392   mScrollOvershootAnimation.Clear();
393   mScrollOvershootAnimation = NULL;
394   mAnimationStateFlags = 0;
395   if( animateOff )
396   {
397     SetOvershoot(0.0f, true);
398   }
399 }
400
401 ScrollOvershootEffectRipplePtr ScrollOvershootEffectRipple::New( bool vertical, Scrollable& scrollable )
402 {
403   return new ScrollOvershootEffectRipple(vertical, scrollable);
404 }
405
406 } // namespace Internal
407
408 } // namespace Toolkit
409
410 } // namespace Dali