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