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