Merge "Remove obsolete and non functional SizeChanged signal from actor" into tizen
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / buttons / push-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 "push-button-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <algorithm>
23 #include <dali/public-api/actors/image-actor.h>
24 #include <dali/public-api/object/type-registry.h>
25 #include <dali/public-api/scripting/scripting.h>
26
27 // INTERNAL INCLUDES
28 #include "push-button-default-painter-impl.h"
29
30 #include <dali-toolkit/public-api/controls/text-view/text-view.h>
31 #include <dali-toolkit/internal/controls/relayout-helper.h>
32
33 namespace Dali
34 {
35
36 namespace Toolkit
37 {
38
39 namespace Internal
40 {
41
42 namespace
43 {
44
45 BaseHandle Create()
46 {
47   return Toolkit::PushButton::New();
48 }
49
50 TypeRegistration typeRegistration( typeid(Toolkit::PushButton), typeid(Toolkit::Button), Create );
51
52 SignalConnectorType signalConnector1( typeRegistration, Toolkit::PushButton::SIGNAL_PRESSED , &PushButton::DoConnectSignal );
53 SignalConnectorType signalConnector2( typeRegistration, Toolkit::PushButton::SIGNAL_RELEASED, &PushButton::DoConnectSignal );
54
55 TypeAction action1( typeRegistration, Toolkit::PushButton::ACTION_PUSH_BUTTON_CLICK, &PushButton::DoAction );
56
57 } // unnamed namespace
58
59 namespace
60 {
61
62 const unsigned int INITIAL_AUTOREPEATING_DELAY( 0.15f );
63 const unsigned int NEXT_AUTOREPEATING_DELAY( 0.05f );
64
65 const float TEXT_PADDING = 12.0f;
66
67 // Helper function used to cast a ButtonPainter to PushButtonDefaultPainter
68 PushButtonDefaultPainterPtr GetPushButtonPainter( Dali::Toolkit::Internal::ButtonPainterPtr painter )
69 {
70   return static_cast<PushButtonDefaultPainter*>( painter.Get() );
71 }
72
73 /**
74  * Find the first image actor in the actor hierarchy
75  */
76 ImageActor FindImageActor( Actor root )
77 {
78   ImageActor imageActor = ImageActor::DownCast( root );
79   if( !imageActor && root )
80   {
81     for( unsigned int i = 0, numChildren = root.GetChildCount(); i < numChildren; ++i )
82     {
83       ImageActor childImageActor = FindImageActor( root.GetChildAt( i ) );
84       if( childImageActor )
85       {
86         return childImageActor;
87       }
88     }
89   }
90
91   return imageActor;
92 }
93
94
95 } // unnamed namespace
96
97 Dali::Toolkit::PushButton PushButton::New()
98 {
99   // Create the implementation, temporarily owned on stack
100   IntrusivePtr< PushButton > internalPushButton = new PushButton();
101
102   // Pass ownership to CustomActor
103   Dali::Toolkit::PushButton pushButton( *internalPushButton );
104
105   // Second-phase init of the implementation
106   // This can only be done after the CustomActor connection has been made...
107   internalPushButton->Initialize();
108
109   return pushButton;
110 }
111
112 void PushButton::SetAutoRepeating( bool autoRepeating )
113 {
114   mAutoRepeating = autoRepeating;
115
116   // An autorepeating button can't be a toggle button.
117   if( autoRepeating )
118   {
119     mToggleButton = false;
120     if( mToggled )
121     {
122       // Emit a signal is not wanted, only change the appearance.
123       Toolkit::PushButton handle( GetOwner() );
124       GetPushButtonPainter( mPainter )->Toggled( handle );
125       mToggled = false;
126     }
127   }
128
129   // Notifies the painter.
130   GetPushButtonPainter( mPainter )->SetAutoRepeating( mAutoRepeating );
131 }
132
133 bool PushButton::IsAutoRepeating() const
134 {
135   return mAutoRepeating;
136 }
137
138 void PushButton::SetInitialAutoRepeatingDelay( float initialAutoRepeatingDelay )
139 {
140   DALI_ASSERT_ALWAYS( initialAutoRepeatingDelay > 0.f );
141   mInitialAutoRepeatingDelay = initialAutoRepeatingDelay;
142 }
143
144 float PushButton::GetInitialAutoRepeatingDelay() const
145 {
146   return mInitialAutoRepeatingDelay;
147 }
148
149 void PushButton::SetNextAutoRepeatingDelay( float nextAutoRepeatingDelay )
150 {
151   DALI_ASSERT_ALWAYS( nextAutoRepeatingDelay > 0.f );
152   mNextAutoRepeatingDelay = nextAutoRepeatingDelay;
153 }
154
155 float PushButton::GetNextAutoRepeatingDelay() const
156 {
157   return mNextAutoRepeatingDelay;
158 }
159
160 void PushButton::SetToggleButton( bool toggle )
161 {
162   mToggleButton = toggle;
163
164   // A toggle button can't be an autorepeating button.
165   if( toggle )
166   {
167     mAutoRepeating = false;
168
169     // Notifies the painter.
170     GetPushButtonPainter( mPainter )->SetAutoRepeating( mAutoRepeating );
171   }
172 }
173
174 bool PushButton::IsToggleButton() const
175 {
176   return mToggleButton;
177 }
178
179 void PushButton::SetToggled( bool toggle )
180 {
181   if( !mDisabled && mToggleButton && ( toggle != mToggled ) )
182   {
183     mToggled = toggle;
184
185     Toolkit::PushButton handle( GetOwner() );
186
187     // Notifies the painter the button has been toggled.
188     GetPushButtonPainter( mPainter )->Toggled( handle );
189
190     // Emit signal.
191     mStateChangedSignal.Emit( handle, mToggled );
192   }
193 }
194
195 bool PushButton::IsToggled() const
196 {
197   return mToggleButton && mToggled;
198 }
199
200 void PushButton::SetButtonImage( Image image )
201 {
202   SetButtonImage( ImageActor::New( image ) );
203 }
204
205 void PushButton::SetButtonImage( Actor image )
206 {
207   Toolkit::PushButton handle( GetOwner() );
208   GetPushButtonPainter( mPainter )->SetButtonImage( handle, image );
209 }
210
211 Actor& PushButton::GetButtonImage()
212 {
213   return mButtonImage;
214 }
215
216 Actor PushButton::GetButtonImage() const
217 {
218   return mButtonImage;
219 }
220
221 void PushButton::SetBackgroundImage( Image image )
222 {
223   SetBackgroundImage( ImageActor::New( image ) );
224 }
225
226 void PushButton::SetBackgroundImage( Actor image )
227 {
228   Toolkit::PushButton handle( GetOwner() );
229   GetPushButtonPainter( mPainter )->SetBackgroundImage( handle, image );
230 }
231
232 Actor& PushButton::GetBackgroundImage()
233 {
234   return mBackgroundImage;
235 }
236
237 Actor PushButton::GetBackgroundImage() const
238 {
239   return mBackgroundImage;
240 }
241
242 void PushButton::SetSelectedImage( Image image )
243 {
244   SetSelectedImage( ImageActor::New( image ) );
245 }
246
247 void PushButton::SetSelectedImage( Actor image )
248 {
249   Toolkit::PushButton handle( GetOwner() );
250   GetPushButtonPainter( mPainter )->SetSelectedImage( handle, image );
251 }
252
253 Actor& PushButton::GetSelectedImage()
254 {
255   return mSelectedImage;
256 }
257
258 Actor PushButton::GetSelectedImage() const
259 {
260   return mSelectedImage;
261 }
262
263 void PushButton::SetDisabledBackgroundImage( Image image )
264 {
265   SetDisabledBackgroundImage( ImageActor::New( image ) );
266 }
267
268 void PushButton::SetDisabledBackgroundImage( Actor image )
269 {
270   Toolkit::PushButton handle( GetOwner() );
271   GetPushButtonPainter( mPainter )->SetDisabledBackgroundImage( handle, image );
272 }
273
274 Actor& PushButton::GetDisabledBackgroundImage()
275 {
276   return mDisabledBackgroundImage;
277 }
278
279 Actor PushButton::GetDisabledBackgroundImage() const
280 {
281   return mDisabledBackgroundImage;
282 }
283
284 void PushButton::SetDisabledImage( Image image )
285 {
286   SetDisabledImage( ImageActor::New( image ) );
287 }
288
289 void PushButton::SetDisabledImage( Actor image )
290 {
291   Toolkit::PushButton handle( GetOwner() );
292   GetPushButtonPainter( mPainter )->SetDisabledImage( handle, image );
293 }
294
295 Actor& PushButton::GetDisabledImage()
296 {
297   return mDisabledImage;
298 }
299
300 Actor PushButton::GetDisabledImage() const
301 {
302   return mDisabledImage;
303 }
304
305 void PushButton::SetLabel( const std::string& label )
306 {
307   Toolkit::TextView textView ( Toolkit::TextView::New( label ) );
308   textView.SetWidthExceedPolicy( Toolkit::TextView::ShrinkToFit ); // Make sure our text always fits inside the button
309   SetLabel( textView );
310 }
311
312 void PushButton::SetLabel( Actor label )
313 {
314   Toolkit::PushButton handle( GetOwner() );
315   GetPushButtonPainter( mPainter )->SetLabel( handle, label );
316 }
317
318 Actor PushButton::GetLabel() const
319 {
320   return mLabel;
321 }
322
323 Actor& PushButton::GetLabel()
324 {
325   return mLabel;
326 }
327
328 Actor& PushButton::GetFadeOutBackgroundImage()
329 {
330   return mFadeOutBackgroundImage;
331 }
332
333 Actor& PushButton::GetFadeOutButtonImage()
334 {
335   return mFadeOutButtonImage;
336 }
337
338 Toolkit::PushButton::PressedSignalType& PushButton::PressedSignal()
339 {
340   return mPressedSignal;
341 }
342
343 Toolkit::PushButton::ReleasedSignalType& PushButton::ReleasedSignal()
344 {
345   return mReleasedSignal;
346 }
347
348 bool PushButton::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
349 {
350   Dali::BaseHandle handle( object );
351
352   bool connected( true );
353   Toolkit::PushButton button = Toolkit::PushButton::DownCast(handle);
354
355   if( Toolkit::PushButton::SIGNAL_STATE_CHANGED == signalName )
356   {
357     button.StateChangedSignal().Connect( tracker, functor );
358   }
359   else if( Toolkit::PushButton::SIGNAL_PRESSED == signalName )
360   {
361     button.PressedSignal().Connect( tracker, functor );
362   }
363   else if( Toolkit::PushButton::SIGNAL_RELEASED == signalName )
364   {
365     button.ReleasedSignal().Connect( tracker, functor );
366   }
367   else
368   {
369     // signalName does not match any signal
370     connected = false;
371   }
372
373   return connected;
374 }
375
376 void PushButton::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
377 {
378   Toolkit::PushButton pushButton = Toolkit::PushButton::DownCast( Dali::BaseHandle( object ) );
379
380   if ( pushButton )
381   {
382     PushButton& pushButtonImpl( GetImplementation( pushButton ) );
383
384     if ( propertyIndex == Toolkit::Button::PROPERTY_AUTO_REPEATING )
385     {
386       pushButtonImpl.SetAutoRepeating( value.Get< bool >() );
387     }
388     else if ( propertyIndex == Toolkit::Button::PROPERTY_INITIAL_AUTO_REPEATING_DELAY )
389     {
390       pushButtonImpl.SetInitialAutoRepeatingDelay( value.Get< float >() );
391     }
392     else if ( propertyIndex == Toolkit::Button::PROPERTY_NEXT_AUTO_REPEATING_DELAY )
393     {
394       pushButtonImpl.SetNextAutoRepeatingDelay( value.Get< float >() );
395     }
396     else if ( propertyIndex == Toolkit::Button::PROPERTY_TOGGLABLE )
397     {
398       pushButtonImpl.SetToggleButton( value.Get< bool >() );
399     }
400     else if ( propertyIndex == Toolkit::Button::PROPERTY_TOGGLED )
401     {
402       pushButtonImpl.SetToggled( value.Get< bool >() );
403     }
404     else if ( propertyIndex == Toolkit::Button::PROPERTY_NORMAL_STATE_ACTOR )
405     {
406       pushButtonImpl.SetButtonImage( Scripting::NewActor( value.Get< Property::Map >() ) );
407     }
408     else if ( propertyIndex == Toolkit::Button::PROPERTY_SELECTED_STATE_ACTOR )
409     {
410       pushButtonImpl.SetSelectedImage( Scripting::NewActor( value.Get< Property::Map >() ) );
411     }
412     else if ( propertyIndex == Toolkit::Button::PROPERTY_DISABLED_STATE_ACTOR )
413     {
414       pushButtonImpl.SetDisabledImage( Scripting::NewActor( value.Get< Property::Map >() ) );
415     }
416     else if ( propertyIndex == Toolkit::Button::PROPERTY_LABEL_ACTOR )
417     {
418       pushButtonImpl.SetLabel( Scripting::NewActor( value.Get< Property::Map >() ) );
419     }
420   }
421 }
422
423 Property::Value PushButton::GetProperty( BaseObject* object, Property::Index propertyIndex )
424 {
425   Property::Value value;
426
427   Toolkit::PushButton pushButton = Toolkit::PushButton::DownCast( Dali::BaseHandle( object ) );
428
429   if ( pushButton )
430   {
431     PushButton& pushButtonImpl( GetImplementation( pushButton ) );
432
433     if ( propertyIndex == Toolkit::Button::PROPERTY_AUTO_REPEATING )
434     {
435       value = pushButtonImpl.mAutoRepeating;
436     }
437     else if ( propertyIndex == Toolkit::Button::PROPERTY_INITIAL_AUTO_REPEATING_DELAY )
438     {
439       value = pushButtonImpl.mInitialAutoRepeatingDelay;
440     }
441     else if ( propertyIndex == Toolkit::Button::PROPERTY_NEXT_AUTO_REPEATING_DELAY )
442     {
443       value = pushButtonImpl.mNextAutoRepeatingDelay;
444     }
445     else if ( propertyIndex == Toolkit::Button::PROPERTY_TOGGLABLE )
446     {
447       value = pushButtonImpl.mToggleButton;
448     }
449     else if ( propertyIndex == Toolkit::Button::PROPERTY_TOGGLED )
450     {
451       value = pushButtonImpl.mToggled;
452     }
453     else if ( propertyIndex == Toolkit::Button::PROPERTY_NORMAL_STATE_ACTOR )
454     {
455       Property::Map map;
456       Scripting::CreatePropertyMap( pushButtonImpl.mButtonImage, map );
457       value = map;
458     }
459     else if ( propertyIndex == Toolkit::Button::PROPERTY_SELECTED_STATE_ACTOR )
460     {
461       Property::Map map;
462       Scripting::CreatePropertyMap( pushButtonImpl.mSelectedImage, map );
463       value = map;
464     }
465     else if ( propertyIndex == Toolkit::Button::PROPERTY_DISABLED_STATE_ACTOR )
466     {
467       Property::Map map;
468       Scripting::CreatePropertyMap( pushButtonImpl.mDisabledImage, map );
469       value = map;
470     }
471     else if ( propertyIndex == Toolkit::Button::PROPERTY_LABEL_ACTOR )
472     {
473       Property::Map map;
474       Scripting::CreatePropertyMap( pushButtonImpl.mLabel, map );
475       value = map;
476     }
477   }
478
479   return value;
480 }
481
482 void PushButton::OnButtonInitialize()
483 {
484   // Push button requires the Leave event.
485   Actor root = Self();
486   root.SetLeaveRequired( true );
487 }
488
489 void PushButton::OnButtonDown()
490 {
491   if( !mToggleButton )
492   {
493     Toolkit::PushButton handle( GetOwner() );
494
495     // Notifies the painter the button has been pressed.
496     GetPushButtonPainter( mPainter )->Pressed( handle );
497
498     if( mAutoRepeating )
499     {
500       SetUpTimer( mInitialAutoRepeatingDelay );
501     }
502
503     //Emit signal.
504     mPressedSignal.Emit( handle );
505   }
506 }
507
508 void PushButton::OnButtonUp()
509 {
510   if( ButtonDown == mState )
511   {
512     if( mToggleButton )
513     {
514       mToggled = !mToggled;
515
516       Toolkit::PushButton handle( GetOwner() );
517
518       // Notifies the painter the button has been toggled.
519       GetPushButtonPainter( mPainter )->Toggled( handle );
520
521       // Emit signal.
522       mStateChangedSignal.Emit( handle, mToggled );
523     }
524     else
525     {
526       Toolkit::PushButton handle( GetOwner() );
527
528       // Notifies the painter the button has been clicked.
529       GetPushButtonPainter( mPainter )->Released( handle );
530       GetPushButtonPainter( mPainter )->Clicked( handle );
531
532       if( mAutoRepeating )
533       {
534         mAutoRepeatingTimer.Reset();
535       }
536
537       //Emit signal.
538       mReleasedSignal.Emit( handle );
539       mClickedSignal.Emit( handle );
540     }
541   }
542 }
543
544 void PushButton::OnTouchPointLeave()
545 {
546   if( ButtonDown == mState )
547   {
548     if( !mToggleButton )
549     {
550       Toolkit::PushButton handle( GetOwner() );
551
552       // Notifies the painter the button has been released.
553       GetPushButtonPainter( mPainter )->Released( handle );
554
555       if( mAutoRepeating )
556       {
557         mAutoRepeatingTimer.Reset();
558       }
559
560       //Emit signal.
561       mReleasedSignal.Emit( handle );
562     }
563   }
564 }
565
566 void PushButton::OnTouchPointInterrupted()
567 {
568   OnTouchPointLeave();
569 }
570
571 void PushButton::OnAnimationTimeSet( float animationTime )
572 {
573   GetPushButtonPainter( mPainter )->SetAnimationTime( animationTime );
574 }
575
576 float PushButton::OnAnimationTimeRequested() const
577 {
578   return GetPushButtonPainter( mPainter )->GetAnimationTime();
579 }
580
581 void PushButton::OnButtonStageDisconnection()
582 {
583   if( ButtonDown == mState )
584   {
585     if( !mToggleButton )
586     {
587       Toolkit::PushButton handle( GetOwner() );
588
589       // Notifies the painter the button has been released.
590       GetPushButtonPainter( mPainter )->Released( handle );
591
592       if( mAutoRepeating )
593       {
594         mAutoRepeatingTimer.Reset();
595       }
596     }
597   }
598 }
599
600 PushButton::PushButton()
601 : Button(),
602   mAutoRepeating( false ),
603   mInitialAutoRepeatingDelay( INITIAL_AUTOREPEATING_DELAY ),
604   mNextAutoRepeatingDelay( NEXT_AUTOREPEATING_DELAY ),
605   mToggleButton( false ),
606   mAutoRepeatingTimer(),
607   mToggled( false ),
608   mClickActionPerforming(false)
609 {
610   // Creates specific painter.
611   mPainter = PushButtonDefaultPainterPtr( new PushButtonDefaultPainter() );
612 }
613
614 PushButton::~PushButton()
615 {
616   if( mAutoRepeatingTimer )
617   {
618     mAutoRepeatingTimer.Reset();
619   }
620
621   mPainter = NULL;
622 }
623
624 void PushButton::SetUpTimer( float delay )
625 {
626   mAutoRepeatingTimer = Dali::Timer::New( static_cast<unsigned int>( 1000.f * delay ) );
627   mAutoRepeatingTimer.TickSignal().Connect( this, &PushButton::AutoRepeatingSlot );
628   mAutoRepeatingTimer.Start();
629 }
630
631 bool PushButton::AutoRepeatingSlot()
632 {
633   bool consumed = false;
634   if( !mDisabled )
635   {
636     // Restart the autorepeat timer.
637     SetUpTimer( mNextAutoRepeatingDelay );
638
639     Toolkit::PushButton handle( GetOwner() );
640
641     // Notifies the painter the button has been pressed.
642     GetPushButtonPainter( mPainter )->Pressed( handle );
643
644     //Emit signal.
645     consumed = mReleasedSignal.Emit( handle );
646     consumed |= mClickedSignal.Emit( handle );
647     consumed |= mPressedSignal.Emit( handle );
648  }
649
650   return consumed;
651 }
652
653 void PushButton::OnActivated()
654 {
655   // When the button is activated, it performs the click action
656   PropertyValueContainer attributes;
657   DoClickAction(attributes);
658 }
659
660 Vector3 PushButton::GetNaturalSize()
661 {
662   Vector3 size = Control::GetNaturalSize();
663
664   const bool widthIsZero = EqualsZero( size.width );
665   const bool heightIsZero = EqualsZero( size.height );
666
667   if( widthIsZero || heightIsZero )
668   {
669     // If background and background not scale9 try get size from that
670     ImageActor imageActor = FindImageActor( mButtonImage );
671     if( imageActor && imageActor.GetStyle() != ImageActor::STYLE_NINE_PATCH )
672     {
673       Vector3 imageSize = RelayoutHelper::GetNaturalSize( imageActor );
674
675       if( widthIsZero )
676       {
677         size.width = imageSize.width;
678       }
679
680       if( heightIsZero )
681       {
682         size.height = imageSize.height;
683       }
684     }
685
686     ImageActor backgroundImageActor = FindImageActor( mBackgroundImage );
687     if( backgroundImageActor && backgroundImageActor.GetStyle() != ImageActor::STYLE_NINE_PATCH )
688     {
689       Vector3 imageSize = RelayoutHelper::GetNaturalSize( backgroundImageActor );
690
691       if( widthIsZero )
692       {
693         size.width = std::max( size.width, imageSize.width );
694       }
695
696       if( heightIsZero )
697       {
698         size.height = std::max( size.height, imageSize.height );
699       }
700     }
701
702     // If label, test against it's size
703     Toolkit::TextView textView = Toolkit::TextView::DownCast( mLabel );
704     if( textView )
705     {
706       Vector3 textViewSize = textView.GetNaturalSize();
707
708       if( widthIsZero )
709       {
710         size.width = std::max( size.width, textViewSize.width + TEXT_PADDING * 2.0f );
711       }
712
713       if( heightIsZero )
714       {
715         size.height = std::max( size.height, textViewSize.height + TEXT_PADDING * 2.0f );
716       }
717     }
718   }
719
720   return size;
721 }
722
723 void PushButton::DoClickAction(const PropertyValueContainer& attributes)
724 {
725   // Prevents the button signals from doing a recursive loop by sending an action
726   // and re-emitting the signals.
727   if(!mClickActionPerforming)
728   {
729     mClickActionPerforming = true;
730     OnButtonDown();
731     mState = ButtonDown;
732     OnButtonUp();
733     mClickActionPerforming = false;
734   }
735 }
736
737 bool PushButton::DoAction(BaseObject* object, const std::string& actionName, const PropertyValueContainer& attributes)
738 {
739   bool ret = false;
740
741   Dali::BaseHandle handle(object);
742
743   Toolkit::PushButton button = Toolkit::PushButton::DownCast(handle);
744
745   DALI_ASSERT_ALWAYS(button);
746
747   if(Toolkit::PushButton::ACTION_PUSH_BUTTON_CLICK == actionName)
748   {
749     GetImplementation(button).DoClickAction(attributes);
750     ret = true;
751   }
752
753   return ret;
754 }
755
756 } // namespace Internal
757
758 } // namespace Toolkit
759
760 } // namespace Dali