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