Remove ResourceImage Usage
[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
634   // Only events are processed when the button is not disabled
635   auto result( false );
636
637   if( !IsDisabled() )
638   {
639     if ( 1 == touch.GetPointCount() )
640     {
641       switch( touch.GetState( 0 ) )
642       {
643         case PointState::DOWN:
644         {
645           ButtonDown();
646           break;
647         }
648         case PointState::UP:
649         {
650           ButtonUp();
651           break;
652         }
653         case PointState::INTERRUPTED:
654         {
655           OnTouchPointInterrupted();
656           break;
657         }
658         case PointState::LEAVE:
659         {
660           OnTouchPointLeave();
661           break;
662         }
663         case PointState::MOTION:
664         case PointState::STATIONARY: // FALLTHROUGH
665         {
666           // Nothing to do
667           break;
668         }
669       }
670     }
671     else if( 1 < touch.GetPointCount() )
672     {
673       OnTouchPointLeave(); // Notification for derived classes.
674
675       // Sets the button state to the default
676       mButtonPressedState = UNPRESSED;
677     }
678     result = true;
679   }
680   return result;
681 }
682
683 bool Button::OnKeyboardEnter()
684 {
685   // When the enter key is pressed, or button is activated, the click action is performed.
686   Property::Map attributes;
687   bool ret = DoClickAction( attributes );
688
689   return ret;
690 }
691
692 void Button::OnStageDisconnection()
693 {
694   if( DEPRESSED == mButtonPressedState )
695   {
696     if( !mTogglableButton )
697     {
698       Released();
699
700       if( mAutoRepeating )
701       {
702         mAutoRepeatingTimer.Reset();
703       }
704     }
705   }
706
707   mButtonPressedState = UNPRESSED;
708
709   Control::OnStageDisconnection(); // Visuals will be set off stage
710 }
711
712 void Button::OnStageConnection( int depth )
713 {
714   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::OnStageConnection ptr(%p) \n", this );
715   OnButtonVisualRemoval( VISUAL_INDEX_FOR_STATE[ mPreviousButtonState ][ BACKGROUND ] );
716   OnButtonVisualRemoval( VISUAL_INDEX_FOR_STATE[ mPreviousButtonState ][ FOREGROUND ] );
717   SelectRequiredVisual( Toolkit::Button::Property::LABEL );
718   SelectRequiredVisual( VISUAL_INDEX_FOR_STATE[ mButtonState ][ BACKGROUND ] );
719   SelectRequiredVisual( VISUAL_INDEX_FOR_STATE[ mButtonState ][ FOREGROUND ] );
720   Control::OnStageConnection( depth ); // Enabled visuals will be put on stage
721   RelayoutRequest();
722 }
723
724 Vector3 Button::GetNaturalSize()
725 {
726   Vector3 size = Vector3::ZERO;
727
728   bool horizontalAlignment = mTextLabelAlignment == BEGIN || mTextLabelAlignment == END; // label and visual side by side
729
730   // Get natural size of foreground ( largest of the possible visuals )
731   Size largestProvidedVisual;
732   Size labelSize = Size::ZERO;
733
734   bool foreGroundVisualUsed = false;
735
736   for ( int state = Button::UNSELECTED_STATE; state < Button::STATE_COUNT; state++ )
737   {
738     Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, VISUAL_INDEX_FOR_STATE[state][FOREGROUND] );
739     Size visualSize;
740     if ( visual )
741     {
742       visual.GetNaturalSize( visualSize );
743       largestProvidedVisual.width = std::max(largestProvidedVisual.width, visualSize.width );
744       largestProvidedVisual.height = std::max(largestProvidedVisual.height, visualSize.height );
745       foreGroundVisualUsed = true;
746     }
747   }
748
749   if ( !foreGroundVisualUsed ) // If foreground visual not supplied then use the background visual to calculate Natural size
750   {
751     for ( int state = Button::UNSELECTED_STATE; state < Button::STATE_COUNT; state++ )
752     {
753       Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, VISUAL_INDEX_FOR_STATE[state][BACKGROUND] );
754       Size visualSize;
755       if ( visual )
756       {
757         visual.GetNaturalSize( visualSize );
758         largestProvidedVisual.width = std::max(largestProvidedVisual.width, visualSize.width );
759         largestProvidedVisual.height = std::max(largestProvidedVisual.height, visualSize.height );
760       }
761     }
762   }
763
764   // Get horizontal padding total
765   if ( largestProvidedVisual.width > 0 )  // if visual exists
766   {
767     size.width += largestProvidedVisual.width + mForegroundPadding.left + mForegroundPadding.right;
768   }
769   // Get vertical padding total
770   if ( largestProvidedVisual.height > 0 )
771   {
772     size.height += largestProvidedVisual.height + mForegroundPadding.top + mForegroundPadding.bottom;
773   }
774
775   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetNaturalSize visual Size(%f,%f)\n",
776                  largestProvidedVisual.width, largestProvidedVisual.height );
777
778   // Get natural size of label if text has been set
779   if ( mTextStringSetFlag )
780   {
781     Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, Toolkit::Button::Property::LABEL );
782
783     if ( visual )
784     {
785       visual.GetNaturalSize( labelSize );
786
787       DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetNaturalSize labelSize(%f,%f) padding(%f,%f)\n",
788                      labelSize.width, labelSize.height, mLabelPadding.left + mLabelPadding.right, mLabelPadding.top + mLabelPadding.bottom);
789
790       labelSize.width += mLabelPadding.left + mLabelPadding.right;
791       labelSize.height += mLabelPadding.top + mLabelPadding.bottom;
792
793       // Add label size to height or width depending on alignment position
794       if ( horizontalAlignment )
795       {
796         size.width += labelSize.width;
797         size.height = std::max(size.height, labelSize.height );
798       }
799       else
800       {
801         size.height += labelSize.height;
802         size.width = std::max(size.width, labelSize.width );
803       }
804     }
805   }
806
807   if( size.width < 1 && size.height < 1 )
808   {
809     // if no image or label then use Control's natural size
810     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetNaturalSize Using control natural size\n");
811     size = Control::GetNaturalSize();
812   }
813
814   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "Button GetNaturalSize (%f,%f)\n", size.width, size.height );
815
816   return size;
817 }
818
819 void Button::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
820 {
821   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnSetResizePolicy\n");
822   RelayoutRequest();
823 }
824
825 /**
826  * Visuals are sized and positioned in this function.
827  * Whilst the control has it's size negotiated it has to size it's visuals explicitly here.
828  */
829
830 void Button::OnRelayout( const Vector2& size, RelayoutContainer& container )
831 {
832   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout targetSize(%f,%f) ptr(%p) state[%d]\n", size.width, size.height, this, mButtonState );
833
834   Toolkit::Visual::Base currentVisual = DevelControl::GetVisual( *this, VISUAL_INDEX_FOR_STATE[mButtonState][FOREGROUND] );
835   Toolkit::Visual::Base currentBackGroundVisual = DevelControl::GetVisual( *this, VISUAL_INDEX_FOR_STATE[mButtonState][BACKGROUND] );
836
837   // Sizes and padding set to zero, if not present then values will no effect calculations.
838   Vector2 visualPosition = Vector2::ZERO;
839   Vector2 labelPosition = Vector2::ZERO;
840   Size visualSize = Size::ZERO;
841   Padding foregroundVisualPadding = Padding(0.0f, 0.0f, 0.0f, 0.0f );
842   Padding labelVisualPadding = Padding(0.0f, 0.0f, 0.0f, 0.0f );
843
844   if ( mTextStringSetFlag )
845   {
846     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Label padding setting padding:%f,%f,%f,%f\n", mLabelPadding.y, mLabelPadding.x, mLabelPadding.width,mLabelPadding.height );
847     labelVisualPadding = mLabelPadding;
848   }
849
850   if ( currentVisual )
851   {
852     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Foreground Visual setting padding:%f,%f,%f,%f\n", mForegroundPadding.y, mForegroundPadding.x, mForegroundPadding.width,mForegroundPadding.height );
853     currentVisual.GetNaturalSize( visualSize );
854     foregroundVisualPadding = mForegroundPadding;
855   }
856
857   Toolkit::Align::Type visualAnchorPoint = Toolkit::Align::TOP_BEGIN;
858
859   Vector2 visualAndPaddingSize = Vector2( ( foregroundVisualPadding.x + visualSize.width + foregroundVisualPadding.y ),
860                                           ( foregroundVisualPadding.width + visualSize.height + foregroundVisualPadding.height ));
861
862   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout visualAndPaddingSize(%f,%f)\n", visualAndPaddingSize.width, visualAndPaddingSize.height);
863
864   // Text Visual should take all space available after foreground visual size and all padding is considered.
865   // Remaining Space priority, Foreground padding, foreground visual, Text padding then Text visual.
866   Size remainingSpaceForText = Size::ZERO;
867
868   switch ( mTextLabelAlignment )
869   {
870     case BEGIN :
871     {
872       visualAnchorPoint = Toolkit::Align::TOP_END;
873       visualPosition.x = foregroundVisualPadding.right;
874       visualPosition.y = foregroundVisualPadding.top;
875
876       labelPosition.x = labelVisualPadding.x;
877       labelPosition.y = labelVisualPadding.top;
878
879       remainingSpaceForText.width = size.width - visualAndPaddingSize.width - labelVisualPadding.x - labelVisualPadding.y;
880       remainingSpaceForText.height = size.height - labelVisualPadding.top - labelVisualPadding.bottom;
881       break;
882     }
883     case END :
884     {
885       visualAnchorPoint = Toolkit::Align::TOP_BEGIN;
886       visualPosition.x = foregroundVisualPadding.left;
887       visualPosition.y = foregroundVisualPadding.top;
888
889       labelPosition.x = visualAndPaddingSize.width + labelVisualPadding.x;
890       labelPosition.y = labelVisualPadding.top;
891
892       remainingSpaceForText.width = size.width - visualAndPaddingSize.width - labelVisualPadding.x - labelVisualPadding.y;
893       remainingSpaceForText.height = size.height - labelVisualPadding.top - labelVisualPadding.bottom;
894       break;
895     }
896     case TOP :
897     {
898       visualAnchorPoint = Toolkit::Align::BOTTOM_END;
899       visualPosition.x = foregroundVisualPadding.left;
900       visualPosition.y = foregroundVisualPadding.bottom;
901
902       labelPosition.x = labelVisualPadding.left;
903       labelPosition.y = labelVisualPadding.top;
904
905       remainingSpaceForText.width = size.width - labelVisualPadding.x - labelVisualPadding.y;
906       remainingSpaceForText.height = size.height - visualAndPaddingSize.height - labelVisualPadding.top - labelVisualPadding.bottom;
907
908       break;
909     }
910     case BOTTOM :
911     {
912       visualAnchorPoint = Toolkit::Align::TOP_END;
913       visualPosition.x = foregroundVisualPadding.left;
914       visualPosition.y = foregroundVisualPadding.top;
915
916       labelPosition.x = labelVisualPadding.left;
917       labelPosition.y = visualAndPaddingSize.height + labelVisualPadding.top;
918
919       remainingSpaceForText.width = size.width - labelVisualPadding.x - labelVisualPadding.y;
920       remainingSpaceForText.height = size.height - visualAndPaddingSize.height - labelVisualPadding.top - labelVisualPadding.bottom;
921
922       break;
923     }
924   }
925
926   if ( currentBackGroundVisual )
927   {
928     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Setting visual background size to(%f,%f)\n", size.width, size.height);
929
930     Property::Map visualTransform;
931
932     visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, size )
933                    .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) );
934
935     currentBackGroundVisual.SetTransformAndSize( visualTransform, size );
936   }
937
938   if ( currentVisual )
939   {
940     DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Setting visual size to(%f,%f)\n", visualSize.width, visualSize.height);
941
942     Property::Map visualTransform;
943
944     visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, visualSize )
945                    .Add( Toolkit::Visual::Transform::Property::OFFSET, visualPosition )
946                    .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
947                    .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
948                    .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
949                    .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, visualAnchorPoint );
950
951     currentVisual.SetTransformAndSize( visualTransform, size );
952   }
953
954   if ( mTextStringSetFlag )
955   {
956     Toolkit::Visual::Base textVisual = DevelControl::GetVisual( *this, Toolkit::Button::Property::LABEL ); // No need to search for Label visual if no text set.
957
958     if ( textVisual )
959     {
960       if ( !currentVisual )
961       {
962         DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Only Text\n");
963         labelPosition.x = labelVisualPadding.left;
964         labelPosition.y = labelVisualPadding.height;
965       }
966
967       Vector2 preSize = Vector2( static_cast< int >( remainingSpaceForText.x ), static_cast< int >( remainingSpaceForText.y ));
968
969       DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout text Size(%f,%f) text Position(%f,%f) \n", remainingSpaceForText.width, remainingSpaceForText.height, labelPosition.x, labelPosition.y);
970
971       DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout text Size -- (%f,%f) text Position(%f,%f) \n", preSize.width, preSize.height, labelPosition.x, labelPosition.y);
972
973
974       Property::Map textVisualTransform;
975       textVisualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, preSize )
976                          .Add( Toolkit::Visual::Transform::Property::OFFSET, labelPosition )
977                          .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
978                          .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
979                          .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
980                          .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, visualAnchorPoint );
981
982       textVisual.SetTransformAndSize( textVisualTransform, size );
983     }
984   }
985
986   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout selected (%s) \n", IsSelected()?"yes":"no" );
987
988   DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout << \n");
989 }
990
991 void Button::OnTap(Actor actor, const TapGesture& tap)
992 {
993   // Prevents Parent getting a tap event
994 }
995
996 void Button::SetUpTimer( float delay )
997 {
998   mAutoRepeatingTimer = Dali::Timer::New( static_cast<unsigned int>( 1000.f * delay ) );
999   mAutoRepeatingTimer.TickSignal().Connect( this, &Button::AutoRepeatingSlot );
1000   mAutoRepeatingTimer.Start();
1001 }
1002
1003 bool Button::AutoRepeatingSlot()
1004 {
1005   bool consumed = false;
1006   if( !IsDisabled() )
1007   {
1008     // Restart the autorepeat timer.
1009     SetUpTimer( mNextAutoRepeatingDelay );
1010
1011     Pressed();
1012
1013     Toolkit::Button handle( GetOwner() );
1014
1015     //Emit signal.
1016     consumed = mReleasedSignal.Emit( handle );
1017     consumed = mClickedSignal.Emit( handle );
1018     consumed |= mPressedSignal.Emit( handle );
1019  }
1020
1021   return consumed;
1022 }
1023
1024 void Button::Pressed()
1025 {
1026   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::Pressed\n" );
1027
1028   if( mButtonState == UNSELECTED_STATE )
1029   {
1030     ChangeState( SELECTED_STATE );
1031     OnPressed();  // Notifies the derived class the button has been pressed.
1032   }
1033 }
1034
1035 void Button::Released()
1036 {
1037   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::Released\n" );
1038
1039   if( mButtonState == SELECTED_STATE && !mTogglableButton )
1040   {
1041     ChangeState( UNSELECTED_STATE );
1042     OnReleased(); //    // Notifies the derived class the button has been released.
1043   }
1044   mButtonPressedState = UNPRESSED;
1045 }
1046
1047 void Button::SelectRequiredVisual( Property::Index visualIndex )
1048 {
1049   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SelectRequiredVisual index(%d) state(%d)\n", visualIndex, mButtonState );
1050   // only enable visuals that exist
1051   if( DevelControl::GetVisual( *this, visualIndex ) )
1052   {
1053     DevelControl::EnableVisual( *this, visualIndex, true );
1054   }
1055 }
1056
1057 void Button::RemoveVisual( Property::Index visualIndex )
1058 {
1059   // Use OnButtonVisualRemoval if want button developer to have the option to override removal.
1060   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::RemoveVisual index(%d) state(%d)\n", visualIndex, mButtonState );
1061
1062   Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, visualIndex );
1063
1064   if( visual )
1065   {
1066     DevelControl::EnableVisual( *this, visualIndex, false );
1067   }
1068 }
1069
1070 void Button::OnButtonVisualRemoval( Property::Index visualIndex )
1071 {
1072   // Derived Buttons can over ride this to prevent default removal.
1073   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::OnButtonVisualRemoval index(%d)\n", visualIndex );
1074   RemoveVisual( visualIndex );
1075 }
1076
1077 void Button::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
1078 {
1079   Toolkit::Button button = Toolkit::Button::DownCast( Dali::BaseHandle( object ) );
1080
1081   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetProperty index[%d]\n", index );
1082
1083   if ( button )
1084   {
1085     switch ( index )
1086     {
1087       case Toolkit::Button::Property::DISABLED:
1088       {
1089         GetImplementation( button ).SetDisabled( value.Get< bool >() );
1090         break;
1091       }
1092
1093       case Toolkit::Button::Property::AUTO_REPEATING:
1094       {
1095         GetImplementation( button ).SetAutoRepeating( value.Get< bool >() );
1096         break;
1097       }
1098
1099       case Toolkit::Button::Property::INITIAL_AUTO_REPEATING_DELAY:
1100       {
1101         GetImplementation( button ).SetInitialAutoRepeatingDelay( value.Get< float >() );
1102         break;
1103       }
1104
1105       case Toolkit::Button::Property::NEXT_AUTO_REPEATING_DELAY:
1106       {
1107         GetImplementation( button ).SetNextAutoRepeatingDelay( value.Get< float >() );
1108         break;
1109       }
1110
1111       case Toolkit::Button::Property::TOGGLABLE:
1112       {
1113         GetImplementation( button ).SetTogglableButton( value.Get< bool >() );
1114         break;
1115       }
1116
1117       case Toolkit::Button::Property::SELECTED:
1118       {
1119         GetImplementation( button ).SetSelected( value.Get< bool >() );
1120         break;
1121       }
1122
1123       case Toolkit::Button::Property::UNSELECTED_VISUAL:
1124       case Toolkit::Button::Property::SELECTED_VISUAL:
1125       case Toolkit::Button::Property::DISABLED_SELECTED_VISUAL:
1126       case Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL:
1127       {
1128         GetImplementation( button ).CreateVisualsForComponent( index, value, DepthIndex::CONTENT );
1129         break;
1130       }
1131
1132       case Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL:
1133       case Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL:
1134       case Toolkit::Button::Property::DISABLED_SELECTED_BACKGROUND_VISUAL:
1135       case Toolkit::Button::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL:
1136       {
1137         GetImplementation( button ).CreateVisualsForComponent( index , value, DepthIndex::BACKGROUND);
1138         break;
1139       }
1140
1141       case Toolkit::Button::Property::LABEL:
1142       {
1143         Property::Map outTextVisualProperties;
1144         std::string textString;
1145
1146         if ( value.Get( textString ) )
1147         {
1148           DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetProperty Setting TextVisual with string[%s]\n", textString.c_str() );
1149
1150           Property::Map setPropertyMap;
1151           setPropertyMap.Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT )
1152                         .Add( Toolkit::TextVisual::Property::TEXT, textString );
1153
1154           GetImplementation( button ).MergeWithExistingLabelProperties( setPropertyMap, outTextVisualProperties );
1155         }
1156         else
1157         {
1158           // Get a Property::Map from the property if possible.
1159           Property::Map* setPropertyMap = value.GetMap();
1160           if( setPropertyMap )
1161           {
1162             TextVisual::ConvertStringKeysToIndexKeys( *setPropertyMap );
1163             GetImplementation( button ).MergeWithExistingLabelProperties( *setPropertyMap, outTextVisualProperties );
1164           }
1165         }
1166
1167         if( !outTextVisualProperties.Empty() )
1168         {
1169           GetImplementation( button ).CreateVisualsForComponent( index, outTextVisualProperties, DepthIndex::CONTENT );
1170         }
1171         break;
1172       }
1173
1174       case Toolkit::DevelButton::Property::LABEL_RELATIVE_ALIGNMENT:
1175       {
1176         Button::Align labelAlignment(END);
1177         Scripting::GetEnumeration< Button::Align> ( value.Get< std::string >().c_str(),
1178                                                     ALIGNMENT_TABLE, ALIGNMENT_TABLE_COUNT,
1179                                                     labelAlignment );
1180
1181         GetImplementation( button ).SetLabelAlignment( labelAlignment );
1182         break;
1183       }
1184
1185       case Toolkit::DevelButton::Property::LABEL_PADDING:
1186       {
1187         Vector4 padding ( value.Get< Vector4 >() );
1188         GetImplementation( button ).SetLabelPadding( Padding( padding.x, padding.y, padding.z, padding.w ) );
1189         break;
1190       }
1191
1192       case Toolkit::DevelButton::Property::VISUAL_PADDING:
1193       {
1194         Vector4 padding ( value.Get< Vector4 >() );
1195         GetImplementation( button ).SetForegroundPadding( Padding( padding.x, padding.y, padding.z, padding.w ) );
1196         break;
1197       }
1198     }
1199   }
1200 }
1201
1202 Property::Value Button::GetProperty( BaseObject* object, Property::Index propertyIndex )
1203 {
1204   Property::Value value;
1205
1206   Toolkit::Button button = Toolkit::Button::DownCast( Dali::BaseHandle( object ) );
1207
1208   if ( button )
1209   {
1210     switch ( propertyIndex )
1211     {
1212       case Toolkit::Button::Property::DISABLED:
1213       {
1214         value = GetImplementation( button ).IsDisabled();
1215         break;
1216       }
1217
1218       case Toolkit::Button::Property::AUTO_REPEATING:
1219       {
1220         value = GetImplementation( button ).mAutoRepeating;
1221         break;
1222       }
1223
1224       case Toolkit::Button::Property::INITIAL_AUTO_REPEATING_DELAY:
1225       {
1226         value = GetImplementation( button ).mInitialAutoRepeatingDelay;
1227         break;
1228       }
1229
1230       case Toolkit::Button::Property::NEXT_AUTO_REPEATING_DELAY:
1231       {
1232         value = GetImplementation( button ).mNextAutoRepeatingDelay;
1233         break;
1234       }
1235
1236       case Toolkit::Button::Property::TOGGLABLE:
1237       {
1238         value = GetImplementation( button ).mTogglableButton;
1239         break;
1240       }
1241
1242       case Toolkit::Button::Property::SELECTED:
1243       {
1244         value = GetImplementation( button ).IsSelected();
1245         break;
1246       }
1247
1248       case Toolkit::Button::Property::UNSELECTED_VISUAL:
1249       case Toolkit::Button::Property::SELECTED_VISUAL:
1250       case Toolkit::Button::Property::DISABLED_SELECTED_VISUAL:
1251       case Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL:
1252       case Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL:
1253       case Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL:
1254       case Toolkit::Button::Property::DISABLED_SELECTED_BACKGROUND_VISUAL:
1255       case Toolkit::Button::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL:
1256       case Toolkit::Button::Property::LABEL:
1257       {
1258         Property::Map visualProperty;
1259         if ( GetImplementation( button ).GetPropertyMapForVisual( propertyIndex, visualProperty ) )
1260         {
1261           value = visualProperty;
1262         }
1263         break;
1264       }
1265
1266       case Toolkit::DevelButton::Property::LABEL_RELATIVE_ALIGNMENT:
1267       {
1268         const char* alignment = Scripting::GetEnumerationName< Button::Align >( GetImplementation( button ).GetLabelAlignment(),
1269                                                                                 ALIGNMENT_STRING_TABLE,
1270                                                                                 ALIGNMENT_STRING_TABLE_COUNT );
1271         if( alignment )
1272         {
1273           value = std::string( alignment );
1274         }
1275
1276         break;
1277       }
1278
1279       case Toolkit::DevelButton::Property::LABEL_PADDING:
1280       {
1281         Padding padding = GetImplementation( button ).GetLabelPadding();
1282         value = Vector4( padding.x, padding.y, padding.top, padding.bottom);
1283         break;
1284       }
1285
1286       case Toolkit::DevelButton::Property::VISUAL_PADDING:
1287       {
1288         Padding padding = GetImplementation( button ).GetForegroundPadding();
1289         value = Vector4( padding.x, padding.y, padding.top, padding.bottom);
1290       }
1291     }
1292   }
1293
1294   return value;
1295 }
1296
1297 void Button::SetLabelPadding( const Padding& padding)
1298 {
1299   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetLabelPadding padding(%f,%f,%f,%f)\n", padding.left, padding.right, padding.bottom, padding.top );
1300   mLabelPadding = Padding( padding.left, padding.right, padding.bottom, padding.top );
1301   RelayoutRequest();
1302 }
1303
1304 Padding Button::GetLabelPadding()
1305 {
1306   return mLabelPadding;
1307 }
1308
1309 void Button::SetForegroundPadding( const Padding& padding)
1310 {
1311   DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetForegroundPadding padding(%f,%f,%f,%f)\n", padding.left, padding.right, padding.bottom, padding.top );
1312   mForegroundPadding = Padding( padding.left, padding.right, padding.bottom, padding.top );
1313   RelayoutRequest();
1314 }
1315
1316 Padding Button::GetForegroundPadding()
1317 {
1318   return mForegroundPadding;
1319 }
1320
1321 } // namespace Internal
1322
1323 } // namespace Toolkit
1324
1325 } // namespace Dali