(A11y) Let we make some way to do not create new Accessible
[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 // Gesture Detection Methods
700 void Control::Impl::PinchDetected(Actor actor, const PinchGesture& pinch)
701 {
702   mControlImpl.OnPinch(pinch);
703 }
704
705 void Control::Impl::PanDetected(Actor actor, const PanGesture& pan)
706 {
707   mControlImpl.OnPan(pan);
708 }
709
710 void Control::Impl::TapDetected(Actor actor, const TapGesture& tap)
711 {
712   mControlImpl.OnTap(tap);
713 }
714
715 void Control::Impl::LongPressDetected(Actor actor, const LongPressGesture& longPress)
716 {
717   mControlImpl.OnLongPress(longPress);
718 }
719
720 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual)
721 {
722   RegisterVisual(index, visual, VisualState::ENABLED, DepthIndexValue::NOT_SET);
723 }
724
725 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, int depthIndex)
726 {
727   RegisterVisual(index, visual, VisualState::ENABLED, DepthIndexValue::SET, depthIndex);
728 }
729
730 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled)
731 {
732   RegisterVisual(index, visual, (enabled ? VisualState::ENABLED : VisualState::DISABLED), DepthIndexValue::NOT_SET);
733 }
734
735 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex)
736 {
737   RegisterVisual(index, visual, (enabled ? VisualState::ENABLED : VisualState::DISABLED), DepthIndexValue::SET, depthIndex);
738 }
739
740 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex)
741 {
742   DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
743
744   DALI_LOG_INFO(gLogFilter, Debug::Concise, "RegisterVisual:%d \n", index);
745
746   bool  visualReplaced(false);
747   Actor self = mControlImpl.Self();
748
749   // Set the depth index, if not set by caller this will be either the current visual depth, max depth of all visuals
750   // or zero.
751   int requiredDepthIndex = visual.GetDepthIndex();
752
753   if(depthIndexValueSet == DepthIndexValue::SET)
754   {
755     requiredDepthIndex = depthIndex;
756   }
757
758   // Visual replacement, existing visual should only be removed from stage when replacement ready.
759   if(!mVisuals.Empty())
760   {
761     RegisteredVisualContainer::Iterator registeredVisualsiter;
762     // Check if visual (index) is already registered, this is the current visual.
763     if(FindVisual(index, mVisuals, registeredVisualsiter))
764     {
765       Toolkit::Visual::Base& currentRegisteredVisual = (*registeredVisualsiter)->visual;
766       if(currentRegisteredVisual)
767       {
768         // Store current visual depth index as may need to set the replacement visual to same depth
769         const int currentDepthIndex = (*registeredVisualsiter)->visual.GetDepthIndex();
770
771         // No longer required to know if the replaced visual's resources are ready
772         StopObservingVisual(currentRegisteredVisual);
773
774         // If control staged and visual enabled then visuals will be swapped once ready
775         if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE) && enabled)
776         {
777           // Check if visual is currently in the process of being replaced ( is in removal container )
778           RegisteredVisualContainer::Iterator visualQueuedForRemoval;
779           if(FindVisual(index, mRemoveVisuals, visualQueuedForRemoval))
780           {
781             // Visual with same index is already in removal container so current visual pending
782             // Only the the last requested visual will be displayed so remove current visual which is staged but not ready.
783             Toolkit::GetImplementation(currentRegisteredVisual).SetOffScene(self);
784             mVisuals.Erase(registeredVisualsiter);
785           }
786           else
787           {
788             // current visual not already in removal container so add now.
789             DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %d \n", index);
790             MoveVisual(registeredVisualsiter, mVisuals, mRemoveVisuals);
791           }
792         }
793         else
794         {
795           // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later.
796           mVisuals.Erase(registeredVisualsiter);
797         }
798
799         // 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
800         if((depthIndexValueSet == DepthIndexValue::NOT_SET) &&
801            (visual.GetDepthIndex() == 0))
802         {
803           requiredDepthIndex = currentDepthIndex;
804         }
805       }
806
807       visualReplaced = true;
808     }
809   }
810
811   // If not set, set the name of the visual to the same name as the control's property.
812   // ( If the control has been type registered )
813   if(visual.GetName().empty())
814   {
815     // returns empty string if index is not found as long as index is not -1
816     std::string visualName = self.GetPropertyName(index);
817     if(!visualName.empty())
818     {
819       DALI_LOG_INFO(gLogFilter, Debug::Concise, "Setting visual name for property %d to %s\n", index, visualName.c_str());
820       visual.SetName(visualName);
821     }
822   }
823
824   if(!visualReplaced) // New registration entry
825   {
826     // 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
827     if((depthIndexValueSet == DepthIndexValue::NOT_SET) &&
828        (mVisuals.Size() > 0) &&
829        (visual.GetDepthIndex() == 0))
830     {
831       int maxDepthIndex = std::numeric_limits<int>::min();
832
833       RegisteredVisualContainer::ConstIterator       iter;
834       const RegisteredVisualContainer::ConstIterator endIter = mVisuals.End();
835       for(iter = mVisuals.Begin(); iter != endIter; iter++)
836       {
837         const int visualDepthIndex = (*iter)->visual.GetDepthIndex();
838         if(visualDepthIndex > maxDepthIndex)
839         {
840           maxDepthIndex = visualDepthIndex;
841         }
842       }
843       ++maxDepthIndex;                                 // Add one to the current maximum depth index so that our added visual appears on top
844       requiredDepthIndex = std::max(0, maxDepthIndex); // Start at zero if maxDepth index belongs to a background
845     }
846   }
847
848   if(visual)
849   {
850     // Set determined depth index
851     visual.SetDepthIndex(requiredDepthIndex);
852
853     // Monitor when the visual resources are ready
854     StartObservingVisual(visual);
855
856     DALI_LOG_INFO(gLogFilter, Debug::Concise, "New Visual registration index[%d] depth[%d]\n", index, requiredDepthIndex);
857     RegisteredVisual* newRegisteredVisual = new RegisteredVisual(index, visual, (enabled == VisualState::ENABLED ? true : false), (visualReplaced && enabled));
858     mVisuals.PushBack(newRegisteredVisual);
859
860     Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
861     // Put on stage if enabled and the control is already on the stage
862     if((enabled == VisualState::ENABLED) && self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
863     {
864       visualImpl.SetOnScene(self);
865     }
866     else if(enabled && visualImpl.IsResourceReady()) // When not being staged, check if visual already 'ResourceReady' before it was Registered. ( Resource may have been loaded already )
867     {
868       ResourceReady(visualImpl);
869     }
870   }
871
872   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::RegisterVisual() Registered %s(%d), enabled:%s\n", visual.GetName().c_str(), index, enabled ? "true" : "false");
873 }
874
875 void Control::Impl::UnregisterVisual(Property::Index index)
876 {
877   DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
878
879   RegisteredVisualContainer::Iterator iter;
880   if(FindVisual(index, mVisuals, iter))
881   {
882     // stop observing visual
883     StopObservingVisual((*iter)->visual);
884
885     Actor self(mControlImpl.Self());
886     Toolkit::GetImplementation((*iter)->visual).SetOffScene(self);
887     (*iter)->visual.Reset();
888     mVisuals.Erase(iter);
889   }
890
891   if(FindVisual(index, mRemoveVisuals, iter))
892   {
893     Actor self(mControlImpl.Self());
894     Toolkit::GetImplementation((*iter)->visual).SetOffScene(self);
895     (*iter)->pending = false;
896
897     // Discard removed visual. It will be destroyed at next Idle time.
898     DiscardVisual(iter, mRemoveVisuals);
899   }
900 }
901
902 Toolkit::Visual::Base Control::Impl::GetVisual(Property::Index index) const
903 {
904   RegisteredVisualContainer::Iterator iter;
905   if(FindVisual(index, mVisuals, iter))
906   {
907     return (*iter)->visual;
908   }
909
910   return Toolkit::Visual::Base();
911 }
912
913 void Control::Impl::EnableVisual(Property::Index index, bool enable)
914 {
915   DALI_LOG_INFO(gLogFilter, Debug::General, "Control::EnableVisual(%d, %s)\n", index, enable ? "T" : "F");
916
917   RegisteredVisualContainer::Iterator iter;
918   if(FindVisual(index, mVisuals, iter))
919   {
920     if((*iter)->enabled == enable)
921     {
922       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Visual %s(%d) already %s\n", (*iter)->visual.GetName().c_str(), index, enable ? "enabled" : "disabled");
923       return;
924     }
925
926     (*iter)->enabled  = enable;
927     Actor parentActor = mControlImpl.Self();
928     if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE)) // If control not on Scene then Visual will be added when SceneConnection is called.
929     {
930       if(enable)
931       {
932         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) on stage \n", (*iter)->visual.GetName().c_str(), index);
933         Toolkit::GetImplementation((*iter)->visual).SetOnScene(parentActor);
934       }
935       else
936       {
937         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) off stage \n", (*iter)->visual.GetName().c_str(), index);
938         Toolkit::GetImplementation((*iter)->visual).SetOffScene(parentActor); // No need to call if control not staged.
939       }
940     }
941   }
942   else
943   {
944     DALI_LOG_WARNING("Control::EnableVisual(%d, %s) FAILED - NO SUCH VISUAL\n", index, enable ? "T" : "F");
945   }
946 }
947
948 bool Control::Impl::IsVisualEnabled(Property::Index index) const
949 {
950   RegisteredVisualContainer::Iterator iter;
951   if(FindVisual(index, mVisuals, iter))
952   {
953     return (*iter)->enabled;
954   }
955   return false;
956 }
957
958 void Control::Impl::EnableReadyTransitionOverriden(Toolkit::Visual::Base& visual, bool enable)
959 {
960   DALI_LOG_INFO(gLogFilter, Debug::General, "Control::EnableReadyTransitionOverriden(%p, %s)\n", visual, enable ? "T" : "F");
961
962   RegisteredVisualContainer::Iterator iter;
963   if(FindVisual(visual, mVisuals, iter))
964   {
965     if((*iter)->overideReadyTransition == enable)
966     {
967       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableReadyTransitionOverriden Visual %s(%p) already %s\n", (*iter)->visual.GetName().c_str(), visual, enable ? "enabled" : "disabled");
968       return;
969     }
970
971     (*iter)->overideReadyTransition = enable;
972   }
973 }
974
975 void Control::Impl::StopObservingVisual(Toolkit::Visual::Base& visual)
976 {
977   Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
978
979   // Stop observing the visual
980   visualImpl.RemoveEventObserver(*this);
981 }
982
983 void Control::Impl::StartObservingVisual(Toolkit::Visual::Base& visual)
984 {
985   Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
986
987   // start observing the visual for events
988   visualImpl.AddEventObserver(*this);
989 }
990
991 void Control::Impl::ResourceReady()
992 {
993   DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
994
995   // Emit signal if all enabled visuals registered by the control are ready or there are no visuals.
996   if(IsResourceReady())
997   {
998     EmitResourceReadySignal();
999   }
1000 }
1001
1002 // Called by a Visual when it's resource is ready
1003 void Control::Impl::ResourceReady(Visual::Base& object)
1004 {
1005   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::Impl::ResourceReady() replacements pending[%d]\n", mRemoveVisuals.Count());
1006
1007   Actor self = mControlImpl.Self();
1008
1009   RegisteredVisualContainer::Iterator registeredIter;
1010
1011   // A resource is ready, find resource in the registered visuals container and get its index
1012   if(!FindVisual(object, mVisuals, registeredIter))
1013   {
1014     return;
1015   }
1016
1017   RegisteredVisualContainer::Iterator visualToRemoveIter;
1018   // Find visual with the same index in the removal container
1019   // Set if off stage as it's replacement is now ready.
1020   // Remove if from removal list as now removed from stage.
1021   // Set Pending flag on the ready visual to false as now ready.
1022   if(FindVisual((*registeredIter)->index, mRemoveVisuals, visualToRemoveIter))
1023   {
1024     (*registeredIter)->pending = false;
1025     if(!((*visualToRemoveIter)->overideReadyTransition))
1026     {
1027       Toolkit::GetImplementation((*visualToRemoveIter)->visual).SetOffScene(self);
1028     }
1029
1030     // Discard removed visual. It will be destroyed at next Idle time.
1031     DiscardVisual(visualToRemoveIter, mRemoveVisuals);
1032   }
1033
1034   // A visual is ready so control may need relayouting if staged
1035   RelayoutRequest(object);
1036
1037   // Called by a Visual when it's resource is ready
1038   if(((*registeredIter)->enabled))
1039   {
1040     ResourceReady();
1041   }
1042 }
1043
1044 void Control::Impl::NotifyVisualEvent(Visual::Base& object, Property::Index signalId)
1045 {
1046   for(auto registeredIter = mVisuals.Begin(), end = mVisuals.End(); registeredIter != end; ++registeredIter)
1047   {
1048     Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation((*registeredIter)->visual);
1049     if(&object == &registeredVisualImpl)
1050     {
1051       Dali::Toolkit::Control handle(mControlImpl.GetOwner());
1052       mVisualEventSignal.Emit(handle, (*registeredIter)->index, signalId);
1053       break;
1054     }
1055   }
1056 }
1057
1058 void Control::Impl::RelayoutRequest(Visual::Base& object)
1059 {
1060   if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
1061   {
1062     mControlImpl.RelayoutRequest();
1063   }
1064 }
1065
1066 bool Control::Impl::IsResourceReady() const
1067 {
1068   // Iterate through and check all the enabled visuals are ready
1069   for(auto visualIter = mVisuals.Begin();
1070       visualIter != mVisuals.End();
1071       ++visualIter)
1072   {
1073     const Toolkit::Visual::Base   visual     = (*visualIter)->visual;
1074     const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
1075
1076     // one of the enabled visuals is not ready
1077     if(!visualImpl.IsResourceReady() && (*visualIter)->enabled)
1078     {
1079       return false;
1080     }
1081   }
1082   return true;
1083 }
1084
1085 Toolkit::Visual::ResourceStatus Control::Impl::GetVisualResourceStatus(Property::Index index) const
1086 {
1087   RegisteredVisualContainer::Iterator iter;
1088   if(FindVisual(index, mVisuals, iter))
1089   {
1090     const Toolkit::Visual::Base   visual     = (*iter)->visual;
1091     const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
1092     return visualImpl.GetResourceStatus();
1093   }
1094
1095   return Toolkit::Visual::ResourceStatus::PREPARING;
1096 }
1097
1098 void Control::Impl::AddTransitions(Dali::Animation&               animation,
1099                                    const Toolkit::TransitionData& handle,
1100                                    bool                           createAnimation)
1101 {
1102   // Setup a Transition from TransitionData.
1103   const Internal::TransitionData& transitionData = Toolkit::GetImplementation(handle);
1104   TransitionData::Iterator        end            = transitionData.End();
1105   for(TransitionData::Iterator iter = transitionData.Begin();
1106       iter != end;
1107       ++iter)
1108   {
1109     TransitionData::Animator* animator = (*iter);
1110
1111     Toolkit::Visual::Base visual = GetVisualByName(mVisuals, animator->objectName);
1112
1113     if(visual)
1114     {
1115 #if defined(DEBUG_ENABLED)
1116       Dali::TypeInfo  typeInfo;
1117       ControlWrapper* controlWrapperImpl = dynamic_cast<ControlWrapper*>(&mControlImpl);
1118       if(controlWrapperImpl)
1119       {
1120         typeInfo = controlWrapperImpl->GetTypeInfo();
1121       }
1122
1123       DALI_LOG_INFO(gLogFilter, Debug::Concise, "CreateTransition: Found %s visual for %s\n", visual.GetName().c_str(), typeInfo ? typeInfo.GetName().c_str() : "Unknown");
1124 #endif
1125       Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
1126       visualImpl.AnimateProperty(animation, *animator);
1127     }
1128     else
1129     {
1130       DALI_LOG_INFO(gLogFilter, Debug::Concise, "CreateTransition: Could not find visual. Trying actors");
1131       // Otherwise, try any actor children of control (Including the control)
1132       Actor child = mControlImpl.Self().FindChildByName(animator->objectName);
1133       if(child)
1134       {
1135         Property::Index propertyIndex = child.GetPropertyIndex(animator->propertyKey);
1136         if(propertyIndex != Property::INVALID_INDEX)
1137         {
1138           if(animator->animate == false)
1139           {
1140             if(animator->targetValue.GetType() != Property::NONE)
1141             {
1142               child.SetProperty(propertyIndex, animator->targetValue);
1143             }
1144           }
1145           else // animate the property
1146           {
1147             if(animator->initialValue.GetType() != Property::NONE)
1148             {
1149               child.SetProperty(propertyIndex, animator->initialValue);
1150             }
1151
1152             if(createAnimation && !animation)
1153             {
1154               animation = Dali::Animation::New(0.1f);
1155             }
1156
1157             animation.AnimateTo(Property(child, propertyIndex),
1158                                 animator->targetValue,
1159                                 animator->alphaFunction,
1160                                 TimePeriod(animator->timePeriodDelay,
1161                                            animator->timePeriodDuration));
1162           }
1163         }
1164       }
1165     }
1166   }
1167 }
1168
1169 Dali::Animation Control::Impl::CreateTransition(const Toolkit::TransitionData& transitionData)
1170 {
1171   Dali::Animation transition;
1172
1173   if(transitionData.Count() > 0)
1174   {
1175     AddTransitions(transition, transitionData, true);
1176   }
1177   return transition;
1178 }
1179
1180 void Control::Impl::DoAction(Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes)
1181 {
1182   RegisteredVisualContainer::Iterator iter;
1183   if(FindVisual(visualIndex, mVisuals, iter))
1184   {
1185     Toolkit::GetImplementation((*iter)->visual).DoAction(actionId, attributes);
1186   }
1187 }
1188
1189 void Control::Impl::DoActionExtension(Dali::Property::Index visualIndex, Dali::Property::Index actionId, Dali::Any attributes)
1190 {
1191   RegisteredVisualContainer::Iterator iter;
1192   if(FindVisual(visualIndex, mVisuals, iter))
1193   {
1194     Toolkit::GetImplementation((*iter)->visual).DoActionExtension(actionId, attributes);
1195   }
1196 }
1197
1198 void Control::Impl::AppendAccessibilityAttribute(const std::string& key, const std::string value)
1199 {
1200   Property::Value* checkedValue = mAccessibilityAttributes.Find(key);
1201   if(checkedValue)
1202   {
1203     mAccessibilityAttributes[key] = Property::Value(value);
1204   }
1205   else
1206   {
1207     mAccessibilityAttributes.Insert(key, value);
1208   }
1209 }
1210
1211 void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
1212 {
1213   DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
1214
1215   Toolkit::Control control = Toolkit::Control::DownCast(BaseHandle(object));
1216
1217   if(control)
1218   {
1219     Control& controlImpl(GetImplementation(control));
1220
1221     switch(index)
1222     {
1223       case Toolkit::Control::Property::STYLE_NAME:
1224       {
1225         controlImpl.SetStyleName(value.Get<std::string>());
1226         break;
1227       }
1228
1229       case Toolkit::DevelControl::Property::STATE:
1230       {
1231         bool                   withTransitions = true;
1232         const Property::Value* valuePtr        = &value;
1233         const Property::Map*   map             = value.GetMap();
1234         if(map)
1235         {
1236           Property::Value* value2 = map->Find("withTransitions");
1237           if(value2)
1238           {
1239             withTransitions = value2->Get<bool>();
1240           }
1241
1242           valuePtr = map->Find("state");
1243         }
1244
1245         if(valuePtr)
1246         {
1247           Toolkit::DevelControl::State state(controlImpl.mImpl->mState);
1248           if(Scripting::GetEnumerationProperty<Toolkit::DevelControl::State>(*valuePtr, ControlStateTable, ControlStateTableCount, state))
1249           {
1250             controlImpl.mImpl->SetState(state, withTransitions);
1251           }
1252         }
1253       }
1254       break;
1255
1256       case Toolkit::DevelControl::Property::SUB_STATE:
1257       {
1258         std::string subState;
1259         if(value.Get(subState))
1260         {
1261           controlImpl.mImpl->SetSubState(subState);
1262         }
1263       }
1264       break;
1265
1266       case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
1267       {
1268         int focusId;
1269         if(value.Get(focusId))
1270         {
1271           controlImpl.mImpl->mLeftFocusableActorId = focusId;
1272         }
1273       }
1274       break;
1275
1276       case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
1277       {
1278         int focusId;
1279         if(value.Get(focusId))
1280         {
1281           controlImpl.mImpl->mRightFocusableActorId = focusId;
1282         }
1283       }
1284       break;
1285
1286       case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
1287       {
1288         int focusId;
1289         if(value.Get(focusId))
1290         {
1291           controlImpl.mImpl->mUpFocusableActorId = focusId;
1292         }
1293       }
1294       break;
1295
1296       case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
1297       {
1298         int focusId;
1299         if(value.Get(focusId))
1300         {
1301           controlImpl.mImpl->mDownFocusableActorId = focusId;
1302         }
1303       }
1304       break;
1305
1306       case Toolkit::Control::Property::KEY_INPUT_FOCUS:
1307       {
1308         if(value.Get<bool>())
1309         {
1310           controlImpl.SetKeyInputFocus();
1311         }
1312         else
1313         {
1314           controlImpl.ClearKeyInputFocus();
1315         }
1316         break;
1317       }
1318
1319       case Toolkit::Control::Property::BACKGROUND:
1320       {
1321         std::string          url;
1322         Vector4              color;
1323         const Property::Map* map = value.GetMap();
1324         if(map && !map->Empty())
1325         {
1326           controlImpl.SetBackground(*map);
1327         }
1328         else if(value.Get(url))
1329         {
1330           // don't know the size to load
1331           Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual(url, ImageDimensions());
1332           if(visual)
1333           {
1334             controlImpl.mImpl->RegisterVisual(Toolkit::Control::Property::BACKGROUND, visual, DepthIndex::BACKGROUND);
1335           }
1336         }
1337         else if(value.Get(color))
1338         {
1339           controlImpl.SetBackgroundColor(color);
1340         }
1341         else
1342         {
1343           // The background is an empty property map, so we should clear the background
1344           controlImpl.ClearBackground();
1345         }
1346         break;
1347       }
1348
1349       case Toolkit::Control::Property::MARGIN:
1350       {
1351         Extents margin;
1352         if(value.Get(margin))
1353         {
1354           controlImpl.mImpl->SetMargin(margin);
1355         }
1356         break;
1357       }
1358
1359       case Toolkit::Control::Property::PADDING:
1360       {
1361         Extents padding;
1362         if(value.Get(padding))
1363         {
1364           controlImpl.mImpl->SetPadding(padding);
1365         }
1366         break;
1367       }
1368
1369       case Toolkit::DevelControl::Property::TOOLTIP:
1370       {
1371         TooltipPtr& tooltipPtr = controlImpl.mImpl->mTooltip;
1372         if(!tooltipPtr)
1373         {
1374           tooltipPtr = Tooltip::New(control);
1375         }
1376         tooltipPtr->SetProperties(value);
1377         break;
1378       }
1379
1380       case Toolkit::DevelControl::Property::SHADOW:
1381       {
1382         const Property::Map* map = value.GetMap();
1383         if(map && !map->Empty())
1384         {
1385           controlImpl.mImpl->SetShadow(*map);
1386         }
1387         else
1388         {
1389           // The shadow is an empty property map, so we should clear the shadow
1390           controlImpl.mImpl->ClearShadow();
1391         }
1392         break;
1393       }
1394
1395       case Toolkit::DevelControl::Property::ACCESSIBILITY_NAME:
1396       {
1397         std::string name;
1398         if(value.Get(name))
1399         {
1400           controlImpl.mImpl->mAccessibilityName = name;
1401         }
1402         break;
1403       }
1404
1405       case Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION:
1406       {
1407         std::string text;
1408         if(value.Get(text))
1409         {
1410           controlImpl.mImpl->mAccessibilityDescription = text;
1411         }
1412         break;
1413       }
1414
1415       case Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN:
1416       {
1417         std::string text;
1418         if(value.Get(text))
1419         {
1420           controlImpl.mImpl->mAccessibilityTranslationDomain = text;
1421         }
1422         break;
1423       }
1424
1425       case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE:
1426       {
1427         Dali::Accessibility::Role role;
1428         if(value.Get(role))
1429         {
1430           controlImpl.mImpl->mAccessibilityRole = role;
1431         }
1432         break;
1433       }
1434
1435       case Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE:
1436       {
1437         bool highlightable;
1438         if(value.Get(highlightable))
1439         {
1440           controlImpl.mImpl->mAccessibilityHighlightable = highlightable;
1441         }
1442         break;
1443       }
1444
1445       case Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES:
1446       {
1447         const Property::Map* map = value.GetMap();
1448         if(map && !map->Empty())
1449         {
1450           controlImpl.mImpl->mAccessibilityAttributes = *map;
1451         }
1452         break;
1453       }
1454
1455       case Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS:
1456       {
1457         bool dispatch;
1458         if(value.Get(dispatch))
1459         {
1460           controlImpl.mImpl->mDispatchKeyEvents = dispatch;
1461         }
1462         break;
1463       }
1464
1465       case Toolkit::DevelControl::Property::ACCESSIBILITY_HIDDEN:
1466       {
1467         bool hidden;
1468         if(value.Get(hidden))
1469         {
1470           controlImpl.mImpl->mAccessibilityHidden = hidden;
1471
1472           auto* accessible = controlImpl.GetAccessibleObject();
1473           if(DALI_LIKELY(accessible))
1474           {
1475             auto* parent = dynamic_cast<Dali::Accessibility::ActorAccessible*>(accessible->GetParent());
1476             if(parent)
1477             {
1478               parent->OnChildrenChanged();
1479             }
1480           }
1481         }
1482         break;
1483       }
1484       case Toolkit::DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID:
1485       {
1486         int focusId;
1487         if(value.Get(focusId))
1488         {
1489           controlImpl.mImpl->mClockwiseFocusableActorId = focusId;
1490         }
1491         break;
1492       }
1493       case Toolkit::DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID:
1494       {
1495         int focusId;
1496         if(value.Get(focusId))
1497         {
1498           controlImpl.mImpl->mCounterClockwiseFocusableActorId = focusId;
1499         }
1500         break;
1501       }
1502
1503       case Toolkit::DevelControl::Property::AUTOMATION_ID:
1504       {
1505         std::string automationId;
1506         if(value.Get(automationId))
1507         {
1508           controlImpl.mImpl->mAutomationId = automationId;
1509         }
1510         break;
1511       }
1512     }
1513   }
1514 }
1515
1516 Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index index)
1517 {
1518   DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
1519
1520   Property::Value value;
1521
1522   Toolkit::Control control = Toolkit::Control::DownCast(BaseHandle(object));
1523
1524   if(control)
1525   {
1526     Control& controlImpl(GetImplementation(control));
1527
1528     switch(index)
1529     {
1530       case Toolkit::Control::Property::STYLE_NAME:
1531       {
1532         value = controlImpl.GetStyleName();
1533         break;
1534       }
1535
1536       case Toolkit::DevelControl::Property::STATE:
1537       {
1538         value = controlImpl.mImpl->mState;
1539         break;
1540       }
1541
1542       case Toolkit::DevelControl::Property::SUB_STATE:
1543       {
1544         value = controlImpl.mImpl->mSubStateName;
1545         break;
1546       }
1547
1548       case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
1549       {
1550         value = controlImpl.mImpl->mLeftFocusableActorId;
1551         break;
1552       }
1553
1554       case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
1555       {
1556         value = controlImpl.mImpl->mRightFocusableActorId;
1557         break;
1558       }
1559
1560       case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
1561       {
1562         value = controlImpl.mImpl->mUpFocusableActorId;
1563         break;
1564       }
1565
1566       case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
1567       {
1568         value = controlImpl.mImpl->mDownFocusableActorId;
1569         break;
1570       }
1571
1572       case Toolkit::Control::Property::KEY_INPUT_FOCUS:
1573       {
1574         value = controlImpl.HasKeyInputFocus();
1575         break;
1576       }
1577
1578       case Toolkit::Control::Property::BACKGROUND:
1579       {
1580         Property::Map         map;
1581         Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual(Toolkit::Control::Property::BACKGROUND);
1582         if(visual)
1583         {
1584           visual.CreatePropertyMap(map);
1585         }
1586
1587         value = map;
1588         break;
1589       }
1590
1591       case Toolkit::Control::Property::MARGIN:
1592       {
1593         value = controlImpl.mImpl->GetMargin();
1594         break;
1595       }
1596
1597       case Toolkit::Control::Property::PADDING:
1598       {
1599         value = controlImpl.mImpl->GetPadding();
1600         break;
1601       }
1602
1603       case Toolkit::DevelControl::Property::TOOLTIP:
1604       {
1605         Property::Map map;
1606         if(controlImpl.mImpl->mTooltip)
1607         {
1608           controlImpl.mImpl->mTooltip->CreatePropertyMap(map);
1609         }
1610         value = map;
1611         break;
1612       }
1613
1614       case Toolkit::DevelControl::Property::SHADOW:
1615       {
1616         Property::Map         map;
1617         Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual(Toolkit::DevelControl::Property::SHADOW);
1618         if(visual)
1619         {
1620           visual.CreatePropertyMap(map);
1621         }
1622
1623         value = map;
1624         break;
1625       }
1626
1627       case Toolkit::DevelControl::Property::ACCESSIBILITY_NAME:
1628       {
1629         value = controlImpl.mImpl->mAccessibilityName;
1630         break;
1631       }
1632
1633       case Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION:
1634       {
1635         value = controlImpl.mImpl->mAccessibilityDescription;
1636         break;
1637       }
1638
1639       case Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN:
1640       {
1641         value = controlImpl.mImpl->mAccessibilityTranslationDomain;
1642         break;
1643       }
1644
1645       case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE:
1646       {
1647         value = Property::Value(controlImpl.mImpl->mAccessibilityRole);
1648         break;
1649       }
1650
1651       case Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE:
1652       {
1653         value = controlImpl.mImpl->mAccessibilityHighlightable;
1654         break;
1655       }
1656
1657       case Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES:
1658       {
1659         value = controlImpl.mImpl->mAccessibilityAttributes;
1660         break;
1661       }
1662
1663       case Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS:
1664       {
1665         value = controlImpl.mImpl->mDispatchKeyEvents;
1666         break;
1667       }
1668
1669       case Toolkit::DevelControl::Property::ACCESSIBILITY_HIDDEN:
1670       {
1671         value = controlImpl.mImpl->mAccessibilityHidden;
1672         break;
1673       }
1674
1675       case Toolkit::DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID:
1676       {
1677         value = controlImpl.mImpl->mClockwiseFocusableActorId;
1678         break;
1679       }
1680
1681       case Toolkit::DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID:
1682       {
1683         value = controlImpl.mImpl->mCounterClockwiseFocusableActorId;
1684         break;
1685       }
1686
1687       case Toolkit::DevelControl::Property::AUTOMATION_ID:
1688       {
1689         value = controlImpl.mImpl->mAutomationId;
1690         break;
1691       }
1692     }
1693   }
1694
1695   return value;
1696 }
1697
1698 void Control::Impl::RemoveAccessibilityAttribute(const std::string& key)
1699 {
1700   Property::Value* value = mAccessibilityAttributes.Find(key);
1701   if(value)
1702   {
1703     mAccessibilityAttributes[key] = Property::Value();
1704   }
1705 }
1706
1707 void Control::Impl::ClearAccessibilityAttributes()
1708 {
1709   mAccessibilityAttributes.Clear();
1710 }
1711
1712 void Control::Impl::SetAccessibilityReadingInfoType(const Dali::Accessibility::ReadingInfoTypes types)
1713 {
1714   std::string value{};
1715   if(types[Dali::Accessibility::ReadingInfoType::NAME])
1716   {
1717     value += READING_INFO_TYPE_NAME;
1718   }
1719   if(types[Dali::Accessibility::ReadingInfoType::ROLE])
1720   {
1721     if(!value.empty())
1722     {
1723       value += READING_INFO_TYPE_SEPARATOR;
1724     }
1725     value += READING_INFO_TYPE_ROLE;
1726   }
1727   if(types[Dali::Accessibility::ReadingInfoType::DESCRIPTION])
1728   {
1729     if(!value.empty())
1730     {
1731       value += READING_INFO_TYPE_SEPARATOR;
1732     }
1733     value += READING_INFO_TYPE_DESCRIPTION;
1734   }
1735   if(types[Dali::Accessibility::ReadingInfoType::STATE])
1736   {
1737     if(!value.empty())
1738     {
1739       value += READING_INFO_TYPE_SEPARATOR;
1740     }
1741     value += READING_INFO_TYPE_STATE;
1742   }
1743   AppendAccessibilityAttribute(READING_INFO_TYPE_ATTRIBUTE_NAME, value);
1744 }
1745
1746 Dali::Accessibility::ReadingInfoTypes Control::Impl::GetAccessibilityReadingInfoType() const
1747 {
1748   std::string value{};
1749   auto        place = mAccessibilityAttributes.Find(READING_INFO_TYPE_ATTRIBUTE_NAME);
1750   if(place)
1751   {
1752     place->Get(value);
1753   }
1754   else
1755   {
1756     Dali::Accessibility::ReadingInfoTypes types;
1757     types[Dali::Accessibility::ReadingInfoType::NAME]        = true;
1758     types[Dali::Accessibility::ReadingInfoType::ROLE]        = true;
1759     types[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
1760     types[Dali::Accessibility::ReadingInfoType::STATE]       = true;
1761     return types;
1762   }
1763
1764   if(value.empty())
1765   {
1766     return {};
1767   }
1768
1769   Dali::Accessibility::ReadingInfoTypes types;
1770
1771   if(value.find(READING_INFO_TYPE_NAME) != std::string::npos)
1772   {
1773     types[Dali::Accessibility::ReadingInfoType::NAME] = true;
1774   }
1775   if(value.find(READING_INFO_TYPE_ROLE) != std::string::npos)
1776   {
1777     types[Dali::Accessibility::ReadingInfoType::ROLE] = true;
1778   }
1779   if(value.find(READING_INFO_TYPE_DESCRIPTION) != std::string::npos)
1780   {
1781     types[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
1782   }
1783   if(value.find(READING_INFO_TYPE_STATE) != std::string::npos)
1784   {
1785     types[Dali::Accessibility::ReadingInfoType::STATE] = true;
1786   }
1787
1788   return types;
1789 }
1790
1791 void Control::Impl::CopyInstancedProperties(RegisteredVisualContainer& visuals, Dictionary<Property::Map>& instancedProperties)
1792 {
1793   for(RegisteredVisualContainer::Iterator iter = visuals.Begin(); iter != visuals.End(); iter++)
1794   {
1795     if((*iter)->visual)
1796     {
1797       Property::Map instanceMap;
1798       Toolkit::GetImplementation((*iter)->visual).CreateInstancePropertyMap(instanceMap);
1799       instancedProperties.Add((*iter)->visual.GetName(), instanceMap);
1800     }
1801   }
1802 }
1803
1804 void Control::Impl::RemoveVisual(RegisteredVisualContainer& visuals, const std::string& visualName)
1805 {
1806   Actor self(mControlImpl.Self());
1807
1808   for(RegisteredVisualContainer::Iterator visualIter = visuals.Begin();
1809       visualIter != visuals.End();
1810       ++visualIter)
1811   {
1812     Toolkit::Visual::Base visual = (*visualIter)->visual;
1813     if(visual && visual.GetName() == visualName)
1814     {
1815       Toolkit::GetImplementation(visual).SetOffScene(self);
1816       (*visualIter)->visual.Reset();
1817       visuals.Erase(visualIter);
1818       break;
1819     }
1820   }
1821 }
1822
1823 void Control::Impl::RemoveVisuals(RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals)
1824 {
1825   Actor self(mControlImpl.Self());
1826   for(DictionaryKeys::iterator iter = removeVisuals.begin(); iter != removeVisuals.end(); ++iter)
1827   {
1828     const std::string visualName = *iter;
1829     RemoveVisual(visuals, visualName);
1830   }
1831 }
1832
1833 void Control::Impl::RecreateChangedVisuals(Dictionary<Property::Map>& stateVisualsToChange,
1834                                            Dictionary<Property::Map>& instancedProperties)
1835 {
1836   Dali::CustomActor handle(mControlImpl.GetOwner());
1837   for(Dictionary<Property::Map>::iterator iter = stateVisualsToChange.Begin();
1838       iter != stateVisualsToChange.End();
1839       ++iter)
1840   {
1841     const std::string&   visualName = (*iter).key;
1842     const Property::Map& toMap      = (*iter).entry;
1843
1844     Actor                               self = mControlImpl.Self();
1845     RegisteredVisualContainer::Iterator registeredVisualsiter;
1846     // Check if visual (visualName) is already registered, this is the current visual.
1847     if(FindVisual(visualName, mVisuals, registeredVisualsiter))
1848     {
1849       Toolkit::Visual::Base& visual = (*registeredVisualsiter)->visual;
1850       if(visual)
1851       {
1852         // No longer required to know if the replaced visual's resources are ready
1853         StopObservingVisual(visual);
1854
1855         // If control staged then visuals will be swapped once ready
1856         if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
1857         {
1858           // Check if visual is currently in the process of being replaced ( is in removal container )
1859           RegisteredVisualContainer::Iterator visualQueuedForRemoval;
1860           if(FindVisual(visualName, mRemoveVisuals, visualQueuedForRemoval))
1861           {
1862             // Visual with same visual name is already in removal container so current visual pending
1863             // Only the the last requested visual will be displayed so remove current visual which is staged but not ready.
1864             Toolkit::GetImplementation(visual).SetOffScene(self);
1865             (*registeredVisualsiter)->visual.Reset();
1866             mVisuals.Erase(registeredVisualsiter);
1867           }
1868           else
1869           {
1870             // current visual not already in removal container so add now.
1871             DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %s \n", visualName.c_str());
1872             MoveVisual(registeredVisualsiter, mVisuals, mRemoveVisuals);
1873           }
1874         }
1875         else
1876         {
1877           // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later.
1878           (*registeredVisualsiter)->visual.Reset();
1879           mVisuals.Erase(registeredVisualsiter);
1880         }
1881       }
1882
1883       const Property::Map* instancedMap = instancedProperties.FindConst(visualName);
1884       Style::ApplyVisual(handle, visualName, toMap, instancedMap);
1885     }
1886   }
1887 }
1888
1889 void Control::Impl::ReplaceStateVisualsAndProperties(const StylePtr oldState, const StylePtr newState, const std::string& subState)
1890 {
1891   DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
1892
1893   // Collect all old visual names
1894   DictionaryKeys stateVisualsToRemove;
1895   if(oldState)
1896   {
1897     oldState->visuals.GetKeys(stateVisualsToRemove);
1898     if(!subState.empty())
1899     {
1900       const StylePtr* oldSubState = oldState->subStates.FindConst(subState);
1901       if(oldSubState)
1902       {
1903         DictionaryKeys subStateVisualsToRemove;
1904         (*oldSubState)->visuals.GetKeys(subStateVisualsToRemove);
1905         Merge(stateVisualsToRemove, subStateVisualsToRemove);
1906       }
1907     }
1908   }
1909
1910   // Collect all new visual properties
1911   Dictionary<Property::Map> stateVisualsToAdd;
1912   if(newState)
1913   {
1914     stateVisualsToAdd = newState->visuals;
1915     if(!subState.empty())
1916     {
1917       const StylePtr* newSubState = newState->subStates.FindConst(subState);
1918       if(newSubState)
1919       {
1920         stateVisualsToAdd.Merge((*newSubState)->visuals);
1921       }
1922     }
1923   }
1924
1925   // If a name is in both add/remove, move it to change list.
1926   Dictionary<Property::Map> stateVisualsToChange;
1927   FindChangableVisuals(stateVisualsToAdd, stateVisualsToChange, stateVisualsToRemove);
1928
1929   // Copy instanced properties (e.g. text label) of current visuals
1930   Dictionary<Property::Map> instancedProperties;
1931   CopyInstancedProperties(mVisuals, instancedProperties);
1932
1933   // For each visual in remove list, remove from mVisuals
1934   RemoveVisuals(mVisuals, stateVisualsToRemove);
1935
1936   // For each visual in add list, create and add to mVisuals
1937   Dali::CustomActor handle(mControlImpl.GetOwner());
1938   Style::ApplyVisuals(handle, stateVisualsToAdd, instancedProperties);
1939
1940   // For each visual in change list, if it requires a new visual,
1941   // remove old visual, create and add to mVisuals
1942   RecreateChangedVisuals(stateVisualsToChange, instancedProperties);
1943 }
1944
1945 void Control::Impl::SetState(DevelControl::State newState, bool withTransitions)
1946 {
1947   DevelControl::State oldState = mState;
1948   Dali::CustomActor   handle(mControlImpl.GetOwner());
1949   DALI_LOG_INFO(gLogFilter, Debug::Concise, "Control::Impl::SetState: %s\n", (mState == DevelControl::NORMAL ? "NORMAL" : (mState == DevelControl::FOCUSED ? "FOCUSED" : (mState == DevelControl::DISABLED ? "DISABLED" : "NONE"))));
1950
1951   if(mState != newState)
1952   {
1953     // If mState was Disabled, and new state is Focused, should probably
1954     // store that fact, e.g. in another property that FocusManager can access.
1955     mState = newState;
1956
1957     // Trigger state change and transitions
1958     // Apply new style, if stylemanager is available
1959     Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
1960     if(styleManager)
1961     {
1962       const StylePtr stylePtr = GetImpl(styleManager).GetRecordedStyle(Toolkit::Control(mControlImpl.GetOwner()));
1963
1964       if(stylePtr)
1965       {
1966         std::string oldStateName = Scripting::GetEnumerationName<Toolkit::DevelControl::State>(oldState, ControlStateTable, ControlStateTableCount);
1967         std::string newStateName = Scripting::GetEnumerationName<Toolkit::DevelControl::State>(newState, ControlStateTable, ControlStateTableCount);
1968
1969         const StylePtr* newStateStyle = stylePtr->subStates.Find(newStateName);
1970         const StylePtr* oldStateStyle = stylePtr->subStates.Find(oldStateName);
1971         if(oldStateStyle && newStateStyle)
1972         {
1973           // Only change if both state styles exist
1974           ReplaceStateVisualsAndProperties(*oldStateStyle, *newStateStyle, mSubStateName);
1975         }
1976       }
1977     }
1978   }
1979 }
1980
1981 void Control::Impl::SetSubState(const std::string& subStateName, bool withTransitions)
1982 {
1983   if(mSubStateName != subStateName)
1984   {
1985     // Get existing sub-state visuals, and unregister them
1986     Dali::CustomActor handle(mControlImpl.GetOwner());
1987
1988     Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
1989     if(styleManager)
1990     {
1991       const StylePtr stylePtr = GetImpl(styleManager).GetRecordedStyle(Toolkit::Control(mControlImpl.GetOwner()));
1992       if(stylePtr)
1993       {
1994         // Stringify state
1995         std::string stateName = Scripting::GetEnumerationName<Toolkit::DevelControl::State>(mState, ControlStateTable, ControlStateTableCount);
1996
1997         const StylePtr* state = stylePtr->subStates.Find(stateName);
1998         if(state)
1999         {
2000           StylePtr stateStyle(*state);
2001
2002           const StylePtr* newStateStyle = stateStyle->subStates.Find(subStateName);
2003           const StylePtr* oldStateStyle = stateStyle->subStates.Find(mSubStateName);
2004           if(oldStateStyle && newStateStyle)
2005           {
2006             std::string empty;
2007             ReplaceStateVisualsAndProperties(*oldStateStyle, *newStateStyle, empty);
2008           }
2009         }
2010       }
2011     }
2012
2013     mSubStateName = subStateName;
2014   }
2015 }
2016
2017 void Control::Impl::OnSceneDisconnection()
2018 {
2019   Actor self = mControlImpl.Self();
2020
2021   // Any visuals set for replacement but not yet ready should still be registered.
2022   // Reason: If a request was made to register a new visual but the control removed from scene before visual was ready
2023   // then when this control appears back on stage it should use that new visual.
2024
2025   // Iterate through all registered visuals and set off scene
2026   SetVisualsOffScene(mVisuals, self);
2027
2028   // Visuals pending replacement can now be taken out of the removal list and set off scene
2029   // Iterate through all replacement visuals and add to a move queue then set off scene
2030
2031   if(!mRemoveVisuals.Empty())
2032   {
2033     std::reverse(mRemoveVisuals.Begin(), mRemoveVisuals.End());
2034
2035     while(!mRemoveVisuals.Empty())
2036     {
2037       auto removalIter = mRemoveVisuals.End() - 1u;
2038       Toolkit::GetImplementation((*removalIter)->visual).SetOffScene(self);
2039
2040       // Discard removed visual. It will be destroyed at next Idle time.
2041       DiscardVisual(removalIter, mRemoveVisuals);
2042     }
2043   }
2044
2045   for(auto replacedIter = mVisuals.Begin(), end = mVisuals.End(); replacedIter != end; replacedIter++)
2046   {
2047     (*replacedIter)->pending = false;
2048   }
2049 }
2050
2051 void Control::Impl::SetMargin(Extents margin)
2052 {
2053   mControlImpl.mImpl->mMargin = margin;
2054
2055   // Trigger a size negotiation request that may be needed when setting a margin.
2056   mControlImpl.RelayoutRequest();
2057 }
2058
2059 Extents Control::Impl::GetMargin() const
2060 {
2061   return mControlImpl.mImpl->mMargin;
2062 }
2063
2064 void Control::Impl::SetPadding(Extents padding)
2065 {
2066   mControlImpl.mImpl->mPadding = padding;
2067
2068   // Trigger a size negotiation request that may be needed when setting a padding.
2069   mControlImpl.RelayoutRequest();
2070 }
2071
2072 Extents Control::Impl::GetPadding() const
2073 {
2074   return mControlImpl.mImpl->mPadding;
2075 }
2076
2077 void Control::Impl::SetInputMethodContext(InputMethodContext& inputMethodContext)
2078 {
2079   mInputMethodContext = inputMethodContext;
2080 }
2081
2082 bool Control::Impl::FilterKeyEvent(const KeyEvent& event)
2083 {
2084   bool consumed(false);
2085
2086   if(mInputMethodContext)
2087   {
2088     consumed = mInputMethodContext.FilterEventKey(event);
2089   }
2090   return consumed;
2091 }
2092
2093 DevelControl::VisualEventSignalType& Control::Impl::VisualEventSignal()
2094 {
2095   return mVisualEventSignal;
2096 }
2097
2098 void Control::Impl::SetShadow(const Property::Map& map)
2099 {
2100   Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual(map);
2101   visual.SetName("shadow");
2102
2103   if(visual)
2104   {
2105     mControlImpl.mImpl->RegisterVisual(Toolkit::DevelControl::Property::SHADOW, visual, DepthIndex::BACKGROUND_EFFECT);
2106
2107     mControlImpl.RelayoutRequest();
2108   }
2109 }
2110
2111 void Control::Impl::ClearShadow()
2112 {
2113   mControlImpl.mImpl->UnregisterVisual(Toolkit::DevelControl::Property::SHADOW);
2114
2115   // Trigger a size negotiation request that may be needed when unregistering a visual.
2116   mControlImpl.RelayoutRequest();
2117 }
2118
2119 Dali::Property Control::Impl::GetVisualProperty(Dali::Property::Index index, Dali::Property::Key visualPropertyKey)
2120 {
2121   Toolkit::Visual::Base visual = GetVisualByIndex(mVisuals, index);
2122   if(visual)
2123   {
2124     Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
2125     return visualImpl.GetPropertyObject(std::move(visualPropertyKey));
2126   }
2127
2128   Handle handle;
2129   return Dali::Property(handle, Property::INVALID_INDEX);
2130 }
2131
2132 void Control::Impl::CreateTransitions(std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& sourceProperties,
2133                                       std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& destinationProperties,
2134                                       Dali::Toolkit::Control                                              source,
2135                                       Dali::Toolkit::Control                                              destination)
2136 {
2137   // Retrieves background properties to be transitioned.
2138   Dali::Property::Map backgroundSourcePropertyMap, backgroundDestinationPropertyMap;
2139   mControlImpl.MakeVisualTransition(backgroundSourcePropertyMap, backgroundDestinationPropertyMap, source, destination, Toolkit::Control::Property::BACKGROUND);
2140   if(backgroundSourcePropertyMap.Count() > 0)
2141   {
2142     sourceProperties.push_back(std::pair<Dali::Property::Index, Dali::Property::Map>(Toolkit::Control::Property::BACKGROUND, backgroundSourcePropertyMap));
2143     destinationProperties.push_back(std::pair<Dali::Property::Index, Dali::Property::Map>(Toolkit::Control::Property::BACKGROUND, backgroundDestinationPropertyMap));
2144   }
2145
2146   // Retrieves shadow properties to be transitioned.
2147   Dali::Property::Map shadowSourcePropertyMap, shadowDestinationPropertyMap;
2148   mControlImpl.MakeVisualTransition(shadowSourcePropertyMap, shadowDestinationPropertyMap, source, destination, Toolkit::DevelControl::Property::SHADOW);
2149   if(shadowSourcePropertyMap.Count() > 0)
2150   {
2151     sourceProperties.push_back(std::pair<Dali::Property::Index, Dali::Property::Map>(Toolkit::DevelControl::Property::SHADOW, shadowSourcePropertyMap));
2152     destinationProperties.push_back(std::pair<Dali::Property::Index, Dali::Property::Map>(Toolkit::DevelControl::Property::SHADOW, shadowDestinationPropertyMap));
2153   }
2154
2155   // Retrieves transition from inherited class.
2156   mControlImpl.OnCreateTransitions(sourceProperties, destinationProperties, source, destination);
2157 }
2158
2159 void Control::Impl::UpdateVisualProperties(const std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& properties)
2160 {
2161   for(auto&& data : properties)
2162   {
2163     if(data.first == Toolkit::Control::Property::BACKGROUND)
2164     {
2165       DoAction(Toolkit::Control::Property::BACKGROUND, DevelVisual::Action::UPDATE_PROPERTY, data.second);
2166     }
2167     else if(data.first == Toolkit::DevelControl::Property::SHADOW)
2168     {
2169       DoAction(Toolkit::DevelControl::Property::SHADOW, DevelVisual::Action::UPDATE_PROPERTY, data.second);
2170     }
2171   }
2172   mControlImpl.OnUpdateVisualProperties(properties);
2173 }
2174
2175 void Control::Impl::EmitResourceReadySignal()
2176 {
2177   if(!mIsEmittingResourceReadySignal)
2178   {
2179     // Guard against calls to emit the signal during the callback
2180     mIsEmittingResourceReadySignal = true;
2181
2182     // If the signal handler changes visual, it may become ready during this call & therefore this method will
2183     // get called again recursively. If so, mIdleCallbackRegistered is set below, and we act on it after that secondary
2184     // invocation has completed by notifying in an Idle callback to prevent further recursion.
2185     Dali::Toolkit::Control handle(mControlImpl.GetOwner());
2186     mResourceReadySignal.Emit(handle);
2187
2188     mIsEmittingResourceReadySignal = false;
2189   }
2190   else
2191   {
2192     if(!mIdleCallbackRegistered)
2193     {
2194       mIdleCallbackRegistered = true;
2195
2196       // Add idler to emit the signal again
2197       if(!mIdleCallback)
2198       {
2199         // The callback manager takes the ownership of the callback object.
2200         mIdleCallback = MakeCallback(this, &Control::Impl::OnIdleCallback);
2201         Adaptor::Get().AddIdle(mIdleCallback, true);
2202       }
2203     }
2204   }
2205 }
2206
2207 bool Control::Impl::OnIdleCallback()
2208 {
2209   // Reset the flag
2210   mIdleCallbackRegistered = false;
2211
2212   // A visual is ready so control may need relayouting if staged
2213   if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
2214   {
2215     mControlImpl.RelayoutRequest();
2216   }
2217
2218   EmitResourceReadySignal();
2219
2220   if(!mIdleCallbackRegistered)
2221   {
2222     // Set the pointer to null as the callback manager deletes the callback after execute it.
2223     mIdleCallback = nullptr;
2224   }
2225
2226   // Repeat idle if mIdleCallbackRegistered become true one more time.
2227   return mIdleCallbackRegistered;
2228 }
2229
2230 Toolkit::DevelControl::ControlAccessible* Control::Impl::GetAccessibleObject()
2231 {
2232   if(mAccessibleCreatable && !mAccessibleObject)
2233   {
2234     mAccessibleObject.reset(mControlImpl.CreateAccessibleObject());
2235   }
2236
2237   return mAccessibleObject.get();
2238 }
2239
2240 bool Control::Impl::IsAccessibleCreated() const
2241 {
2242   return !!mAccessibleObject;
2243 }
2244
2245 void Control::Impl::EnableCreateAccessible(bool enable)
2246 {
2247   mAccessibleCreatable = enable;
2248 }
2249
2250 bool Control::Impl::IsCreateAccessibleEnabled() const
2251 {
2252   return mAccessibleCreatable;
2253 }
2254
2255 } // namespace Internal
2256
2257 } // namespace Toolkit
2258
2259 } // namespace Dali