[dali_1.9.24] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / buttons / button-impl.cpp
1 /*
2  * Copyright (c) 2020 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 <cstring> // for strcmp
23 #include <dali/devel-api/scripting/enum-helper.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/public-api/events/touch-data.h>
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/public-api/object/type-registry-helper.h>
28 #include <dali/public-api/size-negotiation/relayout-container.h>
29 #include <dali/devel-api/object/property-helper-devel.h>
30 #include <dali/devel-api/scripting/scripting.h>
31
32 // INTERNAL INCLUDES
33 #include <dali-toolkit/public-api/controls/text-controls/text-label.h>
34 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
35 #include <dali-toolkit/public-api/visuals/color-visual-properties.h>
36 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
37 #include <dali-toolkit/public-api/align-enumerations.h>
38 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
39 #include <dali-toolkit/devel-api/controls/control-devel.h>
40 #include <dali-toolkit/devel-api/controls/buttons/button-devel.h>
41 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
42 #include <dali-toolkit/internal/visuals/text/text-visual.h>
43 #include <dali-toolkit/public-api/visuals/text-visual-properties.h>
44 #include <dali-toolkit/public-api/visuals/visual-properties.h>
45
46 #if defined(DEBUG_ENABLED)
47     Debug::Filter* gLogButtonFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_BUTTON_CONTROL");
48 #endif
49
50 namespace Dali
51 {
52
53 namespace Toolkit
54 {
55
56 namespace Internal
57 {
58
59 namespace
60 {
61
62 BaseHandle Create()
63 {
64   // empty handle as we cannot create button (but type registered for clicked signal)
65   return BaseHandle();
66 }
67
68 // Setup properties, signals and actions using the type-registry.
69 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Button, Toolkit::Control, Create )
70
71 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "disabled",                           BOOLEAN, DISABLED                              )
72 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "autoRepeating",                      BOOLEAN, AUTO_REPEATING                        )
73 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "initialAutoRepeatingDelay",          FLOAT,   INITIAL_AUTO_REPEATING_DELAY          )
74 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "nextAutoRepeatingDelay",             FLOAT,   NEXT_AUTO_REPEATING_DELAY             )
75 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "togglable",                          BOOLEAN, TOGGLABLE                             )
76 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "selected",                           BOOLEAN, SELECTED                              )
77 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "unselectedVisual",                   MAP,     UNSELECTED_VISUAL                     )
78 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "selectedVisual",                     MAP,     SELECTED_VISUAL                       )
79 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "disabledSelectedVisual",             MAP,     DISABLED_SELECTED_VISUAL              )
80 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "disabledUnselectedVisual",           MAP,     DISABLED_UNSELECTED_VISUAL            )
81 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "unselectedBackgroundVisual",         MAP,     UNSELECTED_BACKGROUND_VISUAL          )
82 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "label",                              MAP,     LABEL                                 )
83 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "selectedBackgroundVisual",           MAP,     SELECTED_BACKGROUND_VISUAL            )
84 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "disabledUnselectedBackgroundVisual", MAP,     DISABLED_UNSELECTED_BACKGROUND_VISUAL )
85 DALI_PROPERTY_REGISTRATION( Toolkit, Button, "disabledSelectedBackgroundVisual",   MAP,     DISABLED_SELECTED_BACKGROUND_VISUAL   )
86 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "labelRelativeAlignment",             STRING,  LABEL_RELATIVE_ALIGNMENT              )
87 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "labelPadding",                       VECTOR4, LABEL_PADDING                         )
88 DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "visualPadding",                      VECTOR4, VISUAL_PADDING                        )
89
90 // Signals:
91 DALI_SIGNAL_REGISTRATION(   Toolkit, Button, "pressed",                               SIGNAL_PRESSED               )
92 DALI_SIGNAL_REGISTRATION(   Toolkit, Button, "released",                              SIGNAL_RELEASED              )
93 DALI_SIGNAL_REGISTRATION(   Toolkit, Button, "clicked",                               SIGNAL_CLICKED               )
94 DALI_SIGNAL_REGISTRATION(   Toolkit, Button, "stateChanged",                          SIGNAL_STATE_CHANGED         )
95
96 // Actions:
97 DALI_ACTION_REGISTRATION(   Toolkit, Button, "buttonClick",                           ACTION_BUTTON_CLICK          )
98
99 DALI_TYPE_REGISTRATION_END()
100
101 DALI_ENUM_TO_STRING_TABLE_BEGIN( ALIGNMENT )
102 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Internal::Button, BEGIN )
103 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Internal::Button, END )
104 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Internal::Button, TOP )
105 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Internal::Button, BOTTOM )
106 DALI_ENUM_TO_STRING_TABLE_END( ALIGNMENT )
107
108 const Scripting::StringEnum ALIGNMENT_STRING_TABLE[] =
109 {
110   { "BEGIN",  Button::BEGIN   },
111   { "END",    Button::END     },
112   { "TOP",    Button::TOP     },
113   { "BOTTOM", Button::BOTTOM  },
114 };
115
116 const unsigned int ALIGNMENT_STRING_TABLE_COUNT = sizeof( ALIGNMENT_STRING_TABLE ) / sizeof( ALIGNMENT_STRING_TABLE[0] );
117
118 const Property::Index VISUAL_INDEX_FOR_STATE[][Button::STATE_COUNT] =
119 {
120   { Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, Toolkit::Button::Property::UNSELECTED_VISUAL },
121   { Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, Toolkit::Button::Property::SELECTED_VISUAL  },
122   { Toolkit::Button::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL, Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL },
123   { Toolkit::Button::Property::DISABLED_SELECTED_BACKGROUND_VISUAL, Toolkit::Button::Property::DISABLED_SELECTED_VISUAL }
124 };
125
126 /**
127  * Checks if given map contains a text string
128  */
129 bool MapContainsTextString( Property::Map& map )
130 {
131   bool result = false;
132   Property::Value* value = map.Find( Toolkit::TextVisual::Property::TEXT );
133   if ( value )
134   {
135     std::string textString;
136     value->Get( textString );
137     if ( !textString.empty() )
138     {
139       result = true;
140     }
141   }
142   return result;
143 }
144
145 } // unnamed namespace
146
147 Button::Button()
148 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
149   mAutoRepeatingTimer(),
150   mTextLabelAlignment( END ),
151   mAutoRepeating( false ),
152   mTogglableButton( false ),
153   mTextStringSetFlag( false ),
154   mInitialAutoRepeatingDelay( 0.0f ),
155   mNextAutoRepeatingDelay( 0.0f ),
156   mAnimationTime( 0.0f ),
157   mButtonPressedState( UNPRESSED ),
158   mButtonState( UNSELECTED_STATE ),
159   mPreviousButtonState( mButtonState ),
160   mClickActionPerforming( false )
161 {
162 }
163
164 Button::~Button()
165 {
166 }
167
168 void Button::SetAutoRepeating( bool autoRepeating )
169 {
170   mAutoRepeating = autoRepeating;
171
172   // An autorepeating button can't be a toggle button.
173   if( autoRepeating )
174   {
175     if( IsSelected() )
176     {
177       SetSelected( false ); // UnSelect before switching off Toggle feature.
178     }
179     mTogglableButton = false;
180   }
181 }
182
183 void Button::SetInitialAutoRepeatingDelay( float initialAutoRepeatingDelay )
184 {
185   DALI_ASSERT_DEBUG( initialAutoRepeatingDelay > 0.f );
186   mInitialAutoRepeatingDelay = initialAutoRepeatingDelay;
187 }
188
189 void Button::SetNextAutoRepeatingDelay( float nextAutoRepeatingDelay )
190 {
191   DALI_ASSERT_DEBUG( nextAutoRepeatingDelay > 0.f );
192   mNextAutoRepeatingDelay = nextAutoRepeatingDelay;
193 }
194
195 void Button::SetTogglableButton( bool togglable )
196 {
197   mTogglableButton = togglable;
198
199   // A toggle button can't be an autorepeating button.
200   if( togglable )
201   {
202     mAutoRepeating = false;
203   }
204 }
205
206 void Button::SetSelected( bool selected )
207 {
208   if( mTogglableButton )
209   {
210     DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetSelected (%s)\n", (selected?"true":"false") );
211
212     if ( selected && ( mButtonState != SELECTED_STATE ) )
213     {
214       ChangeState( SELECTED_STATE );
215     }
216     else if ( !selected && ( mButtonState != UNSELECTED_STATE ) )
217     {
218       ChangeState( UNSELECTED_STATE );
219     }
220   }
221 }
222
223 void Button::SetDisabled( bool disabled )
224 {
225   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetDisabled(%s) state(%d)\n", (disabled)?"disabled":"active", mButtonState );
226
227   if ( disabled )
228   {
229     if ( mButtonState == SELECTED_STATE )
230     {
231       ChangeState( DISABLED_SELECTED_STATE );
232     }
233     else if ( mButtonState == UNSELECTED_STATE )
234     {
235       ChangeState( DISABLED_UNSELECTED_STATE );
236     }
237   }
238   else
239   {
240     if ( mButtonState == DISABLED_SELECTED_STATE )
241     {
242       ChangeState( SELECTED_STATE );
243     }
244     else if ( mButtonState == DISABLED_UNSELECTED_STATE )
245     {
246       ChangeState( UNSELECTED_STATE );
247     }
248   }
249 }
250
251 bool Button::IsDisabled() const
252 {
253   return ( mButtonState == DISABLED_SELECTED_STATE || mButtonState == DISABLED_UNSELECTED_STATE ) ;
254 }
255
256 bool Button::ValidateState( State requestedState )
257 {
258   /*  Below tables shows allowed state transitions
259    *  Match rows in first column to following columns, if true then transition allowed.
260    *  eg UNSELECTED_STATE to DISABLED_UNSELECTED_STATE is true so state transition allowed.
261    *
262                                                              to| UNSELECTED_STATE | SELECTED_STATE | DISABLED_UNSELECTED_STATE | DISABLED_SELECTED_STATE |*/
263                                  /* from*/
264   bool transitionTable[4][4] = { /* UNSELECTED_STATE*/         {      false,            true,               true,                   false         },
265                                  /* SELECTED_STATE*/           {      true,             false,              false,                  true          },
266                                  /* DISABLED_UNSELECTED_STATE*/{      true,             true,               false,                  false         },
267                                  /* DISABLED_SELECTED_STATE*/  {      false,            true,               false,                  false         }
268                                };
269
270   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::ValidateState ReuestedState:%d, CurrentState:%d, result:%s\n",
271                  requestedState, mButtonState, (transitionTable[mButtonState][requestedState])?"change-accepted":"change-denied");
272
273   return transitionTable[mButtonState][requestedState];
274 }
275
276 void Button::ChangeState( State requestedState )
277 {
278   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::ChangeState ReuestedState(%d)\n", requestedState );
279
280   // Validate State before changing
281   if ( !ValidateState( requestedState ))
282   {
283     DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::ChangeState ReuestedState(%d) not validated\n", requestedState );
284     return;
285   }
286
287   // If not on stage the button could have still been set to selected so update state
288   mPreviousButtonState = mButtonState; // Store previous state for visual removal (used when animations ended)
289   mButtonState = requestedState; // Update current state
290
291   if ( Self().GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) )
292   {
293     OnStateChange( mButtonState ); // Notify derived buttons
294     SelectRequiredVisual( VISUAL_INDEX_FOR_STATE[ mButtonState ][ BACKGROUND ] );
295     SelectRequiredVisual( VISUAL_INDEX_FOR_STATE[ mButtonState ][ FOREGROUND ] );
296     // If animation supported then visual removal should be performed after any transition animation has completed.
297     // If Required Visual is not loaded before current visual is removed then a flickering will be evident.
298     // Derived button can override OnButtonVisualRemoval
299     OnButtonVisualRemoval( VISUAL_INDEX_FOR_STATE[ mPreviousButtonState ][ BACKGROUND ] );
300     OnButtonVisualRemoval( VISUAL_INDEX_FOR_STATE[ mPreviousButtonState ][ FOREGROUND ] );
301     RelayoutRequest();
302   }
303
304   Toolkit::Button handle( GetOwner() );
305   // Emit signal.
306   mStateChangedSignal.Emit( handle );
307 }
308
309 bool Button::IsSelected() const
310 {
311   bool selected = ( mButtonState == SELECTED_STATE ) || ( mButtonState == DISABLED_SELECTED_STATE );
312   return mTogglableButton && selected;
313 }
314
315 void Button::MergeWithExistingLabelProperties( const Property::Map& inMap, Property::Map& outMap )
316 {
317   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "MergeLabelProperties with %d properties\n", inMap.Count() );
318
319   /**
320    * Properties for the Label visual could be from a style sheet but after being set the "TEXT" property could be set.
321    * Hence would need to create the Text Visual with the complete merged set of properties.
322    *
323    * 1) Find Label Visual
324    * 2) Retrieve current properties ( settings )
325    * 3) Merge with new properties ( settings )
326    * 4) Return new merged map
327    */
328   Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, Toolkit::Button::Property::LABEL );
329   if ( visual )
330   {
331     DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "MergeLabelProperties Visual already exists, retrieving existing map\n");
332     visual.CreatePropertyMap( outMap );
333     DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "MergeLabelProperties retrieved %d properties\n", outMap.Count() );
334   }
335
336   outMap.Merge( inMap );
337
338   // Store if a text string has been supplied.
339
340   mTextStringSetFlag = MapContainsTextString( outMap );
341
342   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "MergeLabelProperties now has %d properties\n", outMap.Count() );
343 }
344
345 void Button::SetLabelAlignment( Button::Align labelAlignment)
346 {
347   mTextLabelAlignment = labelAlignment;
348   RelayoutRequest();
349 }
350
351 Button::Align Button::GetLabelAlignment()
352 {
353   return mTextLabelAlignment;
354 }
355
356 /**
357  * Create Visual for given index from a property map or url.
358  * 1) Check if value passed in is a url and create visual
359  * 2) Create visual from map if step (1) is false
360  * 3) Register visual with control with false for enable flag. Button will later enable visual when needed ( Button::SelectRequiredVisual )
361  * 4) Unregister visual if empty map was provided. This is the method to remove a visual
362  */
363 void Button::CreateVisualsForComponent( Property::Index index, const Property::Value& value, const int visualDepth )
364 {
365   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent index(%d)\n", index );
366   Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
367   Toolkit::Visual::Base buttonVisual;
368
369   std::string imageUrl;
370   if( value.Get( imageUrl ) )
371   {
372     DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent Using image URL(%d)\n", index );
373     if ( !imageUrl.empty() )
374     {
375       DALI_ASSERT_DEBUG( index != Toolkit::Button::Property::LABEL && "Creating a Image Visual instead of Text Visual " );
376       buttonVisual = visualFactory.CreateVisual(  imageUrl, ImageDimensions()  );
377     }
378   }
379   else
380   {
381     // if its not a string then get a Property::Map from the property if possible.
382     Property::Map *map = value.GetMap();
383     if( map && !map->Empty()  ) // Empty map results in current visual removal.
384     {
385       DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent Using Map(%d)\n", index );
386       buttonVisual = visualFactory.CreateVisual( *map );
387     }
388   }
389
390   if ( buttonVisual )
391   {
392     DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent RegisterVisual index(%d) enabled(%s)\n",
393                    index, DevelControl::IsVisualEnabled( *this, index )?"true":"false" );
394     // enable the visual if needed for current state
395     const bool enabled = ( ( index == VISUAL_INDEX_FOR_STATE[ mButtonState ][ BACKGROUND ] )||
396                            ( index == VISUAL_INDEX_FOR_STATE[ mButtonState ][ FOREGROUND ] )||
397                            ( index == Toolkit::Button::Property::LABEL ) );
398     DevelControl::RegisterVisual( *this, index, buttonVisual, enabled, visualDepth );
399   }
400   else
401   {
402     DevelControl::UnregisterVisual( *this, index );
403     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "CreateVisualsForComponent Visual not created or empty map (clearing visual).(%d)\n", index);
404   }
405   RelayoutRequest();
406 }
407
408 bool Button::GetPropertyMapForVisual( Property::Index visualIndex, Property::Map& retreivedMap ) const
409 {
410   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetPropertyMapForVisual visual(%d)\n", visualIndex);
411   bool success = false;
412   Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, visualIndex );
413   if ( visual )
414   {
415     visual.CreatePropertyMap( retreivedMap );
416     success = true;
417   }
418   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetPropertyMapForVisual %s\n", success?"Success":"Failure");
419   return success;
420 }
421
422 bool Button::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
423 {
424   bool ret = false;
425
426   Dali::BaseHandle handle( object );
427
428   Toolkit::Button button = Toolkit::Button::DownCast( handle );
429
430   DALI_ASSERT_DEBUG( button );
431
432   if( 0 == strcmp( actionName.c_str(), ACTION_BUTTON_CLICK ) )
433   {
434     ret = GetImplementation( button ).DoClickAction( attributes );
435   }
436
437   return ret;
438 }
439
440 bool Button::DoClickAction( const Property::Map& attributes )
441 {
442   // Prevents the button signals from doing a recursive loop by sending an action
443   // and re-emitting the signals.
444   if( !mClickActionPerforming )
445   {
446     mClickActionPerforming = true;
447     ButtonDown();
448     if ( !mTogglableButton )
449     {
450       mButtonPressedState = DEPRESSED;
451     }
452     ButtonUp();
453     mClickActionPerforming = false;
454
455     return true;
456   }
457
458   return false;
459 }
460
461 void Button::ButtonDown()
462 {
463   if( mTogglableButton )
464   {
465     if ( mButtonState != SELECTED_STATE )
466     {
467       SetSelected( true );
468       mButtonPressedState = TOGGLE_DEPRESSED;
469     }
470     else
471     {
472       mButtonPressedState = DEPRESSED;
473     }
474   }
475   else
476   {
477     Pressed();
478     mButtonPressedState = DEPRESSED;
479     if( mAutoRepeating )
480     {
481        SetUpTimer( mInitialAutoRepeatingDelay );
482     }
483   }
484
485   // The pressed signal should be emitted regardless of toggle mode.
486   Toolkit::Button handle( GetOwner() );
487   mPressedSignal.Emit( handle );
488 }
489
490 void Button::ButtonUp()
491 {
492   bool emitSignalsForPressAndReleaseAction = false;
493
494   if( DEPRESSED == mButtonPressedState )
495   {
496     if( mTogglableButton ) // Button up will change state
497     {
498       emitSignalsForPressAndReleaseAction = OnToggleReleased(); // Derived toggle buttons can override this to provide custom behaviour
499     }
500     else
501     {
502       Released(); // Button up will result in unselected state
503       if( mAutoRepeating )
504       {
505         mAutoRepeatingTimer.Reset();
506       }
507       emitSignalsForPressAndReleaseAction = true;
508     }
509   }
510   else if ( TOGGLE_DEPRESSED == mButtonPressedState )
511   {
512     emitSignalsForPressAndReleaseAction = true; // toggle released after being pressed, a click
513   }
514
515   if ( emitSignalsForPressAndReleaseAction )
516   {
517     // The clicked and released signals should be emitted regardless of toggle mode.
518     Toolkit::Button handle( GetOwner() );
519     mReleasedSignal.Emit( handle );
520     mClickedSignal.Emit( handle );
521   }
522 }
523
524 bool Button::OnToggleReleased()
525 {
526   SetSelected( !IsSelected() );
527   mButtonPressedState = UNPRESSED;
528   return true;
529 }
530
531
532 void Button::OnTouchPointLeave()
533 {
534   if( DEPRESSED == mButtonPressedState )
535   {
536     if( !mTogglableButton )
537     {
538       Released();
539
540       if( mAutoRepeating )
541       {
542         mAutoRepeatingTimer.Reset();
543       }
544     }
545
546     mButtonPressedState = UNPRESSED;
547
548     // The released signal should be emitted regardless of toggle mode.
549     Toolkit::Button handle( GetOwner() );
550     mReleasedSignal.Emit( handle );
551   }
552 }
553
554 void Button::OnTouchPointInterrupted()
555 {
556   OnTouchPointLeave();
557 }
558
559 Toolkit::Button::ButtonSignalType& Button::PressedSignal()
560 {
561   return mPressedSignal;
562 }
563
564 Toolkit::Button::ButtonSignalType& Button::ReleasedSignal()
565 {
566   return mReleasedSignal;
567 }
568
569 Toolkit::Button::ButtonSignalType& Button::ClickedSignal()
570 {
571   return mClickedSignal;
572 }
573
574 Toolkit::Button::ButtonSignalType& Button::StateChangedSignal()
575 {
576   return mStateChangedSignal;
577 }
578
579 bool Button::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
580 {
581   Dali::BaseHandle handle( object );
582
583   bool connected( true );
584   Toolkit::Button button = Toolkit::Button::DownCast( handle );
585
586   if( 0 == strcmp( signalName.c_str(), SIGNAL_PRESSED ) )
587   {
588     button.PressedSignal().Connect( tracker, functor );
589   }
590   else if( 0 == strcmp( signalName.c_str(), SIGNAL_RELEASED ) )
591   {
592     button.ReleasedSignal().Connect( tracker, functor );
593   }
594   else if( 0 == strcmp( signalName.c_str(), SIGNAL_CLICKED ) )
595   {
596     button.ClickedSignal().Connect( tracker, functor );
597   }
598   else if( 0 == strcmp( signalName.c_str(), SIGNAL_STATE_CHANGED ) )
599   {
600     button.StateChangedSignal().Connect( tracker, functor );
601   }
602   else
603   {
604     // signalName does not match any signal
605     connected = false;
606   }
607
608   return connected;
609 }
610
611 void Button::OnInitialize()
612 {
613   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::OnInitialize\n" );
614
615   Actor self = Self();
616
617   mTapDetector = TapGestureDetector::New();
618   mTapDetector.Attach( self );
619   mTapDetector.DetectedSignal().Connect(this, &Button::OnTap);
620
621   self.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE, true );
622
623   self.TouchSignal().Connect( this, &Button::OnTouch );
624 }
625
626 bool Button::OnAccessibilityActivated()
627 {
628   return OnKeyboardEnter();
629 }
630
631 bool Button::OnTouch( Actor actor, const TouchData& touch )
632 {
633   if( !IsDisabled() && (actor == touch.GetHitActor(0)) )
634   {
635     if ( 1 == touch.GetPointCount() )
636     {
637       switch( touch.GetState( 0 ) )
638       {
639         case PointState::DOWN:
640         {
641           ButtonDown();
642           break;
643         }
644         case PointState::UP:
645         {
646           ButtonUp();
647           break;
648         }
649         case PointState::INTERRUPTED:
650         {
651           OnTouchPointInterrupted();
652           break;
653         }
654         case PointState::LEAVE:
655         {
656           OnTouchPointLeave();
657           break;
658         }
659         case PointState::MOTION:
660         case PointState::STATIONARY: // FALLTHROUGH
661         {
662           // Nothing to do
663           break;
664         }
665       }
666     }
667     else if( 1 < touch.GetPointCount() )
668     {
669       OnTouchPointLeave(); // Notification for derived classes.
670
671       // Sets the button state to the default
672       mButtonPressedState = UNPRESSED;
673     }
674   }
675   return false;
676 }
677
678 bool Button::OnKeyboardEnter()
679 {
680   // When the enter key is pressed, or button is activated, the click action is performed.
681   Property::Map attributes;
682   bool ret = DoClickAction( attributes );
683
684   return ret;
685 }
686
687 void Button::OnSceneDisconnection()
688 {
689   if( DEPRESSED == mButtonPressedState )
690   {
691     if( !mTogglableButton )
692     {
693       Released();
694
695       if( mAutoRepeating )
696       {
697         mAutoRepeatingTimer.Reset();
698       }
699     }
700   }
701
702   mButtonPressedState = UNPRESSED;
703
704   Control::OnSceneDisconnection(); // Visuals will be set off stage
705 }
706
707 void Button::OnSceneConnection( int depth )
708 {
709   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::OnSceneConnection ptr(%p) \n", this );
710   OnButtonVisualRemoval( VISUAL_INDEX_FOR_STATE[ mPreviousButtonState ][ BACKGROUND ] );
711   OnButtonVisualRemoval( VISUAL_INDEX_FOR_STATE[ mPreviousButtonState ][ FOREGROUND ] );
712   SelectRequiredVisual( Toolkit::Button::Property::LABEL );
713   SelectRequiredVisual( VISUAL_INDEX_FOR_STATE[ mButtonState ][ BACKGROUND ] );
714   SelectRequiredVisual( VISUAL_INDEX_FOR_STATE[ mButtonState ][ FOREGROUND ] );
715   Control::OnSceneConnection( depth ); // Enabled visuals will be put on stage
716   RelayoutRequest();
717 }
718
719 Vector3 Button::GetNaturalSize()
720 {
721   Vector3 size = Vector3::ZERO;
722
723   bool horizontalAlignment = mTextLabelAlignment == BEGIN || mTextLabelAlignment == END; // label and visual side by side
724
725   // Get natural size of foreground ( largest of the possible visuals )
726   Size largestProvidedVisual;
727   Size labelSize = Size::ZERO;
728
729   bool foreGroundVisualUsed = false;
730
731   for ( int state = Button::UNSELECTED_STATE; state < Button::STATE_COUNT; state++ )
732   {
733     Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, VISUAL_INDEX_FOR_STATE[state][FOREGROUND] );
734     Size visualSize;
735     if ( visual )
736     {
737       visual.GetNaturalSize( visualSize );
738       largestProvidedVisual.width = std::max(largestProvidedVisual.width, visualSize.width );
739       largestProvidedVisual.height = std::max(largestProvidedVisual.height, visualSize.height );
740       foreGroundVisualUsed = true;
741     }
742   }
743
744   if ( !foreGroundVisualUsed ) // If foreground visual not supplied then use the background visual to calculate Natural size
745   {
746     for ( int state = Button::UNSELECTED_STATE; state < Button::STATE_COUNT; state++ )
747     {
748       Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, VISUAL_INDEX_FOR_STATE[state][BACKGROUND] );
749       Size visualSize;
750       if ( visual )
751       {
752         visual.GetNaturalSize( visualSize );
753         largestProvidedVisual.width = std::max(largestProvidedVisual.width, visualSize.width );
754         largestProvidedVisual.height = std::max(largestProvidedVisual.height, visualSize.height );
755       }
756     }
757   }
758
759   // Get horizontal padding total
760   if ( largestProvidedVisual.width > 0 )  // if visual exists
761   {
762     size.width += largestProvidedVisual.width + mForegroundPadding.left + mForegroundPadding.right;
763   }
764   // Get vertical padding total
765   if ( largestProvidedVisual.height > 0 )
766   {
767     size.height += largestProvidedVisual.height + mForegroundPadding.top + mForegroundPadding.bottom;
768   }
769
770   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetNaturalSize visual Size(%f,%f)\n",
771                  largestProvidedVisual.width, largestProvidedVisual.height );
772
773   // Get natural size of label if text has been set
774   if ( mTextStringSetFlag )
775   {
776     Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, Toolkit::Button::Property::LABEL );
777
778     if ( visual )
779     {
780       visual.GetNaturalSize( labelSize );
781
782       DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetNaturalSize labelSize(%f,%f) padding(%f,%f)\n",
783                      labelSize.width, labelSize.height, mLabelPadding.left + mLabelPadding.right, mLabelPadding.top + mLabelPadding.bottom);
784
785       labelSize.width += mLabelPadding.left + mLabelPadding.right;
786       labelSize.height += mLabelPadding.top + mLabelPadding.bottom;
787
788       // Add label size to height or width depending on alignment position
789       if ( horizontalAlignment )
790       {
791         size.width += labelSize.width;
792         size.height = std::max(size.height, labelSize.height );
793       }
794       else
795       {
796         size.height += labelSize.height;
797         size.width = std::max(size.width, labelSize.width );
798       }
799     }
800   }
801
802   if( size.width < 1 && size.height < 1 )
803   {
804     // if no image or label then use Control's natural size
805     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetNaturalSize Using control natural size\n");
806     size = Control::GetNaturalSize();
807   }
808
809   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "Button GetNaturalSize (%f,%f)\n", size.width, size.height );
810
811   return size;
812 }
813
814 void Button::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
815 {
816   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnSetResizePolicy\n");
817   RelayoutRequest();
818 }
819
820 /**
821  * Visuals are sized and positioned in this function.
822  * Whilst the control has it's size negotiated it has to size it's visuals explicitly here.
823  */
824
825 void Button::OnRelayout( const Vector2& size, RelayoutContainer& container )
826 {
827   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout targetSize(%f,%f) ptr(%p) state[%d]\n", size.width, size.height, this, mButtonState );
828
829   Toolkit::Visual::Base currentVisual = DevelControl::GetVisual( *this, VISUAL_INDEX_FOR_STATE[mButtonState][FOREGROUND] );
830   Toolkit::Visual::Base currentBackGroundVisual = DevelControl::GetVisual( *this, VISUAL_INDEX_FOR_STATE[mButtonState][BACKGROUND] );
831
832   // Sizes and padding set to zero, if not present then values will no effect calculations.
833   Vector2 visualPosition = Vector2::ZERO;
834   Vector2 labelPosition = Vector2::ZERO;
835   Size visualSize = Size::ZERO;
836   Padding foregroundVisualPadding = Padding(0.0f, 0.0f, 0.0f, 0.0f );
837   Padding labelVisualPadding = Padding(0.0f, 0.0f, 0.0f, 0.0f );
838
839   if ( mTextStringSetFlag )
840   {
841     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Label padding setting padding:%f,%f,%f,%f\n", mLabelPadding.y, mLabelPadding.x, mLabelPadding.width,mLabelPadding.height );
842     labelVisualPadding = mLabelPadding;
843   }
844
845   if ( currentVisual )
846   {
847     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Foreground Visual setting padding:%f,%f,%f,%f\n", mForegroundPadding.y, mForegroundPadding.x, mForegroundPadding.width,mForegroundPadding.height );
848     currentVisual.GetNaturalSize( visualSize );
849     foregroundVisualPadding = mForegroundPadding;
850   }
851
852   Toolkit::Align::Type visualAnchorPoint = Toolkit::Align::TOP_BEGIN;
853
854   Vector2 visualAndPaddingSize = Vector2( ( foregroundVisualPadding.x + visualSize.width + foregroundVisualPadding.y ),
855                                           ( foregroundVisualPadding.width + visualSize.height + foregroundVisualPadding.height ));
856
857   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout visualAndPaddingSize(%f,%f)\n", visualAndPaddingSize.width, visualAndPaddingSize.height);
858
859   // Text Visual should take all space available after foreground visual size and all padding is considered.
860   // Remaining Space priority, Foreground padding, foreground visual, Text padding then Text visual.
861   Size remainingSpaceForText = Size::ZERO;
862
863   switch ( mTextLabelAlignment )
864   {
865     case BEGIN :
866     {
867       visualAnchorPoint = Toolkit::Align::TOP_END;
868       visualPosition.x = foregroundVisualPadding.right;
869       visualPosition.y = foregroundVisualPadding.top;
870
871       labelPosition.x = labelVisualPadding.x;
872       labelPosition.y = labelVisualPadding.top;
873
874       remainingSpaceForText.width = size.width - visualAndPaddingSize.width - labelVisualPadding.x - labelVisualPadding.y;
875       remainingSpaceForText.height = size.height - labelVisualPadding.top - labelVisualPadding.bottom;
876       break;
877     }
878     case END :
879     {
880       visualAnchorPoint = Toolkit::Align::TOP_BEGIN;
881       visualPosition.x = foregroundVisualPadding.left;
882       visualPosition.y = foregroundVisualPadding.top;
883
884       labelPosition.x = visualAndPaddingSize.width + labelVisualPadding.x;
885       labelPosition.y = labelVisualPadding.top;
886
887       remainingSpaceForText.width = size.width - visualAndPaddingSize.width - labelVisualPadding.x - labelVisualPadding.y;
888       remainingSpaceForText.height = size.height - labelVisualPadding.top - labelVisualPadding.bottom;
889       break;
890     }
891     case TOP :
892     {
893       visualAnchorPoint = Toolkit::Align::BOTTOM_END;
894       visualPosition.x = foregroundVisualPadding.left;
895       visualPosition.y = foregroundVisualPadding.bottom;
896
897       labelPosition.x = labelVisualPadding.left;
898       labelPosition.y = labelVisualPadding.top;
899
900       remainingSpaceForText.width = size.width - labelVisualPadding.x - labelVisualPadding.y;
901       remainingSpaceForText.height = size.height - visualAndPaddingSize.height - labelVisualPadding.top - labelVisualPadding.bottom;
902
903       break;
904     }
905     case BOTTOM :
906     {
907       visualAnchorPoint = Toolkit::Align::TOP_END;
908       visualPosition.x = foregroundVisualPadding.left;
909       visualPosition.y = foregroundVisualPadding.top;
910
911       labelPosition.x = labelVisualPadding.left;
912       labelPosition.y = visualAndPaddingSize.height + labelVisualPadding.top;
913
914       remainingSpaceForText.width = size.width - labelVisualPadding.x - labelVisualPadding.y;
915       remainingSpaceForText.height = size.height - visualAndPaddingSize.height - labelVisualPadding.top - labelVisualPadding.bottom;
916
917       break;
918     }
919   }
920
921   if ( currentBackGroundVisual )
922   {
923     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Setting visual background size to(%f,%f)\n", size.width, size.height);
924
925     Property::Map visualTransform;
926
927     visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, size )
928                    .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) );
929
930     currentBackGroundVisual.SetTransformAndSize( visualTransform, size );
931   }
932
933   if ( currentVisual )
934   {
935     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Setting visual size to(%f,%f)\n", visualSize.width, visualSize.height);
936
937     Property::Map visualTransform;
938
939     visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, visualSize )
940                    .Add( Toolkit::Visual::Transform::Property::OFFSET, visualPosition )
941                    .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
942                    .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
943                    .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
944                    .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, visualAnchorPoint );
945
946     currentVisual.SetTransformAndSize( visualTransform, size );
947   }
948
949   if ( mTextStringSetFlag )
950   {
951     Toolkit::Visual::Base textVisual = DevelControl::GetVisual( *this, Toolkit::Button::Property::LABEL ); // No need to search for Label visual if no text set.
952
953     if ( textVisual )
954     {
955       if ( !currentVisual )
956       {
957         DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Only Text\n");
958         labelPosition.x = labelVisualPadding.left;
959         labelPosition.y = labelVisualPadding.height;
960       }
961
962       Vector2 preSize = Vector2( static_cast< int >( remainingSpaceForText.x ), static_cast< int >( remainingSpaceForText.y ));
963
964       DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout text Size(%f,%f) text Position(%f,%f) \n", remainingSpaceForText.width, remainingSpaceForText.height, labelPosition.x, labelPosition.y);
965
966       DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout text Size -- (%f,%f) text Position(%f,%f) \n", preSize.width, preSize.height, labelPosition.x, labelPosition.y);
967
968
969       Property::Map textVisualTransform;
970       textVisualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, preSize )
971                          .Add( Toolkit::Visual::Transform::Property::OFFSET, labelPosition )
972                          .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
973                          .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
974                          .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
975                          .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, visualAnchorPoint );
976
977       textVisual.SetTransformAndSize( textVisualTransform, size );
978     }
979   }
980
981   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout selected (%s) \n", IsSelected()?"yes":"no" );
982
983   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout << \n");
984 }
985
986 void Button::OnTap(Actor actor, const TapGesture& tap)
987 {
988   // Prevents Parent getting a tap event
989 }
990
991 void Button::SetUpTimer( float delay )
992 {
993   mAutoRepeatingTimer = Dali::Timer::New( static_cast<unsigned int>( 1000.f * delay ) );
994   mAutoRepeatingTimer.TickSignal().Connect( this, &Button::AutoRepeatingSlot );
995   mAutoRepeatingTimer.Start();
996 }
997
998 bool Button::AutoRepeatingSlot()
999 {
1000   bool consumed = false;
1001   if( !IsDisabled() )
1002   {
1003     // Restart the autorepeat timer.
1004     SetUpTimer( mNextAutoRepeatingDelay );
1005
1006     Pressed();
1007
1008     Toolkit::Button handle( GetOwner() );
1009
1010     //Emit signal.
1011     consumed = mReleasedSignal.Emit( handle );
1012     consumed = mClickedSignal.Emit( handle );
1013     consumed |= mPressedSignal.Emit( handle );
1014  }
1015
1016   return consumed;
1017 }
1018
1019 void Button::Pressed()
1020 {
1021   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::Pressed\n" );
1022
1023   if( mButtonState == UNSELECTED_STATE )
1024   {
1025     ChangeState( SELECTED_STATE );
1026     OnPressed();  // Notifies the derived class the button has been pressed.
1027   }
1028 }
1029
1030 void Button::Released()
1031 {
1032   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::Released\n" );
1033
1034   if( mButtonState == SELECTED_STATE && !mTogglableButton )
1035   {
1036     ChangeState( UNSELECTED_STATE );
1037     OnReleased(); //    // Notifies the derived class the button has been released.
1038   }
1039   mButtonPressedState = UNPRESSED;
1040 }
1041
1042 void Button::SelectRequiredVisual( Property::Index visualIndex )
1043 {
1044   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SelectRequiredVisual index(%d) state(%d)\n", visualIndex, mButtonState );
1045   // only enable visuals that exist
1046   if( DevelControl::GetVisual( *this, visualIndex ) )
1047   {
1048     DevelControl::EnableVisual( *this, visualIndex, true );
1049   }
1050 }
1051
1052 void Button::RemoveVisual( Property::Index visualIndex )
1053 {
1054   // Use OnButtonVisualRemoval if want button developer to have the option to override removal.
1055   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::RemoveVisual index(%d) state(%d)\n", visualIndex, mButtonState );
1056
1057   Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, visualIndex );
1058
1059   if( visual )
1060   {
1061     DevelControl::EnableVisual( *this, visualIndex, false );
1062   }
1063 }
1064
1065 void Button::OnButtonVisualRemoval( Property::Index visualIndex )
1066 {
1067   // Derived Buttons can over ride this to prevent default removal.
1068   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::OnButtonVisualRemoval index(%d)\n", visualIndex );
1069   RemoveVisual( visualIndex );
1070 }
1071
1072 void Button::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
1073 {
1074   Toolkit::Button button = Toolkit::Button::DownCast( Dali::BaseHandle( object ) );
1075
1076   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetProperty index[%d]\n", index );
1077
1078   if ( button )
1079   {
1080     switch ( index )
1081     {
1082       case Toolkit::Button::Property::DISABLED:
1083       {
1084         GetImplementation( button ).SetDisabled( value.Get< bool >() );
1085         break;
1086       }
1087
1088       case Toolkit::Button::Property::AUTO_REPEATING:
1089       {
1090         GetImplementation( button ).SetAutoRepeating( value.Get< bool >() );
1091         break;
1092       }
1093
1094       case Toolkit::Button::Property::INITIAL_AUTO_REPEATING_DELAY:
1095       {
1096         GetImplementation( button ).SetInitialAutoRepeatingDelay( value.Get< float >() );
1097         break;
1098       }
1099
1100       case Toolkit::Button::Property::NEXT_AUTO_REPEATING_DELAY:
1101       {
1102         GetImplementation( button ).SetNextAutoRepeatingDelay( value.Get< float >() );
1103         break;
1104       }
1105
1106       case Toolkit::Button::Property::TOGGLABLE:
1107       {
1108         GetImplementation( button ).SetTogglableButton( value.Get< bool >() );
1109         break;
1110       }
1111
1112       case Toolkit::Button::Property::SELECTED:
1113       {
1114         GetImplementation( button ).SetSelected( value.Get< bool >() );
1115         break;
1116       }
1117
1118       case Toolkit::Button::Property::UNSELECTED_VISUAL:
1119       case Toolkit::Button::Property::SELECTED_VISUAL:
1120       case Toolkit::Button::Property::DISABLED_SELECTED_VISUAL:
1121       case Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL:
1122       {
1123         GetImplementation( button ).CreateVisualsForComponent( index, value, DepthIndex::CONTENT );
1124         break;
1125       }
1126
1127       case Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL:
1128       case Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL:
1129       case Toolkit::Button::Property::DISABLED_SELECTED_BACKGROUND_VISUAL:
1130       case Toolkit::Button::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL:
1131       {
1132         GetImplementation( button ).CreateVisualsForComponent( index , value, DepthIndex::BACKGROUND);
1133         break;
1134       }
1135
1136       case Toolkit::Button::Property::LABEL:
1137       {
1138         Property::Map outTextVisualProperties;
1139         std::string textString;
1140
1141         if ( value.Get( textString ) )
1142         {
1143           DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetProperty Setting TextVisual with string[%s]\n", textString.c_str() );
1144
1145           Property::Map setPropertyMap;
1146           setPropertyMap.Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT )
1147                         .Add( Toolkit::TextVisual::Property::TEXT, textString );
1148
1149           GetImplementation( button ).MergeWithExistingLabelProperties( setPropertyMap, outTextVisualProperties );
1150         }
1151         else
1152         {
1153           // Get a Property::Map from the property if possible.
1154           Property::Map* setPropertyMap = value.GetMap();
1155           if( setPropertyMap )
1156           {
1157             TextVisual::ConvertStringKeysToIndexKeys( *setPropertyMap );
1158             GetImplementation( button ).MergeWithExistingLabelProperties( *setPropertyMap, outTextVisualProperties );
1159           }
1160         }
1161
1162         if( !outTextVisualProperties.Empty() )
1163         {
1164           GetImplementation( button ).CreateVisualsForComponent( index, outTextVisualProperties, DepthIndex::CONTENT );
1165         }
1166         break;
1167       }
1168
1169       case Toolkit::DevelButton::Property::LABEL_RELATIVE_ALIGNMENT:
1170       {
1171         Button::Align labelAlignment(END);
1172         Scripting::GetEnumeration< Button::Align> ( value.Get< std::string >().c_str(),
1173                                                     ALIGNMENT_TABLE, ALIGNMENT_TABLE_COUNT,
1174                                                     labelAlignment );
1175
1176         GetImplementation( button ).SetLabelAlignment( labelAlignment );
1177         break;
1178       }
1179
1180       case Toolkit::DevelButton::Property::LABEL_PADDING:
1181       {
1182         Vector4 padding ( value.Get< Vector4 >() );
1183         GetImplementation( button ).SetLabelPadding( Padding( padding.x, padding.y, padding.z, padding.w ) );
1184         break;
1185       }
1186
1187       case Toolkit::DevelButton::Property::VISUAL_PADDING:
1188       {
1189         Vector4 padding ( value.Get< Vector4 >() );
1190         GetImplementation( button ).SetForegroundPadding( Padding( padding.x, padding.y, padding.z, padding.w ) );
1191         break;
1192       }
1193     }
1194   }
1195 }
1196
1197 Property::Value Button::GetProperty( BaseObject* object, Property::Index propertyIndex )
1198 {
1199   Property::Value value;
1200
1201   Toolkit::Button button = Toolkit::Button::DownCast( Dali::BaseHandle( object ) );
1202
1203   if ( button )
1204   {
1205     switch ( propertyIndex )
1206     {
1207       case Toolkit::Button::Property::DISABLED:
1208       {
1209         value = GetImplementation( button ).IsDisabled();
1210         break;
1211       }
1212
1213       case Toolkit::Button::Property::AUTO_REPEATING:
1214       {
1215         value = GetImplementation( button ).mAutoRepeating;
1216         break;
1217       }
1218
1219       case Toolkit::Button::Property::INITIAL_AUTO_REPEATING_DELAY:
1220       {
1221         value = GetImplementation( button ).mInitialAutoRepeatingDelay;
1222         break;
1223       }
1224
1225       case Toolkit::Button::Property::NEXT_AUTO_REPEATING_DELAY:
1226       {
1227         value = GetImplementation( button ).mNextAutoRepeatingDelay;
1228         break;
1229       }
1230
1231       case Toolkit::Button::Property::TOGGLABLE:
1232       {
1233         value = GetImplementation( button ).mTogglableButton;
1234         break;
1235       }
1236
1237       case Toolkit::Button::Property::SELECTED:
1238       {
1239         value = GetImplementation( button ).IsSelected();
1240         break;
1241       }
1242
1243       case Toolkit::Button::Property::UNSELECTED_VISUAL:
1244       case Toolkit::Button::Property::SELECTED_VISUAL:
1245       case Toolkit::Button::Property::DISABLED_SELECTED_VISUAL:
1246       case Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL:
1247       case Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL:
1248       case Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL:
1249       case Toolkit::Button::Property::DISABLED_SELECTED_BACKGROUND_VISUAL:
1250       case Toolkit::Button::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL:
1251       case Toolkit::Button::Property::LABEL:
1252       {
1253         Property::Map visualProperty;
1254         if ( GetImplementation( button ).GetPropertyMapForVisual( propertyIndex, visualProperty ) )
1255         {
1256           value = visualProperty;
1257         }
1258         break;
1259       }
1260
1261       case Toolkit::DevelButton::Property::LABEL_RELATIVE_ALIGNMENT:
1262       {
1263         const char* alignment = Scripting::GetEnumerationName< Button::Align >( GetImplementation( button ).GetLabelAlignment(),
1264                                                                                 ALIGNMENT_STRING_TABLE,
1265                                                                                 ALIGNMENT_STRING_TABLE_COUNT );
1266         if( alignment )
1267         {
1268           value = std::string( alignment );
1269         }
1270
1271         break;
1272       }
1273
1274       case Toolkit::DevelButton::Property::LABEL_PADDING:
1275       {
1276         Padding padding = GetImplementation( button ).GetLabelPadding();
1277         value = Vector4( padding.x, padding.y, padding.top, padding.bottom);
1278         break;
1279       }
1280
1281       case Toolkit::DevelButton::Property::VISUAL_PADDING:
1282       {
1283         Padding padding = GetImplementation( button ).GetForegroundPadding();
1284         value = Vector4( padding.x, padding.y, padding.top, padding.bottom);
1285       }
1286     }
1287   }
1288
1289   return value;
1290 }
1291
1292 void Button::SetLabelPadding( const Padding& padding)
1293 {
1294   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetLabelPadding padding(%f,%f,%f,%f)\n", padding.left, padding.right, padding.bottom, padding.top );
1295   mLabelPadding = Padding( padding.left, padding.right, padding.bottom, padding.top );
1296   RelayoutRequest();
1297 }
1298
1299 Padding Button::GetLabelPadding()
1300 {
1301   return mLabelPadding;
1302 }
1303
1304 void Button::SetForegroundPadding( const Padding& padding)
1305 {
1306   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetForegroundPadding padding(%f,%f,%f,%f)\n", padding.left, padding.right, padding.bottom, padding.top );
1307   mForegroundPadding = Padding( padding.left, padding.right, padding.bottom, padding.top );
1308   RelayoutRequest();
1309 }
1310
1311 Padding Button::GetForegroundPadding()
1312 {
1313   return mForegroundPadding;
1314 }
1315
1316 } // namespace Internal
1317
1318 } // namespace Toolkit
1319
1320 } // namespace Dali