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