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