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