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