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