2 * Copyright (c) 2021 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/public-api/controls/control-impl.h>
32 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
33 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
43 namespace // Unnamed namespace
47 return Dali::Toolkit::Slider::New();
51 // Setup properties, signals and actions using the type-registry.
52 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::Slider, Toolkit::Control, Create )
54 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "lowerBound", FLOAT, LOWER_BOUND )
55 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "upperBound", FLOAT, UPPER_BOUND )
56 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "value", FLOAT, VALUE )
57 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "trackVisual", MAP, TRACK_VISUAL )
58 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "handleVisual", MAP, HANDLE_VISUAL )
59 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "progressVisual", MAP, PROGRESS_VISUAL )
60 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "popupVisual", MAP, POPUP_VISUAL )
61 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "popupArrowVisual", MAP, POPUP_ARROW_VISUAL)
62 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "disabledColor", VECTOR4, DISABLED_COLOR )
63 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "valuePrecision", INTEGER, VALUE_PRECISION )
64 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "showPopup", BOOLEAN, SHOW_POPUP )
65 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "showValue", BOOLEAN, SHOW_VALUE )
66 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "marks", ARRAY, MARKS )
67 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "snapToMarks", BOOLEAN, SNAP_TO_MARKS )
68 DALI_PROPERTY_REGISTRATION(Toolkit, Slider, "markTolerance", FLOAT, MARK_TOLERANCE )
70 DALI_SIGNAL_REGISTRATION(Toolkit, Slider, "valueChanged", SIGNAL_VALUE_CHANGED)
71 DALI_SIGNAL_REGISTRATION(Toolkit, Slider, "mark", SIGNAL_MARK )
73 DALI_TYPE_REGISTRATION_END()
76 const float MARK_SNAP_TOLERANCE = 0.05f; // 5% of slider width
78 const int VALUE_VIEW_SHOW_DURATION = 1000; // millisec
79 const int VALUE_VIEW_SHOW_DURATION_LONG = 2000; // millisec
81 const float VALUE_VERTICAL_OFFSET = 48.0f;
83 const float DEFAULT_WIDTH = 0.0f;
84 const float DEFAULT_HEIGHT = 27.0f;
85 const float DEFAULT_HIT_HEIGHT = 72.0f;
86 const float DEFAULT_HANDLE_HEIGHT = DEFAULT_HIT_HEIGHT;
87 const float POPUP_TEXT_PADDING = 10.0f;
89 const char* SKINNED_TRACK_VISUAL_FILE_NAME = "slider-skin.9.png";
90 const char* SKINNED_HANDLE_VISUAL_FILE_NAME = "slider-skin-handle.png";
91 const char* SKINNED_PROGRESS_VISUAL_FILE_NAME = "slider-skin-progress.9.png";
92 const char* SKINNED_POPUP_VISUAL_FILE_NAME = "slider-popup.9.png";
93 const char* SKINNED_POPUP_ARROW_VISUAL_FILE_NAME = "slider-popup-arrow.png";
95 const Vector2 DEFAULT_HIT_REGION(DEFAULT_WIDTH, DEFAULT_HIT_HEIGHT);
96 const Vector2 DEFAULT_TRACK_REGION(DEFAULT_WIDTH, DEFAULT_HEIGHT);
97 const Vector2 DEFAULT_HANDLE_SIZE(DEFAULT_HANDLE_HEIGHT, DEFAULT_HANDLE_HEIGHT);
99 const Vector4 DEFAULT_DISABLED_COLOR(0.5f, 0.5f, 0.5f, 1.0f);
101 const float VALUE_POPUP_MARGIN = 10.0f;
102 const float VALUE_POPUP_HEIGHT = 81.0f;
103 const float VALUE_POPUP_MIN_WIDTH = 54.0f;
105 const float DEFAULT_LOWER_BOUND = 0.0f;
106 const float DEFAULT_UPPER_BOUND = 1.0f;
107 const float DEFAULT_VALUE = 0.0f;
108 const int DEFAULT_VALUE_PRECISION = 0;
109 const bool DEFAULT_SHOW_POPUP = false;
110 const bool DEFAULT_SHOW_VALUE = true;
111 const bool DEFAULT_ENABLED = true;
112 const bool DEFAULT_SNAP_TO_MARKS = false;
114 } // Unnamed namespace
116 ///////////////////////////////////////////////////////////////////////////////////////////////////
118 ///////////////////////////////////////////////////////////////////////////////////////////////////
120 Dali::Toolkit::Slider Slider::New()
122 // Create the implementation
123 SliderPtr slider(new Slider());
125 // Pass ownership to CustomActor via derived handle
126 Dali::Toolkit::Slider handle(*slider);
128 // Second-phase init of the implementation
129 // This can only be done after the CustomActor connection has been made...
130 slider->Initialize();
136 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
139 mPopupArrowVisual(""),
147 mDisabledColor(0.0f, 0.0f, 0.0f, 0.0f),
148 mHitRegion(0.0f, 0.0f),
149 mTrackRegion(0.0f, 0.0f),
150 mHandleSize(0.0f, 0.0f),
154 mMarkTolerance(0.0f),
166 void Slider::OnInitialize()
174 SetHitRegion(DEFAULT_HIT_REGION);
175 SetTrackRegion(DEFAULT_TRACK_REGION);
176 SetHandleSize(DEFAULT_HANDLE_SIZE);
178 const std::string imageDirPath = AssetManager::GetDaliImagePath();
179 SetTrackVisual(imageDirPath + SKINNED_TRACK_VISUAL_FILE_NAME);
180 SetHandleVisual(imageDirPath + SKINNED_HANDLE_VISUAL_FILE_NAME);
181 SetProgressVisual(imageDirPath + SKINNED_PROGRESS_VISUAL_FILE_NAME);
182 SetPopupVisual(imageDirPath + SKINNED_POPUP_VISUAL_FILE_NAME);
183 SetPopupArrowVisual(imageDirPath + SKINNED_POPUP_ARROW_VISUAL_FILE_NAME);
185 SetShowPopup(DEFAULT_SHOW_POPUP);
186 SetShowValue(DEFAULT_SHOW_VALUE);
188 SetEnabled(DEFAULT_ENABLED);
189 SetDisabledColor(DEFAULT_DISABLED_COLOR);
191 SetSnapToMarks(DEFAULT_SNAP_TO_MARKS);
192 SetMarkTolerance(MARK_SNAP_TOLERANCE);
194 SetLowerBound(DEFAULT_LOWER_BOUND);
195 SetUpperBound(DEFAULT_UPPER_BOUND);
197 SetValuePrecision(DEFAULT_VALUE_PRECISION);
198 mValue = DEFAULT_VALUE;
199 DisplayValue(mValue, false); // Run this last to display the correct value
201 // Size the Slider actor to a default
202 self.SetProperty(Actor::Property::SIZE, Vector2(DEFAULT_HIT_REGION.x, DEFAULT_HIT_REGION.y));
204 // Set the Slider to be highlightable in Screen Reader mode
205 self.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true);
207 // Connect to the touch signal
208 self.TouchedSignal().Connect(this, &Slider::OnTouch);
210 DevelControl::SetAccessibilityConstructor(self, [](Dali::Actor actor) {
211 return std::unique_ptr<Dali::Accessibility::Accessible>(
212 new AccessibleImpl(actor, Dali::Accessibility::Role::SLIDER));
216 void Slider::OnRelayout(const Vector2& size, RelayoutContainer& container)
218 SetHitRegion(Vector2(size.x, GetHitRegion().y));
219 // Factor in handle overshoot into size of backing
220 SetTrackRegion(Vector2(size.x - GetHandleSize().x, GetTrackRegion().y));
221 Control::OnRelayout(size, container);
224 bool Slider::OnTouch(Actor actor, const TouchEvent& touch)
226 if(mState != DISABLED)
228 const PointState::Type touchState = touch.GetState(0);
230 if(touchState == PointState::DOWN)
234 float percentage = MapPercentage(touch.GetLocalPosition(0));
235 float value = MapBounds((GetSnapToMarks()) ? SnapToMark(percentage) : MarkFilter(percentage), GetLowerBound(), GetUpperBound());
239 else if(touchState == PointState::UP)
241 if(mState == PRESSED)
244 mSlidingFinishedSignal.Emit(Toolkit::Slider::DownCast(Self()), GetValue());
252 void Slider::OnPan(Actor actor, const PanGesture& gesture)
254 // gesture.position is in local actor coordinates
255 if(mState != DISABLED)
257 switch(gesture.GetState())
259 case GestureState::CONTINUING:
261 if(mState == PRESSED)
263 float value = MapBounds(MarkFilter(MapPercentage(gesture.GetPosition())), GetLowerBound(), GetUpperBound());
269 case GestureState::FINISHED:
271 if(mState == PRESSED)
275 float value = MapBounds(SnapToMark(MapPercentage(gesture.GetPosition())), GetLowerBound(), GetUpperBound());
279 mSlidingFinishedSignal.Emit(Toolkit::Slider::DownCast(Self()), GetValue());
293 float Slider::HitSpaceToDomain(float x)
295 float halfRegionWidth = GetHitRegion().x * 0.5f;
296 float halfDomainWidth = (mDomain.to.x - mDomain.from.x) * 0.5f;
297 float endDiff = halfRegionWidth - halfDomainWidth;
302 float Slider::MapPercentage(const Vector2& point)
304 return Clamp((HitSpaceToDomain(point.x) - mDomain.from.x) / (mDomain.to.x - mDomain.from.x), 0.0f, 1.0f);
307 float Slider::MapValuePercentage(float value)
309 return (value - GetLowerBound()) / (GetUpperBound() - GetLowerBound());
312 float Slider::MapBounds(float percent, float lowerBound, float upperBound)
314 return lowerBound + percent * (upperBound - lowerBound);
317 Slider::Domain Slider::CalcDomain(const Vector2& currentSize)
319 return Domain(Vector2(0.0f, 0.0f), currentSize);
322 void Slider::DisplayValue(float value, bool raiseSignals)
324 float clampedValue = Clamp(value, GetLowerBound(), GetUpperBound());
326 float percent = MapValuePercentage(clampedValue);
328 float x = mDomain.from.x + percent * (mDomain.to.x - mDomain.from.x);
330 mHandle.SetProperty(Actor::Property::POSITION_X, x);
335 mProgress.SetProperty(Actor::Property::SIZE, Vector2(x, GetTrackRegion().y));
341 Toolkit::Slider self = Toolkit::Slider::DownCast(Self());
342 mValueChangedSignal.Emit(self, clampedValue);
345 if(MarkReached(percent, markIndex))
347 mMarkReachedSignal.Emit(self, markIndex);
351 if(mHandleValueTextLabel)
353 std::stringstream ss;
354 ss.precision(GetValuePrecision());
355 ss << std::fixed << clampedValue;
357 std::string label = mHandleValueTextLabel.GetProperty<std::string>(Toolkit::TextLabel::Property::TEXT);
358 if(label.compare(ss.str()))
360 mHandleValueTextLabel.SetProperty(Toolkit::TextLabel::Property::TEXT, ss.str());
365 void Slider::SetMarks(const MarkList& marks)
370 const Slider::MarkList& Slider::GetMarks() const
375 void Slider::SetSnapToMarks(bool snap)
380 bool Slider::GetSnapToMarks() const
385 Actor Slider::CreateHitRegion()
387 Actor hitRegion = Actor::New();
388 hitRegion.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
389 hitRegion.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
390 hitRegion.TouchedSignal().Connect(this, &Slider::OnTouch);
395 Toolkit::ImageView Slider::CreateTrack()
397 Toolkit::ImageView track = Toolkit::ImageView::New();
398 track.SetProperty(Dali::Actor::Property::NAME, "SliderTrack");
399 track.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
400 track.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
404 void Slider::SetTrackVisual(const std::string& filename)
406 if(mHandle && (filename.size() > 0))
408 mTrack.SetImage(filename);
409 mTrackVisual = filename;
413 void Slider::SetTrackVisual(Property::Map map)
415 Property::Value* imageValue = map.Find("url");
418 mTrackVisual.clear();
419 std::string filename;
420 if(imageValue->Get(filename))
422 if(mTrack && (filename.size() > 0))
424 mTrack.SetImage(filename);
430 Property::Value* sizeValue = map.Find("size");
434 if(sizeValue->Get(size))
439 mTrack.SetProperty(Actor::Property::SIZE, mTrackRegion);
442 ResizeProgressRegion(Vector2(0.0f, mTrackRegion.y));
444 mDomain = CalcDomain(mTrackRegion);
446 // Set the progress bar to correct width
447 DisplayValue(GetValue(), false);
452 std::string Slider::GetTrackVisual()
457 Toolkit::ImageView Slider::CreateProgress()
459 Toolkit::ImageView progress = Toolkit::ImageView::New();
460 progress.SetProperty(Dali::Actor::Property::NAME, "SliderProgress");
461 progress.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER_LEFT);
462 progress.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER_LEFT);
467 void Slider::SetProgressVisual(const std::string& filename)
469 if(mProgress && (filename.size() > 0))
471 mProgress.SetImage(filename);
472 mProgressVisual = filename;
476 void Slider::SetProgressVisual(Property::Map map)
478 Property::Value* imageValue = map.Find("url");
481 mProgressVisual.clear();
482 std::string filename;
483 if(imageValue->Get(filename))
485 if(mProgress && (filename.size() > 0))
487 mProgress.SetImage(filename);
494 std::string Slider::GetProgressVisual()
496 return mProgressVisual;
499 void Slider::SetPopupVisual(const std::string& filename)
501 mPopupVisual = filename;
504 void Slider::SetPopupVisual(Property::Map map)
506 Property::Value* imageValue = map.Find("url");
509 mPopupVisual.clear();
510 std::string filename;
511 if(imageValue->Get(filename))
513 if(mPopup && (filename.size() > 0))
515 mPopup.SetImage(filename);
522 std::string Slider::GetPopupVisual()
527 void Slider::CreatePopupImage(const std::string& filename)
529 if(mPopup && (filename.size() > 0))
532 map[Toolkit::ImageVisual::Property::URL] = filename;
533 mPopup.SetProperty(Toolkit::ImageView::Property::IMAGE, map);
537 void Slider::SetPopupArrowVisual(const std::string& filename)
539 mPopupArrowVisual = filename;
542 void Slider::SetPopupArrowVisual(Property::Map map)
544 Property::Value* imageValue = map.Find("url");
547 mPopupArrowVisual.clear();
548 std::string filename;
549 if(imageValue->Get(filename))
551 if(mPopupArrow && (filename.size() > 0))
553 mPopupArrow.SetImage(filename);
554 mPopupArrowMap = map;
560 std::string Slider::GetPopupArrowVisual()
562 return mPopupArrowVisual;
565 void Slider::CreatePopupArrowImage(const std::string& filename)
567 if(mPopupArrow && (filename.size() > 0))
570 map[Toolkit::ImageVisual::Property::URL] = filename;
571 mPopupArrow.SetProperty(Toolkit::ImageView::Property::IMAGE, map);
575 void Slider::ResizeProgressRegion(const Vector2& region)
579 mProgress.SetProperty(Actor::Property::SIZE, region);
583 Toolkit::ImageView Slider::CreateHandle()
585 Toolkit::ImageView handle = Toolkit::ImageView::New();
586 handle.SetProperty(Dali::Actor::Property::NAME, "SliderHandle");
587 handle.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER_LEFT);
588 handle.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
593 Toolkit::ImageView Slider::CreatePopupArrow()
595 Toolkit::ImageView arrow = Toolkit::ImageView::New();
596 arrow.SetStyleName("SliderPopupArrow");
597 arrow.SetProperty(Dali::Actor::Property::NAME, "SliderPopupArrow");
598 arrow.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER);
599 arrow.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
604 Toolkit::TextLabel Slider::CreatePopupText()
606 Toolkit::TextLabel textLabel = Toolkit::TextLabel::New();
607 textLabel.SetProperty(Dali::Actor::Property::NAME, "SliderPopupTextLabel");
608 textLabel.SetStyleName("SliderPopupTextLabel");
609 textLabel.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
610 textLabel.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
611 textLabel.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
612 textLabel.SetProperty(Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER");
613 textLabel.SetProperty(Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER");
614 textLabel.SetProperty(Actor::Property::PADDING, Padding(POPUP_TEXT_PADDING, POPUP_TEXT_PADDING, 0.0f, 0.0f));
615 textLabel.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, false);
619 Toolkit::ImageView Slider::CreatePopup()
621 Toolkit::ImageView popup = Toolkit::ImageView::New();
622 popup.SetProperty(Dali::Actor::Property::NAME, "SliderPopup");
623 popup.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
624 popup.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
625 popup.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::WIDTH);
627 mValueTextLabel = CreatePopupText();
628 popup.Add(mValueTextLabel);
633 void Slider::SetHandleVisual(const std::string& filename)
635 if(mHandle && (filename.size() > 0))
637 mHandle.SetImage(filename);
638 mHandleVisual = filename;
642 void Slider::SetHandleVisual(Property::Map map)
644 Property::Value* imageValue = map.Find("url");
647 mHandleVisual.clear();
648 std::string filename;
649 if(imageValue->Get(filename))
651 if(mHandle && (filename.size() > 0))
653 mHandle.SetImage(filename);
659 Property::Value* sizeValue = map.Find("size");
663 if(sizeValue->Get(size))
666 ResizeHandleSize(mHandleSize);
668 Vector2 hitRegion = GetHitRegion();
669 hitRegion.x += mHandleSize.x;
670 SetHitRegion(hitRegion);
675 std::string Slider::GetHandleVisual()
677 return mHandleVisual;
680 void Slider::ResizeHandleSize(const Vector2& size)
684 mHandle.SetProperty(Actor::Property::SIZE, size);
688 void Slider::CreateHandleValueDisplay()
690 if(mHandle && !mHandleValueTextLabel)
692 mHandleValueTextLabel = Toolkit::TextLabel::New();
693 mHandleValueTextLabel.SetProperty(Dali::Actor::Property::NAME, "SliderHandleTextLabel");
694 mHandleValueTextLabel.SetStyleName("SliderHandleTextLabel");
695 mHandleValueTextLabel.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
696 mHandleValueTextLabel.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
697 mHandleValueTextLabel.SetProperty(Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER");
698 mHandleValueTextLabel.SetProperty(Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER");
699 mHandleValueTextLabel.SetProperty(Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, false);
700 mHandle.Add(mHandleValueTextLabel);
704 void Slider::DestroyHandleValueDisplay()
706 UnparentAndReset(mHandleValueTextLabel);
709 Actor Slider::CreateValueDisplay()
711 Actor popup = Actor::New();
712 popup.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
713 popup.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
715 mPopupArrow = CreatePopupArrow();
716 popup.Add(mPopupArrow);
718 mPopup = CreatePopup();
719 mPopup.SetProperty(Actor::Property::SIZE, Vector2(0.0f, VALUE_POPUP_HEIGHT));
720 mPopupArrow.Add(mPopup);
725 Toolkit::Slider::ValueChangedSignalType& Slider::ValueChangedSignal()
727 return mValueChangedSignal;
730 Toolkit::Slider::ValueChangedSignalType& Slider::SlidingFinishedSignal()
732 return mSlidingFinishedSignal;
735 Toolkit::Slider::MarkReachedSignalType& Slider::MarkReachedSignal()
737 return mMarkReachedSignal;
740 void Slider::UpdateSkin()
746 mTrack.SetProperty(Actor::Property::COLOR, Color::WHITE);
747 mHandle.SetProperty(Actor::Property::COLOR, Color::WHITE);
748 mProgress.SetProperty(Actor::Property::COLOR, Color::WHITE);
753 Vector4 disabledColor = GetDisabledColor();
754 mTrack.SetProperty(Actor::Property::COLOR, disabledColor);
755 mHandle.SetProperty(Actor::Property::COLOR, disabledColor);
756 mProgress.SetProperty(Actor::Property::COLOR, disabledColor);
770 void Slider::CreateChildren()
775 mHitArea = CreateHitRegion();
776 mPanDetector = PanGestureDetector::New();
777 mPanDetector.Attach(mHitArea);
778 mPanDetector.DetectedSignal().Connect(this, &Slider::OnPan);
782 mTrack = CreateTrack();
786 mProgress = CreateProgress();
787 mTrack.Add(mProgress);
790 mHandle = CreateHandle();
791 mProgress.Add(mHandle);
794 void Slider::SetHitRegion(const Vector2& size)
800 mHitArea.SetProperty(Actor::Property::SIZE, mHitRegion);
804 const Vector2& Slider::GetHitRegion() const
809 void Slider::AddPopup()
813 mValueDisplay = CreateValueDisplay();
814 mValueDisplay.SetProperty(Actor::Property::VISIBLE, false);
815 mHandle.Add(mValueDisplay);
817 CreatePopupImage(GetPopupVisual());
818 CreatePopupArrowImage(GetPopupArrowVisual());
820 mValueTimer = Timer::New(VALUE_VIEW_SHOW_DURATION);
821 mValueTimer.TickSignal().Connect(this, &Slider::HideValueView);
825 void Slider::RemovePopup()
832 mPopupArrow.Unparent();
835 mValueDisplay.Unparent();
836 mValueDisplay.Reset();
838 mValueTimer.TickSignal().Disconnect(this, &Slider::HideValueView);
843 float Slider::MarkFilter(float value)
845 const float MARK_TOLERANCE = GetMarkTolerance();
847 float mark = SnapToMark(value);
848 if(fabsf(mark - value) < MARK_TOLERANCE)
854 float Slider::SnapToMark(float value)
856 float closestMark = value;
857 float closestDist = std::numeric_limits<float>::max();
860 for(MarkList::SizeType i = 0; i < mMarks.Count(); ++i)
862 const Property::Value& propertyValue = mMarks[i];
863 propertyValue.Get(mark);
864 mark = MapValuePercentage(mark);
866 float dist = fabsf(mark - value);
867 if(dist < closestDist)
877 bool Slider::MarkReached(float value, int& outIndex)
879 const float MARK_TOLERANCE = GetMarkTolerance();
883 tail = mMarks.Size() - 1;
889 current = head + (tail - head) / 2;
891 const Property::Value& propertyValue = mMarks[current];
892 propertyValue.Get(mark);
893 mark = MapValuePercentage(mark);
895 if(fabsf(mark - value) < MARK_TOLERANCE)
914 bool Slider::HideValueView()
918 mValueDisplay.SetProperty(Actor::Property::VISIBLE, false);
924 void Slider::SetLowerBound(float bound)
927 DisplayValue(GetValue(), false);
930 float Slider::GetLowerBound() const
935 void Slider::SetUpperBound(float bound)
938 DisplayValue(GetValue(), false);
941 float Slider::GetUpperBound() const
946 void Slider::SetValue(float value)
949 DisplayValue(mValue, true);
950 if(Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor())
952 Control::Impl::GetAccessibilityObject(Self())->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
956 float Slider::GetValue() const
961 void Slider::SetTrackRegion(const Vector2& region)
963 mTrackRegion = region;
967 mTrack.SetProperty(Actor::Property::SIZE, mTrackRegion);
970 ResizeProgressRegion(Vector2(0.0f, mTrackRegion.y));
972 mDomain = CalcDomain(mTrackRegion);
974 DisplayValue(GetValue(), false); // Set the progress bar to correct width
977 const Vector2& Slider::GetTrackRegion() const
982 void Slider::SetHandleSize(const Vector2& size)
986 ResizeHandleSize(mHandleSize);
988 Vector2 hitRegion = GetHitRegion();
989 hitRegion.x += mHandleSize.x;
990 SetHitRegion(hitRegion);
993 const Vector2& Slider::GetHandleSize() const
998 void Slider::SetDisabledColor(const Vector4& color)
1000 mDisabledColor = color;
1005 Vector4 Slider::GetDisabledColor() const
1007 return mDisabledColor;
1010 void Slider::SetValuePrecision(int precision)
1012 mValuePrecision = precision;
1015 int Slider::GetValuePrecision() const
1017 return mValuePrecision;
1020 void Slider::SetShowPopup(bool showPopup)
1022 mShowPopup = showPopup;
1035 bool Slider::GetShowPopup() const
1040 void Slider::SetShowValue(bool showValue)
1042 mShowValue = showValue;
1046 CreateHandleValueDisplay();
1050 DestroyHandleValueDisplay();
1054 bool Slider::GetShowValue() const
1059 void Slider::SetEnabled(bool enabled)
1073 bool Slider::IsEnabled() const
1075 return mState != DISABLED;
1078 void Slider::SetMarkTolerance(float tolerance)
1080 mMarkTolerance = tolerance;
1083 float Slider::GetMarkTolerance() const
1085 return mMarkTolerance;
1088 // Static class method to support script connecting signals
1089 bool Slider::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
1091 Dali::BaseHandle handle(object);
1093 bool connected = true;
1094 Toolkit::Slider slider = Toolkit::Slider::DownCast(handle);
1096 if(0 == strcmp(signalName.c_str(), SIGNAL_VALUE_CHANGED))
1098 slider.ValueChangedSignal().Connect(tracker, functor);
1100 else if(0 == strcmp(signalName.c_str(), SIGNAL_MARK))
1102 slider.MarkReachedSignal().Connect(tracker, functor);
1106 // signalName does not match any signal
1113 void Slider::DisplayPopup(float value)
1115 // Value displayDoConnectSignal
1118 std::stringstream ss;
1119 ss.precision(GetValuePrecision());
1120 ss << std::fixed << value;
1121 mValueTextLabel.SetProperty(Toolkit::TextLabel::Property::TEXT, ss.str());
1125 mValueDisplay.SetProperty(Actor::Property::VISIBLE, true);
1127 mValueTimer.SetInterval(VALUE_VIEW_SHOW_DURATION);
1132 void Slider::SetProperty(BaseObject* object, Property::Index propertyIndex, const Property::Value& value)
1134 Toolkit::Slider slider = Toolkit::Slider::DownCast(Dali::BaseHandle(object));
1138 Slider& sliderImpl(GetImpl(slider));
1140 switch(propertyIndex)
1142 case Toolkit::Slider::Property::LOWER_BOUND:
1144 sliderImpl.SetLowerBound(value.Get<float>());
1148 case Toolkit::Slider::Property::UPPER_BOUND:
1150 sliderImpl.SetUpperBound(value.Get<float>());
1154 case Toolkit::Slider::Property::VALUE:
1156 sliderImpl.SetValue(value.Get<float>());
1160 case Toolkit::Slider::Property::TRACK_VISUAL:
1165 sliderImpl.SetTrackVisual(map);
1170 case Toolkit::Slider::Property::HANDLE_VISUAL:
1175 sliderImpl.SetHandleVisual(map);
1180 case Toolkit::Slider::Property::PROGRESS_VISUAL:
1185 sliderImpl.SetProgressVisual(map);
1190 case Toolkit::Slider::Property::POPUP_VISUAL:
1192 std::string imageUrl;
1193 if(value.Get(imageUrl))
1195 sliderImpl.SetPopupVisual(imageUrl);
1198 // If it is not a string, then get a Property::Map from the property if possible.
1202 sliderImpl.SetPopupVisual(map);
1208 case Toolkit::Slider::Property::POPUP_ARROW_VISUAL:
1213 sliderImpl.SetPopupArrowVisual(map);
1218 case Toolkit::Slider::Property::DISABLED_COLOR:
1220 sliderImpl.SetDisabledColor(value.Get<Vector4>());
1224 case Toolkit::Slider::Property::VALUE_PRECISION:
1226 sliderImpl.SetValuePrecision(value.Get<int>());
1230 case Toolkit::Slider::Property::SHOW_POPUP:
1232 sliderImpl.SetShowPopup(value.Get<bool>());
1236 case Toolkit::Slider::Property::SHOW_VALUE:
1238 sliderImpl.SetShowValue(value.Get<bool>());
1242 case Toolkit::Slider::Property::MARKS:
1244 sliderImpl.SetMarks(value.Get<Property::Array>());
1248 case Toolkit::Slider::Property::SNAP_TO_MARKS:
1250 sliderImpl.SetSnapToMarks(value.Get<bool>());
1254 case Toolkit::Slider::Property::MARK_TOLERANCE:
1256 sliderImpl.SetMarkTolerance(value.Get<float>());
1263 Property::Value Slider::GetProperty(BaseObject* object, Property::Index propertyIndex)
1265 Property::Value value;
1267 Toolkit::Slider slider = Toolkit::Slider::DownCast(Dali::BaseHandle(object));
1271 Slider& sliderImpl(GetImpl(slider));
1273 switch(propertyIndex)
1275 case Toolkit::Slider::Property::LOWER_BOUND:
1277 value = sliderImpl.GetLowerBound();
1281 case Toolkit::Slider::Property::UPPER_BOUND:
1283 value = sliderImpl.GetUpperBound();
1287 case Toolkit::Slider::Property::VALUE:
1289 value = sliderImpl.GetValue();
1293 case Toolkit::Slider::Property::TRACK_VISUAL:
1295 if(!sliderImpl.mTrackVisual.empty())
1297 value = sliderImpl.GetTrackVisual();
1299 else if(!sliderImpl.mTrackMap.Empty())
1301 value = sliderImpl.mTrackMap;
1306 case Toolkit::Slider::Property::HANDLE_VISUAL:
1308 if(!sliderImpl.mHandleVisual.empty())
1310 value = sliderImpl.GetHandleVisual();
1312 else if(!sliderImpl.mHandleMap.Empty())
1314 value = sliderImpl.mHandleMap;
1319 case Toolkit::Slider::Property::PROGRESS_VISUAL:
1321 if(!sliderImpl.mProgressVisual.empty())
1323 value = sliderImpl.GetProgressVisual();
1325 else if(!sliderImpl.mProgressMap.Empty())
1327 value = sliderImpl.mProgressMap;
1332 case Toolkit::Slider::Property::POPUP_VISUAL:
1334 if(!sliderImpl.mPopupVisual.empty())
1336 value = sliderImpl.GetPopupVisual();
1338 else if(!sliderImpl.mPopupMap.Empty())
1340 value = sliderImpl.mPopupMap;
1345 case Toolkit::Slider::Property::POPUP_ARROW_VISUAL:
1347 if(!sliderImpl.mPopupArrowVisual.empty())
1349 value = sliderImpl.GetPopupArrowVisual();
1351 else if(!sliderImpl.mPopupArrowMap.Empty())
1353 value = sliderImpl.mPopupArrowMap;
1358 case Toolkit::Slider::Property::DISABLED_COLOR:
1360 value = sliderImpl.GetDisabledColor();
1364 case Toolkit::Slider::Property::VALUE_PRECISION:
1366 value = sliderImpl.GetValuePrecision();
1370 case Toolkit::Slider::Property::SHOW_POPUP:
1372 value = sliderImpl.GetShowPopup();
1376 case Toolkit::Slider::Property::SHOW_VALUE:
1378 value = sliderImpl.GetShowValue();
1382 case Toolkit::Slider::Property::MARKS:
1384 Property::Value value1(Property::ARRAY);
1385 Property::Array* markArray = value1.GetArray();
1389 *markArray = sliderImpl.GetMarks();
1396 case Toolkit::Slider::Property::SNAP_TO_MARKS:
1398 value = sliderImpl.GetSnapToMarks();
1402 case Toolkit::Slider::Property::MARK_TOLERANCE:
1404 value = sliderImpl.GetMarkTolerance();
1413 double Slider::AccessibleImpl::GetMinimum()
1415 auto p = Toolkit::Slider::DownCast(self);
1416 return p.GetProperty(Toolkit::Slider::Property::LOWER_BOUND).Get<float>();
1419 double Slider::AccessibleImpl::GetCurrent()
1421 auto p = Toolkit::Slider::DownCast(self);
1422 return p.GetProperty(Toolkit::Slider::Property::VALUE).Get<float>();
1425 double Slider::AccessibleImpl::GetMaximum()
1427 auto p = Toolkit::Slider::DownCast(self);
1428 return p.GetProperty(Toolkit::Slider::Property::UPPER_BOUND).Get<float>();
1431 bool Slider::AccessibleImpl::SetCurrent(double current)
1433 if(current < GetMinimum() || current > GetMaximum())
1436 auto p = Toolkit::Slider::DownCast(self);
1437 auto& impl = Toolkit::GetImpl(p);
1439 const float prev = p.GetProperty<float>(Toolkit::Slider::Property::VALUE);
1440 float next = static_cast<float>(current);
1442 if(fabsf(next - prev) < Math::MACHINE_EPSILON_0)
1446 else if(p.GetProperty<bool>(Toolkit::Slider::Property::SNAP_TO_MARKS))
1448 auto marks = p.GetProperty<Property::Array>(Toolkit::Slider::Property::MARKS);
1451 if(impl.MarkReached(impl.MapValuePercentage(prev), prevIdx))
1453 int nextIdx = prevIdx;
1454 nextIdx += (next > prev) ? 1 : -1;
1456 if(nextIdx < 0 || nextIdx >= static_cast<int>(marks.Count()))
1459 next = marks[nextIdx].Get<float>();
1463 next = impl.MapBounds(impl.SnapToMark(impl.MapValuePercentage(next)), impl.GetLowerBound(), impl.GetUpperBound());
1468 next = impl.MapBounds(impl.MarkFilter(impl.MapValuePercentage(next)), impl.GetLowerBound(), impl.GetUpperBound());
1471 impl.SetValue(next);
1472 impl.DisplayPopup(next);
1477 double Slider::AccessibleImpl::GetMinimumIncrement()
1479 auto p = Toolkit::Slider::DownCast(self);
1481 bool hasMarks = !p.GetProperty<Property::Array>(Toolkit::Slider::Property::MARKS).Empty();
1482 float tolerance = p.GetProperty<float>(Toolkit::Slider::Property::MARK_TOLERANCE);
1484 if(!hasMarks || fabsf(tolerance) < 0.01)
1485 return 0.0; // let screen-reader choose the increment
1487 return Math::MACHINE_EPSILON_10000 + tolerance * (GetMaximum() - GetMinimum());
1490 } // namespace Internal
1492 } // namespace Toolkit