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