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