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