Fix button label centering of text
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / buttons / button-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 "button-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 #include <dali/public-api/object/type-registry-helper.h>
25 #include <dali/public-api/actors/image-actor.h>
26 #include <dali/public-api/scripting/scripting.h>
27
28 // INTERNAL INCLUDES
29 #include <dali-toolkit/public-api/controls/text-controls/text-label.h>
30
31 /**
32  * Button states and contents
33  *                                         (3) mSelectedContent
34  *  (2) mButtonContent                     (2) mSelectedBackgroundContent
35  *  (1) mBackgroundContent                 (1) mBackgroundContent
36  * < unselected > ----------------------- < selected >
37  *       |                OnSelect()            |
38  *       | OnDisabled()                         | OnDisabled()
39  *       |                                      |
40  * < disabled >                           < disabled-selected >
41  *  (2) mDisabledContent                   (2) mDisabledSelectedContent
42  *  (1) mDisabledBackgroundContent         (1) mDisabledBackgroundContent
43  *
44  * The drawing order of child actors is as follows.
45  *
46  *  Top      mLabel
47  *   |       mButtonContent / mSelectedContent / mDisabledContent / mDisabledSelectedContent
48  *   |       mSelectedBackgroundContent
49  * Bottom    mBackgroundContent / mDisabledBackgroundContent
50  *
51  * Some of contents may be missed.
52  * And 2 images - fade-in image and fade-out image - in the same layer can be shown during the transition animation. Fade-in image should be above fade-out image.
53  */
54
55 namespace Dali
56 {
57
58 namespace Toolkit
59 {
60
61 namespace Internal
62 {
63
64 namespace
65 {
66
67 BaseHandle Create()
68 {
69   // empty handle as we cannot create button (but type registered for clicked signal)
70   return BaseHandle();
71 }
72
73 // Setup properties, signals and actions using the type-registry.
74 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Button, Toolkit::Control, Create );
75
76 DALI_PROPERTY_REGISTRATION( Button, "disabled",                     BOOLEAN, DISABLED                     )
77 DALI_PROPERTY_REGISTRATION( Button, "auto-repeating",               BOOLEAN, AUTO_REPEATING               )
78 DALI_PROPERTY_REGISTRATION( Button, "initial-auto-repeating-delay", FLOAT,   INITIAL_AUTO_REPEATING_DELAY )
79 DALI_PROPERTY_REGISTRATION( Button, "next-auto-repeating-delay",    FLOAT,   NEXT_AUTO_REPEATING_DELAY    )
80 DALI_PROPERTY_REGISTRATION( Button, "togglable",                    BOOLEAN, TOGGLABLE                    )
81 DALI_PROPERTY_REGISTRATION( Button, "selected",                     BOOLEAN, SELECTED                     )
82 DALI_PROPERTY_REGISTRATION( Button, "normal-state-actor",           MAP,     NORMAL_STATE_ACTOR           )
83 DALI_PROPERTY_REGISTRATION( Button, "selected-state-actor",         MAP,     SELECTED_STATE_ACTOR         )
84 DALI_PROPERTY_REGISTRATION( Button, "disabled-state-actor",         MAP,     DISABLED_STATE_ACTOR         )
85 DALI_PROPERTY_REGISTRATION( Button, "label-actor",                  MAP,     LABEL_ACTOR                  )
86
87 DALI_SIGNAL_REGISTRATION(   Button, "pressed",                               SIGNAL_PRESSED               )
88 DALI_SIGNAL_REGISTRATION(   Button, "released",                              SIGNAL_RELEASED              )
89 DALI_SIGNAL_REGISTRATION(   Button, "clicked",                               SIGNAL_CLICKED               )
90 DALI_SIGNAL_REGISTRATION(   Button, "state-changed",                         SIGNAL_STATE_CHANGED         )
91
92 DALI_ACTION_REGISTRATION(   Button, "button-click",                          ACTION_BUTTON_CLICK          )
93
94 DALI_TYPE_REGISTRATION_END()
95
96 const unsigned int INITIAL_AUTOREPEATING_DELAY( 0.15f );
97 const unsigned int NEXT_AUTOREPEATING_DELAY( 0.05f );
98
99 } // unnamed namespace
100
101 Button::Button()
102 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
103   mAutoRepeatingTimer(),
104   mDisabled( false ),
105   mAutoRepeating( false ),
106   mTogglableButton( false ),
107   mSelected( false ),
108   mInitialAutoRepeatingDelay( INITIAL_AUTOREPEATING_DELAY ),
109   mNextAutoRepeatingDelay( NEXT_AUTOREPEATING_DELAY ),
110   mAnimationTime( 0.0f ),
111   mClickActionPerforming( false ),
112   mState( ButtonUp ),
113   mPaintState( UnselectedState )
114 {
115 }
116
117 Button::~Button()
118 {
119   if( mAutoRepeatingTimer )
120   {
121     mAutoRepeatingTimer.Reset();
122   }
123 }
124
125 void Button::SetDisabled( bool disabled )
126 {
127   if( disabled != mDisabled )
128   {
129     unsigned int backgroundIndex;
130     unsigned int buttonIndex;
131
132     bool animationStarted = false;
133
134     mDisabled = disabled;
135
136     switch( mPaintState )
137     {
138       case UnselectedState:
139       {
140         buttonIndex = FindChildIndex( mLabel );
141         InsertChild( buttonIndex, mDisabledContent );
142
143         if( mBackgroundContent )
144         {
145           backgroundIndex = 1;
146         }
147         else
148         {
149           backgroundIndex = 0;
150         }
151
152         InsertChild( backgroundIndex, mDisabledBackgroundContent );
153
154         animationStarted = OnDisabled();
155
156         if( animationStarted )
157         {
158           mPaintState = UnselectedDisabledTransition;
159         }
160         else
161         {
162           mPaintState = DisabledUnselectedState;
163         }
164         break;
165       }
166       case SelectedState:
167       {
168         buttonIndex = FindChildIndex( mLabel );
169         InsertChild( buttonIndex, mDisabledSelectedContent );
170
171         if( mBackgroundContent )
172         {
173           backgroundIndex = 1;
174         }
175         else
176         {
177           backgroundIndex = 0;
178         }
179
180         InsertChild( backgroundIndex, mDisabledBackgroundContent );
181
182         animationStarted = OnDisabled();
183
184         if( animationStarted )
185         {
186           mPaintState = SelectedDisabledTransition;
187         }
188         else
189         {
190           mPaintState = DisabledSelectedState;
191         }
192         break;
193       }
194       case DisabledUnselectedState:
195       {
196         buttonIndex = FindChildIndex( mLabel );
197         InsertChild( buttonIndex, mButtonContent );
198
199         if( mDisabledBackgroundContent )
200         {
201           backgroundIndex = 1;
202         }
203         else
204         {
205           backgroundIndex = 0;
206         }
207
208         InsertChild( backgroundIndex, mBackgroundContent );
209
210         animationStarted = OnDisabled();
211
212         if( animationStarted )
213         {
214           mPaintState = DisabledUnselectedTransition;
215         }
216         else
217         {
218           mPaintState = UnselectedState;
219         }
220         break;
221       }
222       case DisabledSelectedState:
223       {
224         buttonIndex = FindChildIndex( mLabel );
225         InsertChild( buttonIndex, mSelectedContent );
226
227         if( mDisabledBackgroundContent )
228         {
229           backgroundIndex = 1;
230         }
231         else
232         {
233           backgroundIndex = 0;
234         }
235
236         InsertChild( backgroundIndex, mSelectedBackgroundContent );
237         InsertChild( backgroundIndex, mBackgroundContent );
238
239         animationStarted = OnDisabled();
240
241         if( animationStarted )
242         {
243           mPaintState = DisabledSelectedTransition;
244         }
245         else
246         {
247           mPaintState = SelectedState;
248         }
249         break;
250       }
251       case UnselectedSelectedTransition:
252       {
253         buttonIndex = FindChildIndex( mLabel );
254         InsertChild( buttonIndex, mDisabledSelectedContent );
255
256         if( mBackgroundContent )
257         {
258           backgroundIndex = 1;
259         }
260         else
261         {
262           backgroundIndex = 0;
263         }
264
265         InsertChild( backgroundIndex, mDisabledBackgroundContent );
266
267         animationStarted = OnDisabled();
268
269         if( animationStarted )
270         {
271           mPaintState = SelectedDisabledTransition;
272         }
273         else
274         {
275           mPaintState = DisabledSelectedState;
276         }
277         break;
278       }
279       case SelectedUnselectedTransition:
280       {
281         buttonIndex = FindChildIndex( mLabel );
282         InsertChild( buttonIndex, mDisabledContent );
283
284         if( mBackgroundContent )
285         {
286           backgroundIndex = 1;
287         }
288         else
289         {
290           backgroundIndex = 0;
291         }
292
293         InsertChild( backgroundIndex, mDisabledBackgroundContent );
294
295         animationStarted = OnDisabled();
296
297         if( animationStarted )
298         {
299           mPaintState = UnselectedDisabledTransition;
300         }
301         else
302         {
303           mPaintState = DisabledUnselectedState;
304         }
305         break;
306       }
307       case UnselectedDisabledTransition:
308       {
309         animationStarted = OnDisabled();
310
311         if( animationStarted )
312         {
313           mPaintState = DisabledUnselectedTransition;
314         }
315         else
316         {
317           mPaintState = UnselectedState;
318         }
319         break;
320       }
321       case DisabledUnselectedTransition:
322       {
323         animationStarted = OnDisabled();
324
325         if( animationStarted )
326         {
327           mPaintState = UnselectedDisabledTransition;
328         }
329         else
330         {
331           mPaintState = DisabledUnselectedState;
332         }
333         break;
334       }
335       case SelectedDisabledTransition:
336       {
337         animationStarted = OnDisabled();
338
339         if( animationStarted )
340         {
341           mPaintState = DisabledSelectedTransition;
342         }
343         else
344         {
345           mPaintState = SelectedState;
346         }
347         break;
348       }
349       case DisabledSelectedTransition:
350       {
351         animationStarted = OnDisabled();
352
353         if( animationStarted )
354         {
355           mPaintState = SelectedDisabledTransition;
356         }
357         else
358         {
359           mPaintState = DisabledSelectedState;
360         }
361         break;
362       }
363     }
364   }
365 }
366
367 bool Button::IsDisabled() const
368 {
369   return mDisabled;
370 }
371
372 void Button::SetAutoRepeating( bool autoRepeating )
373 {
374   mAutoRepeating = autoRepeating;
375
376   // An autorepeating button can't be a togglable button.
377   if( autoRepeating )
378   {
379     mTogglableButton = false;
380
381     if( mSelected )
382     {
383       // Emit a signal is not wanted, only change the appearance.
384       SetSelected( false, false );
385     }
386   }
387 }
388
389 bool Button::IsAutoRepeating() const
390 {
391   return mAutoRepeating;
392 }
393
394 void Button::SetInitialAutoRepeatingDelay( float initialAutoRepeatingDelay )
395 {
396   DALI_ASSERT_ALWAYS( initialAutoRepeatingDelay > 0.f );
397   mInitialAutoRepeatingDelay = initialAutoRepeatingDelay;
398 }
399
400 float Button::GetInitialAutoRepeatingDelay() const
401 {
402   return mInitialAutoRepeatingDelay;
403 }
404
405 void Button::SetNextAutoRepeatingDelay( float nextAutoRepeatingDelay )
406 {
407   DALI_ASSERT_ALWAYS( nextAutoRepeatingDelay > 0.f );
408   mNextAutoRepeatingDelay = nextAutoRepeatingDelay;
409 }
410
411 float Button::GetNextAutoRepeatingDelay() const
412 {
413   return mNextAutoRepeatingDelay;
414 }
415
416 void Button::SetTogglableButton( bool togglable )
417 {
418   mTogglableButton = togglable;
419
420   // A togglable button can't be an autorepeating button.
421   if( togglable )
422   {
423     mAutoRepeating = false;
424   }
425 }
426
427 bool Button::IsTogglableButton() const
428 {
429   return mTogglableButton;
430 }
431
432 void Button::SetSelected( bool selected )
433 {
434   if( !mDisabled && mTogglableButton && ( selected != mSelected ) )
435   {
436     SetSelected( selected, true );
437   }
438 }
439
440 void Button::SetSelected( bool selected, bool emitSignal )
441 {
442   unsigned int buttonIndex, backgroundIndex;
443   bool animationStarted = false;
444
445   mSelected = selected;
446
447   switch( mPaintState )
448   {
449     case UnselectedState:
450     {
451       buttonIndex = FindChildIndex( mLabel );
452       InsertChild( buttonIndex, mSelectedContent );
453
454       if( mBackgroundContent )
455       {
456         backgroundIndex = 1;
457       }
458       else
459       {
460         backgroundIndex = 0;
461       }
462
463       InsertChild( backgroundIndex, mSelectedBackgroundContent );
464
465       // Notifies the derived class the button has been selected.
466       animationStarted = OnSelected();
467
468       if( animationStarted )
469       {
470         mPaintState = UnselectedSelectedTransition;
471       }
472       else
473       {
474         mPaintState = SelectedState;
475       }
476       break;
477     }
478     case SelectedState:
479     {
480       buttonIndex = FindChildIndex( mLabel );
481       InsertChild( buttonIndex, mButtonContent );
482
483       // Notifies the derived class the button has been selected.
484       animationStarted = OnSelected();
485
486       if( animationStarted )
487       {
488         mPaintState = SelectedUnselectedTransition;
489       }
490       else
491       {
492         mPaintState = UnselectedState;
493       }
494       break;
495     }
496     case UnselectedSelectedTransition:
497     {
498       // Notifies the derived class the button has been selected.
499       animationStarted = OnSelected();
500
501       if( animationStarted )
502       {
503         mPaintState = SelectedUnselectedTransition;
504       }
505       else
506       {
507         mPaintState = UnselectedState;
508       }
509       break;
510     }
511     case SelectedUnselectedTransition:
512     {
513       // Notifies the derived class the button has been selected.
514       animationStarted = OnSelected();
515
516       if( animationStarted )
517       {
518         mPaintState = UnselectedSelectedTransition;
519       }
520       else
521       {
522         mPaintState = SelectedState;
523       }
524       break;
525     }
526     case DisabledUnselectedTransition:
527     {
528       buttonIndex = FindChildIndex( mLabel );
529       InsertChild( buttonIndex, mSelectedContent );
530
531       if( mDisabledBackgroundContent )
532       {
533         if(  mBackgroundContent )
534         {
535           backgroundIndex = 2;
536         }
537         else
538         {
539           backgroundIndex = 1;
540         }
541       }
542       else if( mBackgroundContent )
543       {
544         backgroundIndex = 1;
545       }
546       else
547       {
548         backgroundIndex = 0;
549       }
550
551       InsertChild( backgroundIndex, mSelectedBackgroundContent );
552
553       // Notifies the derived class the button has been selected.
554       animationStarted = OnSelected();
555
556       if( animationStarted )
557       {
558         mPaintState = UnselectedSelectedTransition;
559       }
560       else
561       {
562         mPaintState = SelectedState;
563       }
564       break;
565     }
566     case DisabledSelectedTransition:
567     {
568       buttonIndex = FindChildIndex( mLabel );
569       InsertChild( buttonIndex, mButtonContent );
570
571       // Notifies the derived class the button has been selected.
572       animationStarted = OnSelected();
573
574       if( animationStarted )
575       {
576         mPaintState = SelectedUnselectedTransition;
577       }
578       else
579       {
580         mPaintState = UnselectedState;
581       }
582       break;
583     }
584     default:
585     {
586       break;
587     }
588   }
589
590   if( emitSignal )
591   {
592     Toolkit::Button handle( GetOwner() );
593
594     // Emit signal.
595     mStateChangedSignal.Emit( handle );
596   }
597
598   RelayoutRequest();
599 }
600
601 bool Button::IsSelected() const
602 {
603   return mTogglableButton && mSelected;
604 }
605
606 void Button::SetAnimationTime( float animationTime )
607 {
608   mAnimationTime = animationTime;
609 }
610
611 float Button::GetAnimationTime() const
612 {
613   return mAnimationTime;
614 }
615
616 void Button::SetLabel( const std::string& label )
617 {
618   Toolkit::TextLabel textLabel = Toolkit::TextLabel::New( label );
619   textLabel.SetResizePolicy( FILL_TO_PARENT, ALL_DIMENSIONS );
620   textLabel.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
621   textLabel.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
622   textLabel.SetProperty( Toolkit::TextLabel::Property::MULTI_LINE, true );
623
624   SetLabel( textLabel );
625 }
626
627 void Button::SetLabel( Actor label )
628 {
629   if( mLabel != label )
630   {
631     if( mLabel && mLabel.GetParent() )
632     {
633       mLabel.GetParent().Remove( mLabel );
634     }
635
636     mLabel = label;
637     mLabel.SetPosition( 0.f, 0.f );
638
639     // label should be the top of the button
640     Self().Add( mLabel );
641
642     OnLabelSet();
643
644     RelayoutRequest();
645   }
646 }
647
648 Actor Button::GetLabel() const
649 {
650   return mLabel;
651 }
652
653 Actor& Button::GetLabel()
654 {
655   return mLabel;
656 }
657
658 void Button::SetButtonImage( Actor image )
659 {
660   StopAllAnimations();
661
662   if( mButtonContent && mButtonContent.GetParent() )
663   {
664     Self().Remove( mButtonContent );
665   }
666
667   mButtonContent = image;
668
669   mButtonContent.SetAnchorPoint( AnchorPoint::TOP_LEFT );
670   mButtonContent.SetParentOrigin( ParentOrigin::TOP_LEFT );
671   mButtonContent.SetPosition( 0.f, 0.f );
672
673   if( mPaintState == UnselectedState )
674   {
675     unsigned int index = FindChildIndex( mLabel );
676
677     Self().Insert( index, mButtonContent );
678   }
679
680   OnButtonImageSet();
681 }
682
683 Actor Button::GetButtonImage() const
684 {
685   return mButtonContent;
686 }
687
688 Actor& Button::GetButtonImage()
689 {
690   return mButtonContent;
691 }
692
693 void Button::SetSelectedImage( Actor image )
694 {
695   StopAllAnimations();
696
697   if( mSelectedContent && mSelectedContent.GetParent() )
698   {
699     Self().Remove( mSelectedContent );
700   }
701
702   mSelectedContent = image;
703
704   mSelectedContent.SetAnchorPoint( AnchorPoint::TOP_LEFT );
705   mSelectedContent.SetParentOrigin( ParentOrigin::TOP_LEFT );
706   mSelectedContent.SetPosition( 0.f, 0.f );
707
708   if( mPaintState == SelectedState )
709   {
710     unsigned int index = FindChildIndex( mLabel );
711
712     Self().Insert( index, mSelectedContent );
713   }
714
715   OnSelectedImageSet();
716 }
717
718 Actor Button::GetSelectedImage() const
719 {
720   return mSelectedContent;
721 }
722
723 Actor& Button::GetSelectedImage()
724 {
725   return mSelectedContent;
726 }
727
728 void Button::SetBackgroundImage( Actor image )
729 {
730   StopAllAnimations();
731
732   if( mBackgroundContent && mBackgroundContent.GetParent() )
733   {
734     Self().Remove( mBackgroundContent );
735   }
736
737   mBackgroundContent = image;
738
739   mBackgroundContent.SetAnchorPoint( AnchorPoint::TOP_LEFT );
740   mBackgroundContent.SetParentOrigin( ParentOrigin::TOP_LEFT );
741   mBackgroundContent.SetPosition( 0.f, 0.f );
742
743   if( mPaintState == UnselectedState || mPaintState == SelectedState )
744   {
745     Self().Insert( 0, mBackgroundContent );
746   }
747
748   OnBackgroundImageSet();
749 }
750
751 Actor Button::GetBackgroundImage() const
752 {
753   return mBackgroundContent;
754 }
755
756 Actor& Button::GetBackgroundImage()
757 {
758   return mBackgroundContent;
759 }
760
761 void Button::SetSelectedBackgroundImage( Actor image )
762 {
763   StopAllAnimations();
764
765   if( mSelectedBackgroundContent && mSelectedBackgroundContent.GetParent() )
766   {
767     Self().Remove( mSelectedBackgroundContent );
768   }
769
770   mSelectedBackgroundContent = image;
771
772   mSelectedBackgroundContent.SetAnchorPoint( AnchorPoint::TOP_LEFT );
773   mSelectedBackgroundContent.SetParentOrigin( ParentOrigin::TOP_LEFT );
774   mSelectedBackgroundContent.SetPosition( 0.f, 0.f );
775
776   if( mPaintState == SelectedState )
777   {
778     if( mBackgroundContent )
779     {
780       Self().Insert( 1, mSelectedBackgroundContent );
781     }
782     else
783     {
784       Self().Insert( 0, mSelectedBackgroundContent );
785     }
786   }
787
788   OnSelectedBackgroundImageSet();
789 }
790
791 Actor Button::GetSelectedBackgroundImage() const
792 {
793   return mSelectedBackgroundContent;
794 }
795
796 Actor& Button::GetSelectedBackgroundImage()
797 {
798   return mSelectedBackgroundContent;
799 }
800
801 void Button::SetDisabledImage( Actor image )
802 {
803   StopAllAnimations();
804
805   if( mDisabledContent && mDisabledContent.GetParent() )
806   {
807     Self().Remove( mDisabledContent );
808   }
809
810   mDisabledContent = image;
811
812   mDisabledContent.SetAnchorPoint( AnchorPoint::TOP_LEFT );
813   mDisabledContent.SetParentOrigin( ParentOrigin::TOP_LEFT );
814   mDisabledContent.SetPosition( 0.f, 0.f );
815
816   if( mPaintState == DisabledUnselectedState || mPaintState == DisabledSelectedState )
817   {
818     unsigned int index = FindChildIndex( mLabel );
819
820     Self().Insert( index, mDisabledContent );
821   }
822
823   OnDisabledImageSet();
824 }
825
826 Actor Button::GetDisabledImage() const
827 {
828   return mDisabledContent;
829 }
830
831 Actor& Button::GetDisabledImage()
832 {
833   return mDisabledContent;
834 }
835
836 void Button::SetDisabledSelectedImage( Actor image )
837 {
838   StopAllAnimations();
839
840   if( mDisabledSelectedContent && mDisabledSelectedContent.GetParent() )
841   {
842     Self().Remove( mDisabledSelectedContent );
843   }
844
845   mDisabledSelectedContent = image;
846
847   mDisabledSelectedContent.SetAnchorPoint( AnchorPoint::TOP_LEFT );
848   mDisabledSelectedContent.SetParentOrigin( ParentOrigin::TOP_LEFT );
849   mDisabledSelectedContent.SetPosition( 0.f, 0.f );
850
851   if( mPaintState == DisabledSelectedState )
852   {
853     unsigned int index = FindChildIndex( mLabel );
854
855     Self().Insert( index, mDisabledSelectedContent );
856   }
857
858   OnDisabledSelectedImageSet();
859 }
860
861 Actor Button::GetDisabledSelectedImage() const
862 {
863   return mDisabledSelectedContent;
864 }
865
866 Actor& Button::GetDisabledSelectedImage()
867 {
868   return mDisabledSelectedContent;
869 }
870
871 void Button::SetDisabledBackgroundImage( Actor image )
872 {
873   StopAllAnimations();
874
875   if( mDisabledBackgroundContent && mDisabledBackgroundContent.GetParent() )
876   {
877     Self().Remove( mDisabledBackgroundContent );
878   }
879
880   mDisabledBackgroundContent = image;
881
882   mDisabledBackgroundContent.SetAnchorPoint( AnchorPoint::TOP_LEFT );
883   mDisabledBackgroundContent.SetParentOrigin( ParentOrigin::TOP_LEFT );
884   mDisabledBackgroundContent.SetPosition( 0.f, 0.f );
885
886   if( mPaintState == DisabledUnselectedState || mPaintState == DisabledSelectedState )
887   {
888     Self().Insert( 0, mDisabledBackgroundContent );
889   }
890
891   OnDisabledBackgroundImageSet();
892 }
893
894 Actor Button::GetDisabledBackgroundImage() const
895 {
896   return mDisabledBackgroundContent;
897 }
898
899 Actor& Button::GetDisabledBackgroundImage()
900 {
901   return mDisabledBackgroundContent;
902 }
903
904 bool Button::DoAction( BaseObject* object, const std::string& actionName, const PropertyValueContainer& attributes )
905 {
906   bool ret = false;
907
908   Dali::BaseHandle handle( object );
909
910   Toolkit::Button button = Toolkit::Button::DownCast( handle );
911
912   DALI_ASSERT_ALWAYS( button );
913
914   if( 0 == strcmp( actionName.c_str(), ACTION_BUTTON_CLICK ) )
915   {
916     GetImplementation( button ).DoClickAction( attributes );
917     ret = true;
918   }
919
920   return ret;
921 }
922
923 void Button::DoClickAction( const PropertyValueContainer& attributes )
924 {
925   // Prevents the button signals from doing a recursive loop by sending an action
926   // and re-emitting the signals.
927   if( !mClickActionPerforming )
928   {
929     mClickActionPerforming = true;
930     OnButtonDown();
931     mState = ButtonDown;
932     OnButtonUp();
933     mClickActionPerforming = false;
934   }
935 }
936
937 void Button::UpdatePaintTransitionState()
938 {
939   switch( mPaintState )
940   {
941     case UnselectedSelectedTransition:
942     {
943       RemoveChild( mButtonContent );
944       mPaintState = SelectedState;
945       break;
946     }
947     case SelectedUnselectedTransition:
948     {
949       RemoveChild( mSelectedBackgroundContent );
950       RemoveChild( mSelectedContent );
951       mPaintState = UnselectedState;
952       break;
953     }
954     case UnselectedDisabledTransition:
955     {
956       RemoveChild( mBackgroundContent );
957       RemoveChild( mButtonContent );
958       mPaintState = DisabledUnselectedState;
959       break;
960     }
961     case DisabledUnselectedTransition:
962     {
963       RemoveChild( mDisabledBackgroundContent );
964       RemoveChild( mDisabledContent );
965       mPaintState = UnselectedState;
966       break;
967     }
968     case SelectedDisabledTransition:
969     {
970       RemoveChild( mBackgroundContent );
971       RemoveChild( mSelectedBackgroundContent );
972       RemoveChild( mSelectedContent );
973       mPaintState = DisabledSelectedState;
974       break;
975     }
976     case DisabledSelectedTransition:
977     {
978       RemoveChild( mDisabledBackgroundContent );
979       RemoveChild( mDisabledSelectedContent );
980       mPaintState = SelectedState;
981       break;
982     }
983     default:
984     {
985       break;
986     }
987   }
988 }
989
990 void Button::OnButtonStageDisconnection()
991 {
992   if( ButtonDown == mState )
993   {
994     if( !mTogglableButton )
995     {
996       Released();
997
998       if( mAutoRepeating )
999       {
1000         mAutoRepeatingTimer.Reset();
1001       }
1002     }
1003   }
1004 }
1005
1006 void Button::OnButtonDown()
1007 {
1008   if( !mTogglableButton )
1009   {
1010     Toolkit::Button handle( GetOwner() );
1011
1012     Pressed();
1013
1014     if( mAutoRepeating )
1015     {
1016       SetUpTimer( mInitialAutoRepeatingDelay );
1017     }
1018
1019     //Emit signal.
1020     mPressedSignal.Emit( handle );
1021   }
1022 }
1023
1024 void Button::OnButtonUp()
1025 {
1026   if( ButtonDown == mState )
1027   {
1028     if( mTogglableButton )
1029     {
1030       SetSelected( !mSelected );
1031     }
1032     else
1033     {
1034       Released();
1035
1036       if( mAutoRepeating )
1037       {
1038         mAutoRepeatingTimer.Reset();
1039       }
1040
1041       Toolkit::Button handle( GetOwner() );
1042
1043       //Emit signal.
1044       mReleasedSignal.Emit( handle );
1045       mClickedSignal.Emit( handle );
1046     }
1047   }
1048 }
1049
1050 void Button::OnTouchPointLeave()
1051 {
1052   if( ButtonDown == mState )
1053   {
1054     if( !mTogglableButton )
1055     {
1056       Toolkit::Button handle( GetOwner() );
1057
1058       Released();
1059
1060       if( mAutoRepeating )
1061       {
1062         mAutoRepeatingTimer.Reset();
1063       }
1064
1065       //Emit signal.
1066       mReleasedSignal.Emit( handle );
1067     }
1068   }
1069 }
1070
1071 void Button::OnTouchPointInterrupted()
1072 {
1073   OnTouchPointLeave();
1074 }
1075
1076 Toolkit::Button::ButtonSignalType& Button::PressedSignal()
1077 {
1078   return mPressedSignal;
1079 }
1080
1081 Toolkit::Button::ButtonSignalType& Button::ReleasedSignal()
1082 {
1083   return mReleasedSignal;
1084 }
1085
1086 Toolkit::Button::ButtonSignalType& Button::ClickedSignal()
1087 {
1088   return mClickedSignal;
1089 }
1090
1091 Toolkit::Button::ButtonSignalType& Button::StateChangedSignal()
1092 {
1093   return mStateChangedSignal;
1094 }
1095
1096 bool Button::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
1097 {
1098   Dali::BaseHandle handle( object );
1099
1100   bool connected( true );
1101   Toolkit::Button button = Toolkit::Button::DownCast( handle );
1102
1103   if( 0 == strcmp( signalName.c_str(), SIGNAL_PRESSED ) )
1104   {
1105     button.PressedSignal().Connect( tracker, functor );
1106   }
1107   else if( 0 == strcmp( signalName.c_str(), SIGNAL_RELEASED ) )
1108   {
1109     button.ReleasedSignal().Connect( tracker, functor );
1110   }
1111   else if( 0 == strcmp( signalName.c_str(), SIGNAL_CLICKED ) )
1112   {
1113     button.ClickedSignal().Connect( tracker, functor );
1114   }
1115   else if( 0 == strcmp( signalName.c_str(), SIGNAL_STATE_CHANGED ) )
1116   {
1117     button.StateChangedSignal().Connect( tracker, functor );
1118   }
1119   else
1120   {
1121     // signalName does not match any signal
1122     connected = false;
1123   }
1124
1125   return connected;
1126 }
1127
1128 bool Button::OnTouchEvent(const TouchEvent& event)
1129 {
1130   // Only events are processed when the button is not disabled and the touch event has only
1131   // one touch point.
1132   if( ( !mDisabled ) && ( 1 == event.GetPointCount() ) )
1133   {
1134     switch( event.GetPoint(0).state )
1135     {
1136       case TouchPoint::Down:
1137       {
1138         OnButtonDown(); // Notification for derived classes.
1139
1140         // Sets the button state to ButtonDown.
1141         mState = ButtonDown;
1142         break;
1143       }
1144       case TouchPoint::Up:
1145       {
1146         OnButtonUp(); // Notification for derived classes.
1147
1148         // Sets the button state to ButtonUp.
1149         mState = ButtonUp;
1150         break;
1151       }
1152       case TouchPoint::Interrupted:
1153       {
1154         OnTouchPointInterrupted(); // Notification for derived classes.
1155
1156         // Sets the button state to the default (ButtonUp).
1157         mState = ButtonUp;
1158         break;
1159       }
1160       case TouchPoint::Leave:
1161       {
1162         OnTouchPointLeave(); // Notification for derived classes.
1163
1164         // Sets the button state to the default (ButtonUp).
1165         mState = ButtonUp;
1166         break;
1167       }
1168       case TouchPoint::Motion:
1169       case TouchPoint::Stationary: // FALLTHROUGH
1170       {
1171         // Nothing to do
1172         break;
1173       }
1174       default:
1175       {
1176         DALI_ASSERT_ALWAYS( !"Point status unhandled." );
1177         break;
1178       }
1179     }
1180   }
1181   else if( 1 < event.GetPointCount() )
1182   {
1183     OnTouchPointLeave(); // Notification for derived classes.
1184
1185     // Sets the button state to the default (ButtonUp).
1186     mState = ButtonUp;
1187   }
1188
1189   return false;
1190 }
1191
1192 void Button::OnInitialize()
1193 {
1194   Actor self = Self();
1195
1196   mTapDetector = TapGestureDetector::New();
1197   mTapDetector.Attach( self );
1198   mTapDetector.DetectedSignal().Connect(this, &Button::OnTap);
1199
1200   OnButtonInitialize();
1201
1202   self.SetDrawMode( DrawMode::OVERLAY );
1203   self.SetKeyboardFocusable( true );
1204 }
1205
1206 void Button::OnActivated()
1207 {
1208   // When the button is activated, it performs the click action
1209   PropertyValueContainer attributes;
1210   DoClickAction( attributes );
1211 }
1212
1213 void Button::OnControlStageDisconnection()
1214 {
1215   OnButtonStageDisconnection(); // Notification for derived classes.
1216   mState = ButtonUp;
1217 }
1218
1219 void Button::OnTap(Actor actor, const TapGesture& tap)
1220 {
1221   // Do nothing.
1222 }
1223
1224 void Button::SetUpTimer( float delay )
1225 {
1226   mAutoRepeatingTimer = Dali::Timer::New( static_cast<unsigned int>( 1000.f * delay ) );
1227   mAutoRepeatingTimer.TickSignal().Connect( this, &Button::AutoRepeatingSlot );
1228   mAutoRepeatingTimer.Start();
1229 }
1230
1231 bool Button::AutoRepeatingSlot()
1232 {
1233   bool consumed = false;
1234   if( !mDisabled )
1235   {
1236     // Restart the autorepeat timer.
1237     SetUpTimer( mNextAutoRepeatingDelay );
1238
1239     Pressed();
1240
1241     Toolkit::Button handle( GetOwner() );
1242
1243     //Emit signal.
1244     consumed = mReleasedSignal.Emit( handle );
1245     consumed |= mClickedSignal.Emit( handle );
1246     consumed |= mPressedSignal.Emit( handle );
1247  }
1248
1249   return consumed;
1250 }
1251
1252 void Button::Pressed()
1253 {
1254   unsigned int buttonIndex, backgroundIndex;
1255   bool animationStarted = false;
1256
1257   switch( mPaintState )
1258   {
1259     case UnselectedState:
1260     {
1261       buttonIndex = FindChildIndex( mLabel );
1262       InsertChild( buttonIndex, mSelectedContent );
1263
1264       if( mBackgroundContent )
1265       {
1266         backgroundIndex = 1;
1267       }
1268       else
1269       {
1270         backgroundIndex = 0;
1271       }
1272
1273       InsertChild( backgroundIndex, mSelectedBackgroundContent );
1274
1275       // Notifies the derived class the button has been pressed.
1276       animationStarted = OnPressed();
1277
1278       if( animationStarted )
1279       {
1280         mPaintState = UnselectedSelectedTransition;
1281       }
1282       else
1283       {
1284         mPaintState = SelectedState;
1285       }
1286       break;
1287     }
1288     case SelectedUnselectedTransition:
1289     {
1290       // Notifies the derived class the button has been pressed.
1291       animationStarted = OnPressed();
1292
1293       if( animationStarted )
1294       {
1295         mPaintState = UnselectedSelectedTransition;
1296       }
1297       else
1298       {
1299         mPaintState = SelectedState;
1300       }
1301       break;
1302     }
1303     case DisabledUnselectedTransition:
1304     {
1305       buttonIndex = FindChildIndex( mLabel );
1306       InsertChild( buttonIndex, mSelectedContent );
1307
1308       if( mDisabledBackgroundContent )
1309       {
1310         if(  mBackgroundContent )
1311         {
1312           backgroundIndex = 2;
1313         }
1314         else
1315         {
1316           backgroundIndex = 1;
1317         }
1318       }
1319       else if( mBackgroundContent )
1320       {
1321         backgroundIndex = 1;
1322       }
1323       else
1324       {
1325         backgroundIndex = 0;
1326       }
1327
1328       InsertChild( backgroundIndex, mSelectedBackgroundContent );
1329
1330       // Notifies the derived class the button has been pressed.
1331       animationStarted = OnPressed();
1332
1333       if( animationStarted )
1334       {
1335         mPaintState = UnselectedSelectedTransition;
1336       }
1337       else
1338       {
1339         mPaintState = SelectedState;
1340       }
1341       break;
1342     }
1343     default:
1344       break;
1345   }
1346 }
1347
1348 void Button::Released()
1349 {
1350   unsigned int buttonIndex;
1351   bool animationStarted = false;
1352
1353   switch( mPaintState )
1354   {
1355     case SelectedState:
1356     {
1357       buttonIndex = FindChildIndex( mLabel );
1358       InsertChild( buttonIndex, mButtonContent );
1359
1360       // Notifies the derived class the button has been released.
1361       animationStarted = OnReleased();
1362
1363       if( animationStarted )
1364       {
1365         mPaintState = SelectedUnselectedTransition;
1366       }
1367       else
1368       {
1369         mPaintState = UnselectedState;
1370       }
1371       break;
1372     }
1373     case UnselectedSelectedTransition:
1374     {
1375       // Notifies the derived class the button has been released.
1376       animationStarted = OnReleased();
1377
1378       if( animationStarted )
1379       {
1380         mPaintState = SelectedUnselectedTransition;
1381       }
1382       else
1383       {
1384         mPaintState = UnselectedState;
1385       }
1386       break;
1387     }
1388     case DisabledSelectedTransition:
1389     {
1390       buttonIndex = FindChildIndex( mLabel );
1391       InsertChild( buttonIndex, mButtonContent );
1392
1393       // Notifies the derived class the button has been released.
1394       animationStarted = OnReleased();
1395
1396       if( animationStarted )
1397       {
1398         mPaintState = SelectedUnselectedTransition;
1399       }
1400       else
1401       {
1402         mPaintState = UnselectedState;
1403       }
1404       break;
1405     }
1406     default:
1407     {
1408       break;
1409     }
1410   }
1411 }
1412
1413 Button::ButtonState Button::GetState()
1414 {
1415   return mState;
1416 }
1417
1418 Button::PaintState Button::GetPaintState()
1419 {
1420   return mPaintState;
1421 }
1422
1423 void Button::InsertChild( unsigned int index, Actor& actor )
1424 {
1425   if( actor )
1426   {
1427     Self().Insert( index, actor);
1428   }
1429 }
1430
1431 void Button::RemoveChild( Actor& actor )
1432 {
1433   if( actor && actor.GetParent() )
1434   {
1435     Self().Remove( actor );
1436   }
1437 }
1438
1439 unsigned int Button::FindChildIndex( Actor& actor )
1440 {
1441   Actor self = Self();
1442   unsigned int childrenNum = self.GetChildCount();
1443
1444   for( unsigned int i = 0; i < childrenNum; i++ )
1445   {
1446     Actor child = self.GetChildAt( i );
1447     if( child == actor )
1448     {
1449       return i;
1450     }
1451   }
1452
1453   return childrenNum;
1454 }
1455
1456 void Button::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
1457 {
1458   Toolkit::Button button = Toolkit::Button::DownCast( Dali::BaseHandle( object ) );
1459
1460   if ( button )
1461   {
1462     switch ( index )
1463     {
1464       case Toolkit::Button::Property::DISABLED:
1465       {
1466         GetImplementation( button ).SetDisabled( value.Get<bool>() );
1467         break;
1468       }
1469
1470       case Toolkit::Button::Property::AUTO_REPEATING:
1471       {
1472         GetImplementation( button ).SetAutoRepeating( value.Get< bool >() );
1473         break;
1474       }
1475
1476       case Toolkit::Button::Property::INITIAL_AUTO_REPEATING_DELAY:
1477       {
1478         GetImplementation( button ).SetInitialAutoRepeatingDelay( value.Get< float >() );
1479         break;
1480       }
1481
1482       case Toolkit::Button::Property::NEXT_AUTO_REPEATING_DELAY:
1483       {
1484         GetImplementation( button ).SetNextAutoRepeatingDelay( value.Get< float >() );
1485         break;
1486       }
1487
1488       case Toolkit::Button::Property::TOGGLABLE:
1489       {
1490         GetImplementation( button ).SetTogglableButton( value.Get< bool >() );
1491         break;
1492       }
1493
1494       case Toolkit::Button::Property::SELECTED:
1495       {
1496         GetImplementation( button ).SetSelected( value.Get< bool >() );
1497         break;
1498       }
1499
1500       case Toolkit::Button::Property::NORMAL_STATE_ACTOR:
1501       {
1502         GetImplementation( button ).SetButtonImage( Scripting::NewActor( value.Get< Property::Map >() ) );
1503         break;
1504       }
1505
1506       case Toolkit::Button::Property::SELECTED_STATE_ACTOR:
1507       {
1508         GetImplementation( button ).SetSelectedImage( Scripting::NewActor( value.Get< Property::Map >() ) );
1509         break;
1510       }
1511
1512       case Toolkit::Button::Property::DISABLED_STATE_ACTOR:
1513       {
1514         GetImplementation( button ).SetDisabledImage( Scripting::NewActor( value.Get< Property::Map >() ) );
1515         break;
1516       }
1517
1518       case Toolkit::Button::Property::LABEL_ACTOR:
1519       {
1520         GetImplementation( button ).SetLabel( Scripting::NewActor( value.Get< Property::Map >() ) );
1521         break;
1522       }
1523     }
1524   }
1525 }
1526
1527 Property::Value Button::GetProperty( BaseObject* object, Property::Index propertyIndex )
1528 {
1529   Property::Value value;
1530
1531   Toolkit::Button button = Toolkit::Button::DownCast( Dali::BaseHandle( object ) );
1532
1533   if ( button )
1534   {
1535     switch ( propertyIndex )
1536     {
1537       case Toolkit::Button::Property::DISABLED:
1538       {
1539         value = GetImplementation( button ).mDisabled;
1540         break;
1541       }
1542
1543       case Toolkit::Button::Property::AUTO_REPEATING:
1544       {
1545         value = GetImplementation( button ).mAutoRepeating;
1546         break;
1547       }
1548
1549       case Toolkit::Button::Property::INITIAL_AUTO_REPEATING_DELAY:
1550       {
1551         value = GetImplementation( button ).mInitialAutoRepeatingDelay;
1552         break;
1553       }
1554
1555       case Toolkit::Button::Property::NEXT_AUTO_REPEATING_DELAY:
1556       {
1557         value = GetImplementation( button ).mNextAutoRepeatingDelay;
1558         break;
1559       }
1560
1561       case Toolkit::Button::Property::TOGGLABLE:
1562       {
1563         value = GetImplementation( button ).mTogglableButton;
1564         break;
1565       }
1566
1567       case Toolkit::Button::Property::SELECTED:
1568       {
1569         value = GetImplementation( button ).mSelected;
1570         break;
1571       }
1572
1573       case Toolkit::Button::Property::NORMAL_STATE_ACTOR:
1574       {
1575         Property::Map map;
1576         Scripting::CreatePropertyMap( GetImplementation( button ).mButtonContent, map );
1577         value = map;
1578         break;
1579       }
1580
1581       case Toolkit::Button::Property::SELECTED_STATE_ACTOR:
1582       {
1583         Property::Map map;
1584         Scripting::CreatePropertyMap( GetImplementation( button ).mSelectedContent, map );
1585         value = map;
1586         break;
1587       }
1588
1589       case Toolkit::Button::Property::DISABLED_STATE_ACTOR:
1590       {
1591         Property::Map map;
1592         Scripting::CreatePropertyMap( GetImplementation( button ).mDisabledContent, map );
1593         value = map;
1594         break;
1595       }
1596
1597       case Toolkit::Button::Property::LABEL_ACTOR:
1598       {
1599         Property::Map map;
1600         Scripting::CreatePropertyMap( GetImplementation( button ).mLabel, map );
1601         value = map;
1602         break;
1603       }
1604     }
1605   }
1606
1607   return value;
1608 }
1609
1610 } // namespace Internal
1611
1612 } // namespace Toolkit
1613
1614 } // namespace Dali