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