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