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