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