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