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