Fix SVACE errors in accessibility code in control-data-impl
[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 } // unnamed namespace
443
444 // clang-format off
445 // Properties registered without macro to use specific member variables.
446 const PropertyRegistration Control::Impl::PROPERTY_1(typeRegistration,  "styleName",                      Toolkit::Control::Property::STYLE_NAME,                            Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty);
447 const PropertyRegistration Control::Impl::PROPERTY_4(typeRegistration,  "keyInputFocus",                  Toolkit::Control::Property::KEY_INPUT_FOCUS,                       Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
448 const PropertyRegistration Control::Impl::PROPERTY_5(typeRegistration,  "background",                     Toolkit::Control::Property::BACKGROUND,                            Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty);
449 const PropertyRegistration Control::Impl::PROPERTY_6(typeRegistration,  "margin",                         Toolkit::Control::Property::MARGIN,                                Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
450 const PropertyRegistration Control::Impl::PROPERTY_7(typeRegistration,  "padding",                        Toolkit::Control::Property::PADDING,                               Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
451 const PropertyRegistration Control::Impl::PROPERTY_8(typeRegistration,  "tooltip",                        Toolkit::DevelControl::Property::TOOLTIP,                          Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty);
452 const PropertyRegistration Control::Impl::PROPERTY_9(typeRegistration,  "state",                          Toolkit::DevelControl::Property::STATE,                            Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty);
453 const PropertyRegistration Control::Impl::PROPERTY_10(typeRegistration, "subState",                       Toolkit::DevelControl::Property::SUB_STATE,                        Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty);
454 const PropertyRegistration Control::Impl::PROPERTY_11(typeRegistration, "leftFocusableActorId",           Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID,          Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
455 const PropertyRegistration Control::Impl::PROPERTY_12(typeRegistration, "rightFocusableActorId",          Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID,         Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
456 const PropertyRegistration Control::Impl::PROPERTY_13(typeRegistration, "upFocusableActorId",             Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID,            Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
457 const PropertyRegistration Control::Impl::PROPERTY_14(typeRegistration, "downFocusableActorId",           Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID,          Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
458 const PropertyRegistration Control::Impl::PROPERTY_15(typeRegistration, "shadow",                         Toolkit::DevelControl::Property::SHADOW,                           Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty);
459 const PropertyRegistration Control::Impl::PROPERTY_16(typeRegistration, "accessibilityName",              Toolkit::DevelControl::Property::ACCESSIBILITY_NAME,               Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty);
460 const PropertyRegistration Control::Impl::PROPERTY_17(typeRegistration, "accessibilityDescription",       Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION,        Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty);
461 const PropertyRegistration Control::Impl::PROPERTY_18(typeRegistration, "accessibilityTranslationDomain", Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN, Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty);
462 const PropertyRegistration Control::Impl::PROPERTY_19(typeRegistration, "accessibilityRole",              Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE,               Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
463 const PropertyRegistration Control::Impl::PROPERTY_20(typeRegistration, "accessibilityHighlightable",     Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE,      Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
464 const PropertyRegistration Control::Impl::PROPERTY_21(typeRegistration, "accessibilityAttributes",        Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES,         Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty);
465 // clang-format on
466
467 Control::Impl::Impl(Control& controlImpl)
468 : mControlImpl(controlImpl),
469   mState(Toolkit::DevelControl::NORMAL),
470   mSubStateName(""),
471   mLeftFocusableActorId(-1),
472   mRightFocusableActorId(-1),
473   mUpFocusableActorId(-1),
474   mDownFocusableActorId(-1),
475   mStyleName(""),
476   mBackgroundColor(Color::TRANSPARENT),
477   mStartingPinchScale(nullptr),
478   mMargin(0, 0, 0, 0),
479   mPadding(0, 0, 0, 0),
480   mKeyEventSignal(),
481   mKeyInputFocusGainedSignal(),
482   mKeyInputFocusLostSignal(),
483   mResourceReadySignal(),
484   mVisualEventSignal(),
485   mAccessibilityGetNameSignal(),
486   mAccessibilityGetDescriptionSignal(),
487   mAccessibilityDoGestureSignal(),
488   mPinchGestureDetector(),
489   mPanGestureDetector(),
490   mTapGestureDetector(),
491   mLongPressGestureDetector(),
492   mTooltip(NULL),
493   mInputMethodContext(),
494   mIdleCallback(nullptr),
495   mFlags(Control::ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
496   mIsKeyboardNavigationSupported(false),
497   mIsKeyboardFocusGroup(false),
498   mIsEmittingResourceReadySignal(false),
499   mNeedToEmitResourceReady(false)
500 {
501   Dali::Accessibility::Accessible::RegisterControlAccessibilityGetter(
502     [](Dali::Actor actor) -> Dali::Accessibility::Accessible* {
503       return Control::Impl::GetAccessibilityObject(actor);
504     });
505
506   mAccessibilityConstructor = [](Dali::Actor actor) -> std::unique_ptr<Dali::Accessibility::Accessible> {
507     return std::unique_ptr<Dali::Accessibility::Accessible>(new DevelControl::AccessibleImpl(actor, Dali::Accessibility::Role::UNKNOWN));
508   };
509
510   size_t length = static_cast<size_t>(Dali::Accessibility::RelationType::MAX_COUNT);
511   mAccessibilityRelations.reserve(length);
512   for(auto i = 0u; i < length; ++i)
513   {
514     mAccessibilityRelations.push_back({});
515   }
516 }
517
518 Control::Impl::~Impl()
519 {
520   for(auto&& iter : mVisuals)
521   {
522     StopObservingVisual(iter->visual);
523   }
524
525   for(auto&& iter : mRemoveVisuals)
526   {
527     StopObservingVisual(iter->visual);
528   }
529
530   // All gesture detectors will be destroyed so no need to disconnect.
531   delete mStartingPinchScale;
532
533   if(mIdleCallback && Adaptor::IsAvailable())
534   {
535     // Removes the callback from the callback manager in case the control is destroyed before the callback is executed.
536     Adaptor::Get().RemoveIdle(mIdleCallback);
537   }
538 }
539
540 Control::Impl& Control::Impl::Get(Internal::Control& internalControl)
541 {
542   return *internalControl.mImpl;
543 }
544
545 const Control::Impl& Control::Impl::Get(const Internal::Control& internalControl)
546 {
547   return *internalControl.mImpl;
548 }
549
550 void Control::Impl::CheckHighlightedObjectGeometry(PropertyNotification& propertyNotification)
551 {
552   auto accessibleImpl = dynamic_cast<Dali::Toolkit::DevelControl::AccessibleImpl*>(mAccessibilityObject.get());
553   if(!accessibleImpl)
554   {
555     DALI_LOG_ERROR("accessibleImpl is not a pointer to a DevelControl::AccessibleImpl type");
556     return;
557   }
558
559   auto lastPosition   = accessibleImpl->GetLastPosition();
560   auto accessibleRect = accessibleImpl->GetExtents(Dali::Accessibility::CoordinateType::WINDOW);
561
562   if(lastPosition.x == accessibleRect.x && lastPosition.y == accessibleRect.y)
563   {
564     return;
565   }
566
567   auto rect = GetShowingGeometry(accessibleRect, accessibleImpl);
568
569   // MoveOuted is sent already, no need to send it again
570   if(mAccessibilityMovedOutOfScreenDirection != Dali::Accessibility::MovedOutOfScreenType::NONE)
571   {
572     if(rect.width > 0 && rect.height > 0)
573     {
574       // flick next does not use MoveOuted - ScrollToSelf makes object show, so reset for sending MoveOuted next
575       mAccessibilityMovedOutOfScreenDirection = Dali::Accessibility::MovedOutOfScreenType::NONE;
576     }
577     return;
578   }
579
580   if(rect.width < 0)
581   {
582     mAccessibilityMovedOutOfScreenDirection = (accessibleRect.x < lastPosition.x) ? Dali::Accessibility::MovedOutOfScreenType::TOP_LEFT : Dali::Accessibility::MovedOutOfScreenType::BOTTOM_RIGHT;
583   }
584
585   if(rect.height < 0)
586   {
587     mAccessibilityMovedOutOfScreenDirection = (accessibleRect.y < lastPosition.y) ? Dali::Accessibility::MovedOutOfScreenType::TOP_LEFT : Dali::Accessibility::MovedOutOfScreenType::BOTTOM_RIGHT;
588   }
589
590   if(mAccessibilityMovedOutOfScreenDirection != Dali::Accessibility::MovedOutOfScreenType::NONE)
591   {
592     mAccessibilityObject.get()->EmitMovedOutOfScreen(mAccessibilityMovedOutOfScreenDirection);
593     accessibleImpl->SetLastPosition(Vector2(0.0f, 0.0f));
594     return;
595   }
596
597   accessibleImpl->SetLastPosition(Vector2(accessibleRect.x, accessibleRect.y));
598 }
599
600 void Control::Impl::RegisterAccessibilityPositionPropertyNotification()
601 {
602   if(mIsAccessibilityPositionPropertyNotificationSet)
603   {
604     return;
605   }
606
607   mAccessibilityMovedOutOfScreenDirection = Dali::Accessibility::MovedOutOfScreenType::NONE;
608   mAccessibilityPositionNotification      = mControlImpl.Self().AddPropertyNotification(Actor::Property::WORLD_POSITION, StepCondition(1.0f, 1.0f));
609   mAccessibilityPositionNotification.SetNotifyMode(PropertyNotification::NOTIFY_ON_CHANGED);
610   mAccessibilityPositionNotification.NotifySignal().Connect(this, &Control::Impl::CheckHighlightedObjectGeometry);
611   mIsAccessibilityPositionPropertyNotificationSet = true;
612 }
613
614 void Control::Impl::UnregisterAccessibilityPositionPropertyNotification()
615 {
616   mControlImpl.Self().RemovePropertyNotification(mAccessibilityPositionNotification);
617   mIsAccessibilityPositionPropertyNotificationSet = false;
618 }
619
620 // Gesture Detection Methods
621 void Control::Impl::PinchDetected(Actor actor, const PinchGesture& pinch)
622 {
623   mControlImpl.OnPinch(pinch);
624 }
625
626 void Control::Impl::PanDetected(Actor actor, const PanGesture& pan)
627 {
628   mControlImpl.OnPan(pan);
629 }
630
631 void Control::Impl::TapDetected(Actor actor, const TapGesture& tap)
632 {
633   mControlImpl.OnTap(tap);
634 }
635
636 void Control::Impl::LongPressDetected(Actor actor, const LongPressGesture& longPress)
637 {
638   mControlImpl.OnLongPress(longPress);
639 }
640
641 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual)
642 {
643   RegisterVisual(index, visual, VisualState::ENABLED, DepthIndexValue::NOT_SET);
644 }
645
646 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, int depthIndex)
647 {
648   RegisterVisual(index, visual, VisualState::ENABLED, DepthIndexValue::SET, depthIndex);
649 }
650
651 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled)
652 {
653   RegisterVisual(index, visual, (enabled ? VisualState::ENABLED : VisualState::DISABLED), DepthIndexValue::NOT_SET);
654 }
655
656 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex)
657 {
658   RegisterVisual(index, visual, (enabled ? VisualState::ENABLED : VisualState::DISABLED), DepthIndexValue::SET, depthIndex);
659 }
660
661 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex)
662 {
663   DALI_LOG_INFO(gLogFilter, Debug::Concise, "RegisterVisual:%d \n", index);
664
665   bool  visualReplaced(false);
666   Actor self = mControlImpl.Self();
667
668   // Set the depth index, if not set by caller this will be either the current visual depth, max depth of all visuals
669   // or zero.
670   int requiredDepthIndex = visual.GetDepthIndex();
671
672   if(depthIndexValueSet == DepthIndexValue::SET)
673   {
674     requiredDepthIndex = depthIndex;
675   }
676
677   // Visual replacement, existing visual should only be removed from stage when replacement ready.
678   if(!mVisuals.Empty())
679   {
680     RegisteredVisualContainer::Iterator registeredVisualsiter;
681     // Check if visual (index) is already registered, this is the current visual.
682     if(FindVisual(index, mVisuals, registeredVisualsiter))
683     {
684       Toolkit::Visual::Base& currentRegisteredVisual = (*registeredVisualsiter)->visual;
685       if(currentRegisteredVisual)
686       {
687         // Store current visual depth index as may need to set the replacement visual to same depth
688         const int currentDepthIndex = (*registeredVisualsiter)->visual.GetDepthIndex();
689
690         // No longer required to know if the replaced visual's resources are ready
691         StopObservingVisual(currentRegisteredVisual);
692
693         // If control staged and visual enabled then visuals will be swapped once ready
694         if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE) && enabled)
695         {
696           // Check if visual is currently in the process of being replaced ( is in removal container )
697           RegisteredVisualContainer::Iterator visualQueuedForRemoval;
698           if(FindVisual(index, mRemoveVisuals, visualQueuedForRemoval))
699           {
700             // Visual with same index is already in removal container so current visual pending
701             // Only the the last requested visual will be displayed so remove current visual which is staged but not ready.
702             Toolkit::GetImplementation(currentRegisteredVisual).SetOffScene(self);
703             mVisuals.Erase(registeredVisualsiter);
704           }
705           else
706           {
707             // current visual not already in removal container so add now.
708             DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %d \n", index);
709             MoveVisual(registeredVisualsiter, mVisuals, mRemoveVisuals);
710           }
711         }
712         else
713         {
714           // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later.
715           mVisuals.Erase(registeredVisualsiter);
716         }
717
718         // 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
719         if((depthIndexValueSet == DepthIndexValue::NOT_SET) &&
720            (visual.GetDepthIndex() == 0))
721         {
722           requiredDepthIndex = currentDepthIndex;
723         }
724       }
725
726       visualReplaced = true;
727     }
728   }
729
730   // If not set, set the name of the visual to the same name as the control's property.
731   // ( If the control has been type registered )
732   if(visual.GetName().empty())
733   {
734     // returns empty string if index is not found as long as index is not -1
735     std::string visualName = self.GetPropertyName(index);
736     if(!visualName.empty())
737     {
738       DALI_LOG_INFO(gLogFilter, Debug::Concise, "Setting visual name for property %d to %s\n", index, visualName.c_str());
739       visual.SetName(visualName);
740     }
741   }
742
743   if(!visualReplaced) // New registration entry
744   {
745     // 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
746     if((depthIndexValueSet == DepthIndexValue::NOT_SET) &&
747        (mVisuals.Size() > 0) &&
748        (visual.GetDepthIndex() == 0))
749     {
750       int maxDepthIndex = std::numeric_limits<int>::min();
751
752       RegisteredVisualContainer::ConstIterator       iter;
753       const RegisteredVisualContainer::ConstIterator endIter = mVisuals.End();
754       for(iter = mVisuals.Begin(); iter != endIter; iter++)
755       {
756         const int visualDepthIndex = (*iter)->visual.GetDepthIndex();
757         if(visualDepthIndex > maxDepthIndex)
758         {
759           maxDepthIndex = visualDepthIndex;
760         }
761       }
762       ++maxDepthIndex;                                 // Add one to the current maximum depth index so that our added visual appears on top
763       requiredDepthIndex = std::max(0, maxDepthIndex); // Start at zero if maxDepth index belongs to a background
764     }
765   }
766
767   if(visual)
768   {
769     // Set determined depth index
770     visual.SetDepthIndex(requiredDepthIndex);
771
772     // Monitor when the visual resources are ready
773     StartObservingVisual(visual);
774
775     DALI_LOG_INFO(gLogFilter, Debug::Concise, "New Visual registration index[%d] depth[%d]\n", index, requiredDepthIndex);
776     RegisteredVisual* newRegisteredVisual = new RegisteredVisual(index, visual, (enabled == VisualState::ENABLED ? true : false), (visualReplaced && enabled));
777     mVisuals.PushBack(newRegisteredVisual);
778
779     Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
780     // Put on stage if enabled and the control is already on the stage
781     if((enabled == VisualState::ENABLED) && self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
782     {
783       visualImpl.SetOnScene(self);
784     }
785     else if(visualImpl.IsResourceReady()) // When not being staged, check if visual already 'ResourceReady' before it was Registered. ( Resource may have been loaded already )
786     {
787       ResourceReady(visualImpl);
788     }
789   }
790
791   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::RegisterVisual() Registered %s(%d), enabled:%s\n", visual.GetName().c_str(), index, enabled ? "true" : "false");
792 }
793
794 void Control::Impl::UnregisterVisual(Property::Index index)
795 {
796   RegisteredVisualContainer::Iterator iter;
797   if(FindVisual(index, mVisuals, iter))
798   {
799     // stop observing visual
800     StopObservingVisual((*iter)->visual);
801
802     Actor self(mControlImpl.Self());
803     Toolkit::GetImplementation((*iter)->visual).SetOffScene(self);
804     (*iter)->visual.Reset();
805     mVisuals.Erase(iter);
806   }
807
808   if(FindVisual(index, mRemoveVisuals, iter))
809   {
810     Actor self(mControlImpl.Self());
811     Toolkit::GetImplementation((*iter)->visual).SetOffScene(self);
812     (*iter)->pending = false;
813     (*iter)->visual.Reset();
814     mRemoveVisuals.Erase(iter);
815   }
816 }
817
818 Toolkit::Visual::Base Control::Impl::GetVisual(Property::Index index) const
819 {
820   RegisteredVisualContainer::Iterator iter;
821   if(FindVisual(index, mVisuals, iter))
822   {
823     return (*iter)->visual;
824   }
825
826   return Toolkit::Visual::Base();
827 }
828
829 void Control::Impl::EnableVisual(Property::Index index, bool enable)
830 {
831   DALI_LOG_INFO(gLogFilter, Debug::General, "Control::EnableVisual(%d, %s)\n", index, enable ? "T" : "F");
832
833   RegisteredVisualContainer::Iterator iter;
834   if(FindVisual(index, mVisuals, iter))
835   {
836     if((*iter)->enabled == enable)
837     {
838       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Visual %s(%d) already %s\n", (*iter)->visual.GetName().c_str(), index, enable ? "enabled" : "disabled");
839       return;
840     }
841
842     (*iter)->enabled  = enable;
843     Actor parentActor = mControlImpl.Self();
844     if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE)) // If control not on Scene then Visual will be added when SceneConnection is called.
845     {
846       if(enable)
847       {
848         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) on stage \n", (*iter)->visual.GetName().c_str(), index);
849         Toolkit::GetImplementation((*iter)->visual).SetOnScene(parentActor);
850       }
851       else
852       {
853         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) off stage \n", (*iter)->visual.GetName().c_str(), index);
854         Toolkit::GetImplementation((*iter)->visual).SetOffScene(parentActor); // No need to call if control not staged.
855       }
856     }
857   }
858   else
859   {
860     DALI_LOG_WARNING("Control::EnableVisual(%d, %s) FAILED - NO SUCH VISUAL\n", index, enable ? "T" : "F");
861   }
862 }
863
864 bool Control::Impl::IsVisualEnabled(Property::Index index) const
865 {
866   RegisteredVisualContainer::Iterator iter;
867   if(FindVisual(index, mVisuals, iter))
868   {
869     return (*iter)->enabled;
870   }
871   return false;
872 }
873
874 void Control::Impl::StopObservingVisual(Toolkit::Visual::Base& visual)
875 {
876   Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
877
878   // Stop observing the visual
879   visualImpl.RemoveEventObserver(*this);
880 }
881
882 void Control::Impl::StartObservingVisual(Toolkit::Visual::Base& visual)
883 {
884   Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
885
886   // start observing the visual for events
887   visualImpl.AddEventObserver(*this);
888 }
889
890 // Called by a Visual when it's resource is ready
891 void Control::Impl::ResourceReady(Visual::Base& object)
892 {
893   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::Impl::ResourceReady() replacements pending[%d]\n", mRemoveVisuals.Count());
894
895   Actor self = mControlImpl.Self();
896
897   // A resource is ready, find resource in the registered visuals container and get its index
898   for(auto registeredIter = mVisuals.Begin(), end = mVisuals.End(); registeredIter != end; ++registeredIter)
899   {
900     Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation((*registeredIter)->visual);
901
902     if(&object == &registeredVisualImpl)
903     {
904       RegisteredVisualContainer::Iterator visualToRemoveIter;
905       // Find visual with the same index in the removal container
906       // Set if off stage as it's replacement is now ready.
907       // Remove if from removal list as now removed from stage.
908       // Set Pending flag on the ready visual to false as now ready.
909       if(FindVisual((*registeredIter)->index, mRemoveVisuals, visualToRemoveIter))
910       {
911         (*registeredIter)->pending = false;
912         Toolkit::GetImplementation((*visualToRemoveIter)->visual).SetOffScene(self);
913         mRemoveVisuals.Erase(visualToRemoveIter);
914       }
915       break;
916     }
917   }
918
919   // A visual is ready so control may need relayouting if staged
920   if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
921   {
922     mControlImpl.RelayoutRequest();
923   }
924
925   // Emit signal if all enabled visuals registered by the control are ready.
926   if(IsResourceReady())
927   {
928     // Reset the flag
929     mNeedToEmitResourceReady = false;
930
931     EmitResourceReadySignal();
932   }
933 }
934
935 void Control::Impl::NotifyVisualEvent(Visual::Base& object, Property::Index signalId)
936 {
937   for(auto registeredIter = mVisuals.Begin(), end = mVisuals.End(); registeredIter != end; ++registeredIter)
938   {
939     Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation((*registeredIter)->visual);
940     if(&object == &registeredVisualImpl)
941     {
942       Dali::Toolkit::Control handle(mControlImpl.GetOwner());
943       mVisualEventSignal.Emit(handle, (*registeredIter)->index, signalId);
944       break;
945     }
946   }
947 }
948
949 bool Control::Impl::IsResourceReady() const
950 {
951   // Iterate through and check all the enabled visuals are ready
952   for(auto visualIter = mVisuals.Begin();
953       visualIter != mVisuals.End();
954       ++visualIter)
955   {
956     const Toolkit::Visual::Base   visual     = (*visualIter)->visual;
957     const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
958
959     // one of the enabled visuals is not ready
960     if(!visualImpl.IsResourceReady() && (*visualIter)->enabled)
961     {
962       return false;
963     }
964   }
965   return true;
966 }
967
968 Toolkit::Visual::ResourceStatus Control::Impl::GetVisualResourceStatus(Property::Index index) const
969 {
970   RegisteredVisualContainer::Iterator iter;
971   if(FindVisual(index, mVisuals, iter))
972   {
973     const Toolkit::Visual::Base   visual     = (*iter)->visual;
974     const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
975     return visualImpl.GetResourceStatus();
976   }
977
978   return Toolkit::Visual::ResourceStatus::PREPARING;
979 }
980
981 void Control::Impl::AddTransitions(Dali::Animation&               animation,
982                                    const Toolkit::TransitionData& handle,
983                                    bool                           createAnimation)
984 {
985   // Setup a Transition from TransitionData.
986   const Internal::TransitionData& transitionData = Toolkit::GetImplementation(handle);
987   TransitionData::Iterator        end            = transitionData.End();
988   for(TransitionData::Iterator iter = transitionData.Begin();
989       iter != end;
990       ++iter)
991   {
992     TransitionData::Animator* animator = (*iter);
993
994     Toolkit::Visual::Base visual = GetVisualByName(mVisuals, animator->objectName);
995
996     if(visual)
997     {
998 #if defined(DEBUG_ENABLED)
999       Dali::TypeInfo  typeInfo;
1000       ControlWrapper* controlWrapperImpl = dynamic_cast<ControlWrapper*>(&mControlImpl);
1001       if(controlWrapperImpl)
1002       {
1003         typeInfo = controlWrapperImpl->GetTypeInfo();
1004       }
1005
1006       DALI_LOG_INFO(gLogFilter, Debug::Concise, "CreateTransition: Found %s visual for %s\n", visual.GetName().c_str(), typeInfo ? typeInfo.GetName().c_str() : "Unknown");
1007 #endif
1008       Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
1009       visualImpl.AnimateProperty(animation, *animator);
1010     }
1011     else
1012     {
1013       DALI_LOG_INFO(gLogFilter, Debug::Concise, "CreateTransition: Could not find visual. Trying actors");
1014       // Otherwise, try any actor children of control (Including the control)
1015       Actor child = mControlImpl.Self().FindChildByName(animator->objectName);
1016       if(child)
1017       {
1018         Property::Index propertyIndex = child.GetPropertyIndex(animator->propertyKey);
1019         if(propertyIndex != Property::INVALID_INDEX)
1020         {
1021           if(animator->animate == false)
1022           {
1023             if(animator->targetValue.GetType() != Property::NONE)
1024             {
1025               child.SetProperty(propertyIndex, animator->targetValue);
1026             }
1027           }
1028           else // animate the property
1029           {
1030             if(animator->initialValue.GetType() != Property::NONE)
1031             {
1032               child.SetProperty(propertyIndex, animator->initialValue);
1033             }
1034
1035             if(createAnimation && !animation)
1036             {
1037               animation = Dali::Animation::New(0.1f);
1038             }
1039
1040             animation.AnimateTo(Property(child, propertyIndex),
1041                                 animator->targetValue,
1042                                 animator->alphaFunction,
1043                                 TimePeriod(animator->timePeriodDelay,
1044                                            animator->timePeriodDuration));
1045           }
1046         }
1047       }
1048     }
1049   }
1050 }
1051
1052 Dali::Animation Control::Impl::CreateTransition(const Toolkit::TransitionData& transitionData)
1053 {
1054   Dali::Animation transition;
1055
1056   if(transitionData.Count() > 0)
1057   {
1058     AddTransitions(transition, transitionData, true);
1059   }
1060   return transition;
1061 }
1062
1063 void Control::Impl::DoAction(Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes)
1064 {
1065   RegisteredVisualContainer::Iterator iter;
1066   if(FindVisual(visualIndex, mVisuals, iter))
1067   {
1068     Toolkit::GetImplementation((*iter)->visual).DoAction(actionId, attributes);
1069   }
1070 }
1071
1072 void Control::Impl::AppendAccessibilityAttribute(const std::string& key, const std::string value)
1073 {
1074   Property::Value* checkedValue = mAccessibilityAttributes.Find(key);
1075   if(checkedValue)
1076   {
1077     mAccessibilityAttributes[key] = Property::Value(value);
1078   }
1079   else
1080   {
1081     mAccessibilityAttributes.Insert(key, value);
1082   }
1083 }
1084
1085 void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
1086 {
1087   Toolkit::Control control = Toolkit::Control::DownCast(BaseHandle(object));
1088
1089   if(control)
1090   {
1091     Control& controlImpl(GetImplementation(control));
1092
1093     switch(index)
1094     {
1095       case Toolkit::Control::Property::STYLE_NAME:
1096       {
1097         controlImpl.SetStyleName(value.Get<std::string>());
1098         break;
1099       }
1100
1101       case Toolkit::DevelControl::Property::STATE:
1102       {
1103         bool                   withTransitions = true;
1104         const Property::Value* valuePtr        = &value;
1105         const Property::Map*   map             = value.GetMap();
1106         if(map)
1107         {
1108           Property::Value* value2 = map->Find("withTransitions");
1109           if(value2)
1110           {
1111             withTransitions = value2->Get<bool>();
1112           }
1113
1114           valuePtr = map->Find("state");
1115         }
1116
1117         if(valuePtr)
1118         {
1119           Toolkit::DevelControl::State state(controlImpl.mImpl->mState);
1120           if(Scripting::GetEnumerationProperty<Toolkit::DevelControl::State>(*valuePtr, ControlStateTable, ControlStateTableCount, state))
1121           {
1122             controlImpl.mImpl->SetState(state, withTransitions);
1123           }
1124         }
1125       }
1126       break;
1127
1128       case Toolkit::DevelControl::Property::SUB_STATE:
1129       {
1130         std::string subState;
1131         if(value.Get(subState))
1132         {
1133           controlImpl.mImpl->SetSubState(subState);
1134         }
1135       }
1136       break;
1137
1138       case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
1139       {
1140         int focusId;
1141         if(value.Get(focusId))
1142         {
1143           controlImpl.mImpl->mLeftFocusableActorId = focusId;
1144         }
1145       }
1146       break;
1147
1148       case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
1149       {
1150         int focusId;
1151         if(value.Get(focusId))
1152         {
1153           controlImpl.mImpl->mRightFocusableActorId = focusId;
1154         }
1155       }
1156       break;
1157
1158       case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
1159       {
1160         int focusId;
1161         if(value.Get(focusId))
1162         {
1163           controlImpl.mImpl->mUpFocusableActorId = focusId;
1164         }
1165       }
1166       break;
1167
1168       case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
1169       {
1170         int focusId;
1171         if(value.Get(focusId))
1172         {
1173           controlImpl.mImpl->mDownFocusableActorId = focusId;
1174         }
1175       }
1176       break;
1177
1178       case Toolkit::Control::Property::KEY_INPUT_FOCUS:
1179       {
1180         if(value.Get<bool>())
1181         {
1182           controlImpl.SetKeyInputFocus();
1183         }
1184         else
1185         {
1186           controlImpl.ClearKeyInputFocus();
1187         }
1188         break;
1189       }
1190
1191       case Toolkit::Control::Property::BACKGROUND:
1192       {
1193         std::string          url;
1194         Vector4              color;
1195         const Property::Map* map = value.GetMap();
1196         if(map && !map->Empty())
1197         {
1198           controlImpl.SetBackground(*map);
1199         }
1200         else if(value.Get(url))
1201         {
1202           // don't know the size to load
1203           Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual(url, ImageDimensions());
1204           if(visual)
1205           {
1206             controlImpl.mImpl->RegisterVisual(Toolkit::Control::Property::BACKGROUND, visual, DepthIndex::BACKGROUND);
1207           }
1208         }
1209         else if(value.Get(color))
1210         {
1211           controlImpl.SetBackgroundColor(color);
1212         }
1213         else
1214         {
1215           // The background is an empty property map, so we should clear the background
1216           controlImpl.ClearBackground();
1217         }
1218         break;
1219       }
1220
1221       case Toolkit::Control::Property::MARGIN:
1222       {
1223         Extents margin;
1224         if(value.Get(margin))
1225         {
1226           controlImpl.mImpl->SetMargin(margin);
1227         }
1228         break;
1229       }
1230
1231       case Toolkit::Control::Property::PADDING:
1232       {
1233         Extents padding;
1234         if(value.Get(padding))
1235         {
1236           controlImpl.mImpl->SetPadding(padding);
1237         }
1238         break;
1239       }
1240
1241       case Toolkit::DevelControl::Property::TOOLTIP:
1242       {
1243         TooltipPtr& tooltipPtr = controlImpl.mImpl->mTooltip;
1244         if(!tooltipPtr)
1245         {
1246           tooltipPtr = Tooltip::New(control);
1247         }
1248         tooltipPtr->SetProperties(value);
1249         break;
1250       }
1251
1252       case Toolkit::DevelControl::Property::SHADOW:
1253       {
1254         const Property::Map* map = value.GetMap();
1255         if(map && !map->Empty())
1256         {
1257           controlImpl.mImpl->SetShadow(*map);
1258         }
1259         else
1260         {
1261           // The shadow is an empty property map, so we should clear the shadow
1262           controlImpl.mImpl->ClearShadow();
1263         }
1264         break;
1265       }
1266
1267       case Toolkit::DevelControl::Property::ACCESSIBILITY_NAME:
1268       {
1269         std::string name;
1270         if(value.Get(name))
1271         {
1272           controlImpl.mImpl->mAccessibilityName    = name;
1273           controlImpl.mImpl->mAccessibilityNameSet = true;
1274         }
1275         else
1276         {
1277           controlImpl.mImpl->mAccessibilityNameSet = false;
1278         }
1279       }
1280       break;
1281
1282       case Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION:
1283       {
1284         std::string text;
1285         if(value.Get(text))
1286         {
1287           controlImpl.mImpl->mAccessibilityDescription    = text;
1288           controlImpl.mImpl->mAccessibilityDescriptionSet = true;
1289         }
1290         else
1291         {
1292           controlImpl.mImpl->mAccessibilityDescriptionSet = false;
1293         }
1294       }
1295       break;
1296
1297       case Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN:
1298       {
1299         std::string text;
1300         if(value.Get(text))
1301         {
1302           controlImpl.mImpl->mAccessibilityTranslationDomain    = text;
1303           controlImpl.mImpl->mAccessibilityTranslationDomainSet = true;
1304         }
1305         else
1306         {
1307           controlImpl.mImpl->mAccessibilityTranslationDomainSet = false;
1308         }
1309       }
1310       break;
1311
1312       case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE:
1313       {
1314         Dali::Accessibility::Role role;
1315         if(value.Get(role))
1316         {
1317           controlImpl.mImpl->mAccessibilityRole = role;
1318         }
1319       }
1320       break;
1321
1322       case Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE:
1323       {
1324         bool highlightable;
1325         if(value.Get(highlightable))
1326         {
1327           controlImpl.mImpl->mAccessibilityHighlightable    = highlightable;
1328           controlImpl.mImpl->mAccessibilityHighlightableSet = true;
1329         }
1330         else
1331         {
1332           controlImpl.mImpl->mAccessibilityHighlightableSet = false;
1333         }
1334       }
1335       break;
1336
1337       case Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES:
1338       {
1339         const Property::Map* map = value.GetMap();
1340         if(map && !map->Empty())
1341         {
1342           controlImpl.mImpl->mAccessibilityAttributes = *map;
1343         }
1344         break;
1345       }
1346     }
1347   }
1348 }
1349
1350 Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index index)
1351 {
1352   Property::Value value;
1353
1354   Toolkit::Control control = Toolkit::Control::DownCast(BaseHandle(object));
1355
1356   if(control)
1357   {
1358     Control& controlImpl(GetImplementation(control));
1359
1360     switch(index)
1361     {
1362       case Toolkit::Control::Property::STYLE_NAME:
1363       {
1364         value = controlImpl.GetStyleName();
1365         break;
1366       }
1367
1368       case Toolkit::DevelControl::Property::STATE:
1369       {
1370         value = controlImpl.mImpl->mState;
1371         break;
1372       }
1373
1374       case Toolkit::DevelControl::Property::SUB_STATE:
1375       {
1376         value = controlImpl.mImpl->mSubStateName;
1377         break;
1378       }
1379
1380       case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
1381       {
1382         value = controlImpl.mImpl->mLeftFocusableActorId;
1383         break;
1384       }
1385
1386       case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
1387       {
1388         value = controlImpl.mImpl->mRightFocusableActorId;
1389         break;
1390       }
1391
1392       case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
1393       {
1394         value = controlImpl.mImpl->mUpFocusableActorId;
1395         break;
1396       }
1397
1398       case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
1399       {
1400         value = controlImpl.mImpl->mDownFocusableActorId;
1401         break;
1402       }
1403
1404       case Toolkit::Control::Property::KEY_INPUT_FOCUS:
1405       {
1406         value = controlImpl.HasKeyInputFocus();
1407         break;
1408       }
1409
1410       case Toolkit::Control::Property::BACKGROUND:
1411       {
1412         Property::Map         map;
1413         Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual(Toolkit::Control::Property::BACKGROUND);
1414         if(visual)
1415         {
1416           visual.CreatePropertyMap(map);
1417         }
1418
1419         value = map;
1420         break;
1421       }
1422
1423       case Toolkit::Control::Property::MARGIN:
1424       {
1425         value = controlImpl.mImpl->GetMargin();
1426         break;
1427       }
1428
1429       case Toolkit::Control::Property::PADDING:
1430       {
1431         value = controlImpl.mImpl->GetPadding();
1432         break;
1433       }
1434
1435       case Toolkit::DevelControl::Property::TOOLTIP:
1436       {
1437         Property::Map map;
1438         if(controlImpl.mImpl->mTooltip)
1439         {
1440           controlImpl.mImpl->mTooltip->CreatePropertyMap(map);
1441         }
1442         value = map;
1443         break;
1444       }
1445
1446       case Toolkit::DevelControl::Property::SHADOW:
1447       {
1448         Property::Map         map;
1449         Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual(Toolkit::DevelControl::Property::SHADOW);
1450         if(visual)
1451         {
1452           visual.CreatePropertyMap(map);
1453         }
1454
1455         value = map;
1456         break;
1457       }
1458
1459       case Toolkit::DevelControl::Property::ACCESSIBILITY_NAME:
1460       {
1461         if(controlImpl.mImpl->mAccessibilityNameSet)
1462         {
1463           value = controlImpl.mImpl->mAccessibilityName;
1464         }
1465         break;
1466       }
1467
1468       case Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION:
1469       {
1470         if(controlImpl.mImpl->mAccessibilityDescriptionSet)
1471         {
1472           value = controlImpl.mImpl->mAccessibilityDescription;
1473         }
1474         break;
1475       }
1476
1477       case Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN:
1478       {
1479         if(controlImpl.mImpl->mAccessibilityTranslationDomainSet)
1480         {
1481           value = controlImpl.mImpl->mAccessibilityTranslationDomain;
1482         }
1483         break;
1484       }
1485
1486       case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE:
1487       {
1488         value = Property::Value(controlImpl.mImpl->mAccessibilityRole);
1489         break;
1490       }
1491
1492       case Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE:
1493       {
1494         if(controlImpl.mImpl->mAccessibilityHighlightableSet)
1495         {
1496           value = controlImpl.mImpl->mAccessibilityHighlightable;
1497         }
1498         break;
1499       }
1500
1501       case Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES:
1502       {
1503         value = controlImpl.mImpl->mAccessibilityAttributes;
1504         break;
1505       }
1506     }
1507   }
1508
1509   return value;
1510 }
1511
1512 void Control::Impl::RemoveAccessibilityAttribute(const std::string& key)
1513 {
1514   Property::Value* value = mAccessibilityAttributes.Find(key);
1515   if(value)
1516   {
1517     mAccessibilityAttributes[key] = Property::Value();
1518   }
1519 }
1520
1521 void Control::Impl::ClearAccessibilityAttributes()
1522 {
1523   mAccessibilityAttributes.Clear();
1524 }
1525
1526 void Control::Impl::SetAccessibilityReadingInfoType(const Dali::Accessibility::ReadingInfoTypes types)
1527 {
1528   std::string value{};
1529   if(types[Dali::Accessibility::ReadingInfoType::NAME])
1530   {
1531     value += READING_INFO_TYPE_NAME;
1532   }
1533   if(types[Dali::Accessibility::ReadingInfoType::ROLE])
1534   {
1535     if(!value.empty())
1536     {
1537       value += READING_INFO_TYPE_SEPARATOR;
1538     }
1539     value += READING_INFO_TYPE_ROLE;
1540   }
1541   if(types[Dali::Accessibility::ReadingInfoType::DESCRIPTION])
1542   {
1543     if(!value.empty())
1544     {
1545       value += READING_INFO_TYPE_SEPARATOR;
1546     }
1547     value += READING_INFO_TYPE_DESCRIPTION;
1548   }
1549   if(types[Dali::Accessibility::ReadingInfoType::STATE])
1550   {
1551     if(!value.empty())
1552     {
1553       value += READING_INFO_TYPE_SEPARATOR;
1554     }
1555     value += READING_INFO_TYPE_STATE;
1556   }
1557   AppendAccessibilityAttribute(READING_INFO_TYPE_ATTRIBUTE_NAME, value);
1558 }
1559
1560 Dali::Accessibility::ReadingInfoTypes Control::Impl::GetAccessibilityReadingInfoType() const
1561 {
1562   std::string value{};
1563   auto        place = mAccessibilityAttributes.Find(READING_INFO_TYPE_ATTRIBUTE_NAME);
1564   if(place)
1565   {
1566     place->Get(value);
1567   }
1568   else
1569   {
1570     Dali::Accessibility::ReadingInfoTypes types;
1571     types[Dali::Accessibility::ReadingInfoType::NAME]        = true;
1572     types[Dali::Accessibility::ReadingInfoType::ROLE]        = true;
1573     types[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
1574     types[Dali::Accessibility::ReadingInfoType::STATE]       = true;
1575     return types;
1576   }
1577
1578   if(value.empty())
1579   {
1580     return {};
1581   }
1582
1583   Dali::Accessibility::ReadingInfoTypes types;
1584
1585   if(value.find(READING_INFO_TYPE_NAME) != std::string::npos)
1586   {
1587     types[Dali::Accessibility::ReadingInfoType::NAME] = true;
1588   }
1589   if(value.find(READING_INFO_TYPE_ROLE) != std::string::npos)
1590   {
1591     types[Dali::Accessibility::ReadingInfoType::ROLE] = true;
1592   }
1593   if(value.find(READING_INFO_TYPE_DESCRIPTION) != std::string::npos)
1594   {
1595     types[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
1596   }
1597   if(value.find(READING_INFO_TYPE_STATE) != std::string::npos)
1598   {
1599     types[Dali::Accessibility::ReadingInfoType::STATE] = true;
1600   }
1601
1602   return types;
1603 }
1604
1605 void Control::Impl::CopyInstancedProperties(RegisteredVisualContainer& visuals, Dictionary<Property::Map>& instancedProperties)
1606 {
1607   for(RegisteredVisualContainer::Iterator iter = visuals.Begin(); iter != visuals.End(); iter++)
1608   {
1609     if((*iter)->visual)
1610     {
1611       Property::Map instanceMap;
1612       Toolkit::GetImplementation((*iter)->visual).CreateInstancePropertyMap(instanceMap);
1613       instancedProperties.Add((*iter)->visual.GetName(), instanceMap);
1614     }
1615   }
1616 }
1617
1618 void Control::Impl::RemoveVisual(RegisteredVisualContainer& visuals, const std::string& visualName)
1619 {
1620   Actor self(mControlImpl.Self());
1621
1622   for(RegisteredVisualContainer::Iterator visualIter = visuals.Begin();
1623       visualIter != visuals.End();
1624       ++visualIter)
1625   {
1626     Toolkit::Visual::Base visual = (*visualIter)->visual;
1627     if(visual && visual.GetName() == visualName)
1628     {
1629       Toolkit::GetImplementation(visual).SetOffScene(self);
1630       (*visualIter)->visual.Reset();
1631       visuals.Erase(visualIter);
1632       break;
1633     }
1634   }
1635 }
1636
1637 void Control::Impl::RemoveVisuals(RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals)
1638 {
1639   Actor self(mControlImpl.Self());
1640   for(DictionaryKeys::iterator iter = removeVisuals.begin(); iter != removeVisuals.end(); ++iter)
1641   {
1642     const std::string visualName = *iter;
1643     RemoveVisual(visuals, visualName);
1644   }
1645 }
1646
1647 void Control::Impl::RecreateChangedVisuals(Dictionary<Property::Map>& stateVisualsToChange,
1648                                            Dictionary<Property::Map>& instancedProperties)
1649 {
1650   Dali::CustomActor handle(mControlImpl.GetOwner());
1651   for(Dictionary<Property::Map>::iterator iter = stateVisualsToChange.Begin();
1652       iter != stateVisualsToChange.End();
1653       ++iter)
1654   {
1655     const std::string&   visualName = (*iter).key;
1656     const Property::Map& toMap      = (*iter).entry;
1657
1658     Actor                               self = mControlImpl.Self();
1659     RegisteredVisualContainer::Iterator registeredVisualsiter;
1660     // Check if visual (visualName) is already registered, this is the current visual.
1661     if(FindVisual(visualName, mVisuals, registeredVisualsiter))
1662     {
1663       Toolkit::Visual::Base& visual = (*registeredVisualsiter)->visual;
1664       if(visual)
1665       {
1666         // No longer required to know if the replaced visual's resources are ready
1667         StopObservingVisual(visual);
1668
1669         // If control staged then visuals will be swapped once ready
1670         if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
1671         {
1672           // Check if visual is currently in the process of being replaced ( is in removal container )
1673           RegisteredVisualContainer::Iterator visualQueuedForRemoval;
1674           if(FindVisual(visualName, mRemoveVisuals, visualQueuedForRemoval))
1675           {
1676             // Visual with same visual name is already in removal container so current visual pending
1677             // Only the the last requested visual will be displayed so remove current visual which is staged but not ready.
1678             Toolkit::GetImplementation(visual).SetOffScene(self);
1679             (*registeredVisualsiter)->visual.Reset();
1680             mVisuals.Erase(registeredVisualsiter);
1681           }
1682           else
1683           {
1684             // current visual not already in removal container so add now.
1685             DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %s \n", visualName.c_str());
1686             MoveVisual(registeredVisualsiter, mVisuals, mRemoveVisuals);
1687           }
1688         }
1689         else
1690         {
1691           // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later.
1692           (*registeredVisualsiter)->visual.Reset();
1693           mVisuals.Erase(registeredVisualsiter);
1694         }
1695       }
1696
1697       const Property::Map* instancedMap = instancedProperties.FindConst(visualName);
1698       Style::ApplyVisual(handle, visualName, toMap, instancedMap);
1699     }
1700   }
1701 }
1702
1703 void Control::Impl::ReplaceStateVisualsAndProperties(const StylePtr oldState, const StylePtr newState, const std::string& subState)
1704 {
1705   // Collect all old visual names
1706   DictionaryKeys stateVisualsToRemove;
1707   if(oldState)
1708   {
1709     oldState->visuals.GetKeys(stateVisualsToRemove);
1710     if(!subState.empty())
1711     {
1712       const StylePtr* oldSubState = oldState->subStates.FindConst(subState);
1713       if(oldSubState)
1714       {
1715         DictionaryKeys subStateVisualsToRemove;
1716         (*oldSubState)->visuals.GetKeys(subStateVisualsToRemove);
1717         Merge(stateVisualsToRemove, subStateVisualsToRemove);
1718       }
1719     }
1720   }
1721
1722   // Collect all new visual properties
1723   Dictionary<Property::Map> stateVisualsToAdd;
1724   if(newState)
1725   {
1726     stateVisualsToAdd = newState->visuals;
1727     if(!subState.empty())
1728     {
1729       const StylePtr* newSubState = newState->subStates.FindConst(subState);
1730       if(newSubState)
1731       {
1732         stateVisualsToAdd.Merge((*newSubState)->visuals);
1733       }
1734     }
1735   }
1736
1737   // If a name is in both add/remove, move it to change list.
1738   Dictionary<Property::Map> stateVisualsToChange;
1739   FindChangableVisuals(stateVisualsToAdd, stateVisualsToChange, stateVisualsToRemove);
1740
1741   // Copy instanced properties (e.g. text label) of current visuals
1742   Dictionary<Property::Map> instancedProperties;
1743   CopyInstancedProperties(mVisuals, instancedProperties);
1744
1745   // For each visual in remove list, remove from mVisuals
1746   RemoveVisuals(mVisuals, stateVisualsToRemove);
1747
1748   // For each visual in add list, create and add to mVisuals
1749   Dali::CustomActor handle(mControlImpl.GetOwner());
1750   Style::ApplyVisuals(handle, stateVisualsToAdd, instancedProperties);
1751
1752   // For each visual in change list, if it requires a new visual,
1753   // remove old visual, create and add to mVisuals
1754   RecreateChangedVisuals(stateVisualsToChange, instancedProperties);
1755 }
1756
1757 void Control::Impl::SetState(DevelControl::State newState, bool withTransitions)
1758 {
1759   DevelControl::State oldState = mState;
1760   Dali::CustomActor   handle(mControlImpl.GetOwner());
1761   DALI_LOG_INFO(gLogFilter, Debug::Concise, "Control::Impl::SetState: %s\n", (mState == DevelControl::NORMAL ? "NORMAL" : (mState == DevelControl::FOCUSED ? "FOCUSED" : (mState == DevelControl::DISABLED ? "DISABLED" : "NONE"))));
1762
1763   if(mState != newState)
1764   {
1765     // If mState was Disabled, and new state is Focused, should probably
1766     // store that fact, e.g. in another property that FocusManager can access.
1767     mState = newState;
1768
1769     // Trigger state change and transitions
1770     // Apply new style, if stylemanager is available
1771     Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
1772     if(styleManager)
1773     {
1774       const StylePtr stylePtr = GetImpl(styleManager).GetRecordedStyle(Toolkit::Control(mControlImpl.GetOwner()));
1775
1776       if(stylePtr)
1777       {
1778         std::string oldStateName = Scripting::GetEnumerationName<Toolkit::DevelControl::State>(oldState, ControlStateTable, ControlStateTableCount);
1779         std::string newStateName = Scripting::GetEnumerationName<Toolkit::DevelControl::State>(newState, ControlStateTable, ControlStateTableCount);
1780
1781         const StylePtr* newStateStyle = stylePtr->subStates.Find(newStateName);
1782         const StylePtr* oldStateStyle = stylePtr->subStates.Find(oldStateName);
1783         if(oldStateStyle && newStateStyle)
1784         {
1785           // Only change if both state styles exist
1786           ReplaceStateVisualsAndProperties(*oldStateStyle, *newStateStyle, mSubStateName);
1787         }
1788       }
1789     }
1790   }
1791 }
1792
1793 void Control::Impl::SetSubState(const std::string& subStateName, bool withTransitions)
1794 {
1795   if(mSubStateName != subStateName)
1796   {
1797     // Get existing sub-state visuals, and unregister them
1798     Dali::CustomActor handle(mControlImpl.GetOwner());
1799
1800     Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
1801     if(styleManager)
1802     {
1803       const StylePtr stylePtr = GetImpl(styleManager).GetRecordedStyle(Toolkit::Control(mControlImpl.GetOwner()));
1804       if(stylePtr)
1805       {
1806         // Stringify state
1807         std::string stateName = Scripting::GetEnumerationName<Toolkit::DevelControl::State>(mState, ControlStateTable, ControlStateTableCount);
1808
1809         const StylePtr* state = stylePtr->subStates.Find(stateName);
1810         if(state)
1811         {
1812           StylePtr stateStyle(*state);
1813
1814           const StylePtr* newStateStyle = stateStyle->subStates.Find(subStateName);
1815           const StylePtr* oldStateStyle = stateStyle->subStates.Find(mSubStateName);
1816           if(oldStateStyle && newStateStyle)
1817           {
1818             std::string empty;
1819             ReplaceStateVisualsAndProperties(*oldStateStyle, *newStateStyle, empty);
1820           }
1821         }
1822       }
1823     }
1824
1825     mSubStateName = subStateName;
1826   }
1827 }
1828
1829 void Control::Impl::OnSceneDisconnection()
1830 {
1831   Actor self = mControlImpl.Self();
1832
1833   // Any visuals set for replacement but not yet ready should still be registered.
1834   // Reason: If a request was made to register a new visual but the control removed from scene before visual was ready
1835   // then when this control appears back on stage it should use that new visual.
1836
1837   // Iterate through all registered visuals and set off scene
1838   SetVisualsOffScene(mVisuals, self);
1839
1840   // Visuals pending replacement can now be taken out of the removal list and set off scene
1841   // Iterate through all replacement visuals and add to a move queue then set off scene
1842   for(auto removalIter = mRemoveVisuals.Begin(), end = mRemoveVisuals.End(); removalIter != end; removalIter++)
1843   {
1844     Toolkit::GetImplementation((*removalIter)->visual).SetOffScene(self);
1845   }
1846
1847   for(auto replacedIter = mVisuals.Begin(), end = mVisuals.End(); replacedIter != end; replacedIter++)
1848   {
1849     (*replacedIter)->pending = false;
1850   }
1851
1852   mRemoveVisuals.Clear();
1853 }
1854
1855 void Control::Impl::SetMargin(Extents margin)
1856 {
1857   mControlImpl.mImpl->mMargin = margin;
1858
1859   // Trigger a size negotiation request that may be needed when setting a margin.
1860   mControlImpl.RelayoutRequest();
1861 }
1862
1863 Extents Control::Impl::GetMargin() const
1864 {
1865   return mControlImpl.mImpl->mMargin;
1866 }
1867
1868 void Control::Impl::SetPadding(Extents padding)
1869 {
1870   mControlImpl.mImpl->mPadding = padding;
1871
1872   // Trigger a size negotiation request that may be needed when setting a padding.
1873   mControlImpl.RelayoutRequest();
1874 }
1875
1876 Extents Control::Impl::GetPadding() const
1877 {
1878   return mControlImpl.mImpl->mPadding;
1879 }
1880
1881 void Control::Impl::SetInputMethodContext(InputMethodContext& inputMethodContext)
1882 {
1883   mInputMethodContext = inputMethodContext;
1884 }
1885
1886 bool Control::Impl::FilterKeyEvent(const KeyEvent& event)
1887 {
1888   bool consumed(false);
1889
1890   if(mInputMethodContext)
1891   {
1892     consumed = mInputMethodContext.FilterEventKey(event);
1893   }
1894   return consumed;
1895 }
1896
1897 DevelControl::VisualEventSignalType& Control::Impl::VisualEventSignal()
1898 {
1899   return mVisualEventSignal;
1900 }
1901
1902 void Control::Impl::SetShadow(const Property::Map& map)
1903 {
1904   Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual(map);
1905   visual.SetName("shadow");
1906
1907   if(visual)
1908   {
1909     mControlImpl.mImpl->RegisterVisual(Toolkit::DevelControl::Property::SHADOW, visual, DepthIndex::BACKGROUND_EFFECT);
1910
1911     mControlImpl.RelayoutRequest();
1912   }
1913 }
1914
1915 void Control::Impl::ClearShadow()
1916 {
1917   mControlImpl.mImpl->UnregisterVisual(Toolkit::DevelControl::Property::SHADOW);
1918
1919   // Trigger a size negotiation request that may be needed when unregistering a visual.
1920   mControlImpl.RelayoutRequest();
1921 }
1922
1923 Dali::Property Control::Impl::GetVisualProperty(Dali::Property::Index index, Dali::Property::Key visualPropertyKey)
1924 {
1925   Toolkit::Visual::Base visual = GetVisualByIndex(mVisuals, index);
1926   if(visual)
1927   {
1928     Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
1929     return visualImpl.GetPropertyObject(visualPropertyKey);
1930   }
1931
1932   Handle handle;
1933   return Dali::Property(handle, Property::INVALID_INDEX);
1934 }
1935
1936 void Control::Impl::MakeVisualTransition(Dali::Animation& animation, Dali::Toolkit::Control source, Dali::Property::Index visualIndex, AlphaFunction alphaFunction, TimePeriod timePeriod)
1937 {
1938   Dali::Toolkit::Control sourceHandle      = Dali::Toolkit::Control::DownCast(source);
1939   Property::Map          sourceMap         = sourceHandle.GetProperty<Property::Map>(visualIndex);
1940   Dali::Toolkit::Control destinationHandle = Dali::Toolkit::Control::DownCast(mControlImpl.Self());
1941   Property::Map          destinationMap    = destinationHandle.GetProperty<Property::Map>(visualIndex);
1942
1943   Vector4 mixColor(1.0f, 1.0f, 1.0f, 1.0f);
1944   Vector4 cornerRadius(0.0f, 0.0f, 0.0f, 0.0f);
1945   float   borderlineWidth(0.0f);
1946   Vector4 borderlineColor(0.0f, 0.0f, 0.0f, 1.0f);
1947   float   borderlineOffset(0.0f);
1948
1949   if(!destinationMap.Empty())
1950   {
1951     static auto findValueVector4 = [](const Property::Map& map, Property::Index index, const Vector4& defaultValue = Vector4()) -> Vector4 {
1952       Property::Value* propertyValue = map.Find(index);
1953       if(propertyValue)
1954       {
1955         return propertyValue->Get<Vector4>();
1956       }
1957       return defaultValue;
1958     };
1959
1960     static auto findValueFloat = [](const Property::Map& map, Property::Index index, const float& defaultValue = 0.0f) -> float {
1961       Property::Value* propertyValue = map.Find(index);
1962       if(propertyValue)
1963       {
1964         return propertyValue->Get<float>();
1965       }
1966       return defaultValue;
1967     };
1968
1969     mixColor         = findValueVector4(destinationMap, Dali::Toolkit::Visual::Property::MIX_COLOR, mixColor);
1970     cornerRadius     = findValueVector4(destinationMap, Toolkit::DevelVisual::Property::CORNER_RADIUS, cornerRadius);
1971     borderlineWidth  = findValueFloat(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth);
1972     borderlineColor  = findValueVector4(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_COLOR, borderlineColor);
1973     borderlineOffset = findValueFloat(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset);
1974
1975     if(sourceMap.Empty())
1976     {
1977       sourceMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
1978       sourceMap.Insert(Dali::Toolkit::Visual::Property::MIX_COLOR, Color::TRANSPARENT);
1979       sourceMap.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, cornerRadius);
1980       sourceMap.Insert(Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth);
1981       sourceMap.Insert(Toolkit::DevelVisual::Property::BORDERLINE_COLOR, borderlineColor);
1982       sourceMap.Insert(Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset);
1983     }
1984
1985     Vector4 sourceMixColor         = findValueVector4(sourceMap, Dali::Toolkit::Visual::Property::MIX_COLOR, mixColor);
1986     Vector4 sourceCornerRadius     = findValueVector4(sourceMap, Toolkit::DevelVisual::Property::CORNER_RADIUS, cornerRadius);
1987     float   sourceBorderlineWidth  = findValueFloat(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth);
1988     Vector4 sourceBorderlineColor  = findValueVector4(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_COLOR, borderlineColor);
1989     float   sourceBorderlineOffset = findValueFloat(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset);
1990
1991     std::vector<Dali::Property>                              properties;
1992     std::vector<std::pair<Property::Value, Property::Value>> values;
1993
1994     if(Vector3(sourceMixColor) != Vector3(mixColor))
1995     {
1996       properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::Visual::Property::MIX_COLOR));
1997       values.push_back(std::make_pair(Vector3(sourceMixColor), Vector3(mixColor)));
1998     }
1999
2000     if(std::abs(sourceMixColor.a - mixColor.a) > Math::MACHINE_EPSILON_1)
2001     {
2002       properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::Visual::Property::OPACITY));
2003       values.push_back(std::make_pair(sourceMixColor.a, mixColor.a));
2004     }
2005
2006     if(sourceCornerRadius != cornerRadius)
2007     {
2008       properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::CORNER_RADIUS));
2009       values.push_back(std::make_pair(sourceCornerRadius, cornerRadius));
2010     }
2011
2012     if(sourceBorderlineWidth != borderlineWidth)
2013     {
2014       properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::BORDERLINE_WIDTH));
2015       values.push_back(std::make_pair(sourceBorderlineWidth, borderlineWidth));
2016     }
2017
2018     if(sourceBorderlineColor != borderlineColor)
2019     {
2020       properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::BORDERLINE_COLOR));
2021       values.push_back(std::make_pair(sourceBorderlineColor, borderlineColor));
2022     }
2023
2024     if(sourceBorderlineOffset != borderlineOffset)
2025     {
2026       properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::BORDERLINE_OFFSET));
2027       values.push_back(std::make_pair(sourceBorderlineOffset, borderlineOffset));
2028     }
2029
2030     for(uint32_t i = 0; i < properties.size(); ++i)
2031     {
2032       if(timePeriod.delaySeconds > 0.0f)
2033       {
2034         Dali::KeyFrames initialKeyframes = Dali::KeyFrames::New();
2035         initialKeyframes.Add(0.0f, values[i].first);
2036         initialKeyframes.Add(1.0f, values[i].first);
2037         animation.AnimateBetween(properties[i], initialKeyframes, TimePeriod(timePeriod.delaySeconds));
2038       }
2039       Dali::KeyFrames keyframes = Dali::KeyFrames::New();
2040       keyframes.Add(0.0f, values[i].first);
2041       keyframes.Add(1.0f, values[i].second);
2042       animation.AnimateBetween(properties[i], keyframes, alphaFunction, timePeriod);
2043     }
2044   }
2045 }
2046
2047 void Control::Impl::EmitResourceReadySignal()
2048 {
2049   if(!mIsEmittingResourceReadySignal)
2050   {
2051     // Guard against calls to emit the signal during the callback
2052     mIsEmittingResourceReadySignal = true;
2053
2054     // If the signal handler changes visual, it may become ready during this call & therefore this method will
2055     // get called again recursively. If so, mNeedToEmitResourceReady is set below, and we act on it after that secondary
2056     // invocation has completed by notifying in an Idle callback to prevent further recursion.
2057     Dali::Toolkit::Control handle(mControlImpl.GetOwner());
2058     mResourceReadySignal.Emit(handle);
2059
2060     if(mNeedToEmitResourceReady)
2061     {
2062       // Add idler to emit the signal again
2063       if(!mIdleCallback)
2064       {
2065         // The callback manager takes the ownership of the callback object.
2066         mIdleCallback = MakeCallback(this, &Control::Impl::OnIdleCallback);
2067         Adaptor::Get().AddIdle(mIdleCallback, false);
2068       }
2069     }
2070
2071     mIsEmittingResourceReadySignal = false;
2072   }
2073   else
2074   {
2075     mNeedToEmitResourceReady = true;
2076   }
2077 }
2078
2079 void Control::Impl::OnIdleCallback()
2080 {
2081   if(mNeedToEmitResourceReady)
2082   {
2083     // Reset the flag
2084     mNeedToEmitResourceReady = false;
2085
2086     // A visual is ready so control may need relayouting if staged
2087     if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
2088     {
2089       mControlImpl.RelayoutRequest();
2090     }
2091
2092     EmitResourceReadySignal();
2093   }
2094
2095   // Set the pointer to null as the callback manager deletes the callback after execute it.
2096   mIdleCallback = nullptr;
2097 }
2098
2099 Dali::Accessibility::Accessible* Control::Impl::GetAccessibilityObject()
2100 {
2101   if(!mAccessibilityObject)
2102   {
2103     mAccessibilityObject = mAccessibilityConstructor(mControlImpl.Self());
2104   }
2105   return mAccessibilityObject.get();
2106 }
2107
2108 Dali::Accessibility::Accessible* Control::Impl::GetAccessibilityObject(Dali::Actor actor)
2109 {
2110   if(actor)
2111   {
2112     auto control = Dali::Toolkit::Control::DownCast(actor);
2113     if(control)
2114     {
2115       auto controlImpl = static_cast<Internal::Control*>(&control.GetImplementation());
2116       return controlImpl->mImpl->GetAccessibilityObject();
2117     }
2118   }
2119   return nullptr;
2120 }
2121
2122 } // namespace Internal
2123
2124 } // namespace Toolkit
2125
2126 } // namespace Dali