4701d6c809b4dc79c8adc3b5f35d690f3b378f3f
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / scroll-bar / scroll-bar-impl.cpp
1 /*
2  * Copyright (c) 2021 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-bar/scroll-bar-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/actors/actor-devel.h>
23 #include <dali/devel-api/object/property-helper-devel.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/public-api/animation/constraint.h>
26 #include <dali/public-api/animation/constraints.h>
27 #include <dali/public-api/object/property-array.h>
28 #include <dali/public-api/object/type-registry-helper.h>
29 #include <dali/public-api/object/type-registry.h>
30 #include <cstring> // for strcmp
31
32 // INTERNAL INCLUDES
33 #include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
34 #include <dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h>
35 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
36
37 using namespace Dali;
38
39 namespace
40 {
41 const char* DEFAULT_INDICATOR_IMAGE_FILE_NAME = "popup_scroll.9.png";
42 const float DEFAULT_SLIDER_DEPTH(1.0f);
43 const float DEFAULT_INDICATOR_SHOW_DURATION(0.5f);
44 const float DEFAULT_INDICATOR_HIDE_DURATION(0.5f);
45 const float DEFAULT_PAN_GESTURE_PROCESS_TIME(16.7f); // 16.7 milliseconds, i.e. one frame
46 const float DEFAULT_INDICATOR_FIXED_HEIGHT(80.0f);
47 const float DEFAULT_INDICATOR_MINIMUM_HEIGHT(0.0f);
48 const float DEFAULT_INDICATOR_START_PADDING(0.0f);
49 const float DEFAULT_INDICATOR_END_PADDING(0.0f);
50 const float DEFAULT_INDICATOR_TRANSIENT_DURATION(1.0f);
51
52 /**
53  * Indicator size constraint
54  * Indicator size depends on both indicator's parent size and the scroll content size
55  */
56 struct IndicatorSizeConstraint
57 {
58   /**
59    * @param[in] minimumHeight The minimum height for the indicator
60    * @param[in] padding The sum of the padding at the start & end of the indicator
61    */
62   IndicatorSizeConstraint(float minimumHeight, float padding)
63   : mMinimumHeight(minimumHeight),
64     mPadding(padding)
65   {
66   }
67
68   /**
69    * Constraint operator
70    * @param[in] current The current indicator size
71    * @param[in] parentSizeProperty The parent size of scroll indicator.
72    * @return The new scroll indicator size.
73    */
74   void operator()(Vector3& current, const PropertyInputContainer& inputs)
75   {
76     const Vector3& parentSize  = inputs[0]->GetVector3();
77     const float    contentSize = inputs[1]->GetFloat();
78
79     // Take into account padding that may exist at the beginning and end of the indicator.
80     const float parentHeightMinusPadding = parentSize.height - mPadding;
81
82     float height = contentSize > parentHeightMinusPadding ? parentHeightMinusPadding * (parentHeightMinusPadding / contentSize) : parentHeightMinusPadding * ((parentHeightMinusPadding - contentSize * 0.5f) / parentHeightMinusPadding);
83
84     current.y = std::max(mMinimumHeight, height);
85   }
86
87   float mMinimumHeight;
88   float mPadding;
89 };
90
91 /**
92  * Indicator position constraint
93  * Positions the indicator to reflect the current scroll position within the scroll domain.
94  */
95 struct IndicatorPositionConstraint
96 {
97   /**
98    * @param[in] startPadding The padding at the start of the indicator
99    * @param[in] endPadding The padding at the end of the indicator
100    */
101   IndicatorPositionConstraint(float startPadding, float endPadding)
102   : mStartPadding(startPadding),
103     mEndPadding(endPadding)
104   {
105   }
106
107   /**
108    * Constraint operator
109    * @param[in,out] current The current indicator position
110    * @param[in] inputs Contains the size of indicator, the size of indicator's parent, and the scroll position of the scrollable container (from 0.0 -> 1.0 in each axis)
111    * @return The new indicator position is returned.
112    */
113   void operator()(Vector3& current, const PropertyInputContainer& inputs)
114   {
115     const Vector3& indicatorSize         = inputs[0]->GetVector3();
116     const Vector3& parentSize            = inputs[1]->GetVector3();
117     const float    scrollPosition        = -inputs[2]->GetFloat();
118     const float    minimumScrollPosition = inputs[3]->GetFloat();
119     const float    maximumScrollPosition = inputs[4]->GetFloat();
120
121     // Take into account padding that may exist at the beginning and end of the indicator.
122     const float parentHeightMinusPadding = parentSize.height - (mStartPadding + mEndPadding);
123
124     float relativePosition = std::max(0.0f, std::min(1.0f, (scrollPosition - minimumScrollPosition) / (maximumScrollPosition - minimumScrollPosition)));
125     current.y              = mStartPadding + (parentHeightMinusPadding - indicatorSize.height) * relativePosition;
126     current.z              = DEFAULT_SLIDER_DEPTH;
127   }
128
129   float mStartPadding;
130   float mEndPadding;
131 };
132
133 } // unnamed namespace
134
135 namespace Dali
136 {
137 namespace Toolkit
138 {
139 namespace Internal
140 {
141 namespace
142 {
143 using namespace Dali;
144
145 BaseHandle Create()
146 {
147   return Toolkit::ScrollBar::New();
148 }
149
150 // clang-format off
151 // Setup properties, signals and actions using the type-registry.
152 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ScrollBar, Toolkit::Control, Create );
153
154 DALI_PROPERTY_REGISTRATION(Toolkit, ScrollBar, "scrollDirection",            STRING, SCROLL_DIRECTION            )
155 DALI_PROPERTY_REGISTRATION(Toolkit, ScrollBar, "indicatorHeightPolicy",      STRING, INDICATOR_HEIGHT_POLICY     )
156 DALI_PROPERTY_REGISTRATION(Toolkit, ScrollBar, "indicatorFixedHeight",       FLOAT,  INDICATOR_FIXED_HEIGHT      )
157 DALI_PROPERTY_REGISTRATION(Toolkit, ScrollBar, "indicatorShowDuration",      FLOAT,  INDICATOR_SHOW_DURATION     )
158 DALI_PROPERTY_REGISTRATION(Toolkit, ScrollBar, "indicatorHideDuration",      FLOAT,  INDICATOR_HIDE_DURATION     )
159 DALI_PROPERTY_REGISTRATION(Toolkit, ScrollBar, "scrollPositionIntervals",    ARRAY,  SCROLL_POSITION_INTERVALS   )
160 DALI_PROPERTY_REGISTRATION(Toolkit, ScrollBar, "indicatorMinimumHeight",     FLOAT,  INDICATOR_MINIMUM_HEIGHT    )
161 DALI_PROPERTY_REGISTRATION(Toolkit, ScrollBar, "indicatorStartPadding",      FLOAT,  INDICATOR_START_PADDING     )
162 DALI_PROPERTY_REGISTRATION(Toolkit, ScrollBar, "indicatorEndPadding",        FLOAT,  INDICATOR_END_PADDING       )
163 DALI_PROPERTY_REGISTRATION(Toolkit, ScrollBar, "indicatorTransientDuration", FLOAT,  INDICATOR_TRANSIENT_DURATION)
164
165 DALI_SIGNAL_REGISTRATION(Toolkit, ScrollBar, "panFinished",                   PAN_FINISHED_SIGNAL                    )
166 DALI_SIGNAL_REGISTRATION(Toolkit, ScrollBar, "scrollPositionIntervalReached", SCROLL_POSITION_INTERVAL_REACHED_SIGNAL)
167
168 DALI_ACTION_REGISTRATION(Toolkit, ScrollBar, "ShowIndicator",          ACTION_SHOW_INDICATOR          )
169 DALI_ACTION_REGISTRATION(Toolkit, ScrollBar, "HideIndicator",          ACTION_HIDE_INDICATOR          )
170 DALI_ACTION_REGISTRATION(Toolkit, ScrollBar, "ShowTransientIndicator", ACTION_SHOW_TRANSIENT_INDICATOR)
171
172 DALI_TYPE_REGISTRATION_END()
173 // clang-format on
174
175 const char* SCROLL_DIRECTION_NAME[]        = {"VERTICAL", "HORIZONTAL"};
176 const char* INDICATOR_HEIGHT_POLICY_NAME[] = {"VARIABLE", "FIXED"};
177
178 } // namespace
179
180 ScrollBar::ScrollBar(Toolkit::ScrollBar::Direction direction)
181 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
182   mIndicatorShowAlpha(1.0f),
183   mDirection(direction),
184   mScrollableObject(WeakHandle<Handle>()),
185   mPropertyScrollPosition(Property::INVALID_INDEX),
186   mPropertyMinScrollPosition(Property::INVALID_INDEX),
187   mPropertyMaxScrollPosition(Property::INVALID_INDEX),
188   mPropertyScrollContentSize(Property::INVALID_INDEX),
189   mIndicatorShowDuration(DEFAULT_INDICATOR_SHOW_DURATION),
190   mIndicatorHideDuration(DEFAULT_INDICATOR_HIDE_DURATION),
191   mTransientIndicatorDuration(DEFAULT_INDICATOR_TRANSIENT_DURATION),
192   mScrollStart(0.0f),
193   mGestureDisplacement(Vector2::ZERO),
194   mCurrentScrollPosition(0.0f),
195   mIndicatorHeightPolicy(Toolkit::ScrollBar::VARIABLE),
196   mIndicatorFixedHeight(DEFAULT_INDICATOR_FIXED_HEIGHT),
197   mIndicatorMinimumHeight(DEFAULT_INDICATOR_MINIMUM_HEIGHT),
198   mIndicatorStartPadding(DEFAULT_INDICATOR_START_PADDING),
199   mIndicatorEndPadding(DEFAULT_INDICATOR_END_PADDING),
200   mIsPanning(false),
201   mIndicatorFirstShow(true)
202 {
203 }
204
205 ScrollBar::~ScrollBar()
206 {
207 }
208
209 void ScrollBar::OnInitialize()
210 {
211   CreateDefaultIndicatorActor();
212   Self().SetProperty(Actor::Property::DRAW_MODE, DrawMode::OVERLAY_2D);
213
214   DevelControl::SetAccessibilityConstructor(Self(), [](Dali::Actor actor) {
215     return std::unique_ptr<Dali::Accessibility::Accessible>(
216       new AccessibleImpl(actor, Dali::Accessibility::Role::SCROLL_BAR));
217   });
218 }
219
220 void ScrollBar::SetScrollPropertySource(Handle handle, Property::Index propertyScrollPosition, Property::Index propertyMinScrollPosition, Property::Index propertyMaxScrollPosition, Property::Index propertyScrollContentSize)
221 {
222   if(handle && propertyScrollPosition != Property::INVALID_INDEX && propertyMinScrollPosition != Property::INVALID_INDEX && propertyMaxScrollPosition != Property::INVALID_INDEX && propertyScrollContentSize != Property::INVALID_INDEX)
223   {
224     mScrollableObject          = WeakHandle<Handle>(handle);
225     mPropertyScrollPosition    = propertyScrollPosition;
226     mPropertyMinScrollPosition = propertyMinScrollPosition;
227     mPropertyMaxScrollPosition = propertyMaxScrollPosition;
228     mPropertyScrollContentSize = propertyScrollContentSize;
229
230     ApplyConstraints();
231   }
232   else
233   {
234     DALI_LOG_ERROR("Can not set empty handle of source object or invalid source property index\n");
235   }
236 }
237
238 void ScrollBar::CreateDefaultIndicatorActor()
239 {
240   const std::string  imageDirPath = AssetManager::GetDaliImagePath();
241   Toolkit::ImageView indicator    = Toolkit::ImageView::New(imageDirPath + DEFAULT_INDICATOR_IMAGE_FILE_NAME);
242   indicator.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
243   indicator.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
244   indicator.SetStyleName("ScrollBarIndicator");
245   indicator.SetProperty(Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR);
246   SetScrollIndicator(indicator);
247 }
248
249 void ScrollBar::SetScrollIndicator(Actor indicator)
250 {
251   // Don't allow empty handle
252   if(indicator)
253   {
254     // Remove current Indicator
255     if(mIndicator)
256     {
257       Self().Remove(mIndicator);
258     }
259     mIndicator = indicator;
260
261     mIndicatorFirstShow = true;
262     Self().Add(mIndicator);
263
264     EnableGestureDetection(GestureType::Value(GestureType::PAN));
265
266     PanGestureDetector detector(GetPanGestureDetector());
267     detector.DetachAll();
268     detector.Attach(mIndicator);
269
270     unsigned int childCount = mIndicator.GetChildCount();
271     for(unsigned int index = 0; index < childCount; index++)
272     {
273       Actor child = mIndicator.GetChildAt(index);
274       if(child)
275       {
276         detector.Attach(child);
277       }
278     }
279   }
280   else
281   {
282     DALI_LOG_ERROR("Empty handle of scroll indicator\n");
283   }
284 }
285
286 Actor ScrollBar::GetScrollIndicator()
287 {
288   return mIndicator;
289 }
290
291 void ScrollBar::ApplyConstraints()
292 {
293   Handle scrollableHandle = mScrollableObject.GetHandle();
294
295   if(scrollableHandle)
296   {
297     if(mIndicatorSizeConstraint)
298     {
299       mIndicatorSizeConstraint.Remove();
300     }
301
302     // Set indicator height according to the indicator's height policy
303     if(mIndicatorHeightPolicy == Toolkit::ScrollBar::FIXED)
304     {
305       mIndicator.SetProperty(Actor::Property::SIZE, Vector2(Self().GetCurrentProperty<Vector3>(Actor::Property::SIZE).width, mIndicatorFixedHeight));
306     }
307     else
308     {
309       mIndicatorSizeConstraint = Constraint::New<Vector3>(mIndicator, Actor::Property::SIZE, IndicatorSizeConstraint(mIndicatorMinimumHeight, mIndicatorStartPadding + mIndicatorEndPadding));
310       mIndicatorSizeConstraint.AddSource(ParentSource(Actor::Property::SIZE));
311       mIndicatorSizeConstraint.AddSource(Source(scrollableHandle, mPropertyScrollContentSize));
312       mIndicatorSizeConstraint.Apply();
313     }
314
315     if(mIndicatorPositionConstraint)
316     {
317       mIndicatorPositionConstraint.Remove();
318     }
319
320     mIndicatorPositionConstraint = Constraint::New<Vector3>(mIndicator, Actor::Property::POSITION, IndicatorPositionConstraint(mIndicatorStartPadding, mIndicatorEndPadding));
321     mIndicatorPositionConstraint.AddSource(LocalSource(Actor::Property::SIZE));
322     mIndicatorPositionConstraint.AddSource(ParentSource(Actor::Property::SIZE));
323     mIndicatorPositionConstraint.AddSource(Source(scrollableHandle, mPropertyScrollPosition));
324     mIndicatorPositionConstraint.AddSource(Source(scrollableHandle, mPropertyMinScrollPosition));
325     mIndicatorPositionConstraint.AddSource(Source(scrollableHandle, mPropertyMaxScrollPosition));
326     mIndicatorPositionConstraint.Apply();
327   }
328 }
329
330 void ScrollBar::SetScrollPositionIntervals(const Dali::Vector<float>& positions)
331 {
332   mScrollPositionIntervals = positions;
333
334   Handle scrollableHandle = mScrollableObject.GetHandle();
335
336   if(scrollableHandle)
337   {
338     if(mPositionNotification)
339     {
340       scrollableHandle.RemovePropertyNotification(mPositionNotification);
341     }
342
343     mPositionNotification = scrollableHandle.AddPropertyNotification(mPropertyScrollPosition, VariableStepCondition(mScrollPositionIntervals));
344     mPositionNotification.NotifySignal().Connect(this, &ScrollBar::OnScrollPositionIntervalReached);
345   }
346 }
347
348 Dali::Vector<float> ScrollBar::GetScrollPositionIntervals() const
349 {
350   return mScrollPositionIntervals;
351 }
352
353 void ScrollBar::OnScrollPositionIntervalReached(PropertyNotification& source)
354 {
355   // Emit the signal to notify the scroll position crossing
356   Handle scrollableHandle = mScrollableObject.GetHandle();
357   if(scrollableHandle)
358   {
359     mScrollPositionIntervalReachedSignal.Emit(scrollableHandle.GetCurrentProperty<float>(mPropertyScrollPosition));
360     if(Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor())
361     {
362       Control::Impl::GetAccessibilityObject(Self())->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
363     }
364   }
365 }
366
367 void ScrollBar::ShowIndicator()
368 {
369   // Cancel any animation
370   if(mAnimation)
371   {
372     mAnimation.Clear();
373     mAnimation.Reset();
374   }
375
376   if(mIndicatorFirstShow)
377   {
378     // Preserve the alpha value from the stylesheet
379     mIndicatorShowAlpha = Self().GetCurrentProperty<Vector4>(Actor::Property::COLOR).a;
380     mIndicatorFirstShow = false;
381   }
382
383   if(mIndicatorShowDuration > 0.0f)
384   {
385     mAnimation = Animation::New(mIndicatorShowDuration);
386     mAnimation.AnimateTo(Property(mIndicator, Actor::Property::COLOR_ALPHA), mIndicatorShowAlpha, AlphaFunction::EASE_IN);
387     mAnimation.Play();
388   }
389   else
390   {
391     mIndicator.SetProperty(Actor::Property::OPACITY, mIndicatorShowAlpha);
392   }
393 }
394
395 void ScrollBar::HideIndicator()
396 {
397   // Cancel any animation
398   if(mAnimation)
399   {
400     mAnimation.Clear();
401     mAnimation.Reset();
402   }
403
404   if(mIndicatorHideDuration > 0.0f)
405   {
406     mAnimation = Animation::New(mIndicatorHideDuration);
407     mAnimation.AnimateTo(Property(mIndicator, Actor::Property::COLOR_ALPHA), 0.0f, AlphaFunction::EASE_IN);
408     mAnimation.Play();
409   }
410   else
411   {
412     mIndicator.SetProperty(Actor::Property::OPACITY, 0.0f);
413   }
414 }
415
416 void ScrollBar::ShowTransientIndicator()
417 {
418   // Cancel any animation
419   if(mAnimation)
420   {
421     mAnimation.Clear();
422     mAnimation.Reset();
423   }
424
425   mAnimation = Animation::New(mIndicatorShowDuration + mTransientIndicatorDuration + mIndicatorHideDuration);
426   if(mIndicatorShowDuration > 0.0f)
427   {
428     mAnimation.AnimateTo(Property(mIndicator, Actor::Property::COLOR_ALPHA),
429                          mIndicatorShowAlpha,
430                          AlphaFunction::EASE_IN,
431                          TimePeriod(0, mIndicatorShowDuration));
432   }
433   else
434   {
435     mIndicator.SetProperty(Actor::Property::OPACITY, mIndicatorShowAlpha);
436   }
437   mAnimation.AnimateTo(Property(mIndicator, Actor::Property::COLOR_ALPHA),
438                        0.0f,
439                        AlphaFunction::EASE_IN,
440                        TimePeriod((mIndicatorShowDuration + mTransientIndicatorDuration), mIndicatorHideDuration));
441   mAnimation.Play();
442 }
443
444 bool ScrollBar::OnPanGestureProcessTick()
445 {
446   // Update the scroll position property.
447   Handle scrollableHandle = mScrollableObject.GetHandle();
448   if(scrollableHandle)
449   {
450     scrollableHandle.SetProperty(mPropertyScrollPosition, mCurrentScrollPosition);
451   }
452
453   return true;
454 }
455
456 void ScrollBar::OnPan(const PanGesture& gesture)
457 {
458   Handle scrollableHandle = mScrollableObject.GetHandle();
459
460   if(scrollableHandle)
461   {
462     Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::DownCast(scrollableHandle);
463
464     switch(gesture.GetState())
465     {
466       case Dali::GestureState::STARTED:
467       {
468         if(!mPanProcessTimer)
469         {
470           // Make sure the pan gesture is only being processed once per frame.
471           mPanProcessTimer = Timer::New(DEFAULT_PAN_GESTURE_PROCESS_TIME);
472           mPanProcessTimer.TickSignal().Connect(this, &ScrollBar::OnPanGestureProcessTick);
473           mPanProcessTimer.Start();
474         }
475
476         ShowIndicator();
477         mScrollStart         = scrollableHandle.GetCurrentProperty<float>(mPropertyScrollPosition);
478         mGestureDisplacement = Vector2::ZERO;
479         mIsPanning           = true;
480
481         break;
482       }
483       case Dali::GestureState::CONTINUING:
484       {
485         mGestureDisplacement += gesture.GetDisplacement();
486
487         float minScrollPosition = scrollableHandle.GetCurrentProperty<float>(mPropertyMinScrollPosition);
488         float maxScrollPosition = scrollableHandle.GetCurrentProperty<float>(mPropertyMaxScrollPosition);
489
490         // The domain size is the internal range
491         float domainSize  = maxScrollPosition - minScrollPosition;
492         float logicalSize = Self().GetCurrentProperty<Vector3>(Actor::Property::SIZE).y - (mIndicator.GetCurrentProperty<Vector3>(Actor::Property::SIZE).y + mIndicatorStartPadding + mIndicatorEndPadding);
493
494         mCurrentScrollPosition = mScrollStart - ((mGestureDisplacement.y * domainSize) / logicalSize);
495         mCurrentScrollPosition = -std::min(maxScrollPosition, std::max(-mCurrentScrollPosition, minScrollPosition));
496
497         break;
498       }
499       default:
500       {
501         mIsPanning = false;
502
503         if(mPanProcessTimer)
504         {
505           // Destroy the timer when pan gesture is finished.
506           mPanProcessTimer.Stop();
507           mPanProcessTimer.TickSignal().Disconnect(this, &ScrollBar::OnPanGestureProcessTick);
508           mPanProcessTimer.Reset();
509         }
510
511         if(itemView)
512         {
513           // Refresh the ItemView cache with extra items
514           GetImpl(itemView).DoRefresh(mCurrentScrollPosition, true);
515         }
516
517         mPanFinishedSignal.Emit();
518
519         break;
520       }
521     }
522
523     if(itemView)
524     {
525       // Disable automatic refresh in ItemView during fast scrolling
526       GetImpl(itemView).SetRefreshEnabled(!mIsPanning);
527     }
528   }
529 }
530
531 void ScrollBar::OnSizeSet(const Vector3& size)
532 {
533   if(mIndicatorHeightPolicy == Toolkit::ScrollBar::FIXED)
534   {
535     mIndicator.SetProperty(Actor::Property::SIZE, Vector2(size.width, mIndicatorFixedHeight));
536   }
537
538   Control::OnSizeSet(size);
539 }
540
541 void ScrollBar::SetScrollDirection(Toolkit::ScrollBar::Direction direction)
542 {
543   mDirection = direction;
544 }
545
546 Toolkit::ScrollBar::Direction ScrollBar::GetScrollDirection() const
547 {
548   return mDirection;
549 }
550
551 void ScrollBar::SetIndicatorHeightPolicy(Toolkit::ScrollBar::IndicatorHeightPolicy policy)
552 {
553   if(policy != mIndicatorHeightPolicy)
554   {
555     mIndicatorHeightPolicy = policy;
556     ApplyConstraints();
557   }
558 }
559
560 Toolkit::ScrollBar::IndicatorHeightPolicy ScrollBar::GetIndicatorHeightPolicy() const
561 {
562   return mIndicatorHeightPolicy;
563 }
564
565 void ScrollBar::SetIndicatorFixedHeight(float height)
566 {
567   mIndicatorFixedHeight = height;
568
569   if(mIndicatorHeightPolicy == Toolkit::ScrollBar::FIXED)
570   {
571     mIndicator.SetProperty(Actor::Property::SIZE, Vector2(Self().GetCurrentProperty<Vector3>(Actor::Property::SIZE).width, mIndicatorFixedHeight));
572   }
573 }
574
575 float ScrollBar::GetIndicatorFixedHeight() const
576 {
577   return mIndicatorFixedHeight;
578 }
579
580 void ScrollBar::SetIndicatorShowDuration(float durationSeconds)
581 {
582   mIndicatorShowDuration = durationSeconds;
583 }
584
585 float ScrollBar::GetIndicatorShowDuration() const
586 {
587   return mIndicatorShowDuration;
588 }
589
590 void ScrollBar::SetIndicatorHideDuration(float durationSeconds)
591 {
592   mIndicatorHideDuration = durationSeconds;
593 }
594
595 float ScrollBar::GetIndicatorHideDuration() const
596 {
597   return mIndicatorHideDuration;
598 }
599
600 void ScrollBar::OnScrollDirectionPropertySet(Property::Value propertyValue)
601 {
602   std::string directionName(propertyValue.Get<std::string>());
603   if(directionName == "VERTICAL")
604   {
605     SetScrollDirection(Toolkit::ScrollBar::VERTICAL);
606   }
607   else if(directionName == "HORIZONTAL")
608   {
609     SetScrollDirection(Toolkit::ScrollBar::HORIZONTAL);
610   }
611   else
612   {
613     DALI_ASSERT_ALWAYS(!"ScrollBar::OnScrollDirectionPropertySet(). Invalid Property value.");
614   }
615 }
616
617 void ScrollBar::OnIndicatorHeightPolicyPropertySet(Property::Value propertyValue)
618 {
619   std::string policyName(propertyValue.Get<std::string>());
620   if(policyName == "VARIABLE")
621   {
622     SetIndicatorHeightPolicy(Toolkit::ScrollBar::VARIABLE);
623   }
624   else if(policyName == "FIXED")
625   {
626     SetIndicatorHeightPolicy(Toolkit::ScrollBar::FIXED);
627   }
628   else
629   {
630     DALI_ASSERT_ALWAYS(!"ScrollBar::OnIndicatorHeightPolicyPropertySet(). Invalid Property value.");
631   }
632 }
633
634 bool ScrollBar::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
635 {
636   Dali::BaseHandle handle(object);
637
638   bool               connected(true);
639   Toolkit::ScrollBar scrollBar = Toolkit::ScrollBar::DownCast(handle);
640
641   if(0 == strcmp(signalName.c_str(), PAN_FINISHED_SIGNAL))
642   {
643     scrollBar.PanFinishedSignal().Connect(tracker, functor);
644   }
645   else if(0 == strcmp(signalName.c_str(), SCROLL_POSITION_INTERVAL_REACHED_SIGNAL))
646   {
647     scrollBar.ScrollPositionIntervalReachedSignal().Connect(tracker, functor);
648   }
649   else
650   {
651     // signalName does not match any signal
652     connected = false;
653   }
654
655   return connected;
656 }
657
658 void ScrollBar::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
659 {
660   Toolkit::ScrollBar scrollBar = Toolkit::ScrollBar::DownCast(Dali::BaseHandle(object));
661
662   if(scrollBar)
663   {
664     ScrollBar& scrollBarImpl(GetImpl(scrollBar));
665     switch(index)
666     {
667       case Toolkit::ScrollBar::Property::SCROLL_DIRECTION:
668       {
669         scrollBarImpl.OnScrollDirectionPropertySet(value);
670         break;
671       }
672       case Toolkit::ScrollBar::Property::INDICATOR_HEIGHT_POLICY:
673       {
674         scrollBarImpl.OnIndicatorHeightPolicyPropertySet(value);
675         break;
676       }
677       case Toolkit::ScrollBar::Property::INDICATOR_FIXED_HEIGHT:
678       {
679         scrollBarImpl.SetIndicatorFixedHeight(value.Get<float>());
680         break;
681       }
682       case Toolkit::ScrollBar::Property::INDICATOR_SHOW_DURATION:
683       {
684         scrollBarImpl.SetIndicatorShowDuration(value.Get<float>());
685         break;
686       }
687       case Toolkit::ScrollBar::Property::INDICATOR_HIDE_DURATION:
688       {
689         scrollBarImpl.SetIndicatorHideDuration(value.Get<float>());
690         break;
691       }
692       case Toolkit::ScrollBar::Property::SCROLL_POSITION_INTERVALS:
693       {
694         const Property::Array* array = value.GetArray();
695         if(array)
696         {
697           Dali::Vector<float> positions;
698           size_t              positionCount = array->Count();
699           positions.Resize(positionCount);
700           for(size_t i = 0; i != positionCount; ++i)
701           {
702             array->GetElementAt(i).Get(positions[i]);
703           }
704
705           scrollBarImpl.SetScrollPositionIntervals(positions);
706         }
707         break;
708       }
709       case Toolkit::ScrollBar::Property::INDICATOR_MINIMUM_HEIGHT:
710       {
711         scrollBarImpl.mIndicatorMinimumHeight = value.Get<float>();
712         scrollBarImpl.ApplyConstraints();
713         break;
714       }
715       case Toolkit::ScrollBar::Property::INDICATOR_START_PADDING:
716       {
717         scrollBarImpl.mIndicatorStartPadding = value.Get<float>();
718         scrollBarImpl.ApplyConstraints();
719         break;
720       }
721       case Toolkit::ScrollBar::Property::INDICATOR_END_PADDING:
722       {
723         scrollBarImpl.mIndicatorEndPadding = value.Get<float>();
724         scrollBarImpl.ApplyConstraints();
725         break;
726       }
727       case Toolkit::ScrollBar::Property::INDICATOR_TRANSIENT_DURATION:
728       {
729         scrollBarImpl.mTransientIndicatorDuration = value.Get<float>();
730         break;
731       }
732     }
733   }
734 }
735
736 Property::Value ScrollBar::GetProperty(BaseObject* object, Property::Index index)
737 {
738   Property::Value value;
739
740   Toolkit::ScrollBar scrollBar = Toolkit::ScrollBar::DownCast(Dali::BaseHandle(object));
741
742   if(scrollBar)
743   {
744     ScrollBar& scrollBarImpl(GetImpl(scrollBar));
745     switch(index)
746     {
747       case Toolkit::ScrollBar::Property::SCROLL_DIRECTION:
748       {
749         value = SCROLL_DIRECTION_NAME[scrollBarImpl.GetScrollDirection()];
750         break;
751       }
752       case Toolkit::ScrollBar::Property::INDICATOR_HEIGHT_POLICY:
753       {
754         value = INDICATOR_HEIGHT_POLICY_NAME[scrollBarImpl.GetIndicatorHeightPolicy()];
755         break;
756       }
757       case Toolkit::ScrollBar::Property::INDICATOR_FIXED_HEIGHT:
758       {
759         value = scrollBarImpl.GetIndicatorFixedHeight();
760         break;
761       }
762       case Toolkit::ScrollBar::Property::INDICATOR_SHOW_DURATION:
763       {
764         value = scrollBarImpl.GetIndicatorShowDuration();
765         break;
766       }
767       case Toolkit::ScrollBar::Property::INDICATOR_HIDE_DURATION:
768       {
769         value = scrollBarImpl.GetIndicatorHideDuration();
770         break;
771       }
772       case Toolkit::ScrollBar::Property::SCROLL_POSITION_INTERVALS:
773       {
774         Property::Value  tempValue(Property::ARRAY);
775         Property::Array* array = tempValue.GetArray();
776
777         if(array)
778         {
779           Dali::Vector<float> positions = scrollBarImpl.GetScrollPositionIntervals();
780           size_t              positionCount(positions.Count());
781
782           for(size_t i(0); i != positionCount; ++i)
783           {
784             array->PushBack(positions[i]);
785           }
786
787           value = tempValue;
788         }
789         break;
790       }
791       case Toolkit::ScrollBar::Property::INDICATOR_MINIMUM_HEIGHT:
792       {
793         value = scrollBarImpl.mIndicatorMinimumHeight;
794         break;
795       }
796       case Toolkit::ScrollBar::Property::INDICATOR_START_PADDING:
797       {
798         value = scrollBarImpl.mIndicatorStartPadding;
799         break;
800       }
801       case Toolkit::ScrollBar::Property::INDICATOR_END_PADDING:
802       {
803         value = scrollBarImpl.mIndicatorEndPadding;
804         break;
805       }
806       case Toolkit::ScrollBar::Property::INDICATOR_TRANSIENT_DURATION:
807       {
808         value = scrollBarImpl.mTransientIndicatorDuration;
809         break;
810       }
811     }
812   }
813   return value;
814 }
815
816 bool ScrollBar::DoAction(BaseObject* object, const std::string& actionName, const Property::Map& attributes)
817 {
818   bool ret = false;
819
820   Dali::BaseHandle handle(object);
821
822   Toolkit::ScrollBar scrollBar = Toolkit::ScrollBar::DownCast(handle);
823
824   DALI_ASSERT_DEBUG(scrollBar);
825
826   if(scrollBar)
827   {
828     if(0 == strcmp(actionName.c_str(), ACTION_SHOW_INDICATOR))
829     {
830       GetImpl(scrollBar).ShowIndicator();
831       ret = true;
832     }
833     else if(0 == strcmp(actionName.c_str(), ACTION_HIDE_INDICATOR))
834     {
835       GetImpl(scrollBar).HideIndicator();
836       ret = true;
837     }
838     else if(0 == strcmp(actionName.c_str(), ACTION_SHOW_TRANSIENT_INDICATOR))
839     {
840       GetImpl(scrollBar).ShowTransientIndicator();
841       ret = true;
842     }
843   }
844
845   return ret;
846 }
847
848 Toolkit::ScrollBar ScrollBar::New(Toolkit::ScrollBar::Direction direction)
849 {
850   // Create the implementation, temporarily owned by this handle on stack
851   IntrusivePtr<ScrollBar> impl = new ScrollBar(direction);
852
853   // Pass ownership to CustomActor handle
854   Toolkit::ScrollBar handle(*impl);
855
856   // Second-phase init of the implementation
857   // This can only be done after the CustomActor connection has been made...
858   impl->Initialize();
859
860   return handle;
861 }
862
863 double ScrollBar::AccessibleImpl::GetMinimum()
864 {
865   auto   p                = Toolkit::ScrollBar::DownCast(self);
866   Handle scrollableHandle = GetImpl(p).mScrollableObject.GetHandle();
867   return scrollableHandle ? scrollableHandle.GetCurrentProperty<float>(GetImpl(p).mPropertyMinScrollPosition) : 0.0f;
868 }
869
870 double ScrollBar::AccessibleImpl::GetCurrent()
871 {
872   auto   p                = Toolkit::ScrollBar::DownCast(self);
873   Handle scrollableHandle = GetImpl(p).mScrollableObject.GetHandle();
874   return scrollableHandle ? scrollableHandle.GetCurrentProperty<float>(GetImpl(p).mPropertyScrollPosition) : 0.0f;
875 }
876
877 double ScrollBar::AccessibleImpl::GetMaximum()
878 {
879   auto   p                = Toolkit::ScrollBar::DownCast(self);
880   Handle scrollableHandle = GetImpl(p).mScrollableObject.GetHandle();
881   return scrollableHandle ? scrollableHandle.GetCurrentProperty<float>(GetImpl(p).mPropertyMaxScrollPosition) : 1.0f;
882 }
883
884 bool ScrollBar::AccessibleImpl::SetCurrent(double current)
885 {
886   if(current < GetMinimum() || current > GetMaximum())
887     return false;
888
889   auto value_before = GetCurrent();
890
891   auto   p                = Toolkit::ScrollBar::DownCast(self);
892   Handle scrollableHandle = GetImpl(p).mScrollableObject.GetHandle();
893   if(!scrollableHandle)
894     return false;
895   scrollableHandle.SetProperty(GetImpl(p).mPropertyScrollPosition, static_cast<float>(current));
896
897   auto value_after = GetCurrent();
898
899   if((current != value_before) && (value_before == value_after))
900     return false;
901
902   return true;
903 }
904
905 double ScrollBar::AccessibleImpl::GetMinimumIncrement()
906 {
907   return 1.0;
908 }
909
910 } // namespace Internal
911
912 } // namespace Toolkit
913
914 } // namespace Dali