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