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