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