[AT-SPI] Remove SetAccessibilityConstructor()
[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   auto self = Self();
213
214   CreateDefaultIndicatorActor();
215   self.SetProperty(Actor::Property::DRAW_MODE, DrawMode::OVERLAY_2D);
216
217   self.SetProperty(DevelControl::Property::ACCESSIBILITY_ROLE, Dali::Accessibility::Role::SCROLL_BAR);
218 }
219
220 DevelControl::ControlAccessible* ScrollBar::CreateAccessibleObject()
221 {
222   return new ScrollBarAccessible(Self());
223 }
224
225 void ScrollBar::SetScrollPropertySource(Handle handle, Property::Index propertyScrollPosition, Property::Index propertyMinScrollPosition, Property::Index propertyMaxScrollPosition, Property::Index propertyScrollContentSize)
226 {
227   if(handle && propertyScrollPosition != Property::INVALID_INDEX && propertyMinScrollPosition != Property::INVALID_INDEX && propertyMaxScrollPosition != Property::INVALID_INDEX && propertyScrollContentSize != Property::INVALID_INDEX)
228   {
229     mScrollableObject          = WeakHandle<Handle>(handle);
230     mPropertyScrollPosition    = propertyScrollPosition;
231     mPropertyMinScrollPosition = propertyMinScrollPosition;
232     mPropertyMaxScrollPosition = propertyMaxScrollPosition;
233     mPropertyScrollContentSize = propertyScrollContentSize;
234
235     ApplyConstraints();
236   }
237   else
238   {
239     DALI_LOG_ERROR("Can not set empty handle of source object or invalid source property index\n");
240   }
241 }
242
243 void ScrollBar::CreateDefaultIndicatorActor()
244 {
245   const std::string  imageDirPath = AssetManager::GetDaliImagePath();
246   Toolkit::ImageView indicator    = Toolkit::ImageView::New(imageDirPath + DEFAULT_INDICATOR_IMAGE_FILE_NAME);
247   indicator.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
248   indicator.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
249   indicator.SetStyleName("ScrollBarIndicator");
250   indicator.SetProperty(Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR);
251   SetScrollIndicator(indicator);
252 }
253
254 void ScrollBar::SetScrollIndicator(Actor indicator)
255 {
256   // Don't allow empty handle
257   if(indicator)
258   {
259     // Remove current Indicator
260     if(mIndicator)
261     {
262       Self().Remove(mIndicator);
263     }
264     mIndicator = indicator;
265
266     mIndicatorFirstShow = true;
267     Self().Add(mIndicator);
268
269     EnableGestureDetection(GestureType::Value(GestureType::PAN));
270
271     PanGestureDetector detector(GetPanGestureDetector());
272     detector.DetachAll();
273     detector.Attach(mIndicator);
274
275     unsigned int childCount = mIndicator.GetChildCount();
276     for(unsigned int index = 0; index < childCount; index++)
277     {
278       Actor child = mIndicator.GetChildAt(index);
279       if(child)
280       {
281         detector.Attach(child);
282       }
283     }
284   }
285   else
286   {
287     DALI_LOG_ERROR("Empty handle of scroll indicator\n");
288   }
289 }
290
291 Actor ScrollBar::GetScrollIndicator()
292 {
293   return mIndicator;
294 }
295
296 void ScrollBar::ApplyConstraints()
297 {
298   Handle scrollableHandle = mScrollableObject.GetHandle();
299
300   if(scrollableHandle)
301   {
302     if(mIndicatorSizeConstraint)
303     {
304       mIndicatorSizeConstraint.Remove();
305     }
306
307     // Set indicator height according to the indicator's height policy
308     if(mIndicatorHeightPolicy == Toolkit::ScrollBar::FIXED)
309     {
310       mIndicator.SetProperty(Actor::Property::SIZE, Vector2(Self().GetCurrentProperty<Vector3>(Actor::Property::SIZE).width, mIndicatorFixedHeight));
311     }
312     else
313     {
314       mIndicatorSizeConstraint = Constraint::New<Vector3>(mIndicator, Actor::Property::SIZE, IndicatorSizeConstraint(mIndicatorMinimumHeight, mIndicatorStartPadding + mIndicatorEndPadding));
315       mIndicatorSizeConstraint.AddSource(ParentSource(Actor::Property::SIZE));
316       mIndicatorSizeConstraint.AddSource(Source(scrollableHandle, mPropertyScrollContentSize));
317       mIndicatorSizeConstraint.Apply();
318     }
319
320     if(mIndicatorPositionConstraint)
321     {
322       mIndicatorPositionConstraint.Remove();
323     }
324
325     mIndicatorPositionConstraint = Constraint::New<Vector3>(mIndicator, Actor::Property::POSITION, IndicatorPositionConstraint(mIndicatorStartPadding, mIndicatorEndPadding));
326     mIndicatorPositionConstraint.AddSource(LocalSource(Actor::Property::SIZE));
327     mIndicatorPositionConstraint.AddSource(ParentSource(Actor::Property::SIZE));
328     mIndicatorPositionConstraint.AddSource(Source(scrollableHandle, mPropertyScrollPosition));
329     mIndicatorPositionConstraint.AddSource(Source(scrollableHandle, mPropertyMinScrollPosition));
330     mIndicatorPositionConstraint.AddSource(Source(scrollableHandle, mPropertyMaxScrollPosition));
331     mIndicatorPositionConstraint.Apply();
332   }
333 }
334
335 void ScrollBar::SetScrollPositionIntervals(const Dali::Vector<float>& positions)
336 {
337   mScrollPositionIntervals = positions;
338
339   Handle scrollableHandle = mScrollableObject.GetHandle();
340
341   if(scrollableHandle)
342   {
343     if(mPositionNotification)
344     {
345       scrollableHandle.RemovePropertyNotification(mPositionNotification);
346     }
347
348     mPositionNotification = scrollableHandle.AddPropertyNotification(mPropertyScrollPosition, VariableStepCondition(mScrollPositionIntervals));
349     mPositionNotification.NotifySignal().Connect(this, &ScrollBar::OnScrollPositionIntervalReached);
350   }
351 }
352
353 Dali::Vector<float> ScrollBar::GetScrollPositionIntervals() const
354 {
355   return mScrollPositionIntervals;
356 }
357
358 void ScrollBar::OnScrollPositionIntervalReached(PropertyNotification& source)
359 {
360   // Emit the signal to notify the scroll position crossing
361   Handle scrollableHandle = mScrollableObject.GetHandle();
362   if(scrollableHandle)
363   {
364     mScrollPositionIntervalReachedSignal.Emit(scrollableHandle.GetCurrentProperty<float>(mPropertyScrollPosition));
365     if(Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor())
366     {
367       GetAccessibleObject()->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
368     }
369   }
370 }
371
372 void ScrollBar::ShowIndicator()
373 {
374   // Cancel any animation
375   if(mAnimation)
376   {
377     mAnimation.Clear();
378     mAnimation.Reset();
379   }
380
381   if(mIndicatorFirstShow)
382   {
383     // Preserve the alpha value from the stylesheet
384     mIndicatorShowAlpha = Self().GetCurrentProperty<Vector4>(Actor::Property::COLOR).a;
385     mIndicatorFirstShow = false;
386   }
387
388   if(mIndicatorShowDuration > 0.0f)
389   {
390     mAnimation = Animation::New(mIndicatorShowDuration);
391     mAnimation.AnimateTo(Property(mIndicator, Actor::Property::COLOR_ALPHA), mIndicatorShowAlpha, AlphaFunction::EASE_IN);
392     mAnimation.Play();
393   }
394   else
395   {
396     mIndicator.SetProperty(Actor::Property::OPACITY, mIndicatorShowAlpha);
397   }
398 }
399
400 void ScrollBar::HideIndicator()
401 {
402   // Cancel any animation
403   if(mAnimation)
404   {
405     mAnimation.Clear();
406     mAnimation.Reset();
407   }
408
409   if(mIndicatorHideDuration > 0.0f)
410   {
411     mAnimation = Animation::New(mIndicatorHideDuration);
412     mAnimation.AnimateTo(Property(mIndicator, Actor::Property::COLOR_ALPHA), 0.0f, AlphaFunction::EASE_IN);
413     mAnimation.Play();
414   }
415   else
416   {
417     mIndicator.SetProperty(Actor::Property::OPACITY, 0.0f);
418   }
419 }
420
421 void ScrollBar::ShowTransientIndicator()
422 {
423   // Cancel any animation
424   if(mAnimation)
425   {
426     mAnimation.Clear();
427     mAnimation.Reset();
428   }
429
430   mAnimation = Animation::New(mIndicatorShowDuration + mTransientIndicatorDuration + mIndicatorHideDuration);
431   if(mIndicatorShowDuration > 0.0f)
432   {
433     mAnimation.AnimateTo(Property(mIndicator, Actor::Property::COLOR_ALPHA),
434                          mIndicatorShowAlpha,
435                          AlphaFunction::EASE_IN,
436                          TimePeriod(0, mIndicatorShowDuration));
437   }
438   else
439   {
440     mIndicator.SetProperty(Actor::Property::OPACITY, mIndicatorShowAlpha);
441   }
442   mAnimation.AnimateTo(Property(mIndicator, Actor::Property::COLOR_ALPHA),
443                        0.0f,
444                        AlphaFunction::EASE_IN,
445                        TimePeriod((mIndicatorShowDuration + mTransientIndicatorDuration), mIndicatorHideDuration));
446   mAnimation.Play();
447 }
448
449 bool ScrollBar::OnPanGestureProcessTick()
450 {
451   // Update the scroll position property.
452   Handle scrollableHandle = mScrollableObject.GetHandle();
453   if(scrollableHandle)
454   {
455     scrollableHandle.SetProperty(mPropertyScrollPosition, mCurrentScrollPosition);
456   }
457
458   return true;
459 }
460
461 void ScrollBar::OnPan(const PanGesture& gesture)
462 {
463   Handle scrollableHandle = mScrollableObject.GetHandle();
464
465   if(scrollableHandle)
466   {
467     Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::DownCast(scrollableHandle);
468
469     switch(gesture.GetState())
470     {
471       case Dali::GestureState::STARTED:
472       {
473         if(!mPanProcessTimer)
474         {
475           // Make sure the pan gesture is only being processed once per frame.
476           mPanProcessTimer = Timer::New(DEFAULT_PAN_GESTURE_PROCESS_TIME);
477           mPanProcessTimer.TickSignal().Connect(this, &ScrollBar::OnPanGestureProcessTick);
478           mPanProcessTimer.Start();
479         }
480
481         ShowIndicator();
482         mScrollStart         = scrollableHandle.GetCurrentProperty<float>(mPropertyScrollPosition);
483         mGestureDisplacement = Vector2::ZERO;
484         mIsPanning           = true;
485
486         break;
487       }
488       case Dali::GestureState::CONTINUING:
489       {
490         mGestureDisplacement += gesture.GetDisplacement();
491
492         float minScrollPosition = scrollableHandle.GetCurrentProperty<float>(mPropertyMinScrollPosition);
493         float maxScrollPosition = scrollableHandle.GetCurrentProperty<float>(mPropertyMaxScrollPosition);
494
495         // The domain size is the internal range
496         float domainSize  = maxScrollPosition - minScrollPosition;
497         float logicalSize = Self().GetCurrentProperty<Vector3>(Actor::Property::SIZE).y - (mIndicator.GetCurrentProperty<Vector3>(Actor::Property::SIZE).y + mIndicatorStartPadding + mIndicatorEndPadding);
498
499         mCurrentScrollPosition = mScrollStart - ((mGestureDisplacement.y * domainSize) / logicalSize);
500         mCurrentScrollPosition = -std::min(maxScrollPosition, std::max(-mCurrentScrollPosition, minScrollPosition));
501
502         break;
503       }
504       default:
505       {
506         mIsPanning = false;
507
508         if(mPanProcessTimer)
509         {
510           // Destroy the timer when pan gesture is finished.
511           mPanProcessTimer.Stop();
512           mPanProcessTimer.TickSignal().Disconnect(this, &ScrollBar::OnPanGestureProcessTick);
513           mPanProcessTimer.Reset();
514         }
515
516         if(itemView)
517         {
518           // Refresh the ItemView cache with extra items
519           GetImpl(itemView).DoRefresh(mCurrentScrollPosition, true);
520         }
521
522         mPanFinishedSignal.Emit();
523
524         break;
525       }
526     }
527
528     if(itemView)
529     {
530       // Disable automatic refresh in ItemView during fast scrolling
531       GetImpl(itemView).SetRefreshEnabled(!mIsPanning);
532     }
533   }
534 }
535
536 void ScrollBar::OnSizeSet(const Vector3& size)
537 {
538   if(mIndicatorHeightPolicy == Toolkit::ScrollBar::FIXED)
539   {
540     mIndicator.SetProperty(Actor::Property::SIZE, Vector2(size.width, mIndicatorFixedHeight));
541   }
542
543   Control::OnSizeSet(size);
544 }
545
546 void ScrollBar::SetScrollDirection(Toolkit::ScrollBar::Direction direction)
547 {
548   mDirection = direction;
549 }
550
551 Toolkit::ScrollBar::Direction ScrollBar::GetScrollDirection() const
552 {
553   return mDirection;
554 }
555
556 void ScrollBar::SetIndicatorHeightPolicy(Toolkit::ScrollBar::IndicatorHeightPolicy policy)
557 {
558   if(policy != mIndicatorHeightPolicy)
559   {
560     mIndicatorHeightPolicy = policy;
561     ApplyConstraints();
562   }
563 }
564
565 Toolkit::ScrollBar::IndicatorHeightPolicy ScrollBar::GetIndicatorHeightPolicy() const
566 {
567   return mIndicatorHeightPolicy;
568 }
569
570 void ScrollBar::SetIndicatorFixedHeight(float height)
571 {
572   mIndicatorFixedHeight = height;
573
574   if(mIndicatorHeightPolicy == Toolkit::ScrollBar::FIXED)
575   {
576     mIndicator.SetProperty(Actor::Property::SIZE, Vector2(Self().GetCurrentProperty<Vector3>(Actor::Property::SIZE).width, mIndicatorFixedHeight));
577   }
578 }
579
580 float ScrollBar::GetIndicatorFixedHeight() const
581 {
582   return mIndicatorFixedHeight;
583 }
584
585 void ScrollBar::SetIndicatorShowDuration(float durationSeconds)
586 {
587   mIndicatorShowDuration = durationSeconds;
588 }
589
590 float ScrollBar::GetIndicatorShowDuration() const
591 {
592   return mIndicatorShowDuration;
593 }
594
595 void ScrollBar::SetIndicatorHideDuration(float durationSeconds)
596 {
597   mIndicatorHideDuration = durationSeconds;
598 }
599
600 float ScrollBar::GetIndicatorHideDuration() const
601 {
602   return mIndicatorHideDuration;
603 }
604
605 void ScrollBar::OnScrollDirectionPropertySet(Property::Value propertyValue)
606 {
607   std::string directionName(propertyValue.Get<std::string>());
608   if(directionName == "VERTICAL")
609   {
610     SetScrollDirection(Toolkit::ScrollBar::VERTICAL);
611   }
612   else if(directionName == "HORIZONTAL")
613   {
614     SetScrollDirection(Toolkit::ScrollBar::HORIZONTAL);
615   }
616   else
617   {
618     DALI_ASSERT_ALWAYS(!"ScrollBar::OnScrollDirectionPropertySet(). Invalid Property value.");
619   }
620 }
621
622 void ScrollBar::OnIndicatorHeightPolicyPropertySet(Property::Value propertyValue)
623 {
624   std::string policyName(propertyValue.Get<std::string>());
625   if(policyName == "VARIABLE")
626   {
627     SetIndicatorHeightPolicy(Toolkit::ScrollBar::VARIABLE);
628   }
629   else if(policyName == "FIXED")
630   {
631     SetIndicatorHeightPolicy(Toolkit::ScrollBar::FIXED);
632   }
633   else
634   {
635     DALI_ASSERT_ALWAYS(!"ScrollBar::OnIndicatorHeightPolicyPropertySet(). Invalid Property value.");
636   }
637 }
638
639 bool ScrollBar::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
640 {
641   Dali::BaseHandle handle(object);
642
643   bool               connected(true);
644   Toolkit::ScrollBar scrollBar = Toolkit::ScrollBar::DownCast(handle);
645
646   if(0 == strcmp(signalName.c_str(), PAN_FINISHED_SIGNAL))
647   {
648     scrollBar.PanFinishedSignal().Connect(tracker, functor);
649   }
650   else if(0 == strcmp(signalName.c_str(), SCROLL_POSITION_INTERVAL_REACHED_SIGNAL))
651   {
652     scrollBar.ScrollPositionIntervalReachedSignal().Connect(tracker, functor);
653   }
654   else
655   {
656     // signalName does not match any signal
657     connected = false;
658   }
659
660   return connected;
661 }
662
663 void ScrollBar::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
664 {
665   Toolkit::ScrollBar scrollBar = Toolkit::ScrollBar::DownCast(Dali::BaseHandle(object));
666
667   if(scrollBar)
668   {
669     ScrollBar& scrollBarImpl(GetImpl(scrollBar));
670     switch(index)
671     {
672       case Toolkit::ScrollBar::Property::SCROLL_DIRECTION:
673       {
674         scrollBarImpl.OnScrollDirectionPropertySet(value);
675         break;
676       }
677       case Toolkit::ScrollBar::Property::INDICATOR_HEIGHT_POLICY:
678       {
679         scrollBarImpl.OnIndicatorHeightPolicyPropertySet(value);
680         break;
681       }
682       case Toolkit::ScrollBar::Property::INDICATOR_FIXED_HEIGHT:
683       {
684         scrollBarImpl.SetIndicatorFixedHeight(value.Get<float>());
685         break;
686       }
687       case Toolkit::ScrollBar::Property::INDICATOR_SHOW_DURATION:
688       {
689         scrollBarImpl.SetIndicatorShowDuration(value.Get<float>());
690         break;
691       }
692       case Toolkit::ScrollBar::Property::INDICATOR_HIDE_DURATION:
693       {
694         scrollBarImpl.SetIndicatorHideDuration(value.Get<float>());
695         break;
696       }
697       case Toolkit::ScrollBar::Property::SCROLL_POSITION_INTERVALS:
698       {
699         const Property::Array* array = value.GetArray();
700         if(array)
701         {
702           Dali::Vector<float> positions;
703           size_t              positionCount = array->Count();
704           positions.Resize(positionCount);
705           for(size_t i = 0; i != positionCount; ++i)
706           {
707             array->GetElementAt(i).Get(positions[i]);
708           }
709
710           scrollBarImpl.SetScrollPositionIntervals(positions);
711         }
712         break;
713       }
714       case Toolkit::ScrollBar::Property::INDICATOR_MINIMUM_HEIGHT:
715       {
716         scrollBarImpl.mIndicatorMinimumHeight = value.Get<float>();
717         scrollBarImpl.ApplyConstraints();
718         break;
719       }
720       case Toolkit::ScrollBar::Property::INDICATOR_START_PADDING:
721       {
722         scrollBarImpl.mIndicatorStartPadding = value.Get<float>();
723         scrollBarImpl.ApplyConstraints();
724         break;
725       }
726       case Toolkit::ScrollBar::Property::INDICATOR_END_PADDING:
727       {
728         scrollBarImpl.mIndicatorEndPadding = value.Get<float>();
729         scrollBarImpl.ApplyConstraints();
730         break;
731       }
732       case Toolkit::ScrollBar::Property::INDICATOR_TRANSIENT_DURATION:
733       {
734         scrollBarImpl.mTransientIndicatorDuration = value.Get<float>();
735         break;
736       }
737     }
738   }
739 }
740
741 Property::Value ScrollBar::GetProperty(BaseObject* object, Property::Index index)
742 {
743   Property::Value value;
744
745   Toolkit::ScrollBar scrollBar = Toolkit::ScrollBar::DownCast(Dali::BaseHandle(object));
746
747   if(scrollBar)
748   {
749     ScrollBar& scrollBarImpl(GetImpl(scrollBar));
750     switch(index)
751     {
752       case Toolkit::ScrollBar::Property::SCROLL_DIRECTION:
753       {
754         value = SCROLL_DIRECTION_NAME[scrollBarImpl.GetScrollDirection()];
755         break;
756       }
757       case Toolkit::ScrollBar::Property::INDICATOR_HEIGHT_POLICY:
758       {
759         value = INDICATOR_HEIGHT_POLICY_NAME[scrollBarImpl.GetIndicatorHeightPolicy()];
760         break;
761       }
762       case Toolkit::ScrollBar::Property::INDICATOR_FIXED_HEIGHT:
763       {
764         value = scrollBarImpl.GetIndicatorFixedHeight();
765         break;
766       }
767       case Toolkit::ScrollBar::Property::INDICATOR_SHOW_DURATION:
768       {
769         value = scrollBarImpl.GetIndicatorShowDuration();
770         break;
771       }
772       case Toolkit::ScrollBar::Property::INDICATOR_HIDE_DURATION:
773       {
774         value = scrollBarImpl.GetIndicatorHideDuration();
775         break;
776       }
777       case Toolkit::ScrollBar::Property::SCROLL_POSITION_INTERVALS:
778       {
779         Property::Value  tempValue(Property::ARRAY);
780         Property::Array* array = tempValue.GetArray();
781
782         if(array)
783         {
784           Dali::Vector<float> positions = scrollBarImpl.GetScrollPositionIntervals();
785           size_t              positionCount(positions.Count());
786
787           for(size_t i(0); i != positionCount; ++i)
788           {
789             array->PushBack(positions[i]);
790           }
791
792           value = tempValue;
793         }
794         break;
795       }
796       case Toolkit::ScrollBar::Property::INDICATOR_MINIMUM_HEIGHT:
797       {
798         value = scrollBarImpl.mIndicatorMinimumHeight;
799         break;
800       }
801       case Toolkit::ScrollBar::Property::INDICATOR_START_PADDING:
802       {
803         value = scrollBarImpl.mIndicatorStartPadding;
804         break;
805       }
806       case Toolkit::ScrollBar::Property::INDICATOR_END_PADDING:
807       {
808         value = scrollBarImpl.mIndicatorEndPadding;
809         break;
810       }
811       case Toolkit::ScrollBar::Property::INDICATOR_TRANSIENT_DURATION:
812       {
813         value = scrollBarImpl.mTransientIndicatorDuration;
814         break;
815       }
816     }
817   }
818   return value;
819 }
820
821 bool ScrollBar::DoAction(BaseObject* object, const std::string& actionName, const Property::Map& attributes)
822 {
823   bool ret = false;
824
825   Dali::BaseHandle handle(object);
826
827   Toolkit::ScrollBar scrollBar = Toolkit::ScrollBar::DownCast(handle);
828
829   DALI_ASSERT_DEBUG(scrollBar);
830
831   if(scrollBar)
832   {
833     if(0 == strcmp(actionName.c_str(), ACTION_SHOW_INDICATOR))
834     {
835       GetImpl(scrollBar).ShowIndicator();
836       ret = true;
837     }
838     else if(0 == strcmp(actionName.c_str(), ACTION_HIDE_INDICATOR))
839     {
840       GetImpl(scrollBar).HideIndicator();
841       ret = true;
842     }
843     else if(0 == strcmp(actionName.c_str(), ACTION_SHOW_TRANSIENT_INDICATOR))
844     {
845       GetImpl(scrollBar).ShowTransientIndicator();
846       ret = true;
847     }
848   }
849
850   return ret;
851 }
852
853 Toolkit::ScrollBar ScrollBar::New(Toolkit::ScrollBar::Direction direction)
854 {
855   // Create the implementation, temporarily owned by this handle on stack
856   IntrusivePtr<ScrollBar> impl = new ScrollBar(direction);
857
858   // Pass ownership to CustomActor handle
859   Toolkit::ScrollBar handle(*impl);
860
861   // Second-phase init of the implementation
862   // This can only be done after the CustomActor connection has been made...
863   impl->Initialize();
864
865   return handle;
866 }
867
868 double ScrollBar::ScrollBarAccessible::GetMinimum() const
869 {
870   auto self = Toolkit::ScrollBar::DownCast(Self());
871   Handle scrollableHandle = GetImpl(self).mScrollableObject.GetHandle();
872   return scrollableHandle ? scrollableHandle.GetCurrentProperty<float>(GetImpl(self).mPropertyMinScrollPosition) : 0.0f;
873 }
874
875 double ScrollBar::ScrollBarAccessible::GetCurrent() const
876 {
877   auto self = Toolkit::ScrollBar::DownCast(Self());
878   Handle scrollableHandle = GetImpl(self).mScrollableObject.GetHandle();
879   return scrollableHandle ? scrollableHandle.GetCurrentProperty<float>(GetImpl(self).mPropertyScrollPosition) : 0.0f;
880 }
881
882 double ScrollBar::ScrollBarAccessible::GetMaximum() const
883 {
884   auto self = Toolkit::ScrollBar::DownCast(Self());
885   Handle scrollableHandle = GetImpl(self).mScrollableObject.GetHandle();
886   return scrollableHandle ? scrollableHandle.GetCurrentProperty<float>(GetImpl(self).mPropertyMaxScrollPosition) : 1.0f;
887 }
888
889 bool ScrollBar::ScrollBarAccessible::SetCurrent(double current)
890 {
891   if(current < GetMinimum() || current > GetMaximum())
892   {
893     return false;
894   }
895
896   auto valueBefore = GetCurrent();
897
898   auto self = Toolkit::ScrollBar::DownCast(Self());
899   Handle scrollableHandle = GetImpl(self).mScrollableObject.GetHandle();
900   if(!scrollableHandle)
901   {
902     return false;
903   }
904
905   scrollableHandle.SetProperty(GetImpl(self).mPropertyScrollPosition, static_cast<float>(current));
906
907   auto valueAfter = GetCurrent();
908
909   if((current != valueBefore) && (valueBefore == valueAfter))
910   {
911     return false;
912   }
913
914   return true;
915 }
916
917 double ScrollBar::ScrollBarAccessible::GetMinimumIncrement() const
918 {
919   return 1.0;
920 }
921
922 } // namespace Internal
923
924 } // namespace Toolkit
925
926 } // namespace Dali