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