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