0f7a0a596a1f3c1e2e3c0fe2a594a39e146df077
[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 namespace Dali
32 {
33
34 namespace Toolkit
35 {
36
37 namespace Internal
38 {
39
40 namespace
41 {
42
43 BaseHandle Create()
44 {
45   // empty handle as we cannot create button (but type registered for clicked signal)
46   return BaseHandle();
47 }
48
49 // Setup properties, signals and actions using the type-registry.
50 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Button, Toolkit::Control, Create );
51
52 DALI_PROPERTY_REGISTRATION( Button, "disabled",                     BOOLEAN, DISABLED                     )
53 DALI_PROPERTY_REGISTRATION( Button, "auto-repeating",               BOOLEAN, AUTO_REPEATING               )
54 DALI_PROPERTY_REGISTRATION( Button, "initial-auto-repeating-delay", FLOAT,   INITIAL_AUTO_REPEATING_DELAY )
55 DALI_PROPERTY_REGISTRATION( Button, "next-auto-repeating-delay",    FLOAT,   NEXT_AUTO_REPEATING_DELAY    )
56 DALI_PROPERTY_REGISTRATION( Button, "togglable",                    BOOLEAN, TOGGLABLE                    )
57 DALI_PROPERTY_REGISTRATION( Button, "selected",                     BOOLEAN, SELECTED                     )
58 DALI_PROPERTY_REGISTRATION( Button, "normal-state-actor",           MAP,     NORMAL_STATE_ACTOR           )
59 DALI_PROPERTY_REGISTRATION( Button, "selected-state-actor",         MAP,     SELECTED_STATE_ACTOR         )
60 DALI_PROPERTY_REGISTRATION( Button, "disabled-state-actor",         MAP,     DISABLED_STATE_ACTOR         )
61 DALI_PROPERTY_REGISTRATION( Button, "label-actor",                  MAP,     LABEL_ACTOR                  )
62
63 DALI_SIGNAL_REGISTRATION(   Button, "pressed",                               SIGNAL_PRESSED               )
64 DALI_SIGNAL_REGISTRATION(   Button, "released",                              SIGNAL_RELEASED              )
65 DALI_SIGNAL_REGISTRATION(   Button, "clicked",                               SIGNAL_CLICKED               )
66 DALI_SIGNAL_REGISTRATION(   Button, "state-changed",                         SIGNAL_STATE_CHANGED         )
67
68 DALI_ACTION_REGISTRATION(   Button, "button-click",                          ACTION_BUTTON_CLICK          )
69
70 DALI_TYPE_REGISTRATION_END()
71
72 const unsigned int INITIAL_AUTOREPEATING_DELAY( 0.15f );
73 const unsigned int NEXT_AUTOREPEATING_DELAY( 0.05f );
74
75 } // unnamed namespace
76
77 Button::Button()
78 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
79   mAutoRepeatingTimer(),
80   mDisabled( false ),
81   mAutoRepeating( false ),
82   mTogglableButton( false ),
83   mSelected( false ),
84   mInitialAutoRepeatingDelay( INITIAL_AUTOREPEATING_DELAY ),
85   mNextAutoRepeatingDelay( NEXT_AUTOREPEATING_DELAY ),
86   mAnimationTime( 0.0f ),
87   mClickActionPerforming( false ),
88   mState( ButtonUp )
89 {
90 }
91
92 Button::~Button()
93 {
94   if( mAutoRepeatingTimer )
95   {
96     mAutoRepeatingTimer.Reset();
97   }
98 }
99
100 void Button::SetDisabled( bool disabled )
101 {
102   if( disabled != mDisabled )
103   {
104     mDisabled = disabled;
105
106     OnDisabled( mDisabled );
107   }
108 }
109
110 bool Button::IsDisabled() const
111 {
112   return mDisabled;
113 }
114
115 void Button::SetAutoRepeating( bool autoRepeating )
116 {
117   mAutoRepeating = autoRepeating;
118
119   // An autorepeating button can't be a togglable button.
120   if( autoRepeating )
121   {
122     mTogglableButton = false;
123
124     if( mSelected )
125     {
126       // Emit a signal is not wanted, only change the appearance.
127       OnSelected( false );
128
129       mSelected = false;
130
131       RelayoutRequest();
132     }
133   }
134 }
135
136 bool Button::IsAutoRepeating() const
137 {
138   return mAutoRepeating;
139 }
140
141 void Button::SetInitialAutoRepeatingDelay( float initialAutoRepeatingDelay )
142 {
143   DALI_ASSERT_ALWAYS( initialAutoRepeatingDelay > 0.f );
144   mInitialAutoRepeatingDelay = initialAutoRepeatingDelay;
145 }
146
147 float Button::GetInitialAutoRepeatingDelay() const
148 {
149   return mInitialAutoRepeatingDelay;
150 }
151
152 void Button::SetNextAutoRepeatingDelay( float nextAutoRepeatingDelay )
153 {
154   DALI_ASSERT_ALWAYS( nextAutoRepeatingDelay > 0.f );
155   mNextAutoRepeatingDelay = nextAutoRepeatingDelay;
156 }
157
158 float Button::GetNextAutoRepeatingDelay() const
159 {
160   return mNextAutoRepeatingDelay;
161 }
162
163 void Button::SetTogglableButton( bool togglable )
164 {
165   mTogglableButton = togglable;
166
167   // A togglable button can't be an autorepeating button.
168   if( togglable )
169   {
170     mAutoRepeating = false;
171   }
172 }
173
174 bool Button::IsTogglableButton() const
175 {
176   return mTogglableButton;
177 }
178
179 void Button::SetSelected( bool selected )
180 {
181   if( !mDisabled && mTogglableButton && ( selected != mSelected ) )
182   {
183     // Notifies the derived class the button has been selected.
184     OnSelected( selected );
185
186     mSelected = selected;
187
188     Toolkit::Button handle( GetOwner() );
189
190     // Emit signal.
191     mStateChangedSignal.Emit( handle );
192
193     RelayoutRequest();
194   }
195 }
196
197 bool Button::IsSelected() const
198 {
199   return mTogglableButton && mSelected;
200 }
201
202 void Button::SetAnimationTime( float animationTime )
203 {
204   mAnimationTime = animationTime;
205 }
206
207 float Button::GetAnimationTime() const
208 {
209   return mAnimationTime;
210 }
211
212 void Button::SetLabel( const std::string& label )
213 {
214   Toolkit::TextLabel textLabel = Toolkit::TextLabel::New( label );
215   SetLabel( textLabel );
216 }
217
218 void Button::SetLabel( Actor label )
219 {
220   if( mLabel != label )
221   {
222     if( mLabel && mLabel.GetParent() )
223     {
224       mLabel.GetParent().Remove( mLabel );
225     }
226
227     mLabel = label;
228
229     OnLabelSet();
230
231     RelayoutRequest();
232   }
233 }
234
235 Actor Button::GetLabel() const
236 {
237   return mLabel;
238 }
239
240 Actor& Button::GetLabel()
241 {
242   return mLabel;
243 }
244
245 Actor Button::GetButtonImage() const
246 {
247   return mButtonContent;
248 }
249
250 Actor& Button::GetButtonImage()
251 {
252   return mButtonContent;
253 }
254
255 Actor Button::GetSelectedImage() const
256 {
257   return mSelectedContent;
258 }
259
260 Actor& Button::GetSelectedImage()
261 {
262   return mSelectedContent;
263 }
264
265 Actor Button::GetBackgroundImage() const
266 {
267   return mBackgroundContent;
268 }
269
270 Actor& Button::GetBackgroundImage()
271 {
272   return mBackgroundContent;
273 }
274
275 Actor Button::GetDisabledImage() const
276 {
277   return mDisabledContent;
278 }
279
280 Actor& Button::GetDisabledImage()
281 {
282   return mDisabledContent;
283 }
284
285 Actor Button::GetDisabledSelectedImage() const
286 {
287   return mDisabledSelectedContent;
288 }
289
290 Actor& Button::GetDisabledSelectedImage()
291 {
292   return mDisabledSelectedContent;
293 }
294
295 Actor Button::GetDisabledBackgroundImage() const
296 {
297   return mDisabledBackgroundContent;
298 }
299
300 Actor& Button::GetDisabledBackgroundImage()
301 {
302   return mDisabledBackgroundContent;
303 }
304
305 bool Button::DoAction( BaseObject* object, const std::string& actionName, const PropertyValueContainer& attributes )
306 {
307   bool ret = false;
308
309   Dali::BaseHandle handle( object );
310
311   Toolkit::Button button = Toolkit::Button::DownCast( handle );
312
313   DALI_ASSERT_ALWAYS( button );
314
315   if( 0 == strcmp( actionName.c_str(), ACTION_BUTTON_CLICK ) )
316   {
317     GetImplementation( button ).DoClickAction( attributes );
318     ret = true;
319   }
320
321   return ret;
322 }
323
324 void Button::DoClickAction( const PropertyValueContainer& attributes )
325 {
326   // Prevents the button signals from doing a recursive loop by sending an action
327   // and re-emitting the signals.
328   if( !mClickActionPerforming )
329   {
330     mClickActionPerforming = true;
331     OnButtonDown();
332     mState = ButtonDown;
333     OnButtonUp();
334     mClickActionPerforming = false;
335   }
336 }
337
338 void Button::OnButtonStageDisconnection()
339 {
340   if( ButtonDown == mState )
341   {
342     if( !mTogglableButton )
343     {
344       Toolkit::Button handle( GetOwner() );
345
346       // Notifies the derived class the button has been released.
347       OnReleased();
348
349       if( mAutoRepeating )
350       {
351         mAutoRepeatingTimer.Reset();
352       }
353     }
354   }
355 }
356
357 void Button::OnButtonDown()
358 {
359   if( !mTogglableButton )
360   {
361     Toolkit::Button handle( GetOwner() );
362
363     // Notifies the derived class the button has been pressed.
364     OnPressed();
365
366     if( mAutoRepeating )
367     {
368       SetUpTimer( mInitialAutoRepeatingDelay );
369     }
370
371     //Emit signal.
372     mPressedSignal.Emit( handle );
373   }
374 }
375
376 void Button::OnButtonUp()
377 {
378   if( ButtonDown == mState )
379   {
380     if( mTogglableButton )
381     {
382       SetSelected( !mSelected );
383     }
384     else
385     {
386       // Notifies the derived class the button has been clicked.
387       OnReleased();
388       OnClicked();
389
390       if( mAutoRepeating )
391       {
392         mAutoRepeatingTimer.Reset();
393       }
394
395       Toolkit::Button handle( GetOwner() );
396
397       //Emit signal.
398       mReleasedSignal.Emit( handle );
399       mClickedSignal.Emit( handle );
400     }
401   }
402 }
403
404 void Button::OnTouchPointLeave()
405 {
406   if( ButtonDown == mState )
407   {
408     if( !mTogglableButton )
409     {
410       Toolkit::Button handle( GetOwner() );
411
412       // Notifies the derived class the button has been released.
413       OnReleased();
414
415       if( mAutoRepeating )
416       {
417         mAutoRepeatingTimer.Reset();
418       }
419
420       //Emit signal.
421       mReleasedSignal.Emit( handle );
422     }
423   }
424 }
425
426 void Button::OnTouchPointInterrupted()
427 {
428   OnTouchPointLeave();
429 }
430
431 Toolkit::Button::ButtonSignalType& Button::PressedSignal()
432 {
433   return mPressedSignal;
434 }
435
436 Toolkit::Button::ButtonSignalType& Button::ReleasedSignal()
437 {
438   return mReleasedSignal;
439 }
440
441 Toolkit::Button::ButtonSignalType& Button::ClickedSignal()
442 {
443   return mClickedSignal;
444 }
445
446 Toolkit::Button::ButtonSignalType& Button::StateChangedSignal()
447 {
448   return mStateChangedSignal;
449 }
450
451 bool Button::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
452 {
453   Dali::BaseHandle handle( object );
454
455   bool connected( true );
456   Toolkit::Button button = Toolkit::Button::DownCast( handle );
457
458   if( 0 == strcmp( signalName.c_str(), SIGNAL_PRESSED ) )
459   {
460     button.PressedSignal().Connect( tracker, functor );
461   }
462   else if( 0 == strcmp( signalName.c_str(), SIGNAL_RELEASED ) )
463   {
464     button.ReleasedSignal().Connect( tracker, functor );
465   }
466   else if( 0 == strcmp( signalName.c_str(), SIGNAL_CLICKED ) )
467   {
468     button.ClickedSignal().Connect( tracker, functor );
469   }
470   else if( 0 == strcmp( signalName.c_str(), SIGNAL_STATE_CHANGED ) )
471   {
472     button.StateChangedSignal().Connect( tracker, functor );
473   }
474   else
475   {
476     // signalName does not match any signal
477     connected = false;
478   }
479
480   return connected;
481 }
482
483 bool Button::OnTouchEvent(const TouchEvent& event)
484 {
485   // Only events are processed when the button is not disabled and the touch event has only
486   // one touch point.
487   if( ( !mDisabled ) && ( 1 == event.GetPointCount() ) )
488   {
489     switch( event.GetPoint(0).state )
490     {
491       case TouchPoint::Down:
492       {
493         OnButtonDown(); // Notification for derived classes.
494
495         // Sets the button state to ButtonDown.
496         mState = ButtonDown;
497         break;
498       }
499       case TouchPoint::Up:
500       {
501         OnButtonUp(); // Notification for derived classes.
502
503         // Sets the button state to ButtonUp.
504         mState = ButtonUp;
505         break;
506       }
507       case TouchPoint::Interrupted:
508       {
509         OnTouchPointInterrupted(); // Notification for derived classes.
510
511         // Sets the button state to the default (ButtonUp).
512         mState = ButtonUp;
513         break;
514       }
515       case TouchPoint::Leave:
516       {
517         OnTouchPointLeave(); // Notification for derived classes.
518
519         // Sets the button state to the default (ButtonUp).
520         mState = ButtonUp;
521         break;
522       }
523       case TouchPoint::Motion:
524       case TouchPoint::Stationary: // FALLTHROUGH
525       {
526         // Nothing to do
527         break;
528       }
529       default:
530       {
531         DALI_ASSERT_ALWAYS( !"Point status unhandled." );
532         break;
533       }
534     }
535   }
536   else if( 1 < event.GetPointCount() )
537   {
538     OnTouchPointLeave(); // Notification for derived classes.
539
540     // Sets the button state to the default (ButtonUp).
541     mState = ButtonUp;
542   }
543
544   return false;
545 }
546
547 void Button::OnInitialize()
548 {
549   Actor self = Self();
550
551   mTapDetector = TapGestureDetector::New();
552   mTapDetector.Attach( self );
553   mTapDetector.DetectedSignal().Connect(this, &Button::OnTap);
554
555   OnButtonInitialize();
556
557   self.SetKeyboardFocusable( true );
558 }
559
560 void Button::OnActivated()
561 {
562   // When the button is activated, it performs the click action
563   PropertyValueContainer attributes;
564   DoClickAction( attributes );
565 }
566
567 void Button::OnTap(Actor actor, const TapGesture& tap)
568 {
569   // Do nothing.
570 }
571
572 void Button::SetUpTimer( float delay )
573 {
574   mAutoRepeatingTimer = Dali::Timer::New( static_cast<unsigned int>( 1000.f * delay ) );
575   mAutoRepeatingTimer.TickSignal().Connect( this, &Button::AutoRepeatingSlot );
576   mAutoRepeatingTimer.Start();
577 }
578
579 bool Button::AutoRepeatingSlot()
580 {
581   bool consumed = false;
582   if( !mDisabled )
583   {
584     // Restart the autorepeat timer.
585     SetUpTimer( mNextAutoRepeatingDelay );
586
587     Toolkit::Button handle( GetOwner() );
588
589     // Notifies the derived class the button has been pressed.
590     OnPressed();
591
592     //Emit signal.
593     consumed = mReleasedSignal.Emit( handle );
594     consumed |= mClickedSignal.Emit( handle );
595     consumed |= mPressedSignal.Emit( handle );
596  }
597
598   return consumed;
599 }
600
601 void Button::OnControlStageDisconnection()
602 {
603   OnButtonStageDisconnection(); // Notification for derived classes.
604   mState = ButtonUp;
605 }
606
607 Button::ButtonState Button::GetState()
608 {
609   return mState;
610 }
611
612 void Button::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
613 {
614   Toolkit::Button button = Toolkit::Button::DownCast( Dali::BaseHandle( object ) );
615
616   if ( button )
617   {
618     switch ( index )
619     {
620       case Toolkit::Button::Property::DISABLED:
621       {
622         GetImplementation( button ).SetDisabled( value.Get<bool>() );
623         break;
624       }
625
626       case Toolkit::Button::Property::AUTO_REPEATING:
627       {
628         GetImplementation( button ).SetAutoRepeating( value.Get< bool >() );
629         break;
630       }
631
632       case Toolkit::Button::Property::INITIAL_AUTO_REPEATING_DELAY:
633       {
634         GetImplementation( button ).SetInitialAutoRepeatingDelay( value.Get< float >() );
635         break;
636       }
637
638       case Toolkit::Button::Property::NEXT_AUTO_REPEATING_DELAY:
639       {
640         GetImplementation( button ).SetNextAutoRepeatingDelay( value.Get< float >() );
641         break;
642       }
643
644       case Toolkit::Button::Property::TOGGLABLE:
645       {
646         GetImplementation( button ).SetTogglableButton( value.Get< bool >() );
647         break;
648       }
649
650       case Toolkit::Button::Property::SELECTED:
651       {
652         GetImplementation( button ).SetSelected( value.Get< bool >() );
653         break;
654       }
655
656       case Toolkit::Button::Property::NORMAL_STATE_ACTOR:
657       {
658         GetImplementation( button ).SetButtonImage( Scripting::NewActor( value.Get< Property::Map >() ) );
659         break;
660       }
661
662       case Toolkit::Button::Property::SELECTED_STATE_ACTOR:
663       {
664         GetImplementation( button ).SetSelectedImage( Scripting::NewActor( value.Get< Property::Map >() ) );
665         break;
666       }
667
668       case Toolkit::Button::Property::DISABLED_STATE_ACTOR:
669       {
670         GetImplementation( button ).SetDisabledImage( Scripting::NewActor( value.Get< Property::Map >() ) );
671         break;
672       }
673
674       case Toolkit::Button::Property::LABEL_ACTOR:
675       {
676         GetImplementation( button ).SetLabel( Scripting::NewActor( value.Get< Property::Map >() ) );
677         break;
678       }
679     }
680   }
681 }
682
683 Property::Value Button::GetProperty( BaseObject* object, Property::Index propertyIndex )
684 {
685   Property::Value value;
686
687   Toolkit::Button button = Toolkit::Button::DownCast( Dali::BaseHandle( object ) );
688
689   if ( button )
690   {
691     switch ( propertyIndex )
692     {
693       case Toolkit::Button::Property::DISABLED:
694       {
695         value = GetImplementation( button ).mDisabled;
696         break;
697       }
698
699       case Toolkit::Button::Property::AUTO_REPEATING:
700       {
701         value = GetImplementation( button ).mAutoRepeating;
702         break;
703       }
704
705       case Toolkit::Button::Property::INITIAL_AUTO_REPEATING_DELAY:
706       {
707         value = GetImplementation( button ).mInitialAutoRepeatingDelay;
708         break;
709       }
710
711       case Toolkit::Button::Property::NEXT_AUTO_REPEATING_DELAY:
712       {
713         value = GetImplementation( button ).mNextAutoRepeatingDelay;
714         break;
715       }
716
717       case Toolkit::Button::Property::TOGGLABLE:
718       {
719         value = GetImplementation( button ).mTogglableButton;
720         break;
721       }
722
723       case Toolkit::Button::Property::SELECTED:
724       {
725         value = GetImplementation( button ).mSelected;
726         break;
727       }
728
729       case Toolkit::Button::Property::NORMAL_STATE_ACTOR:
730       {
731         Property::Map map;
732         Scripting::CreatePropertyMap( GetImplementation( button ).mButtonContent, map );
733         value = map;
734         break;
735       }
736
737       case Toolkit::Button::Property::SELECTED_STATE_ACTOR:
738       {
739         Property::Map map;
740         Scripting::CreatePropertyMap( GetImplementation( button ).mSelectedContent, map );
741         value = map;
742         break;
743       }
744
745       case Toolkit::Button::Property::DISABLED_STATE_ACTOR:
746       {
747         Property::Map map;
748         Scripting::CreatePropertyMap( GetImplementation( button ).mDisabledContent, map );
749         value = map;
750         break;
751       }
752
753       case Toolkit::Button::Property::LABEL_ACTOR:
754       {
755         Property::Map map;
756         Scripting::CreatePropertyMap( GetImplementation( button ).mLabel, map );
757         value = map;
758         break;
759       }
760     }
761   }
762
763   return value;
764 }
765
766 } // namespace Internal
767
768 } // namespace Toolkit
769
770 } // namespace Dali