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