Merge "TextLayout - Use one method to do the single line or multi-line layout." into...
[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
100 const char* SKINNED_BACKING_IMAGE_NAME = DALI_IMAGE_DIR "slider-skin.9.png";
101 const char* SKINNED_HANDLE_IMAGE_NAME = DALI_IMAGE_DIR "slider-skin-handle.png";;
102 const char* SKINNED_PROGRESS_IMAGE_NAME = DALI_IMAGE_DIR "slider-skin-progress.9.png";
103 const char* SKINNED_POPUP_IMAGE_NAME = DALI_IMAGE_DIR "slider-popup.9.png";
104 const char* SKINNED_POPUP_ARROW_IMAGE_NAME = DALI_IMAGE_DIR "slider-popup-arrow.png";
105
106 const Vector2 DEFAULT_HIT_REGION( DEFAULT_WIDTH, DEFAULT_HIT_HEIGHT );
107 const Vector2 DEFAULT_BACKING_REGION( DEFAULT_WIDTH, DEFAULT_HEIGHT );
108 const Vector2 DEFAULT_HANDLE_REGION( DEFAULT_HANDLE_HEIGHT, DEFAULT_HANDLE_HEIGHT );
109
110 const Vector4 DEFAULT_DISABLE_COLOR( 0.5f, 0.5f, 0.5f, 1.0f );
111 const Vector4 DEFAULT_POPUP_TEXT_COLOR( 0.5f, 0.5f, 0.5f, 1.0f );
112
113 const float VALUE_POPUP_MARGIN = 10.0f;
114 const float VALUE_POPUP_HEIGHT = 81.0f;
115 const float VALUE_POPUP_MIN_WIDTH = 54.0f;
116 const Vector2 VALUE_POPUP_ARROW_SIZE( 18.0f, 18.0f );
117
118 const float DEFAULT_LOWER_BOUND = 0.0f;
119 const float DEFAULT_UPPER_BOUND = 1.0f;
120 const float DEFAULT_VALUE = 0.0f;
121 const int DEFAULT_VALUE_PRECISION = 0;
122 const bool DEFAULT_SHOW_POPUP = false;
123 const bool DEFAULT_SHOW_VALUE = true;
124 const bool DEFAULT_ENABLED = true;
125 const bool DEFAULT_SNAP_TO_MARKS = false;
126
127 } // Unnamed namespace
128
129 ///////////////////////////////////////////////////////////////////////////////////////////////////
130 // Slider
131 ///////////////////////////////////////////////////////////////////////////////////////////////////
132
133 Dali::Toolkit::Slider Slider::New()
134 {
135   // Create the implementation
136   SliderPtr slider( new Slider() );
137
138   // Pass ownership to CustomActor via derived handle
139   Dali::Toolkit::Slider handle( *slider );
140
141   // Second-phase init of the implementation
142   // This can only be done after the CustomActor connection has been made...
143   slider->Initialize();
144
145   return handle;
146 }
147
148 Slider::Slider()
149 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
150   mState( NORMAL ),
151   mDisableColor( 0.0f, 0.0f, 0.0f, 0.0f ),
152   mPopupTextColor( 0.0f, 0.0f, 0.0f, 0.0f ),
153   mHitRegion( 0.0f, 0.0f ),
154   mBackingRegion( 0.0f, 0.0f ),
155   mHandleRegionSize( 0.0f, 0.0f ),
156   mLowerBound( 0.0f ),
157   mUpperBound( 0.0f ),
158   mValue( 0.0f ),
159   mMarkTolerance( 0.0f ),
160   mValuePrecision( 0 ),
161   mShowPopup( false ),
162   mShowValue( false ),
163   mSnapToMarks( false )
164 {
165 }
166
167 Slider::~Slider()
168 {
169 }
170
171 void Slider::OnInitialize()
172 {
173   // Setup
174   CreateChildren();
175
176   // Properties
177   Actor self = Self();
178
179   SetHitRegion(     DEFAULT_HIT_REGION     );
180   SetBackingRegion( DEFAULT_BACKING_REGION );
181   SetHandleRegion(  DEFAULT_HANDLE_REGION  );
182
183   SetBackingImageName(    SKINNED_BACKING_IMAGE_NAME     );
184   SetHandleImageName(     SKINNED_HANDLE_IMAGE_NAME      );
185   SetProgressImageName(   SKINNED_PROGRESS_IMAGE_NAME    );
186   SetPopupImageName(      SKINNED_POPUP_IMAGE_NAME       );
187   SetPopupArrowImageName( SKINNED_POPUP_ARROW_IMAGE_NAME );
188
189   SetPopupTextColor( DEFAULT_POPUP_TEXT_COLOR );
190
191   SetShowPopup( DEFAULT_SHOW_POPUP );
192   SetShowValue( DEFAULT_SHOW_VALUE );
193
194   SetEnabled( DEFAULT_ENABLED );
195   SetDisableColor( DEFAULT_DISABLE_COLOR );
196
197   SetSnapToMarks( DEFAULT_SNAP_TO_MARKS );
198   SetMarkTolerance( MARK_SNAP_TOLERANCE );
199
200   SetLowerBound( DEFAULT_LOWER_BOUND );
201   SetUpperBound( DEFAULT_UPPER_BOUND );
202   UpdateSkin();
203   SetValuePrecision( DEFAULT_VALUE_PRECISION );
204   mValue = DEFAULT_VALUE;
205   DisplayValue( mValue, false );       // Run this last to display the correct value
206
207   // Size the Slider actor to a default
208   self.SetSize( DEFAULT_HIT_REGION.x, DEFAULT_HIT_REGION.y );
209 }
210
211 void Slider::OnControlSizeSet( const Vector3& size )
212 {
213   // Factor in handle overshoot into size of backing
214   SetHitRegion( Vector2( size.x, GetHitRegion().y ) );
215   SetBackingRegion( Vector2( size.x - GetHandleRegion().x, GetBackingRegion().y ) );
216 }
217
218 bool Slider::OnTouchEvent(Actor actor, const TouchEvent& event)
219 {
220   if( mState != DISABLED )
221   {
222     TouchPoint::State touchState = event.GetPoint(0).state;
223
224     if( touchState == TouchPoint::Down )
225     {
226       mState = PRESSED;
227
228       float percentage = MapPercentage( event.GetPoint(0).local );
229       float value = MapBounds( ( GetSnapToMarks() ) ? SnapToMark( percentage ) : MarkFilter( percentage ), GetLowerBound(), GetUpperBound() );
230       SetValue( value );
231       DisplayPopup( value );
232     }
233     else if( touchState == TouchPoint::Up)
234     {
235       if( mState == PRESSED )
236       {
237         mState = NORMAL;
238         mSlidingFinishedSignal.Emit( Toolkit::Slider::DownCast( Self() ), GetValue() );
239       }
240     }
241   }
242
243   return true;
244 }
245
246 void Slider::OnPan( Actor actor, const PanGesture& gesture )
247 {
248   // gesture.position is in local actor coordinates
249   if( mState != DISABLED )
250   {
251     switch( gesture.state )
252     {
253       case Gesture::Continuing:
254       {
255         if( mState == PRESSED )
256         {
257           float value = MapBounds( MarkFilter ( MapPercentage( gesture.position ) ), GetLowerBound(), GetUpperBound() );
258           SetValue( value );
259           DisplayPopup( value );
260         }
261         break;
262       }
263       case Gesture::Finished:
264       {
265         if( mState == PRESSED  )
266         {
267           if( GetSnapToMarks() )
268           {
269             float value = MapBounds( SnapToMark( MapPercentage( gesture.position ) ), GetLowerBound(), GetUpperBound() );
270             SetValue( value );
271             DisplayPopup( value );
272           }
273           mSlidingFinishedSignal.Emit( Toolkit::Slider::DownCast( Self() ), GetValue() );
274         }
275
276         mState = NORMAL;
277         break;
278       }
279       default:
280       {
281         break;
282       }
283     }
284   }
285 }
286
287 float Slider::HitSpaceToDomain( float x )
288 {
289   float halfRegionWidth = GetHitRegion().x * 0.5f;
290   float halfDomainWidth = ( mDomain.to.x - mDomain.from.x ) * 0.5f;
291   float endDiff = halfRegionWidth - halfDomainWidth;
292
293   return x - endDiff;
294 }
295
296 float Slider::MapPercentage( const Vector2& point )
297 {
298   return Clamp( ( HitSpaceToDomain( point.x ) - mDomain.from.x ) / ( mDomain.to.x - mDomain.from.x ), 0.0f, 1.0f );
299 }
300
301 float Slider::MapValuePercentage( float value )
302 {
303   return ( value - GetLowerBound() ) / ( GetUpperBound() - GetLowerBound() );
304 }
305
306 float Slider::MapBounds( float percent, float lowerBound, float upperBound )
307 {
308   return lowerBound + percent * ( upperBound - lowerBound );
309 }
310
311 Slider::Domain Slider::CalcDomain( const Vector2& currentSize )
312 {
313    return Domain( Vector2( 0.0f, 0.0f ), currentSize );
314 }
315
316 void Slider::DisplayValue( float value, bool raiseSignals )
317 {
318   float clampledValue = Clamp( value, GetLowerBound(), GetUpperBound() );
319
320   float percent = MapValuePercentage( clampledValue );
321
322   float x = mDomain.from.x + percent * ( mDomain.to.x - mDomain.from.x );
323
324   mHandle.SetPosition( x, 0.0f, HANDLE_Z );
325
326   // Progress bar
327   if( mProgress )
328   {
329     if( clampledValue > 0.0f )
330     {
331       mProgress.SetVisible( true ); // Deliberately set this in case multiple SetValues are fired at once
332       mProgress.SetSize( x, GetBackingRegion().y );
333     }
334     else
335     {
336       mProgress.SetVisible( false );
337     }
338   }
339
340   // Signals
341   if( raiseSignals )
342   {
343     Toolkit::Slider self = Toolkit::Slider::DownCast( Self() );
344     mValueChangedSignal.Emit( self, clampledValue );
345
346     int markIndex;
347     if( MarkReached( percent, markIndex ) )
348     {
349       mMarkSignal.Emit( self, markIndex );
350     }
351   }
352
353   if( mHandleValueTextLabel )
354   {
355     std::stringstream ss;
356     ss.precision( GetValuePrecision() );
357     ss << std::fixed << clampledValue;
358
359     mHandleValueTextLabel.SetProperty( Toolkit::TextLabel::Property::TEXT, ss.str() );
360   }
361 }
362
363 void Slider::SetMarks( const MarkList& marks )
364 {
365   float value;
366   for( MarkList::const_iterator it = marks.begin(), itEnd = marks.end(); it != itEnd; ++it )
367   {
368     const Property::Value& propertyValue = *it;
369     propertyValue.Get( value );
370
371     mMarks.push_back( value );
372   }
373 }
374
375 const Slider::MarkList& Slider::GetMarks() const
376 {
377   return mMarks;
378 }
379
380 void Slider::SetSnapToMarks( bool snap )
381 {
382   mSnapToMarks = snap;
383 }
384
385 bool Slider::GetSnapToMarks() const
386 {
387   return mSnapToMarks;
388 }
389
390 Actor Slider::CreateHitRegion()
391 {
392   Actor hitRegion = Actor::New();
393   hitRegion.SetParentOrigin( ParentOrigin::CENTER );
394   hitRegion.SetAnchorPoint( AnchorPoint::CENTER );
395   hitRegion.TouchedSignal().Connect( this, &Slider::OnTouchEvent );
396
397   return hitRegion;
398 }
399
400 ImageActor Slider::CreateBacking()
401 {
402   ImageActor backing = ImageActor::New();
403   backing.SetRelayoutEnabled( false );
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.SetRelayoutEnabled( false );
434   progress.SetParentOrigin( ParentOrigin::CENTER_LEFT );
435   progress.SetAnchorPoint( AnchorPoint::CENTER_LEFT );
436   progress.SetZ( PROGRESS_Z );
437
438   return progress;
439 }
440
441 void Slider::SetProgressImageName( const std::string& imageName )
442 {
443   if( mProgress && ( imageName.size() > 0 ) )
444   {
445     Image image = ResourceImage::New( imageName );
446     mProgress.SetImage( image );
447   }
448 }
449
450 std::string Slider::GetProgressImageName()
451 {
452   if( mProgress )
453   {
454     return ResourceImage::DownCast( mProgress.GetImage()).GetUrl();
455   }
456
457   return std::string( "" );
458 }
459
460 void Slider::SetPopupImageName( const std::string& imageName )
461 {
462   mPopupImageName = imageName;
463 }
464
465 std::string Slider::GetPopupImageName()
466 {
467   return mPopupImageName;
468 }
469
470 void Slider::CreatePopupImage( const std::string& imageName )
471 {
472   if( mPopup && ( imageName.size() > 0 ) )
473   {
474     Image image = ResourceImage::New( imageName );
475     mPopup.SetImage( image );
476   }
477 }
478
479 void Slider::SetPopupArrowImageName( const std::string& imageName )
480 {
481   mPopupArrowImageName = imageName;
482 }
483
484 std::string Slider::GetPopupArrowImageName()
485 {
486   return mPopupArrowImageName;
487 }
488
489 void Slider::CreatePopupArrowImage( const std::string& imageName )
490 {
491   if( mPopupArrow && ( imageName.size() > 0 ) )
492   {
493     Image image = ResourceImage::New( imageName );
494     mPopupArrow.SetImage( image );
495   }
496 }
497
498 void Slider::ResizeProgressRegion( const Vector2& region )
499 {
500   if( mProgress )
501   {
502     mProgress.SetSize( region );
503   }
504 }
505
506 ImageActor Slider::CreateHandle()
507 {
508   ImageActor handle = ImageActor::New();
509   handle.SetRelayoutEnabled( false );
510   handle.SetParentOrigin( ParentOrigin::CENTER_LEFT );
511   handle.SetAnchorPoint( AnchorPoint::CENTER );
512   handle.SetZ( HANDLE_Z );
513
514   return handle;
515 }
516
517 ImageActor Slider::CreatePopupArrow()
518 {
519   ImageActor arrow = ImageActor::New();
520   arrow.SetRelayoutEnabled( false );
521   arrow.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
522   arrow.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
523   arrow.SetZ( HANDLE_Z );
524
525   return arrow;
526 }
527
528 Toolkit::TextLabel Slider::CreatePopupText()
529 {
530   Toolkit::TextLabel textLabel = Toolkit::TextLabel::New();
531   textLabel.SetParentOrigin( ParentOrigin::CENTER );
532   textLabel.SetAnchorPoint( AnchorPoint::CENTER );
533   textLabel.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
534   textLabel.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
535   textLabel.SetZ( VALUE_DISPLAY_TEXT_Z );
536   return textLabel;
537 }
538
539 ImageActor Slider::CreatePopup()
540 {
541   ImageActor popup = ImageActor::New();
542   popup.SetRelayoutEnabled( false );
543   popup.SetParentOrigin( ParentOrigin::TOP_CENTER );
544   popup.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
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