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