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