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