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