2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-toolkit/internal/controls/slider/slider-impl.h>
22 #include <dali/public-api/events/touch-event.h>
23 #include <dali/public-api/object/type-registry-helper.h>
24 #include <dali/public-api/object/type-registry.h>
25 #include <cstring> // for strcmp
30 #include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
31 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
32 #include <dali-toolkit/public-api/controls/control-impl.h>
33 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
34 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
44 namespace // Unnamed namespace
48 return Dali::Toolkit::Slider::New();
52 // Setup properties, signals and actions using the type-registry.
53 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::Slider, Toolkit::Control, Create )
55 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "lowerBound", FLOAT, LOWER_BOUND )
56 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "upperBound", FLOAT, UPPER_BOUND )
57 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "value", FLOAT, VALUE )
58 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "trackVisual", MAP, TRACK_VISUAL )
59 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "handleVisual", MAP, HANDLE_VISUAL )
60 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "progressVisual", MAP, PROGRESS_VISUAL )
61 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "popupVisual", MAP, POPUP_VISUAL )
62 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "popupArrowVisual", MAP, POPUP_ARROW_VISUAL)
63 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "disabledColor", VECTOR4, DISABLED_COLOR )
64 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "valuePrecision", INTEGER, VALUE_PRECISION )
65 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "showPopup", BOOLEAN, SHOW_POPUP )
66 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "showValue", BOOLEAN, SHOW_VALUE )
67 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "marks", ARRAY, MARKS )
68 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "snapToMarks", BOOLEAN, SNAP_TO_MARKS )
69 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "markTolerance", FLOAT, MARK_TOLERANCE )
71 DALI_SIGNAL_REGISTRATION(Toolkit, Slider, "valueChanged", SIGNAL_VALUE_CHANGED)
72 DALI_SIGNAL_REGISTRATION(Toolkit, Slider, "mark", SIGNAL_MARK )
74 DALI_TYPE_REGISTRATION_END()
77 const float MARK_SNAP_TOLERANCE = 0.05f; // 5% of slider width
79 const int VALUE_VIEW_SHOW_DURATION = 1000; // millisec
80 const int VALUE_VIEW_SHOW_DURATION_LONG = 2000; // millisec
82 const float VALUE_VERTICAL_OFFSET = 48.0f;
84 const float DEFAULT_WIDTH = 0.0f;
85 const float DEFAULT_HEIGHT = 27.0f;
86 const float DEFAULT_HIT_HEIGHT = 72.0f;
87 const float DEFAULT_HANDLE_HEIGHT = DEFAULT_HIT_HEIGHT;
88 const float POPUP_TEXT_PADDING = 10.0f;
90 const char* SKINNED_TRACK_VISUAL_FILE_NAME = "slider-skin.9.png";
91 const char* SKINNED_HANDLE_VISUAL_FILE_NAME = "slider-skin-handle.png";
92 const char* SKINNED_PROGRESS_VISUAL_FILE_NAME = "slider-skin-progress.9.png";
93 const char* SKINNED_POPUP_VISUAL_FILE_NAME = "slider-popup.9.png";
94 const char* SKINNED_POPUP_ARROW_VISUAL_FILE_NAME = "slider-popup-arrow.png";
96 const Vector2 DEFAULT_HIT_REGION(DEFAULT_WIDTH, DEFAULT_HIT_HEIGHT);
97 const Vector2 DEFAULT_TRACK_REGION(DEFAULT_WIDTH, DEFAULT_HEIGHT);
98 const Vector2 DEFAULT_HANDLE_SIZE(DEFAULT_HANDLE_HEIGHT, DEFAULT_HANDLE_HEIGHT);
100 const Vector4 DEFAULT_DISABLED_COLOR(0.5f, 0.5f, 0.5f, 1.0f);
102 const float VALUE_POPUP_MARGIN = 10.0f;
103 const float VALUE_POPUP_HEIGHT = 81.0f;
104 const float VALUE_POPUP_MIN_WIDTH = 54.0f;
106 const float DEFAULT_LOWER_BOUND = 0.0f;
107 const float DEFAULT_UPPER_BOUND = 1.0f;
108 const float DEFAULT_VALUE = 0.0f;
109 const int DEFAULT_VALUE_PRECISION = 0;
110 const bool DEFAULT_SHOW_POPUP = false;
111 const bool DEFAULT_SHOW_VALUE = true;
112 const bool DEFAULT_ENABLED = true;
113 const bool DEFAULT_SNAP_TO_MARKS = false;
115 } // Unnamed namespace
117 ///////////////////////////////////////////////////////////////////////////////////////////////////
119 ///////////////////////////////////////////////////////////////////////////////////////////////////
121 Dali::Toolkit::Slider Slider::New()
123 // Create the implementation
124 SliderPtr slider(new Slider());
126 // Pass ownership to CustomActor via derived handle
127 Dali::Toolkit::Slider handle(*slider);
129 // Second-phase init of the implementation
130 // This can only be done after the CustomActor connection has been made...
131 slider->Initialize();
137 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
140 mPopupArrowVisual(""),
148 mDisabledColor(0.0f, 0.0f, 0.0f, 0.0f),
149 mHitRegion(0.0f, 0.0f),
150 mTrackRegion(0.0f, 0.0f),
151 mHandleSize(0.0f, 0.0f),
155 mMarkTolerance(0.0f),
167 void Slider::OnInitialize()
175 SetHitRegion(DEFAULT_HIT_REGION);
176 SetTrackRegion(DEFAULT_TRACK_REGION);
177 SetHandleSize(DEFAULT_HANDLE_SIZE);
179 const std::string imageDirPath = AssetManager::GetDaliImagePath();
180 SetTrackVisual(imageDirPath + SKINNED_TRACK_VISUAL_FILE_NAME);
181 SetHandleVisual(imageDirPath + SKINNED_HANDLE_VISUAL_FILE_NAME);
182 SetProgressVisual(imageDirPath + SKINNED_PROGRESS_VISUAL_FILE_NAME);
183 SetPopupVisual(imageDirPath + SKINNED_POPUP_VISUAL_FILE_NAME);
184 SetPopupArrowVisual(imageDirPath + SKINNED_POPUP_ARROW_VISUAL_FILE_NAME);
186 SetShowPopup(DEFAULT_SHOW_POPUP);
187 SetShowValue(DEFAULT_SHOW_VALUE);
189 SetEnabled(DEFAULT_ENABLED);
190 SetDisabledColor(DEFAULT_DISABLED_COLOR);
192 SetSnapToMarks(DEFAULT_SNAP_TO_MARKS);
193 SetMarkTolerance(MARK_SNAP_TOLERANCE);
195 SetLowerBound(DEFAULT_LOWER_BOUND);
196 SetUpperBound(DEFAULT_UPPER_BOUND);
198 SetValuePrecision(DEFAULT_VALUE_PRECISION);
199 mValue = DEFAULT_VALUE;
200 DisplayValue(mValue, false); // Run this last to display the correct value
202 // Size the Slider actor to a default
203 self.SetProperty(Actor::Property::SIZE, Vector2(DEFAULT_HIT_REGION.x, DEFAULT_HIT_REGION.y));
205 // Connect to the touch signal
206 self.TouchedSignal().Connect(this, &Slider::OnTouch);
209 self.SetProperty(DevelControl::Property::ACCESSIBILITY_ROLE, Dali::Accessibility::Role::SLIDER);
210 self.SetProperty(DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true);
213 DevelControl::ControlAccessible* Slider::CreateAccessibleObject()
215 return new SliderAccessible(Self());
218 void Slider::OnRelayout(const Vector2& size, RelayoutContainer& container)
220 SetHitRegion(Vector2(size.x, GetHitRegion().y));
221 // Factor in handle overshoot into size of backing
222 SetTrackRegion(Vector2(size.x - GetHandleSize().x, GetTrackRegion().y));
223 Control::OnRelayout(size, container);
226 bool Slider::OnTouch(Actor actor, const TouchEvent& touch)
228 if(mState != DISABLED)
230 const PointState::Type touchState = touch.GetState(0);
232 if(touchState == PointState::DOWN)
236 float percentage = MapPercentage(touch.GetLocalPosition(0));
237 float value = MapBounds((GetSnapToMarks()) ? SnapToMark(percentage) : MarkFilter(percentage), GetLowerBound(), GetUpperBound());
241 else if(touchState == PointState::UP)
243 if(mState == PRESSED)
246 mSlidingFinishedSignal.Emit(Toolkit::Slider::DownCast(Self()), GetValue());
254 void Slider::OnPan(Actor actor, const PanGesture& gesture)
256 // gesture.position is in local actor coordinates
257 if(mState != DISABLED)
259 switch(gesture.GetState())
261 case GestureState::CONTINUING:
263 if(mState == PRESSED)
265 float value = MapBounds(MarkFilter(MapPercentage(gesture.GetPosition())), GetLowerBound(), GetUpperBound());
271 case GestureState::FINISHED:
273 if(mState == PRESSED)
277 float value = MapBounds(SnapToMark(MapPercentage(gesture.GetPosition())), GetLowerBound(), GetUpperBound());
281 mSlidingFinishedSignal.Emit(Toolkit::Slider::DownCast(Self()), GetValue());
295 float Slider::HitSpaceToDomain(float x)
297 float halfRegionWidth = GetHitRegion().x * 0.5f;
298 float halfDomainWidth = (mDomain.to.x - mDomain.from.x) * 0.5f;
299 float endDiff = halfRegionWidth - halfDomainWidth;
304 float Slider::MapPercentage(const Vector2& point)
306 return Clamp((HitSpaceToDomain(point.x) - mDomain.from.x) / (mDomain.to.x - mDomain.from.x), 0.0f, 1.0f);
309 float Slider::MapValuePercentage(float value)
311 return (value - GetLowerBound()) / (GetUpperBound() - GetLowerBound());
314 float Slider::MapBounds(float percent, float lowerBound, float upperBound)
316 return lowerBound + percent * (upperBound - lowerBound);
319 Slider::Domain Slider::CalcDomain(const Vector2& currentSize)
321 return Domain(Vector2(0.0f, 0.0f), currentSize);
324 void Slider::DisplayValue(float value, bool raiseSignals)
326 float clampedValue = Clamp(value, GetLowerBound(), GetUpperBound());
328 float percent = MapValuePercentage(clampedValue);
330 float x = mDomain.from.x + percent * (mDomain.to.x - mDomain.from.x);
332 mHandle.SetProperty(Actor::Property::POSITION_X, x);
337 mProgress.SetProperty(Actor::Property::SIZE, Vector2(x, GetTrackRegion().y));
343 Toolkit::Slider self = Toolkit::Slider::DownCast(Self());
344 mValueChangedSignal.Emit(self, clampedValue);
347 if(MarkReached(percent, markIndex))
349 mMarkReachedSignal.Emit(self, markIndex);
353 if(mHandleValueTextLabel)
355 std::stringstream ss;
356 ss.precision(GetValuePrecision());
357 ss << std::fixed << clampedValue;
359 std::string label = mHandleValueTextLabel.GetProperty<std::string>(Toolkit::TextLabel::Property::TEXT);
360 if(label.compare(ss.str()))
362 mHandleValueTextLabel.SetProperty(Toolkit::TextLabel::Property::TEXT, ss.str());
367 void Slider::SetMarks(const MarkList& marks)
372 const Slider::MarkList& Slider::GetMarks() const
377 void Slider::SetSnapToMarks(bool snap)
382 bool Slider::GetSnapToMarks() const
387 Actor Slider::CreateHitRegion()
389 Actor hitRegion = Actor::New();
390 hitRegion.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
391 hitRegion.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
392 hitRegion.TouchedSignal().Connect(this, &Slider::OnTouch);
397 Toolkit::ImageView Slider::CreateTrack()
399 Toolkit::ImageView track = Toolkit::ImageView::New();
400 track.SetProperty(Dali::Actor::Property::NAME, "SliderTrack");
401 track.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
402 track.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
406 void Slider::SetTrackVisual(const std::string& filename)
408 if(mHandle && (filename.size() > 0))
410 mTrack.SetImage(filename);
411 mTrackVisual = filename;
415 void Slider::SetTrackVisual(Property::Map map)
417 Property::Value* imageValue = map.Find("url");
420 mTrackVisual.clear();
421 std::string filename;
422 if(imageValue->Get(filename))
424 if(mTrack && (filename.size() > 0))
426 mTrack.SetImage(filename);
432 Property::Value* sizeValue = map.Find("size");
436 if(sizeValue->Get(size))
441 mTrack.SetProperty(Actor::Property::SIZE, mTrackRegion);
444 ResizeProgressRegion(Vector2(0.0f, mTrackRegion.y));
446 mDomain = CalcDomain(mTrackRegion);
448 // Set the progress bar to correct width
449 DisplayValue(GetValue(), false);
454 std::string Slider::GetTrackVisual()
459 Toolkit::ImageView Slider::CreateProgress()
461 Toolkit::ImageView progress = Toolkit::ImageView::New();
462 progress.SetProperty(Dali::Actor::Property::NAME, "SliderProgress");
463 progress.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER_LEFT);
464 progress.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER_LEFT);
469 void Slider::SetProgressVisual(const std::string& filename)
471 if(mProgress && (filename.size() > 0))
473 mProgress.SetImage(filename);
474 mProgressVisual = filename;
478 void Slider::SetProgressVisual(Property::Map map)
480 Property::Value* imageValue = map.Find("url");
483 mProgressVisual.clear();
484 std::string filename;
485 if(imageValue->Get(filename))
487 if(mProgress && (filename.size() > 0))
489 mProgress.SetImage(filename);
496 std::string Slider::GetProgressVisual()
498 return mProgressVisual;
501 void Slider::SetPopupVisual(const std::string& filename)
503 mPopupVisual = filename;
506 void Slider::SetPopupVisual(Property::Map map)
508 Property::Value* imageValue = map.Find("url");
511 mPopupVisual.clear();
512 std::string filename;
513 if(imageValue->Get(filename))
515 if(mPopup && (filename.size() > 0))
517 mPopup.SetImage(filename);
524 std::string Slider::GetPopupVisual()
529 void Slider::CreatePopupImage(const std::string& filename)
531 if(mPopup && (filename.size() > 0))
534 map[Toolkit::ImageVisual::Property::URL] = filename;
535 mPopup.SetProperty(Toolkit::ImageView::Property::IMAGE, map);
539 void Slider::SetPopupArrowVisual(const std::string& filename)
541 mPopupArrowVisual = filename;
544 void Slider::SetPopupArrowVisual(Property::Map map)
546 Property::Value* imageValue = map.Find("url");
549 mPopupArrowVisual.clear();
550 std::string filename;
551 if(imageValue->Get(filename))
553 if(mPopupArrow && (filename.size() > 0))
555 mPopupArrow.SetImage(filename);
556 mPopupArrowMap = map;
562 std::string Slider::GetPopupArrowVisual()
564 return mPopupArrowVisual;
567 void Slider::CreatePopupArrowImage(const std::string& filename)
569 if(mPopupArrow && (filename.size() > 0))
572 map[Toolkit::ImageVisual::Property::URL] = filename;
573 mPopupArrow.SetProperty(Toolkit::ImageView::Property::IMAGE, map);
577 void Slider::ResizeProgressRegion(const Vector2& region)
581 mProgress.SetProperty(Actor::Property::SIZE, region);
585 Toolkit::ImageView Slider::CreateHandle()
587 Toolkit::ImageView handle = Toolkit::ImageView::New();
588 handle.SetProperty(Dali::Actor::Property::NAME, "SliderHandle");
589 handle.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER_LEFT);
590 handle.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
595 Toolkit::ImageView Slider::CreatePopupArrow()
597 Toolkit::ImageView arrow = Toolkit::ImageView::New();
598 arrow.SetStyleName("SliderPopupArrow");
599 arrow.SetProperty(Dali::Actor::Property::NAME, "SliderPopupArrow");
600 arrow.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER);
601 arrow.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
606 Toolkit::TextLabel Slider::CreatePopupText()
608 Toolkit::TextLabel textLabel = Toolkit::TextLabel::New();
609 textLabel.SetProperty(Dali::Actor::Property::NAME, "SliderPopupTextLabel");
610 textLabel.SetStyleName("SliderPopupTextLabel");
611 textLabel.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
612 textLabel.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
613 textLabel.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
614 textLabel.SetProperty(Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER");
615 textLabel.SetProperty(Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER");
616 textLabel.SetProperty(Actor::Property::PADDING, Padding(POPUP_TEXT_PADDING, POPUP_TEXT_PADDING, 0.0f, 0.0f));
617 textLabel.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, false);
621 Toolkit::ImageView Slider::CreatePopup()
623 Toolkit::ImageView popup = Toolkit::ImageView::New();
624 popup.SetProperty(Dali::Actor::Property::NAME, "SliderPopup");
625 popup.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
626 popup.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
627 popup.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::WIDTH);
629 mValueTextLabel = CreatePopupText();
630 popup.Add(mValueTextLabel);
635 void Slider::SetHandleVisual(const std::string& filename)
637 if(mHandle && (filename.size() > 0))
639 mHandle.SetImage(filename);
640 mHandleVisual = filename;
644 void Slider::SetHandleVisual(Property::Map map)
646 Property::Value* imageValue = map.Find("url");
649 mHandleVisual.clear();
650 std::string filename;
651 if(imageValue->Get(filename))
653 if(mHandle && (filename.size() > 0))
655 mHandle.SetImage(filename);
661 Property::Value* sizeValue = map.Find("size");
665 if(sizeValue->Get(size))
668 ResizeHandleSize(mHandleSize);
670 Vector2 hitRegion = GetHitRegion();
671 hitRegion.x += mHandleSize.x;
672 SetHitRegion(hitRegion);
677 std::string Slider::GetHandleVisual()
679 return mHandleVisual;
682 void Slider::ResizeHandleSize(const Vector2& size)
686 mHandle.SetProperty(Actor::Property::SIZE, size);
690 void Slider::CreateHandleValueDisplay()
692 if(mHandle && !mHandleValueTextLabel)
694 mHandleValueTextLabel = Toolkit::TextLabel::New();
695 mHandleValueTextLabel.SetProperty(Dali::Actor::Property::NAME, "SliderHandleTextLabel");
696 mHandleValueTextLabel.SetStyleName("SliderHandleTextLabel");
697 mHandleValueTextLabel.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
698 mHandleValueTextLabel.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
699 mHandleValueTextLabel.SetProperty(Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER");
700 mHandleValueTextLabel.SetProperty(Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER");
701 mHandleValueTextLabel.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, false);
702 mHandle.Add(mHandleValueTextLabel);
706 void Slider::DestroyHandleValueDisplay()
708 UnparentAndReset(mHandleValueTextLabel);
711 Actor Slider::CreateValueDisplay()
713 Actor popup = Actor::New();
714 popup.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
715 popup.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
717 mPopupArrow = CreatePopupArrow();
718 popup.Add(mPopupArrow);
720 mPopup = CreatePopup();
721 mPopup.SetProperty(Actor::Property::SIZE, Vector2(0.0f, VALUE_POPUP_HEIGHT));
722 mPopupArrow.Add(mPopup);
727 Toolkit::Slider::ValueChangedSignalType& Slider::ValueChangedSignal()
729 return mValueChangedSignal;
732 Toolkit::Slider::ValueChangedSignalType& Slider::SlidingFinishedSignal()
734 return mSlidingFinishedSignal;
737 Toolkit::Slider::MarkReachedSignalType& Slider::MarkReachedSignal()
739 return mMarkReachedSignal;
742 void Slider::UpdateSkin()
748 mTrack.SetProperty(Actor::Property::COLOR, Color::WHITE);
749 mHandle.SetProperty(Actor::Property::COLOR, Color::WHITE);
750 mProgress.SetProperty(Actor::Property::COLOR, Color::WHITE);
755 Vector4 disabledColor = GetDisabledColor();
756 mTrack.SetProperty(Actor::Property::COLOR, disabledColor);
757 mHandle.SetProperty(Actor::Property::COLOR, disabledColor);
758 mProgress.SetProperty(Actor::Property::COLOR, disabledColor);
772 void Slider::CreateChildren()
777 mHitArea = CreateHitRegion();
778 mPanDetector = PanGestureDetector::New();
779 mPanDetector.Attach(mHitArea);
780 mPanDetector.DetectedSignal().Connect(this, &Slider::OnPan);
784 mTrack = CreateTrack();
788 mProgress = CreateProgress();
789 mTrack.Add(mProgress);
792 mHandle = CreateHandle();
793 mProgress.Add(mHandle);
796 void Slider::SetHitRegion(const Vector2& size)
802 mHitArea.SetProperty(Actor::Property::SIZE, mHitRegion);
806 const Vector2& Slider::GetHitRegion() const
811 void Slider::AddPopup()
815 mValueDisplay = CreateValueDisplay();
816 mValueDisplay.SetProperty(Actor::Property::VISIBLE, false);
817 mHandle.Add(mValueDisplay);
819 CreatePopupImage(GetPopupVisual());
820 CreatePopupArrowImage(GetPopupArrowVisual());
822 mValueTimer = Timer::New(VALUE_VIEW_SHOW_DURATION);
823 mValueTimer.TickSignal().Connect(this, &Slider::HideValueView);
827 void Slider::RemovePopup()
834 mPopupArrow.Unparent();
837 mValueDisplay.Unparent();
838 mValueDisplay.Reset();
840 mValueTimer.TickSignal().Disconnect(this, &Slider::HideValueView);
845 float Slider::MarkFilter(float value)
847 const float MARK_TOLERANCE = GetMarkTolerance();
849 float mark = SnapToMark(value);
850 if(fabsf(mark - value) < MARK_TOLERANCE)
856 float Slider::SnapToMark(float value)
858 float closestMark = value;
859 float closestDist = std::numeric_limits<float>::max();
862 for(MarkList::SizeType i = 0; i < mMarks.Count(); ++i)
864 const Property::Value& propertyValue = mMarks[i];
865 propertyValue.Get(mark);
866 mark = MapValuePercentage(mark);
868 float dist = fabsf(mark - value);
869 if(dist < closestDist)
879 bool Slider::MarkReached(float value, int& outIndex)
881 const float MARK_TOLERANCE = GetMarkTolerance();
885 tail = mMarks.Size() - 1;
891 current = head + (tail - head) / 2;
893 const Property::Value& propertyValue = mMarks[current];
894 propertyValue.Get(mark);
895 mark = MapValuePercentage(mark);
897 if(fabsf(mark - value) < MARK_TOLERANCE)
916 bool Slider::HideValueView()
920 mValueDisplay.SetProperty(Actor::Property::VISIBLE, false);
926 void Slider::SetLowerBound(float bound)
929 DisplayValue(GetValue(), false);
932 float Slider::GetLowerBound() const
937 void Slider::SetUpperBound(float bound)
940 DisplayValue(GetValue(), false);
943 float Slider::GetUpperBound() const
948 void Slider::SetValue(float value)
951 DisplayValue(mValue, true);
952 if(Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor())
954 auto accessible = GetAccessibleObject();
955 if(DALI_LIKELY(accessible))
957 accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
962 float Slider::GetValue() const
967 void Slider::SetTrackRegion(const Vector2& region)
969 mTrackRegion = region;
973 mTrack.SetProperty(Actor::Property::SIZE, mTrackRegion);
976 ResizeProgressRegion(Vector2(0.0f, mTrackRegion.y));
978 mDomain = CalcDomain(mTrackRegion);
980 DisplayValue(GetValue(), false); // Set the progress bar to correct width
983 const Vector2& Slider::GetTrackRegion() const
988 void Slider::SetHandleSize(const Vector2& size)
992 ResizeHandleSize(mHandleSize);
994 Vector2 hitRegion = GetHitRegion();
995 hitRegion.x += mHandleSize.x;
996 SetHitRegion(hitRegion);
999 const Vector2& Slider::GetHandleSize() const
1004 void Slider::SetDisabledColor(const Vector4& color)
1006 mDisabledColor = color;
1011 Vector4 Slider::GetDisabledColor() const
1013 return mDisabledColor;
1016 void Slider::SetValuePrecision(int precision)
1018 mValuePrecision = precision;
1021 int Slider::GetValuePrecision() const
1023 return mValuePrecision;
1026 void Slider::SetShowPopup(bool showPopup)
1028 mShowPopup = showPopup;
1041 bool Slider::GetShowPopup() const
1046 void Slider::SetShowValue(bool showValue)
1048 mShowValue = showValue;
1052 CreateHandleValueDisplay();
1056 DestroyHandleValueDisplay();
1060 bool Slider::GetShowValue() const
1065 void Slider::SetEnabled(bool enabled)
1079 bool Slider::IsEnabled() const
1081 return mState != DISABLED;
1084 void Slider::SetMarkTolerance(float tolerance)
1086 mMarkTolerance = tolerance;
1089 float Slider::GetMarkTolerance() const
1091 return mMarkTolerance;
1094 // Static class method to support script connecting signals
1095 bool Slider::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
1097 Dali::BaseHandle handle(object);
1099 bool connected = true;
1100 Toolkit::Slider slider = Toolkit::Slider::DownCast(handle);
1102 if(0 == strcmp(signalName.c_str(), SIGNAL_VALUE_CHANGED))
1104 slider.ValueChangedSignal().Connect(tracker, functor);
1106 else if(0 == strcmp(signalName.c_str(), SIGNAL_MARK))
1108 slider.MarkReachedSignal().Connect(tracker, functor);
1112 // signalName does not match any signal
1119 void Slider::DisplayPopup(float value)
1121 // Value displayDoConnectSignal
1124 std::stringstream ss;
1125 ss.precision(GetValuePrecision());
1126 ss << std::fixed << value;
1127 mValueTextLabel.SetProperty(Toolkit::TextLabel::Property::TEXT, ss.str());
1131 mValueDisplay.SetProperty(Actor::Property::VISIBLE, true);
1133 mValueTimer.SetInterval(VALUE_VIEW_SHOW_DURATION);
1138 void Slider::SetProperty(BaseObject* object, Property::Index propertyIndex, const Property::Value& value)
1140 Toolkit::Slider slider = Toolkit::Slider::DownCast(Dali::BaseHandle(object));
1144 Slider& sliderImpl(GetImpl(slider));
1146 switch(propertyIndex)
1148 case Toolkit::Slider::Property::LOWER_BOUND:
1150 sliderImpl.SetLowerBound(value.Get<float>());
1154 case Toolkit::Slider::Property::UPPER_BOUND:
1156 sliderImpl.SetUpperBound(value.Get<float>());
1160 case Toolkit::Slider::Property::VALUE:
1162 sliderImpl.SetValue(value.Get<float>());
1166 case Toolkit::Slider::Property::TRACK_VISUAL:
1171 sliderImpl.SetTrackVisual(map);
1176 case Toolkit::Slider::Property::HANDLE_VISUAL:
1181 sliderImpl.SetHandleVisual(map);
1186 case Toolkit::Slider::Property::PROGRESS_VISUAL:
1191 sliderImpl.SetProgressVisual(map);
1196 case Toolkit::Slider::Property::POPUP_VISUAL:
1198 std::string imageUrl;
1199 if(value.Get(imageUrl))
1201 sliderImpl.SetPopupVisual(imageUrl);
1204 // If it is not a string, then get a Property::Map from the property if possible.
1208 sliderImpl.SetPopupVisual(map);
1214 case Toolkit::Slider::Property::POPUP_ARROW_VISUAL:
1219 sliderImpl.SetPopupArrowVisual(map);
1224 case Toolkit::Slider::Property::DISABLED_COLOR:
1226 sliderImpl.SetDisabledColor(value.Get<Vector4>());
1230 case Toolkit::Slider::Property::VALUE_PRECISION:
1232 sliderImpl.SetValuePrecision(value.Get<int>());
1236 case Toolkit::Slider::Property::SHOW_POPUP:
1238 sliderImpl.SetShowPopup(value.Get<bool>());
1242 case Toolkit::Slider::Property::SHOW_VALUE:
1244 sliderImpl.SetShowValue(value.Get<bool>());
1248 case Toolkit::Slider::Property::MARKS:
1250 sliderImpl.SetMarks(value.Get<Property::Array>());
1254 case Toolkit::Slider::Property::SNAP_TO_MARKS:
1256 sliderImpl.SetSnapToMarks(value.Get<bool>());
1260 case Toolkit::Slider::Property::MARK_TOLERANCE:
1262 sliderImpl.SetMarkTolerance(value.Get<float>());
1269 Property::Value Slider::GetProperty(BaseObject* object, Property::Index propertyIndex)
1271 Property::Value value;
1273 Toolkit::Slider slider = Toolkit::Slider::DownCast(Dali::BaseHandle(object));
1277 Slider& sliderImpl(GetImpl(slider));
1279 switch(propertyIndex)
1281 case Toolkit::Slider::Property::LOWER_BOUND:
1283 value = sliderImpl.GetLowerBound();
1287 case Toolkit::Slider::Property::UPPER_BOUND:
1289 value = sliderImpl.GetUpperBound();
1293 case Toolkit::Slider::Property::VALUE:
1295 value = sliderImpl.GetValue();
1299 case Toolkit::Slider::Property::TRACK_VISUAL:
1301 if(!sliderImpl.mTrackVisual.empty())
1303 value = sliderImpl.GetTrackVisual();
1305 else if(!sliderImpl.mTrackMap.Empty())
1307 value = sliderImpl.mTrackMap;
1312 case Toolkit::Slider::Property::HANDLE_VISUAL:
1314 if(!sliderImpl.mHandleVisual.empty())
1316 value = sliderImpl.GetHandleVisual();
1318 else if(!sliderImpl.mHandleMap.Empty())
1320 value = sliderImpl.mHandleMap;
1325 case Toolkit::Slider::Property::PROGRESS_VISUAL:
1327 if(!sliderImpl.mProgressVisual.empty())
1329 value = sliderImpl.GetProgressVisual();
1331 else if(!sliderImpl.mProgressMap.Empty())
1333 value = sliderImpl.mProgressMap;
1338 case Toolkit::Slider::Property::POPUP_VISUAL:
1340 if(!sliderImpl.mPopupVisual.empty())
1342 value = sliderImpl.GetPopupVisual();
1344 else if(!sliderImpl.mPopupMap.Empty())
1346 value = sliderImpl.mPopupMap;
1351 case Toolkit::Slider::Property::POPUP_ARROW_VISUAL:
1353 if(!sliderImpl.mPopupArrowVisual.empty())
1355 value = sliderImpl.GetPopupArrowVisual();
1357 else if(!sliderImpl.mPopupArrowMap.Empty())
1359 value = sliderImpl.mPopupArrowMap;
1364 case Toolkit::Slider::Property::DISABLED_COLOR:
1366 value = sliderImpl.GetDisabledColor();
1370 case Toolkit::Slider::Property::VALUE_PRECISION:
1372 value = sliderImpl.GetValuePrecision();
1376 case Toolkit::Slider::Property::SHOW_POPUP:
1378 value = sliderImpl.GetShowPopup();
1382 case Toolkit::Slider::Property::SHOW_VALUE:
1384 value = sliderImpl.GetShowValue();
1388 case Toolkit::Slider::Property::MARKS:
1390 Property::Value value1(Property::ARRAY);
1391 Property::Array* markArray = value1.GetArray();
1395 *markArray = sliderImpl.GetMarks();
1402 case Toolkit::Slider::Property::SNAP_TO_MARKS:
1404 value = sliderImpl.GetSnapToMarks();
1408 case Toolkit::Slider::Property::MARK_TOLERANCE:
1410 value = sliderImpl.GetMarkTolerance();
1419 double Slider::SliderAccessible::GetMinimum() const
1421 auto self = Toolkit::Slider::DownCast(Self());
1422 return self.GetProperty(Toolkit::Slider::Property::LOWER_BOUND).Get<float>();
1425 double Slider::SliderAccessible::GetCurrent() const
1427 auto self = Toolkit::Slider::DownCast(Self());
1428 return self.GetProperty(Toolkit::Slider::Property::VALUE).Get<float>();
1431 std::string Slider::SliderAccessible::GetValueText() const
1433 return {}; // Text mode is not used at the moment
1436 double Slider::SliderAccessible::GetMaximum() const
1438 auto self = Toolkit::Slider::DownCast(Self());
1439 return self.GetProperty(Toolkit::Slider::Property::UPPER_BOUND).Get<float>();
1442 bool Slider::SliderAccessible::SetCurrent(double current)
1444 if(current < GetMinimum() || current > GetMaximum())
1447 auto self = Toolkit::Slider::DownCast(Self());
1448 auto& impl = Toolkit::GetImpl(self);
1450 const float prev = self.GetProperty<float>(Toolkit::Slider::Property::VALUE);
1451 float next = static_cast<float>(current);
1453 if(fabsf(next - prev) < Math::MACHINE_EPSILON_0)
1457 else if(self.GetProperty<bool>(Toolkit::Slider::Property::SNAP_TO_MARKS))
1459 auto marks = self.GetProperty<Property::Array>(Toolkit::Slider::Property::MARKS);
1462 if(impl.MarkReached(impl.MapValuePercentage(prev), prevIdx))
1464 int nextIdx = prevIdx;
1465 nextIdx += (next > prev) ? 1 : -1;
1467 if(nextIdx < 0 || nextIdx >= static_cast<int>(marks.Count()))
1472 next = marks[nextIdx].Get<float>();
1476 next = impl.MapBounds(impl.SnapToMark(impl.MapValuePercentage(next)), impl.GetLowerBound(), impl.GetUpperBound());
1481 next = impl.MapBounds(impl.MarkFilter(impl.MapValuePercentage(next)), impl.GetLowerBound(), impl.GetUpperBound());
1484 impl.SetValue(next);
1485 impl.DisplayPopup(next);
1490 double Slider::SliderAccessible::GetMinimumIncrement() const
1492 auto self = Toolkit::Slider::DownCast(Self());
1494 bool hasMarks = !self.GetProperty<Property::Array>(Toolkit::Slider::Property::MARKS).Empty();
1495 float tolerance = self.GetProperty<float>(Toolkit::Slider::Property::MARK_TOLERANCE);
1497 if(!hasMarks || fabsf(tolerance) < 0.01)
1499 return 0.0; // let screen-reader choose the increment
1502 return Math::MACHINE_EPSILON_10000 + tolerance * (GetMaximum() - GetMinimum());
1505 } // namespace Internal
1507 } // namespace Toolkit