Merge branch 'devel/master' into devel/new_mesh
[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     mHandle.Add( mHandleValueTextLabel );
574   }
575 }
576
577 void Slider::DestroyHandleValueDisplay()
578 {
579   UnparentAndReset(mHandleValueTextLabel);
580 }
581
582 void Slider::SetPopupTextColor( const Vector4& color )
583 {
584   mPopupTextColor = color;
585 }
586
587 Actor Slider::CreateValueDisplay()
588 {
589   Actor popup = Actor::New();
590   popup.SetParentOrigin( ParentOrigin::TOP_CENTER );
591   popup.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
592
593   mPopupArrow = CreatePopupArrow();
594   popup.Add( mPopupArrow );
595
596   mPopup = CreatePopup();
597   mPopup.SetSize( 0.0f, VALUE_POPUP_HEIGHT );
598   mPopupArrow.Add( mPopup );
599
600   return popup;
601 }
602
603 Toolkit::Slider::ValueChangedSignalType& Slider::ValueChangedSignal()
604 {
605   return mValueChangedSignal;
606 }
607
608 Toolkit::Slider::ValueChangedSignalType& Slider::SlidingFinishedSignal()
609 {
610   return mSlidingFinishedSignal;
611 }
612
613 Toolkit::Slider::MarkSignalType& Slider::MarkSignal()
614 {
615   return mMarkSignal;
616 }
617
618 void Slider::UpdateSkin()
619 {
620   switch( mState )
621   {
622     case NORMAL:
623     {
624       mBacking.SetColor( Color::WHITE );
625       mHandle.SetColor( Color::WHITE );
626       mProgress.SetColor( Color::WHITE );
627       break;
628     }
629     case DISABLED:
630     {
631       Vector4 disableColor = GetDisableColor();
632       mBacking.SetColor( disableColor );
633       mHandle.SetColor( disableColor );
634       mProgress.SetColor( disableColor );
635       break;
636     }
637     case PRESSED:
638     {
639       break;
640     }
641     case FOCUSED:
642     {
643       break;
644     }
645   }
646 }
647
648 void Slider::CreateChildren()
649 {
650   Actor self = Self();
651
652   // Hit region
653   mHitArea = CreateHitRegion();
654   mPanDetector = PanGestureDetector::New();
655   mPanDetector.Attach( mHitArea );
656   mPanDetector.DetectedSignal().Connect( this, &Slider::OnPan );
657   self.Add( mHitArea );
658
659   // Background
660   mBacking = CreateBacking();
661   self.Add( mBacking );
662
663   // Progress bar
664   mProgress = CreateProgress();
665   mBacking.Add( mProgress );
666
667   // Handle
668   mHandle = CreateHandle();
669   mBacking.Add( mHandle );
670 }
671
672 void Slider::SetHitRegion( const Vector2& size )
673 {
674   mHitRegion = size;
675
676   if( mHitArea )
677   {
678     mHitArea.SetSize( mHitRegion );
679   }
680 }
681
682 const Vector2& Slider::GetHitRegion() const
683 {
684   return mHitRegion;
685 }
686
687 void Slider::AddPopup()
688 {
689   if( !mValueDisplay )
690   {
691     mValueDisplay = CreateValueDisplay();
692     mValueDisplay.SetVisible( false );
693     mHandle.Add( mValueDisplay );
694
695     CreatePopupImage( GetPopupImageName() );
696     CreatePopupArrowImage( GetPopupArrowImageName() );
697
698     mValueTimer = Timer::New( VALUE_VIEW_SHOW_DURATION );
699     mValueTimer.TickSignal().Connect( this, &Slider::HideValueView );
700   }
701 }
702
703 void Slider::RemovePopup()
704 {
705   if( mValueDisplay )
706   {
707     mPopup.Unparent();
708     mPopup.Reset();
709
710     mPopupArrow.Unparent();
711     mPopupArrow.Reset();
712
713     mValueDisplay.Unparent();
714     mValueDisplay.Reset();
715
716     mValueTimer.TickSignal().Disconnect( this, &Slider::HideValueView );
717     mValueTimer.Reset();
718   }
719 }
720
721
722 float Slider::MarkFilter( float value )
723 {
724   const float MARK_TOLERANCE = GetMarkTolerance();
725
726   float mark;
727   for( MarkList::SizeType i = 0; i < mMarks.Count(); ++i)
728   {
729     const Property::Value& propertyValue = mMarks[i];
730     propertyValue.Get( mark );
731     mark = MapValuePercentage( mark );
732
733     // If close to a mark, return the mark
734     if( fabsf( mark - value ) < MARK_TOLERANCE )
735     {
736       return mark;
737     }
738   }
739
740   return value;
741 }
742
743 float Slider::SnapToMark( float value )
744 {
745   float closestMark = value;
746   float closestDist = std::numeric_limits<float>::max();
747
748   float mark;
749   for( MarkList::SizeType  i = 0; i < mMarks.Count(); ++i)
750   {
751     const Property::Value& propertyValue = mMarks[i];
752     propertyValue.Get( mark );
753     mark = MapValuePercentage( mark );
754
755     float dist = fabsf( mark - value );
756     if( dist < closestDist )
757     {
758       closestDist = dist;
759       closestMark = mark;
760     }
761   }
762
763   return closestMark;
764 }
765
766 bool Slider::MarkReached( float value, int& outIndex )
767 {
768   const float MARK_TOLERANCE = GetMarkTolerance();
769
770   // Binary search
771   int head = 0,
772       tail = mMarks.Size() - 1;
773   int current;
774   float mark;
775
776   while( head <= tail )
777   {
778     current = head + ( tail - head ) / 2;
779
780     const Property::Value& propertyValue = mMarks[ current ];
781     propertyValue.Get( mark );
782     mark = MapValuePercentage( mark );
783
784     if( fabsf( mark - value ) < MARK_TOLERANCE )
785     {
786       outIndex = current;
787       return true;
788     }
789
790     if( value < mark )
791     {
792       tail = current - 1;
793     }
794     else
795     {
796       head = current + 1;
797     }
798   }
799
800   return false;
801 }
802
803 bool Slider::HideValueView()
804 {
805   if( mValueDisplay )
806   {
807     mValueDisplay.SetVisible( false );
808   }
809
810   return false;
811 }
812
813 void Slider::SetLowerBound( float bound )
814 {
815   mLowerBound = bound;
816   DisplayValue( GetValue(), false );
817 }
818
819 float Slider::GetLowerBound() const
820 {
821   return mLowerBound;
822 }
823
824 void Slider::SetUpperBound( float bound )
825 {
826   mUpperBound = bound;
827   DisplayValue( GetValue(), false );
828 }
829
830 float Slider::GetUpperBound() const
831 {
832   return mUpperBound;
833 }
834
835 void Slider::SetValue( float value )
836 {
837   mValue = value;
838   DisplayValue( mValue, true );
839 }
840
841 float Slider::GetValue() const
842 {
843   return mValue;
844 }
845
846 void Slider::SetBackingRegion( const Vector2& region )
847 {
848   mBackingRegion = region;
849
850   if( mBacking )
851   {
852     mBacking.SetSize( mBackingRegion );
853   }
854
855   ResizeProgressRegion( Vector2( 0.0f, mBackingRegion.y ) );
856
857   mDomain = CalcDomain( mBackingRegion );
858
859   DisplayValue( GetValue(), false );  // Set the progress bar to correct width
860 }
861
862 const Vector2& Slider::GetBackingRegion() const
863 {
864   return mBackingRegion;
865 }
866
867 void Slider::SetHandleRegion( const Vector2& region )
868 {
869   mHandleRegionSize = region;
870
871   ResizeHandleRegion( mHandleRegionSize );
872
873   Vector2 hitRegion = GetHitRegion();
874   hitRegion.x += mHandleRegionSize.x;
875   SetHitRegion( hitRegion );
876 }
877
878 const Vector2& Slider::GetHandleRegion() const
879 {
880   return mHandleRegionSize;
881 }
882
883 void Slider::SetDisableColor( const Vector4& color )
884 {
885   mDisableColor = color;
886
887   UpdateSkin();
888 }
889
890 Vector4 Slider::GetDisableColor() const
891 {
892   return mDisableColor;
893 }
894
895 Vector4 Slider::GetPopupTextColor() const
896 {
897   return mPopupTextColor;
898 }
899
900 void Slider::SetValuePrecision( int precision )
901 {
902   mValuePrecision = precision;
903 }
904
905 int Slider::GetValuePrecision() const
906 {
907   return mValuePrecision;
908 }
909
910 void Slider::SetShowPopup( bool showPopup )
911 {
912   mShowPopup = showPopup;
913
914   // Value display
915   if( mShowPopup )
916   {
917     AddPopup();
918   }
919   else
920   {
921     RemovePopup();
922   }
923 }
924
925 bool Slider::GetShowPopup() const
926 {
927   return mShowPopup;
928 }
929
930 void Slider::SetShowValue( bool showValue )
931 {
932   mShowValue = showValue;
933
934   if( mShowValue )
935   {
936     CreateHandleValueDisplay();
937   }
938   else
939   {
940     DestroyHandleValueDisplay();
941   }
942 }
943
944 bool Slider::GetShowValue() const
945 {
946   return mShowValue;
947 }
948
949 void Slider::SetEnabled( bool enabled )
950 {
951   if( enabled )
952   {
953     mState = NORMAL;
954   }
955   else
956   {
957     mState = DISABLED;
958   }
959
960   UpdateSkin();
961 }
962
963 bool Slider::IsEnabled() const
964 {
965   return mState != DISABLED;
966 }
967
968 void Slider::SetMarkTolerance( float tolerance )
969 {
970   mMarkTolerance = tolerance;
971 }
972
973 float Slider::GetMarkTolerance() const
974 {
975   return mMarkTolerance;
976 }
977
978 // Static class method to support script connecting signals
979 bool Slider::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
980 {
981   Dali::BaseHandle handle( object );
982
983   bool connected = true;
984   Toolkit::Slider slider = Toolkit::Slider::DownCast( handle );
985
986   if( 0 == strcmp( signalName.c_str(), SIGNAL_VALUE_CHANGED ) )
987   {
988     slider.ValueChangedSignal().Connect( tracker, functor );
989   }
990   else if( 0 == strcmp( signalName.c_str(), SIGNAL_MARK ) )
991   {
992     slider.MarkSignal().Connect( tracker, functor );
993   }
994   else
995   {
996     // signalName does not match any signal
997     connected = false;
998   }
999
1000   return connected;
1001 }
1002
1003 void Slider::DisplayPopup( float value )
1004 {
1005   // Value displayDoConnectSignal
1006   if( mValueTextLabel )
1007   {
1008     std::stringstream ss;
1009     ss.precision( GetValuePrecision() );
1010     ss << std::fixed << value;
1011     mValueTextLabel.SetProperty( Toolkit::TextLabel::Property::TEXT, ss.str() );
1012
1013     if( mValueDisplay )
1014     {
1015       mValueDisplay.SetVisible( true );
1016
1017       mValueTimer.SetInterval( VALUE_VIEW_SHOW_DURATION );
1018     }
1019   }
1020 }
1021
1022 void Slider::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
1023 {
1024   Toolkit::Slider slider = Toolkit::Slider::DownCast( Dali::BaseHandle( object ) );
1025
1026   if ( slider )
1027   {
1028     Slider& sliderImpl( GetImpl( slider ) );
1029
1030     switch ( propertyIndex )
1031     {
1032       case Toolkit::Slider::Property::LOWER_BOUND:
1033       {
1034         sliderImpl.SetLowerBound( value.Get< float >() );
1035         break;
1036       }
1037
1038       case Toolkit::Slider::Property::UPPER_BOUND:
1039       {
1040         sliderImpl.SetUpperBound( value.Get< float >() );
1041         break;
1042       }
1043
1044       case Toolkit::Slider::Property::VALUE:
1045       {
1046         sliderImpl.SetValue( value.Get< float >() );
1047         break;
1048       }
1049
1050       case Toolkit::Slider::Property::HIT_REGION:
1051       {
1052         sliderImpl.SetHitRegion( value.Get< Vector2 >() );
1053         break;
1054       }
1055
1056       case Toolkit::Slider::Property::BACKING_REGION:
1057       {
1058         sliderImpl.SetBackingRegion( value.Get< Vector2 >() );
1059         break;
1060       }
1061
1062       case Toolkit::Slider::Property::HANDLE_REGION:
1063       {
1064         sliderImpl.SetHandleRegion( value.Get< Vector2 >() );
1065         break;
1066       }
1067
1068       case Toolkit::Slider::Property::BACKING_IMAGE_NAME:
1069       {
1070         sliderImpl.SetBackingImageName( value.Get< std::string >() );
1071         break;
1072       }
1073
1074       case Toolkit::Slider::Property::HANDLE_IMAGE_NAME:
1075       {
1076         sliderImpl.SetHandleImageName( value.Get< std::string >() );
1077         break;
1078       }
1079
1080       case Toolkit::Slider::Property::PROGRESS_IMAGE_NAME:
1081       {
1082         sliderImpl.SetProgressImageName( value.Get< std::string >() );
1083         break;
1084       }
1085
1086       case Toolkit::Slider::Property::POPUP_IMAGE_NAME:
1087       {
1088         sliderImpl.SetPopupImageName( value.Get< std::string >() );
1089         break;
1090       }
1091
1092       case Toolkit::Slider::Property::POPUP_ARROW_IMAGE_NAME:
1093       {
1094         sliderImpl.SetPopupArrowImageName( value.Get< std::string >() );
1095         break;
1096       }
1097
1098       case Toolkit::Slider::Property::DISABLE_COLOR:
1099       {
1100         sliderImpl.SetDisableColor( value.Get< Vector4 >() );
1101         break;
1102       }
1103
1104       case Toolkit::Slider::Property::POPUP_TEXT_COLOR:
1105       {
1106         sliderImpl.SetPopupTextColor( value.Get< Vector4 >() );
1107         break;
1108       }
1109
1110       case Toolkit::Slider::Property::VALUE_PRECISION:
1111       {
1112         sliderImpl.SetValuePrecision( value.Get< int >() );
1113         break;
1114       }
1115
1116       case Toolkit::Slider::Property::SHOW_POPUP:
1117       {
1118         sliderImpl.SetShowPopup( value.Get< bool >() );
1119         break;
1120       }
1121
1122       case Toolkit::Slider::Property::SHOW_VALUE:
1123       {
1124         sliderImpl.SetShowValue( value.Get< bool >() );
1125         break;
1126       }
1127
1128       case Toolkit::Slider::Property::ENABLED:
1129       {
1130         sliderImpl.SetEnabled( value.Get< bool >() );
1131         break;
1132       }
1133
1134       case Toolkit::Slider::Property::MARKS:
1135       {
1136         sliderImpl.SetMarks( value.Get< Property::Array >() );
1137         break;
1138       }
1139
1140       case Toolkit::Slider::Property::SNAP_TO_MARKS:
1141       {
1142         sliderImpl.SetSnapToMarks( value.Get< bool >() );
1143         break;
1144       }
1145
1146       case Toolkit::Slider::Property::MARK_TOLERANCE:
1147       {
1148         sliderImpl.SetMarkTolerance( value.Get< float >() );
1149         break;
1150       }
1151     }
1152   }
1153 }
1154
1155 Property::Value Slider::GetProperty( BaseObject* object, Property::Index propertyIndex )
1156 {
1157   Property::Value value;
1158
1159   Toolkit::Slider slider = Toolkit::Slider::DownCast( Dali::BaseHandle( object ) );
1160
1161   if ( slider )
1162   {
1163     Slider& sliderImpl( GetImpl( slider ) );
1164
1165     switch ( propertyIndex )
1166     {
1167       case Toolkit::Slider::Property::LOWER_BOUND:
1168       {
1169         value = sliderImpl.GetLowerBound();
1170         break;
1171       }
1172
1173       case Toolkit::Slider::Property::UPPER_BOUND:
1174       {
1175         value = sliderImpl.GetUpperBound();
1176         break;
1177       }
1178
1179       case Toolkit::Slider::Property::VALUE:
1180       {
1181         value = sliderImpl.GetValue();
1182         break;
1183       }
1184
1185       case Toolkit::Slider::Property::HIT_REGION:
1186       {
1187         value = sliderImpl.GetHitRegion();
1188         break;
1189       }
1190
1191       case Toolkit::Slider::Property::BACKING_REGION:
1192       {
1193         value = sliderImpl.GetBackingRegion();
1194         break;
1195       }
1196
1197       case Toolkit::Slider::Property::HANDLE_REGION:
1198       {
1199         value = sliderImpl.GetHandleRegion();
1200         break;
1201       }
1202
1203       case Toolkit::Slider::Property::BACKING_IMAGE_NAME:
1204       {
1205         value = sliderImpl.GetBackingImageName();
1206         break;
1207       }
1208
1209       case Toolkit::Slider::Property::HANDLE_IMAGE_NAME:
1210       {
1211         value = sliderImpl.GetHandleImageName();
1212         break;
1213       }
1214
1215       case Toolkit::Slider::Property::PROGRESS_IMAGE_NAME:
1216       {
1217         value = sliderImpl.GetProgressImageName();
1218         break;
1219       }
1220
1221       case Toolkit::Slider::Property::POPUP_IMAGE_NAME:
1222       {
1223         value = sliderImpl.GetPopupImageName();
1224         break;
1225       }
1226
1227       case Toolkit::Slider::Property::POPUP_ARROW_IMAGE_NAME:
1228       {
1229         value = sliderImpl.GetPopupArrowImageName();
1230         break;
1231       }
1232
1233       case Toolkit::Slider::Property::DISABLE_COLOR:
1234       {
1235         value = sliderImpl.GetDisableColor();
1236         break;
1237       }
1238
1239       case Toolkit::Slider::Property::POPUP_TEXT_COLOR:
1240       {
1241         value = sliderImpl.GetPopupTextColor();
1242         break;
1243       }
1244
1245       case Toolkit::Slider::Property::VALUE_PRECISION:
1246       {
1247         value = sliderImpl.GetValuePrecision();
1248         break;
1249       }
1250
1251       case Toolkit::Slider::Property::SHOW_POPUP:
1252       {
1253         value = sliderImpl.GetShowPopup();
1254         break;
1255       }
1256
1257       case Toolkit::Slider::Property::SHOW_VALUE:
1258       {
1259         value = sliderImpl.GetShowValue();
1260         break;
1261       }
1262
1263       case Toolkit::Slider::Property::ENABLED:
1264       {
1265         value = sliderImpl.IsEnabled();
1266         break;
1267       }
1268
1269       case Toolkit::Slider::Property::MARKS:
1270       {
1271         // TODO: Need to be able to return a PropertyArray
1272         // value = sliderImpl.GetMarks();
1273         break;
1274       }
1275
1276       case Toolkit::Slider::Property::SNAP_TO_MARKS:
1277       {
1278         value = sliderImpl.GetSnapToMarks();
1279         break;
1280       }
1281
1282       case Toolkit::Slider::Property::MARK_TOLERANCE:
1283       {
1284         value = sliderImpl.GetMarkTolerance();
1285         break;
1286       }
1287     }
1288   }
1289
1290   return value;
1291 }
1292
1293 } // namespace Internal
1294
1295 } // namespace Toolkit
1296
1297 } // namespace Dali