Merge "Add TOUCH_FOCUSABLE property" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / control / control-data-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 "control-data-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali-toolkit/public-api/controls/control-impl.h>
23 #include <dali-toolkit/public-api/controls/control.h>
24 #include <dali-toolkit/public-api/dali-toolkit-common.h>
25 #include <dali/devel-api/actors/actor-devel.h>
26 #include <dali/devel-api/adaptor-framework/accessibility.h>
27 #include <dali/devel-api/common/stage.h>
28 #include <dali/devel-api/object/handle-devel.h>
29 #include <dali/devel-api/scripting/enum-helper.h>
30 #include <dali/devel-api/scripting/scripting.h>
31 #include <dali/integration-api/adaptor-framework/adaptor.h>
32 #include <dali/integration-api/debug.h>
33 #include <dali/public-api/object/object-registry.h>
34 #include <dali/public-api/object/type-registry-helper.h>
35 #include <cstring>
36 #include <limits>
37
38 // INTERNAL INCLUDES
39 #include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
40 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
41 #include <dali-toolkit/devel-api/controls/control-devel.h>
42 #include <dali-toolkit/devel-api/controls/control-wrapper-impl.h>
43 #include <dali-toolkit/internal/styling/style-manager-impl.h>
44 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
45 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
46 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
47 #include <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
48 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
49 #include <dali-toolkit/public-api/visuals/visual-properties.h>
50
51 namespace
52 {
53 const std::string READING_INFO_TYPE_NAME           = "name";
54 const std::string READING_INFO_TYPE_ROLE           = "role";
55 const std::string READING_INFO_TYPE_DESCRIPTION    = "description";
56 const std::string READING_INFO_TYPE_STATE          = "state";
57 const std::string READING_INFO_TYPE_ATTRIBUTE_NAME = "reading_info_type";
58 const std::string READING_INFO_TYPE_SEPARATOR      = "|";
59 } // namespace
60
61 namespace Dali
62 {
63 namespace Toolkit
64 {
65 namespace Internal
66 {
67 extern const Dali::Scripting::StringEnum ControlStateTable[];
68 extern const unsigned int                ControlStateTableCount;
69
70 // Not static or anonymous - shared with other translation units
71 const Scripting::StringEnum ControlStateTable[] = {
72   {"NORMAL", Toolkit::DevelControl::NORMAL},
73   {"FOCUSED", Toolkit::DevelControl::FOCUSED},
74   {"DISABLED", Toolkit::DevelControl::DISABLED},
75 };
76 const unsigned int ControlStateTableCount = sizeof(ControlStateTable) / sizeof(ControlStateTable[0]);
77
78 namespace
79 {
80 #if defined(DEBUG_ENABLED)
81 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_CONTROL_VISUALS");
82 #endif
83
84 template<typename T>
85 void Remove(Dictionary<T>& keyValues, const std::string& name)
86 {
87   keyValues.Remove(name);
88 }
89
90 void Remove(DictionaryKeys& keys, const std::string& name)
91 {
92   DictionaryKeys::iterator iter = std::find(keys.begin(), keys.end(), name);
93   if(iter != keys.end())
94   {
95     keys.erase(iter);
96   }
97 }
98
99 /**
100  *  Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
101  */
102 bool FindVisual(Property::Index targetIndex, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter)
103 {
104   for(iter = visuals.Begin(); iter != visuals.End(); iter++)
105   {
106     if((*iter)->index == targetIndex)
107     {
108       return true;
109     }
110   }
111   return false;
112 }
113
114 /**
115  *  Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
116  */
117 bool FindVisual(std::string visualName, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter)
118 {
119   for(iter = visuals.Begin(); iter != visuals.End(); iter++)
120   {
121     Toolkit::Visual::Base visual = (*iter)->visual;
122     if(visual && visual.GetName() == visualName)
123     {
124       return true;
125     }
126   }
127   return false;
128 }
129
130 void FindChangableVisuals(Dictionary<Property::Map>& stateVisualsToAdd,
131                           Dictionary<Property::Map>& stateVisualsToChange,
132                           DictionaryKeys&            stateVisualsToRemove)
133 {
134   DictionaryKeys copyOfStateVisualsToRemove = stateVisualsToRemove;
135
136   for(DictionaryKeys::iterator iter = copyOfStateVisualsToRemove.begin();
137       iter != copyOfStateVisualsToRemove.end();
138       ++iter)
139   {
140     const std::string& visualName = (*iter);
141     Property::Map*     toMap      = stateVisualsToAdd.Find(visualName);
142     if(toMap)
143     {
144       stateVisualsToChange.Add(visualName, *toMap);
145       stateVisualsToAdd.Remove(visualName);
146       Remove(stateVisualsToRemove, visualName);
147     }
148   }
149 }
150
151 Toolkit::Visual::Base GetVisualByName(
152   const RegisteredVisualContainer& visuals,
153   const std::string&               visualName)
154 {
155   Toolkit::Visual::Base visualHandle;
156
157   RegisteredVisualContainer::Iterator iter;
158   for(iter = visuals.Begin(); iter != visuals.End(); iter++)
159   {
160     Toolkit::Visual::Base visual = (*iter)->visual;
161     if(visual && visual.GetName() == visualName)
162     {
163       visualHandle = visual;
164       break;
165     }
166   }
167   return visualHandle;
168 }
169
170 Toolkit::Visual::Base GetVisualByIndex(
171   const RegisteredVisualContainer& visuals,
172   Property::Index                  index)
173 {
174   Toolkit::Visual::Base visualHandle;
175
176   RegisteredVisualContainer::Iterator iter;
177   for(iter = visuals.Begin(); iter != visuals.End(); iter++)
178   {
179     if((*iter)->index == index)
180     {
181       visualHandle = (*iter)->visual;
182       break;
183     }
184   }
185   return visualHandle;
186 }
187
188 /**
189  * Move visual from source to destination container
190  */
191 void MoveVisual(RegisteredVisualContainer::Iterator sourceIter, RegisteredVisualContainer& source, RegisteredVisualContainer& destination)
192 {
193   Toolkit::Visual::Base visual = (*sourceIter)->visual;
194   if(visual)
195   {
196     RegisteredVisual* rv = source.Release(sourceIter);
197     destination.PushBack(rv);
198   }
199 }
200
201 /**
202  * Performs actions as requested using the action name.
203  * @param[in] object The object on which to perform the action.
204  * @param[in] actionName The action to perform.
205  * @param[in] attributes The attributes with which to perfrom this action.
206  * @return true if action has been accepted by this control
207  */
208 const char* ACTION_ACCESSIBILITY_ACTIVATED         = "accessibilityActivated";
209 const char* ACTION_ACCESSIBILITY_READING_CANCELLED = "ReadingCancelled";
210 const char* ACTION_ACCESSIBILITY_READING_PAUSED    = "ReadingPaused";
211 const char* ACTION_ACCESSIBILITY_READING_RESUMED   = "ReadingResumed";
212 const char* ACTION_ACCESSIBILITY_READING_SKIPPED   = "ReadingSkipped";
213 const char* ACTION_ACCESSIBILITY_READING_STOPPED   = "ReadingStopped";
214
215 static bool DoAction(BaseObject* object, const std::string& actionName, const Property::Map& attributes)
216 {
217   bool ret = true;
218
219   Dali::BaseHandle handle(object);
220
221   Toolkit::Control control = Toolkit::Control::DownCast(handle);
222
223   DALI_ASSERT_ALWAYS(control);
224
225   if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_ACTIVATED) ||
226      actionName == "activate")
227   {
228     // if cast succeeds there is an implementation so no need to check
229     if(!DevelControl::AccessibilityActivateSignal(control).Empty())
230       DevelControl::AccessibilityActivateSignal(control).Emit();
231     else
232       ret = Internal::GetImplementation(control).OnAccessibilityActivated();
233   }
234   else if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_READING_SKIPPED))
235   {
236     // if cast succeeds there is an implementation so no need to check
237     if(!DevelControl::AccessibilityReadingSkippedSignal(control).Empty())
238       DevelControl::AccessibilityReadingSkippedSignal(control).Emit();
239   }
240   else if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_READING_PAUSED))
241   {
242     // if cast succeeds there is an implementation so no need to check
243     if(!DevelControl::AccessibilityReadingPausedSignal(control).Empty())
244       DevelControl::AccessibilityReadingPausedSignal(control).Emit();
245   }
246   else if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_READING_RESUMED))
247   {
248     // if cast succeeds there is an implementation so no need to check
249     if(!DevelControl::AccessibilityReadingResumedSignal(control).Empty())
250       DevelControl::AccessibilityReadingResumedSignal(control).Emit();
251   }
252   else if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_READING_CANCELLED))
253   {
254     // if cast succeeds there is an implementation so no need to check
255     if(!DevelControl::AccessibilityReadingCancelledSignal(control).Empty())
256       DevelControl::AccessibilityReadingCancelledSignal(control).Emit();
257   }
258   else if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_READING_STOPPED))
259   {
260     // if cast succeeds there is an implementation so no need to check
261     if(!DevelControl::AccessibilityReadingStoppedSignal(control).Empty())
262       DevelControl::AccessibilityReadingStoppedSignal(control).Emit();
263   }
264   else
265   {
266     ret = false;
267   }
268   return ret;
269 }
270
271 /**
272  * Connects a callback function with the object's signals.
273  * @param[in] object The object providing the signal.
274  * @param[in] tracker Used to disconnect the signal.
275  * @param[in] signalName The signal to connect to.
276  * @param[in] functor A newly allocated FunctorDelegate.
277  * @return True if the signal was connected.
278  * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
279  */
280 const char* SIGNAL_KEY_EVENT              = "keyEvent";
281 const char* SIGNAL_KEY_INPUT_FOCUS_GAINED = "keyInputFocusGained";
282 const char* SIGNAL_KEY_INPUT_FOCUS_LOST   = "keyInputFocusLost";
283 const char* SIGNAL_TAPPED                 = "tapped";
284 const char* SIGNAL_PANNED                 = "panned";
285 const char* SIGNAL_PINCHED                = "pinched";
286 const char* SIGNAL_LONG_PRESSED           = "longPressed";
287 const char* SIGNAL_GET_NAME               = "getName";
288 const char* SIGNAL_GET_DESCRIPTION        = "getDescription";
289 const char* SIGNAL_DO_GESTURE             = "doGesture";
290 static bool DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
291 {
292   Dali::BaseHandle handle(object);
293
294   bool             connected(false);
295   Toolkit::Control control = Toolkit::Control::DownCast(handle);
296   if(control)
297   {
298     Internal::Control& controlImpl(Internal::GetImplementation(control));
299     connected = true;
300
301     if(0 == strcmp(signalName.c_str(), SIGNAL_KEY_EVENT))
302     {
303       controlImpl.KeyEventSignal().Connect(tracker, functor);
304     }
305     else if(0 == strcmp(signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_GAINED))
306     {
307       controlImpl.KeyInputFocusGainedSignal().Connect(tracker, functor);
308     }
309     else if(0 == strcmp(signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_LOST))
310     {
311       controlImpl.KeyInputFocusLostSignal().Connect(tracker, functor);
312     }
313     else if(0 == strcmp(signalName.c_str(), SIGNAL_TAPPED))
314     {
315       controlImpl.EnableGestureDetection(GestureType::TAP);
316       controlImpl.GetTapGestureDetector().DetectedSignal().Connect(tracker, functor);
317     }
318     else if(0 == strcmp(signalName.c_str(), SIGNAL_PANNED))
319     {
320       controlImpl.EnableGestureDetection(GestureType::PAN);
321       controlImpl.GetPanGestureDetector().DetectedSignal().Connect(tracker, functor);
322     }
323     else if(0 == strcmp(signalName.c_str(), SIGNAL_PINCHED))
324     {
325       controlImpl.EnableGestureDetection(GestureType::PINCH);
326       controlImpl.GetPinchGestureDetector().DetectedSignal().Connect(tracker, functor);
327     }
328     else if(0 == strcmp(signalName.c_str(), SIGNAL_LONG_PRESSED))
329     {
330       controlImpl.EnableGestureDetection(GestureType::LONG_PRESS);
331       controlImpl.GetLongPressGestureDetector().DetectedSignal().Connect(tracker, functor);
332     }
333     else if(0 == strcmp(signalName.c_str(), SIGNAL_GET_NAME))
334     {
335       DevelControl::AccessibilityGetNameSignal(control).Connect(tracker, functor);
336     }
337     else if(0 == strcmp(signalName.c_str(), SIGNAL_GET_DESCRIPTION))
338     {
339       DevelControl::AccessibilityGetDescriptionSignal(control).Connect(tracker, functor);
340     }
341     else if(0 == strcmp(signalName.c_str(), SIGNAL_DO_GESTURE))
342     {
343       DevelControl::AccessibilityDoGestureSignal(control).Connect(tracker, functor);
344     }
345   }
346   return connected;
347 }
348
349 /**
350  * Creates control through type registry
351  */
352 BaseHandle Create()
353 {
354   return Internal::Control::New();
355 }
356 // Setup signals and actions using the type-registry.
357 DALI_TYPE_REGISTRATION_BEGIN(Control, CustomActor, Create);
358
359 // Note: Properties are registered separately below.
360
361 SignalConnectorType registerSignal1(typeRegistration, SIGNAL_KEY_EVENT, &DoConnectSignal);
362 SignalConnectorType registerSignal2(typeRegistration, SIGNAL_KEY_INPUT_FOCUS_GAINED, &DoConnectSignal);
363 SignalConnectorType registerSignal3(typeRegistration, SIGNAL_KEY_INPUT_FOCUS_LOST, &DoConnectSignal);
364 SignalConnectorType registerSignal4(typeRegistration, SIGNAL_TAPPED, &DoConnectSignal);
365 SignalConnectorType registerSignal5(typeRegistration, SIGNAL_PANNED, &DoConnectSignal);
366 SignalConnectorType registerSignal6(typeRegistration, SIGNAL_PINCHED, &DoConnectSignal);
367 SignalConnectorType registerSignal7(typeRegistration, SIGNAL_LONG_PRESSED, &DoConnectSignal);
368 SignalConnectorType registerSignal8(typeRegistration, SIGNAL_GET_NAME, &DoConnectSignal);
369 SignalConnectorType registerSignal9(typeRegistration, SIGNAL_GET_DESCRIPTION, &DoConnectSignal);
370 SignalConnectorType registerSignal10(typeRegistration, SIGNAL_DO_GESTURE, &DoConnectSignal);
371
372 TypeAction registerAction1(typeRegistration, "activate", &DoAction);
373 TypeAction registerAction2(typeRegistration, ACTION_ACCESSIBILITY_ACTIVATED, &DoAction);
374 TypeAction registerAction3(typeRegistration, ACTION_ACCESSIBILITY_READING_SKIPPED, &DoAction);
375 TypeAction registerAction4(typeRegistration, ACTION_ACCESSIBILITY_READING_CANCELLED, &DoAction);
376 TypeAction registerAction5(typeRegistration, ACTION_ACCESSIBILITY_READING_STOPPED, &DoAction);
377 TypeAction registerAction6(typeRegistration, ACTION_ACCESSIBILITY_READING_PAUSED, &DoAction);
378 TypeAction registerAction7(typeRegistration, ACTION_ACCESSIBILITY_READING_RESUMED, &DoAction);
379
380 DALI_TYPE_REGISTRATION_END()
381
382 /**
383  * @brief Iterate through given container and setOffScene any visual found
384  *
385  * @param[in] container Container of visuals
386  * @param[in] parent Parent actor to remove visuals from
387  */
388 void SetVisualsOffScene(const RegisteredVisualContainer& container, Actor parent)
389 {
390   for(auto iter = container.Begin(), end = container.End(); iter != end; iter++)
391   {
392     if((*iter)->visual)
393     {
394       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::SetOffScene Setting visual(%d) off stage\n", (*iter)->index);
395       Toolkit::GetImplementation((*iter)->visual).SetOffScene(parent);
396     }
397   }
398 }
399
400 } // unnamed namespace
401
402 // clang-format off
403 // Properties registered without macro to use specific member variables.
404 const PropertyRegistration Control::Impl::PROPERTY_1(typeRegistration,  "styleName",                      Toolkit::Control::Property::STYLE_NAME,                            Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty);
405 const PropertyRegistration Control::Impl::PROPERTY_4(typeRegistration,  "keyInputFocus",                  Toolkit::Control::Property::KEY_INPUT_FOCUS,                       Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
406 const PropertyRegistration Control::Impl::PROPERTY_5(typeRegistration,  "background",                     Toolkit::Control::Property::BACKGROUND,                            Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty);
407 const PropertyRegistration Control::Impl::PROPERTY_6(typeRegistration,  "margin",                         Toolkit::Control::Property::MARGIN,                                Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
408 const PropertyRegistration Control::Impl::PROPERTY_7(typeRegistration,  "padding",                        Toolkit::Control::Property::PADDING,                               Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
409 const PropertyRegistration Control::Impl::PROPERTY_8(typeRegistration,  "tooltip",                        Toolkit::DevelControl::Property::TOOLTIP,                          Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty);
410 const PropertyRegistration Control::Impl::PROPERTY_9(typeRegistration,  "state",                          Toolkit::DevelControl::Property::STATE,                            Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty);
411 const PropertyRegistration Control::Impl::PROPERTY_10(typeRegistration, "subState",                       Toolkit::DevelControl::Property::SUB_STATE,                        Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty);
412 const PropertyRegistration Control::Impl::PROPERTY_11(typeRegistration, "leftFocusableActorId",           Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID,          Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
413 const PropertyRegistration Control::Impl::PROPERTY_12(typeRegistration, "rightFocusableActorId",          Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID,         Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
414 const PropertyRegistration Control::Impl::PROPERTY_13(typeRegistration, "upFocusableActorId",             Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID,            Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
415 const PropertyRegistration Control::Impl::PROPERTY_14(typeRegistration, "downFocusableActorId",           Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID,          Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
416 const PropertyRegistration Control::Impl::PROPERTY_15(typeRegistration, "shadow",                         Toolkit::DevelControl::Property::SHADOW,                           Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty);
417 const PropertyRegistration Control::Impl::PROPERTY_16(typeRegistration, "accessibilityAttributes",        Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES,         Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty);
418 const PropertyRegistration Control::Impl::PROPERTY_17(typeRegistration, "accessibilityName",              Toolkit::DevelControl::Property::ACCESSIBILITY_NAME,               Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty);
419 const PropertyRegistration Control::Impl::PROPERTY_18(typeRegistration, "accessibilityDescription",       Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION,        Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty);
420 const PropertyRegistration Control::Impl::PROPERTY_19(typeRegistration, "accessibilityTranslationDomain", Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN, Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty);
421 const PropertyRegistration Control::Impl::PROPERTY_20(typeRegistration, "accessibilityRole",              Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE,               Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
422 const PropertyRegistration Control::Impl::PROPERTY_21(typeRegistration, "accessibilityHighlightable",     Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE,      Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
423 // clang-format on
424
425 Control::Impl::Impl(Control& controlImpl)
426 : mControlImpl(controlImpl),
427   mState(Toolkit::DevelControl::NORMAL),
428   mSubStateName(""),
429   mLeftFocusableActorId(-1),
430   mRightFocusableActorId(-1),
431   mUpFocusableActorId(-1),
432   mDownFocusableActorId(-1),
433   mStyleName(""),
434   mBackgroundColor(Color::TRANSPARENT),
435   mStartingPinchScale(nullptr),
436   mMargin(0, 0, 0, 0),
437   mPadding(0, 0, 0, 0),
438   mKeyEventSignal(),
439   mKeyInputFocusGainedSignal(),
440   mKeyInputFocusLostSignal(),
441   mResourceReadySignal(),
442   mVisualEventSignal(),
443   mAccessibilityGetNameSignal(),
444   mAccessibilityGetDescriptionSignal(),
445   mAccessibilityDoGestureSignal(),
446   mPinchGestureDetector(),
447   mPanGestureDetector(),
448   mTapGestureDetector(),
449   mLongPressGestureDetector(),
450   mTooltip(NULL),
451   mInputMethodContext(),
452   mIdleCallback(nullptr),
453   mFlags(Control::ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
454   mIsKeyboardNavigationSupported(false),
455   mIsKeyboardFocusGroup(false),
456   mIsEmittingResourceReadySignal(false),
457   mNeedToEmitResourceReady(false)
458 {
459   Dali::Accessibility::Accessible::RegisterControlAccessibilityGetter(
460     [](Dali::Actor actor) -> Dali::Accessibility::Accessible* {
461       return Control::Impl::GetAccessibilityObject(actor);
462     });
463
464   accessibilityConstructor = [](Dali::Actor actor) -> std::unique_ptr<Dali::Accessibility::Accessible> {
465     return std::unique_ptr<Dali::Accessibility::Accessible>(new DevelControl::AccessibleImpl(actor,
466                                                                                              Dali::Accessibility::Role::UNKNOWN));
467   };
468
469   size_t len = static_cast<size_t>(Dali::Accessibility::RelationType::MAX_COUNT);
470   mAccessibilityRelations.reserve(len);
471   for(auto i = 0u; i < len; ++i)
472   {
473     mAccessibilityRelations.push_back({});
474   }
475 }
476
477 Control::Impl::~Impl()
478 {
479   for(auto&& iter : mVisuals)
480   {
481     StopObservingVisual(iter->visual);
482   }
483
484   for(auto&& iter : mRemoveVisuals)
485   {
486     StopObservingVisual(iter->visual);
487   }
488
489   // All gesture detectors will be destroyed so no need to disconnect.
490   delete mStartingPinchScale;
491
492   if(mIdleCallback && Adaptor::IsAvailable())
493   {
494     // Removes the callback from the callback manager in case the control is destroyed before the callback is executed.
495     Adaptor::Get().RemoveIdle(mIdleCallback);
496   }
497 }
498
499 Control::Impl& Control::Impl::Get(Internal::Control& internalControl)
500 {
501   return *internalControl.mImpl;
502 }
503
504 const Control::Impl& Control::Impl::Get(const Internal::Control& internalControl)
505 {
506   return *internalControl.mImpl;
507 }
508
509 // Gesture Detection Methods
510 void Control::Impl::PinchDetected(Actor actor, const PinchGesture& pinch)
511 {
512   mControlImpl.OnPinch(pinch);
513 }
514
515 void Control::Impl::PanDetected(Actor actor, const PanGesture& pan)
516 {
517   mControlImpl.OnPan(pan);
518 }
519
520 void Control::Impl::TapDetected(Actor actor, const TapGesture& tap)
521 {
522   mControlImpl.OnTap(tap);
523 }
524
525 void Control::Impl::LongPressDetected(Actor actor, const LongPressGesture& longPress)
526 {
527   mControlImpl.OnLongPress(longPress);
528 }
529
530 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual)
531 {
532   RegisterVisual(index, visual, VisualState::ENABLED, DepthIndexValue::NOT_SET);
533 }
534
535 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, int depthIndex)
536 {
537   RegisterVisual(index, visual, VisualState::ENABLED, DepthIndexValue::SET, depthIndex);
538 }
539
540 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled)
541 {
542   RegisterVisual(index, visual, (enabled ? VisualState::ENABLED : VisualState::DISABLED), DepthIndexValue::NOT_SET);
543 }
544
545 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex)
546 {
547   RegisterVisual(index, visual, (enabled ? VisualState::ENABLED : VisualState::DISABLED), DepthIndexValue::SET, depthIndex);
548 }
549
550 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex)
551 {
552   DALI_LOG_INFO(gLogFilter, Debug::Concise, "RegisterVisual:%d \n", index);
553
554   bool  visualReplaced(false);
555   Actor self = mControlImpl.Self();
556
557   // Set the depth index, if not set by caller this will be either the current visual depth, max depth of all visuals
558   // or zero.
559   int requiredDepthIndex = visual.GetDepthIndex();
560
561   if(depthIndexValueSet == DepthIndexValue::SET)
562   {
563     requiredDepthIndex = depthIndex;
564   }
565
566   // Visual replacement, existing visual should only be removed from stage when replacement ready.
567   if(!mVisuals.Empty())
568   {
569     RegisteredVisualContainer::Iterator registeredVisualsiter;
570     // Check if visual (index) is already registered, this is the current visual.
571     if(FindVisual(index, mVisuals, registeredVisualsiter))
572     {
573       Toolkit::Visual::Base& currentRegisteredVisual = (*registeredVisualsiter)->visual;
574       if(currentRegisteredVisual)
575       {
576         // Store current visual depth index as may need to set the replacement visual to same depth
577         const int currentDepthIndex = (*registeredVisualsiter)->visual.GetDepthIndex();
578
579         // No longer required to know if the replaced visual's resources are ready
580         StopObservingVisual(currentRegisteredVisual);
581
582         // If control staged and visual enabled then visuals will be swapped once ready
583         if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE) && enabled)
584         {
585           // Check if visual is currently in the process of being replaced ( is in removal container )
586           RegisteredVisualContainer::Iterator visualQueuedForRemoval;
587           if(FindVisual(index, mRemoveVisuals, visualQueuedForRemoval))
588           {
589             // Visual with same index is already in removal container so current visual pending
590             // Only the the last requested visual will be displayed so remove current visual which is staged but not ready.
591             Toolkit::GetImplementation(currentRegisteredVisual).SetOffScene(self);
592             mVisuals.Erase(registeredVisualsiter);
593           }
594           else
595           {
596             // current visual not already in removal container so add now.
597             DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %d \n", index);
598             MoveVisual(registeredVisualsiter, mVisuals, mRemoveVisuals);
599           }
600         }
601         else
602         {
603           // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later.
604           mVisuals.Erase(registeredVisualsiter);
605         }
606
607         // If we've not set the depth-index value and the new visual does not have a depth index applied to it, then use the previously set depth-index for this index
608         if((depthIndexValueSet == DepthIndexValue::NOT_SET) &&
609            (visual.GetDepthIndex() == 0))
610         {
611           requiredDepthIndex = currentDepthIndex;
612         }
613       }
614
615       visualReplaced = true;
616     }
617   }
618
619   // If not set, set the name of the visual to the same name as the control's property.
620   // ( If the control has been type registered )
621   if(visual.GetName().empty())
622   {
623     // returns empty string if index is not found as long as index is not -1
624     std::string visualName = self.GetPropertyName(index);
625     if(!visualName.empty())
626     {
627       DALI_LOG_INFO(gLogFilter, Debug::Concise, "Setting visual name for property %d to %s\n", index, visualName.c_str());
628       visual.SetName(visualName);
629     }
630   }
631
632   if(!visualReplaced) // New registration entry
633   {
634     // If we've not set the depth-index value, we have more than one visual and the visual does not have a depth index, then set it to be the highest
635     if((depthIndexValueSet == DepthIndexValue::NOT_SET) &&
636        (mVisuals.Size() > 0) &&
637        (visual.GetDepthIndex() == 0))
638     {
639       int maxDepthIndex = std::numeric_limits<int>::min();
640
641       RegisteredVisualContainer::ConstIterator       iter;
642       const RegisteredVisualContainer::ConstIterator endIter = mVisuals.End();
643       for(iter = mVisuals.Begin(); iter != endIter; iter++)
644       {
645         const int visualDepthIndex = (*iter)->visual.GetDepthIndex();
646         if(visualDepthIndex > maxDepthIndex)
647         {
648           maxDepthIndex = visualDepthIndex;
649         }
650       }
651       ++maxDepthIndex;                                 // Add one to the current maximum depth index so that our added visual appears on top
652       requiredDepthIndex = std::max(0, maxDepthIndex); // Start at zero if maxDepth index belongs to a background
653     }
654   }
655
656   if(visual)
657   {
658     // Set determined depth index
659     visual.SetDepthIndex(requiredDepthIndex);
660
661     // Monitor when the visual resources are ready
662     StartObservingVisual(visual);
663
664     DALI_LOG_INFO(gLogFilter, Debug::Concise, "New Visual registration index[%d] depth[%d]\n", index, requiredDepthIndex);
665     RegisteredVisual* newRegisteredVisual = new RegisteredVisual(index, visual, (enabled == VisualState::ENABLED ? true : false), (visualReplaced && enabled));
666     mVisuals.PushBack(newRegisteredVisual);
667
668     Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
669     // Put on stage if enabled and the control is already on the stage
670     if((enabled == VisualState::ENABLED) && self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
671     {
672       visualImpl.SetOnScene(self);
673     }
674     else if(visualImpl.IsResourceReady()) // When not being staged, check if visual already 'ResourceReady' before it was Registered. ( Resource may have been loaded already )
675     {
676       ResourceReady(visualImpl);
677     }
678   }
679
680   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::RegisterVisual() Registered %s(%d), enabled:%s\n", visual.GetName().c_str(), index, enabled ? "true" : "false");
681 }
682
683 void Control::Impl::UnregisterVisual(Property::Index index)
684 {
685   RegisteredVisualContainer::Iterator iter;
686   if(FindVisual(index, mVisuals, iter))
687   {
688     // stop observing visual
689     StopObservingVisual((*iter)->visual);
690
691     Actor self(mControlImpl.Self());
692     Toolkit::GetImplementation((*iter)->visual).SetOffScene(self);
693     (*iter)->visual.Reset();
694     mVisuals.Erase(iter);
695   }
696
697   if(FindVisual(index, mRemoveVisuals, iter))
698   {
699     Actor self(mControlImpl.Self());
700     Toolkit::GetImplementation((*iter)->visual).SetOffScene(self);
701     (*iter)->pending = false;
702     (*iter)->visual.Reset();
703     mRemoveVisuals.Erase(iter);
704   }
705 }
706
707 Toolkit::Visual::Base Control::Impl::GetVisual(Property::Index index) const
708 {
709   RegisteredVisualContainer::Iterator iter;
710   if(FindVisual(index, mVisuals, iter))
711   {
712     return (*iter)->visual;
713   }
714
715   return Toolkit::Visual::Base();
716 }
717
718 void Control::Impl::EnableVisual(Property::Index index, bool enable)
719 {
720   DALI_LOG_INFO(gLogFilter, Debug::General, "Control::EnableVisual(%d, %s)\n", index, enable ? "T" : "F");
721
722   RegisteredVisualContainer::Iterator iter;
723   if(FindVisual(index, mVisuals, iter))
724   {
725     if((*iter)->enabled == enable)
726     {
727       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Visual %s(%d) already %s\n", (*iter)->visual.GetName().c_str(), index, enable ? "enabled" : "disabled");
728       return;
729     }
730
731     (*iter)->enabled  = enable;
732     Actor parentActor = mControlImpl.Self();
733     if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE)) // If control not on Scene then Visual will be added when SceneConnection is called.
734     {
735       if(enable)
736       {
737         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) on stage \n", (*iter)->visual.GetName().c_str(), index);
738         Toolkit::GetImplementation((*iter)->visual).SetOnScene(parentActor);
739       }
740       else
741       {
742         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) off stage \n", (*iter)->visual.GetName().c_str(), index);
743         Toolkit::GetImplementation((*iter)->visual).SetOffScene(parentActor); // No need to call if control not staged.
744       }
745     }
746   }
747   else
748   {
749     DALI_LOG_WARNING("Control::EnableVisual(%d, %s) FAILED - NO SUCH VISUAL\n", index, enable ? "T" : "F");
750   }
751 }
752
753 bool Control::Impl::IsVisualEnabled(Property::Index index) const
754 {
755   RegisteredVisualContainer::Iterator iter;
756   if(FindVisual(index, mVisuals, iter))
757   {
758     return (*iter)->enabled;
759   }
760   return false;
761 }
762
763 void Control::Impl::StopObservingVisual(Toolkit::Visual::Base& visual)
764 {
765   Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
766
767   // Stop observing the visual
768   visualImpl.RemoveEventObserver(*this);
769 }
770
771 void Control::Impl::StartObservingVisual(Toolkit::Visual::Base& visual)
772 {
773   Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
774
775   // start observing the visual for events
776   visualImpl.AddEventObserver(*this);
777 }
778
779 // Called by a Visual when it's resource is ready
780 void Control::Impl::ResourceReady(Visual::Base& object)
781 {
782   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::Impl::ResourceReady() replacements pending[%d]\n", mRemoveVisuals.Count());
783
784   Actor self = mControlImpl.Self();
785
786   // A resource is ready, find resource in the registered visuals container and get its index
787   for(auto registeredIter = mVisuals.Begin(), end = mVisuals.End(); registeredIter != end; ++registeredIter)
788   {
789     Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation((*registeredIter)->visual);
790
791     if(&object == &registeredVisualImpl)
792     {
793       RegisteredVisualContainer::Iterator visualToRemoveIter;
794       // Find visual with the same index in the removal container
795       // Set if off stage as it's replacement is now ready.
796       // Remove if from removal list as now removed from stage.
797       // Set Pending flag on the ready visual to false as now ready.
798       if(FindVisual((*registeredIter)->index, mRemoveVisuals, visualToRemoveIter))
799       {
800         (*registeredIter)->pending = false;
801         Toolkit::GetImplementation((*visualToRemoveIter)->visual).SetOffScene(self);
802         mRemoveVisuals.Erase(visualToRemoveIter);
803       }
804       break;
805     }
806   }
807
808   // A visual is ready so control may need relayouting if staged
809   if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
810   {
811     mControlImpl.RelayoutRequest();
812   }
813
814   // Emit signal if all enabled visuals registered by the control are ready.
815   if(IsResourceReady())
816   {
817     // Reset the flag
818     mNeedToEmitResourceReady = false;
819
820     EmitResourceReadySignal();
821   }
822 }
823
824 void Control::Impl::NotifyVisualEvent(Visual::Base& object, Property::Index signalId)
825 {
826   for(auto registeredIter = mVisuals.Begin(), end = mVisuals.End(); registeredIter != end; ++registeredIter)
827   {
828     Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation((*registeredIter)->visual);
829     if(&object == &registeredVisualImpl)
830     {
831       Dali::Toolkit::Control handle(mControlImpl.GetOwner());
832       mVisualEventSignal.Emit(handle, (*registeredIter)->index, signalId);
833       break;
834     }
835   }
836 }
837
838 bool Control::Impl::IsResourceReady() const
839 {
840   // Iterate through and check all the enabled visuals are ready
841   for(auto visualIter = mVisuals.Begin();
842       visualIter != mVisuals.End();
843       ++visualIter)
844   {
845     const Toolkit::Visual::Base   visual     = (*visualIter)->visual;
846     const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
847
848     // one of the enabled visuals is not ready
849     if(!visualImpl.IsResourceReady() && (*visualIter)->enabled)
850     {
851       return false;
852     }
853   }
854   return true;
855 }
856
857 Toolkit::Visual::ResourceStatus Control::Impl::GetVisualResourceStatus(Property::Index index) const
858 {
859   RegisteredVisualContainer::Iterator iter;
860   if(FindVisual(index, mVisuals, iter))
861   {
862     const Toolkit::Visual::Base   visual     = (*iter)->visual;
863     const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
864     return visualImpl.GetResourceStatus();
865   }
866
867   return Toolkit::Visual::ResourceStatus::PREPARING;
868 }
869
870 void Control::Impl::AddTransitions(Dali::Animation&               animation,
871                                    const Toolkit::TransitionData& handle,
872                                    bool                           createAnimation)
873 {
874   // Setup a Transition from TransitionData.
875   const Internal::TransitionData& transitionData = Toolkit::GetImplementation(handle);
876   TransitionData::Iterator        end            = transitionData.End();
877   for(TransitionData::Iterator iter = transitionData.Begin();
878       iter != end;
879       ++iter)
880   {
881     TransitionData::Animator* animator = (*iter);
882
883     Toolkit::Visual::Base visual = GetVisualByName(mVisuals, animator->objectName);
884
885     if(visual)
886     {
887 #if defined(DEBUG_ENABLED)
888       Dali::TypeInfo  typeInfo;
889       ControlWrapper* controlWrapperImpl = dynamic_cast<ControlWrapper*>(&mControlImpl);
890       if(controlWrapperImpl)
891       {
892         typeInfo = controlWrapperImpl->GetTypeInfo();
893       }
894
895       DALI_LOG_INFO(gLogFilter, Debug::Concise, "CreateTransition: Found %s visual for %s\n", visual.GetName().c_str(), typeInfo ? typeInfo.GetName().c_str() : "Unknown");
896 #endif
897       Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
898       visualImpl.AnimateProperty(animation, *animator);
899     }
900     else
901     {
902       DALI_LOG_INFO(gLogFilter, Debug::Concise, "CreateTransition: Could not find visual. Trying actors");
903       // Otherwise, try any actor children of control (Including the control)
904       Actor child = mControlImpl.Self().FindChildByName(animator->objectName);
905       if(child)
906       {
907         Property::Index propertyIndex = child.GetPropertyIndex(animator->propertyKey);
908         if(propertyIndex != Property::INVALID_INDEX)
909         {
910           if(animator->animate == false)
911           {
912             if(animator->targetValue.GetType() != Property::NONE)
913             {
914               child.SetProperty(propertyIndex, animator->targetValue);
915             }
916           }
917           else // animate the property
918           {
919             if(animator->initialValue.GetType() != Property::NONE)
920             {
921               child.SetProperty(propertyIndex, animator->initialValue);
922             }
923
924             if(createAnimation && !animation)
925             {
926               animation = Dali::Animation::New(0.1f);
927             }
928
929             animation.AnimateTo(Property(child, propertyIndex),
930                                 animator->targetValue,
931                                 animator->alphaFunction,
932                                 TimePeriod(animator->timePeriodDelay,
933                                            animator->timePeriodDuration));
934           }
935         }
936       }
937     }
938   }
939 }
940
941 Dali::Animation Control::Impl::CreateTransition(const Toolkit::TransitionData& transitionData)
942 {
943   Dali::Animation transition;
944
945   if(transitionData.Count() > 0)
946   {
947     AddTransitions(transition, transitionData, true);
948   }
949   return transition;
950 }
951
952 void Control::Impl::DoAction(Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes)
953 {
954   RegisteredVisualContainer::Iterator iter;
955   if(FindVisual(visualIndex, mVisuals, iter))
956   {
957     Toolkit::GetImplementation((*iter)->visual).DoAction(actionId, attributes);
958   }
959 }
960
961 void Control::Impl::AppendAccessibilityAttribute(const std::string& key,
962                                                  const std::string  value)
963 {
964   Property::Value* val = mAccessibilityAttributes.Find(key);
965   if(val)
966   {
967     mAccessibilityAttributes[key] = Property::Value(value);
968   }
969   else
970   {
971     mAccessibilityAttributes.Insert(key, value);
972   }
973 }
974
975 void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
976 {
977   Toolkit::Control control = Toolkit::Control::DownCast(BaseHandle(object));
978
979   if(control)
980   {
981     Control& controlImpl(GetImplementation(control));
982
983     switch(index)
984     {
985       case Toolkit::Control::Property::STYLE_NAME:
986       {
987         controlImpl.SetStyleName(value.Get<std::string>());
988         break;
989       }
990
991       case Toolkit::DevelControl::Property::STATE:
992       {
993         bool                   withTransitions = true;
994         const Property::Value* valuePtr        = &value;
995         const Property::Map*   map             = value.GetMap();
996         if(map)
997         {
998           Property::Value* value2 = map->Find("withTransitions");
999           if(value2)
1000           {
1001             withTransitions = value2->Get<bool>();
1002           }
1003
1004           valuePtr = map->Find("state");
1005         }
1006
1007         if(valuePtr)
1008         {
1009           Toolkit::DevelControl::State state(controlImpl.mImpl->mState);
1010           if(Scripting::GetEnumerationProperty<Toolkit::DevelControl::State>(*valuePtr, ControlStateTable, ControlStateTableCount, state))
1011           {
1012             controlImpl.mImpl->SetState(state, withTransitions);
1013           }
1014         }
1015       }
1016       break;
1017
1018       case Toolkit::DevelControl::Property::SUB_STATE:
1019       {
1020         std::string subState;
1021         if(value.Get(subState))
1022         {
1023           controlImpl.mImpl->SetSubState(subState);
1024         }
1025       }
1026       break;
1027
1028       case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
1029       {
1030         int focusId;
1031         if(value.Get(focusId))
1032         {
1033           controlImpl.mImpl->mLeftFocusableActorId = focusId;
1034         }
1035       }
1036       break;
1037
1038       case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
1039       {
1040         int focusId;
1041         if(value.Get(focusId))
1042         {
1043           controlImpl.mImpl->mRightFocusableActorId = focusId;
1044         }
1045       }
1046       break;
1047
1048       case Toolkit::DevelControl::Property::ACCESSIBILITY_NAME:
1049       {
1050         std::string name;
1051         if(value.Get(name))
1052         {
1053           controlImpl.mImpl->mAccessibilityName    = name;
1054           controlImpl.mImpl->mAccessibilityNameSet = true;
1055         }
1056         else
1057         {
1058           controlImpl.mImpl->mAccessibilityNameSet = false;
1059         }
1060       }
1061       break;
1062
1063       case Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION:
1064       {
1065         std::string txt;
1066         if(value.Get(txt))
1067         {
1068           controlImpl.mImpl->mAccessibilityDescription    = txt;
1069           controlImpl.mImpl->mAccessibilityDescriptionSet = true;
1070         }
1071         else
1072         {
1073           controlImpl.mImpl->mAccessibilityDescriptionSet = false;
1074         }
1075       }
1076       break;
1077
1078       case Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN:
1079       {
1080         std::string txt;
1081         if(value.Get(txt))
1082         {
1083           controlImpl.mImpl->mAccessibilityTranslationDomain    = txt;
1084           controlImpl.mImpl->mAccessibilityTranslationDomainSet = true;
1085         }
1086         else
1087         {
1088           controlImpl.mImpl->mAccessibilityTranslationDomainSet = false;
1089         }
1090       }
1091       break;
1092
1093       case Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE:
1094       {
1095         bool highlightable;
1096         if(value.Get(highlightable))
1097         {
1098           controlImpl.mImpl->mAccessibilityHighlightable    = highlightable;
1099           controlImpl.mImpl->mAccessibilityHighlightableSet = true;
1100         }
1101         else
1102         {
1103           controlImpl.mImpl->mAccessibilityHighlightableSet = false;
1104         }
1105       }
1106       break;
1107
1108       case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE:
1109       {
1110         Dali::Accessibility::Role val;
1111         if(value.Get(val))
1112         {
1113           controlImpl.mImpl->mAccessibilityRole = val;
1114         }
1115       }
1116       break;
1117
1118       case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
1119       {
1120         int focusId;
1121         if(value.Get(focusId))
1122         {
1123           controlImpl.mImpl->mUpFocusableActorId = focusId;
1124         }
1125       }
1126       break;
1127
1128       case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
1129       {
1130         int focusId;
1131         if(value.Get(focusId))
1132         {
1133           controlImpl.mImpl->mDownFocusableActorId = focusId;
1134         }
1135       }
1136       break;
1137
1138       case Toolkit::Control::Property::KEY_INPUT_FOCUS:
1139       {
1140         if(value.Get<bool>())
1141         {
1142           controlImpl.SetKeyInputFocus();
1143         }
1144         else
1145         {
1146           controlImpl.ClearKeyInputFocus();
1147         }
1148         break;
1149       }
1150
1151       case Toolkit::Control::Property::BACKGROUND:
1152       {
1153         std::string          url;
1154         Vector4              color;
1155         const Property::Map* map = value.GetMap();
1156         if(map && !map->Empty())
1157         {
1158           controlImpl.SetBackground(*map);
1159         }
1160         else if(value.Get(url))
1161         {
1162           // don't know the size to load
1163           Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual(url, ImageDimensions());
1164           if(visual)
1165           {
1166             controlImpl.mImpl->RegisterVisual(Toolkit::Control::Property::BACKGROUND, visual, DepthIndex::BACKGROUND);
1167           }
1168         }
1169         else if(value.Get(color))
1170         {
1171           controlImpl.SetBackgroundColor(color);
1172         }
1173         else
1174         {
1175           // The background is an empty property map, so we should clear the background
1176           controlImpl.ClearBackground();
1177         }
1178         break;
1179       }
1180
1181       case Toolkit::Control::Property::MARGIN:
1182       {
1183         Extents margin;
1184         if(value.Get(margin))
1185         {
1186           controlImpl.mImpl->SetMargin(margin);
1187         }
1188         break;
1189       }
1190
1191       case Toolkit::Control::Property::PADDING:
1192       {
1193         Extents padding;
1194         if(value.Get(padding))
1195         {
1196           controlImpl.mImpl->SetPadding(padding);
1197         }
1198         break;
1199       }
1200
1201       case Toolkit::DevelControl::Property::TOOLTIP:
1202       {
1203         TooltipPtr& tooltipPtr = controlImpl.mImpl->mTooltip;
1204         if(!tooltipPtr)
1205         {
1206           tooltipPtr = Tooltip::New(control);
1207         }
1208         tooltipPtr->SetProperties(value);
1209         break;
1210       }
1211
1212       case Toolkit::DevelControl::Property::SHADOW:
1213       {
1214         const Property::Map* map = value.GetMap();
1215         if(map && !map->Empty())
1216         {
1217           controlImpl.mImpl->SetShadow(*map);
1218         }
1219         else
1220         {
1221           // The shadow is an empty property map, so we should clear the shadow
1222           controlImpl.mImpl->ClearShadow();
1223         }
1224         break;
1225       }
1226
1227       case Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES:
1228       {
1229         const Property::Map* map = value.GetMap();
1230         if(map && !map->Empty())
1231         {
1232           controlImpl.mImpl->mAccessibilityAttributes = *map;
1233         }
1234         break;
1235       }
1236     }
1237   }
1238 }
1239
1240 Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index index)
1241 {
1242   Property::Value value;
1243
1244   Toolkit::Control control = Toolkit::Control::DownCast(BaseHandle(object));
1245
1246   if(control)
1247   {
1248     Control& controlImpl(GetImplementation(control));
1249
1250     switch(index)
1251     {
1252       case Toolkit::Control::Property::STYLE_NAME:
1253       {
1254         value = controlImpl.GetStyleName();
1255         break;
1256       }
1257
1258       case Toolkit::DevelControl::Property::STATE:
1259       {
1260         value = controlImpl.mImpl->mState;
1261         break;
1262       }
1263
1264       case Toolkit::DevelControl::Property::SUB_STATE:
1265       {
1266         value = controlImpl.mImpl->mSubStateName;
1267         break;
1268       }
1269
1270       case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
1271       {
1272         value = controlImpl.mImpl->mLeftFocusableActorId;
1273         break;
1274       }
1275
1276       case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
1277       {
1278         value = controlImpl.mImpl->mRightFocusableActorId;
1279         break;
1280       }
1281
1282       case Toolkit::DevelControl::Property::ACCESSIBILITY_NAME:
1283       {
1284         if(controlImpl.mImpl->mAccessibilityNameSet)
1285         {
1286           value = controlImpl.mImpl->mAccessibilityName;
1287         }
1288         break;
1289       }
1290
1291       case Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION:
1292       {
1293         if(controlImpl.mImpl->mAccessibilityDescriptionSet)
1294         {
1295           value = controlImpl.mImpl->mAccessibilityDescription;
1296         }
1297         break;
1298       }
1299
1300       case Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN:
1301       {
1302         if(controlImpl.mImpl->mAccessibilityTranslationDomainSet)
1303         {
1304           value = controlImpl.mImpl->mAccessibilityTranslationDomain;
1305         }
1306         break;
1307       }
1308
1309       case Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE:
1310       {
1311         if(controlImpl.mImpl->mAccessibilityHighlightableSet)
1312         {
1313           value = controlImpl.mImpl->mAccessibilityHighlightable;
1314         }
1315         break;
1316       }
1317
1318       case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE:
1319       {
1320         value = Property::Value(controlImpl.mImpl->mAccessibilityRole);
1321         break;
1322       }
1323
1324       case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
1325       {
1326         value = controlImpl.mImpl->mUpFocusableActorId;
1327         break;
1328       }
1329
1330       case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
1331       {
1332         value = controlImpl.mImpl->mDownFocusableActorId;
1333         break;
1334       }
1335
1336       case Toolkit::Control::Property::KEY_INPUT_FOCUS:
1337       {
1338         value = controlImpl.HasKeyInputFocus();
1339         break;
1340       }
1341
1342       case Toolkit::Control::Property::BACKGROUND:
1343       {
1344         Property::Map         map;
1345         Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual(Toolkit::Control::Property::BACKGROUND);
1346         if(visual)
1347         {
1348           visual.CreatePropertyMap(map);
1349         }
1350
1351         value = map;
1352         break;
1353       }
1354
1355       case Toolkit::Control::Property::MARGIN:
1356       {
1357         value = controlImpl.mImpl->GetMargin();
1358         break;
1359       }
1360
1361       case Toolkit::Control::Property::PADDING:
1362       {
1363         value = controlImpl.mImpl->GetPadding();
1364         break;
1365       }
1366
1367       case Toolkit::DevelControl::Property::TOOLTIP:
1368       {
1369         Property::Map map;
1370         if(controlImpl.mImpl->mTooltip)
1371         {
1372           controlImpl.mImpl->mTooltip->CreatePropertyMap(map);
1373         }
1374         value = map;
1375         break;
1376       }
1377
1378       case Toolkit::DevelControl::Property::SHADOW:
1379       {
1380         Property::Map         map;
1381         Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual(Toolkit::DevelControl::Property::SHADOW);
1382         if(visual)
1383         {
1384           visual.CreatePropertyMap(map);
1385         }
1386
1387         value = map;
1388         break;
1389       }
1390
1391       case Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES:
1392       {
1393         value = controlImpl.mImpl->mAccessibilityAttributes;
1394         break;
1395       }
1396     }
1397   }
1398
1399   return value;
1400 }
1401
1402 void Control::Impl::RemoveAccessibilityAttribute(const std::string& key)
1403 {
1404   Property::Value* val = mAccessibilityAttributes.Find(key);
1405   if(val)
1406     mAccessibilityAttributes[key] = Property::Value();
1407 }
1408
1409 void Control::Impl::ClearAccessibilityAttributes()
1410 {
1411   mAccessibilityAttributes.Clear();
1412 }
1413
1414 void Control::Impl::SetAccessibilityReadingInfoType(const Dali::Accessibility::ReadingInfoTypes types)
1415 {
1416   std::string value;
1417   if(types[Dali::Accessibility::ReadingInfoType::NAME])
1418   {
1419     value += READING_INFO_TYPE_NAME;
1420   }
1421   if(types[Dali::Accessibility::ReadingInfoType::ROLE])
1422   {
1423     if(!value.empty())
1424     {
1425       value += READING_INFO_TYPE_SEPARATOR;
1426     }
1427     value += READING_INFO_TYPE_ROLE;
1428   }
1429   if(types[Dali::Accessibility::ReadingInfoType::DESCRIPTION])
1430   {
1431     if(!value.empty())
1432     {
1433       value += READING_INFO_TYPE_SEPARATOR;
1434     }
1435     value += READING_INFO_TYPE_DESCRIPTION;
1436   }
1437   if(types[Dali::Accessibility::ReadingInfoType::STATE])
1438   {
1439     if(!value.empty())
1440     {
1441       value += READING_INFO_TYPE_SEPARATOR;
1442     }
1443     value += READING_INFO_TYPE_STATE;
1444   }
1445   AppendAccessibilityAttribute(READING_INFO_TYPE_ATTRIBUTE_NAME, value);
1446 }
1447
1448 Dali::Accessibility::ReadingInfoTypes Control::Impl::GetAccessibilityReadingInfoType() const
1449 {
1450   std::string value;
1451   auto        place = mAccessibilityAttributes.Find(READING_INFO_TYPE_ATTRIBUTE_NAME);
1452   if(place)
1453   {
1454     place->Get(value);
1455   }
1456   else
1457   {
1458     Dali::Accessibility::ReadingInfoTypes types;
1459     types[Dali::Accessibility::ReadingInfoType::NAME] = true;
1460     types[Dali::Accessibility::ReadingInfoType::ROLE] = true;
1461     types[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
1462     types[Dali::Accessibility::ReadingInfoType::STATE] = true;
1463     return types;
1464   }
1465
1466   if(value.empty())
1467   {
1468     return {};
1469   }
1470
1471   Dali::Accessibility::ReadingInfoTypes types;
1472
1473   if(value.find(READING_INFO_TYPE_NAME) != std::string::npos)
1474   {
1475     types[Dali::Accessibility::ReadingInfoType::NAME] = true;
1476   }
1477   if(value.find(READING_INFO_TYPE_ROLE) != std::string::npos)
1478   {
1479     types[Dali::Accessibility::ReadingInfoType::ROLE] = true;
1480   }
1481   if(value.find(READING_INFO_TYPE_DESCRIPTION) != std::string::npos)
1482   {
1483     types[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
1484   }
1485   if(value.find(READING_INFO_TYPE_STATE) != std::string::npos)
1486   {
1487     types[Dali::Accessibility::ReadingInfoType::STATE] = true;
1488   }
1489
1490   return types;
1491 }
1492
1493 void Control::Impl::CopyInstancedProperties(RegisteredVisualContainer& visuals, Dictionary<Property::Map>& instancedProperties)
1494 {
1495   for(RegisteredVisualContainer::Iterator iter = visuals.Begin(); iter != visuals.End(); iter++)
1496   {
1497     if((*iter)->visual)
1498     {
1499       Property::Map instanceMap;
1500       Toolkit::GetImplementation((*iter)->visual).CreateInstancePropertyMap(instanceMap);
1501       instancedProperties.Add((*iter)->visual.GetName(), instanceMap);
1502     }
1503   }
1504 }
1505
1506 void Control::Impl::RemoveVisual(RegisteredVisualContainer& visuals, const std::string& visualName)
1507 {
1508   Actor self(mControlImpl.Self());
1509
1510   for(RegisteredVisualContainer::Iterator visualIter = visuals.Begin();
1511       visualIter != visuals.End();
1512       ++visualIter)
1513   {
1514     Toolkit::Visual::Base visual = (*visualIter)->visual;
1515     if(visual && visual.GetName() == visualName)
1516     {
1517       Toolkit::GetImplementation(visual).SetOffScene(self);
1518       (*visualIter)->visual.Reset();
1519       visuals.Erase(visualIter);
1520       break;
1521     }
1522   }
1523 }
1524
1525 void Control::Impl::RemoveVisuals(RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals)
1526 {
1527   Actor self(mControlImpl.Self());
1528   for(DictionaryKeys::iterator iter = removeVisuals.begin(); iter != removeVisuals.end(); ++iter)
1529   {
1530     const std::string visualName = *iter;
1531     RemoveVisual(visuals, visualName);
1532   }
1533 }
1534
1535 void Control::Impl::RecreateChangedVisuals(Dictionary<Property::Map>& stateVisualsToChange,
1536                                            Dictionary<Property::Map>& instancedProperties)
1537 {
1538   Dali::CustomActor handle(mControlImpl.GetOwner());
1539   for(Dictionary<Property::Map>::iterator iter = stateVisualsToChange.Begin();
1540       iter != stateVisualsToChange.End();
1541       ++iter)
1542   {
1543     const std::string&   visualName = (*iter).key;
1544     const Property::Map& toMap      = (*iter).entry;
1545
1546     Actor                               self = mControlImpl.Self();
1547     RegisteredVisualContainer::Iterator registeredVisualsiter;
1548     // Check if visual (visualName) is already registered, this is the current visual.
1549     if(FindVisual(visualName, mVisuals, registeredVisualsiter))
1550     {
1551       Toolkit::Visual::Base& visual = (*registeredVisualsiter)->visual;
1552       if(visual)
1553       {
1554         // No longer required to know if the replaced visual's resources are ready
1555         StopObservingVisual(visual);
1556
1557         // If control staged then visuals will be swapped once ready
1558         if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
1559         {
1560           // Check if visual is currently in the process of being replaced ( is in removal container )
1561           RegisteredVisualContainer::Iterator visualQueuedForRemoval;
1562           if(FindVisual(visualName, mRemoveVisuals, visualQueuedForRemoval))
1563           {
1564             // Visual with same visual name is already in removal container so current visual pending
1565             // Only the the last requested visual will be displayed so remove current visual which is staged but not ready.
1566             Toolkit::GetImplementation(visual).SetOffScene(self);
1567             (*registeredVisualsiter)->visual.Reset();
1568             mVisuals.Erase(registeredVisualsiter);
1569           }
1570           else
1571           {
1572             // current visual not already in removal container so add now.
1573             DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %s \n", visualName.c_str());
1574             MoveVisual(registeredVisualsiter, mVisuals, mRemoveVisuals);
1575           }
1576         }
1577         else
1578         {
1579           // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later.
1580           (*registeredVisualsiter)->visual.Reset();
1581           mVisuals.Erase(registeredVisualsiter);
1582         }
1583       }
1584
1585       const Property::Map* instancedMap = instancedProperties.FindConst(visualName);
1586       Style::ApplyVisual(handle, visualName, toMap, instancedMap);
1587     }
1588   }
1589 }
1590
1591 void Control::Impl::ReplaceStateVisualsAndProperties(const StylePtr oldState, const StylePtr newState, const std::string& subState)
1592 {
1593   // Collect all old visual names
1594   DictionaryKeys stateVisualsToRemove;
1595   if(oldState)
1596   {
1597     oldState->visuals.GetKeys(stateVisualsToRemove);
1598     if(!subState.empty())
1599     {
1600       const StylePtr* oldSubState = oldState->subStates.FindConst(subState);
1601       if(oldSubState)
1602       {
1603         DictionaryKeys subStateVisualsToRemove;
1604         (*oldSubState)->visuals.GetKeys(subStateVisualsToRemove);
1605         Merge(stateVisualsToRemove, subStateVisualsToRemove);
1606       }
1607     }
1608   }
1609
1610   // Collect all new visual properties
1611   Dictionary<Property::Map> stateVisualsToAdd;
1612   if(newState)
1613   {
1614     stateVisualsToAdd = newState->visuals;
1615     if(!subState.empty())
1616     {
1617       const StylePtr* newSubState = newState->subStates.FindConst(subState);
1618       if(newSubState)
1619       {
1620         stateVisualsToAdd.Merge((*newSubState)->visuals);
1621       }
1622     }
1623   }
1624
1625   // If a name is in both add/remove, move it to change list.
1626   Dictionary<Property::Map> stateVisualsToChange;
1627   FindChangableVisuals(stateVisualsToAdd, stateVisualsToChange, stateVisualsToRemove);
1628
1629   // Copy instanced properties (e.g. text label) of current visuals
1630   Dictionary<Property::Map> instancedProperties;
1631   CopyInstancedProperties(mVisuals, instancedProperties);
1632
1633   // For each visual in remove list, remove from mVisuals
1634   RemoveVisuals(mVisuals, stateVisualsToRemove);
1635
1636   // For each visual in add list, create and add to mVisuals
1637   Dali::CustomActor handle(mControlImpl.GetOwner());
1638   Style::ApplyVisuals(handle, stateVisualsToAdd, instancedProperties);
1639
1640   // For each visual in change list, if it requires a new visual,
1641   // remove old visual, create and add to mVisuals
1642   RecreateChangedVisuals(stateVisualsToChange, instancedProperties);
1643 }
1644
1645 void Control::Impl::SetState(DevelControl::State newState, bool withTransitions)
1646 {
1647   DevelControl::State oldState = mState;
1648   Dali::CustomActor   handle(mControlImpl.GetOwner());
1649   DALI_LOG_INFO(gLogFilter, Debug::Concise, "Control::Impl::SetState: %s\n", (mState == DevelControl::NORMAL ? "NORMAL" : (mState == DevelControl::FOCUSED ? "FOCUSED" : (mState == DevelControl::DISABLED ? "DISABLED" : "NONE"))));
1650
1651   if(mState != newState)
1652   {
1653     // If mState was Disabled, and new state is Focused, should probably
1654     // store that fact, e.g. in another property that FocusManager can access.
1655     mState = newState;
1656
1657     // Trigger state change and transitions
1658     // Apply new style, if stylemanager is available
1659     Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
1660     if(styleManager)
1661     {
1662       const StylePtr stylePtr = GetImpl(styleManager).GetRecordedStyle(Toolkit::Control(mControlImpl.GetOwner()));
1663
1664       if(stylePtr)
1665       {
1666         std::string oldStateName = Scripting::GetEnumerationName<Toolkit::DevelControl::State>(oldState, ControlStateTable, ControlStateTableCount);
1667         std::string newStateName = Scripting::GetEnumerationName<Toolkit::DevelControl::State>(newState, ControlStateTable, ControlStateTableCount);
1668
1669         const StylePtr* newStateStyle = stylePtr->subStates.Find(newStateName);
1670         const StylePtr* oldStateStyle = stylePtr->subStates.Find(oldStateName);
1671         if(oldStateStyle && newStateStyle)
1672         {
1673           // Only change if both state styles exist
1674           ReplaceStateVisualsAndProperties(*oldStateStyle, *newStateStyle, mSubStateName);
1675         }
1676       }
1677     }
1678   }
1679 }
1680
1681 void Control::Impl::SetSubState(const std::string& subStateName, bool withTransitions)
1682 {
1683   if(mSubStateName != subStateName)
1684   {
1685     // Get existing sub-state visuals, and unregister them
1686     Dali::CustomActor handle(mControlImpl.GetOwner());
1687
1688     Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
1689     if(styleManager)
1690     {
1691       const StylePtr stylePtr = GetImpl(styleManager).GetRecordedStyle(Toolkit::Control(mControlImpl.GetOwner()));
1692       if(stylePtr)
1693       {
1694         // Stringify state
1695         std::string stateName = Scripting::GetEnumerationName<Toolkit::DevelControl::State>(mState, ControlStateTable, ControlStateTableCount);
1696
1697         const StylePtr* state = stylePtr->subStates.Find(stateName);
1698         if(state)
1699         {
1700           StylePtr stateStyle(*state);
1701
1702           const StylePtr* newStateStyle = stateStyle->subStates.Find(subStateName);
1703           const StylePtr* oldStateStyle = stateStyle->subStates.Find(mSubStateName);
1704           if(oldStateStyle && newStateStyle)
1705           {
1706             std::string empty;
1707             ReplaceStateVisualsAndProperties(*oldStateStyle, *newStateStyle, empty);
1708           }
1709         }
1710       }
1711     }
1712
1713     mSubStateName = subStateName;
1714   }
1715 }
1716
1717 void Control::Impl::OnSceneDisconnection()
1718 {
1719   Actor self = mControlImpl.Self();
1720
1721   // Any visuals set for replacement but not yet ready should still be registered.
1722   // Reason: If a request was made to register a new visual but the control removed from scene before visual was ready
1723   // then when this control appears back on stage it should use that new visual.
1724
1725   // Iterate through all registered visuals and set off scene
1726   SetVisualsOffScene(mVisuals, self);
1727
1728   // Visuals pending replacement can now be taken out of the removal list and set off scene
1729   // Iterate through all replacement visuals and add to a move queue then set off scene
1730   for(auto removalIter = mRemoveVisuals.Begin(), end = mRemoveVisuals.End(); removalIter != end; removalIter++)
1731   {
1732     Toolkit::GetImplementation((*removalIter)->visual).SetOffScene(self);
1733   }
1734
1735   for(auto replacedIter = mVisuals.Begin(), end = mVisuals.End(); replacedIter != end; replacedIter++)
1736   {
1737     (*replacedIter)->pending = false;
1738   }
1739
1740   mRemoveVisuals.Clear();
1741 }
1742
1743 void Control::Impl::SetMargin(Extents margin)
1744 {
1745   mControlImpl.mImpl->mMargin = margin;
1746
1747   // Trigger a size negotiation request that may be needed when setting a margin.
1748   mControlImpl.RelayoutRequest();
1749 }
1750
1751 Extents Control::Impl::GetMargin() const
1752 {
1753   return mControlImpl.mImpl->mMargin;
1754 }
1755
1756 void Control::Impl::SetPadding(Extents padding)
1757 {
1758   mControlImpl.mImpl->mPadding = padding;
1759
1760   // Trigger a size negotiation request that may be needed when setting a padding.
1761   mControlImpl.RelayoutRequest();
1762 }
1763
1764 Extents Control::Impl::GetPadding() const
1765 {
1766   return mControlImpl.mImpl->mPadding;
1767 }
1768
1769 void Control::Impl::SetInputMethodContext(InputMethodContext& inputMethodContext)
1770 {
1771   mInputMethodContext = inputMethodContext;
1772 }
1773
1774 bool Control::Impl::FilterKeyEvent(const KeyEvent& event)
1775 {
1776   bool consumed(false);
1777
1778   if(mInputMethodContext)
1779   {
1780     consumed = mInputMethodContext.FilterEventKey(event);
1781   }
1782   return consumed;
1783 }
1784
1785 DevelControl::VisualEventSignalType& Control::Impl::VisualEventSignal()
1786 {
1787   return mVisualEventSignal;
1788 }
1789
1790 void Control::Impl::SetShadow(const Property::Map& map)
1791 {
1792   Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual(map);
1793   visual.SetName("shadow");
1794
1795   if(visual)
1796   {
1797     mControlImpl.mImpl->RegisterVisual(Toolkit::DevelControl::Property::SHADOW, visual, DepthIndex::BACKGROUND_EFFECT);
1798
1799     mControlImpl.RelayoutRequest();
1800   }
1801 }
1802
1803 void Control::Impl::ClearShadow()
1804 {
1805   mControlImpl.mImpl->UnregisterVisual(Toolkit::DevelControl::Property::SHADOW);
1806
1807   // Trigger a size negotiation request that may be needed when unregistering a visual.
1808   mControlImpl.RelayoutRequest();
1809 }
1810
1811 Dali::Property Control::Impl::GetVisualProperty(Dali::Property::Index index, Dali::Property::Key visualPropertyKey)
1812 {
1813   Toolkit::Visual::Base visual = GetVisualByIndex(mVisuals, index);
1814   if(visual)
1815   {
1816     Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
1817     return visualImpl.GetPropertyObject(visualPropertyKey);
1818   }
1819
1820   Handle handle;
1821   return Dali::Property(handle, Property::INVALID_INDEX);
1822 }
1823
1824 void Control::Impl::MakeVisualTransition(Dali::Animation& animation, Dali::Toolkit::Control source, Dali::Property::Index visualIndex, AlphaFunction alphaFunction, TimePeriod timePeriod)
1825 {
1826   Dali::Toolkit::Control sourceHandle      = Dali::Toolkit::Control::DownCast(source);
1827   Property::Map          sourceMap         = sourceHandle.GetProperty<Property::Map>(visualIndex);
1828   Dali::Toolkit::Control destinationHandle = Dali::Toolkit::Control::DownCast(mControlImpl.Self());
1829   Property::Map          destinationMap    = destinationHandle.GetProperty<Property::Map>(visualIndex);
1830
1831   Vector4                  mixColor(1.0f, 1.0f, 1.0f, 1.0f);
1832   Vector4                  cornerRadius(0.0f, 0.0f, 0.0f, 0.0f);
1833
1834   if(!destinationMap.Empty())
1835   {
1836     mixColor     = destinationMap.Find(Dali::Toolkit::Visual::Property::MIX_COLOR)->Get<Vector4>();
1837     cornerRadius = destinationMap.Find(Toolkit::DevelVisual::Property::CORNER_RADIUS)->Get<Vector4>();
1838
1839     if(sourceMap.Empty())
1840     {
1841       sourceMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
1842       sourceMap.Insert(Dali::Toolkit::Visual::Property::MIX_COLOR, Color::TRANSPARENT);
1843       sourceMap.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, cornerRadius);
1844     }
1845
1846     Vector4 sourceMixColor     = sourceMap.Find(Dali::Toolkit::Visual::Property::MIX_COLOR)->Get<Vector4>();
1847     Vector4 sourceCornerRadius = sourceMap.Find(Toolkit::DevelVisual::Property::CORNER_RADIUS)->Get<Vector4>();
1848
1849     std::vector<Dali::Property> properties;
1850     std::vector<std::pair<Property::Value, Property::Value>> values;
1851
1852     if(Vector3(sourceMixColor) != Vector3(mixColor))
1853     {
1854       properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::Visual::Property::MIX_COLOR));
1855       values.push_back(std::make_pair(Vector3(sourceMixColor), Vector3(mixColor)));
1856     }
1857
1858     if(std::abs(sourceMixColor.a - mixColor.a) > Math::MACHINE_EPSILON_1)
1859     {
1860       properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::Visual::Property::OPACITY));
1861       values.push_back(std::make_pair(sourceMixColor.a, mixColor.a));
1862     }
1863
1864     if(sourceCornerRadius != cornerRadius)
1865     {
1866       properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::CORNER_RADIUS));
1867       values.push_back(std::make_pair(sourceCornerRadius, cornerRadius));
1868     }
1869
1870     for(uint32_t i = 0; i < properties.size(); ++i)
1871     {
1872       if(timePeriod.delaySeconds > 0.0f)
1873       {
1874         Dali::KeyFrames initialKeyframes = Dali::KeyFrames::New();
1875         initialKeyframes.Add(0.0f, values[i].first);
1876         initialKeyframes.Add(1.0f, values[i].first);
1877         animation.AnimateBetween(properties[i], initialKeyframes, TimePeriod(timePeriod.delaySeconds));
1878       }
1879       Dali::KeyFrames keyframes = Dali::KeyFrames::New();
1880       keyframes.Add(0.0f, values[i].first);
1881       keyframes.Add(1.0f, values[i].second);
1882       animation.AnimateBetween(properties[i], keyframes, alphaFunction, timePeriod);
1883     }
1884   }
1885 }
1886
1887 void Control::Impl::EmitResourceReadySignal()
1888 {
1889   if(!mIsEmittingResourceReadySignal)
1890   {
1891     // Guard against calls to emit the signal during the callback
1892     mIsEmittingResourceReadySignal = true;
1893
1894     // If the signal handler changes visual, it may become ready during this call & therefore this method will
1895     // get called again recursively. If so, mNeedToEmitResourceReady is set below, and we act on it after that secondary
1896     // invocation has completed by notifying in an Idle callback to prevent further recursion.
1897     Dali::Toolkit::Control handle(mControlImpl.GetOwner());
1898     mResourceReadySignal.Emit(handle);
1899
1900     if(mNeedToEmitResourceReady)
1901     {
1902       // Add idler to emit the signal again
1903       if(!mIdleCallback)
1904       {
1905         // The callback manager takes the ownership of the callback object.
1906         mIdleCallback = MakeCallback(this, &Control::Impl::OnIdleCallback);
1907         Adaptor::Get().AddIdle(mIdleCallback, false);
1908       }
1909     }
1910
1911     mIsEmittingResourceReadySignal = false;
1912   }
1913   else
1914   {
1915     mNeedToEmitResourceReady = true;
1916   }
1917 }
1918
1919 void Control::Impl::OnIdleCallback()
1920 {
1921   if(mNeedToEmitResourceReady)
1922   {
1923     // Reset the flag
1924     mNeedToEmitResourceReady = false;
1925
1926     // A visual is ready so control may need relayouting if staged
1927     if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
1928     {
1929       mControlImpl.RelayoutRequest();
1930     }
1931
1932     EmitResourceReadySignal();
1933   }
1934
1935   // Set the pointer to null as the callback manager deletes the callback after execute it.
1936   mIdleCallback = nullptr;
1937 }
1938
1939 Dali::Accessibility::Accessible* Control::Impl::GetAccessibilityObject()
1940 {
1941   if(!accessibilityObject)
1942     accessibilityObject = accessibilityConstructor(mControlImpl.Self());
1943   return accessibilityObject.get();
1944 }
1945
1946 Dali::Accessibility::Accessible* Control::Impl::GetAccessibilityObject(Dali::Actor actor)
1947 {
1948   if(actor)
1949   {
1950     auto q = Dali::Toolkit::Control::DownCast(actor);
1951     if(q)
1952     {
1953       auto q2 = static_cast<Internal::Control*>(&q.GetImplementation());
1954       return q2->mImpl->GetAccessibilityObject();
1955     }
1956   }
1957   return nullptr;
1958 }
1959
1960 } // namespace Internal
1961
1962 } // namespace Toolkit
1963
1964 } // namespace Dali