2 * Copyright (c) 2024 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "control-data-impl.h"
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/math/math-utils.h>
34 #include <dali/public-api/object/object-registry.h>
35 #include <dali/public-api/object/type-registry-helper.h>
40 #include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
41 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
42 #include <dali-toolkit/devel-api/controls/control-devel.h>
43 #include <dali-toolkit/devel-api/controls/control-wrapper-impl.h>
44 #include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
45 #include <dali-toolkit/internal/styling/style-manager-impl.h>
46 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
47 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
48 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
49 #include <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
50 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
51 #include <dali-toolkit/public-api/visuals/visual-properties.h>
55 const char* READING_INFO_TYPE_NAME = "name";
56 const char* READING_INFO_TYPE_ROLE = "role";
57 const char* READING_INFO_TYPE_DESCRIPTION = "description";
58 const char* READING_INFO_TYPE_STATE = "state";
59 const char* READING_INFO_TYPE_ATTRIBUTE_NAME = "reading_info_type";
60 const char* READING_INFO_TYPE_SEPARATOR = "|";
69 extern const Dali::Scripting::StringEnum ControlStateTable[];
70 extern const unsigned int ControlStateTableCount;
72 // Not static or anonymous - shared with other translation units
73 const Scripting::StringEnum ControlStateTable[] = {
74 {"NORMAL", Toolkit::DevelControl::NORMAL},
75 {"FOCUSED", Toolkit::DevelControl::FOCUSED},
76 {"DISABLED", Toolkit::DevelControl::DISABLED},
78 const unsigned int ControlStateTableCount = sizeof(ControlStateTable) / sizeof(ControlStateTable[0]);
82 #if defined(DEBUG_ENABLED)
83 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_CONTROL_VISUALS");
87 void Remove(Dictionary<T>& keyValues, const std::string& name)
89 keyValues.Remove(name);
92 void Remove(DictionaryKeys& keys, const std::string& name)
94 DictionaryKeys::iterator iter = std::find(keys.begin(), keys.end(), name);
95 if(iter != keys.end())
102 * Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
104 bool FindVisual(Property::Index targetIndex, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter)
106 for(iter = visuals.Begin(); iter != visuals.End(); iter++)
108 if((*iter)->index == targetIndex)
117 * Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
119 bool FindVisual(std::string visualName, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter)
121 for(iter = visuals.Begin(); iter != visuals.End(); iter++)
123 Toolkit::Visual::Base visual = (*iter)->visual;
124 if(visual && visual.GetName() == visualName)
133 * Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
135 bool FindVisual(const Toolkit::Visual::Base findVisual, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter)
137 for(iter = visuals.Begin(); iter != visuals.End(); iter++)
139 Toolkit::Visual::Base visual = (*iter)->visual;
140 if(visual && visual == findVisual)
149 * Finds internal visual in given array, returning true if found along with the iterator for that visual as a out parameter
151 bool FindVisual(const Visual::Base& findInternalVisual, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter)
153 for(iter = visuals.Begin(); iter != visuals.End(); iter++)
155 Visual::Base& visual = Toolkit::GetImplementation((*iter)->visual);
156 if((&visual == &findInternalVisual))
164 void FindChangableVisuals(Dictionary<Property::Map>& stateVisualsToAdd,
165 Dictionary<Property::Map>& stateVisualsToChange,
166 DictionaryKeys& stateVisualsToRemove)
168 DictionaryKeys copyOfStateVisualsToRemove = stateVisualsToRemove;
170 for(DictionaryKeys::iterator iter = copyOfStateVisualsToRemove.begin();
171 iter != copyOfStateVisualsToRemove.end();
174 const std::string& visualName = (*iter);
175 Property::Map* toMap = stateVisualsToAdd.Find(visualName);
178 stateVisualsToChange.Add(visualName, *toMap);
179 stateVisualsToAdd.Remove(visualName);
180 Remove(stateVisualsToRemove, visualName);
185 Toolkit::Visual::Base GetVisualByName(
186 const RegisteredVisualContainer& visuals,
187 const std::string& visualName)
189 Toolkit::Visual::Base visualHandle;
191 RegisteredVisualContainer::Iterator iter;
192 for(iter = visuals.Begin(); iter != visuals.End(); iter++)
194 Toolkit::Visual::Base visual = (*iter)->visual;
195 if(visual && visual.GetName() == visualName)
197 visualHandle = visual;
204 Toolkit::Visual::Base GetVisualByIndex(
205 const RegisteredVisualContainer& visuals,
206 Property::Index index)
208 Toolkit::Visual::Base visualHandle;
210 RegisteredVisualContainer::Iterator iter;
211 for(iter = visuals.Begin(); iter != visuals.End(); iter++)
213 if((*iter)->index == index)
215 visualHandle = (*iter)->visual;
223 * Move visual from source to destination container
225 void MoveVisual(RegisteredVisualContainer::Iterator sourceIter, RegisteredVisualContainer& source, RegisteredVisualContainer& destination)
227 Toolkit::Visual::Base visual = (*sourceIter)->visual;
230 RegisteredVisual* rv = source.Release(sourceIter);
231 destination.PushBack(rv);
236 * Discard visual from source to visual factory.
238 void DiscardVisual(RegisteredVisualContainer::Iterator sourceIter, RegisteredVisualContainer& source)
240 Toolkit::Visual::Base visual = (*sourceIter)->visual;
243 if(Stage::IsInstalled())
245 Toolkit::VisualFactory::Get().DiscardVisual(visual);
249 source.Erase(sourceIter);
253 * Performs actions as requested using the action name.
254 * @param[in] object The object on which to perform the action.
255 * @param[in] actionName The action to perform.
256 * @param[in] attributes The attributes with which to perfrom this action.
257 * @return true if action has been accepted by this control
259 const char* ACTION_ACCESSIBILITY_ACTIVATED = "accessibilityActivated";
260 const char* ACTION_ACCESSIBILITY_READING_CANCELLED = "ReadingCancelled";
261 const char* ACTION_ACCESSIBILITY_READING_PAUSED = "ReadingPaused";
262 const char* ACTION_ACCESSIBILITY_READING_RESUMED = "ReadingResumed";
263 const char* ACTION_ACCESSIBILITY_READING_SKIPPED = "ReadingSkipped";
264 const char* ACTION_ACCESSIBILITY_READING_STOPPED = "ReadingStopped";
266 static bool DoAction(BaseObject* object, const std::string& actionName, const Property::Map& attributes)
270 Dali::BaseHandle handle(object);
272 Toolkit::Control control = Toolkit::Control::DownCast(handle);
274 DALI_ASSERT_ALWAYS(control);
276 if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_ACTIVATED) || actionName == "activate")
278 // if cast succeeds there is an implementation so no need to check
279 if(!DevelControl::AccessibilityActivateSignal(control).Empty())
281 DevelControl::AccessibilityActivateSignal(control).Emit();
285 ret = Internal::GetImplementation(control).OnAccessibilityActivated();
288 else if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_READING_SKIPPED))
290 // if cast succeeds there is an implementation so no need to check
291 if(!DevelControl::AccessibilityReadingSkippedSignal(control).Empty())
293 DevelControl::AccessibilityReadingSkippedSignal(control).Emit();
296 else if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_READING_PAUSED))
298 // if cast succeeds there is an implementation so no need to check
299 if(!DevelControl::AccessibilityReadingPausedSignal(control).Empty())
301 DevelControl::AccessibilityReadingPausedSignal(control).Emit();
304 else if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_READING_RESUMED))
306 // if cast succeeds there is an implementation so no need to check
307 if(!DevelControl::AccessibilityReadingResumedSignal(control).Empty())
309 DevelControl::AccessibilityReadingResumedSignal(control).Emit();
312 else if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_READING_CANCELLED))
314 // if cast succeeds there is an implementation so no need to check
315 if(!DevelControl::AccessibilityReadingCancelledSignal(control).Empty())
317 DevelControl::AccessibilityReadingCancelledSignal(control).Emit();
320 else if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_READING_STOPPED))
322 // if cast succeeds there is an implementation so no need to check
323 if(!DevelControl::AccessibilityReadingStoppedSignal(control).Empty())
325 DevelControl::AccessibilityReadingStoppedSignal(control).Emit();
336 * Connects a callback function with the object's signals.
337 * @param[in] object The object providing the signal.
338 * @param[in] tracker Used to disconnect the signal.
339 * @param[in] signalName The signal to connect to.
340 * @param[in] functor A newly allocated FunctorDelegate.
341 * @return True if the signal was connected.
342 * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
344 const char* SIGNAL_KEY_EVENT = "keyEvent";
345 const char* SIGNAL_KEY_INPUT_FOCUS_GAINED = "keyInputFocusGained";
346 const char* SIGNAL_KEY_INPUT_FOCUS_LOST = "keyInputFocusLost";
347 const char* SIGNAL_TAPPED = "tapped";
348 const char* SIGNAL_PANNED = "panned";
349 const char* SIGNAL_PINCHED = "pinched";
350 const char* SIGNAL_LONG_PRESSED = "longPressed";
351 const char* SIGNAL_GET_NAME = "getName";
352 const char* SIGNAL_GET_DESCRIPTION = "getDescription";
353 const char* SIGNAL_DO_GESTURE = "doGesture";
354 static bool DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
356 Dali::BaseHandle handle(object);
358 bool connected(false);
359 Toolkit::Control control = Toolkit::Control::DownCast(handle);
362 Internal::Control& controlImpl(Internal::GetImplementation(control));
365 if(0 == strcmp(signalName.c_str(), SIGNAL_KEY_EVENT))
367 controlImpl.KeyEventSignal().Connect(tracker, functor);
369 else if(0 == strcmp(signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_GAINED))
371 controlImpl.KeyInputFocusGainedSignal().Connect(tracker, functor);
373 else if(0 == strcmp(signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_LOST))
375 controlImpl.KeyInputFocusLostSignal().Connect(tracker, functor);
377 else if(0 == strcmp(signalName.c_str(), SIGNAL_TAPPED))
379 controlImpl.EnableGestureDetection(GestureType::TAP);
380 controlImpl.GetTapGestureDetector().DetectedSignal().Connect(tracker, functor);
382 else if(0 == strcmp(signalName.c_str(), SIGNAL_PANNED))
384 controlImpl.EnableGestureDetection(GestureType::PAN);
385 controlImpl.GetPanGestureDetector().DetectedSignal().Connect(tracker, functor);
387 else if(0 == strcmp(signalName.c_str(), SIGNAL_PINCHED))
389 controlImpl.EnableGestureDetection(GestureType::PINCH);
390 controlImpl.GetPinchGestureDetector().DetectedSignal().Connect(tracker, functor);
392 else if(0 == strcmp(signalName.c_str(), SIGNAL_LONG_PRESSED))
394 controlImpl.EnableGestureDetection(GestureType::LONG_PRESS);
395 controlImpl.GetLongPressGestureDetector().DetectedSignal().Connect(tracker, functor);
397 else if(0 == strcmp(signalName.c_str(), SIGNAL_GET_NAME))
399 DevelControl::AccessibilityGetNameSignal(control).Connect(tracker, functor);
401 else if(0 == strcmp(signalName.c_str(), SIGNAL_GET_DESCRIPTION))
403 DevelControl::AccessibilityGetDescriptionSignal(control).Connect(tracker, functor);
405 else if(0 == strcmp(signalName.c_str(), SIGNAL_DO_GESTURE))
407 DevelControl::AccessibilityDoGestureSignal(control).Connect(tracker, functor);
414 * Creates control through type registry
418 return Internal::Control::New();
420 // Setup signals and actions using the type-registry.
421 DALI_TYPE_REGISTRATION_BEGIN(Control, CustomActor, Create);
423 // Note: Properties are registered separately below.
425 SignalConnectorType registerSignal1(typeRegistration, SIGNAL_KEY_EVENT, &DoConnectSignal);
426 SignalConnectorType registerSignal2(typeRegistration, SIGNAL_KEY_INPUT_FOCUS_GAINED, &DoConnectSignal);
427 SignalConnectorType registerSignal3(typeRegistration, SIGNAL_KEY_INPUT_FOCUS_LOST, &DoConnectSignal);
428 SignalConnectorType registerSignal4(typeRegistration, SIGNAL_TAPPED, &DoConnectSignal);
429 SignalConnectorType registerSignal5(typeRegistration, SIGNAL_PANNED, &DoConnectSignal);
430 SignalConnectorType registerSignal6(typeRegistration, SIGNAL_PINCHED, &DoConnectSignal);
431 SignalConnectorType registerSignal7(typeRegistration, SIGNAL_LONG_PRESSED, &DoConnectSignal);
432 SignalConnectorType registerSignal8(typeRegistration, SIGNAL_GET_NAME, &DoConnectSignal);
433 SignalConnectorType registerSignal9(typeRegistration, SIGNAL_GET_DESCRIPTION, &DoConnectSignal);
434 SignalConnectorType registerSignal10(typeRegistration, SIGNAL_DO_GESTURE, &DoConnectSignal);
436 TypeAction registerAction1(typeRegistration, "activate", &DoAction);
437 TypeAction registerAction2(typeRegistration, ACTION_ACCESSIBILITY_ACTIVATED, &DoAction);
438 TypeAction registerAction3(typeRegistration, ACTION_ACCESSIBILITY_READING_SKIPPED, &DoAction);
439 TypeAction registerAction4(typeRegistration, ACTION_ACCESSIBILITY_READING_CANCELLED, &DoAction);
440 TypeAction registerAction5(typeRegistration, ACTION_ACCESSIBILITY_READING_STOPPED, &DoAction);
441 TypeAction registerAction6(typeRegistration, ACTION_ACCESSIBILITY_READING_PAUSED, &DoAction);
442 TypeAction registerAction7(typeRegistration, ACTION_ACCESSIBILITY_READING_RESUMED, &DoAction);
444 DALI_TYPE_REGISTRATION_END()
447 * @brief Iterate through given container and setOffScene any visual found
449 * @param[in] container Container of visuals
450 * @param[in] parent Parent actor to remove visuals from
452 void SetVisualsOffScene(const RegisteredVisualContainer& container, Actor parent)
454 for(auto iter = container.Begin(), end = container.End(); iter != end; iter++)
458 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::SetOffScene Setting visual(%d) off stage\n", (*iter)->index);
459 Toolkit::GetImplementation((*iter)->visual).SetOffScene(parent);
464 Dali::Rect<> GetShowingGeometry(Dali::Rect<> rect, Dali::Toolkit::DevelControl::ControlAccessible* accessible)
467 Vector2 currentPosition;
468 auto parent = dynamic_cast<Toolkit::DevelControl::ControlAccessible*>(accessible->GetParent());
472 parentRect = parent->GetExtents(Dali::Accessibility::CoordinateType::WINDOW);
474 currentPosition.x = rect.x;
475 currentPosition.y = rect.y;
477 rect.x = rect.x > parentRect.x ? rect.x : parentRect.x;
478 rect.y = rect.y > parentRect.y ? rect.y : parentRect.y;
479 rect.width = currentPosition.x + rect.width < parentRect.x + parentRect.width ? currentPosition.x + rect.width - rect.x : parentRect.x + parentRect.width - rect.x;
480 rect.height = currentPosition.y + rect.height < parentRect.y + parentRect.height ? currentPosition.y + rect.height - rect.y : parentRect.y + parentRect.height - rect.y;
482 if(rect.width < 0 || rect.height < 0)
487 parent = dynamic_cast<Toolkit::DevelControl::ControlAccessible*>(parent->GetParent());
493 static bool IsShowingGeometryOnScreen(Dali::Rect<> rect)
495 return rect.width > 0 && rect.height > 0;
498 Dali::Accessibility::Accessible* ExternalAccessibleGetter(Dali::Actor actor)
500 auto control = Toolkit::Control::DownCast(actor);
506 auto& controlImpl = Toolkit::Internal::GetImplementation(control);
508 return controlImpl.GetAccessibleObject();
511 } // unnamed namespace
514 // Properties registered without macro to use specific member variables.
515 const PropertyRegistration Control::Impl::PROPERTY_1(typeRegistration, "styleName", Toolkit::Control::Property::STYLE_NAME, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
516 const PropertyRegistration Control::Impl::PROPERTY_4(typeRegistration, "keyInputFocus", Toolkit::Control::Property::KEY_INPUT_FOCUS, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
517 const PropertyRegistration Control::Impl::PROPERTY_5(typeRegistration, "background", Toolkit::Control::Property::BACKGROUND, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
518 const PropertyRegistration Control::Impl::PROPERTY_6(typeRegistration, "margin", Toolkit::Control::Property::MARGIN, Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
519 const PropertyRegistration Control::Impl::PROPERTY_7(typeRegistration, "padding", Toolkit::Control::Property::PADDING, Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
520 const PropertyRegistration Control::Impl::PROPERTY_8(typeRegistration, "tooltip", Toolkit::DevelControl::Property::TOOLTIP, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
521 const PropertyRegistration Control::Impl::PROPERTY_9(typeRegistration, "state", Toolkit::DevelControl::Property::STATE, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
522 const PropertyRegistration Control::Impl::PROPERTY_10(typeRegistration, "subState", Toolkit::DevelControl::Property::SUB_STATE, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
523 const PropertyRegistration Control::Impl::PROPERTY_11(typeRegistration, "leftFocusableActorId", Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
524 const PropertyRegistration Control::Impl::PROPERTY_12(typeRegistration, "rightFocusableActorId", Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
525 const PropertyRegistration Control::Impl::PROPERTY_13(typeRegistration, "upFocusableActorId", Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
526 const PropertyRegistration Control::Impl::PROPERTY_14(typeRegistration, "downFocusableActorId", Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
527 const PropertyRegistration Control::Impl::PROPERTY_15(typeRegistration, "shadow", Toolkit::DevelControl::Property::SHADOW, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
528 const PropertyRegistration Control::Impl::PROPERTY_16(typeRegistration, "accessibilityName", Toolkit::DevelControl::Property::ACCESSIBILITY_NAME, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
529 const PropertyRegistration Control::Impl::PROPERTY_17(typeRegistration, "accessibilityDescription", Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
530 const PropertyRegistration Control::Impl::PROPERTY_18(typeRegistration, "accessibilityTranslationDomain", Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
531 const PropertyRegistration Control::Impl::PROPERTY_19(typeRegistration, "accessibilityRole", Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
532 const PropertyRegistration Control::Impl::PROPERTY_20(typeRegistration, "accessibilityHighlightable", Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
533 const PropertyRegistration Control::Impl::PROPERTY_21(typeRegistration, "accessibilityAttributes", Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
534 const PropertyRegistration Control::Impl::PROPERTY_22(typeRegistration, "dispatchKeyEvents", Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
535 const PropertyRegistration Control::Impl::PROPERTY_23(typeRegistration, "accessibilityHidden", Toolkit::DevelControl::Property::ACCESSIBILITY_HIDDEN, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
536 const PropertyRegistration Control::Impl::PROPERTY_24(typeRegistration, "clockwiseFocusableActorId", Toolkit::DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
537 const PropertyRegistration Control::Impl::PROPERTY_25(typeRegistration, "counterClockwiseFocusableActorId", Toolkit::DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
538 const PropertyRegistration Control::Impl::PROPERTY_26(typeRegistration, "automationId", Toolkit::DevelControl::Property::AUTOMATION_ID, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
542 Control::Impl::Impl(Control& controlImpl)
543 : mControlImpl(controlImpl),
544 mState(Toolkit::DevelControl::NORMAL),
546 mLeftFocusableActorId(-1),
547 mRightFocusableActorId(-1),
548 mUpFocusableActorId(-1),
549 mDownFocusableActorId(-1),
550 mClockwiseFocusableActorId(-1),
551 mCounterClockwiseFocusableActorId(-1),
553 mBackgroundColor(Color::TRANSPARENT),
554 mStartingPinchScale(nullptr),
556 mPadding(0, 0, 0, 0),
558 mKeyInputFocusGainedSignal(),
559 mKeyInputFocusLostSignal(),
560 mResourceReadySignal(),
561 mVisualEventSignal(),
562 mAccessibilityGetNameSignal(),
563 mAccessibilityGetDescriptionSignal(),
564 mAccessibilityDoGestureSignal(),
565 mPinchGestureDetector(),
566 mPanGestureDetector(),
567 mTapGestureDetector(),
568 mLongPressGestureDetector(),
570 mInputMethodContext(),
571 mIdleCallback(nullptr),
572 mFlags(Control::ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
573 mIsKeyboardNavigationSupported(false),
574 mIsKeyboardFocusGroup(false),
575 mIsEmittingResourceReadySignal(false),
576 mIdleCallbackRegistered(false),
577 mDispatchKeyEvents(true)
579 Dali::Accessibility::Accessible::RegisterExternalAccessibleGetter(&ExternalAccessibleGetter);
582 Control::Impl::~Impl()
584 for(auto&& iter : mVisuals)
586 StopObservingVisual(iter->visual);
589 for(auto&& iter : mRemoveVisuals)
591 StopObservingVisual(iter->visual);
594 // All gesture detectors will be destroyed so no need to disconnect.
595 delete mStartingPinchScale;
597 if(mIdleCallback && Adaptor::IsAvailable())
599 // Removes the callback from the callback manager in case the control is destroyed before the callback is executed.
600 Adaptor::Get().RemoveIdle(mIdleCallback);
604 Control::Impl& Control::Impl::Get(Internal::Control& internalControl)
606 DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
608 return *internalControl.mImpl;
611 const Control::Impl& Control::Impl::Get(const Internal::Control& internalControl)
613 DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
615 return *internalControl.mImpl;
618 void Control::Impl::CheckHighlightedObjectGeometry()
620 auto accessible = GetAccessibleObject();
621 if(DALI_LIKELY(accessible))
623 auto lastPosition = accessible->GetLastPosition();
624 auto accessibleRect = accessible->GetExtents(Dali::Accessibility::CoordinateType::WINDOW);
625 auto rect = GetShowingGeometry(accessibleRect, accessible);
627 switch(mAccessibilityLastScreenRelativeMoveType)
629 case Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE:
631 if(IsShowingGeometryOnScreen(rect))
633 mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE;
637 case Dali::Accessibility::ScreenRelativeMoveType::INSIDE:
639 if(rect.width < 0 && !Dali::Equals(accessibleRect.x, lastPosition.x))
641 mAccessibilityLastScreenRelativeMoveType = (accessibleRect.x < lastPosition.x) ? Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT : Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT;
643 if(rect.height < 0 && !Dali::Equals(accessibleRect.y, lastPosition.y))
645 mAccessibilityLastScreenRelativeMoveType = (accessibleRect.y < lastPosition.y) ? Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT : Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT;
647 // notify AT-clients on outgoing moves only
648 if(mAccessibilityLastScreenRelativeMoveType != Dali::Accessibility::ScreenRelativeMoveType::INSIDE)
650 accessible->EmitMovedOutOfScreen(mAccessibilityLastScreenRelativeMoveType);
654 case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT:
655 case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT:
657 if(IsShowingGeometryOnScreen(rect))
659 mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE;
663 mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE;
673 accessible->SetLastPosition(Vector2(accessibleRect.x, accessibleRect.y));
677 void Control::Impl::RegisterAccessibilityPositionPropertyNotification()
679 if(mIsAccessibilityPositionPropertyNotificationSet)
683 // set default value until first move of object is detected
684 mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE;
685 // recalculate mAccessibilityLastScreenRelativeMoveType accordingly to the initial position
686 CheckHighlightedObjectGeometry();
687 mAccessibilityPositionNotification = mControlImpl.Self().AddPropertyNotification(Actor::Property::WORLD_POSITION, StepCondition(1.0f, 1.0f));
688 mAccessibilityPositionNotification.SetNotifyMode(PropertyNotification::NOTIFY_ON_CHANGED);
689 mAccessibilityPositionNotification.NotifySignal().Connect(this, [this](PropertyNotification&) { CheckHighlightedObjectGeometry(); });
690 mIsAccessibilityPositionPropertyNotificationSet = true;
693 void Control::Impl::UnregisterAccessibilityPositionPropertyNotification()
695 mControlImpl.Self().RemovePropertyNotification(mAccessibilityPositionNotification);
696 mIsAccessibilityPositionPropertyNotificationSet = false;
699 void Control::Impl::RegisterAccessibilityPropertySetSignal()
701 if(mIsAccessibilityPropertySetSignalRegistered)
705 mControlImpl.Self().PropertySetSignal().Connect(this, &Control::Impl::OnAccessibilityPropertySet);
706 mIsAccessibilityPropertySetSignalRegistered = true;
709 void Control::Impl::UnregisterAccessibilityPropertySetSignal()
711 if(!mIsAccessibilityPropertySetSignalRegistered)
715 mControlImpl.Self().PropertySetSignal().Disconnect(this, &Control::Impl::OnAccessibilityPropertySet);
716 mIsAccessibilityPropertySetSignalRegistered = false;
719 void Control::Impl::OnAccessibilityPropertySet(Dali::Handle& handle, Dali::Property::Index index, const Dali::Property::Value& value)
721 auto* accessible = GetAccessibleObject();
722 if(DALI_LIKELY(accessible))
724 if(mAccessibilityGetNameSignal.Empty())
726 if(index == DevelControl::Property::ACCESSIBILITY_NAME || (mAccessibilityName.empty() && index == accessible->GetNamePropertyIndex()))
728 accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::NAME);
732 if(mAccessibilityGetDescriptionSignal.Empty())
734 if(index == DevelControl::Property::ACCESSIBILITY_DESCRIPTION || (mAccessibilityDescription.empty() && index == accessible->GetDescriptionPropertyIndex()))
736 accessible->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::DESCRIPTION);
742 // Gesture Detection Methods
743 void Control::Impl::PinchDetected(Actor actor, const PinchGesture& pinch)
745 mControlImpl.OnPinch(pinch);
748 void Control::Impl::PanDetected(Actor actor, const PanGesture& pan)
750 mControlImpl.OnPan(pan);
753 void Control::Impl::TapDetected(Actor actor, const TapGesture& tap)
755 mControlImpl.OnTap(tap);
758 void Control::Impl::LongPressDetected(Actor actor, const LongPressGesture& longPress)
760 mControlImpl.OnLongPress(longPress);
763 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual)
765 RegisterVisual(index, visual, VisualState::ENABLED, DepthIndexValue::NOT_SET);
768 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, int depthIndex)
770 RegisterVisual(index, visual, VisualState::ENABLED, DepthIndexValue::SET, depthIndex);
773 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled)
775 RegisterVisual(index, visual, (enabled ? VisualState::ENABLED : VisualState::DISABLED), DepthIndexValue::NOT_SET);
778 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex)
780 RegisterVisual(index, visual, (enabled ? VisualState::ENABLED : VisualState::DISABLED), DepthIndexValue::SET, depthIndex);
783 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex)
785 DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
787 DALI_LOG_INFO(gLogFilter, Debug::Concise, "RegisterVisual:%d \n", index);
789 bool visualReplaced(false);
790 Actor self = mControlImpl.Self();
792 // Set the depth index, if not set by caller this will be either the current visual depth, max depth of all visuals
794 int requiredDepthIndex = visual.GetDepthIndex();
796 if(depthIndexValueSet == DepthIndexValue::SET)
798 requiredDepthIndex = depthIndex;
801 // Change the depth index value automatically if the visual has DepthIndex to AUTO_INDEX
802 // or if RegisterVisual set DepthIndex to AUTO_INDEX.
803 const bool requiredDepthIndexChanged = (requiredDepthIndex == DepthIndex::AUTO_INDEX);
805 // Visual replacement, existing visual should only be removed from stage when replacement ready.
806 if(!mVisuals.Empty())
808 RegisteredVisualContainer::Iterator registeredVisualsiter;
809 // Check if visual (index) is already registered, this is the current visual.
810 if(FindVisual(index, mVisuals, registeredVisualsiter))
812 Toolkit::Visual::Base& currentRegisteredVisual = (*registeredVisualsiter)->visual;
813 if(currentRegisteredVisual)
815 // Store current visual depth index as may need to set the replacement visual to same depth
816 const int currentDepthIndex = (*registeredVisualsiter)->visual.GetDepthIndex();
818 // No longer required to know if the replaced visual's resources are ready
819 StopObservingVisual(currentRegisteredVisual);
821 // If control staged and visual enabled then visuals will be swapped once ready
822 if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE) && enabled)
824 // Check if visual is currently in the process of being replaced ( is in removal container )
825 RegisteredVisualContainer::Iterator visualQueuedForRemoval;
826 if(FindVisual(index, mRemoveVisuals, visualQueuedForRemoval))
828 // Visual with same index is already in removal container so current visual pending
829 // Only the the last requested visual will be displayed so remove current visual which is staged but not ready.
830 Toolkit::GetImplementation(currentRegisteredVisual).SetOffScene(self);
831 mVisuals.Erase(registeredVisualsiter);
835 // current visual not already in removal container so add now.
836 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %d \n", index);
837 MoveVisual(registeredVisualsiter, mVisuals, mRemoveVisuals);
842 // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later.
843 mVisuals.Erase(registeredVisualsiter);
846 // If the visual have a depth index as AUTO_INDEX and the new visual does not have a depth index applied to it, then use the previously set depth-index for this index
847 if(requiredDepthIndexChanged)
849 requiredDepthIndex = currentDepthIndex;
850 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Use replaced visual index. VisualDepthIndex AUTO_INDEX set as: %d\n", requiredDepthIndex);
854 visualReplaced = true;
858 // If not set, set the name of the visual to the same name as the control's property.
859 // ( If the control has been type registered )
860 if(visual.GetName().empty())
862 // returns empty string if index is not found as long as index is not -1
863 std::string visualName = self.GetPropertyName(index);
864 if(!visualName.empty())
866 DALI_LOG_INFO(gLogFilter, Debug::Concise, "Setting visual name for property %d to %s\n", index, visualName.c_str());
867 visual.SetName(visualName);
871 if(!visualReplaced) // New registration entry
873 // If we have more than one visual and the visual have a depth index as AUTO_INDEX, then set it to be the highest
874 if((mVisuals.Size() > 0) && requiredDepthIndexChanged)
876 int maxDepthIndex = static_cast<int>(DepthIndex::CONTENT) - 1; // Start at DepthIndex::CONTENT if maxDepth index belongs to a background or no visuals have been added yet.
878 RegisteredVisualContainer::ConstIterator iter;
879 const RegisteredVisualContainer::ConstIterator endIter = mVisuals.End();
880 for(iter = mVisuals.Begin(); iter != endIter; iter++)
882 const int visualDepthIndex = (*iter)->visual.GetDepthIndex();
883 if(visualDepthIndex > maxDepthIndex)
885 maxDepthIndex = visualDepthIndex;
888 requiredDepthIndex = ++maxDepthIndex; // Add one to the current maximum depth index so that our added visual appears on top.
889 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Use top of all visuals. VisualDepthIndex AUTO_INDEX set as: %d\n", requiredDepthIndex);
895 // If required depth index still DepthIndex::AUTO_INDEX, Make it as DepthIndex::CONTENT now
896 if(requiredDepthIndex == static_cast<int>(DepthIndex::AUTO_INDEX))
898 requiredDepthIndex = static_cast<int>(DepthIndex::CONTENT);
899 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Some strange cases. VisualDepthIndex AUTO_INDEX set as: %d\n", requiredDepthIndex);
902 // Set determined depth index
903 visual.SetDepthIndex(requiredDepthIndex);
905 // Monitor when the visual resources are ready
906 StartObservingVisual(visual);
908 DALI_LOG_INFO(gLogFilter, Debug::Concise, "New Visual registration index[%d] depth[%d]\n", index, requiredDepthIndex);
909 RegisteredVisual* newRegisteredVisual = new RegisteredVisual(index, visual, (enabled == VisualState::ENABLED ? true : false), (visualReplaced && enabled));
910 mVisuals.PushBack(newRegisteredVisual);
912 Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
913 // Put on stage if enabled and the control is already on the stage
914 if((enabled == VisualState::ENABLED) && self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
916 visualImpl.SetOnScene(self);
918 else if(enabled && visualImpl.IsResourceReady()) // When not being staged, check if visual already 'ResourceReady' before it was Registered. ( Resource may have been loaded already )
920 ResourceReady(visualImpl);
924 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::RegisterVisual() Registered %s(%d), enabled:%s\n", visual.GetName().c_str(), index, enabled ? "true" : "false");
927 void Control::Impl::UnregisterVisual(Property::Index index)
929 DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
931 RegisteredVisualContainer::Iterator iter;
932 if(FindVisual(index, mVisuals, iter))
934 // stop observing visual
935 StopObservingVisual((*iter)->visual);
937 Actor self(mControlImpl.Self());
938 Toolkit::GetImplementation((*iter)->visual).SetOffScene(self);
939 (*iter)->visual.Reset();
940 mVisuals.Erase(iter);
943 if(FindVisual(index, mRemoveVisuals, iter))
945 Actor self(mControlImpl.Self());
946 Toolkit::GetImplementation((*iter)->visual).SetOffScene(self);
947 (*iter)->pending = false;
949 // Discard removed visual. It will be destroyed at next Idle time.
950 DiscardVisual(iter, mRemoveVisuals);
954 Toolkit::Visual::Base Control::Impl::GetVisual(Property::Index index) const
956 RegisteredVisualContainer::Iterator iter;
957 if(FindVisual(index, mVisuals, iter))
959 return (*iter)->visual;
962 return Toolkit::Visual::Base();
965 void Control::Impl::EnableVisual(Property::Index index, bool enable)
967 DALI_LOG_INFO(gLogFilter, Debug::General, "Control::EnableVisual(%d, %s)\n", index, enable ? "T" : "F");
969 RegisteredVisualContainer::Iterator iter;
970 if(FindVisual(index, mVisuals, iter))
972 if((*iter)->enabled == enable)
974 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Visual %s(%d) already %s\n", (*iter)->visual.GetName().c_str(), index, enable ? "enabled" : "disabled");
978 (*iter)->enabled = enable;
979 Actor parentActor = mControlImpl.Self();
980 if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE)) // If control not on Scene then Visual will be added when SceneConnection is called.
984 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) on stage \n", (*iter)->visual.GetName().c_str(), index);
985 Toolkit::GetImplementation((*iter)->visual).SetOnScene(parentActor);
989 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) off stage \n", (*iter)->visual.GetName().c_str(), index);
990 Toolkit::GetImplementation((*iter)->visual).SetOffScene(parentActor); // No need to call if control not staged.
996 DALI_LOG_WARNING("Control::EnableVisual(%d, %s) FAILED - NO SUCH VISUAL\n", index, enable ? "T" : "F");
1000 bool Control::Impl::IsVisualEnabled(Property::Index index) const
1002 RegisteredVisualContainer::Iterator iter;
1003 if(FindVisual(index, mVisuals, iter))
1005 return (*iter)->enabled;
1010 void Control::Impl::EnableReadyTransitionOverriden(Toolkit::Visual::Base& visual, bool enable)
1012 DALI_LOG_INFO(gLogFilter, Debug::General, "Control::EnableReadyTransitionOverriden(%p, %s)\n", visual, enable ? "T" : "F");
1014 RegisteredVisualContainer::Iterator iter;
1015 if(FindVisual(visual, mVisuals, iter))
1017 if((*iter)->overideReadyTransition == enable)
1019 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableReadyTransitionOverriden Visual %s(%p) already %s\n", (*iter)->visual.GetName().c_str(), visual, enable ? "enabled" : "disabled");
1023 (*iter)->overideReadyTransition = enable;
1027 void Control::Impl::StopObservingVisual(Toolkit::Visual::Base& visual)
1029 Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
1031 // Stop observing the visual
1032 visualImpl.RemoveEventObserver(*this);
1035 void Control::Impl::StartObservingVisual(Toolkit::Visual::Base& visual)
1037 Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
1039 // start observing the visual for events
1040 visualImpl.AddEventObserver(*this);
1043 void Control::Impl::ResourceReady()
1045 DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
1047 // Emit signal if all enabled visuals registered by the control are ready or there are no visuals.
1048 if(IsResourceReady())
1050 EmitResourceReadySignal();
1054 // Called by a Visual when it's resource is ready
1055 void Control::Impl::ResourceReady(Visual::Base& object)
1057 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::Impl::ResourceReady() replacements pending[%d]\n", mRemoveVisuals.Count());
1059 Actor self = mControlImpl.Self();
1061 RegisteredVisualContainer::Iterator registeredIter;
1063 // A resource is ready, find resource in the registered visuals container and get its index
1064 if(!FindVisual(object, mVisuals, registeredIter))
1069 RegisteredVisualContainer::Iterator visualToRemoveIter;
1070 // Find visual with the same index in the removal container
1071 // Set if off stage as it's replacement is now ready.
1072 // Remove if from removal list as now removed from stage.
1073 // Set Pending flag on the ready visual to false as now ready.
1074 if(FindVisual((*registeredIter)->index, mRemoveVisuals, visualToRemoveIter))
1076 (*registeredIter)->pending = false;
1077 if(!((*visualToRemoveIter)->overideReadyTransition))
1079 Toolkit::GetImplementation((*visualToRemoveIter)->visual).SetOffScene(self);
1082 // Discard removed visual. It will be destroyed at next Idle time.
1083 DiscardVisual(visualToRemoveIter, mRemoveVisuals);
1086 // A visual is ready so control may need relayouting if staged
1087 RelayoutRequest(object);
1089 // Called by a Visual when it's resource is ready
1090 if(((*registeredIter)->enabled))
1096 void Control::Impl::NotifyVisualEvent(Visual::Base& object, Property::Index signalId)
1098 for(auto registeredIter = mVisuals.Begin(), end = mVisuals.End(); registeredIter != end; ++registeredIter)
1100 Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation((*registeredIter)->visual);
1101 if(&object == ®isteredVisualImpl)
1103 Dali::Toolkit::Control handle(mControlImpl.GetOwner());
1104 mVisualEventSignal.Emit(handle, (*registeredIter)->index, signalId);
1110 void Control::Impl::RelayoutRequest(Visual::Base& object)
1112 if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
1114 mControlImpl.RelayoutRequest();
1118 bool Control::Impl::IsResourceReady() const
1120 // Iterate through and check all the enabled visuals are ready
1121 for(auto visualIter = mVisuals.Begin();
1122 visualIter != mVisuals.End();
1125 const Toolkit::Visual::Base visual = (*visualIter)->visual;
1126 const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
1128 // one of the enabled visuals is not ready
1129 if(!visualImpl.IsResourceReady() && (*visualIter)->enabled)
1137 Toolkit::Visual::ResourceStatus Control::Impl::GetVisualResourceStatus(Property::Index index) const
1139 RegisteredVisualContainer::Iterator iter;
1140 if(FindVisual(index, mVisuals, iter))
1142 const Toolkit::Visual::Base visual = (*iter)->visual;
1143 const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
1144 return visualImpl.GetResourceStatus();
1147 return Toolkit::Visual::ResourceStatus::PREPARING;
1150 void Control::Impl::AddTransitions(Dali::Animation& animation,
1151 const Toolkit::TransitionData& handle,
1152 bool createAnimation)
1154 // Setup a Transition from TransitionData.
1155 const Internal::TransitionData& transitionData = Toolkit::GetImplementation(handle);
1156 TransitionData::Iterator end = transitionData.End();
1157 for(TransitionData::Iterator iter = transitionData.Begin();
1161 TransitionData::Animator* animator = (*iter);
1163 Toolkit::Visual::Base visual = GetVisualByName(mVisuals, animator->objectName);
1167 #if defined(DEBUG_ENABLED)
1168 Dali::TypeInfo typeInfo;
1169 ControlWrapper* controlWrapperImpl = dynamic_cast<ControlWrapper*>(&mControlImpl);
1170 if(controlWrapperImpl)
1172 typeInfo = controlWrapperImpl->GetTypeInfo();
1175 DALI_LOG_INFO(gLogFilter, Debug::Concise, "CreateTransition: Found %s visual for %s\n", visual.GetName().c_str(), typeInfo ? typeInfo.GetName().c_str() : "Unknown");
1177 Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
1178 visualImpl.AnimateProperty(animation, *animator);
1182 DALI_LOG_INFO(gLogFilter, Debug::Concise, "CreateTransition: Could not find visual. Trying actors");
1183 // Otherwise, try any actor children of control (Including the control)
1184 Actor child = mControlImpl.Self().FindChildByName(animator->objectName);
1187 Property::Index propertyIndex = child.GetPropertyIndex(animator->propertyKey);
1188 if(propertyIndex != Property::INVALID_INDEX)
1190 if(animator->animate == false)
1192 if(animator->targetValue.GetType() != Property::NONE)
1194 child.SetProperty(propertyIndex, animator->targetValue);
1197 else // animate the property
1199 if(animator->initialValue.GetType() != Property::NONE)
1201 child.SetProperty(propertyIndex, animator->initialValue);
1204 if(createAnimation && !animation)
1206 animation = Dali::Animation::New(0.1f);
1209 animation.AnimateTo(Property(child, propertyIndex),
1210 animator->targetValue,
1211 animator->alphaFunction,
1212 TimePeriod(animator->timePeriodDelay,
1213 animator->timePeriodDuration));
1221 Dali::Animation Control::Impl::CreateTransition(const Toolkit::TransitionData& transitionData)
1223 Dali::Animation transition;
1225 if(transitionData.Count() > 0)
1227 AddTransitions(transition, transitionData, true);
1232 void Control::Impl::DoAction(Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes)
1234 RegisteredVisualContainer::Iterator iter;
1235 if(FindVisual(visualIndex, mVisuals, iter))
1237 Toolkit::GetImplementation((*iter)->visual).DoAction(actionId, attributes);
1241 void Control::Impl::DoActionExtension(Dali::Property::Index visualIndex, Dali::Property::Index actionId, Dali::Any attributes)
1243 RegisteredVisualContainer::Iterator iter;
1244 if(FindVisual(visualIndex, mVisuals, iter))
1246 Toolkit::GetImplementation((*iter)->visual).DoActionExtension(actionId, attributes);
1250 void Control::Impl::AppendAccessibilityAttribute(const std::string& key, const std::string value)
1252 Property::Value* checkedValue = mAccessibilityAttributes.Find(key);
1255 mAccessibilityAttributes[key] = Property::Value(value);
1259 mAccessibilityAttributes.Insert(key, value);
1263 void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
1265 DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
1267 Toolkit::Control control = Toolkit::Control::DownCast(BaseHandle(object));
1271 Control& controlImpl(GetImplementation(control));
1275 case Toolkit::Control::Property::STYLE_NAME:
1277 controlImpl.SetStyleName(value.Get<std::string>());
1281 case Toolkit::DevelControl::Property::STATE:
1283 bool withTransitions = true;
1284 const Property::Value* valuePtr = &value;
1285 const Property::Map* map = value.GetMap();
1288 Property::Value* value2 = map->Find("withTransitions");
1291 withTransitions = value2->Get<bool>();
1294 valuePtr = map->Find("state");
1299 Toolkit::DevelControl::State state(controlImpl.mImpl->mState);
1300 if(Scripting::GetEnumerationProperty<Toolkit::DevelControl::State>(*valuePtr, ControlStateTable, ControlStateTableCount, state))
1302 controlImpl.mImpl->SetState(state, withTransitions);
1308 case Toolkit::DevelControl::Property::SUB_STATE:
1310 std::string subState;
1311 if(value.Get(subState))
1313 controlImpl.mImpl->SetSubState(subState);
1318 case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
1321 if(value.Get(focusId))
1323 controlImpl.mImpl->mLeftFocusableActorId = focusId;
1328 case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
1331 if(value.Get(focusId))
1333 controlImpl.mImpl->mRightFocusableActorId = focusId;
1338 case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
1341 if(value.Get(focusId))
1343 controlImpl.mImpl->mUpFocusableActorId = focusId;
1348 case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
1351 if(value.Get(focusId))
1353 controlImpl.mImpl->mDownFocusableActorId = focusId;
1358 case Toolkit::Control::Property::KEY_INPUT_FOCUS:
1360 if(value.Get<bool>())
1362 controlImpl.SetKeyInputFocus();
1366 controlImpl.ClearKeyInputFocus();
1371 case Toolkit::Control::Property::BACKGROUND:
1375 const Property::Map* map = value.GetMap();
1376 if(map && !map->Empty())
1378 controlImpl.SetBackground(*map);
1380 else if(value.Get(url))
1382 // don't know the size to load
1383 Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual(url, ImageDimensions());
1386 controlImpl.mImpl->RegisterVisual(Toolkit::Control::Property::BACKGROUND, visual, DepthIndex::BACKGROUND);
1389 else if(value.Get(color))
1391 controlImpl.SetBackgroundColor(color);
1395 // The background is an empty property map, so we should clear the background
1396 controlImpl.ClearBackground();
1401 case Toolkit::Control::Property::MARGIN:
1404 if(value.Get(margin))
1406 controlImpl.mImpl->SetMargin(margin);
1411 case Toolkit::Control::Property::PADDING:
1414 if(value.Get(padding))
1416 controlImpl.mImpl->SetPadding(padding);
1421 case Toolkit::DevelControl::Property::TOOLTIP:
1423 TooltipPtr& tooltipPtr = controlImpl.mImpl->mTooltip;
1426 tooltipPtr = Tooltip::New(control);
1428 tooltipPtr->SetProperties(value);
1432 case Toolkit::DevelControl::Property::SHADOW:
1434 const Property::Map* map = value.GetMap();
1435 if(map && !map->Empty())
1437 controlImpl.mImpl->SetShadow(*map);
1441 // The shadow is an empty property map, so we should clear the shadow
1442 controlImpl.mImpl->ClearShadow();
1447 case Toolkit::DevelControl::Property::ACCESSIBILITY_NAME:
1452 controlImpl.mImpl->mAccessibilityName = name;
1457 case Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION:
1462 controlImpl.mImpl->mAccessibilityDescription = text;
1467 case Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN:
1472 controlImpl.mImpl->mAccessibilityTranslationDomain = text;
1477 case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE:
1479 Dali::Accessibility::Role role;
1482 controlImpl.mImpl->mAccessibilityRole = role;
1487 case Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE:
1490 if(value.Get(highlightable))
1492 controlImpl.mImpl->mAccessibilityHighlightable = highlightable;
1497 case Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES:
1499 const Property::Map* map = value.GetMap();
1500 if(map && !map->Empty())
1502 controlImpl.mImpl->mAccessibilityAttributes = *map;
1507 case Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS:
1510 if(value.Get(dispatch))
1512 controlImpl.mImpl->mDispatchKeyEvents = dispatch;
1517 case Toolkit::DevelControl::Property::ACCESSIBILITY_HIDDEN:
1520 if(value.Get(hidden))
1522 controlImpl.mImpl->mAccessibilityHidden = hidden;
1524 auto* accessible = controlImpl.GetAccessibleObject();
1525 if(DALI_LIKELY(accessible))
1527 auto* parent = dynamic_cast<Dali::Accessibility::ActorAccessible*>(accessible->GetParent());
1530 parent->OnChildrenChanged();
1536 case Toolkit::DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID:
1539 if(value.Get(focusId))
1541 controlImpl.mImpl->mClockwiseFocusableActorId = focusId;
1545 case Toolkit::DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID:
1548 if(value.Get(focusId))
1550 controlImpl.mImpl->mCounterClockwiseFocusableActorId = focusId;
1555 case Toolkit::DevelControl::Property::AUTOMATION_ID:
1557 std::string automationId;
1558 if(value.Get(automationId))
1560 controlImpl.mImpl->mAutomationId = automationId;
1568 Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index index)
1570 DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
1572 Property::Value value;
1574 Toolkit::Control control = Toolkit::Control::DownCast(BaseHandle(object));
1578 Control& controlImpl(GetImplementation(control));
1582 case Toolkit::Control::Property::STYLE_NAME:
1584 value = controlImpl.GetStyleName();
1588 case Toolkit::DevelControl::Property::STATE:
1590 value = controlImpl.mImpl->mState;
1594 case Toolkit::DevelControl::Property::SUB_STATE:
1596 value = controlImpl.mImpl->mSubStateName;
1600 case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
1602 value = controlImpl.mImpl->mLeftFocusableActorId;
1606 case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
1608 value = controlImpl.mImpl->mRightFocusableActorId;
1612 case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
1614 value = controlImpl.mImpl->mUpFocusableActorId;
1618 case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
1620 value = controlImpl.mImpl->mDownFocusableActorId;
1624 case Toolkit::Control::Property::KEY_INPUT_FOCUS:
1626 value = controlImpl.HasKeyInputFocus();
1630 case Toolkit::Control::Property::BACKGROUND:
1633 Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual(Toolkit::Control::Property::BACKGROUND);
1636 visual.CreatePropertyMap(map);
1643 case Toolkit::Control::Property::MARGIN:
1645 value = controlImpl.mImpl->GetMargin();
1649 case Toolkit::Control::Property::PADDING:
1651 value = controlImpl.mImpl->GetPadding();
1655 case Toolkit::DevelControl::Property::TOOLTIP:
1658 if(controlImpl.mImpl->mTooltip)
1660 controlImpl.mImpl->mTooltip->CreatePropertyMap(map);
1666 case Toolkit::DevelControl::Property::SHADOW:
1669 Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual(Toolkit::DevelControl::Property::SHADOW);
1672 visual.CreatePropertyMap(map);
1679 case Toolkit::DevelControl::Property::ACCESSIBILITY_NAME:
1681 value = controlImpl.mImpl->mAccessibilityName;
1685 case Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION:
1687 value = controlImpl.mImpl->mAccessibilityDescription;
1691 case Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN:
1693 value = controlImpl.mImpl->mAccessibilityTranslationDomain;
1697 case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE:
1699 value = Property::Value(controlImpl.mImpl->mAccessibilityRole);
1703 case Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE:
1705 value = controlImpl.mImpl->mAccessibilityHighlightable;
1709 case Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES:
1711 value = controlImpl.mImpl->mAccessibilityAttributes;
1715 case Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS:
1717 value = controlImpl.mImpl->mDispatchKeyEvents;
1721 case Toolkit::DevelControl::Property::ACCESSIBILITY_HIDDEN:
1723 value = controlImpl.mImpl->mAccessibilityHidden;
1727 case Toolkit::DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID:
1729 value = controlImpl.mImpl->mClockwiseFocusableActorId;
1733 case Toolkit::DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID:
1735 value = controlImpl.mImpl->mCounterClockwiseFocusableActorId;
1739 case Toolkit::DevelControl::Property::AUTOMATION_ID:
1741 value = controlImpl.mImpl->mAutomationId;
1750 void Control::Impl::RemoveAccessibilityAttribute(const std::string& key)
1752 Property::Value* value = mAccessibilityAttributes.Find(key);
1755 mAccessibilityAttributes[key] = Property::Value();
1759 void Control::Impl::ClearAccessibilityAttributes()
1761 mAccessibilityAttributes.Clear();
1764 void Control::Impl::SetAccessibilityReadingInfoType(const Dali::Accessibility::ReadingInfoTypes types)
1766 std::string value{};
1767 if(types[Dali::Accessibility::ReadingInfoType::NAME])
1769 value += READING_INFO_TYPE_NAME;
1771 if(types[Dali::Accessibility::ReadingInfoType::ROLE])
1775 value += READING_INFO_TYPE_SEPARATOR;
1777 value += READING_INFO_TYPE_ROLE;
1779 if(types[Dali::Accessibility::ReadingInfoType::DESCRIPTION])
1783 value += READING_INFO_TYPE_SEPARATOR;
1785 value += READING_INFO_TYPE_DESCRIPTION;
1787 if(types[Dali::Accessibility::ReadingInfoType::STATE])
1791 value += READING_INFO_TYPE_SEPARATOR;
1793 value += READING_INFO_TYPE_STATE;
1795 AppendAccessibilityAttribute(READING_INFO_TYPE_ATTRIBUTE_NAME, value);
1798 Dali::Accessibility::ReadingInfoTypes Control::Impl::GetAccessibilityReadingInfoType() const
1800 std::string value{};
1801 auto place = mAccessibilityAttributes.Find(READING_INFO_TYPE_ATTRIBUTE_NAME);
1808 Dali::Accessibility::ReadingInfoTypes types;
1809 types[Dali::Accessibility::ReadingInfoType::NAME] = true;
1810 types[Dali::Accessibility::ReadingInfoType::ROLE] = true;
1811 types[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
1812 types[Dali::Accessibility::ReadingInfoType::STATE] = true;
1821 Dali::Accessibility::ReadingInfoTypes types;
1823 if(value.find(READING_INFO_TYPE_NAME) != std::string::npos)
1825 types[Dali::Accessibility::ReadingInfoType::NAME] = true;
1827 if(value.find(READING_INFO_TYPE_ROLE) != std::string::npos)
1829 types[Dali::Accessibility::ReadingInfoType::ROLE] = true;
1831 if(value.find(READING_INFO_TYPE_DESCRIPTION) != std::string::npos)
1833 types[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
1835 if(value.find(READING_INFO_TYPE_STATE) != std::string::npos)
1837 types[Dali::Accessibility::ReadingInfoType::STATE] = true;
1843 void Control::Impl::CopyInstancedProperties(RegisteredVisualContainer& visuals, Dictionary<Property::Map>& instancedProperties)
1845 for(RegisteredVisualContainer::Iterator iter = visuals.Begin(); iter != visuals.End(); iter++)
1849 Property::Map instanceMap;
1850 Toolkit::GetImplementation((*iter)->visual).CreateInstancePropertyMap(instanceMap);
1851 instancedProperties.Add((*iter)->visual.GetName(), instanceMap);
1856 void Control::Impl::RemoveVisual(RegisteredVisualContainer& visuals, const std::string& visualName)
1858 Actor self(mControlImpl.Self());
1860 for(RegisteredVisualContainer::Iterator visualIter = visuals.Begin();
1861 visualIter != visuals.End();
1864 Toolkit::Visual::Base visual = (*visualIter)->visual;
1865 if(visual && visual.GetName() == visualName)
1867 Toolkit::GetImplementation(visual).SetOffScene(self);
1868 (*visualIter)->visual.Reset();
1869 visuals.Erase(visualIter);
1875 void Control::Impl::RemoveVisuals(RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals)
1877 Actor self(mControlImpl.Self());
1878 for(DictionaryKeys::iterator iter = removeVisuals.begin(); iter != removeVisuals.end(); ++iter)
1880 const std::string visualName = *iter;
1881 RemoveVisual(visuals, visualName);
1885 void Control::Impl::RecreateChangedVisuals(Dictionary<Property::Map>& stateVisualsToChange,
1886 Dictionary<Property::Map>& instancedProperties)
1888 Dali::CustomActor handle(mControlImpl.GetOwner());
1889 for(Dictionary<Property::Map>::iterator iter = stateVisualsToChange.Begin();
1890 iter != stateVisualsToChange.End();
1893 const std::string& visualName = (*iter).key;
1894 const Property::Map& toMap = (*iter).entry;
1896 Actor self = mControlImpl.Self();
1897 RegisteredVisualContainer::Iterator registeredVisualsiter;
1898 // Check if visual (visualName) is already registered, this is the current visual.
1899 if(FindVisual(visualName, mVisuals, registeredVisualsiter))
1901 Toolkit::Visual::Base& visual = (*registeredVisualsiter)->visual;
1904 // No longer required to know if the replaced visual's resources are ready
1905 StopObservingVisual(visual);
1907 // If control staged then visuals will be swapped once ready
1908 if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
1910 // Check if visual is currently in the process of being replaced ( is in removal container )
1911 RegisteredVisualContainer::Iterator visualQueuedForRemoval;
1912 if(FindVisual(visualName, mRemoveVisuals, visualQueuedForRemoval))
1914 // Visual with same visual name is already in removal container so current visual pending
1915 // Only the the last requested visual will be displayed so remove current visual which is staged but not ready.
1916 Toolkit::GetImplementation(visual).SetOffScene(self);
1917 (*registeredVisualsiter)->visual.Reset();
1918 mVisuals.Erase(registeredVisualsiter);
1922 // current visual not already in removal container so add now.
1923 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %s \n", visualName.c_str());
1924 MoveVisual(registeredVisualsiter, mVisuals, mRemoveVisuals);
1929 // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later.
1930 (*registeredVisualsiter)->visual.Reset();
1931 mVisuals.Erase(registeredVisualsiter);
1935 const Property::Map* instancedMap = instancedProperties.FindConst(visualName);
1936 Style::ApplyVisual(handle, visualName, toMap, instancedMap);
1941 void Control::Impl::ReplaceStateVisualsAndProperties(const StylePtr oldState, const StylePtr newState, const std::string& subState)
1943 DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?");
1945 // Collect all old visual names
1946 DictionaryKeys stateVisualsToRemove;
1949 oldState->visuals.GetKeys(stateVisualsToRemove);
1950 if(!subState.empty())
1952 const StylePtr* oldSubState = oldState->subStates.FindConst(subState);
1955 DictionaryKeys subStateVisualsToRemove;
1956 (*oldSubState)->visuals.GetKeys(subStateVisualsToRemove);
1957 Merge(stateVisualsToRemove, subStateVisualsToRemove);
1962 // Collect all new visual properties
1963 Dictionary<Property::Map> stateVisualsToAdd;
1966 stateVisualsToAdd = newState->visuals;
1967 if(!subState.empty())
1969 const StylePtr* newSubState = newState->subStates.FindConst(subState);
1972 stateVisualsToAdd.Merge((*newSubState)->visuals);
1977 // If a name is in both add/remove, move it to change list.
1978 Dictionary<Property::Map> stateVisualsToChange;
1979 FindChangableVisuals(stateVisualsToAdd, stateVisualsToChange, stateVisualsToRemove);
1981 // Copy instanced properties (e.g. text label) of current visuals
1982 Dictionary<Property::Map> instancedProperties;
1983 CopyInstancedProperties(mVisuals, instancedProperties);
1985 // For each visual in remove list, remove from mVisuals
1986 RemoveVisuals(mVisuals, stateVisualsToRemove);
1988 // For each visual in add list, create and add to mVisuals
1989 Dali::CustomActor handle(mControlImpl.GetOwner());
1990 Style::ApplyVisuals(handle, stateVisualsToAdd, instancedProperties);
1992 // For each visual in change list, if it requires a new visual,
1993 // remove old visual, create and add to mVisuals
1994 RecreateChangedVisuals(stateVisualsToChange, instancedProperties);
1997 void Control::Impl::SetState(DevelControl::State newState, bool withTransitions)
1999 DevelControl::State oldState = mState;
2000 Dali::CustomActor handle(mControlImpl.GetOwner());
2001 DALI_LOG_INFO(gLogFilter, Debug::Concise, "Control::Impl::SetState: %s\n", (mState == DevelControl::NORMAL ? "NORMAL" : (mState == DevelControl::FOCUSED ? "FOCUSED" : (mState == DevelControl::DISABLED ? "DISABLED" : "NONE"))));
2003 if(mState != newState)
2005 // If mState was Disabled, and new state is Focused, should probably
2006 // store that fact, e.g. in another property that FocusManager can access.
2009 // Trigger state change and transitions
2010 // Apply new style, if stylemanager is available
2011 Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
2014 const StylePtr stylePtr = GetImpl(styleManager).GetRecordedStyle(Toolkit::Control(mControlImpl.GetOwner()));
2018 std::string oldStateName = Scripting::GetEnumerationName<Toolkit::DevelControl::State>(oldState, ControlStateTable, ControlStateTableCount);
2019 std::string newStateName = Scripting::GetEnumerationName<Toolkit::DevelControl::State>(newState, ControlStateTable, ControlStateTableCount);
2021 const StylePtr* newStateStyle = stylePtr->subStates.Find(newStateName);
2022 const StylePtr* oldStateStyle = stylePtr->subStates.Find(oldStateName);
2023 if(oldStateStyle && newStateStyle)
2025 // Only change if both state styles exist
2026 ReplaceStateVisualsAndProperties(*oldStateStyle, *newStateStyle, mSubStateName);
2033 void Control::Impl::SetSubState(const std::string& subStateName, bool withTransitions)
2035 if(mSubStateName != subStateName)
2037 // Get existing sub-state visuals, and unregister them
2038 Dali::CustomActor handle(mControlImpl.GetOwner());
2040 Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
2043 const StylePtr stylePtr = GetImpl(styleManager).GetRecordedStyle(Toolkit::Control(mControlImpl.GetOwner()));
2047 std::string stateName = Scripting::GetEnumerationName<Toolkit::DevelControl::State>(mState, ControlStateTable, ControlStateTableCount);
2049 const StylePtr* state = stylePtr->subStates.Find(stateName);
2052 StylePtr stateStyle(*state);
2054 const StylePtr* newStateStyle = stateStyle->subStates.Find(subStateName);
2055 const StylePtr* oldStateStyle = stateStyle->subStates.Find(mSubStateName);
2056 if(oldStateStyle && newStateStyle)
2059 ReplaceStateVisualsAndProperties(*oldStateStyle, *newStateStyle, empty);
2065 mSubStateName = subStateName;
2069 void Control::Impl::OnSceneDisconnection()
2071 Actor self = mControlImpl.Self();
2073 // Any visuals set for replacement but not yet ready should still be registered.
2074 // Reason: If a request was made to register a new visual but the control removed from scene before visual was ready
2075 // then when this control appears back on stage it should use that new visual.
2077 // Iterate through all registered visuals and set off scene
2078 SetVisualsOffScene(mVisuals, self);
2080 // Visuals pending replacement can now be taken out of the removal list and set off scene
2081 // Iterate through all replacement visuals and add to a move queue then set off scene
2083 if(!mRemoveVisuals.Empty())
2085 std::reverse(mRemoveVisuals.Begin(), mRemoveVisuals.End());
2087 while(!mRemoveVisuals.Empty())
2089 auto removalIter = mRemoveVisuals.End() - 1u;
2090 Toolkit::GetImplementation((*removalIter)->visual).SetOffScene(self);
2092 // Discard removed visual. It will be destroyed at next Idle time.
2093 DiscardVisual(removalIter, mRemoveVisuals);
2097 for(auto replacedIter = mVisuals.Begin(), end = mVisuals.End(); replacedIter != end; replacedIter++)
2099 (*replacedIter)->pending = false;
2103 void Control::Impl::SetMargin(Extents margin)
2105 mControlImpl.mImpl->mMargin = margin;
2107 // Trigger a size negotiation request that may be needed when setting a margin.
2108 mControlImpl.RelayoutRequest();
2111 Extents Control::Impl::GetMargin() const
2113 return mControlImpl.mImpl->mMargin;
2116 void Control::Impl::SetPadding(Extents padding)
2118 mControlImpl.mImpl->mPadding = padding;
2120 // Trigger a size negotiation request that may be needed when setting a padding.
2121 mControlImpl.RelayoutRequest();
2124 Extents Control::Impl::GetPadding() const
2126 return mControlImpl.mImpl->mPadding;
2129 void Control::Impl::SetInputMethodContext(InputMethodContext& inputMethodContext)
2131 mInputMethodContext = inputMethodContext;
2134 bool Control::Impl::FilterKeyEvent(const KeyEvent& event)
2136 bool consumed(false);
2138 if(mInputMethodContext)
2140 consumed = mInputMethodContext.FilterEventKey(event);
2145 DevelControl::VisualEventSignalType& Control::Impl::VisualEventSignal()
2147 return mVisualEventSignal;
2150 void Control::Impl::SetShadow(const Property::Map& map)
2152 Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual(map);
2153 visual.SetName("shadow");
2157 mControlImpl.mImpl->RegisterVisual(Toolkit::DevelControl::Property::SHADOW, visual, DepthIndex::BACKGROUND_EFFECT);
2159 mControlImpl.RelayoutRequest();
2163 void Control::Impl::ClearShadow()
2165 mControlImpl.mImpl->UnregisterVisual(Toolkit::DevelControl::Property::SHADOW);
2167 // Trigger a size negotiation request that may be needed when unregistering a visual.
2168 mControlImpl.RelayoutRequest();
2171 Dali::Property Control::Impl::GetVisualProperty(Dali::Property::Index index, Dali::Property::Key visualPropertyKey)
2173 Toolkit::Visual::Base visual = GetVisualByIndex(mVisuals, index);
2176 Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
2177 return visualImpl.GetPropertyObject(std::move(visualPropertyKey));
2181 return Dali::Property(handle, Property::INVALID_INDEX);
2184 void Control::Impl::CreateTransitions(std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& sourceProperties,
2185 std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& destinationProperties,
2186 Dali::Toolkit::Control source,
2187 Dali::Toolkit::Control destination)
2189 // Retrieves background properties to be transitioned.
2190 Dali::Property::Map backgroundSourcePropertyMap, backgroundDestinationPropertyMap;
2191 mControlImpl.MakeVisualTransition(backgroundSourcePropertyMap, backgroundDestinationPropertyMap, source, destination, Toolkit::Control::Property::BACKGROUND);
2192 if(backgroundSourcePropertyMap.Count() > 0)
2194 sourceProperties.push_back(std::pair<Dali::Property::Index, Dali::Property::Map>(Toolkit::Control::Property::BACKGROUND, backgroundSourcePropertyMap));
2195 destinationProperties.push_back(std::pair<Dali::Property::Index, Dali::Property::Map>(Toolkit::Control::Property::BACKGROUND, backgroundDestinationPropertyMap));
2198 // Retrieves shadow properties to be transitioned.
2199 Dali::Property::Map shadowSourcePropertyMap, shadowDestinationPropertyMap;
2200 mControlImpl.MakeVisualTransition(shadowSourcePropertyMap, shadowDestinationPropertyMap, source, destination, Toolkit::DevelControl::Property::SHADOW);
2201 if(shadowSourcePropertyMap.Count() > 0)
2203 sourceProperties.push_back(std::pair<Dali::Property::Index, Dali::Property::Map>(Toolkit::DevelControl::Property::SHADOW, shadowSourcePropertyMap));
2204 destinationProperties.push_back(std::pair<Dali::Property::Index, Dali::Property::Map>(Toolkit::DevelControl::Property::SHADOW, shadowDestinationPropertyMap));
2207 // Retrieves transition from inherited class.
2208 mControlImpl.OnCreateTransitions(sourceProperties, destinationProperties, source, destination);
2211 void Control::Impl::UpdateVisualProperties(const std::vector<std::pair<Dali::Property::Index, Dali::Property::Map>>& properties)
2213 for(auto&& data : properties)
2215 if(data.first == Toolkit::Control::Property::BACKGROUND)
2217 DoAction(Toolkit::Control::Property::BACKGROUND, DevelVisual::Action::UPDATE_PROPERTY, data.second);
2219 else if(data.first == Toolkit::DevelControl::Property::SHADOW)
2221 DoAction(Toolkit::DevelControl::Property::SHADOW, DevelVisual::Action::UPDATE_PROPERTY, data.second);
2224 mControlImpl.OnUpdateVisualProperties(properties);
2227 void Control::Impl::EmitResourceReadySignal()
2229 if(!mIsEmittingResourceReadySignal)
2231 // Guard against calls to emit the signal during the callback
2232 mIsEmittingResourceReadySignal = true;
2234 // If the signal handler changes visual, it may become ready during this call & therefore this method will
2235 // get called again recursively. If so, mIdleCallbackRegistered is set below, and we act on it after that secondary
2236 // invocation has completed by notifying in an Idle callback to prevent further recursion.
2237 Dali::Toolkit::Control handle(mControlImpl.GetOwner());
2238 mResourceReadySignal.Emit(handle);
2240 mIsEmittingResourceReadySignal = false;
2244 if(!mIdleCallbackRegistered)
2246 mIdleCallbackRegistered = true;
2248 // Add idler to emit the signal again
2251 // The callback manager takes the ownership of the callback object.
2252 mIdleCallback = MakeCallback(this, &Control::Impl::OnIdleCallback);
2253 if(DALI_UNLIKELY(!Adaptor::Get().AddIdle(mIdleCallback, true)))
2255 DALI_LOG_ERROR("Fail to add idle callback for control resource ready. Skip this callback.\n");
2256 mIdleCallback = nullptr;
2257 mIdleCallbackRegistered = false;
2264 bool Control::Impl::OnIdleCallback()
2267 mIdleCallbackRegistered = false;
2269 // A visual is ready so control may need relayouting if staged
2270 if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
2272 mControlImpl.RelayoutRequest();
2275 EmitResourceReadySignal();
2277 if(!mIdleCallbackRegistered)
2279 // Set the pointer to null as the callback manager deletes the callback after execute it.
2280 mIdleCallback = nullptr;
2283 // Repeat idle if mIdleCallbackRegistered become true one more time.
2284 return mIdleCallbackRegistered;
2287 Toolkit::DevelControl::ControlAccessible* Control::Impl::GetAccessibleObject()
2289 if(mAccessibleCreatable && !mAccessibleObject)
2291 mAccessibleObject.reset(mControlImpl.CreateAccessibleObject());
2294 return mAccessibleObject.get();
2297 bool Control::Impl::IsAccessibleCreated() const
2299 return !!mAccessibleObject;
2302 void Control::Impl::EnableCreateAccessible(bool enable)
2304 mAccessibleCreatable = enable;
2307 bool Control::Impl::IsCreateAccessibleEnabled() const
2309 return mAccessibleCreatable;
2312 } // namespace Internal
2314 } // namespace Toolkit