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