Implemented scroll bar control
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / scroll-component / scroll-bar-internal-impl.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
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
7 //
8 //     http://floralicense.org/license/
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 #include <dali-toolkit/internal/controls/scroll-component/scroll-bar-internal-impl.h>
18 #include <dali-toolkit/public-api/enums.h>
19
20 using namespace Dali;
21
22 namespace
23 {
24 /**
25  * Squares input value
26  * i.e. y = x*x
27  * @param[in] x Input value to be squared
28  * @return Result (x*x)
29  */
30 template<typename T>
31 inline T Square(T x)
32 {
33   return x*x;
34 }
35
36 const char* BAR_TAB_IMAGE_PATH = DALI_IMAGE_DIR "popup_scroll.png";
37 const Vector4 BAR_TAB_NINE_PATCH_BORDER(0.0f, 12.0f, 14.0f, 14.0f);
38 const Vector3 BAR_TAB_SIZE(18.0f, 72.0f, 0.0f);
39 const Vector3 BAR_TAB_OFFSET_V(-18.0f, 0.0f, 0.1f);
40 const Vector3 BAR_TAB_OFFSET_H(0.0f, -18.0f, 0.1f);
41 const float BAR_CONTRACT_DELAY(0.8f);
42 const float BAR_SHOW_TIME(0.4f);
43 const float BAR_HIDE_TIME(0.5f);
44 const int SECOND_UNIT(1000);
45
46 /**
47  * ScrollBarInternal Visibility Constraint
48  * Returns whether scroll bar is visible
49  */
50 bool ScrollBarInternalVisibilityConstraint(const bool& current,
51     const PropertyInput& canScrollProperty)
52 {
53   bool canScroll = canScrollProperty.GetBoolean();
54   return canScroll;
55 }
56
57 /**
58  * ScrollBarInternal Size Constraint
59  * Resize ScrollBarInternal Size depends on both ScrollSize and DomainSize
60  */
61 struct ScrollBarInternalSizeConstraint
62 {
63   /**
64    * @param[in] vertical Whether this constraint controls a vertical scrollbar (true)
65    * or a horizontal one (false)
66    */
67   ScrollBarInternalSizeConstraint(bool vertical)
68   : mVertical(vertical)
69   {
70   }
71
72   /**
73    * Constraint operator
74    * @param[in] current The current ScrollBarInternal size
75    * @param[in] scrollMinProperty The container's minimum position.
76    * @param[in] scrollMaxProperty The container's maximum position.
77    * @param[in] scrollDirectionProperty The container's scroll direction.
78    * @param[in] scrollSizeProperty The container's size of viewport.
79    * @return The new ScrollBarInternal position is returned.
80    */
81   Vector3 operator()(const Vector3& current,
82                      const PropertyInput& scrollMinProperty,
83                      const PropertyInput& scrollMaxProperty,
84                      const PropertyInput& scrollDirectionProperty,
85                      const PropertyInput& scrollSizeProperty)
86   {
87     const Vector3& min = scrollMinProperty.GetVector3();
88     const Vector3& max = scrollMaxProperty.GetVector3();
89     const Vector3& scrollDirection = scrollDirectionProperty.GetVector3();
90     const Toolkit::ControlOrientation::Type& orientation = static_cast<Toolkit::ControlOrientation::Type>(scrollDirection.z);
91     const Vector3& size = scrollSizeProperty.GetVector3();
92     const Vector3 domainSize = max - min;
93
94     if (mVertical && Toolkit::IsVertical(orientation))
95     {
96       float mod = fabsf(domainSize.height) > size.height ? size.height * ( size.height / fabsf(domainSize.height) ) : size.height * ( (size.height - fabsf(domainSize.height * 0.5f)) / size.height);
97       return Vector3( current.width, mod, current.depth );
98     }
99     else
100     {
101       float mod = fabsf(domainSize.height) > size.width ? size.width * ( size.width / fabsf(domainSize.height) ) : size.width * ( (size.width - fabsf(domainSize.height * 0.5f)) / size.width);
102       return Vector3( current.width, mod, current.depth );
103     }
104   }
105
106   bool mVertical;  ///< Whether vertical or horizontal
107 };
108
109 /**
110  * ScrollBarInternal rotation Constraint
111  * Rotate ScrollBarInternal depends on the scroll direction
112  */
113 struct ScrollBarInternalRotationConstraint
114 {
115   /**
116    * @param[in] vertical Whether this constraint controls a vertical scrollbar (true)
117    * or a horizontal one (false)
118    */
119   ScrollBarInternalRotationConstraint(bool vertical)
120   : mVertical(vertical)
121   {
122   }
123
124   /**
125    * Constraint operator
126    * @param[in] current The current ScrollBarInternal rotation
127    * @param[in] scrollDirectionProperty The container's scroll direction.
128    * @return The new ScrollBarInternal rotation is returned.
129    */
130   Quaternion operator()(const Quaternion& current,
131                         const PropertyInput& scrollDirectionProperty)
132   {
133     const Vector3& scrollDirection = scrollDirectionProperty.GetVector3();
134     const Toolkit::ControlOrientation::Type& orientation = static_cast<Toolkit::ControlOrientation::Type>(scrollDirection.z);
135
136     if( (mVertical && Toolkit::IsVertical(orientation)) || (!mVertical && Toolkit::IsHorizontal(orientation)) )
137     {
138       return Quaternion(0.0f, Vector3::ZAXIS);
139     }
140     else
141     {
142       return Quaternion(0.5f * Math::PI, Vector3::ZAXIS);
143     }
144   }
145
146   bool mVertical;  ///< Whether vertical or horizontal
147 };
148
149 /**
150  * ScrollBarInternal Position Constraint
151  * Positions the scroll bar to reflect the current scroll position
152  * within the domain.
153  */
154 struct ScrollBarInternalPositionConstraint
155 {
156   /**
157    * @param[in] vertical Whether this constraint controls a vertical scrollbar (true)
158    * or a horizontal one (false)
159    * @param[in] wrap Whether to base scrollbar on original position or wrapped position
160    */
161   ScrollBarInternalPositionConstraint(bool vertical, bool wrap = false)
162   : mVertical(vertical),
163     mWrap(wrap)
164   {
165   }
166
167   /**
168    * Constraint operator
169    * @param[in] current The current ScrollBarInternal position
170    * @param[in] scrollBarSizeProperty ScrollBarInternal size
171    * @param[in] scrollRelativePositionProperty The container's relative position (from 0.0 -> 1.0 in each axis)
172    * @param[in] scrollMinProperty The container's minimum position.
173    * @param[in] scrollMaxProperty The container's maximum position.
174    * @param[in] scrollDirectionProperty The container's scroll direction.
175    * @param[in] scrollSizeProperty The container's size of viewport.
176    * @return The new ScrollBarInternal position is returned.
177    */
178   Vector3 operator()(const Vector3&    current,
179                      const PropertyInput& scrollBarSizeProperty,
180                      const PropertyInput& scrollRelativePositionProperty,
181                      const PropertyInput& scrollMinProperty,
182                      const PropertyInput& scrollMaxProperty,
183                      const PropertyInput& scrollDirectionProperty,
184                      const PropertyInput& scrollSizeProperty)
185   {
186     Vector3 barSize = scrollBarSizeProperty.GetVector3();
187     Vector3 relativePosition = scrollRelativePositionProperty.GetVector3();
188     Vector3 size = scrollSizeProperty.GetVector3();
189     const Vector3& min = scrollMinProperty.GetVector3();
190     const Vector3& max = scrollMaxProperty.GetVector3();
191     const Vector3& scrollDirection = scrollDirectionProperty.GetVector3();
192     const Toolkit::ControlOrientation::Type& orientation = static_cast<Toolkit::ControlOrientation::Type>(scrollDirection.z);
193
194     Vector3 domainSize = max - min;
195     domainSize.x = fabsf(domainSize.x);
196     domainSize.y = fabsf(domainSize.y);
197     domainSize -= size;
198
199     Vector3 mask;            // Mask movement aspect of scroll bar
200     Vector3 relativeOffset;  // base position of scroll bar in relation to the container
201     Vector3 absoluteOffset;  // absolute offset position of scroll bar
202
203     if(mVertical)
204     {
205       switch(orientation)
206       {
207         case Toolkit::ControlOrientation::Up:
208         {
209           mask = Vector3::YAXIS;
210           relativeOffset = (scrollDirection.y < 0.0f && relativePosition.y <= 0.0f) ? Vector3(1.0f, 1.0f, 0.0f) : Vector3(1.0f, 0.0f, 0.0f); // Right side of stage.
211           absoluteOffset = (scrollDirection.y < 0.0f && relativePosition.y <= 0.0f) ? BAR_TAB_OFFSET_V + Vector3( barSize.width * 0.5f, -barSize.height * 0.5f, 1.0f ) : BAR_TAB_OFFSET_V + Vector3( barSize.width * 0.5f, barSize.height * 0.5f, 1.0f );
212           break;
213         }
214         case Toolkit::ControlOrientation::Left:
215         {
216           mask = Vector3::XAXIS;
217           relativeOffset = (scrollDirection.x <= 0.0f && relativePosition.y <= 0.0f) ? Vector3(1.0f, 0.0f, 0.0f) : Vector3(0.0f, 0.0f, 0.0f); // Bottom side of stage.
218           absoluteOffset = (scrollDirection.x <= 0.0f && relativePosition.y <= 0.0f) ? Vector3( -barSize.height * 0.5f, barSize.width * 0.5f, 1.0f ) : Vector3( barSize.height * 0.5f, barSize.width * 0.5f, 1.0f );
219           break;
220         }
221         case Toolkit::ControlOrientation::Down:
222         {
223           mask = Vector3::YAXIS;
224           relativeOffset = (scrollDirection.y <= 0.0f && relativePosition.y <= 0.0f) ? Vector3(0.0f, 1.0f, 0.0f) : Vector3(0.0f, 0.0f, 0.0f); // Left side of stage.
225           absoluteOffset = (scrollDirection.y <= 0.0f && relativePosition.y <= 0.0f) ? Vector3( barSize.width * 0.5f, -barSize.height * 0.5f, 1.0f ) : Vector3( barSize.width * 0.5f, barSize.height * 0.5f, 1.0f );
226           break;
227         }
228         case Toolkit::ControlOrientation::Right:
229         {
230           mask = Vector3::XAXIS;
231           relativeOffset = (scrollDirection.x <= 0.0f && relativePosition.y <= 0.0f) ? Vector3(1.0f, 1.0f, 0.0f) : Vector3(0.0f, 1.0f, 0.0f); // Up side of stage.
232           absoluteOffset = (scrollDirection.x <= 0.0f && relativePosition.y <= 0.0f) ? Vector3( -barSize.height * 0.5f, -barSize.width * 0.5f, 1.0f ) : Vector3( barSize.height * 0.5f, -barSize.width * 0.5f, 1.0f );
233           break;
234         }
235       }
236     }
237     else
238     {
239       mask = Vector3::XAXIS;
240       relativeOffset = Vector3(0.0f, 1.0f, 0.0f); // Bottom side of stage.
241       absoluteOffset = BAR_TAB_OFFSET_H + Vector3( barSize.height * 0.5f, barSize.width * 0.5f, 1.0f );
242     }
243
244     Vector3 maskedRelativePosition = Toolkit::IsVertical(orientation) ? Vector3(relativePosition.x * (size.x-barSize.y), relativePosition.y * (size.y-barSize.y), 0.0f) * mask
245                                    : Vector3(relativePosition.y * (size.x-barSize.y), relativePosition.x * (size.y-barSize.y), 0.0f) * mask;
246
247     Vector3 finalPosition = relativeOffset * size + absoluteOffset + maskedRelativePosition;
248
249     // If Wrapped Slider, then position 1 domain either before or after current slider.
250     if(mWrap)
251     {
252       if(finalPosition.x < 0.5f)
253       {
254         finalPosition.x += size.x;
255       }
256       else
257       {
258         finalPosition.x -= size.x;
259       }
260
261       if(finalPosition.y < 0.5f)
262       {
263         finalPosition.y += size.y;
264       }
265       else
266       {
267         finalPosition.y -= size.y;
268       }
269     }
270
271     return finalPosition;
272   }
273
274   bool mVertical;           ///< Whether vertical or horizontal.
275   bool mWrap;               ///< Whether to wrap this position.
276 };
277
278 /**
279  * ScrollBarInternal HitSize Constraint
280  * Resizes HitArea to size of the container.
281  */
282 struct ScrollBarInternalHitSizeConstraint
283 {
284   /**
285    * @param[in] vertical Whether this constraint controls a vertical scrollbar (true)
286    * or a horizontal one (false)
287    * @param[in] thickness The thickness of the scrollbar
288    */
289   ScrollBarInternalHitSizeConstraint(bool vertical,
290                              float thickness)
291   : mVertical(vertical),
292     mThickness(thickness)
293   {
294   }
295
296   /**
297    * Constraint operator
298    * @param[in] current The current HitSize
299    * @param[in] scrollDirectionProperty The container's scroll direction.
300    * @param[in] scrollSizeProperty The container's size of viewport.
301    * @return The new ScrollBarInternal Hit Area size is returned.
302    */
303   Vector3 operator()(const Vector3&    current,
304                      const PropertyInput& scrollDirectionProperty,
305                      const PropertyInput& scrollSizeProperty)
306   {
307     const Vector3& scrollDirection = scrollDirectionProperty.GetVector3();
308     const Toolkit::ControlOrientation::Type& orientation = static_cast<Toolkit::ControlOrientation::Type>(scrollDirection.z);
309     Vector3 size = scrollSizeProperty.GetVector3();
310
311     Vector3 mask;            // Mask size aspect of hit area.
312     Vector3 offset;          // Add Offset size.
313
314     if( (mVertical && Toolkit::IsVertical(orientation)) || (!mVertical && Toolkit::IsHorizontal(orientation)) )
315     {
316       mask = Vector3::YAXIS;
317       offset = Vector3::XAXIS * mThickness;
318     }
319     else
320     {
321       mask = Vector3::XAXIS;
322       offset = Vector3::YAXIS * mThickness;
323     }
324
325     return size * mask + offset;
326   }
327
328   bool mVertical;           ///< Whether vertical or horizontal.
329   float mThickness;          ///< Thickness of the scroll bar
330 };
331
332 } // unnamed namespace
333
334 namespace Dali
335 {
336
337 namespace Toolkit
338 {
339
340 namespace Internal
341 {
342
343 namespace
344 {
345
346 using namespace Dali;
347
348 BaseHandle Create()
349 {
350   return BaseHandle();
351 }
352
353 TypeRegistration mType( typeid(Toolkit::ScrollBarInternal), typeid(Toolkit::ScrollComponent), Create );
354
355 }
356
357 ScrollBarInternal::ScrollBarInternal(Toolkit::Scrollable& container, bool vertical)
358 : mContainer(static_cast<Toolkit::Internal::Scrollable&>(container.GetImplementation())),
359   mVertical(vertical),
360   mAxisMask(vertical ? Vector3::YAXIS : Vector3::XAXIS),
361   mDragMode(false)
362 {
363   Image sliderImage = Image::New( BAR_TAB_IMAGE_PATH );
364
365   mSlider = ImageActor::New( sliderImage );
366   mSlider.SetParentOrigin( ParentOrigin::TOP_LEFT );
367   mSlider.SetAnchorPoint( AnchorPoint::CENTER );
368   mSlider.SetSize( BAR_TAB_SIZE );
369   mSlider.SetStyle( ImageActor::STYLE_NINE_PATCH );
370   mSlider.SetNinePatchBorder( BAR_TAB_NINE_PATCH_BORDER );
371
372   // A duplicate Slider should appear 1 domain away from the original Slider
373   mSliderWrap = ImageActor::New( sliderImage );
374   mSliderWrap.SetParentOrigin( ParentOrigin::TOP_LEFT );
375   mSliderWrap.SetAnchorPoint( AnchorPoint::CENTER );
376   mSliderWrap.SetSize( BAR_TAB_SIZE );
377   mSliderWrap.SetStyle( ImageActor::STYLE_NINE_PATCH );
378   mSliderWrap.SetNinePatchBorder( BAR_TAB_NINE_PATCH_BORDER );
379
380   // target the container to observe for scrolling
381   Actor target = mContainer.Self();
382   Constraint constraint = Constraint::New<bool>( Actor::VISIBLE,
383                                       Source( target, vertical ? target.GetPropertyIndex(Scrollable::SCROLLABLE_CAN_SCROLL_VERTICAL) : target.GetPropertyIndex(Scrollable::SCROLLABLE_CAN_SCROLL_HORIZONTAL)),
384                                       ScrollBarInternalVisibilityConstraint );
385   mSlider.ApplyConstraint( constraint );
386   mSliderWrap.ApplyConstraint( constraint );
387
388   constraint = Constraint::New<Vector3>( Actor::SIZE,
389                                                    Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
390                                                    Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
391                                                    Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_DIRECTION_PROPERTY_NAME ) ),
392                                                    Source( target, Actor::SIZE ),
393                                                    ScrollBarInternalSizeConstraint( vertical ) );
394   mSlider.ApplyConstraint( constraint );
395   mSliderWrap.ApplyConstraint( constraint );
396
397   constraint = Constraint::New<Quaternion>( Actor::ROTATION,
398                                             Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_DIRECTION_PROPERTY_NAME ) ),
399                                             ScrollBarInternalRotationConstraint( vertical ) );
400   mSlider.ApplyConstraint( constraint );
401   mSliderWrap.ApplyConstraint( constraint );
402
403   constraint = Constraint::New<Vector3>( Actor::POSITION,
404                                          Source( mSlider, Actor::SIZE),
405                                          Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_RELATIVE_POSITION_PROPERTY_NAME ) ),
406                                          Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
407                                          Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
408                                          Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_DIRECTION_PROPERTY_NAME ) ),
409                                          Source( target, Actor::SIZE ),
410                                          ScrollBarInternalPositionConstraint(vertical) );
411
412   mSlider.ApplyConstraint( constraint );
413
414   constraint = Constraint::New<Vector3>( Actor::POSITION,
415                                          Source( mSlider, Actor::SIZE),
416                                          Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_RELATIVE_POSITION_PROPERTY_NAME ) ),
417                                          Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
418                                          Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
419                                          Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_DIRECTION_PROPERTY_NAME ) ),
420                                          Source( target, Actor::SIZE ),
421                                          ScrollBarInternalPositionConstraint(vertical, true) );
422   mSliderWrap.ApplyConstraint( constraint );
423
424   // Add Sliders to internal Actor, to avoid mixing up with regular
425   // Actors added by user.
426   mContainer.AddOverlay( mSlider );
427   mContainer.AddOverlay( mSliderWrap );
428   mContainer.ScrollStartedSignal().Connect( this, &ScrollBarInternal::OnStarted );
429   mContainer.ScrollCompletedSignal().Connect( this, &ScrollBarInternal::OnCompleted );
430
431   // Hit Area for dragging slider /////////////////////////////////////////////
432   mHitArea = Actor::New();
433   mHitArea.SetPosition(0.0f, 0.0f, 0.2f);
434
435   mContainer.AddOverlay( mHitArea );
436   constraint = Constraint::New<Vector3>( Actor::SIZE,
437                                          Source( target, target.GetPropertyIndex( Toolkit::Scrollable::SCROLL_DIRECTION_PROPERTY_NAME ) ),
438                                          Source( target, Actor::SIZE ),
439                                          ScrollBarInternalHitSizeConstraint(vertical, BAR_TAB_SIZE.width) );
440   mHitArea.ApplyConstraint( constraint );
441
442   if(vertical)
443   {
444     mHitArea.SetParentOrigin(ParentOrigin::CENTER_RIGHT);
445     mHitArea.SetAnchorPoint(AnchorPoint::CENTER_RIGHT);
446   }
447   else
448   {
449     mHitArea.SetParentOrigin(ParentOrigin::BOTTOM_CENTER);
450     mHitArea.SetAnchorPoint(AnchorPoint::BOTTOM_CENTER);
451   }
452
453   WaitingContractDelay();
454 }
455
456 ScrollBarInternal::~ScrollBarInternal()
457 {
458   DestructTimer();
459 }
460
461 void ScrollBarInternal::OnInitialize()
462 {
463   EnableGestureDetection(Gesture::Type(Gesture::Pan));
464 }
465
466 void ScrollBarInternal::OnDisconnect()
467 {
468   // Disconnect all connected callback functions.
469   mContainer.RemoveOverlay( mSlider );
470   mContainer.RemoveOverlay( mSliderWrap );
471 }
472
473 void ScrollBarInternal::OnPanGesture(Actor actor, PanGesture gesture)
474 {
475   switch(gesture.state)
476   {
477     case Gesture::Started:
478     {
479       mDragMode = true;
480       Show();
481       mScrollStart = mContainer.GetCurrentScrollPosition();
482       mGestureDisplacement = Vector3::ZERO;
483       break;
484     }
485     case Gesture::Continuing:
486     {
487       Vector3 delta(gesture.displacement.x, gesture.displacement.y, 0.0f);
488       mGestureDisplacement+=delta;
489
490       Vector3 size = mContainer.Self().GetCurrentSize();
491       Vector3 span = size - Vector3(BAR_TAB_SIZE.y, BAR_TAB_SIZE.y, 1.0f);
492       Vector3 domainSize = mContainer.GetDomainSize();
493
494       Vector3 position = mScrollStart + mGestureDisplacement * mAxisMask * domainSize / span;
495       mContainer.ScrollTo(position, 0.0f);
496       break;
497     }
498     default:
499     {
500       mDragMode = false;
501       break;
502     }
503   }
504 }
505
506 void ScrollBarInternal::OnStarted(const Vector3& position)
507 {
508   // TODO: Need to disable this for the scrollbar which isn't being scrolled.
509   if(!mDragMode)
510   {
511     mDragMode = true;
512     Show();
513   }
514 }
515
516 void ScrollBarInternal::OnCompleted(const Vector3& position)
517 {
518   if( mDragMode )
519   {
520     mDragMode = false;
521
522     WaitingContractDelay();
523   }
524 }
525
526 bool ScrollBarInternal::OnContractDelayExpired()
527 {
528   if ( !mDragMode )
529   {
530     Hide();
531   }
532
533   DestructTimer();
534
535   return true;
536 }
537
538 void ScrollBarInternal::Show()
539 {
540   // Cancel any animation
541   if(mAnimation)
542   {
543     mAnimation.Clear();
544     mAnimation.Reset();
545   }
546
547   mAnimation = Animation::New( BAR_SHOW_TIME );
548   mAnimation.OpacityTo( mSlider, 1.0f, AlphaFunctions::EaseIn );
549   mAnimation.OpacityTo( mSliderWrap, 1.0f, AlphaFunctions::EaseIn );
550   mAnimation.Play();
551
552   DestructTimer();
553 }
554
555 void ScrollBarInternal::Hide()
556 {
557   // Cancel any animation
558   if(mAnimation)
559   {
560     mAnimation.Clear();
561     mAnimation.Reset();
562   }
563
564   mAnimation = Animation::New( BAR_HIDE_TIME );
565   mAnimation.OpacityTo( mSlider, 0.0f, AlphaFunctions::EaseIn );
566   mAnimation.OpacityTo( mSliderWrap, 0.0f, AlphaFunctions::EaseIn );
567   mAnimation.Play();
568 }
569
570 void ScrollBarInternal::CreateTimer()
571 {
572   if( !mTimer )
573   {
574     // Create timer for contract delay
575     mTimer = Timer::New( BAR_CONTRACT_DELAY * SECOND_UNIT );
576     mTimer.TickSignal().Connect( this, &ScrollBarInternal::OnContractDelayExpired );
577   }
578 }
579
580 void ScrollBarInternal::DestructTimer()
581 {
582   if( mTimer )
583   {
584     mTimer.Stop();
585     mTimer.TickSignal().Disconnect( this, &ScrollBarInternal::OnContractDelayExpired );
586     mTimer.Reset();
587   }
588 }
589
590 void ScrollBarInternal::WaitingContractDelay()
591 {
592   CreateTimer();
593   mTimer.Start();
594 }
595
596 Toolkit::ScrollBarInternal ScrollBarInternal::New(Toolkit::Scrollable& container, bool vertical)
597 {
598   // Create the implementation, temporarily owned by this handle on stack
599   IntrusivePtr< ScrollBarInternal > impl = new ScrollBarInternal( container, vertical );
600
601   // Pass ownership to CustomActor handle
602   Toolkit::ScrollBarInternal handle( *impl );
603
604   // Second-phase init of the implementation
605   // This can only be done after the CustomActor connection has been made...
606   impl->Initialize();
607
608   return handle;
609 }
610
611 } // namespace Internal
612
613 } // namespace Toolkit
614
615 } // namespace Dali