[AT-SPI] Fix role setting
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / slider / slider-impl.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/slider/slider-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstring> // for strcmp
23 #include <sstream>
24 #include <limits>
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>
28
29 // INTERNAL INCLUDES
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>
34
35 using namespace Dali;
36
37 namespace Dali
38 {
39
40 namespace Toolkit
41 {
42
43 namespace Internal
44 {
45
46 namespace // Unnamed namespace
47 {
48
49 BaseHandle Create()
50 {
51   return Dali::Toolkit::Slider::New();
52 }
53
54 // Setup properties, signals and actions using the type-registry.
55 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Slider, Toolkit::Control, Create )
56
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         )
72
73 DALI_SIGNAL_REGISTRATION(   Toolkit, Slider, "valueChanged",                     SIGNAL_VALUE_CHANGED   )
74 DALI_SIGNAL_REGISTRATION(   Toolkit, Slider, "mark",                             SIGNAL_MARK            )
75
76 DALI_TYPE_REGISTRATION_END()
77
78 const float MARK_SNAP_TOLERANCE = 0.05f; // 5% of slider width
79
80 const int VALUE_VIEW_SHOW_DURATION = 1000;  // millisec
81 const int VALUE_VIEW_SHOW_DURATION_LONG = 2000;  // millisec
82
83 const float VALUE_VERTICAL_OFFSET = 48.0f;
84
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;
90
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";
96
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 );
100
101 const Vector4 DEFAULT_DISABLED_COLOR( 0.5f, 0.5f, 0.5f, 1.0f );
102
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;
106
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;
115
116 } // Unnamed namespace
117
118 ///////////////////////////////////////////////////////////////////////////////////////////////////
119 // Slider
120 ///////////////////////////////////////////////////////////////////////////////////////////////////
121
122 Dali::Toolkit::Slider Slider::New()
123 {
124   // Create the implementation
125   SliderPtr slider( new Slider() );
126
127   // Pass ownership to CustomActor via derived handle
128   Dali::Toolkit::Slider handle( *slider );
129
130   // Second-phase init of the implementation
131   // This can only be done after the CustomActor connection has been made...
132   slider->Initialize();
133
134   return handle;
135 }
136
137 Slider::Slider()
138 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
139   mState( NORMAL ),
140   mPopupVisual(""),
141   mPopupArrowVisual(""),
142   mTrackVisual(""),
143   mHandleVisual(""),
144   mProgressVisual(""),
145   mPopupMap(),
146   mTrackMap(),
147   mHandleMap(),
148   mPopupArrowMap(),
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 ),
153   mLowerBound( 0.0f ),
154   mUpperBound( 0.0f ),
155   mValue( 0.0f ),
156   mMarkTolerance( 0.0f ),
157   mValuePrecision( 0 ),
158   mShowPopup( false ),
159   mShowValue( false ),
160   mSnapToMarks( false )
161 {
162 }
163
164 Slider::~Slider()
165 {
166 }
167
168 void Slider::OnInitialize()
169 {
170   // Setup
171   CreateChildren();
172
173   // Properties
174   Actor self = Self();
175
176   SetHitRegion(     DEFAULT_HIT_REGION     );
177   SetTrackRegion(   DEFAULT_TRACK_REGION   );
178   SetHandleSize(    DEFAULT_HANDLE_SIZE    );
179
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       );
186
187   SetShowPopup( DEFAULT_SHOW_POPUP );
188   SetShowValue( DEFAULT_SHOW_VALUE );
189
190   SetEnabled( DEFAULT_ENABLED );
191   SetDisabledColor( DEFAULT_DISABLED_COLOR );
192
193   SetSnapToMarks( DEFAULT_SNAP_TO_MARKS );
194   SetMarkTolerance( MARK_SNAP_TOLERANCE );
195
196   SetLowerBound( DEFAULT_LOWER_BOUND );
197   SetUpperBound( DEFAULT_UPPER_BOUND );
198   UpdateSkin();
199   SetValuePrecision( DEFAULT_VALUE_PRECISION );
200   mValue = DEFAULT_VALUE;
201   DisplayValue( mValue, false );       // Run this last to display the correct value
202
203   // Size the Slider actor to a default
204   self.SetProperty( Actor::Property::SIZE, Vector2( DEFAULT_HIT_REGION.x, DEFAULT_HIT_REGION.y ) );
205
206   // Connect to the touch signal
207   self.TouchedSignal().Connect( this, &Slider::OnTouch );
208
209   DevelControl::SetAccessibilityConstructor( self, []( Dali::Actor actor ) {
210     return std::unique_ptr< Dali::Accessibility::Accessible >(
211       new AccessibleImpl( actor, Dali::Accessibility::Role::SLIDER ) );
212   } );
213 }
214
215 void Slider::OnRelayout( const Vector2& size, RelayoutContainer& container )
216 {
217   SetHitRegion( Vector2( size.x, GetHitRegion().y ) );
218   // Factor in handle overshoot into size of backing
219   SetTrackRegion( Vector2( size.x - GetHandleSize().x, GetTrackRegion().y ) );
220   Control::OnRelayout( size, container );
221 }
222
223 bool Slider::OnTouch(Actor actor, const TouchEvent& touch)
224 {
225   if( mState != DISABLED )
226   {
227     const PointState::Type touchState = touch.GetState(0);
228
229     if( touchState == PointState::DOWN )
230     {
231       mState = PRESSED;
232
233       float percentage = MapPercentage( touch.GetLocalPosition( 0 ) );
234       float value = MapBounds( ( GetSnapToMarks() ) ? SnapToMark( percentage ) : MarkFilter( percentage ), GetLowerBound(), GetUpperBound() );
235       SetValue( value );
236       DisplayPopup( value );
237     }
238     else if( touchState == PointState::UP )
239     {
240       if( mState == PRESSED )
241       {
242         mState = NORMAL;
243         mSlidingFinishedSignal.Emit( Toolkit::Slider::DownCast( Self() ), GetValue() );
244       }
245     }
246   }
247
248   return false;
249 }
250
251 void Slider::OnPan( Actor actor, const PanGesture& gesture )
252 {
253   // gesture.position is in local actor coordinates
254   if( mState != DISABLED )
255   {
256     switch( gesture.GetState() )
257     {
258       case GestureState::CONTINUING:
259       {
260         if( mState == PRESSED )
261         {
262           float value = MapBounds( MarkFilter ( MapPercentage( gesture.GetPosition() ) ), GetLowerBound(), GetUpperBound() );
263           SetValue( value );
264           DisplayPopup( value );
265         }
266         break;
267       }
268       case GestureState::FINISHED:
269       {
270         if( mState == PRESSED  )
271         {
272           if( GetSnapToMarks() )
273           {
274             float value = MapBounds( SnapToMark( MapPercentage( gesture.GetPosition() ) ), GetLowerBound(), GetUpperBound() );
275             SetValue( value );
276             DisplayPopup( value );
277           }
278           mSlidingFinishedSignal.Emit( Toolkit::Slider::DownCast( Self() ), GetValue() );
279         }
280
281         mState = NORMAL;
282         break;
283       }
284       default:
285       {
286         break;
287       }
288     }
289   }
290 }
291
292 float Slider::HitSpaceToDomain( float x )
293 {
294   float halfRegionWidth = GetHitRegion().x * 0.5f;
295   float halfDomainWidth = ( mDomain.to.x - mDomain.from.x ) * 0.5f;
296   float endDiff = halfRegionWidth - halfDomainWidth;
297
298   return x - endDiff;
299 }
300
301 float Slider::MapPercentage( const Vector2& point )
302 {
303   return Clamp( ( HitSpaceToDomain( point.x ) - mDomain.from.x ) / ( mDomain.to.x - mDomain.from.x ), 0.0f, 1.0f );
304 }
305
306 float Slider::MapValuePercentage( float value )
307 {
308   return ( value - GetLowerBound() ) / ( GetUpperBound() - GetLowerBound() );
309 }
310
311 float Slider::MapBounds( float percent, float lowerBound, float upperBound )
312 {
313   return lowerBound + percent * ( upperBound - lowerBound );
314 }
315
316 Slider::Domain Slider::CalcDomain( const Vector2& currentSize )
317 {
318    return Domain( Vector2( 0.0f, 0.0f ), currentSize );
319 }
320
321 void Slider::DisplayValue( float value, bool raiseSignals )
322 {
323   float clampedValue = Clamp( value, GetLowerBound(), GetUpperBound() );
324
325   float percent = MapValuePercentage( clampedValue );
326
327   float x = mDomain.from.x + percent * ( mDomain.to.x - mDomain.from.x );
328
329   mHandle.SetProperty( Actor::Property::POSITION_X,  x );
330
331   // Progress bar
332   if( mProgress )
333   {
334     mProgress.SetProperty( Actor::Property::SIZE, Vector2( x, GetTrackRegion().y ) );
335   }
336
337   // Signals
338   if( raiseSignals )
339   {
340     Toolkit::Slider self = Toolkit::Slider::DownCast( Self() );
341     mValueChangedSignal.Emit( self, clampedValue );
342
343     int markIndex;
344     if( MarkReached( percent, markIndex ) )
345     {
346       mMarkReachedSignal.Emit( self, markIndex );
347     }
348   }
349
350   if( mHandleValueTextLabel )
351   {
352     std::stringstream ss;
353     ss.precision( GetValuePrecision() );
354     ss << std::fixed << clampedValue;
355
356     std::string label = mHandleValueTextLabel.GetProperty<std::string>( Toolkit::TextLabel::Property::TEXT );
357     if( label.compare(ss.str()) )
358     {
359       mHandleValueTextLabel.SetProperty( Toolkit::TextLabel::Property::TEXT, ss.str() );
360     }
361   }
362 }
363
364 void Slider::SetMarks( const MarkList& marks )
365 {
366   mMarks = marks;
367 }
368
369 const Slider::MarkList& Slider::GetMarks() const
370 {
371   return mMarks;
372 }
373
374 void Slider::SetSnapToMarks( bool snap )
375 {
376   mSnapToMarks = snap;
377 }
378
379 bool Slider::GetSnapToMarks() const
380 {
381   return mSnapToMarks;
382 }
383
384 Actor Slider::CreateHitRegion()
385 {
386   Actor hitRegion = Actor::New();
387   hitRegion.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
388   hitRegion.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
389   hitRegion.TouchedSignal().Connect( this, &Slider::OnTouch );
390
391   return hitRegion;
392 }
393
394 Toolkit::ImageView Slider::CreateTrack()
395 {
396   Toolkit::ImageView track = Toolkit::ImageView::New();
397   track.SetProperty( Dali::Actor::Property::NAME,"SliderTrack");
398   track.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
399   track.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
400   return track;
401 }
402
403 void Slider::SetTrackVisual( const std::string& filename )
404 {
405   if( mHandle && ( filename.size() > 0 ) )
406   {
407     mTrack.SetImage( filename );
408     mTrackVisual = filename;
409   }
410 }
411
412 void Slider::SetTrackVisual( Property::Map map )
413 {
414   Property::Value* imageValue = map.Find( "url" );
415   if( imageValue )
416   {
417     mTrackVisual.clear();
418     std::string filename;
419     if( imageValue->Get( filename ) )
420     {
421       if( mTrack && ( filename.size() > 0 ) )
422       {
423         mTrack.SetImage( filename );
424         mTrackMap = map;
425       }
426     }
427   }
428
429   Property::Value* sizeValue = map.Find( "size" );
430   if( sizeValue )
431   {
432     Vector2 size;
433     if( sizeValue->Get( size ) )
434     {
435       mTrackRegion = size;
436       if( mTrack )
437       {
438         mTrack.SetProperty( Actor::Property::SIZE, mTrackRegion );
439       }
440
441     ResizeProgressRegion( Vector2( 0.0f, mTrackRegion.y ) );
442
443     mDomain = CalcDomain( mTrackRegion );
444
445     // Set the progress bar to correct width
446     DisplayValue( GetValue(), false );
447     }
448   }
449 }
450
451 std::string Slider::GetTrackVisual()
452 {
453   return mTrackVisual;
454 }
455
456 Toolkit::ImageView Slider::CreateProgress()
457 {
458   Toolkit::ImageView progress = Toolkit::ImageView::New();
459   progress.SetProperty( Dali::Actor::Property::NAME,"SliderProgress");
460   progress.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER_LEFT );
461   progress.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER_LEFT );
462
463   return progress;
464 }
465
466 void Slider::SetProgressVisual( const std::string& filename )
467 {
468   if( mProgress && ( filename.size() > 0 ) )
469   {
470     mProgress.SetImage( filename );
471     mProgressVisual = filename;
472   }
473 }
474
475 void Slider::SetProgressVisual( Property::Map map )
476 {
477   Property::Value* imageValue = map.Find( "url" );
478   if( imageValue )
479   {
480     mProgressVisual.clear();
481     std::string filename;
482     if( imageValue->Get( filename ) )
483     {
484       if( mProgress && ( filename.size() > 0 ) )
485       {
486         mProgress.SetImage( filename );
487         mProgressMap = map;
488       }
489     }
490   }
491 }
492
493 std::string Slider::GetProgressVisual()
494 {
495   return mProgressVisual;
496 }
497
498 void Slider::SetPopupVisual( const std::string& filename )
499 {
500   mPopupVisual = filename;
501 }
502
503 void Slider::SetPopupVisual( Property::Map map )
504 {
505   Property::Value* imageValue = map.Find( "url" );
506   if( imageValue )
507   {
508     mPopupVisual.clear();
509     std::string filename;
510     if( imageValue->Get( filename ) )
511     {
512       if( mPopup && ( filename.size() > 0 ) )
513       {
514         mPopup.SetImage( filename );
515         mPopupMap = map;
516       }
517     }
518   }
519 }
520
521 std::string Slider::GetPopupVisual()
522 {
523   return mPopupVisual;
524 }
525
526 void Slider::CreatePopupImage( const std::string& filename )
527 {
528   if( mPopup && ( filename.size() > 0 ) )
529   {
530     Property::Map map;
531     map[Toolkit::ImageVisual::Property::URL] = filename;
532     mPopup.SetProperty( Toolkit::ImageView::Property::IMAGE, map );
533   }
534 }
535
536 void Slider::SetPopupArrowVisual( const std::string& filename )
537 {
538   mPopupArrowVisual = filename;
539 }
540
541 void Slider::SetPopupArrowVisual( Property::Map map )
542 {
543   Property::Value* imageValue = map.Find( "url" );
544   if( imageValue )
545   {
546     mPopupArrowVisual.clear();
547     std::string filename;
548     if( imageValue->Get( filename ) )
549     {
550       if( mPopupArrow && ( filename.size() > 0 ) )
551       {
552         mPopupArrow.SetImage( filename );
553         mPopupArrowMap = map;
554       }
555     }
556   }
557 }
558
559 std::string Slider::GetPopupArrowVisual()
560 {
561   return mPopupArrowVisual;
562 }
563
564 void Slider::CreatePopupArrowImage( const std::string& filename )
565 {
566   if( mPopupArrow && ( filename.size() > 0 ) )
567   {
568     Property::Map map;
569     map[Toolkit::ImageVisual::Property::URL] = filename;
570     mPopupArrow.SetProperty( Toolkit::ImageView::Property::IMAGE, map );
571   }
572 }
573
574 void Slider::ResizeProgressRegion( const Vector2& region )
575 {
576   if( mProgress )
577   {
578     mProgress.SetProperty( Actor::Property::SIZE, region );
579   }
580 }
581
582 Toolkit::ImageView Slider::CreateHandle()
583 {
584   Toolkit::ImageView handle = Toolkit::ImageView::New();
585   handle.SetProperty( Dali::Actor::Property::NAME,"SliderHandle");
586   handle.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER_LEFT );
587   handle.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
588
589   return handle;
590 }
591
592 Toolkit::ImageView Slider::CreatePopupArrow()
593 {
594   Toolkit::ImageView arrow = Toolkit::ImageView::New();
595   arrow.SetStyleName("SliderPopupArrow");
596   arrow.SetProperty( Dali::Actor::Property::NAME,"SliderPopupArrow");
597   arrow.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER );
598   arrow.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER );
599
600   return arrow;
601 }
602
603 Toolkit::TextLabel Slider::CreatePopupText()
604 {
605   Toolkit::TextLabel textLabel = Toolkit::TextLabel::New();
606   textLabel.SetProperty( Dali::Actor::Property::NAME, "SliderPopupTextLabel" );
607   textLabel.SetStyleName( "SliderPopupTextLabel" );
608   textLabel.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
609   textLabel.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
610   textLabel.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
611   textLabel.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
612   textLabel.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
613   textLabel.SetProperty( Actor::Property::PADDING, Padding( POPUP_TEXT_PADDING, POPUP_TEXT_PADDING, 0.0f, 0.0f ) );
614   return textLabel;
615 }
616
617 Toolkit::ImageView Slider::CreatePopup()
618 {
619   Toolkit::ImageView popup = Toolkit::ImageView::New();
620   popup.SetProperty( Dali::Actor::Property::NAME, "SliderPopup" );
621   popup.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER );
622   popup.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER );
623   popup.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::WIDTH );
624
625   mValueTextLabel = CreatePopupText();
626   popup.Add( mValueTextLabel );
627
628   return popup;
629 }
630
631 void Slider::SetHandleVisual( const std::string& filename )
632 {
633   if( mHandle && ( filename.size() > 0 ) )
634   {
635     mHandle.SetImage( filename );
636     mHandleVisual = filename;
637   }
638 }
639
640 void Slider::SetHandleVisual( Property::Map map )
641 {
642   Property::Value* imageValue = map.Find( "url" );
643   if( imageValue )
644   {
645     mHandleVisual.clear();
646     std::string filename;
647     if( imageValue->Get( filename ) )
648     {
649       if( mHandle && ( filename.size() > 0 ) )
650       {
651         mHandle.SetImage( filename );
652         mHandleMap = map;
653       }
654     }
655   }
656
657   Property::Value* sizeValue = map.Find( "size" );
658   if( sizeValue )
659   {
660     Vector2 size;
661     if( sizeValue->Get( size ) )
662     {
663       mHandleSize = size;
664       ResizeHandleSize( mHandleSize );
665
666       Vector2 hitRegion = GetHitRegion();
667       hitRegion.x += mHandleSize.x;
668       SetHitRegion( hitRegion );
669     }
670   }
671 }
672
673 std::string Slider::GetHandleVisual()
674 {
675   return mHandleVisual;
676 }
677
678 void Slider::ResizeHandleSize( const Vector2& size )
679 {
680   if( mHandle )
681   {
682     mHandle.SetProperty( Actor::Property::SIZE, size );
683   }
684 }
685
686 void Slider::CreateHandleValueDisplay()
687 {
688   if( mHandle && !mHandleValueTextLabel )
689   {
690     mHandleValueTextLabel = Toolkit::TextLabel::New();
691     mHandleValueTextLabel.SetProperty( Dali::Actor::Property::NAME,"SliderHandleTextLabel");
692     mHandleValueTextLabel.SetStyleName("SliderHandleTextLabel");
693     mHandleValueTextLabel.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
694     mHandleValueTextLabel.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
695     mHandleValueTextLabel.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
696     mHandleValueTextLabel.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
697     mHandle.Add( mHandleValueTextLabel );
698   }
699 }
700
701 void Slider::DestroyHandleValueDisplay()
702 {
703   UnparentAndReset(mHandleValueTextLabel);
704 }
705
706 Actor Slider::CreateValueDisplay()
707 {
708   Actor popup = Actor::New();
709   popup.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER );
710   popup.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER );
711
712   mPopupArrow = CreatePopupArrow();
713   popup.Add( mPopupArrow );
714
715   mPopup = CreatePopup();
716   mPopup.SetProperty( Actor::Property::SIZE, Vector2( 0.0f, VALUE_POPUP_HEIGHT ) );
717   mPopupArrow.Add( mPopup );
718
719   return popup;
720 }
721
722 Toolkit::Slider::ValueChangedSignalType& Slider::ValueChangedSignal()
723 {
724   return mValueChangedSignal;
725 }
726
727 Toolkit::Slider::ValueChangedSignalType& Slider::SlidingFinishedSignal()
728 {
729   return mSlidingFinishedSignal;
730 }
731
732 Toolkit::Slider::MarkReachedSignalType& Slider::MarkReachedSignal()
733 {
734   return mMarkReachedSignal;
735 }
736
737 void Slider::UpdateSkin()
738 {
739   switch( mState )
740   {
741     case NORMAL:
742     {
743       mTrack.SetProperty( Actor::Property::COLOR, Color::WHITE );
744       mHandle.SetProperty( Actor::Property::COLOR, Color::WHITE );
745       mProgress.SetProperty( Actor::Property::COLOR, Color::WHITE );
746       break;
747     }
748     case DISABLED:
749     {
750       Vector4 disabledColor = GetDisabledColor();
751       mTrack.SetProperty( Actor::Property::COLOR, disabledColor );
752       mHandle.SetProperty( Actor::Property::COLOR, disabledColor );
753       mProgress.SetProperty( Actor::Property::COLOR, disabledColor );
754       break;
755     }
756     case PRESSED:
757     {
758       break;
759     }
760     case FOCUSED:
761     {
762       break;
763     }
764   }
765 }
766
767 void Slider::CreateChildren()
768 {
769   Actor self = Self();
770
771   // Hit region
772   mHitArea = CreateHitRegion();
773   mPanDetector = PanGestureDetector::New();
774   mPanDetector.Attach( mHitArea );
775   mPanDetector.DetectedSignal().Connect( this, &Slider::OnPan );
776   self.Add( mHitArea );
777
778   // Track
779   mTrack = CreateTrack();
780   self.Add( mTrack );
781
782   // Progress bar
783   mProgress = CreateProgress();
784   mTrack.Add( mProgress );
785
786   // Handle
787   mHandle = CreateHandle();
788   mProgress.Add( mHandle );
789 }
790
791 void Slider::SetHitRegion( const Vector2& size )
792 {
793   mHitRegion = size;
794
795   if( mHitArea )
796   {
797     mHitArea.SetProperty( Actor::Property::SIZE, mHitRegion );
798   }
799 }
800
801 const Vector2& Slider::GetHitRegion() const
802 {
803   return mHitRegion;
804 }
805
806 void Slider::AddPopup()
807 {
808   if( !mValueDisplay )
809   {
810     mValueDisplay = CreateValueDisplay();
811     mValueDisplay.SetProperty( Actor::Property::VISIBLE, false );
812     mHandle.Add( mValueDisplay );
813
814     CreatePopupImage( GetPopupVisual() );
815     CreatePopupArrowImage( GetPopupArrowVisual() );
816
817     mValueTimer = Timer::New( VALUE_VIEW_SHOW_DURATION );
818     mValueTimer.TickSignal().Connect( this, &Slider::HideValueView );
819   }
820 }
821
822 void Slider::RemovePopup()
823 {
824   if( mValueDisplay )
825   {
826     mPopup.Unparent();
827     mPopup.Reset();
828
829     mPopupArrow.Unparent();
830     mPopupArrow.Reset();
831
832     mValueDisplay.Unparent();
833     mValueDisplay.Reset();
834
835     mValueTimer.TickSignal().Disconnect( this, &Slider::HideValueView );
836     mValueTimer.Reset();
837   }
838 }
839
840
841 float Slider::MarkFilter( float value )
842 {
843   const float MARK_TOLERANCE = GetMarkTolerance();
844
845   float mark;
846   for( MarkList::SizeType i = 0; i < mMarks.Count(); ++i)
847   {
848     const Property::Value& propertyValue = mMarks[i];
849     propertyValue.Get( mark );
850     mark = MapValuePercentage( mark );
851
852     // If close to a mark, return the mark
853     if( fabsf( mark - value ) < MARK_TOLERANCE )
854     {
855       return mark;
856     }
857   }
858
859   return value;
860 }
861
862 float Slider::SnapToMark( float value )
863 {
864   float closestMark = value;
865   float closestDist = std::numeric_limits<float>::max();
866
867   float mark;
868   for( MarkList::SizeType  i = 0; i < mMarks.Count(); ++i)
869   {
870     const Property::Value& propertyValue = mMarks[i];
871     propertyValue.Get( mark );
872     mark = MapValuePercentage( mark );
873
874     float dist = fabsf( mark - value );
875     if( dist < closestDist )
876     {
877       closestDist = dist;
878       closestMark = mark;
879     }
880   }
881
882   return closestMark;
883 }
884
885 bool Slider::MarkReached( float value, int& outIndex )
886 {
887   const float MARK_TOLERANCE = GetMarkTolerance();
888
889   // Binary search
890   int head = 0,
891       tail = mMarks.Size() - 1;
892   int current;
893   float mark;
894
895   while( head <= tail )
896   {
897     current = head + ( tail - head ) / 2;
898
899     const Property::Value& propertyValue = mMarks[ current ];
900     propertyValue.Get( mark );
901     mark = MapValuePercentage( mark );
902
903     if( fabsf( mark - value ) < MARK_TOLERANCE )
904     {
905       outIndex = current;
906       return true;
907     }
908
909     if( value < mark )
910     {
911       tail = current - 1;
912     }
913     else
914     {
915       head = current + 1;
916     }
917   }
918
919   return false;
920 }
921
922 bool Slider::HideValueView()
923 {
924   if( mValueDisplay )
925   {
926     mValueDisplay.SetProperty( Actor::Property::VISIBLE, false );
927   }
928
929   return false;
930 }
931
932 void Slider::SetLowerBound( float bound )
933 {
934   mLowerBound = bound;
935   DisplayValue( GetValue(), false );
936 }
937
938 float Slider::GetLowerBound() const
939 {
940   return mLowerBound;
941 }
942
943 void Slider::SetUpperBound( float bound )
944 {
945   mUpperBound = bound;
946   DisplayValue( GetValue(), false );
947 }
948
949 float Slider::GetUpperBound() const
950 {
951   return mUpperBound;
952 }
953
954 void Slider::SetValue( float value )
955 {
956   mValue = value;
957   DisplayValue( mValue, true );
958 }
959
960 float Slider::GetValue() const
961 {
962   return mValue;
963 }
964
965 void Slider::SetTrackRegion( const Vector2& region )
966 {
967   mTrackRegion = region;
968
969   if( mTrack )
970   {
971     mTrack.SetProperty( Actor::Property::SIZE, mTrackRegion );
972   }
973
974   ResizeProgressRegion( Vector2( 0.0f, mTrackRegion.y ) );
975
976   mDomain = CalcDomain( mTrackRegion );
977
978   DisplayValue( GetValue(), false );  // Set the progress bar to correct width
979 }
980
981 const Vector2& Slider::GetTrackRegion() const
982 {
983   return mTrackRegion;
984 }
985
986 void Slider::SetHandleSize( const Vector2& size )
987 {
988   mHandleSize = size;
989
990   ResizeHandleSize( mHandleSize );
991
992   Vector2 hitRegion = GetHitRegion();
993   hitRegion.x += mHandleSize.x;
994   SetHitRegion( hitRegion );
995 }
996
997 const Vector2& Slider::GetHandleSize() const
998 {
999   return mHandleSize;
1000 }
1001
1002 void Slider::SetDisabledColor( const Vector4& color )
1003 {
1004   mDisabledColor = color;
1005
1006   UpdateSkin();
1007 }
1008
1009 Vector4 Slider::GetDisabledColor() const
1010 {
1011   return mDisabledColor;
1012 }
1013
1014 void Slider::SetValuePrecision( int precision )
1015 {
1016   mValuePrecision = precision;
1017 }
1018
1019 int Slider::GetValuePrecision() const
1020 {
1021   return mValuePrecision;
1022 }
1023
1024 void Slider::SetShowPopup( bool showPopup )
1025 {
1026   mShowPopup = showPopup;
1027
1028   // Value display
1029   if( mShowPopup )
1030   {
1031     AddPopup();
1032   }
1033   else
1034   {
1035     RemovePopup();
1036   }
1037 }
1038
1039 bool Slider::GetShowPopup() const
1040 {
1041   return mShowPopup;
1042 }
1043
1044 void Slider::SetShowValue( bool showValue )
1045 {
1046   mShowValue = showValue;
1047
1048   if( mShowValue )
1049   {
1050     CreateHandleValueDisplay();
1051   }
1052   else
1053   {
1054     DestroyHandleValueDisplay();
1055   }
1056 }
1057
1058 bool Slider::GetShowValue() const
1059 {
1060   return mShowValue;
1061 }
1062
1063 void Slider::SetEnabled( bool enabled )
1064 {
1065   if( enabled )
1066   {
1067     mState = NORMAL;
1068   }
1069   else
1070   {
1071     mState = DISABLED;
1072   }
1073
1074   UpdateSkin();
1075 }
1076
1077 bool Slider::IsEnabled() const
1078 {
1079   return mState != DISABLED;
1080 }
1081
1082 void Slider::SetMarkTolerance( float tolerance )
1083 {
1084   mMarkTolerance = tolerance;
1085 }
1086
1087 float Slider::GetMarkTolerance() const
1088 {
1089   return mMarkTolerance;
1090 }
1091
1092 // Static class method to support script connecting signals
1093 bool Slider::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
1094 {
1095   Dali::BaseHandle handle( object );
1096
1097   bool connected = true;
1098   Toolkit::Slider slider = Toolkit::Slider::DownCast( handle );
1099
1100   if( 0 == strcmp( signalName.c_str(), SIGNAL_VALUE_CHANGED ) )
1101   {
1102     slider.ValueChangedSignal().Connect( tracker, functor );
1103   }
1104   else if( 0 == strcmp( signalName.c_str(), SIGNAL_MARK ) )
1105   {
1106     slider.MarkReachedSignal().Connect( tracker, functor );
1107   }
1108   else
1109   {
1110     // signalName does not match any signal
1111     connected = false;
1112   }
1113
1114   return connected;
1115 }
1116
1117 void Slider::DisplayPopup( float value )
1118 {
1119   // Value displayDoConnectSignal
1120   if( mValueTextLabel )
1121   {
1122     std::stringstream ss;
1123     ss.precision( GetValuePrecision() );
1124     ss << std::fixed << value;
1125     mValueTextLabel.SetProperty( Toolkit::TextLabel::Property::TEXT, ss.str() );
1126
1127     if( mValueDisplay )
1128     {
1129       mValueDisplay.SetProperty( Actor::Property::VISIBLE, true );
1130
1131       mValueTimer.SetInterval( VALUE_VIEW_SHOW_DURATION );
1132     }
1133   }
1134 }
1135
1136 void Slider::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
1137 {
1138   Toolkit::Slider slider = Toolkit::Slider::DownCast( Dali::BaseHandle( object ) );
1139
1140   if ( slider )
1141   {
1142     Slider& sliderImpl( GetImpl( slider ) );
1143
1144     switch ( propertyIndex )
1145     {
1146       case Toolkit::Slider::Property::LOWER_BOUND:
1147       {
1148         sliderImpl.SetLowerBound( value.Get< float >() );
1149         break;
1150       }
1151
1152       case Toolkit::Slider::Property::UPPER_BOUND:
1153       {
1154         sliderImpl.SetUpperBound( value.Get< float >() );
1155         break;
1156       }
1157
1158       case Toolkit::Slider::Property::VALUE:
1159       {
1160         sliderImpl.SetValue( value.Get< float >() );
1161         break;
1162       }
1163
1164       case Toolkit::Slider::Property::TRACK_VISUAL:
1165       {
1166         Property::Map map;
1167         if( value.Get( map ) )
1168         {
1169           sliderImpl.SetTrackVisual( map );
1170         }
1171         break;
1172       }
1173
1174       case Toolkit::Slider::Property::HANDLE_VISUAL:
1175       {
1176         Property::Map map;
1177         if( value.Get( map ) )
1178         {
1179           sliderImpl.SetHandleVisual( map );
1180         }
1181         break;
1182       }
1183
1184       case Toolkit::Slider::Property::PROGRESS_VISUAL:
1185       {
1186         Property::Map map;
1187         if( value.Get( map ) )
1188         {
1189           sliderImpl.SetProgressVisual( map );
1190         }
1191         break;
1192       }
1193
1194       case Toolkit::Slider::Property::POPUP_VISUAL:
1195       {
1196         std::string imageUrl;
1197         if( value.Get( imageUrl ) )
1198         {
1199           sliderImpl.SetPopupVisual( imageUrl );
1200         }
1201
1202         // If it is not a string, then get a Property::Map from the property if possible.
1203         Property::Map map;
1204         if( value.Get( map ) )
1205         {
1206           sliderImpl.SetPopupVisual( map );
1207         }
1208
1209         break;
1210       }
1211
1212       case Toolkit::Slider::Property::POPUP_ARROW_VISUAL:
1213       {
1214         Property::Map map;
1215         if( value.Get( map ) )
1216         {
1217           sliderImpl.SetPopupArrowVisual( map );
1218         }
1219         break;
1220       }
1221
1222       case Toolkit::Slider::Property::DISABLED_COLOR:
1223       {
1224         sliderImpl.SetDisabledColor( value.Get< Vector4 >() );
1225         break;
1226       }
1227
1228       case Toolkit::Slider::Property::VALUE_PRECISION:
1229       {
1230         sliderImpl.SetValuePrecision( value.Get< int >() );
1231         break;
1232       }
1233
1234       case Toolkit::Slider::Property::SHOW_POPUP:
1235       {
1236         sliderImpl.SetShowPopup( value.Get< bool >() );
1237         break;
1238       }
1239
1240       case Toolkit::Slider::Property::SHOW_VALUE:
1241       {
1242         sliderImpl.SetShowValue( value.Get< bool >() );
1243         break;
1244       }
1245
1246       case Toolkit::Slider::Property::MARKS:
1247       {
1248         sliderImpl.SetMarks( value.Get< Property::Array >() );
1249         break;
1250       }
1251
1252       case Toolkit::Slider::Property::SNAP_TO_MARKS:
1253       {
1254         sliderImpl.SetSnapToMarks( value.Get< bool >() );
1255         break;
1256       }
1257
1258       case Toolkit::Slider::Property::MARK_TOLERANCE:
1259       {
1260         sliderImpl.SetMarkTolerance( value.Get< float >() );
1261         break;
1262       }
1263     }
1264   }
1265 }
1266
1267 Property::Value Slider::GetProperty( BaseObject* object, Property::Index propertyIndex )
1268 {
1269   Property::Value value;
1270
1271   Toolkit::Slider slider = Toolkit::Slider::DownCast( Dali::BaseHandle( object ) );
1272
1273   if ( slider )
1274   {
1275     Slider& sliderImpl( GetImpl( slider ) );
1276
1277     switch ( propertyIndex )
1278     {
1279       case Toolkit::Slider::Property::LOWER_BOUND:
1280       {
1281         value = sliderImpl.GetLowerBound();
1282         break;
1283       }
1284
1285       case Toolkit::Slider::Property::UPPER_BOUND:
1286       {
1287         value = sliderImpl.GetUpperBound();
1288         break;
1289       }
1290
1291       case Toolkit::Slider::Property::VALUE:
1292       {
1293         value = sliderImpl.GetValue();
1294         break;
1295       }
1296
1297       case Toolkit::Slider::Property::TRACK_VISUAL:
1298       {
1299         if( !sliderImpl.mTrackVisual.empty() )
1300         {
1301           value = sliderImpl.GetTrackVisual();
1302         }
1303         else if( !sliderImpl.mTrackMap.Empty() )
1304         {
1305           value = sliderImpl.mTrackMap;
1306         }
1307         break;
1308       }
1309
1310       case Toolkit::Slider::Property::HANDLE_VISUAL:
1311       {
1312         if( !sliderImpl.mHandleVisual.empty() )
1313         {
1314           value = sliderImpl.GetHandleVisual();
1315         }
1316         else if( !sliderImpl.mHandleMap.Empty() )
1317         {
1318           value = sliderImpl.mHandleMap;
1319         }
1320         break;
1321       }
1322
1323       case Toolkit::Slider::Property::PROGRESS_VISUAL:
1324       {
1325         if( !sliderImpl.mProgressVisual.empty() )
1326         {
1327           value = sliderImpl.GetProgressVisual();
1328         }
1329         else if( !sliderImpl.mProgressMap.Empty() )
1330         {
1331           value = sliderImpl.mProgressMap;
1332         }
1333         break;
1334       }
1335
1336       case Toolkit::Slider::Property::POPUP_VISUAL:
1337       {
1338         if( !sliderImpl.mPopupVisual.empty() )
1339         {
1340           value = sliderImpl.GetPopupVisual();
1341         }
1342         else if( !sliderImpl.mPopupMap.Empty() )
1343         {
1344           value = sliderImpl.mPopupMap;
1345         }
1346         break;
1347       }
1348
1349       case Toolkit::Slider::Property::POPUP_ARROW_VISUAL:
1350       {
1351         if( !sliderImpl.mPopupArrowVisual.empty() )
1352         {
1353           value = sliderImpl.GetPopupArrowVisual();
1354         }
1355         else if( !sliderImpl.mPopupArrowMap.Empty() )
1356         {
1357           value = sliderImpl.mPopupArrowMap;
1358         }
1359         break;
1360       }
1361
1362       case Toolkit::Slider::Property::DISABLED_COLOR:
1363       {
1364         value = sliderImpl.GetDisabledColor();
1365         break;
1366       }
1367
1368       case Toolkit::Slider::Property::VALUE_PRECISION:
1369       {
1370         value = sliderImpl.GetValuePrecision();
1371         break;
1372       }
1373
1374       case Toolkit::Slider::Property::SHOW_POPUP:
1375       {
1376         value = sliderImpl.GetShowPopup();
1377         break;
1378       }
1379
1380       case Toolkit::Slider::Property::SHOW_VALUE:
1381       {
1382         value = sliderImpl.GetShowValue();
1383         break;
1384       }
1385
1386       case Toolkit::Slider::Property::MARKS:
1387       {
1388         Property::Value value1( Property::ARRAY );
1389         Property::Array* markArray = value1.GetArray();
1390
1391         if( markArray )
1392         {
1393           *markArray = sliderImpl.GetMarks();
1394         }
1395
1396         value = value1;
1397         break;
1398       }
1399
1400       case Toolkit::Slider::Property::SNAP_TO_MARKS:
1401       {
1402         value = sliderImpl.GetSnapToMarks();
1403         break;
1404       }
1405
1406       case Toolkit::Slider::Property::MARK_TOLERANCE:
1407       {
1408         value = sliderImpl.GetMarkTolerance();
1409         break;
1410       }
1411     }
1412   }
1413
1414   return value;
1415 }
1416
1417 double Slider::AccessibleImpl::GetMinimum()
1418 {
1419   auto p = Toolkit::Slider::DownCast( self );
1420   return p.GetProperty( Toolkit::Slider::Property::LOWER_BOUND ).Get< float >();
1421 }
1422
1423 double Slider::AccessibleImpl::GetCurrent()
1424 {
1425   auto p = Toolkit::Slider::DownCast( self );
1426   return p.GetProperty( Toolkit::Slider::Property::VALUE ).Get< float >();
1427 }
1428
1429 double Slider::AccessibleImpl::GetMaximum()
1430 {
1431   auto p = Toolkit::Slider::DownCast( self );
1432   return p.GetProperty( Toolkit::Slider::Property::UPPER_BOUND ).Get< float >();
1433 }
1434
1435 bool Slider::AccessibleImpl::SetCurrent( double current )
1436 {
1437   if( current < GetMinimum() || current > GetMaximum() )
1438     return false;
1439   auto p = Toolkit::Slider::DownCast( self );
1440   p.SetProperty( Toolkit::Slider::Property::VALUE, static_cast< float >( current ) );
1441   return true;
1442 }
1443
1444 double Slider::AccessibleImpl::GetMinimumIncrement()
1445 {
1446   auto p = Toolkit::Slider::DownCast( self );
1447   return p.GetProperty( Toolkit::Slider::Property::MARK_TOLERANCE ).Get< float >();
1448 }
1449
1450 } // namespace Internal
1451
1452 } // namespace Toolkit
1453
1454 } // namespace Dali