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