2 * Copyright (c) 2020 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 <cstring> // for strcmp
25 #include <dali/public-api/events/touch-event.h>
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/public-api/object/type-registry-helper.h>
30 #include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
31 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
32 #include <dali-toolkit/public-api/controls/control-impl.h>
33 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
46 namespace // Unnamed namespace
51 return Dali::Toolkit::Slider::New();
54 // Setup properties, signals and actions using the type-registry.
55 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Slider, Toolkit::Control, Create )
57 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "lowerBound", FLOAT, LOWER_BOUND )
58 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "upperBound", FLOAT, UPPER_BOUND )
59 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "value", FLOAT, VALUE )
60 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "trackVisual", MAP, TRACK_VISUAL )
61 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "handleVisual", MAP, HANDLE_VISUAL )
62 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "progressVisual", MAP, PROGRESS_VISUAL )
63 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "popupVisual", MAP, POPUP_VISUAL )
64 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "popupArrowVisual", MAP, POPUP_ARROW_VISUAL )
65 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "disabledColor", VECTOR4, DISABLED_COLOR )
66 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "valuePrecision", INTEGER, VALUE_PRECISION )
67 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "showPopup", BOOLEAN, SHOW_POPUP )
68 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "showValue", BOOLEAN, SHOW_VALUE )
69 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "marks", ARRAY, MARKS )
70 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "snapToMarks", BOOLEAN, SNAP_TO_MARKS )
71 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "markTolerance", FLOAT, MARK_TOLERANCE )
73 DALI_SIGNAL_REGISTRATION( Toolkit, Slider, "valueChanged", SIGNAL_VALUE_CHANGED )
74 DALI_SIGNAL_REGISTRATION( Toolkit, Slider, "mark", SIGNAL_MARK )
76 DALI_TYPE_REGISTRATION_END()
78 const float MARK_SNAP_TOLERANCE = 0.05f; // 5% of slider width
80 const int VALUE_VIEW_SHOW_DURATION = 1000; // millisec
81 const int VALUE_VIEW_SHOW_DURATION_LONG = 2000; // millisec
83 const float VALUE_VERTICAL_OFFSET = 48.0f;
85 const float DEFAULT_WIDTH = 0.0f;
86 const float DEFAULT_HEIGHT = 27.0f;
87 const float DEFAULT_HIT_HEIGHT = 72.0f;
88 const float DEFAULT_HANDLE_HEIGHT = DEFAULT_HIT_HEIGHT;
89 const float POPUP_TEXT_PADDING = 10.0f;
91 const char* SKINNED_TRACK_VISUAL_FILE_NAME = "slider-skin.9.png";
92 const char* SKINNED_HANDLE_VISUAL_FILE_NAME = "slider-skin-handle.png";
93 const char* SKINNED_PROGRESS_VISUAL_FILE_NAME = "slider-skin-progress.9.png";
94 const char* SKINNED_POPUP_VISUAL_FILE_NAME = "slider-popup.9.png";
95 const char* SKINNED_POPUP_ARROW_VISUAL_FILE_NAME = "slider-popup-arrow.png";
97 const Vector2 DEFAULT_HIT_REGION( DEFAULT_WIDTH, DEFAULT_HIT_HEIGHT );
98 const Vector2 DEFAULT_TRACK_REGION( DEFAULT_WIDTH, DEFAULT_HEIGHT );
99 const Vector2 DEFAULT_HANDLE_SIZE( DEFAULT_HANDLE_HEIGHT, DEFAULT_HANDLE_HEIGHT );
101 const Vector4 DEFAULT_DISABLED_COLOR( 0.5f, 0.5f, 0.5f, 1.0f );
103 const float VALUE_POPUP_MARGIN = 10.0f;
104 const float VALUE_POPUP_HEIGHT = 81.0f;
105 const float VALUE_POPUP_MIN_WIDTH = 54.0f;
107 const float DEFAULT_LOWER_BOUND = 0.0f;
108 const float DEFAULT_UPPER_BOUND = 1.0f;
109 const float DEFAULT_VALUE = 0.0f;
110 const int DEFAULT_VALUE_PRECISION = 0;
111 const bool DEFAULT_SHOW_POPUP = false;
112 const bool DEFAULT_SHOW_VALUE = true;
113 const bool DEFAULT_ENABLED = true;
114 const bool DEFAULT_SNAP_TO_MARKS = false;
116 } // Unnamed namespace
118 ///////////////////////////////////////////////////////////////////////////////////////////////////
120 ///////////////////////////////////////////////////////////////////////////////////////////////////
122 Dali::Toolkit::Slider Slider::New()
124 // Create the implementation
125 SliderPtr slider( new Slider() );
127 // Pass ownership to CustomActor via derived handle
128 Dali::Toolkit::Slider handle( *slider );
130 // Second-phase init of the implementation
131 // This can only be done after the CustomActor connection has been made...
132 slider->Initialize();
138 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
141 mPopupArrowVisual(""),
149 mDisabledColor( 0.0f, 0.0f, 0.0f, 0.0f ),
150 mHitRegion( 0.0f, 0.0f ),
151 mTrackRegion( 0.0f, 0.0f ),
152 mHandleSize( 0.0f, 0.0f ),
156 mMarkTolerance( 0.0f ),
157 mValuePrecision( 0 ),
160 mSnapToMarks( false )
168 void Slider::OnInitialize()
176 SetHitRegion( DEFAULT_HIT_REGION );
177 SetTrackRegion( DEFAULT_TRACK_REGION );
178 SetHandleSize( DEFAULT_HANDLE_SIZE );
180 const std::string imageDirPath = AssetManager::GetDaliImagePath();
181 SetTrackVisual( imageDirPath + SKINNED_TRACK_VISUAL_FILE_NAME );
182 SetHandleVisual( imageDirPath + SKINNED_HANDLE_VISUAL_FILE_NAME );
183 SetProgressVisual( imageDirPath + SKINNED_PROGRESS_VISUAL_FILE_NAME );
184 SetPopupVisual( imageDirPath + SKINNED_POPUP_VISUAL_FILE_NAME );
185 SetPopupArrowVisual( imageDirPath + SKINNED_POPUP_ARROW_VISUAL_FILE_NAME );
187 SetShowPopup( DEFAULT_SHOW_POPUP );
188 SetShowValue( DEFAULT_SHOW_VALUE );
190 SetEnabled( DEFAULT_ENABLED );
191 SetDisabledColor( DEFAULT_DISABLED_COLOR );
193 SetSnapToMarks( DEFAULT_SNAP_TO_MARKS );
194 SetMarkTolerance( MARK_SNAP_TOLERANCE );
196 SetLowerBound( DEFAULT_LOWER_BOUND );
197 SetUpperBound( DEFAULT_UPPER_BOUND );
199 SetValuePrecision( DEFAULT_VALUE_PRECISION );
200 mValue = DEFAULT_VALUE;
201 DisplayValue( mValue, false ); // Run this last to display the correct value
203 // Size the Slider actor to a default
204 self.SetProperty( Actor::Property::SIZE, Vector2( DEFAULT_HIT_REGION.x, DEFAULT_HIT_REGION.y ) );
206 // Set the Slider to be highlightable in Screen Reader mode
207 self.SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true );
209 // Connect to the touch signal
210 self.TouchedSignal().Connect( this, &Slider::OnTouch );
212 DevelControl::SetAccessibilityConstructor( self, []( Dali::Actor actor ) {
213 return std::unique_ptr< Dali::Accessibility::Accessible >(
214 new AccessibleImpl( actor, Dali::Accessibility::Role::SLIDER ) );
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() );
239 DisplayPopup( value );
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() );
267 DisplayPopup( value );
271 case GestureState::FINISHED:
273 if( mState == PRESSED )
275 if( GetSnapToMarks() )
277 float value = MapBounds( SnapToMark( MapPercentage( gesture.GetPosition() ) ), GetLowerBound(), GetUpperBound() );
279 DisplayPopup( value );
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 );
781 self.Add( mHitArea );
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 );
846 float Slider::MarkFilter( float value )
848 const float MARK_TOLERANCE = GetMarkTolerance();
851 for( MarkList::SizeType i = 0; i < mMarks.Count(); ++i)
853 const Property::Value& propertyValue = mMarks[i];
854 propertyValue.Get( mark );
855 mark = MapValuePercentage( mark );
857 // If close to a mark, return the mark
858 if( fabsf( mark - value ) < MARK_TOLERANCE )
867 float Slider::SnapToMark( float value )
869 float closestMark = value;
870 float closestDist = std::numeric_limits<float>::max();
873 for( MarkList::SizeType i = 0; i < mMarks.Count(); ++i)
875 const Property::Value& propertyValue = mMarks[i];
876 propertyValue.Get( mark );
877 mark = MapValuePercentage( mark );
879 float dist = fabsf( mark - value );
880 if( dist < closestDist )
890 bool Slider::MarkReached( float value, int& outIndex )
892 const float MARK_TOLERANCE = GetMarkTolerance();
896 tail = mMarks.Size() - 1;
900 while( head <= tail )
902 current = head + ( tail - head ) / 2;
904 const Property::Value& propertyValue = mMarks[ current ];
905 propertyValue.Get( mark );
906 mark = MapValuePercentage( mark );
908 if( fabsf( mark - value ) < MARK_TOLERANCE )
927 bool Slider::HideValueView()
931 mValueDisplay.SetProperty( Actor::Property::VISIBLE, false );
937 void Slider::SetLowerBound( float bound )
940 DisplayValue( GetValue(), false );
943 float Slider::GetLowerBound() const
948 void Slider::SetUpperBound( float bound )
951 DisplayValue( GetValue(), false );
954 float Slider::GetUpperBound() const
959 void Slider::SetValue( float value )
962 DisplayValue( mValue, true );
963 if (Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor())
965 Control::Impl::GetAccessibilityObject(Self())->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE);
969 float Slider::GetValue() const
974 void Slider::SetTrackRegion( const Vector2& region )
976 mTrackRegion = region;
980 mTrack.SetProperty( Actor::Property::SIZE, mTrackRegion );
983 ResizeProgressRegion( Vector2( 0.0f, mTrackRegion.y ) );
985 mDomain = CalcDomain( mTrackRegion );
987 DisplayValue( GetValue(), false ); // Set the progress bar to correct width
990 const Vector2& Slider::GetTrackRegion() const
995 void Slider::SetHandleSize( const Vector2& size )
999 ResizeHandleSize( mHandleSize );
1001 Vector2 hitRegion = GetHitRegion();
1002 hitRegion.x += mHandleSize.x;
1003 SetHitRegion( hitRegion );
1006 const Vector2& Slider::GetHandleSize() const
1011 void Slider::SetDisabledColor( const Vector4& color )
1013 mDisabledColor = color;
1018 Vector4 Slider::GetDisabledColor() const
1020 return mDisabledColor;
1023 void Slider::SetValuePrecision( int precision )
1025 mValuePrecision = precision;
1028 int Slider::GetValuePrecision() const
1030 return mValuePrecision;
1033 void Slider::SetShowPopup( bool showPopup )
1035 mShowPopup = showPopup;
1048 bool Slider::GetShowPopup() const
1053 void Slider::SetShowValue( bool showValue )
1055 mShowValue = showValue;
1059 CreateHandleValueDisplay();
1063 DestroyHandleValueDisplay();
1067 bool Slider::GetShowValue() const
1072 void Slider::SetEnabled( bool enabled )
1086 bool Slider::IsEnabled() const
1088 return mState != DISABLED;
1091 void Slider::SetMarkTolerance( float tolerance )
1093 mMarkTolerance = tolerance;
1096 float Slider::GetMarkTolerance() const
1098 return mMarkTolerance;
1101 // Static class method to support script connecting signals
1102 bool Slider::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
1104 Dali::BaseHandle handle( object );
1106 bool connected = true;
1107 Toolkit::Slider slider = Toolkit::Slider::DownCast( handle );
1109 if( 0 == strcmp( signalName.c_str(), SIGNAL_VALUE_CHANGED ) )
1111 slider.ValueChangedSignal().Connect( tracker, functor );
1113 else if( 0 == strcmp( signalName.c_str(), SIGNAL_MARK ) )
1115 slider.MarkReachedSignal().Connect( tracker, functor );
1119 // signalName does not match any signal
1126 void Slider::DisplayPopup( float value )
1128 // Value displayDoConnectSignal
1129 if( mValueTextLabel )
1131 std::stringstream ss;
1132 ss.precision( GetValuePrecision() );
1133 ss << std::fixed << value;
1134 mValueTextLabel.SetProperty( Toolkit::TextLabel::Property::TEXT, ss.str() );
1138 mValueDisplay.SetProperty( Actor::Property::VISIBLE, true );
1140 mValueTimer.SetInterval( VALUE_VIEW_SHOW_DURATION );
1145 void Slider::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
1147 Toolkit::Slider slider = Toolkit::Slider::DownCast( Dali::BaseHandle( object ) );
1151 Slider& sliderImpl( GetImpl( slider ) );
1153 switch ( propertyIndex )
1155 case Toolkit::Slider::Property::LOWER_BOUND:
1157 sliderImpl.SetLowerBound( value.Get< float >() );
1161 case Toolkit::Slider::Property::UPPER_BOUND:
1163 sliderImpl.SetUpperBound( value.Get< float >() );
1167 case Toolkit::Slider::Property::VALUE:
1169 sliderImpl.SetValue( value.Get< float >() );
1173 case Toolkit::Slider::Property::TRACK_VISUAL:
1176 if( value.Get( map ) )
1178 sliderImpl.SetTrackVisual( map );
1183 case Toolkit::Slider::Property::HANDLE_VISUAL:
1186 if( value.Get( map ) )
1188 sliderImpl.SetHandleVisual( map );
1193 case Toolkit::Slider::Property::PROGRESS_VISUAL:
1196 if( value.Get( map ) )
1198 sliderImpl.SetProgressVisual( map );
1203 case Toolkit::Slider::Property::POPUP_VISUAL:
1205 std::string imageUrl;
1206 if( value.Get( imageUrl ) )
1208 sliderImpl.SetPopupVisual( imageUrl );
1211 // If it is not a string, then get a Property::Map from the property if possible.
1213 if( value.Get( map ) )
1215 sliderImpl.SetPopupVisual( map );
1221 case Toolkit::Slider::Property::POPUP_ARROW_VISUAL:
1224 if( value.Get( map ) )
1226 sliderImpl.SetPopupArrowVisual( map );
1231 case Toolkit::Slider::Property::DISABLED_COLOR:
1233 sliderImpl.SetDisabledColor( value.Get< Vector4 >() );
1237 case Toolkit::Slider::Property::VALUE_PRECISION:
1239 sliderImpl.SetValuePrecision( value.Get< int >() );
1243 case Toolkit::Slider::Property::SHOW_POPUP:
1245 sliderImpl.SetShowPopup( value.Get< bool >() );
1249 case Toolkit::Slider::Property::SHOW_VALUE:
1251 sliderImpl.SetShowValue( value.Get< bool >() );
1255 case Toolkit::Slider::Property::MARKS:
1257 sliderImpl.SetMarks( value.Get< Property::Array >() );
1261 case Toolkit::Slider::Property::SNAP_TO_MARKS:
1263 sliderImpl.SetSnapToMarks( value.Get< bool >() );
1267 case Toolkit::Slider::Property::MARK_TOLERANCE:
1269 sliderImpl.SetMarkTolerance( value.Get< float >() );
1276 Property::Value Slider::GetProperty( BaseObject* object, Property::Index propertyIndex )
1278 Property::Value value;
1280 Toolkit::Slider slider = Toolkit::Slider::DownCast( Dali::BaseHandle( object ) );
1284 Slider& sliderImpl( GetImpl( slider ) );
1286 switch ( propertyIndex )
1288 case Toolkit::Slider::Property::LOWER_BOUND:
1290 value = sliderImpl.GetLowerBound();
1294 case Toolkit::Slider::Property::UPPER_BOUND:
1296 value = sliderImpl.GetUpperBound();
1300 case Toolkit::Slider::Property::VALUE:
1302 value = sliderImpl.GetValue();
1306 case Toolkit::Slider::Property::TRACK_VISUAL:
1308 if( !sliderImpl.mTrackVisual.empty() )
1310 value = sliderImpl.GetTrackVisual();
1312 else if( !sliderImpl.mTrackMap.Empty() )
1314 value = sliderImpl.mTrackMap;
1319 case Toolkit::Slider::Property::HANDLE_VISUAL:
1321 if( !sliderImpl.mHandleVisual.empty() )
1323 value = sliderImpl.GetHandleVisual();
1325 else if( !sliderImpl.mHandleMap.Empty() )
1327 value = sliderImpl.mHandleMap;
1332 case Toolkit::Slider::Property::PROGRESS_VISUAL:
1334 if( !sliderImpl.mProgressVisual.empty() )
1336 value = sliderImpl.GetProgressVisual();
1338 else if( !sliderImpl.mProgressMap.Empty() )
1340 value = sliderImpl.mProgressMap;
1345 case Toolkit::Slider::Property::POPUP_VISUAL:
1347 if( !sliderImpl.mPopupVisual.empty() )
1349 value = sliderImpl.GetPopupVisual();
1351 else if( !sliderImpl.mPopupMap.Empty() )
1353 value = sliderImpl.mPopupMap;
1358 case Toolkit::Slider::Property::POPUP_ARROW_VISUAL:
1360 if( !sliderImpl.mPopupArrowVisual.empty() )
1362 value = sliderImpl.GetPopupArrowVisual();
1364 else if( !sliderImpl.mPopupArrowMap.Empty() )
1366 value = sliderImpl.mPopupArrowMap;
1371 case Toolkit::Slider::Property::DISABLED_COLOR:
1373 value = sliderImpl.GetDisabledColor();
1377 case Toolkit::Slider::Property::VALUE_PRECISION:
1379 value = sliderImpl.GetValuePrecision();
1383 case Toolkit::Slider::Property::SHOW_POPUP:
1385 value = sliderImpl.GetShowPopup();
1389 case Toolkit::Slider::Property::SHOW_VALUE:
1391 value = sliderImpl.GetShowValue();
1395 case Toolkit::Slider::Property::MARKS:
1397 Property::Value value1( Property::ARRAY );
1398 Property::Array* markArray = value1.GetArray();
1402 *markArray = sliderImpl.GetMarks();
1409 case Toolkit::Slider::Property::SNAP_TO_MARKS:
1411 value = sliderImpl.GetSnapToMarks();
1415 case Toolkit::Slider::Property::MARK_TOLERANCE:
1417 value = sliderImpl.GetMarkTolerance();
1426 double Slider::AccessibleImpl::GetMinimum()
1428 auto p = Toolkit::Slider::DownCast( self );
1429 return p.GetProperty( Toolkit::Slider::Property::LOWER_BOUND ).Get< float >();
1432 double Slider::AccessibleImpl::GetCurrent()
1434 auto p = Toolkit::Slider::DownCast( self );
1435 return p.GetProperty( Toolkit::Slider::Property::VALUE ).Get< float >();
1438 double Slider::AccessibleImpl::GetMaximum()
1440 auto p = Toolkit::Slider::DownCast( self );
1441 return p.GetProperty( Toolkit::Slider::Property::UPPER_BOUND ).Get< float >();
1444 bool Slider::AccessibleImpl::SetCurrent( double current )
1446 if (current < GetMinimum() || current > GetMaximum())
1449 auto p = Toolkit::Slider::DownCast( self );
1450 auto &impl = Toolkit::GetImpl(p);
1452 const float prev = p.GetProperty<float>(Toolkit::Slider::Property::VALUE);
1453 float next = static_cast<float>(current);
1455 if (fabsf(next - prev) < Math::MACHINE_EPSILON_0)
1459 else if (p.GetProperty<bool>(Toolkit::Slider::Property::SNAP_TO_MARKS))
1461 auto marks = p.GetProperty<Property::Array>(Toolkit::Slider::Property::MARKS);
1464 if (impl.MarkReached(impl.MapValuePercentage(prev), prevIdx))
1466 int nextIdx = prevIdx;
1467 nextIdx += (next > prev) ? 1 : -1;
1469 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::AccessibleImpl::GetMinimumIncrement()
1492 auto p = Toolkit::Slider::DownCast( self );
1494 bool hasMarks = !p.GetProperty<Property::Array>(Toolkit::Slider::Property::MARKS).Empty();
1495 float tolerance = p.GetProperty<float>(Toolkit::Slider::Property::MARK_TOLERANCE);
1497 if (!hasMarks || fabsf(tolerance) < 0.01)
1498 return 0.0; // let screen-reader choose the increment
1500 return Math::MACHINE_EPSILON_10000 + tolerance * (GetMaximum() - GetMinimum());
1503 } // namespace Internal
1505 } // namespace Toolkit