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