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