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