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