344a7614d2a3bb7e9a0e6d9ef8dd719107dc79fc
[platform/core/uifw/dali-toolkit.git] / 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 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali-toolkit/internal/controls/scrollable/scrollable-impl.h>
23 #include <dali-toolkit/internal/controls/scrollable/bouncing-effect-actor.h>
24 #include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
25
26 using namespace Dali;
27
28 namespace
29 {
30 const Vector2 OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE( 720.0f, 42.0f );
31 const float OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD = 180.0f;
32
33 // local helper function to resize the height of the bounce actor
34 float GetBounceActorHeight( float width )
35 {
36   return (width > OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD) ? OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height : OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height * 0.5f;
37 }
38
39 const float MAX_OVERSHOOT_NOTIFY_AMOUNT = 0.99f;                     // maximum amount to set notification for increased overshoot, beyond this we just wait for it to reduce again
40 const float MIN_OVERSHOOT_NOTIFY_AMOUNT = Math::MACHINE_EPSILON_0;  // minimum amount to set notification for reduced overshoot, beyond this we just wait for it to increase again
41 const float OVERSHOOT_NOTIFY_STEP = 0.01f;                          // amount to set notifications beyond current overshoot value
42
43 }
44
45 namespace Dali
46 {
47
48 namespace Toolkit
49 {
50
51 namespace Internal
52 {
53
54 ScrollOvershootIndicator::ScrollOvershootIndicator() :
55   mEffectX(NULL),
56   mEffectY(NULL)
57 {
58 }
59
60 ScrollOvershootIndicator::~ScrollOvershootIndicator()
61 {
62
63 }
64
65 ScrollOvershootIndicator* ScrollOvershootIndicator::New()
66 {
67   ScrollOvershootIndicator* scrollOvershootPtr = new ScrollOvershootIndicator();
68   return scrollOvershootPtr;
69 }
70
71 void ScrollOvershootIndicator::AttachToScrollable(Scrollable& scrollable)
72 {
73   if(!mEffectX)
74   {
75     mEffectX = ScrollOvershootEffectRipple::New(false, scrollable);
76   }
77   mEffectX->Apply();
78   if(!mEffectY)
79   {
80     mEffectY = ScrollOvershootEffectRipple::New(true, scrollable);
81   }
82   mEffectY->Apply();
83 }
84
85 void ScrollOvershootIndicator::DetachFromScrollable(Scrollable& scrollable)
86 {
87   if(mEffectX)
88   {
89     mEffectX->Remove(scrollable);
90   }
91   if(mEffectY)
92   {
93     mEffectY->Remove(scrollable);
94   }
95 }
96
97 void ScrollOvershootIndicator::Reset()
98 {
99   mEffectX->Reset();
100   mEffectY->Reset();
101 }
102
103 void ScrollOvershootIndicator::SetOvershootEffectColor( const Vector4& color )
104 {
105   if(mEffectX)
106   {
107     mEffectX->SetOvershootEffectColor(color);
108   }
109   if(mEffectY)
110   {
111     mEffectY->SetOvershootEffectColor(color);
112   }
113 }
114
115 void ScrollOvershootIndicator::ClearOvershoot()
116 {
117   if(mEffectX)
118   {
119     mEffectX->SetOvershoot(0.0f);
120   }
121   if(mEffectY)
122   {
123     mEffectY->SetOvershoot(0.0f);
124   }
125 }
126
127 ScrollOvershootEffect::ScrollOvershootEffect( bool vertical ) :
128     mVertical(vertical)
129 {
130
131 }
132
133 bool ScrollOvershootEffect::IsVertical() const
134 {
135   return mVertical;
136 }
137
138 ScrollOvershootEffectRipple::ScrollOvershootEffectRipple( bool vertical, Scrollable& scrollable ) :
139     ScrollOvershootEffect( vertical ),
140     mAttachedScrollView(scrollable),
141     mOvershootProperty(Property::INVALID_INDEX),
142     mEffectOvershootProperty(Property::INVALID_INDEX),
143     mOvershoot(0.0f),
144     mAnimationStateFlags(0)
145 {
146   /*
147   mOvershootOverlay = CreateBouncingEffectActor(mEffectOvershootProperty);
148   mOvershootOverlay.SetColor(mAttachedScrollView.GetOvershootEffectColor());
149   mOvershootOverlay.SetParentOrigin(ParentOrigin::TOP_LEFT);
150   mOvershootOverlay.SetAnchorPoint(AnchorPoint::TOP_LEFT);
151   mOvershootOverlay.SetDrawMode(DrawMode::OVERLAY);
152   mOvershootOverlay.SetVisible(false);
153   */
154 }
155
156 void ScrollOvershootEffectRipple::Apply()
157 {
158   Actor self = mAttachedScrollView.Self();
159   mOvershootProperty = IsVertical() ? Toolkit::ScrollView::Property::OVERSHOOT_Y : Toolkit::ScrollView::Property::OVERSHOOT_X;
160
161   // make sure height is set, since we only create a constraint for image width
162   //mOvershootOverlay.SetSize(OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.width, OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height);
163
164   //mAttachedScrollView.AddOverlay(mOvershootOverlay);
165
166   UpdatePropertyNotifications();
167 }
168
169 void ScrollOvershootEffectRipple::Remove( Scrollable& scrollable )
170 {
171 //  if(mOvershootOverlay)
172   {
173     if(mOvershootIncreaseNotification)
174     {
175       scrollable.Self().RemovePropertyNotification(mOvershootIncreaseNotification);
176       mOvershootIncreaseNotification.Reset();
177     }
178     if(mOvershootDecreaseNotification)
179     {
180       scrollable.Self().RemovePropertyNotification(mOvershootDecreaseNotification);
181       mOvershootDecreaseNotification.Reset();
182     }
183     //scrollable.RemoveOverlay(mOvershootOverlay);
184   }
185 }
186
187 void ScrollOvershootEffectRipple::Reset()
188 {
189 //  mOvershootOverlay.SetVisible(false);
190 //  mOvershootOverlay.SetProperty( mEffectOvershootProperty, 0.f);
191 }
192
193 void ScrollOvershootEffectRipple::UpdatePropertyNotifications()
194 {
195   float absOvershoot = fabsf(mOvershoot);
196
197   Actor self = mAttachedScrollView.Self();
198   // update overshoot increase notify
199   if( mOvershootIncreaseNotification )
200   {
201     self.RemovePropertyNotification( mOvershootIncreaseNotification );
202     mOvershootIncreaseNotification.Reset();
203   }
204   if( absOvershoot < MAX_OVERSHOOT_NOTIFY_AMOUNT )
205   {
206     float increaseStep = absOvershoot + OVERSHOOT_NOTIFY_STEP;
207     if( increaseStep > MAX_OVERSHOOT_NOTIFY_AMOUNT )
208     {
209       increaseStep = MAX_OVERSHOOT_NOTIFY_AMOUNT;
210     }
211     mOvershootIncreaseNotification = self.AddPropertyNotification( mOvershootProperty, OutsideCondition(-increaseStep, increaseStep) );
212     mOvershootIncreaseNotification.SetNotifyMode(PropertyNotification::NotifyOnTrue);
213     mOvershootIncreaseNotification.NotifySignal().Connect(this, &ScrollOvershootEffectRipple::OnOvershootNotification);
214   }
215
216   // update overshoot decrease notify
217   if( mOvershootDecreaseNotification )
218   {
219     self.RemovePropertyNotification( mOvershootDecreaseNotification );
220     mOvershootDecreaseNotification.Reset();
221   }
222   if( absOvershoot > MIN_OVERSHOOT_NOTIFY_AMOUNT )
223   {
224     float reduceStep = absOvershoot - OVERSHOOT_NOTIFY_STEP;
225     if( reduceStep < MIN_OVERSHOOT_NOTIFY_AMOUNT )
226     {
227       reduceStep = MIN_OVERSHOOT_NOTIFY_AMOUNT;
228     }
229     mOvershootDecreaseNotification = self.AddPropertyNotification( mOvershootProperty, InsideCondition(-reduceStep, reduceStep) );
230     mOvershootDecreaseNotification.SetNotifyMode(PropertyNotification::NotifyOnTrue);
231     mOvershootDecreaseNotification.NotifySignal().Connect(this, &ScrollOvershootEffectRipple::OnOvershootNotification);
232   }
233 }
234
235 void ScrollOvershootEffectRipple::SetOvershootEffectColor( const Vector4& color )
236 {
237 }
238
239 void ScrollOvershootEffectRipple::UpdateVisibility( bool visible )
240 {
241 }
242
243 void ScrollOvershootEffectRipple::OnOvershootNotification(PropertyNotification& source)
244 {
245   Actor self = mAttachedScrollView.Self();
246   mOvershoot = self.GetProperty<float>(mOvershootProperty);
247   SetOvershoot(mOvershoot, false);
248   UpdatePropertyNotifications();
249 }
250
251 void ScrollOvershootEffectRipple::SetOvershoot(float amount, bool animate)
252 {
253   float absAmount = fabsf(amount);
254   bool animatingOn = absAmount > Math::MACHINE_EPSILON_0;
255   if( (animatingOn && (mAnimationStateFlags & AnimatingIn)) )
256   {
257     // trying to do what we are already doing
258     if( mAnimationStateFlags & AnimateBack )
259     {
260       mAnimationStateFlags &= ~AnimateBack;
261     }
262     return;
263   }
264   if( (!animatingOn && (mAnimationStateFlags & AnimatingOut)) )
265   {
266     // trying to do what we are already doing
267     return;
268   }
269   if( !animatingOn && (mAnimationStateFlags & AnimatingIn) )
270   {
271     // dont interrupt while animating on
272     mAnimationStateFlags |= AnimateBack;
273     return;
274   }
275
276   if( absAmount > Math::MACHINE_EPSILON_1 )
277   {
278     UpdateVisibility(true);
279   }
280
281   float overshootAnimationSpeed = mAttachedScrollView.Self().GetProperty<float>(Toolkit::Scrollable::Property::OVERSHOOT_ANIMATION_SPEED);
282
283   if( animate && overshootAnimationSpeed > Math::MACHINE_EPSILON_0 )
284   {
285     //float currentOvershoot = 0.0f;//fabsf( mOvershootOverlay.GetProperty( mEffectOvershootProperty ).Get<float>() );
286     float duration = 0.05f;//mOvershootOverlay.GetCurrentSize().height * (animatingOn ? (1.0f - currentOvershoot) : currentOvershoot) / overshootAnimationSpeed;
287
288     if( duration > Math::MACHINE_EPSILON_0 )
289     {
290       if(mScrollOvershootAnimation)
291       {
292         mScrollOvershootAnimation.FinishedSignal().Disconnect( this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished );
293         mScrollOvershootAnimation.Stop();
294         mScrollOvershootAnimation.Reset();
295       }
296       mScrollOvershootAnimation = Animation::New(duration);
297       mScrollOvershootAnimation.FinishedSignal().Connect( this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished );
298       //mScrollOvershootAnimation.AnimateTo( Property(mOvershootOverlay, mEffectOvershootProperty), amount, TimePeriod(duration) );
299       mScrollOvershootAnimation.Play();
300       mAnimationStateFlags = animatingOn ? AnimatingIn : AnimatingOut;
301     }
302   }
303   else
304   {
305     //mOvershootOverlay.SetProperty( mEffectOvershootProperty, amount);
306   }
307 }
308
309 void ScrollOvershootEffectRipple::OnOvershootAnimFinished(Animation& animation)
310 {
311   bool animateOff = false;
312   if( mAnimationStateFlags & AnimatingOut )
313   {
314     // should now be offscreen
315     //mOvershootOverlay.SetVisible(false);
316   }
317   if( (mAnimationStateFlags & AnimateBack) )
318   {
319     animateOff = true;
320   }
321   mScrollOvershootAnimation.FinishedSignal().Disconnect( this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished );
322   mScrollOvershootAnimation.Stop();
323   mScrollOvershootAnimation.Reset();
324   mAnimationStateFlags = 0;
325   if( animateOff )
326   {
327     SetOvershoot(0.0f, true);
328   }
329 }
330
331 ScrollOvershootEffectRipplePtr ScrollOvershootEffectRipple::New( bool vertical, Scrollable& scrollable )
332 {
333   return new ScrollOvershootEffectRipple(vertical, scrollable);
334 }
335
336 } // namespace Internal
337
338 } // namespace Toolkit
339
340 } // namespace Dali