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