Remove dali-any from Property::Value
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / slider / slider-impl.cpp
1 /*
2  * Copyright (c) 2014 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/devel-api/object/type-registry-helper.h>
28 #include <dali/public-api/images/resource-image.h>
29
30 // INTERNAL INCLUDES
31 #include <dali-toolkit/public-api/controls/control-impl.h>
32
33 using namespace Dali;
34
35 namespace Dali
36 {
37
38 namespace Toolkit
39 {
40
41 namespace Internal
42 {
43
44 namespace // Unnamed namespace
45 {
46
47 BaseHandle Create()
48 {
49   return Dali::Toolkit::Slider::New();
50 }
51
52 // Setup properties, signals and actions using the type-registry.
53 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Slider, Toolkit::Control, Create )
54
55 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "lower-bound",            FLOAT,    LOWER_BOUND            )
56 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "upper-bound",            FLOAT,    UPPER_BOUND            )
57 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "value",                  FLOAT,    VALUE                  )
58 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "hit-region",             VECTOR2,  HIT_REGION             )
59 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "backing-region",         VECTOR2,  BACKING_REGION         )
60 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "handle-region",          VECTOR2,  HANDLE_REGION          )
61 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "backing-image-name",     STRING,   BACKING_IMAGE_NAME     )
62 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "handle-image-name",      STRING,   HANDLE_IMAGE_NAME      )
63 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "progress-image-name",    STRING,   PROGRESS_IMAGE_NAME    )
64 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "popup-image-name",       STRING,   POPUP_IMAGE_NAME       )
65 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "popup-arrow-image-name", STRING,   POPUP_ARROW_IMAGE_NAME )
66 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "disable-color",          VECTOR4,  DISABLE_COLOR          )
67 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "popup-text-color",       VECTOR4,  POPUP_TEXT_COLOR       )
68 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "value-precision",        INTEGER,  VALUE_PRECISION        )
69 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "show-popup",             BOOLEAN,  SHOW_POPUP             )
70 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "show-value",             BOOLEAN,  SHOW_VALUE             )
71 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "enabled",                BOOLEAN,  ENABLED                )
72 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "marks",                  ARRAY,    MARKS                  )
73 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "snap-to-marks",          BOOLEAN,  SNAP_TO_MARKS          )
74 DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "mark-tolerance",         FLOAT,    MARK_TOLERANCE         )
75
76 DALI_SIGNAL_REGISTRATION(   Toolkit, Slider, "value-changed",                    SIGNAL_VALUE_CHANGED   )
77 DALI_SIGNAL_REGISTRATION(   Toolkit, Slider, "mark",                             SIGNAL_MARK            )
78
79 DALI_TYPE_REGISTRATION_END()
80
81 const float BACKING_Z = -0.1f;
82 const float PROGRESS_Z = 0.1f;
83 const float HANDLE_Z = 1.0f;
84 const float VALUE_TEXT_INCREMENT = 0.01f;
85 const float HANDLE_VALUE_DISPLAY_TEXT_Z = HANDLE_Z + VALUE_TEXT_INCREMENT;
86 const float VALUE_DISPLAY_TEXT_Z = VALUE_TEXT_INCREMENT + VALUE_TEXT_INCREMENT;  // Put above HANDLE_VALUE_DISPLAY_TEXT_Z (parented to handle)
87
88 const float MARK_SNAP_TOLERANCE = 0.05f; // 5% of slider width
89
90 const int VALUE_VIEW_SHOW_DURATION = 1000;  // millisec
91 const int VALUE_VIEW_SHOW_DURATION_LONG = 2000;  // millisec
92
93 const float VALUE_VERTICAL_OFFSET = 48.0f;
94
95 const float DEFAULT_WIDTH = 0.0f;
96 const float DEFAULT_HEIGHT = 27.0f;
97 const float DEFAULT_HIT_HEIGHT = 72.0f;
98 const float DEFAULT_HANDLE_HEIGHT = DEFAULT_HIT_HEIGHT;
99 const float POPUP_TEXT_PADDING = 10.0f;
100
101 const char* SKINNED_BACKING_IMAGE_NAME = DALI_IMAGE_DIR "slider-skin.9.png";
102 const char* SKINNED_HANDLE_IMAGE_NAME = DALI_IMAGE_DIR "slider-skin-handle.png";;
103 const char* SKINNED_PROGRESS_IMAGE_NAME = DALI_IMAGE_DIR "slider-skin-progress.9.png";
104 const char* SKINNED_POPUP_IMAGE_NAME = DALI_IMAGE_DIR "slider-popup.9.png";
105 const char* SKINNED_POPUP_ARROW_IMAGE_NAME = DALI_IMAGE_DIR "slider-popup-arrow.png";
106
107 const Vector2 DEFAULT_HIT_REGION( DEFAULT_WIDTH, DEFAULT_HIT_HEIGHT );
108 const Vector2 DEFAULT_BACKING_REGION( DEFAULT_WIDTH, DEFAULT_HEIGHT );
109 const Vector2 DEFAULT_HANDLE_REGION( DEFAULT_HANDLE_HEIGHT, DEFAULT_HANDLE_HEIGHT );
110
111 const Vector4 DEFAULT_DISABLE_COLOR( 0.5f, 0.5f, 0.5f, 1.0f );
112 const Vector4 DEFAULT_POPUP_TEXT_COLOR( 0.5f, 0.5f, 0.5f, 1.0f );
113
114 const float VALUE_POPUP_MARGIN = 10.0f;
115 const float VALUE_POPUP_HEIGHT = 81.0f;
116 const float VALUE_POPUP_MIN_WIDTH = 54.0f;
117 const Vector2 VALUE_POPUP_ARROW_SIZE( 18.0f, 18.0f );
118
119 const float DEFAULT_LOWER_BOUND = 0.0f;
120 const float DEFAULT_UPPER_BOUND = 1.0f;
121 const float DEFAULT_VALUE = 0.0f;
122 const int DEFAULT_VALUE_PRECISION = 0;
123 const bool DEFAULT_SHOW_POPUP = false;
124 const bool DEFAULT_SHOW_VALUE = true;
125 const bool DEFAULT_ENABLED = true;
126 const bool DEFAULT_SNAP_TO_MARKS = false;
127
128 } // Unnamed namespace
129
130 ///////////////////////////////////////////////////////////////////////////////////////////////////
131 // Slider
132 ///////////////////////////////////////////////////////////////////////////////////////////////////
133
134 Dali::Toolkit::Slider Slider::New()
135 {
136   // Create the implementation
137   SliderPtr slider( new Slider() );
138
139   // Pass ownership to CustomActor via derived handle
140   Dali::Toolkit::Slider handle( *slider );
141
142   // Second-phase init of the implementation
143   // This can only be done after the CustomActor connection has been made...
144   slider->Initialize();
145
146   return handle;
147 }
148
149 Slider::Slider()
150 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
151   mState( NORMAL ),
152   mDisableColor( 0.0f, 0.0f, 0.0f, 0.0f ),
153   mPopupTextColor( 0.0f, 0.0f, 0.0f, 0.0f ),
154   mHitRegion( 0.0f, 0.0f ),
155   mBackingRegion( 0.0f, 0.0f ),
156   mHandleRegionSize( 0.0f, 0.0f ),
157   mLowerBound( 0.0f ),
158   mUpperBound( 0.0f ),
159   mValue( 0.0f ),
160   mMarkTolerance( 0.0f ),
161   mValuePrecision( 0 ),
162   mShowPopup( false ),
163   mShowValue( false ),
164   mSnapToMarks( false )
165 {
166 }
167
168 Slider::~Slider()
169 {
170 }
171
172 void Slider::OnInitialize()
173 {
174   // Setup
175   CreateChildren();
176
177   // Properties
178   Actor self = Self();
179
180   SetHitRegion(     DEFAULT_HIT_REGION     );
181   SetBackingRegion( DEFAULT_BACKING_REGION );
182   SetHandleRegion(  DEFAULT_HANDLE_REGION  );
183
184   SetBackingImageName(    SKINNED_BACKING_IMAGE_NAME     );
185   SetHandleImageName(     SKINNED_HANDLE_IMAGE_NAME      );
186   SetProgressImageName(   SKINNED_PROGRESS_IMAGE_NAME    );
187   SetPopupImageName(      SKINNED_POPUP_IMAGE_NAME       );
188   SetPopupArrowImageName( SKINNED_POPUP_ARROW_IMAGE_NAME );
189
190   SetPopupTextColor( DEFAULT_POPUP_TEXT_COLOR );
191
192   SetShowPopup( DEFAULT_SHOW_POPUP );
193   SetShowValue( DEFAULT_SHOW_VALUE );
194
195   SetEnabled( DEFAULT_ENABLED );
196   SetDisableColor( DEFAULT_DISABLE_COLOR );
197
198   SetSnapToMarks( DEFAULT_SNAP_TO_MARKS );
199   SetMarkTolerance( MARK_SNAP_TOLERANCE );
200
201   SetLowerBound( DEFAULT_LOWER_BOUND );
202   SetUpperBound( DEFAULT_UPPER_BOUND );
203   UpdateSkin();
204   SetValuePrecision( DEFAULT_VALUE_PRECISION );
205   mValue = DEFAULT_VALUE;
206   DisplayValue( mValue, false );       // Run this last to display the correct value
207
208   // Size the Slider actor to a default
209   self.SetSize( DEFAULT_HIT_REGION.x, DEFAULT_HIT_REGION.y );
210 }
211
212 void Slider::OnSizeSet( const Vector3& size )
213 {
214   // Factor in handle overshoot into size of backing
215   SetHitRegion( Vector2( size.x, GetHitRegion().y ) );
216   SetBackingRegion( Vector2( size.x - GetHandleRegion().x, GetBackingRegion().y ) );
217 }
218
219 bool Slider::OnTouchEvent(Actor actor, const TouchEvent& event)
220 {
221   if( mState != DISABLED )
222   {
223     TouchPoint::State touchState = event.GetPoint(0).state;
224
225     if( touchState == TouchPoint::Down )
226     {
227       mState = PRESSED;
228
229       float percentage = MapPercentage( event.GetPoint(0).local );
230       float value = MapBounds( ( GetSnapToMarks() ) ? SnapToMark( percentage ) : MarkFilter( percentage ), GetLowerBound(), GetUpperBound() );
231       SetValue( value );
232       DisplayPopup( value );
233     }
234     else if( touchState == TouchPoint::Up)
235     {
236       if( mState == PRESSED )
237       {
238         mState = NORMAL;
239         mSlidingFinishedSignal.Emit( Toolkit::Slider::DownCast( Self() ), GetValue() );
240       }
241     }
242   }
243
244   return true;
245 }
246
247 void Slider::OnPan( Actor actor, const PanGesture& gesture )
248 {
249   // gesture.position is in local actor coordinates
250   if( mState != DISABLED )
251   {
252     switch( gesture.state )
253     {
254       case Gesture::Continuing:
255       {
256         if( mState == PRESSED )
257         {
258           float value = MapBounds( MarkFilter ( MapPercentage( gesture.position ) ), GetLowerBound(), GetUpperBound() );
259           SetValue( value );
260           DisplayPopup( value );
261         }
262         break;
263       }
264       case Gesture::Finished:
265       {
266         if( mState == PRESSED  )
267         {
268           if( GetSnapToMarks() )
269           {
270             float value = MapBounds( SnapToMark( MapPercentage( gesture.position ) ), GetLowerBound(), GetUpperBound() );
271             SetValue( value );
272             DisplayPopup( value );
273           }
274           mSlidingFinishedSignal.Emit( Toolkit::Slider::DownCast( Self() ), GetValue() );
275         }
276
277         mState = NORMAL;
278         break;
279       }
280       default:
281       {
282         break;
283       }
284     }
285   }
286 }
287
288 float Slider::HitSpaceToDomain( float x )
289 {
290   float halfRegionWidth = GetHitRegion().x * 0.5f;
291   float halfDomainWidth = ( mDomain.to.x - mDomain.from.x ) * 0.5f;
292   float endDiff = halfRegionWidth - halfDomainWidth;
293
294   return x - endDiff;
295 }
296
297 float Slider::MapPercentage( const Vector2& point )
298 {
299   return Clamp( ( HitSpaceToDomain( point.x ) - mDomain.from.x ) / ( mDomain.to.x - mDomain.from.x ), 0.0f, 1.0f );
300 }
301
302 float Slider::MapValuePercentage( float value )
303 {
304   return ( value - GetLowerBound() ) / ( GetUpperBound() - GetLowerBound() );
305 }
306
307 float Slider::MapBounds( float percent, float lowerBound, float upperBound )
308 {
309   return lowerBound + percent * ( upperBound - lowerBound );
310 }
311
312 Slider::Domain Slider::CalcDomain( const Vector2& currentSize )
313 {
314    return Domain( Vector2( 0.0f, 0.0f ), currentSize );
315 }
316
317 void Slider::DisplayValue( float value, bool raiseSignals )
318 {
319   float clampledValue = Clamp( value, GetLowerBound(), GetUpperBound() );
320
321   float percent = MapValuePercentage( clampledValue );
322
323   float x = mDomain.from.x + percent * ( mDomain.to.x - mDomain.from.x );
324
325   mHandle.SetPosition( x, 0.0f, HANDLE_Z );
326
327   // Progress bar
328   if( mProgress )
329   {
330     mProgress.SetSize( x, GetBackingRegion().y );
331   }
332
333   // Signals
334   if( raiseSignals )
335   {
336     Toolkit::Slider self = Toolkit::Slider::DownCast( Self() );
337     mValueChangedSignal.Emit( self, clampledValue );
338
339     int markIndex;
340     if( MarkReached( percent, markIndex ) )
341     {
342       mMarkSignal.Emit( self, markIndex );
343     }
344   }
345
346   if( mHandleValueTextLabel )
347   {
348     std::stringstream ss;
349     ss.precision( GetValuePrecision() );
350     ss << std::fixed << clampledValue;
351
352     mHandleValueTextLabel.SetProperty( Toolkit::TextLabel::Property::TEXT, ss.str() );
353   }
354 }
355
356 void Slider::SetMarks( const MarkList& marks )
357 {
358   mMarks = marks;
359 }
360
361 const Slider::MarkList& Slider::GetMarks() const
362 {
363   return mMarks;
364 }
365
366 void Slider::SetSnapToMarks( bool snap )
367 {
368   mSnapToMarks = snap;
369 }
370
371 bool Slider::GetSnapToMarks() const
372 {
373   return mSnapToMarks;
374 }
375
376 Actor Slider::CreateHitRegion()
377 {
378   Actor hitRegion = Actor::New();
379   hitRegion.SetParentOrigin( ParentOrigin::CENTER );
380   hitRegion.SetAnchorPoint( AnchorPoint::CENTER );
381   hitRegion.TouchedSignal().Connect( this, &Slider::OnTouchEvent );
382
383   return hitRegion;
384 }
385
386 ImageActor Slider::CreateBacking()
387 {
388   ImageActor backing = ImageActor::New();
389   backing.SetParentOrigin( ParentOrigin::CENTER );
390   backing.SetAnchorPoint( AnchorPoint::CENTER );
391   backing.SetZ( BACKING_Z );
392
393   return backing;
394 }
395
396 void Slider::SetBackingImageName( const std::string& imageName )
397 {
398   if( mBacking && ( imageName.size() > 0 ) )
399   {
400     Image image = ResourceImage::New( imageName );
401     mBacking.SetImage( image );
402   }
403 }
404
405 std::string Slider::GetBackingImageName()
406 {
407   if( mBacking )
408   {
409     return ResourceImage::DownCast( mBacking.GetImage() ).GetUrl();
410   }
411
412   return std::string( "" );
413 }
414
415 ImageActor Slider::CreateProgress()
416 {
417   ImageActor progress = ImageActor::New();
418   progress.SetParentOrigin( ParentOrigin::CENTER_LEFT );
419   progress.SetAnchorPoint( AnchorPoint::CENTER_LEFT );
420   progress.SetZ( PROGRESS_Z );
421
422   return progress;
423 }
424
425 void Slider::SetProgressImageName( const std::string& imageName )
426 {
427   if( mProgress && ( imageName.size() > 0 ) )
428   {
429     Image image = ResourceImage::New( imageName );
430     mProgress.SetImage( image );
431   }
432 }
433
434 std::string Slider::GetProgressImageName()
435 {
436   if( mProgress )
437   {
438     return ResourceImage::DownCast( mProgress.GetImage()).GetUrl();
439   }
440
441   return std::string( "" );
442 }
443
444 void Slider::SetPopupImageName( const std::string& imageName )
445 {
446   mPopupImageName = imageName;
447 }
448
449 std::string Slider::GetPopupImageName()
450 {
451   return mPopupImageName;
452 }
453
454 void Slider::CreatePopupImage( const std::string& imageName )
455 {
456   if( mPopup && ( imageName.size() > 0 ) )
457   {
458     Image image = ResourceImage::New( imageName );
459     mPopup.SetImage( image );
460   }
461 }
462
463 void Slider::SetPopupArrowImageName( const std::string& imageName )
464 {
465   mPopupArrowImageName = imageName;
466 }
467
468 std::string Slider::GetPopupArrowImageName()
469 {
470   return mPopupArrowImageName;
471 }
472
473 void Slider::CreatePopupArrowImage( const std::string& imageName )
474 {
475   if( mPopupArrow && ( imageName.size() > 0 ) )
476   {
477     Image image = ResourceImage::New( imageName );
478     mPopupArrow.SetImage( image );
479   }
480 }
481
482 void Slider::ResizeProgressRegion( const Vector2& region )
483 {
484   if( mProgress )
485   {
486     mProgress.SetSize( region );
487   }
488 }
489
490 ImageActor Slider::CreateHandle()
491 {
492   ImageActor handle = ImageActor::New();
493   handle.SetParentOrigin( ParentOrigin::CENTER_LEFT );
494   handle.SetAnchorPoint( AnchorPoint::CENTER );
495   handle.SetZ( HANDLE_Z );
496
497   return handle;
498 }
499
500 ImageActor Slider::CreatePopupArrow()
501 {
502   ImageActor arrow = ImageActor::New();
503   arrow.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
504   arrow.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
505   arrow.SetZ( HANDLE_Z );
506
507   return arrow;
508 }
509
510 Toolkit::TextLabel Slider::CreatePopupText()
511 {
512   Toolkit::TextLabel textLabel = Toolkit::TextLabel::New();
513   textLabel.SetParentOrigin( ParentOrigin::CENTER );
514   textLabel.SetAnchorPoint( AnchorPoint::CENTER );
515   textLabel.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
516   textLabel.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
517   textLabel.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
518   textLabel.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, DEFAULT_POPUP_TEXT_COLOR );
519   textLabel.SetZ( VALUE_DISPLAY_TEXT_Z );
520   textLabel.SetPadding( Padding( POPUP_TEXT_PADDING, POPUP_TEXT_PADDING, 0.0f, 0.0f ) );
521   return textLabel;
522 }
523
524 ImageActor Slider::CreatePopup()
525 {
526   ImageActor popup = ImageActor::New();
527   popup.SetParentOrigin( ParentOrigin::TOP_CENTER );
528   popup.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
529   popup.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::WIDTH );
530
531   mValueTextLabel = CreatePopupText();
532   popup.Add( mValueTextLabel );
533
534   return popup;
535 }
536
537 void Slider::SetHandleImageName( const std::string& imageName )
538 {
539   if( mHandle && ( imageName.size() > 0 ) )
540   {
541     Image image = ResourceImage::New( imageName );
542     mHandle.SetImage( image );
543   }
544 }
545
546 std::string Slider::GetHandleImageName()
547 {
548   if( mHandle )
549   {
550     return ResourceImage::DownCast( mHandle.GetImage() ).GetUrl();
551   }
552
553   return std::string( "" );
554 }
555
556 void Slider::ResizeHandleRegion( const Vector2& region )
557 {
558   if( mHandle )
559   {
560     mHandle.SetSize( region );
561   }
562 }
563
564 void Slider::CreateHandleValueDisplay()
565 {
566   if( mHandle && !mHandleValueTextLabel )
567   {
568     mHandleValueTextLabel = Toolkit::TextLabel::New();
569     mHandleValueTextLabel.SetParentOrigin( ParentOrigin::CENTER );
570     mHandleValueTextLabel.SetAnchorPoint( AnchorPoint::CENTER );
571     mHandleValueTextLabel.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
572     mHandleValueTextLabel.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
573     mHandleValueTextLabel.SetDrawMode( DrawMode::OVERLAY );
574     mHandle.Add( mHandleValueTextLabel );
575   }
576 }
577
578 void Slider::DestroyHandleValueDisplay()
579 {
580   UnparentAndReset(mHandleValueTextLabel);
581 }
582
583 void Slider::SetPopupTextColor( const Vector4& color )
584 {
585   mPopupTextColor = color;
586 }
587
588 Actor Slider::CreateValueDisplay()
589 {
590   Actor popup = Actor::New();
591   popup.SetParentOrigin( ParentOrigin::TOP_CENTER );
592   popup.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
593
594   mPopupArrow = CreatePopupArrow();
595   popup.Add( mPopupArrow );
596
597   mPopup = CreatePopup();
598   mPopup.SetSize( 0.0f, VALUE_POPUP_HEIGHT );
599   mPopupArrow.Add( mPopup );
600
601   return popup;
602 }
603
604 Toolkit::Slider::ValueChangedSignalType& Slider::ValueChangedSignal()
605 {
606   return mValueChangedSignal;
607 }
608
609 Toolkit::Slider::ValueChangedSignalType& Slider::SlidingFinishedSignal()
610 {
611   return mSlidingFinishedSignal;
612 }
613
614 Toolkit::Slider::MarkSignalType& Slider::MarkSignal()
615 {
616   return mMarkSignal;
617 }
618
619 void Slider::UpdateSkin()
620 {
621   switch( mState )
622   {
623     case NORMAL:
624     {
625       mBacking.SetColor( Color::WHITE );
626       mHandle.SetColor( Color::WHITE );
627       mProgress.SetColor( Color::WHITE );
628       break;
629     }
630     case DISABLED:
631     {
632       Vector4 disableColor = GetDisableColor();
633       mBacking.SetColor( disableColor );
634       mHandle.SetColor( disableColor );
635       mProgress.SetColor( disableColor );
636       break;
637     }
638     case PRESSED:
639     {
640       break;
641     }
642     case FOCUSED:
643     {
644       break;
645     }
646   }
647 }
648
649 void Slider::CreateChildren()
650 {
651   Actor self = Self();
652
653   // Hit region
654   mHitArea = CreateHitRegion();
655   mPanDetector = PanGestureDetector::New();
656   mPanDetector.Attach( mHitArea );
657   mPanDetector.DetectedSignal().Connect( this, &Slider::OnPan );
658   self.Add( mHitArea );
659
660   // Background
661   mBacking = CreateBacking();
662   self.Add( mBacking );
663
664   // Progress bar
665   mProgress = CreateProgress();
666   mBacking.Add( mProgress );
667
668   // Handle
669   mHandle = CreateHandle();
670   mBacking.Add( mHandle );
671 }
672
673 void Slider::SetHitRegion( const Vector2& size )
674 {
675   mHitRegion = size;
676
677   if( mHitArea )
678   {
679     mHitArea.SetSize( mHitRegion );
680   }
681 }
682
683 const Vector2& Slider::GetHitRegion() const
684 {
685   return mHitRegion;
686 }
687
688 void Slider::AddPopup()
689 {
690   if( !mValueDisplay )
691   {
692     mValueDisplay = CreateValueDisplay();
693     mValueDisplay.SetVisible( false );
694     mHandle.Add( mValueDisplay );
695
696     CreatePopupImage( GetPopupImageName() );
697     CreatePopupArrowImage( GetPopupArrowImageName() );
698
699     mValueTimer = Timer::New( VALUE_VIEW_SHOW_DURATION );
700     mValueTimer.TickSignal().Connect( this, &Slider::HideValueView );
701   }
702 }
703
704 void Slider::RemovePopup()
705 {
706   if( mValueDisplay )
707   {
708     mPopup.Unparent();
709     mPopup.Reset();
710
711     mPopupArrow.Unparent();
712     mPopupArrow.Reset();
713
714     mValueDisplay.Unparent();
715     mValueDisplay.Reset();
716
717     mValueTimer.TickSignal().Disconnect( this, &Slider::HideValueView );
718     mValueTimer.Reset();
719   }
720 }
721
722
723 float Slider::MarkFilter( float value )
724 {
725   const float MARK_TOLERANCE = GetMarkTolerance();
726
727   float mark;
728   for( MarkList::SizeType i = 0; i < mMarks.Count(); ++i)
729   {
730     const Property::Value& propertyValue = mMarks[i];
731     propertyValue.Get( mark );
732     mark = MapValuePercentage( mark );
733
734     // If close to a mark, return the mark
735     if( fabsf( mark - value ) < MARK_TOLERANCE )
736     {
737       return mark;
738     }
739   }
740
741   return value;
742 }
743
744 float Slider::SnapToMark( float value )
745 {
746   float closestMark = value;
747   float closestDist = std::numeric_limits<float>::max();
748
749   float mark;
750   for( MarkList::SizeType  i = 0; i < mMarks.Count(); ++i)
751   {
752     const Property::Value& propertyValue = mMarks[i];
753     propertyValue.Get( mark );
754     mark = MapValuePercentage( mark );
755
756     float dist = fabsf( mark - value );
757     if( dist < closestDist )
758     {
759       closestDist = dist;
760       closestMark = mark;
761     }
762   }
763
764   return closestMark;
765 }
766
767 bool Slider::MarkReached( float value, int& outIndex )
768 {
769   const float MARK_TOLERANCE = GetMarkTolerance();
770
771   // Binary search
772   int head = 0,
773       tail = mMarks.Size() - 1;
774   int current;
775   float mark;
776
777   while( head <= tail )
778   {
779     current = head + ( tail - head ) / 2;
780
781     const Property::Value& propertyValue = mMarks[ current ];
782     propertyValue.Get( mark );
783     mark = MapValuePercentage( mark );
784
785     if( fabsf( mark - value ) < MARK_TOLERANCE )
786     {
787       outIndex = current;
788       return true;
789     }
790
791     if( value < mark )
792     {
793       tail = current - 1;
794     }
795     else
796     {
797       head = current + 1;
798     }
799   }
800
801   return false;
802 }
803
804 bool Slider::HideValueView()
805 {
806   if( mValueDisplay )
807   {
808     mValueDisplay.SetVisible( false );
809   }
810
811   return false;
812 }
813
814 void Slider::SetLowerBound( float bound )
815 {
816   mLowerBound = bound;
817   DisplayValue( GetValue(), false );
818 }
819
820 float Slider::GetLowerBound() const
821 {
822   return mLowerBound;
823 }
824
825 void Slider::SetUpperBound( float bound )
826 {
827   mUpperBound = bound;
828   DisplayValue( GetValue(), false );
829 }
830
831 float Slider::GetUpperBound() const
832 {
833   return mUpperBound;
834 }
835
836 void Slider::SetValue( float value )
837 {
838   mValue = value;
839   DisplayValue( mValue, true );
840 }
841
842 float Slider::GetValue() const
843 {
844   return mValue;
845 }
846
847 void Slider::SetBackingRegion( const Vector2& region )
848 {
849   mBackingRegion = region;
850
851   if( mBacking )
852   {
853     mBacking.SetSize( mBackingRegion );
854   }
855
856   ResizeProgressRegion( Vector2( 0.0f, mBackingRegion.y ) );
857
858   mDomain = CalcDomain( mBackingRegion );
859
860   DisplayValue( GetValue(), false );  // Set the progress bar to correct width
861 }
862
863 const Vector2& Slider::GetBackingRegion() const
864 {
865   return mBackingRegion;
866 }
867
868 void Slider::SetHandleRegion( const Vector2& region )
869 {
870   mHandleRegionSize = region;
871
872   ResizeHandleRegion( mHandleRegionSize );
873
874   Vector2 hitRegion = GetHitRegion();
875   hitRegion.x += mHandleRegionSize.x;
876   SetHitRegion( hitRegion );
877 }
878
879 const Vector2& Slider::GetHandleRegion() const
880 {
881   return mHandleRegionSize;
882 }
883
884 void Slider::SetDisableColor( const Vector4& color )
885 {
886   mDisableColor = color;
887
888   UpdateSkin();
889 }
890
891 Vector4 Slider::GetDisableColor() const
892 {
893   return mDisableColor;
894 }
895
896 Vector4 Slider::GetPopupTextColor() const
897 {
898   return mPopupTextColor;
899 }
900
901 void Slider::SetValuePrecision( int precision )
902 {
903   mValuePrecision = precision;
904 }
905
906 int Slider::GetValuePrecision() const
907 {
908   return mValuePrecision;
909 }
910
911 void Slider::SetShowPopup( bool showPopup )
912 {
913   mShowPopup = showPopup;
914
915   // Value display
916   if( mShowPopup )
917   {
918     AddPopup();
919   }
920   else
921   {
922     RemovePopup();
923   }
924 }
925
926 bool Slider::GetShowPopup() const
927 {
928   return mShowPopup;
929 }
930
931 void Slider::SetShowValue( bool showValue )
932 {
933   mShowValue = showValue;
934
935   if( mShowValue )
936   {
937     CreateHandleValueDisplay();
938   }
939   else
940   {
941     DestroyHandleValueDisplay();
942   }
943 }
944
945 bool Slider::GetShowValue() const
946 {
947   return mShowValue;
948 }
949
950 void Slider::SetEnabled( bool enabled )
951 {
952   if( enabled )
953   {
954     mState = NORMAL;
955   }
956   else
957   {
958     mState = DISABLED;
959   }
960
961   UpdateSkin();
962 }
963
964 bool Slider::IsEnabled() const
965 {
966   return mState != DISABLED;
967 }
968
969 void Slider::SetMarkTolerance( float tolerance )
970 {
971   mMarkTolerance = tolerance;
972 }
973
974 float Slider::GetMarkTolerance() const
975 {
976   return mMarkTolerance;
977 }
978
979 // Static class method to support script connecting signals
980 bool Slider::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
981 {
982   Dali::BaseHandle handle( object );
983
984   bool connected = true;
985   Toolkit::Slider slider = Toolkit::Slider::DownCast( handle );
986
987   if( 0 == strcmp( signalName.c_str(), SIGNAL_VALUE_CHANGED ) )
988   {
989     slider.ValueChangedSignal().Connect( tracker, functor );
990   }
991   else if( 0 == strcmp( signalName.c_str(), SIGNAL_MARK ) )
992   {
993     slider.MarkSignal().Connect( tracker, functor );
994   }
995   else
996   {
997     // signalName does not match any signal
998     connected = false;
999   }
1000
1001   return connected;
1002 }
1003
1004 void Slider::DisplayPopup( float value )
1005 {
1006   // Value displayDoConnectSignal
1007   if( mValueTextLabel )
1008   {
1009     std::stringstream ss;
1010     ss.precision( GetValuePrecision() );
1011     ss << std::fixed << value;
1012     mValueTextLabel.SetProperty( Toolkit::TextLabel::Property::TEXT, ss.str() );
1013
1014     if( mValueDisplay )
1015     {
1016       mValueDisplay.SetVisible( true );
1017
1018       mValueTimer.SetInterval( VALUE_VIEW_SHOW_DURATION );
1019     }
1020   }
1021 }
1022
1023 void Slider::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
1024 {
1025   Toolkit::Slider slider = Toolkit::Slider::DownCast( Dali::BaseHandle( object ) );
1026
1027   if ( slider )
1028   {
1029     Slider& sliderImpl( GetImpl( slider ) );
1030
1031     switch ( propertyIndex )
1032     {
1033       case Toolkit::Slider::Property::LOWER_BOUND:
1034       {
1035         sliderImpl.SetLowerBound( value.Get< float >() );
1036         break;
1037       }
1038
1039       case Toolkit::Slider::Property::UPPER_BOUND:
1040       {
1041         sliderImpl.SetUpperBound( value.Get< float >() );
1042         break;
1043       }
1044
1045       case Toolkit::Slider::Property::VALUE:
1046       {
1047         sliderImpl.SetValue( value.Get< float >() );
1048         break;
1049       }
1050
1051       case Toolkit::Slider::Property::HIT_REGION:
1052       {
1053         sliderImpl.SetHitRegion( value.Get< Vector2 >() );
1054         break;
1055       }
1056
1057       case Toolkit::Slider::Property::BACKING_REGION:
1058       {
1059         sliderImpl.SetBackingRegion( value.Get< Vector2 >() );
1060         break;
1061       }
1062
1063       case Toolkit::Slider::Property::HANDLE_REGION:
1064       {
1065         sliderImpl.SetHandleRegion( value.Get< Vector2 >() );
1066         break;
1067       }
1068
1069       case Toolkit::Slider::Property::BACKING_IMAGE_NAME:
1070       {
1071         sliderImpl.SetBackingImageName( value.Get< std::string >() );
1072         break;
1073       }
1074
1075       case Toolkit::Slider::Property::HANDLE_IMAGE_NAME:
1076       {
1077         sliderImpl.SetHandleImageName( value.Get< std::string >() );
1078         break;
1079       }
1080
1081       case Toolkit::Slider::Property::PROGRESS_IMAGE_NAME:
1082       {
1083         sliderImpl.SetProgressImageName( value.Get< std::string >() );
1084         break;
1085       }
1086
1087       case Toolkit::Slider::Property::POPUP_IMAGE_NAME:
1088       {
1089         sliderImpl.SetPopupImageName( value.Get< std::string >() );
1090         break;
1091       }
1092
1093       case Toolkit::Slider::Property::POPUP_ARROW_IMAGE_NAME:
1094       {
1095         sliderImpl.SetPopupArrowImageName( value.Get< std::string >() );
1096         break;
1097       }
1098
1099       case Toolkit::Slider::Property::DISABLE_COLOR:
1100       {
1101         sliderImpl.SetDisableColor( value.Get< Vector4 >() );
1102         break;
1103       }
1104
1105       case Toolkit::Slider::Property::POPUP_TEXT_COLOR:
1106       {
1107         sliderImpl.SetPopupTextColor( value.Get< Vector4 >() );
1108         break;
1109       }
1110
1111       case Toolkit::Slider::Property::VALUE_PRECISION:
1112       {
1113         sliderImpl.SetValuePrecision( value.Get< int >() );
1114         break;
1115       }
1116
1117       case Toolkit::Slider::Property::SHOW_POPUP:
1118       {
1119         sliderImpl.SetShowPopup( value.Get< bool >() );
1120         break;
1121       }
1122
1123       case Toolkit::Slider::Property::SHOW_VALUE:
1124       {
1125         sliderImpl.SetShowValue( value.Get< bool >() );
1126         break;
1127       }
1128
1129       case Toolkit::Slider::Property::ENABLED:
1130       {
1131         sliderImpl.SetEnabled( value.Get< bool >() );
1132         break;
1133       }
1134
1135       case Toolkit::Slider::Property::MARKS:
1136       {
1137         sliderImpl.SetMarks( value.Get< Property::Array >() );
1138         break;
1139       }
1140
1141       case Toolkit::Slider::Property::SNAP_TO_MARKS:
1142       {
1143         sliderImpl.SetSnapToMarks( value.Get< bool >() );
1144         break;
1145       }
1146
1147       case Toolkit::Slider::Property::MARK_TOLERANCE:
1148       {
1149         sliderImpl.SetMarkTolerance( value.Get< float >() );
1150         break;
1151       }
1152     }
1153   }
1154 }
1155
1156 Property::Value Slider::GetProperty( BaseObject* object, Property::Index propertyIndex )
1157 {
1158   Property::Value value;
1159
1160   Toolkit::Slider slider = Toolkit::Slider::DownCast( Dali::BaseHandle( object ) );
1161
1162   if ( slider )
1163   {
1164     Slider& sliderImpl( GetImpl( slider ) );
1165
1166     switch ( propertyIndex )
1167     {
1168       case Toolkit::Slider::Property::LOWER_BOUND:
1169       {
1170         value = sliderImpl.GetLowerBound();
1171         break;
1172       }
1173
1174       case Toolkit::Slider::Property::UPPER_BOUND:
1175       {
1176         value = sliderImpl.GetUpperBound();
1177         break;
1178       }
1179
1180       case Toolkit::Slider::Property::VALUE:
1181       {
1182         value = sliderImpl.GetValue();
1183         break;
1184       }
1185
1186       case Toolkit::Slider::Property::HIT_REGION:
1187       {
1188         value = sliderImpl.GetHitRegion();
1189         break;
1190       }
1191
1192       case Toolkit::Slider::Property::BACKING_REGION:
1193       {
1194         value = sliderImpl.GetBackingRegion();
1195         break;
1196       }
1197
1198       case Toolkit::Slider::Property::HANDLE_REGION:
1199       {
1200         value = sliderImpl.GetHandleRegion();
1201         break;
1202       }
1203
1204       case Toolkit::Slider::Property::BACKING_IMAGE_NAME:
1205       {
1206         value = sliderImpl.GetBackingImageName();
1207         break;
1208       }
1209
1210       case Toolkit::Slider::Property::HANDLE_IMAGE_NAME:
1211       {
1212         value = sliderImpl.GetHandleImageName();
1213         break;
1214       }
1215
1216       case Toolkit::Slider::Property::PROGRESS_IMAGE_NAME:
1217       {
1218         value = sliderImpl.GetProgressImageName();
1219         break;
1220       }
1221
1222       case Toolkit::Slider::Property::POPUP_IMAGE_NAME:
1223       {
1224         value = sliderImpl.GetPopupImageName();
1225         break;
1226       }
1227
1228       case Toolkit::Slider::Property::POPUP_ARROW_IMAGE_NAME:
1229       {
1230         value = sliderImpl.GetPopupArrowImageName();
1231         break;
1232       }
1233
1234       case Toolkit::Slider::Property::DISABLE_COLOR:
1235       {
1236         value = sliderImpl.GetDisableColor();
1237         break;
1238       }
1239
1240       case Toolkit::Slider::Property::POPUP_TEXT_COLOR:
1241       {
1242         value = sliderImpl.GetPopupTextColor();
1243         break;
1244       }
1245
1246       case Toolkit::Slider::Property::VALUE_PRECISION:
1247       {
1248         value = sliderImpl.GetValuePrecision();
1249         break;
1250       }
1251
1252       case Toolkit::Slider::Property::SHOW_POPUP:
1253       {
1254         value = sliderImpl.GetShowPopup();
1255         break;
1256       }
1257
1258       case Toolkit::Slider::Property::SHOW_VALUE:
1259       {
1260         value = sliderImpl.GetShowValue();
1261         break;
1262       }
1263
1264       case Toolkit::Slider::Property::ENABLED:
1265       {
1266         value = sliderImpl.IsEnabled();
1267         break;
1268       }
1269
1270       case Toolkit::Slider::Property::MARKS:
1271       {
1272         // TODO: Need to be able to return a PropertyArray
1273         // value = sliderImpl.GetMarks();
1274         break;
1275       }
1276
1277       case Toolkit::Slider::Property::SNAP_TO_MARKS:
1278       {
1279         value = sliderImpl.GetSnapToMarks();
1280         break;
1281       }
1282
1283       case Toolkit::Slider::Property::MARK_TOLERANCE:
1284       {
1285         value = sliderImpl.GetMarkTolerance();
1286         break;
1287       }
1288     }
1289   }
1290
1291   return value;
1292 }
1293
1294 } // namespace Internal
1295
1296 } // namespace Toolkit
1297
1298 } // namespace Dali