Merge remote-tracking branch 'origin/tizen' into new_text
[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
352 void Slider::SetMarks( const MarkList& marks )
353 {
354   float value;
355   for( MarkList::const_iterator it = marks.begin(), itEnd = marks.end(); it != itEnd; ++it )
356   {
357     const Property::Value& propertyValue = *it;
358     propertyValue.Get( value );
359
360     mMarks.push_back( value );
361   }
362 }
363
364 const Slider::MarkList& Slider::GetMarks() const
365 {
366   return mMarks;
367 }
368
369 void Slider::SetSnapToMarks( bool snap )
370 {
371   mSnapToMarks = snap;
372 }
373
374 bool Slider::GetSnapToMarks() const
375 {
376   return mSnapToMarks;
377 }
378
379 Actor Slider::CreateHitRegion()
380 {
381   Actor hitRegion = Actor::New();
382   hitRegion.SetParentOrigin( ParentOrigin::CENTER );
383   hitRegion.SetAnchorPoint( AnchorPoint::CENTER );
384   hitRegion.TouchedSignal().Connect( this, &Slider::OnTouchEvent );
385
386   return hitRegion;
387 }
388
389 ImageActor Slider::CreateBacking()
390 {
391   ImageActor backing = ImageActor::New();
392   backing.SetParentOrigin( ParentOrigin::CENTER );
393   backing.SetAnchorPoint( AnchorPoint::CENTER );
394   backing.SetZ( BACKING_Z );
395
396   return backing;
397 }
398
399 void Slider::SetBackingImageName( const std::string& imageName )
400 {
401   if( mBacking && ( imageName.size() > 0 ) )
402   {
403     Image image = ResourceImage::New( imageName );
404     mBacking.SetImage( image );
405   }
406 }
407
408 std::string Slider::GetBackingImageName()
409 {
410   if( mBacking )
411   {
412     return ResourceImage::DownCast( mBacking.GetImage() ).GetUrl();
413   }
414
415   return std::string( "" );
416 }
417
418 ImageActor Slider::CreateProgress()
419 {
420   ImageActor progress = ImageActor::New();
421   progress.SetParentOrigin( ParentOrigin::CENTER_LEFT );
422   progress.SetAnchorPoint( AnchorPoint::CENTER_LEFT );
423   progress.SetZ( PROGRESS_Z );
424
425   return progress;
426 }
427
428 void Slider::SetProgressImageName( const std::string& imageName )
429 {
430   if( mProgress && ( imageName.size() > 0 ) )
431   {
432     Image image = ResourceImage::New( imageName );
433     mProgress.SetImage( image );
434   }
435 }
436
437 std::string Slider::GetProgressImageName()
438 {
439   if( mProgress )
440   {
441     return ResourceImage::DownCast( mProgress.GetImage()).GetUrl();
442   }
443
444   return std::string( "" );
445 }
446
447 void Slider::SetPopupImageName( const std::string& imageName )
448 {
449   mPopupImageName = imageName;
450 }
451
452 std::string Slider::GetPopupImageName()
453 {
454   return mPopupImageName;
455 }
456
457 void Slider::CreatePopupImage( const std::string& imageName )
458 {
459   if( mPopup && ( imageName.size() > 0 ) )
460   {
461     Image image = ResourceImage::New( imageName );
462     mPopup.SetImage( image );
463   }
464 }
465
466 void Slider::SetPopupArrowImageName( const std::string& imageName )
467 {
468   mPopupArrowImageName = imageName;
469 }
470
471 std::string Slider::GetPopupArrowImageName()
472 {
473   return mPopupArrowImageName;
474 }
475
476 void Slider::CreatePopupArrowImage( const std::string& imageName )
477 {
478   if( mPopupArrow && ( imageName.size() > 0 ) )
479   {
480     Image image = ResourceImage::New( imageName );
481     mPopupArrow.SetImage( image );
482   }
483 }
484
485 void Slider::ResizeProgressRegion( const Vector2& region )
486 {
487   if( mProgress )
488   {
489     mProgress.SetSize( region );
490   }
491 }
492
493 ImageActor Slider::CreateHandle()
494 {
495   ImageActor handle = ImageActor::New();
496   handle.SetParentOrigin( ParentOrigin::CENTER_LEFT );
497   handle.SetAnchorPoint( AnchorPoint::CENTER );
498   handle.SetZ( HANDLE_Z );
499
500   return handle;
501 }
502
503 ImageActor Slider::CreatePopupArrow()
504 {
505   ImageActor arrow = ImageActor::New();
506   arrow.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
507   arrow.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
508   arrow.SetZ( HANDLE_Z );
509
510   return arrow;
511 }
512
513 //Toolkit::TextView Slider::CreatePopupText()
514 //{
515 //}
516
517 ImageActor Slider::CreatePopup()
518 {
519   ImageActor popup = ImageActor::New();
520   popup.SetParentOrigin( ParentOrigin::TOP_CENTER );
521   popup.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
522
523   return popup;
524 }
525
526 void Slider::SetHandleImageName( const std::string& imageName )
527 {
528   if( mHandle && ( imageName.size() > 0 ) )
529   {
530     Image image = ResourceImage::New( imageName );
531     mHandle.SetImage( image );
532   }
533 }
534
535 std::string Slider::GetHandleImageName()
536 {
537   if( mHandle )
538   {
539     return ResourceImage::DownCast( mHandle.GetImage() ).GetUrl();
540   }
541
542   return std::string( "" );
543 }
544
545 void Slider::ResizeHandleRegion( const Vector2& region )
546 {
547   if( mHandle )
548   {
549     mHandle.SetSize( region );
550   }
551 }
552
553 void Slider::CreateHandleValueDisplay()
554 {
555 }
556
557 void Slider::DestroyHandleValueDisplay()
558 {
559 }
560
561 void Slider::SetPopupTextColor( const Vector4& color )
562 {
563   mPopupTextColor = color;
564 }
565
566 Actor Slider::CreateValueDisplay()
567 {
568   Actor popup = Actor::New();
569   popup.SetParentOrigin( ParentOrigin::TOP_CENTER );
570   popup.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
571
572   mPopupArrow = CreatePopupArrow();
573   popup.Add( mPopupArrow );
574
575   mPopup = CreatePopup();
576   mPopup.SetSize( 0.0f, VALUE_POPUP_HEIGHT );
577   mPopupArrow.Add( mPopup );
578
579   return popup;
580 }
581
582 Toolkit::Slider::ValueChangedSignalType& Slider::ValueChangedSignal()
583 {
584   return mValueChangedSignal;
585 }
586
587 Toolkit::Slider::ValueChangedSignalType& Slider::SlidingFinishedSignal()
588 {
589   return mSlidingFinishedSignal;
590 }
591
592 Toolkit::Slider::MarkSignalType& Slider::MarkSignal()
593 {
594   return mMarkSignal;
595 }
596
597 void Slider::UpdateSkin()
598 {
599   switch( mState )
600   {
601     case NORMAL:
602     {
603       mBacking.SetColor( Color::WHITE );
604       mHandle.SetColor( Color::WHITE );
605       mProgress.SetColor( Color::WHITE );
606       break;
607     }
608     case DISABLED:
609     {
610       Vector4 disableColor = GetDisableColor();
611       mBacking.SetColor( disableColor );
612       mHandle.SetColor( disableColor );
613       mProgress.SetColor( disableColor );
614       break;
615     }
616     case PRESSED:
617     {
618       break;
619     }
620     case FOCUSED:
621     {
622       break;
623     }
624   }
625 }
626
627 void Slider::CreateChildren()
628 {
629   Actor self = Self();
630
631   // Hit region
632   mHitArea = CreateHitRegion();
633   mPanDetector = PanGestureDetector::New();
634   mPanDetector.Attach( mHitArea );
635   mPanDetector.DetectedSignal().Connect( this, &Slider::OnPan );
636   self.Add( mHitArea );
637
638   // Background
639   mBacking = CreateBacking();
640   self.Add( mBacking );
641
642   // Progress bar
643   mProgress = CreateProgress();
644   mBacking.Add( mProgress );
645
646   // Handle
647   mHandle = CreateHandle();
648   mBacking.Add( mHandle );
649 }
650
651 void Slider::SetHitRegion( const Vector2& size )
652 {
653   mHitRegion = size;
654
655   if( mHitArea )
656   {
657     mHitArea.SetSize( mHitRegion );
658   }
659 }
660
661 const Vector2& Slider::GetHitRegion() const
662 {
663   return mHitRegion;
664 }
665
666 void Slider::AddPopup()
667 {
668   if( !mValueDisplay )
669   {
670     mValueDisplay = CreateValueDisplay();
671     mValueDisplay.SetVisible( false );
672     mHandle.Add( mValueDisplay );
673
674     CreatePopupImage( GetPopupImageName() );
675     CreatePopupArrowImage( GetPopupArrowImageName() );
676
677     mValueTimer = Timer::New( VALUE_VIEW_SHOW_DURATION );
678     mValueTimer.TickSignal().Connect( this, &Slider::HideValueView );
679   }
680 }
681
682 void Slider::RemovePopup()
683 {
684   if( mValueDisplay )
685   {
686     mPopup.Unparent();
687     mPopup.Reset();
688
689     mPopupArrow.Unparent();
690     mPopupArrow.Reset();
691
692     mValueDisplay.Unparent();
693     mValueDisplay.Reset();
694
695     mValueTimer.TickSignal().Disconnect( this, &Slider::HideValueView );
696     mValueTimer.Reset();
697   }
698 }
699
700
701 float Slider::MarkFilter( float value )
702 {
703   const float MARK_TOLERANCE = GetMarkTolerance();
704
705   float mark;
706   for( MarkList::iterator it = mMarks.begin(), itEnd = mMarks.end(); it != itEnd; ++it )
707   {
708     const Property::Value& propertyValue = *it;
709     propertyValue.Get( mark );
710     mark = MapValuePercentage( mark );
711
712     // If close to a mark, return the mark
713     if( fabsf( mark - value ) < MARK_TOLERANCE )
714     {
715       return mark;
716     }
717   }
718
719   return value;
720 }
721
722 float Slider::SnapToMark( float value )
723 {
724   float closestMark = value;
725   float closestDist = std::numeric_limits<float>::max();
726
727   float mark;
728   for( MarkList::iterator it = mMarks.begin(), itEnd = mMarks.end(); it != itEnd; ++it )
729   {
730     const Property::Value& propertyValue = *it;
731     propertyValue.Get( mark );
732     mark = MapValuePercentage( mark );
733
734     float dist = fabsf( mark - value );
735     if( dist < closestDist )
736     {
737       closestDist = dist;
738       closestMark = mark;
739     }
740   }
741
742   return closestMark;
743 }
744
745 bool Slider::MarkReached( float value, int& outIndex )
746 {
747   const float MARK_TOLERANCE = GetMarkTolerance();
748
749   // Binary search
750   int head = 0,
751       tail = mMarks.size() - 1;
752   int current;
753   float mark;
754
755   while( head <= tail )
756   {
757     current = head + ( tail - head ) / 2;
758
759     const Property::Value& propertyValue = mMarks[ current ];
760     propertyValue.Get( mark );
761     mark = MapValuePercentage( mark );
762
763     if( fabsf( mark - value ) < MARK_TOLERANCE )
764     {
765       outIndex = current;
766       return true;
767     }
768
769     if( value < mark )
770     {
771       tail = current - 1;
772     }
773     else
774     {
775       head = current + 1;
776     }
777   }
778
779   return false;
780 }
781
782 bool Slider::HideValueView()
783 {
784   if( mValueDisplay )
785   {
786     mValueDisplay.SetVisible( false );
787   }
788
789   return false;
790 }
791
792 void Slider::SetLowerBound( float bound )
793 {
794   mLowerBound = bound;
795   DisplayValue( GetValue(), false );
796 }
797
798 float Slider::GetLowerBound() const
799 {
800   return mLowerBound;
801 }
802
803 void Slider::SetUpperBound( float bound )
804 {
805   mUpperBound = bound;
806   DisplayValue( GetValue(), false );
807 }
808
809 float Slider::GetUpperBound() const
810 {
811   return mUpperBound;
812 }
813
814 void Slider::SetValue( float value )
815 {
816   mValue = value;
817   DisplayValue( mValue, true );
818 }
819
820 float Slider::GetValue() const
821 {
822   return mValue;
823 }
824
825 void Slider::SetBackingRegion( const Vector2& region )
826 {
827   mBackingRegion = region;
828
829   if( mBacking )
830   {
831     mBacking.SetSize( mBackingRegion );
832   }
833
834   ResizeProgressRegion( Vector2( 0.0f, mBackingRegion.y ) );
835
836   mDomain = CalcDomain( mBackingRegion );
837
838   DisplayValue( GetValue(), false );  // Set the progress bar to correct width
839 }
840
841 const Vector2& Slider::GetBackingRegion() const
842 {
843   return mBackingRegion;
844 }
845
846 void Slider::SetHandleRegion( const Vector2& region )
847 {
848   mHandleRegionSize = region;
849
850   ResizeHandleRegion( mHandleRegionSize );
851
852   Vector2 hitRegion = GetHitRegion();
853   hitRegion.x += mHandleRegionSize.x;
854   SetHitRegion( hitRegion );
855 }
856
857 const Vector2& Slider::GetHandleRegion() const
858 {
859   return mHandleRegionSize;
860 }
861
862 void Slider::SetDisableColor( const Vector4& color )
863 {
864   mDisableColor = color;
865
866   UpdateSkin();
867 }
868
869 Vector4 Slider::GetDisableColor() const
870 {
871   return mDisableColor;
872 }
873
874 Vector4 Slider::GetPopupTextColor() const
875 {
876   return mPopupTextColor;
877 }
878
879 void Slider::SetValuePrecision( int precision )
880 {
881   mValuePrecision = precision;
882 }
883
884 int Slider::GetValuePrecision() const
885 {
886   return mValuePrecision;
887 }
888
889 void Slider::SetShowPopup( bool showPopup )
890 {
891   mShowPopup = showPopup;
892
893   // Value display
894   if( mShowPopup )
895   {
896     AddPopup();
897   }
898   else
899   {
900     RemovePopup();
901   }
902 }
903
904 bool Slider::GetShowPopup() const
905 {
906   return mShowPopup;
907 }
908
909 void Slider::SetShowValue( bool showValue )
910 {
911   mShowValue = showValue;
912
913   if( mShowValue )
914   {
915     CreateHandleValueDisplay();
916   }
917   else
918   {
919     DestroyHandleValueDisplay();
920   }
921 }
922
923 bool Slider::GetShowValue() const
924 {
925   return mShowValue;
926 }
927
928 void Slider::SetEnabled( bool enabled )
929 {
930   if( enabled )
931   {
932     mState = NORMAL;
933   }
934   else
935   {
936     mState = DISABLED;
937   }
938
939   UpdateSkin();
940 }
941
942 bool Slider::IsEnabled() const
943 {
944   return mState != DISABLED;
945 }
946
947 void Slider::SetMarkTolerance( float tolerance )
948 {
949   mMarkTolerance = tolerance;
950 }
951
952 float Slider::GetMarkTolerance() const
953 {
954   return mMarkTolerance;
955 }
956
957 // Static class method to support script connecting signals
958 bool Slider::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
959 {
960   Dali::BaseHandle handle( object );
961
962   bool connected = true;
963   Toolkit::Slider slider = Toolkit::Slider::DownCast( handle );
964
965   if( 0 == strcmp( signalName.c_str(), SIGNAL_VALUE_CHANGED ) )
966   {
967     slider.ValueChangedSignal().Connect( tracker, functor );
968   }
969   else if( 0 == strcmp( signalName.c_str(), SIGNAL_MARK ) )
970   {
971     slider.MarkSignal().Connect( tracker, functor );
972   }
973   else
974   {
975     // signalName does not match any signal
976     connected = false;
977   }
978
979   return connected;
980 }
981
982 void Slider::DisplayPopup( float value )
983 {
984 }
985
986 void Slider::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
987 {
988   Toolkit::Slider slider = Toolkit::Slider::DownCast( Dali::BaseHandle( object ) );
989
990   if ( slider )
991   {
992     Slider& sliderImpl( GetImpl( slider ) );
993
994     switch ( propertyIndex )
995     {
996       case Toolkit::Slider::Property::LOWER_BOUND:
997       {
998         sliderImpl.SetLowerBound( value.Get< float >() );
999         break;
1000       }
1001
1002       case Toolkit::Slider::Property::UPPER_BOUND:
1003       {
1004         sliderImpl.SetUpperBound( value.Get< float >() );
1005         break;
1006       }
1007
1008       case Toolkit::Slider::Property::VALUE:
1009       {
1010         sliderImpl.SetValue( value.Get< float >() );
1011         break;
1012       }
1013
1014       case Toolkit::Slider::Property::HIT_REGION:
1015       {
1016         sliderImpl.SetHitRegion( value.Get< Vector2 >() );
1017         break;
1018       }
1019
1020       case Toolkit::Slider::Property::BACKING_REGION:
1021       {
1022         sliderImpl.SetBackingRegion( value.Get< Vector2 >() );
1023         break;
1024       }
1025
1026       case Toolkit::Slider::Property::HANDLE_REGION:
1027       {
1028         sliderImpl.SetHandleRegion( value.Get< Vector2 >() );
1029         break;
1030       }
1031
1032       case Toolkit::Slider::Property::BACKING_IMAGE_NAME:
1033       {
1034         sliderImpl.SetBackingImageName( value.Get< std::string >() );
1035         break;
1036       }
1037
1038       case Toolkit::Slider::Property::HANDLE_IMAGE_NAME:
1039       {
1040         sliderImpl.SetHandleImageName( value.Get< std::string >() );
1041         break;
1042       }
1043
1044       case Toolkit::Slider::Property::PROGRESS_IMAGE_NAME:
1045       {
1046         sliderImpl.SetProgressImageName( value.Get< std::string >() );
1047         break;
1048       }
1049
1050       case Toolkit::Slider::Property::POPUP_IMAGE_NAME:
1051       {
1052         sliderImpl.SetPopupImageName( value.Get< std::string >() );
1053         break;
1054       }
1055
1056       case Toolkit::Slider::Property::POPUP_ARROW_IMAGE_NAME:
1057       {
1058         sliderImpl.SetPopupArrowImageName( value.Get< std::string >() );
1059         break;
1060       }
1061
1062       case Toolkit::Slider::Property::DISABLE_COLOR:
1063       {
1064         sliderImpl.SetDisableColor( value.Get< Vector4 >() );
1065         break;
1066       }
1067
1068       case Toolkit::Slider::Property::POPUP_TEXT_COLOR:
1069       {
1070         sliderImpl.SetPopupTextColor( value.Get< Vector4 >() );
1071         break;
1072       }
1073
1074       case Toolkit::Slider::Property::VALUE_PRECISION:
1075       {
1076         sliderImpl.SetValuePrecision( value.Get< int >() );
1077         break;
1078       }
1079
1080       case Toolkit::Slider::Property::SHOW_POPUP:
1081       {
1082         sliderImpl.SetShowPopup( value.Get< bool >() );
1083         break;
1084       }
1085
1086       case Toolkit::Slider::Property::SHOW_VALUE:
1087       {
1088         sliderImpl.SetShowValue( value.Get< bool >() );
1089         break;
1090       }
1091
1092       case Toolkit::Slider::Property::ENABLED:
1093       {
1094         sliderImpl.SetEnabled( value.Get< bool >() );
1095         break;
1096       }
1097
1098       case Toolkit::Slider::Property::MARKS:
1099       {
1100         sliderImpl.SetMarks( value.Get< Property::Array >() );
1101         break;
1102       }
1103
1104       case Toolkit::Slider::Property::SNAP_TO_MARKS:
1105       {
1106         sliderImpl.SetSnapToMarks( value.Get< bool >() );
1107         break;
1108       }
1109
1110       case Toolkit::Slider::Property::MARK_TOLERANCE:
1111       {
1112         sliderImpl.SetMarkTolerance( value.Get< float >() );
1113         break;
1114       }
1115     }
1116   }
1117 }
1118
1119 Property::Value Slider::GetProperty( BaseObject* object, Property::Index propertyIndex )
1120 {
1121   Property::Value value;
1122
1123   Toolkit::Slider slider = Toolkit::Slider::DownCast( Dali::BaseHandle( object ) );
1124
1125   if ( slider )
1126   {
1127     Slider& sliderImpl( GetImpl( slider ) );
1128
1129     switch ( propertyIndex )
1130     {
1131       case Toolkit::Slider::Property::LOWER_BOUND:
1132       {
1133         value = sliderImpl.GetLowerBound();
1134         break;
1135       }
1136
1137       case Toolkit::Slider::Property::UPPER_BOUND:
1138       {
1139         value = sliderImpl.GetUpperBound();
1140         break;
1141       }
1142
1143       case Toolkit::Slider::Property::VALUE:
1144       {
1145         value = sliderImpl.GetValue();
1146         break;
1147       }
1148
1149       case Toolkit::Slider::Property::HIT_REGION:
1150       {
1151         value = sliderImpl.GetHitRegion();
1152         break;
1153       }
1154
1155       case Toolkit::Slider::Property::BACKING_REGION:
1156       {
1157         value = sliderImpl.GetBackingRegion();
1158         break;
1159       }
1160
1161       case Toolkit::Slider::Property::HANDLE_REGION:
1162       {
1163         value = sliderImpl.GetHandleRegion();
1164         break;
1165       }
1166
1167       case Toolkit::Slider::Property::BACKING_IMAGE_NAME:
1168       {
1169         value = sliderImpl.GetBackingImageName();
1170         break;
1171       }
1172
1173       case Toolkit::Slider::Property::HANDLE_IMAGE_NAME:
1174       {
1175         value = sliderImpl.GetHandleImageName();
1176         break;
1177       }
1178
1179       case Toolkit::Slider::Property::PROGRESS_IMAGE_NAME:
1180       {
1181         value = sliderImpl.GetProgressImageName();
1182         break;
1183       }
1184
1185       case Toolkit::Slider::Property::POPUP_IMAGE_NAME:
1186       {
1187         value = sliderImpl.GetPopupImageName();
1188         break;
1189       }
1190
1191       case Toolkit::Slider::Property::POPUP_ARROW_IMAGE_NAME:
1192       {
1193         value = sliderImpl.GetPopupArrowImageName();
1194         break;
1195       }
1196
1197       case Toolkit::Slider::Property::DISABLE_COLOR:
1198       {
1199         value = sliderImpl.GetDisableColor();
1200         break;
1201       }
1202
1203       case Toolkit::Slider::Property::POPUP_TEXT_COLOR:
1204       {
1205         value = sliderImpl.GetPopupTextColor();
1206         break;
1207       }
1208
1209       case Toolkit::Slider::Property::VALUE_PRECISION:
1210       {
1211         value = sliderImpl.GetValuePrecision();
1212         break;
1213       }
1214
1215       case Toolkit::Slider::Property::SHOW_POPUP:
1216       {
1217         value = sliderImpl.GetShowPopup();
1218         break;
1219       }
1220
1221       case Toolkit::Slider::Property::SHOW_VALUE:
1222       {
1223         value = sliderImpl.GetShowValue();
1224         break;
1225       }
1226
1227       case Toolkit::Slider::Property::ENABLED:
1228       {
1229         value = sliderImpl.IsEnabled();
1230         break;
1231       }
1232
1233       case Toolkit::Slider::Property::MARKS:
1234       {
1235         // TODO: Need to be able to return a PropertyArray
1236         // value = sliderImpl.GetMarks();
1237         break;
1238       }
1239
1240       case Toolkit::Slider::Property::SNAP_TO_MARKS:
1241       {
1242         value = sliderImpl.GetSnapToMarks();
1243         break;
1244       }
1245
1246       case Toolkit::Slider::Property::MARK_TOLERANCE:
1247       {
1248         value = sliderImpl.GetMarkTolerance();
1249         break;
1250       }
1251     }
1252   }
1253
1254   return value;
1255 }
1256
1257 } // namespace Internal
1258
1259 } // namespace Toolkit
1260
1261 } // namespace Dali