56bbd339ea3b3f8880a401d0d83b96a98bf10796
[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( mHandleValueTextView )
352   {
353     std::stringstream ss;
354     ss.precision( GetValuePrecision() );
355     ss << std::fixed << clampledValue;
356     mHandleValueTextView.SetText( ss.str() );
357   }
358 }
359
360 void Slider::SetMarks( const MarkList& marks )
361 {
362   float value;
363   for( MarkList::const_iterator it = marks.begin(), itEnd = marks.end(); it != itEnd; ++it )
364   {
365     const Property::Value& propertyValue = *it;
366     propertyValue.Get( value );
367
368     mMarks.push_back( value );
369   }
370 }
371
372 const Slider::MarkList& Slider::GetMarks() const
373 {
374   return mMarks;
375 }
376
377 void Slider::SetSnapToMarks( bool snap )
378 {
379   mSnapToMarks = snap;
380 }
381
382 bool Slider::GetSnapToMarks() const
383 {
384   return mSnapToMarks;
385 }
386
387 Actor Slider::CreateHitRegion()
388 {
389   Actor hitRegion = Actor::New();
390   hitRegion.SetParentOrigin( ParentOrigin::CENTER );
391   hitRegion.SetAnchorPoint( AnchorPoint::CENTER );
392   hitRegion.TouchedSignal().Connect( this, &Slider::OnTouchEvent );
393
394   return hitRegion;
395 }
396
397 ImageActor Slider::CreateBacking()
398 {
399   ImageActor backing = ImageActor::New();
400   backing.SetParentOrigin( ParentOrigin::CENTER );
401   backing.SetAnchorPoint( AnchorPoint::CENTER );
402   backing.SetZ( BACKING_Z );
403
404   return backing;
405 }
406
407 void Slider::SetBackingImageName( const std::string& imageName )
408 {
409   if( mBacking && ( imageName.size() > 0 ) )
410   {
411     Image image = ResourceImage::New( imageName );
412     mBacking.SetImage( image );
413   }
414 }
415
416 std::string Slider::GetBackingImageName()
417 {
418   if( mBacking )
419   {
420     return ResourceImage::DownCast( mBacking.GetImage() ).GetUrl();
421   }
422
423   return std::string( "" );
424 }
425
426 ImageActor Slider::CreateProgress()
427 {
428   ImageActor progress = ImageActor::New();
429   progress.SetParentOrigin( ParentOrigin::CENTER_LEFT );
430   progress.SetAnchorPoint( AnchorPoint::CENTER_LEFT );
431   progress.SetZ( PROGRESS_Z );
432
433   return progress;
434 }
435
436 void Slider::SetProgressImageName( const std::string& imageName )
437 {
438   if( mProgress && ( imageName.size() > 0 ) )
439   {
440     Image image = ResourceImage::New( imageName );
441     mProgress.SetImage( image );
442   }
443 }
444
445 std::string Slider::GetProgressImageName()
446 {
447   if( mProgress )
448   {
449     return ResourceImage::DownCast( mProgress.GetImage()).GetUrl();
450   }
451
452   return std::string( "" );
453 }
454
455 void Slider::SetPopupImageName( const std::string& imageName )
456 {
457   mPopupImageName = imageName;
458 }
459
460 std::string Slider::GetPopupImageName()
461 {
462   return mPopupImageName;
463 }
464
465 void Slider::CreatePopupImage( const std::string& imageName )
466 {
467   if( mPopup && ( imageName.size() > 0 ) )
468   {
469     Image image = ResourceImage::New( imageName );
470     mPopup.SetImage( image );
471   }
472 }
473
474 void Slider::SetPopupArrowImageName( const std::string& imageName )
475 {
476   mPopupArrowImageName = imageName;
477 }
478
479 std::string Slider::GetPopupArrowImageName()
480 {
481   return mPopupArrowImageName;
482 }
483
484 void Slider::CreatePopupArrowImage( const std::string& imageName )
485 {
486   if( mPopupArrow && ( imageName.size() > 0 ) )
487   {
488     Image image = ResourceImage::New( imageName );
489     mPopupArrow.SetImage( image );
490   }
491 }
492
493 void Slider::ResizeProgressRegion( const Vector2& region )
494 {
495   if( mProgress )
496   {
497     mProgress.SetSize( region );
498   }
499 }
500
501 ImageActor Slider::CreateHandle()
502 {
503   ImageActor handle = ImageActor::New();
504   handle.SetParentOrigin( ParentOrigin::CENTER_LEFT );
505   handle.SetAnchorPoint( AnchorPoint::CENTER );
506   handle.SetZ( HANDLE_Z );
507
508   return handle;
509 }
510
511 ImageActor Slider::CreatePopupArrow()
512 {
513   ImageActor arrow = ImageActor::New();
514   arrow.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
515   arrow.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
516   arrow.SetZ( HANDLE_Z );
517
518   return arrow;
519 }
520
521 Toolkit::TextView Slider::CreatePopupText()
522 {
523   Toolkit::TextView textView = Toolkit::TextView::New();
524   textView.SetParentOrigin( ParentOrigin::CENTER );
525   textView.SetAnchorPoint( AnchorPoint::CENTER );
526   textView.SetSizePolicy( Toolkit::Control::Flexible, Toolkit::Control::Flexible );
527   textView.SetZ( VALUE_DISPLAY_TEXT_Z );
528   return textView;
529 }
530
531 ImageActor Slider::CreatePopup()
532 {
533   ImageActor popup = ImageActor::New();
534   popup.SetParentOrigin( ParentOrigin::TOP_CENTER );
535   popup.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
536
537   mValueTextView = CreatePopupText();
538   popup.Add( mValueTextView );
539
540   return popup;
541 }
542
543 void Slider::SetHandleImageName( const std::string& imageName )
544 {
545   if( mHandle && ( imageName.size() > 0 ) )
546   {
547     Image image = ResourceImage::New( imageName );
548     mHandle.SetImage( image );
549   }
550 }
551
552 std::string Slider::GetHandleImageName()
553 {
554   if( mHandle )
555   {
556     return ResourceImage::DownCast( mHandle.GetImage() ).GetUrl();
557   }
558
559   return std::string( "" );
560 }
561
562 void Slider::ResizeHandleRegion( const Vector2& region )
563 {
564   if( mHandle )
565   {
566     mHandle.SetSize( region );
567   }
568 }
569
570 void Slider::CreateHandleValueDisplay()
571 {
572   if( mHandle && !mHandleValueTextView )
573   {
574     mHandleValueTextView = Toolkit::TextView::New();
575     mHandleValueTextView.SetParentOrigin( ParentOrigin::CENTER );
576     mHandleValueTextView.SetAnchorPoint( AnchorPoint::CENTER );
577     mHandleValueTextView.SetSize( GetHandleRegion() );
578     mHandleValueTextView.SetZ( HANDLE_VALUE_DISPLAY_TEXT_Z );
579     mHandle.Add( mHandleValueTextView );
580   }
581 }
582
583 void Slider::DestroyHandleValueDisplay()
584 {
585   if(mHandleValueTextView)
586   {
587     mHandleValueTextView.Unparent();
588     mHandleValueTextView.Reset();
589   }
590 }
591
592 void Slider::SetPopupTextColor( const Vector4& color )
593 {
594   mPopupTextColor = color;
595 }
596
597 Actor Slider::CreateValueDisplay()
598 {
599   Actor popup = Actor::New();
600   popup.SetParentOrigin( ParentOrigin::TOP_CENTER );
601   popup.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
602
603   mPopupArrow = CreatePopupArrow();
604   popup.Add( mPopupArrow );
605
606   mPopup = CreatePopup();
607   mPopup.SetSize( 0.0f, VALUE_POPUP_HEIGHT );
608   mPopupArrow.Add( mPopup );
609
610   return popup;
611 }
612
613 Toolkit::Slider::ValueChangedSignalType& Slider::ValueChangedSignal()
614 {
615   return mValueChangedSignal;
616 }
617
618 Toolkit::Slider::ValueChangedSignalType& Slider::SlidingFinishedSignal()
619 {
620   return mSlidingFinishedSignal;
621 }
622
623 Toolkit::Slider::MarkSignalType& Slider::MarkSignal()
624 {
625   return mMarkSignal;
626 }
627
628 void Slider::UpdateSkin()
629 {
630   switch( mState )
631   {
632     case NORMAL:
633     {
634       mBacking.SetColor( Color::WHITE );
635       mHandle.SetColor( Color::WHITE );
636       mProgress.SetColor( Color::WHITE );
637       break;
638     }
639     case DISABLED:
640     {
641       Vector4 disableColor = GetDisableColor();
642       mBacking.SetColor( disableColor );
643       mHandle.SetColor( disableColor );
644       mProgress.SetColor( disableColor );
645       break;
646     }
647     case PRESSED:
648     {
649       break;
650     }
651     case FOCUSED:
652     {
653       break;
654     }
655   }
656 }
657
658 void Slider::CreateChildren()
659 {
660   Actor self = Self();
661
662   // Hit region
663   mHitArea = CreateHitRegion();
664   mPanDetector = PanGestureDetector::New();
665   mPanDetector.Attach( mHitArea );
666   mPanDetector.DetectedSignal().Connect( this, &Slider::OnPan );
667   self.Add( mHitArea );
668
669   // Background
670   mBacking = CreateBacking();
671   self.Add( mBacking );
672
673   // Progress bar
674   mProgress = CreateProgress();
675   mBacking.Add( mProgress );
676
677   // Handle
678   mHandle = CreateHandle();
679   mBacking.Add( mHandle );
680 }
681
682 void Slider::SetHitRegion( const Vector2& size )
683 {
684   mHitRegion = size;
685
686   if( mHitArea )
687   {
688     mHitArea.SetSize( mHitRegion );
689   }
690 }
691
692 const Vector2& Slider::GetHitRegion() const
693 {
694   return mHitRegion;
695 }
696
697 void Slider::AddPopup()
698 {
699   if( !mValueDisplay )
700   {
701     mValueDisplay = CreateValueDisplay();
702     mValueDisplay.SetVisible( false );
703     mHandle.Add( mValueDisplay );
704
705     CreatePopupImage( GetPopupImageName() );
706     CreatePopupArrowImage( GetPopupArrowImageName() );
707
708     mValueTimer = Timer::New( VALUE_VIEW_SHOW_DURATION );
709     mValueTimer.TickSignal().Connect( this, &Slider::HideValueView );
710   }
711 }
712
713 void Slider::RemovePopup()
714 {
715   if( mValueDisplay )
716   {
717     mPopup.Unparent();
718     mPopup.Reset();
719
720     mPopupArrow.Unparent();
721     mPopupArrow.Reset();
722
723     mValueDisplay.Unparent();
724     mValueDisplay.Reset();
725
726     mValueTimer.TickSignal().Disconnect( this, &Slider::HideValueView );
727     mValueTimer.Reset();
728   }
729 }
730
731
732 float Slider::MarkFilter( float value )
733 {
734   const float MARK_TOLERANCE = GetMarkTolerance();
735
736   float mark;
737   for( MarkList::iterator it = mMarks.begin(), itEnd = mMarks.end(); it != itEnd; ++it )
738   {
739     const Property::Value& propertyValue = *it;
740     propertyValue.Get( mark );
741     mark = MapValuePercentage( mark );
742
743     // If close to a mark, return the mark
744     if( fabsf( mark - value ) < MARK_TOLERANCE )
745     {
746       return mark;
747     }
748   }
749
750   return value;
751 }
752
753 float Slider::SnapToMark( float value )
754 {
755   float closestMark = value;
756   float closestDist = std::numeric_limits<float>::max();
757
758   float mark;
759   for( MarkList::iterator it = mMarks.begin(), itEnd = mMarks.end(); it != itEnd; ++it )
760   {
761     const Property::Value& propertyValue = *it;
762     propertyValue.Get( mark );
763     mark = MapValuePercentage( mark );
764
765     float dist = fabsf( mark - value );
766     if( dist < closestDist )
767     {
768       closestDist = dist;
769       closestMark = mark;
770     }
771   }
772
773   return closestMark;
774 }
775
776 bool Slider::MarkReached( float value, int& outIndex )
777 {
778   const float MARK_TOLERANCE = GetMarkTolerance();
779
780   // Binary search
781   int head = 0,
782       tail = mMarks.size() - 1;
783   int current;
784   float mark;
785
786   while( head <= tail )
787   {
788     current = head + ( tail - head ) / 2;
789
790     const Property::Value& propertyValue = mMarks[ current ];
791     propertyValue.Get( mark );
792     mark = MapValuePercentage( mark );
793
794     if( fabsf( mark - value ) < MARK_TOLERANCE )
795     {
796       outIndex = current;
797       return true;
798     }
799
800     if( value < mark )
801     {
802       tail = current - 1;
803     }
804     else
805     {
806       head = current + 1;
807     }
808   }
809
810   return false;
811 }
812
813 bool Slider::HideValueView()
814 {
815   if( mValueDisplay )
816   {
817     mValueDisplay.SetVisible( false );
818   }
819
820   return false;
821 }
822
823 void Slider::SetLowerBound( float bound )
824 {
825   mLowerBound = bound;
826   DisplayValue( GetValue(), false );
827 }
828
829 float Slider::GetLowerBound() const
830 {
831   return mLowerBound;
832 }
833
834 void Slider::SetUpperBound( float bound )
835 {
836   mUpperBound = bound;
837   DisplayValue( GetValue(), false );
838 }
839
840 float Slider::GetUpperBound() const
841 {
842   return mUpperBound;
843 }
844
845 void Slider::SetValue( float value )
846 {
847   mValue = value;
848   DisplayValue( mValue, true );
849 }
850
851 float Slider::GetValue() const
852 {
853   return mValue;
854 }
855
856 void Slider::SetBackingRegion( const Vector2& region )
857 {
858   mBackingRegion = region;
859
860   if( mBacking )
861   {
862     mBacking.SetSize( mBackingRegion );
863   }
864
865   ResizeProgressRegion( Vector2( 0.0f, mBackingRegion.y ) );
866
867   mDomain = CalcDomain( mBackingRegion );
868
869   DisplayValue( GetValue(), false );  // Set the progress bar to correct width
870 }
871
872 const Vector2& Slider::GetBackingRegion() const
873 {
874   return mBackingRegion;
875 }
876
877 void Slider::SetHandleRegion( const Vector2& region )
878 {
879   mHandleRegionSize = region;
880
881   ResizeHandleRegion( mHandleRegionSize );
882
883   Vector2 hitRegion = GetHitRegion();
884   hitRegion.x += mHandleRegionSize.x;
885   SetHitRegion( hitRegion );
886 }
887
888 const Vector2& Slider::GetHandleRegion() const
889 {
890   return mHandleRegionSize;
891 }
892
893 void Slider::SetDisableColor( const Vector4& color )
894 {
895   mDisableColor = color;
896
897   UpdateSkin();
898 }
899
900 Vector4 Slider::GetDisableColor() const
901 {
902   return mDisableColor;
903 }
904
905 Vector4 Slider::GetPopupTextColor() const
906 {
907   return mPopupTextColor;
908 }
909
910 void Slider::SetValuePrecision( int precision )
911 {
912   mValuePrecision = precision;
913 }
914
915 int Slider::GetValuePrecision() const
916 {
917   return mValuePrecision;
918 }
919
920 void Slider::SetShowPopup( bool showPopup )
921 {
922   mShowPopup = showPopup;
923
924   // Value display
925   if( mShowPopup )
926   {
927     AddPopup();
928   }
929   else
930   {
931     RemovePopup();
932   }
933 }
934
935 bool Slider::GetShowPopup() const
936 {
937   return mShowPopup;
938 }
939
940 void Slider::SetShowValue( bool showValue )
941 {
942   mShowValue = showValue;
943
944   if( mShowValue )
945   {
946     CreateHandleValueDisplay();
947   }
948   else
949   {
950     DestroyHandleValueDisplay();
951   }
952 }
953
954 bool Slider::GetShowValue() const
955 {
956   return mShowValue;
957 }
958
959 void Slider::SetEnabled( bool enabled )
960 {
961   if( enabled )
962   {
963     mState = NORMAL;
964   }
965   else
966   {
967     mState = DISABLED;
968   }
969
970   UpdateSkin();
971 }
972
973 bool Slider::IsEnabled() const
974 {
975   return mState != DISABLED;
976 }
977
978 void Slider::SetMarkTolerance( float tolerance )
979 {
980   mMarkTolerance = tolerance;
981 }
982
983 float Slider::GetMarkTolerance() const
984 {
985   return mMarkTolerance;
986 }
987
988 // Static class method to support script connecting signals
989 bool Slider::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
990 {
991   Dali::BaseHandle handle( object );
992
993   bool connected = true;
994   Toolkit::Slider slider = Toolkit::Slider::DownCast( handle );
995
996   if( 0 == strcmp( signalName.c_str(), SIGNAL_VALUE_CHANGED ) )
997   {
998     slider.ValueChangedSignal().Connect( tracker, functor );
999   }
1000   else if( 0 == strcmp( signalName.c_str(), SIGNAL_MARK ) )
1001   {
1002     slider.MarkSignal().Connect( tracker, functor );
1003   }
1004   else
1005   {
1006     // signalName does not match any signal
1007     connected = false;
1008   }
1009
1010   return connected;
1011 }
1012
1013 void Slider::DisplayPopup( float value )
1014 {
1015   // Value displayDoConnectSignal
1016   if( mValueTextView )
1017   {
1018     std::stringstream ss;
1019     ss.precision( GetValuePrecision() );
1020     ss << std::fixed << value;
1021     mValueTextView.SetText( ss.str() );
1022     TextStyle style;
1023     style.SetTextColor( GetPopupTextColor() );
1024     mValueTextView.SetStyleToCurrentText( style, TextStyle::COLOR);
1025
1026     if( mValueDisplay )
1027     {
1028       Font font = Font::New();
1029       float popupWidth = font.MeasureText( ss.str() ).x + VALUE_POPUP_MARGIN * 2.0f;
1030       if( popupWidth < VALUE_POPUP_MIN_WIDTH )
1031       {
1032         popupWidth = VALUE_POPUP_MIN_WIDTH;
1033       }
1034
1035       mPopup.SetSize( popupWidth, VALUE_POPUP_HEIGHT );
1036       mValueDisplay.SetVisible( true );
1037
1038       mValueTimer.SetInterval( VALUE_VIEW_SHOW_DURATION );
1039     }
1040   }
1041 }
1042
1043 void Slider::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
1044 {
1045   Toolkit::Slider slider = Toolkit::Slider::DownCast( Dali::BaseHandle( object ) );
1046
1047   if ( slider )
1048   {
1049     Slider& sliderImpl( GetImpl( slider ) );
1050
1051     switch ( propertyIndex )
1052     {
1053       case Toolkit::Slider::Property::LOWER_BOUND:
1054       {
1055         sliderImpl.SetLowerBound( value.Get< float >() );
1056         break;
1057       }
1058
1059       case Toolkit::Slider::Property::UPPER_BOUND:
1060       {
1061         sliderImpl.SetUpperBound( value.Get< float >() );
1062         break;
1063       }
1064
1065       case Toolkit::Slider::Property::VALUE:
1066       {
1067         sliderImpl.SetValue( value.Get< float >() );
1068         break;
1069       }
1070
1071       case Toolkit::Slider::Property::HIT_REGION:
1072       {
1073         sliderImpl.SetHitRegion( value.Get< Vector2 >() );
1074         break;
1075       }
1076
1077       case Toolkit::Slider::Property::BACKING_REGION:
1078       {
1079         sliderImpl.SetBackingRegion( value.Get< Vector2 >() );
1080         break;
1081       }
1082
1083       case Toolkit::Slider::Property::HANDLE_REGION:
1084       {
1085         sliderImpl.SetHandleRegion( value.Get< Vector2 >() );
1086         break;
1087       }
1088
1089       case Toolkit::Slider::Property::BACKING_IMAGE_NAME:
1090       {
1091         sliderImpl.SetBackingImageName( value.Get< std::string >() );
1092         break;
1093       }
1094
1095       case Toolkit::Slider::Property::HANDLE_IMAGE_NAME:
1096       {
1097         sliderImpl.SetHandleImageName( value.Get< std::string >() );
1098         break;
1099       }
1100
1101       case Toolkit::Slider::Property::PROGRESS_IMAGE_NAME:
1102       {
1103         sliderImpl.SetProgressImageName( value.Get< std::string >() );
1104         break;
1105       }
1106
1107       case Toolkit::Slider::Property::POPUP_IMAGE_NAME:
1108       {
1109         sliderImpl.SetPopupImageName( value.Get< std::string >() );
1110         break;
1111       }
1112
1113       case Toolkit::Slider::Property::POPUP_ARROW_IMAGE_NAME:
1114       {
1115         sliderImpl.SetPopupArrowImageName( value.Get< std::string >() );
1116         break;
1117       }
1118
1119       case Toolkit::Slider::Property::DISABLE_COLOR:
1120       {
1121         sliderImpl.SetDisableColor( value.Get< Vector4 >() );
1122         break;
1123       }
1124
1125       case Toolkit::Slider::Property::POPUP_TEXT_COLOR:
1126       {
1127         sliderImpl.SetPopupTextColor( value.Get< Vector4 >() );
1128         break;
1129       }
1130
1131       case Toolkit::Slider::Property::VALUE_PRECISION:
1132       {
1133         sliderImpl.SetValuePrecision( value.Get< int >() );
1134         break;
1135       }
1136
1137       case Toolkit::Slider::Property::SHOW_POPUP:
1138       {
1139         sliderImpl.SetShowPopup( value.Get< bool >() );
1140         break;
1141       }
1142
1143       case Toolkit::Slider::Property::SHOW_VALUE:
1144       {
1145         sliderImpl.SetShowValue( value.Get< bool >() );
1146         break;
1147       }
1148
1149       case Toolkit::Slider::Property::ENABLED:
1150       {
1151         sliderImpl.SetEnabled( value.Get< bool >() );
1152         break;
1153       }
1154
1155       case Toolkit::Slider::Property::MARKS:
1156       {
1157         sliderImpl.SetMarks( value.Get< Property::Array >() );
1158         break;
1159       }
1160
1161       case Toolkit::Slider::Property::SNAP_TO_MARKS:
1162       {
1163         sliderImpl.SetSnapToMarks( value.Get< bool >() );
1164         break;
1165       }
1166
1167       case Toolkit::Slider::Property::MARK_TOLERANCE:
1168       {
1169         sliderImpl.SetMarkTolerance( value.Get< float >() );
1170         break;
1171       }
1172     }
1173   }
1174 }
1175
1176 Property::Value Slider::GetProperty( BaseObject* object, Property::Index propertyIndex )
1177 {
1178   Property::Value value;
1179
1180   Toolkit::Slider slider = Toolkit::Slider::DownCast( Dali::BaseHandle( object ) );
1181
1182   if ( slider )
1183   {
1184     Slider& sliderImpl( GetImpl( slider ) );
1185
1186     switch ( propertyIndex )
1187     {
1188       case Toolkit::Slider::Property::LOWER_BOUND:
1189       {
1190         value = sliderImpl.GetLowerBound();
1191         break;
1192       }
1193
1194       case Toolkit::Slider::Property::UPPER_BOUND:
1195       {
1196         value = sliderImpl.GetUpperBound();
1197         break;
1198       }
1199
1200       case Toolkit::Slider::Property::VALUE:
1201       {
1202         value = sliderImpl.GetValue();
1203         break;
1204       }
1205
1206       case Toolkit::Slider::Property::HIT_REGION:
1207       {
1208         value = sliderImpl.GetHitRegion();
1209         break;
1210       }
1211
1212       case Toolkit::Slider::Property::BACKING_REGION:
1213       {
1214         value = sliderImpl.GetBackingRegion();
1215         break;
1216       }
1217
1218       case Toolkit::Slider::Property::HANDLE_REGION:
1219       {
1220         value = sliderImpl.GetHandleRegion();
1221         break;
1222       }
1223
1224       case Toolkit::Slider::Property::BACKING_IMAGE_NAME:
1225       {
1226         value = sliderImpl.GetBackingImageName();
1227         break;
1228       }
1229
1230       case Toolkit::Slider::Property::HANDLE_IMAGE_NAME:
1231       {
1232         value = sliderImpl.GetHandleImageName();
1233         break;
1234       }
1235
1236       case Toolkit::Slider::Property::PROGRESS_IMAGE_NAME:
1237       {
1238         value = sliderImpl.GetProgressImageName();
1239         break;
1240       }
1241
1242       case Toolkit::Slider::Property::POPUP_IMAGE_NAME:
1243       {
1244         value = sliderImpl.GetPopupImageName();
1245         break;
1246       }
1247
1248       case Toolkit::Slider::Property::POPUP_ARROW_IMAGE_NAME:
1249       {
1250         value = sliderImpl.GetPopupArrowImageName();
1251         break;
1252       }
1253
1254       case Toolkit::Slider::Property::DISABLE_COLOR:
1255       {
1256         value = sliderImpl.GetDisableColor();
1257         break;
1258       }
1259
1260       case Toolkit::Slider::Property::POPUP_TEXT_COLOR:
1261       {
1262         value = sliderImpl.GetPopupTextColor();
1263         break;
1264       }
1265
1266       case Toolkit::Slider::Property::VALUE_PRECISION:
1267       {
1268         value = sliderImpl.GetValuePrecision();
1269         break;
1270       }
1271
1272       case Toolkit::Slider::Property::SHOW_POPUP:
1273       {
1274         value = sliderImpl.GetShowPopup();
1275         break;
1276       }
1277
1278       case Toolkit::Slider::Property::SHOW_VALUE:
1279       {
1280         value = sliderImpl.GetShowValue();
1281         break;
1282       }
1283
1284       case Toolkit::Slider::Property::ENABLED:
1285       {
1286         value = sliderImpl.IsEnabled();
1287         break;
1288       }
1289
1290       case Toolkit::Slider::Property::MARKS:
1291       {
1292         // TODO: Need to be able to return a PropertyArray
1293         // value = sliderImpl.GetMarks();
1294         break;
1295       }
1296
1297       case Toolkit::Slider::Property::SNAP_TO_MARKS:
1298       {
1299         value = sliderImpl.GetSnapToMarks();
1300         break;
1301       }
1302
1303       case Toolkit::Slider::Property::MARK_TOLERANCE:
1304       {
1305         value = sliderImpl.GetMarkTolerance();
1306         break;
1307       }
1308     }
1309   }
1310
1311   return value;
1312 }
1313
1314 } // namespace Internal
1315
1316 } // namespace Toolkit
1317
1318 } // namespace Dali