2 * Copyright (c) 2021 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/object/object-registry.h>
34 #include <dali/public-api/object/type-registry-helper.h>
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>
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 = "|";
67 extern const Dali::Scripting::StringEnum ControlStateTable[];
68 extern const unsigned int ControlStateTableCount;
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},
76 const unsigned int ControlStateTableCount = sizeof(ControlStateTable) / sizeof(ControlStateTable[0]);
80 #if defined(DEBUG_ENABLED)
81 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_CONTROL_VISUALS");
85 void Remove(Dictionary<T>& keyValues, const std::string& name)
87 keyValues.Remove(name);
90 void Remove(DictionaryKeys& keys, const std::string& name)
92 DictionaryKeys::iterator iter = std::find(keys.begin(), keys.end(), name);
93 if(iter != keys.end())
100 * Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
102 bool FindVisual(Property::Index targetIndex, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter)
104 for(iter = visuals.Begin(); iter != visuals.End(); iter++)
106 if((*iter)->index == targetIndex)
115 * Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
117 bool FindVisual(std::string visualName, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter)
119 for(iter = visuals.Begin(); iter != visuals.End(); iter++)
121 Toolkit::Visual::Base visual = (*iter)->visual;
122 if(visual && visual.GetName() == visualName)
130 void FindChangableVisuals(Dictionary<Property::Map>& stateVisualsToAdd,
131 Dictionary<Property::Map>& stateVisualsToChange,
132 DictionaryKeys& stateVisualsToRemove)
134 DictionaryKeys copyOfStateVisualsToRemove = stateVisualsToRemove;
136 for(DictionaryKeys::iterator iter = copyOfStateVisualsToRemove.begin();
137 iter != copyOfStateVisualsToRemove.end();
140 const std::string& visualName = (*iter);
141 Property::Map* toMap = stateVisualsToAdd.Find(visualName);
144 stateVisualsToChange.Add(visualName, *toMap);
145 stateVisualsToAdd.Remove(visualName);
146 Remove(stateVisualsToRemove, visualName);
151 Toolkit::Visual::Base GetVisualByName(
152 const RegisteredVisualContainer& visuals,
153 const std::string& visualName)
155 Toolkit::Visual::Base visualHandle;
157 RegisteredVisualContainer::Iterator iter;
158 for(iter = visuals.Begin(); iter != visuals.End(); iter++)
160 Toolkit::Visual::Base visual = (*iter)->visual;
161 if(visual && visual.GetName() == visualName)
163 visualHandle = visual;
170 Toolkit::Visual::Base GetVisualByIndex(
171 const RegisteredVisualContainer& visuals,
172 Property::Index index)
174 Toolkit::Visual::Base visualHandle;
176 RegisteredVisualContainer::Iterator iter;
177 for(iter = visuals.Begin(); iter != visuals.End(); iter++)
179 if((*iter)->index == index)
181 visualHandle = (*iter)->visual;
189 * Move visual from source to destination container
191 void MoveVisual(RegisteredVisualContainer::Iterator sourceIter, RegisteredVisualContainer& source, RegisteredVisualContainer& destination)
193 Toolkit::Visual::Base visual = (*sourceIter)->visual;
196 RegisteredVisual* rv = source.Release(sourceIter);
197 destination.PushBack(rv);
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
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";
215 static bool DoAction(BaseObject* object, const std::string& actionName, const Property::Map& attributes)
219 Dali::BaseHandle handle(object);
221 Toolkit::Control control = Toolkit::Control::DownCast(handle);
223 DALI_ASSERT_ALWAYS(control);
225 if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_ACTIVATED) || actionName == "activate")
227 // if cast succeeds there is an implementation so no need to check
228 if(!DevelControl::AccessibilityActivateSignal(control).Empty())
230 DevelControl::AccessibilityActivateSignal(control).Emit();
234 ret = Internal::GetImplementation(control).OnAccessibilityActivated();
237 else if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_READING_SKIPPED))
239 // if cast succeeds there is an implementation so no need to check
240 if(!DevelControl::AccessibilityReadingSkippedSignal(control).Empty())
242 DevelControl::AccessibilityReadingSkippedSignal(control).Emit();
245 else if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_READING_PAUSED))
247 // if cast succeeds there is an implementation so no need to check
248 if(!DevelControl::AccessibilityReadingPausedSignal(control).Empty())
250 DevelControl::AccessibilityReadingPausedSignal(control).Emit();
253 else if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_READING_RESUMED))
255 // if cast succeeds there is an implementation so no need to check
256 if(!DevelControl::AccessibilityReadingResumedSignal(control).Empty())
258 DevelControl::AccessibilityReadingResumedSignal(control).Emit();
261 else if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_READING_CANCELLED))
263 // if cast succeeds there is an implementation so no need to check
264 if(!DevelControl::AccessibilityReadingCancelledSignal(control).Empty())
266 DevelControl::AccessibilityReadingCancelledSignal(control).Emit();
269 else if(0 == strcmp(actionName.c_str(), ACTION_ACCESSIBILITY_READING_STOPPED))
271 // if cast succeeds there is an implementation so no need to check
272 if(!DevelControl::AccessibilityReadingStoppedSignal(control).Empty())
274 DevelControl::AccessibilityReadingStoppedSignal(control).Emit();
285 * Connects a callback function with the object's signals.
286 * @param[in] object The object providing the signal.
287 * @param[in] tracker Used to disconnect the signal.
288 * @param[in] signalName The signal to connect to.
289 * @param[in] functor A newly allocated FunctorDelegate.
290 * @return True if the signal was connected.
291 * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
293 const char* SIGNAL_KEY_EVENT = "keyEvent";
294 const char* SIGNAL_KEY_INPUT_FOCUS_GAINED = "keyInputFocusGained";
295 const char* SIGNAL_KEY_INPUT_FOCUS_LOST = "keyInputFocusLost";
296 const char* SIGNAL_TAPPED = "tapped";
297 const char* SIGNAL_PANNED = "panned";
298 const char* SIGNAL_PINCHED = "pinched";
299 const char* SIGNAL_LONG_PRESSED = "longPressed";
300 const char* SIGNAL_GET_NAME = "getName";
301 const char* SIGNAL_GET_DESCRIPTION = "getDescription";
302 const char* SIGNAL_DO_GESTURE = "doGesture";
303 static bool DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
305 Dali::BaseHandle handle(object);
307 bool connected(false);
308 Toolkit::Control control = Toolkit::Control::DownCast(handle);
311 Internal::Control& controlImpl(Internal::GetImplementation(control));
314 if(0 == strcmp(signalName.c_str(), SIGNAL_KEY_EVENT))
316 controlImpl.KeyEventSignal().Connect(tracker, functor);
318 else if(0 == strcmp(signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_GAINED))
320 controlImpl.KeyInputFocusGainedSignal().Connect(tracker, functor);
322 else if(0 == strcmp(signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_LOST))
324 controlImpl.KeyInputFocusLostSignal().Connect(tracker, functor);
326 else if(0 == strcmp(signalName.c_str(), SIGNAL_TAPPED))
328 controlImpl.EnableGestureDetection(GestureType::TAP);
329 controlImpl.GetTapGestureDetector().DetectedSignal().Connect(tracker, functor);
331 else if(0 == strcmp(signalName.c_str(), SIGNAL_PANNED))
333 controlImpl.EnableGestureDetection(GestureType::PAN);
334 controlImpl.GetPanGestureDetector().DetectedSignal().Connect(tracker, functor);
336 else if(0 == strcmp(signalName.c_str(), SIGNAL_PINCHED))
338 controlImpl.EnableGestureDetection(GestureType::PINCH);
339 controlImpl.GetPinchGestureDetector().DetectedSignal().Connect(tracker, functor);
341 else if(0 == strcmp(signalName.c_str(), SIGNAL_LONG_PRESSED))
343 controlImpl.EnableGestureDetection(GestureType::LONG_PRESS);
344 controlImpl.GetLongPressGestureDetector().DetectedSignal().Connect(tracker, functor);
346 else if(0 == strcmp(signalName.c_str(), SIGNAL_GET_NAME))
348 DevelControl::AccessibilityGetNameSignal(control).Connect(tracker, functor);
350 else if(0 == strcmp(signalName.c_str(), SIGNAL_GET_DESCRIPTION))
352 DevelControl::AccessibilityGetDescriptionSignal(control).Connect(tracker, functor);
354 else if(0 == strcmp(signalName.c_str(), SIGNAL_DO_GESTURE))
356 DevelControl::AccessibilityDoGestureSignal(control).Connect(tracker, functor);
363 * Creates control through type registry
367 return Internal::Control::New();
369 // Setup signals and actions using the type-registry.
370 DALI_TYPE_REGISTRATION_BEGIN(Control, CustomActor, Create);
372 // Note: Properties are registered separately below.
374 SignalConnectorType registerSignal1(typeRegistration, SIGNAL_KEY_EVENT, &DoConnectSignal);
375 SignalConnectorType registerSignal2(typeRegistration, SIGNAL_KEY_INPUT_FOCUS_GAINED, &DoConnectSignal);
376 SignalConnectorType registerSignal3(typeRegistration, SIGNAL_KEY_INPUT_FOCUS_LOST, &DoConnectSignal);
377 SignalConnectorType registerSignal4(typeRegistration, SIGNAL_TAPPED, &DoConnectSignal);
378 SignalConnectorType registerSignal5(typeRegistration, SIGNAL_PANNED, &DoConnectSignal);
379 SignalConnectorType registerSignal6(typeRegistration, SIGNAL_PINCHED, &DoConnectSignal);
380 SignalConnectorType registerSignal7(typeRegistration, SIGNAL_LONG_PRESSED, &DoConnectSignal);
381 SignalConnectorType registerSignal8(typeRegistration, SIGNAL_GET_NAME, &DoConnectSignal);
382 SignalConnectorType registerSignal9(typeRegistration, SIGNAL_GET_DESCRIPTION, &DoConnectSignal);
383 SignalConnectorType registerSignal10(typeRegistration, SIGNAL_DO_GESTURE, &DoConnectSignal);
385 TypeAction registerAction1(typeRegistration, "activate", &DoAction);
386 TypeAction registerAction2(typeRegistration, ACTION_ACCESSIBILITY_ACTIVATED, &DoAction);
387 TypeAction registerAction3(typeRegistration, ACTION_ACCESSIBILITY_READING_SKIPPED, &DoAction);
388 TypeAction registerAction4(typeRegistration, ACTION_ACCESSIBILITY_READING_CANCELLED, &DoAction);
389 TypeAction registerAction5(typeRegistration, ACTION_ACCESSIBILITY_READING_STOPPED, &DoAction);
390 TypeAction registerAction6(typeRegistration, ACTION_ACCESSIBILITY_READING_PAUSED, &DoAction);
391 TypeAction registerAction7(typeRegistration, ACTION_ACCESSIBILITY_READING_RESUMED, &DoAction);
393 DALI_TYPE_REGISTRATION_END()
396 * @brief Iterate through given container and setOffScene any visual found
398 * @param[in] container Container of visuals
399 * @param[in] parent Parent actor to remove visuals from
401 void SetVisualsOffScene(const RegisteredVisualContainer& container, Actor parent)
403 for(auto iter = container.Begin(), end = container.End(); iter != end; iter++)
407 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::SetOffScene Setting visual(%d) off stage\n", (*iter)->index);
408 Toolkit::GetImplementation((*iter)->visual).SetOffScene(parent);
413 Dali::Rect<> GetShowingGeometry(Dali::Rect<> rect, Dali::Toolkit::DevelControl::AccessibleImpl* accessibleImpl)
416 Vector2 currentPosition;
417 auto parent = dynamic_cast<Toolkit::DevelControl::AccessibleImpl*>(accessibleImpl->GetParent());
421 parentRect = parent->GetExtents(Dali::Accessibility::CoordinateType::WINDOW);
423 currentPosition.x = rect.x;
424 currentPosition.y = rect.y;
426 rect.x = rect.x > parentRect.x ? rect.x : parentRect.x;
427 rect.y = rect.y > parentRect.y ? rect.y : parentRect.y;
428 rect.width = currentPosition.x + rect.width < parentRect.x + parentRect.width ? currentPosition.x + rect.width - rect.x : parentRect.x + parentRect.width - rect.x;
429 rect.height = currentPosition.y + rect.height < parentRect.y + parentRect.height ? currentPosition.y + rect.height - rect.y : parentRect.y + parentRect.height - rect.y;
431 if(rect.width < 0 || rect.height < 0)
436 parent = dynamic_cast<Toolkit::DevelControl::AccessibleImpl*>(parent->GetParent());
442 static bool IsShowingGeometryOnScreen(Dali::Rect<> rect)
444 return rect.width > 0 && rect.height > 0;
447 } // unnamed namespace
450 // Properties registered without macro to use specific member variables.
451 const PropertyRegistration Control::Impl::PROPERTY_1(typeRegistration, "styleName", Toolkit::Control::Property::STYLE_NAME, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
452 const PropertyRegistration Control::Impl::PROPERTY_4(typeRegistration, "keyInputFocus", Toolkit::Control::Property::KEY_INPUT_FOCUS, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
453 const PropertyRegistration Control::Impl::PROPERTY_5(typeRegistration, "background", Toolkit::Control::Property::BACKGROUND, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
454 const PropertyRegistration Control::Impl::PROPERTY_6(typeRegistration, "margin", Toolkit::Control::Property::MARGIN, Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
455 const PropertyRegistration Control::Impl::PROPERTY_7(typeRegistration, "padding", Toolkit::Control::Property::PADDING, Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
456 const PropertyRegistration Control::Impl::PROPERTY_8(typeRegistration, "tooltip", Toolkit::DevelControl::Property::TOOLTIP, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
457 const PropertyRegistration Control::Impl::PROPERTY_9(typeRegistration, "state", Toolkit::DevelControl::Property::STATE, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
458 const PropertyRegistration Control::Impl::PROPERTY_10(typeRegistration, "subState", Toolkit::DevelControl::Property::SUB_STATE, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
459 const PropertyRegistration Control::Impl::PROPERTY_11(typeRegistration, "leftFocusableActorId", Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
460 const PropertyRegistration Control::Impl::PROPERTY_12(typeRegistration, "rightFocusableActorId", Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
461 const PropertyRegistration Control::Impl::PROPERTY_13(typeRegistration, "upFocusableActorId", Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
462 const PropertyRegistration Control::Impl::PROPERTY_14(typeRegistration, "downFocusableActorId", Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
463 const PropertyRegistration Control::Impl::PROPERTY_15(typeRegistration, "shadow", Toolkit::DevelControl::Property::SHADOW, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
464 const PropertyRegistration Control::Impl::PROPERTY_16(typeRegistration, "accessibilityName", Toolkit::DevelControl::Property::ACCESSIBILITY_NAME, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
465 const PropertyRegistration Control::Impl::PROPERTY_17(typeRegistration, "accessibilityDescription", Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
466 const PropertyRegistration Control::Impl::PROPERTY_18(typeRegistration, "accessibilityTranslationDomain", Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
467 const PropertyRegistration Control::Impl::PROPERTY_19(typeRegistration, "accessibilityRole", Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
468 const PropertyRegistration Control::Impl::PROPERTY_20(typeRegistration, "accessibilityHighlightable", Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
469 const PropertyRegistration Control::Impl::PROPERTY_21(typeRegistration, "accessibilityAttributes", Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
470 const PropertyRegistration Control::Impl::PROPERTY_22(typeRegistration, "dispatchKeyEvents", Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
474 Control::Impl::Impl(Control& controlImpl)
475 : mControlImpl(controlImpl),
476 mState(Toolkit::DevelControl::NORMAL),
478 mLeftFocusableActorId(-1),
479 mRightFocusableActorId(-1),
480 mUpFocusableActorId(-1),
481 mDownFocusableActorId(-1),
483 mBackgroundColor(Color::TRANSPARENT),
484 mStartingPinchScale(nullptr),
486 mPadding(0, 0, 0, 0),
488 mKeyInputFocusGainedSignal(),
489 mKeyInputFocusLostSignal(),
490 mResourceReadySignal(),
491 mVisualEventSignal(),
492 mAccessibilityGetNameSignal(),
493 mAccessibilityGetDescriptionSignal(),
494 mAccessibilityDoGestureSignal(),
495 mPinchGestureDetector(),
496 mPanGestureDetector(),
497 mTapGestureDetector(),
498 mLongPressGestureDetector(),
500 mInputMethodContext(),
501 mIdleCallback(nullptr),
502 mFlags(Control::ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
503 mIsKeyboardNavigationSupported(false),
504 mIsKeyboardFocusGroup(false),
505 mIsEmittingResourceReadySignal(false),
506 mNeedToEmitResourceReady(false),
507 mDispatchKeyEvents(true)
509 Dali::Accessibility::Accessible::RegisterControlAccessibilityGetter(
510 [](Dali::Actor actor) -> Dali::Accessibility::Accessible* {
511 return Control::Impl::GetAccessibilityObject(actor);
514 mAccessibilityConstructor = [](Dali::Actor actor) -> std::unique_ptr<Dali::Accessibility::Accessible> {
515 return std::unique_ptr<Dali::Accessibility::Accessible>(new DevelControl::AccessibleImpl(actor, Dali::Accessibility::Role::UNKNOWN));
518 size_t length = static_cast<size_t>(Dali::Accessibility::RelationType::MAX_COUNT);
519 mAccessibilityRelations.reserve(length);
520 for(auto i = 0u; i < length; ++i)
522 mAccessibilityRelations.push_back({});
526 Control::Impl::~Impl()
528 for(auto&& iter : mVisuals)
530 StopObservingVisual(iter->visual);
533 for(auto&& iter : mRemoveVisuals)
535 StopObservingVisual(iter->visual);
538 // All gesture detectors will be destroyed so no need to disconnect.
539 delete mStartingPinchScale;
541 if(mIdleCallback && Adaptor::IsAvailable())
543 // Removes the callback from the callback manager in case the control is destroyed before the callback is executed.
544 Adaptor::Get().RemoveIdle(mIdleCallback);
548 Control::Impl& Control::Impl::Get(Internal::Control& internalControl)
550 return *internalControl.mImpl;
553 const Control::Impl& Control::Impl::Get(const Internal::Control& internalControl)
555 return *internalControl.mImpl;
558 void Control::Impl::CheckHighlightedObjectGeometry()
560 auto accessibleImpl = dynamic_cast<Dali::Toolkit::DevelControl::AccessibleImpl*>(mAccessibilityObject.get());
563 DALI_LOG_ERROR("accessibleImpl is not a pointer to a DevelControl::AccessibleImpl type");
567 auto lastPosition = accessibleImpl->GetLastPosition();
568 auto accessibleRect = accessibleImpl->GetExtents(Dali::Accessibility::CoordinateType::WINDOW);
569 auto rect = GetShowingGeometry(accessibleRect, accessibleImpl);
571 switch(mAccessibilityLastScreenRelativeMoveType)
573 case Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE:
575 if(IsShowingGeometryOnScreen(rect))
577 mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE;
581 case Dali::Accessibility::ScreenRelativeMoveType::INSIDE:
583 if(rect.width < 0 && accessibleRect.x != lastPosition.x)
585 mAccessibilityLastScreenRelativeMoveType = (accessibleRect.x < lastPosition.x) ? Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT : Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT;
587 if(rect.height < 0 && accessibleRect.y != lastPosition.y)
589 mAccessibilityLastScreenRelativeMoveType = (accessibleRect.y < lastPosition.y) ? Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT : Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT;
591 // notify AT-clients on outgoing moves only
592 if(mAccessibilityLastScreenRelativeMoveType != Dali::Accessibility::ScreenRelativeMoveType::INSIDE)
594 mAccessibilityObject.get()->EmitMovedOutOfScreen(mAccessibilityLastScreenRelativeMoveType);
598 case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT:
599 case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT:
601 if(IsShowingGeometryOnScreen(rect))
603 mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE;
607 mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE;
617 accessibleImpl->SetLastPosition(Vector2(accessibleRect.x, accessibleRect.y));
620 void Control::Impl::RegisterAccessibilityPositionPropertyNotification()
622 if(mIsAccessibilityPositionPropertyNotificationSet)
626 // set default value until first move of object is detected
627 mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE;
628 // recalculate mAccessibilityLastScreenRelativeMoveType accordingly to the initial position
629 CheckHighlightedObjectGeometry();
630 mAccessibilityPositionNotification = mControlImpl.Self().AddPropertyNotification(Actor::Property::WORLD_POSITION, StepCondition(1.0f, 1.0f));
631 mAccessibilityPositionNotification.SetNotifyMode(PropertyNotification::NOTIFY_ON_CHANGED);
632 mAccessibilityPositionNotification.NotifySignal().Connect(this, [this](PropertyNotification&){ CheckHighlightedObjectGeometry(); });
633 mIsAccessibilityPositionPropertyNotificationSet = true;
636 void Control::Impl::UnregisterAccessibilityPositionPropertyNotification()
638 mControlImpl.Self().RemovePropertyNotification(mAccessibilityPositionNotification);
639 mIsAccessibilityPositionPropertyNotificationSet = false;
642 // Gesture Detection Methods
643 void Control::Impl::PinchDetected(Actor actor, const PinchGesture& pinch)
645 mControlImpl.OnPinch(pinch);
648 void Control::Impl::PanDetected(Actor actor, const PanGesture& pan)
650 mControlImpl.OnPan(pan);
653 void Control::Impl::TapDetected(Actor actor, const TapGesture& tap)
655 mControlImpl.OnTap(tap);
658 void Control::Impl::LongPressDetected(Actor actor, const LongPressGesture& longPress)
660 mControlImpl.OnLongPress(longPress);
663 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual)
665 RegisterVisual(index, visual, VisualState::ENABLED, DepthIndexValue::NOT_SET);
668 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, int depthIndex)
670 RegisterVisual(index, visual, VisualState::ENABLED, DepthIndexValue::SET, depthIndex);
673 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled)
675 RegisterVisual(index, visual, (enabled ? VisualState::ENABLED : VisualState::DISABLED), DepthIndexValue::NOT_SET);
678 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex)
680 RegisterVisual(index, visual, (enabled ? VisualState::ENABLED : VisualState::DISABLED), DepthIndexValue::SET, depthIndex);
683 void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex)
685 DALI_LOG_INFO(gLogFilter, Debug::Concise, "RegisterVisual:%d \n", index);
687 bool visualReplaced(false);
688 Actor self = mControlImpl.Self();
690 // Set the depth index, if not set by caller this will be either the current visual depth, max depth of all visuals
692 int requiredDepthIndex = visual.GetDepthIndex();
694 if(depthIndexValueSet == DepthIndexValue::SET)
696 requiredDepthIndex = depthIndex;
699 // Visual replacement, existing visual should only be removed from stage when replacement ready.
700 if(!mVisuals.Empty())
702 RegisteredVisualContainer::Iterator registeredVisualsiter;
703 // Check if visual (index) is already registered, this is the current visual.
704 if(FindVisual(index, mVisuals, registeredVisualsiter))
706 Toolkit::Visual::Base& currentRegisteredVisual = (*registeredVisualsiter)->visual;
707 if(currentRegisteredVisual)
709 // Store current visual depth index as may need to set the replacement visual to same depth
710 const int currentDepthIndex = (*registeredVisualsiter)->visual.GetDepthIndex();
712 // No longer required to know if the replaced visual's resources are ready
713 StopObservingVisual(currentRegisteredVisual);
715 // If control staged and visual enabled then visuals will be swapped once ready
716 if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE) && enabled)
718 // Check if visual is currently in the process of being replaced ( is in removal container )
719 RegisteredVisualContainer::Iterator visualQueuedForRemoval;
720 if(FindVisual(index, mRemoveVisuals, visualQueuedForRemoval))
722 // Visual with same index is already in removal container so current visual pending
723 // Only the the last requested visual will be displayed so remove current visual which is staged but not ready.
724 Toolkit::GetImplementation(currentRegisteredVisual).SetOffScene(self);
725 mVisuals.Erase(registeredVisualsiter);
729 // current visual not already in removal container so add now.
730 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %d \n", index);
731 MoveVisual(registeredVisualsiter, mVisuals, mRemoveVisuals);
736 // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later.
737 mVisuals.Erase(registeredVisualsiter);
740 // If we've not set the depth-index value and the new visual does not have a depth index applied to it, then use the previously set depth-index for this index
741 if((depthIndexValueSet == DepthIndexValue::NOT_SET) &&
742 (visual.GetDepthIndex() == 0))
744 requiredDepthIndex = currentDepthIndex;
748 visualReplaced = true;
752 // If not set, set the name of the visual to the same name as the control's property.
753 // ( If the control has been type registered )
754 if(visual.GetName().empty())
756 // returns empty string if index is not found as long as index is not -1
757 std::string visualName = self.GetPropertyName(index);
758 if(!visualName.empty())
760 DALI_LOG_INFO(gLogFilter, Debug::Concise, "Setting visual name for property %d to %s\n", index, visualName.c_str());
761 visual.SetName(visualName);
765 if(!visualReplaced) // New registration entry
767 // If we've not set the depth-index value, we have more than one visual and the visual does not have a depth index, then set it to be the highest
768 if((depthIndexValueSet == DepthIndexValue::NOT_SET) &&
769 (mVisuals.Size() > 0) &&
770 (visual.GetDepthIndex() == 0))
772 int maxDepthIndex = std::numeric_limits<int>::min();
774 RegisteredVisualContainer::ConstIterator iter;
775 const RegisteredVisualContainer::ConstIterator endIter = mVisuals.End();
776 for(iter = mVisuals.Begin(); iter != endIter; iter++)
778 const int visualDepthIndex = (*iter)->visual.GetDepthIndex();
779 if(visualDepthIndex > maxDepthIndex)
781 maxDepthIndex = visualDepthIndex;
784 ++maxDepthIndex; // Add one to the current maximum depth index so that our added visual appears on top
785 requiredDepthIndex = std::max(0, maxDepthIndex); // Start at zero if maxDepth index belongs to a background
791 // Set determined depth index
792 visual.SetDepthIndex(requiredDepthIndex);
794 // Monitor when the visual resources are ready
795 StartObservingVisual(visual);
797 DALI_LOG_INFO(gLogFilter, Debug::Concise, "New Visual registration index[%d] depth[%d]\n", index, requiredDepthIndex);
798 RegisteredVisual* newRegisteredVisual = new RegisteredVisual(index, visual, (enabled == VisualState::ENABLED ? true : false), (visualReplaced && enabled));
799 mVisuals.PushBack(newRegisteredVisual);
801 Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
802 // Put on stage if enabled and the control is already on the stage
803 if((enabled == VisualState::ENABLED) && self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
805 visualImpl.SetOnScene(self);
807 else if(visualImpl.IsResourceReady()) // When not being staged, check if visual already 'ResourceReady' before it was Registered. ( Resource may have been loaded already )
809 ResourceReady(visualImpl);
813 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::RegisterVisual() Registered %s(%d), enabled:%s\n", visual.GetName().c_str(), index, enabled ? "true" : "false");
816 void Control::Impl::UnregisterVisual(Property::Index index)
818 RegisteredVisualContainer::Iterator iter;
819 if(FindVisual(index, mVisuals, iter))
821 // stop observing visual
822 StopObservingVisual((*iter)->visual);
824 Actor self(mControlImpl.Self());
825 Toolkit::GetImplementation((*iter)->visual).SetOffScene(self);
826 (*iter)->visual.Reset();
827 mVisuals.Erase(iter);
830 if(FindVisual(index, mRemoveVisuals, iter))
832 Actor self(mControlImpl.Self());
833 Toolkit::GetImplementation((*iter)->visual).SetOffScene(self);
834 (*iter)->pending = false;
835 (*iter)->visual.Reset();
836 mRemoveVisuals.Erase(iter);
840 Toolkit::Visual::Base Control::Impl::GetVisual(Property::Index index) const
842 RegisteredVisualContainer::Iterator iter;
843 if(FindVisual(index, mVisuals, iter))
845 return (*iter)->visual;
848 return Toolkit::Visual::Base();
851 void Control::Impl::EnableVisual(Property::Index index, bool enable)
853 DALI_LOG_INFO(gLogFilter, Debug::General, "Control::EnableVisual(%d, %s)\n", index, enable ? "T" : "F");
855 RegisteredVisualContainer::Iterator iter;
856 if(FindVisual(index, mVisuals, iter))
858 if((*iter)->enabled == enable)
860 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Visual %s(%d) already %s\n", (*iter)->visual.GetName().c_str(), index, enable ? "enabled" : "disabled");
864 (*iter)->enabled = enable;
865 Actor parentActor = mControlImpl.Self();
866 if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE)) // If control not on Scene then Visual will be added when SceneConnection is called.
870 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) on stage \n", (*iter)->visual.GetName().c_str(), index);
871 Toolkit::GetImplementation((*iter)->visual).SetOnScene(parentActor);
875 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) off stage \n", (*iter)->visual.GetName().c_str(), index);
876 Toolkit::GetImplementation((*iter)->visual).SetOffScene(parentActor); // No need to call if control not staged.
882 DALI_LOG_WARNING("Control::EnableVisual(%d, %s) FAILED - NO SUCH VISUAL\n", index, enable ? "T" : "F");
886 bool Control::Impl::IsVisualEnabled(Property::Index index) const
888 RegisteredVisualContainer::Iterator iter;
889 if(FindVisual(index, mVisuals, iter))
891 return (*iter)->enabled;
896 void Control::Impl::StopObservingVisual(Toolkit::Visual::Base& visual)
898 Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
900 // Stop observing the visual
901 visualImpl.RemoveEventObserver(*this);
904 void Control::Impl::StartObservingVisual(Toolkit::Visual::Base& visual)
906 Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
908 // start observing the visual for events
909 visualImpl.AddEventObserver(*this);
912 // Called by a Visual when it's resource is ready
913 void Control::Impl::ResourceReady(Visual::Base& object)
915 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::Impl::ResourceReady() replacements pending[%d]\n", mRemoveVisuals.Count());
917 Actor self = mControlImpl.Self();
919 // A resource is ready, find resource in the registered visuals container and get its index
920 for(auto registeredIter = mVisuals.Begin(), end = mVisuals.End(); registeredIter != end; ++registeredIter)
922 Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation((*registeredIter)->visual);
924 if(&object == ®isteredVisualImpl)
926 RegisteredVisualContainer::Iterator visualToRemoveIter;
927 // Find visual with the same index in the removal container
928 // Set if off stage as it's replacement is now ready.
929 // Remove if from removal list as now removed from stage.
930 // Set Pending flag on the ready visual to false as now ready.
931 if(FindVisual((*registeredIter)->index, mRemoveVisuals, visualToRemoveIter))
933 (*registeredIter)->pending = false;
934 Toolkit::GetImplementation((*visualToRemoveIter)->visual).SetOffScene(self);
935 mRemoveVisuals.Erase(visualToRemoveIter);
941 // A visual is ready so control may need relayouting if staged
942 if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
944 mControlImpl.RelayoutRequest();
947 // Emit signal if all enabled visuals registered by the control are ready.
948 if(IsResourceReady())
951 mNeedToEmitResourceReady = false;
953 EmitResourceReadySignal();
957 void Control::Impl::NotifyVisualEvent(Visual::Base& object, Property::Index signalId)
959 for(auto registeredIter = mVisuals.Begin(), end = mVisuals.End(); registeredIter != end; ++registeredIter)
961 Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation((*registeredIter)->visual);
962 if(&object == ®isteredVisualImpl)
964 Dali::Toolkit::Control handle(mControlImpl.GetOwner());
965 mVisualEventSignal.Emit(handle, (*registeredIter)->index, signalId);
971 bool Control::Impl::IsResourceReady() const
973 // Iterate through and check all the enabled visuals are ready
974 for(auto visualIter = mVisuals.Begin();
975 visualIter != mVisuals.End();
978 const Toolkit::Visual::Base visual = (*visualIter)->visual;
979 const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
981 // one of the enabled visuals is not ready
982 if(!visualImpl.IsResourceReady() && (*visualIter)->enabled)
990 Toolkit::Visual::ResourceStatus Control::Impl::GetVisualResourceStatus(Property::Index index) const
992 RegisteredVisualContainer::Iterator iter;
993 if(FindVisual(index, mVisuals, iter))
995 const Toolkit::Visual::Base visual = (*iter)->visual;
996 const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
997 return visualImpl.GetResourceStatus();
1000 return Toolkit::Visual::ResourceStatus::PREPARING;
1003 void Control::Impl::AddTransitions(Dali::Animation& animation,
1004 const Toolkit::TransitionData& handle,
1005 bool createAnimation)
1007 // Setup a Transition from TransitionData.
1008 const Internal::TransitionData& transitionData = Toolkit::GetImplementation(handle);
1009 TransitionData::Iterator end = transitionData.End();
1010 for(TransitionData::Iterator iter = transitionData.Begin();
1014 TransitionData::Animator* animator = (*iter);
1016 Toolkit::Visual::Base visual = GetVisualByName(mVisuals, animator->objectName);
1020 #if defined(DEBUG_ENABLED)
1021 Dali::TypeInfo typeInfo;
1022 ControlWrapper* controlWrapperImpl = dynamic_cast<ControlWrapper*>(&mControlImpl);
1023 if(controlWrapperImpl)
1025 typeInfo = controlWrapperImpl->GetTypeInfo();
1028 DALI_LOG_INFO(gLogFilter, Debug::Concise, "CreateTransition: Found %s visual for %s\n", visual.GetName().c_str(), typeInfo ? typeInfo.GetName().c_str() : "Unknown");
1030 Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
1031 visualImpl.AnimateProperty(animation, *animator);
1035 DALI_LOG_INFO(gLogFilter, Debug::Concise, "CreateTransition: Could not find visual. Trying actors");
1036 // Otherwise, try any actor children of control (Including the control)
1037 Actor child = mControlImpl.Self().FindChildByName(animator->objectName);
1040 Property::Index propertyIndex = child.GetPropertyIndex(animator->propertyKey);
1041 if(propertyIndex != Property::INVALID_INDEX)
1043 if(animator->animate == false)
1045 if(animator->targetValue.GetType() != Property::NONE)
1047 child.SetProperty(propertyIndex, animator->targetValue);
1050 else // animate the property
1052 if(animator->initialValue.GetType() != Property::NONE)
1054 child.SetProperty(propertyIndex, animator->initialValue);
1057 if(createAnimation && !animation)
1059 animation = Dali::Animation::New(0.1f);
1062 animation.AnimateTo(Property(child, propertyIndex),
1063 animator->targetValue,
1064 animator->alphaFunction,
1065 TimePeriod(animator->timePeriodDelay,
1066 animator->timePeriodDuration));
1074 Dali::Animation Control::Impl::CreateTransition(const Toolkit::TransitionData& transitionData)
1076 Dali::Animation transition;
1078 if(transitionData.Count() > 0)
1080 AddTransitions(transition, transitionData, true);
1085 void Control::Impl::DoAction(Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes)
1087 RegisteredVisualContainer::Iterator iter;
1088 if(FindVisual(visualIndex, mVisuals, iter))
1090 Toolkit::GetImplementation((*iter)->visual).DoAction(actionId, attributes);
1094 void Control::Impl::AppendAccessibilityAttribute(const std::string& key, const std::string value)
1096 Property::Value* checkedValue = mAccessibilityAttributes.Find(key);
1099 mAccessibilityAttributes[key] = Property::Value(value);
1103 mAccessibilityAttributes.Insert(key, value);
1107 void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
1109 Toolkit::Control control = Toolkit::Control::DownCast(BaseHandle(object));
1113 Control& controlImpl(GetImplementation(control));
1117 case Toolkit::Control::Property::STYLE_NAME:
1119 controlImpl.SetStyleName(value.Get<std::string>());
1123 case Toolkit::DevelControl::Property::STATE:
1125 bool withTransitions = true;
1126 const Property::Value* valuePtr = &value;
1127 const Property::Map* map = value.GetMap();
1130 Property::Value* value2 = map->Find("withTransitions");
1133 withTransitions = value2->Get<bool>();
1136 valuePtr = map->Find("state");
1141 Toolkit::DevelControl::State state(controlImpl.mImpl->mState);
1142 if(Scripting::GetEnumerationProperty<Toolkit::DevelControl::State>(*valuePtr, ControlStateTable, ControlStateTableCount, state))
1144 controlImpl.mImpl->SetState(state, withTransitions);
1150 case Toolkit::DevelControl::Property::SUB_STATE:
1152 std::string subState;
1153 if(value.Get(subState))
1155 controlImpl.mImpl->SetSubState(subState);
1160 case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
1163 if(value.Get(focusId))
1165 controlImpl.mImpl->mLeftFocusableActorId = focusId;
1170 case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
1173 if(value.Get(focusId))
1175 controlImpl.mImpl->mRightFocusableActorId = focusId;
1180 case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
1183 if(value.Get(focusId))
1185 controlImpl.mImpl->mUpFocusableActorId = focusId;
1190 case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
1193 if(value.Get(focusId))
1195 controlImpl.mImpl->mDownFocusableActorId = focusId;
1200 case Toolkit::Control::Property::KEY_INPUT_FOCUS:
1202 if(value.Get<bool>())
1204 controlImpl.SetKeyInputFocus();
1208 controlImpl.ClearKeyInputFocus();
1213 case Toolkit::Control::Property::BACKGROUND:
1217 const Property::Map* map = value.GetMap();
1218 if(map && !map->Empty())
1220 controlImpl.SetBackground(*map);
1222 else if(value.Get(url))
1224 // don't know the size to load
1225 Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual(url, ImageDimensions());
1228 controlImpl.mImpl->RegisterVisual(Toolkit::Control::Property::BACKGROUND, visual, DepthIndex::BACKGROUND);
1231 else if(value.Get(color))
1233 controlImpl.SetBackgroundColor(color);
1237 // The background is an empty property map, so we should clear the background
1238 controlImpl.ClearBackground();
1243 case Toolkit::Control::Property::MARGIN:
1246 if(value.Get(margin))
1248 controlImpl.mImpl->SetMargin(margin);
1253 case Toolkit::Control::Property::PADDING:
1256 if(value.Get(padding))
1258 controlImpl.mImpl->SetPadding(padding);
1263 case Toolkit::DevelControl::Property::TOOLTIP:
1265 TooltipPtr& tooltipPtr = controlImpl.mImpl->mTooltip;
1268 tooltipPtr = Tooltip::New(control);
1270 tooltipPtr->SetProperties(value);
1274 case Toolkit::DevelControl::Property::SHADOW:
1276 const Property::Map* map = value.GetMap();
1277 if(map && !map->Empty())
1279 controlImpl.mImpl->SetShadow(*map);
1283 // The shadow is an empty property map, so we should clear the shadow
1284 controlImpl.mImpl->ClearShadow();
1289 case Toolkit::DevelControl::Property::ACCESSIBILITY_NAME:
1294 controlImpl.mImpl->mAccessibilityName = name;
1295 controlImpl.mImpl->mAccessibilityNameSet = true;
1299 controlImpl.mImpl->mAccessibilityNameSet = false;
1304 case Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION:
1309 controlImpl.mImpl->mAccessibilityDescription = text;
1310 controlImpl.mImpl->mAccessibilityDescriptionSet = true;
1314 controlImpl.mImpl->mAccessibilityDescriptionSet = false;
1319 case Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN:
1324 controlImpl.mImpl->mAccessibilityTranslationDomain = text;
1325 controlImpl.mImpl->mAccessibilityTranslationDomainSet = true;
1329 controlImpl.mImpl->mAccessibilityTranslationDomainSet = false;
1334 case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE:
1336 Dali::Accessibility::Role role;
1339 controlImpl.mImpl->mAccessibilityRole = role;
1344 case Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE:
1347 if(value.Get(highlightable))
1349 controlImpl.mImpl->mAccessibilityHighlightable = highlightable;
1350 controlImpl.mImpl->mAccessibilityHighlightableSet = true;
1354 controlImpl.mImpl->mAccessibilityHighlightableSet = false;
1359 case Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES:
1361 const Property::Map* map = value.GetMap();
1362 if(map && !map->Empty())
1364 controlImpl.mImpl->mAccessibilityAttributes = *map;
1369 case Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS:
1372 if(value.Get(dispatch))
1374 controlImpl.mImpl->mDispatchKeyEvents = dispatch;
1382 Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index index)
1384 Property::Value value;
1386 Toolkit::Control control = Toolkit::Control::DownCast(BaseHandle(object));
1390 Control& controlImpl(GetImplementation(control));
1394 case Toolkit::Control::Property::STYLE_NAME:
1396 value = controlImpl.GetStyleName();
1400 case Toolkit::DevelControl::Property::STATE:
1402 value = controlImpl.mImpl->mState;
1406 case Toolkit::DevelControl::Property::SUB_STATE:
1408 value = controlImpl.mImpl->mSubStateName;
1412 case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
1414 value = controlImpl.mImpl->mLeftFocusableActorId;
1418 case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
1420 value = controlImpl.mImpl->mRightFocusableActorId;
1424 case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
1426 value = controlImpl.mImpl->mUpFocusableActorId;
1430 case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
1432 value = controlImpl.mImpl->mDownFocusableActorId;
1436 case Toolkit::Control::Property::KEY_INPUT_FOCUS:
1438 value = controlImpl.HasKeyInputFocus();
1442 case Toolkit::Control::Property::BACKGROUND:
1445 Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual(Toolkit::Control::Property::BACKGROUND);
1448 visual.CreatePropertyMap(map);
1455 case Toolkit::Control::Property::MARGIN:
1457 value = controlImpl.mImpl->GetMargin();
1461 case Toolkit::Control::Property::PADDING:
1463 value = controlImpl.mImpl->GetPadding();
1467 case Toolkit::DevelControl::Property::TOOLTIP:
1470 if(controlImpl.mImpl->mTooltip)
1472 controlImpl.mImpl->mTooltip->CreatePropertyMap(map);
1478 case Toolkit::DevelControl::Property::SHADOW:
1481 Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual(Toolkit::DevelControl::Property::SHADOW);
1484 visual.CreatePropertyMap(map);
1491 case Toolkit::DevelControl::Property::ACCESSIBILITY_NAME:
1493 if(controlImpl.mImpl->mAccessibilityNameSet)
1495 value = controlImpl.mImpl->mAccessibilityName;
1500 case Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION:
1502 if(controlImpl.mImpl->mAccessibilityDescriptionSet)
1504 value = controlImpl.mImpl->mAccessibilityDescription;
1509 case Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN:
1511 if(controlImpl.mImpl->mAccessibilityTranslationDomainSet)
1513 value = controlImpl.mImpl->mAccessibilityTranslationDomain;
1518 case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE:
1520 value = Property::Value(controlImpl.mImpl->mAccessibilityRole);
1524 case Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE:
1526 if(controlImpl.mImpl->mAccessibilityHighlightableSet)
1528 value = controlImpl.mImpl->mAccessibilityHighlightable;
1533 case Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES:
1535 value = controlImpl.mImpl->mAccessibilityAttributes;
1538 case Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS:
1540 value = controlImpl.mImpl->mDispatchKeyEvents;
1549 void Control::Impl::RemoveAccessibilityAttribute(const std::string& key)
1551 Property::Value* value = mAccessibilityAttributes.Find(key);
1554 mAccessibilityAttributes[key] = Property::Value();
1558 void Control::Impl::ClearAccessibilityAttributes()
1560 mAccessibilityAttributes.Clear();
1563 void Control::Impl::SetAccessibilityReadingInfoType(const Dali::Accessibility::ReadingInfoTypes types)
1565 std::string value{};
1566 if(types[Dali::Accessibility::ReadingInfoType::NAME])
1568 value += READING_INFO_TYPE_NAME;
1570 if(types[Dali::Accessibility::ReadingInfoType::ROLE])
1574 value += READING_INFO_TYPE_SEPARATOR;
1576 value += READING_INFO_TYPE_ROLE;
1578 if(types[Dali::Accessibility::ReadingInfoType::DESCRIPTION])
1582 value += READING_INFO_TYPE_SEPARATOR;
1584 value += READING_INFO_TYPE_DESCRIPTION;
1586 if(types[Dali::Accessibility::ReadingInfoType::STATE])
1590 value += READING_INFO_TYPE_SEPARATOR;
1592 value += READING_INFO_TYPE_STATE;
1594 AppendAccessibilityAttribute(READING_INFO_TYPE_ATTRIBUTE_NAME, value);
1597 Dali::Accessibility::ReadingInfoTypes Control::Impl::GetAccessibilityReadingInfoType() const
1599 std::string value{};
1600 auto place = mAccessibilityAttributes.Find(READING_INFO_TYPE_ATTRIBUTE_NAME);
1607 Dali::Accessibility::ReadingInfoTypes types;
1608 types[Dali::Accessibility::ReadingInfoType::NAME] = true;
1609 types[Dali::Accessibility::ReadingInfoType::ROLE] = true;
1610 types[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
1611 types[Dali::Accessibility::ReadingInfoType::STATE] = true;
1620 Dali::Accessibility::ReadingInfoTypes types;
1622 if(value.find(READING_INFO_TYPE_NAME) != std::string::npos)
1624 types[Dali::Accessibility::ReadingInfoType::NAME] = true;
1626 if(value.find(READING_INFO_TYPE_ROLE) != std::string::npos)
1628 types[Dali::Accessibility::ReadingInfoType::ROLE] = true;
1630 if(value.find(READING_INFO_TYPE_DESCRIPTION) != std::string::npos)
1632 types[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true;
1634 if(value.find(READING_INFO_TYPE_STATE) != std::string::npos)
1636 types[Dali::Accessibility::ReadingInfoType::STATE] = true;
1642 void Control::Impl::CopyInstancedProperties(RegisteredVisualContainer& visuals, Dictionary<Property::Map>& instancedProperties)
1644 for(RegisteredVisualContainer::Iterator iter = visuals.Begin(); iter != visuals.End(); iter++)
1648 Property::Map instanceMap;
1649 Toolkit::GetImplementation((*iter)->visual).CreateInstancePropertyMap(instanceMap);
1650 instancedProperties.Add((*iter)->visual.GetName(), instanceMap);
1655 void Control::Impl::RemoveVisual(RegisteredVisualContainer& visuals, const std::string& visualName)
1657 Actor self(mControlImpl.Self());
1659 for(RegisteredVisualContainer::Iterator visualIter = visuals.Begin();
1660 visualIter != visuals.End();
1663 Toolkit::Visual::Base visual = (*visualIter)->visual;
1664 if(visual && visual.GetName() == visualName)
1666 Toolkit::GetImplementation(visual).SetOffScene(self);
1667 (*visualIter)->visual.Reset();
1668 visuals.Erase(visualIter);
1674 void Control::Impl::RemoveVisuals(RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals)
1676 Actor self(mControlImpl.Self());
1677 for(DictionaryKeys::iterator iter = removeVisuals.begin(); iter != removeVisuals.end(); ++iter)
1679 const std::string visualName = *iter;
1680 RemoveVisual(visuals, visualName);
1684 void Control::Impl::RecreateChangedVisuals(Dictionary<Property::Map>& stateVisualsToChange,
1685 Dictionary<Property::Map>& instancedProperties)
1687 Dali::CustomActor handle(mControlImpl.GetOwner());
1688 for(Dictionary<Property::Map>::iterator iter = stateVisualsToChange.Begin();
1689 iter != stateVisualsToChange.End();
1692 const std::string& visualName = (*iter).key;
1693 const Property::Map& toMap = (*iter).entry;
1695 Actor self = mControlImpl.Self();
1696 RegisteredVisualContainer::Iterator registeredVisualsiter;
1697 // Check if visual (visualName) is already registered, this is the current visual.
1698 if(FindVisual(visualName, mVisuals, registeredVisualsiter))
1700 Toolkit::Visual::Base& visual = (*registeredVisualsiter)->visual;
1703 // No longer required to know if the replaced visual's resources are ready
1704 StopObservingVisual(visual);
1706 // If control staged then visuals will be swapped once ready
1707 if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
1709 // Check if visual is currently in the process of being replaced ( is in removal container )
1710 RegisteredVisualContainer::Iterator visualQueuedForRemoval;
1711 if(FindVisual(visualName, mRemoveVisuals, visualQueuedForRemoval))
1713 // Visual with same visual name is already in removal container so current visual pending
1714 // Only the the last requested visual will be displayed so remove current visual which is staged but not ready.
1715 Toolkit::GetImplementation(visual).SetOffScene(self);
1716 (*registeredVisualsiter)->visual.Reset();
1717 mVisuals.Erase(registeredVisualsiter);
1721 // current visual not already in removal container so add now.
1722 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %s \n", visualName.c_str());
1723 MoveVisual(registeredVisualsiter, mVisuals, mRemoveVisuals);
1728 // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later.
1729 (*registeredVisualsiter)->visual.Reset();
1730 mVisuals.Erase(registeredVisualsiter);
1734 const Property::Map* instancedMap = instancedProperties.FindConst(visualName);
1735 Style::ApplyVisual(handle, visualName, toMap, instancedMap);
1740 void Control::Impl::ReplaceStateVisualsAndProperties(const StylePtr oldState, const StylePtr newState, const std::string& subState)
1742 // Collect all old visual names
1743 DictionaryKeys stateVisualsToRemove;
1746 oldState->visuals.GetKeys(stateVisualsToRemove);
1747 if(!subState.empty())
1749 const StylePtr* oldSubState = oldState->subStates.FindConst(subState);
1752 DictionaryKeys subStateVisualsToRemove;
1753 (*oldSubState)->visuals.GetKeys(subStateVisualsToRemove);
1754 Merge(stateVisualsToRemove, subStateVisualsToRemove);
1759 // Collect all new visual properties
1760 Dictionary<Property::Map> stateVisualsToAdd;
1763 stateVisualsToAdd = newState->visuals;
1764 if(!subState.empty())
1766 const StylePtr* newSubState = newState->subStates.FindConst(subState);
1769 stateVisualsToAdd.Merge((*newSubState)->visuals);
1774 // If a name is in both add/remove, move it to change list.
1775 Dictionary<Property::Map> stateVisualsToChange;
1776 FindChangableVisuals(stateVisualsToAdd, stateVisualsToChange, stateVisualsToRemove);
1778 // Copy instanced properties (e.g. text label) of current visuals
1779 Dictionary<Property::Map> instancedProperties;
1780 CopyInstancedProperties(mVisuals, instancedProperties);
1782 // For each visual in remove list, remove from mVisuals
1783 RemoveVisuals(mVisuals, stateVisualsToRemove);
1785 // For each visual in add list, create and add to mVisuals
1786 Dali::CustomActor handle(mControlImpl.GetOwner());
1787 Style::ApplyVisuals(handle, stateVisualsToAdd, instancedProperties);
1789 // For each visual in change list, if it requires a new visual,
1790 // remove old visual, create and add to mVisuals
1791 RecreateChangedVisuals(stateVisualsToChange, instancedProperties);
1794 void Control::Impl::SetState(DevelControl::State newState, bool withTransitions)
1796 DevelControl::State oldState = mState;
1797 Dali::CustomActor handle(mControlImpl.GetOwner());
1798 DALI_LOG_INFO(gLogFilter, Debug::Concise, "Control::Impl::SetState: %s\n", (mState == DevelControl::NORMAL ? "NORMAL" : (mState == DevelControl::FOCUSED ? "FOCUSED" : (mState == DevelControl::DISABLED ? "DISABLED" : "NONE"))));
1800 if(mState != newState)
1802 // If mState was Disabled, and new state is Focused, should probably
1803 // store that fact, e.g. in another property that FocusManager can access.
1806 // Trigger state change and transitions
1807 // Apply new style, if stylemanager is available
1808 Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
1811 const StylePtr stylePtr = GetImpl(styleManager).GetRecordedStyle(Toolkit::Control(mControlImpl.GetOwner()));
1815 std::string oldStateName = Scripting::GetEnumerationName<Toolkit::DevelControl::State>(oldState, ControlStateTable, ControlStateTableCount);
1816 std::string newStateName = Scripting::GetEnumerationName<Toolkit::DevelControl::State>(newState, ControlStateTable, ControlStateTableCount);
1818 const StylePtr* newStateStyle = stylePtr->subStates.Find(newStateName);
1819 const StylePtr* oldStateStyle = stylePtr->subStates.Find(oldStateName);
1820 if(oldStateStyle && newStateStyle)
1822 // Only change if both state styles exist
1823 ReplaceStateVisualsAndProperties(*oldStateStyle, *newStateStyle, mSubStateName);
1830 void Control::Impl::SetSubState(const std::string& subStateName, bool withTransitions)
1832 if(mSubStateName != subStateName)
1834 // Get existing sub-state visuals, and unregister them
1835 Dali::CustomActor handle(mControlImpl.GetOwner());
1837 Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
1840 const StylePtr stylePtr = GetImpl(styleManager).GetRecordedStyle(Toolkit::Control(mControlImpl.GetOwner()));
1844 std::string stateName = Scripting::GetEnumerationName<Toolkit::DevelControl::State>(mState, ControlStateTable, ControlStateTableCount);
1846 const StylePtr* state = stylePtr->subStates.Find(stateName);
1849 StylePtr stateStyle(*state);
1851 const StylePtr* newStateStyle = stateStyle->subStates.Find(subStateName);
1852 const StylePtr* oldStateStyle = stateStyle->subStates.Find(mSubStateName);
1853 if(oldStateStyle && newStateStyle)
1856 ReplaceStateVisualsAndProperties(*oldStateStyle, *newStateStyle, empty);
1862 mSubStateName = subStateName;
1866 void Control::Impl::OnSceneDisconnection()
1868 Actor self = mControlImpl.Self();
1870 // Any visuals set for replacement but not yet ready should still be registered.
1871 // Reason: If a request was made to register a new visual but the control removed from scene before visual was ready
1872 // then when this control appears back on stage it should use that new visual.
1874 // Iterate through all registered visuals and set off scene
1875 SetVisualsOffScene(mVisuals, self);
1877 // Visuals pending replacement can now be taken out of the removal list and set off scene
1878 // Iterate through all replacement visuals and add to a move queue then set off scene
1879 for(auto removalIter = mRemoveVisuals.Begin(), end = mRemoveVisuals.End(); removalIter != end; removalIter++)
1881 Toolkit::GetImplementation((*removalIter)->visual).SetOffScene(self);
1884 for(auto replacedIter = mVisuals.Begin(), end = mVisuals.End(); replacedIter != end; replacedIter++)
1886 (*replacedIter)->pending = false;
1889 mRemoveVisuals.Clear();
1892 void Control::Impl::SetMargin(Extents margin)
1894 mControlImpl.mImpl->mMargin = margin;
1896 // Trigger a size negotiation request that may be needed when setting a margin.
1897 mControlImpl.RelayoutRequest();
1900 Extents Control::Impl::GetMargin() const
1902 return mControlImpl.mImpl->mMargin;
1905 void Control::Impl::SetPadding(Extents padding)
1907 mControlImpl.mImpl->mPadding = padding;
1909 // Trigger a size negotiation request that may be needed when setting a padding.
1910 mControlImpl.RelayoutRequest();
1913 Extents Control::Impl::GetPadding() const
1915 return mControlImpl.mImpl->mPadding;
1918 void Control::Impl::SetInputMethodContext(InputMethodContext& inputMethodContext)
1920 mInputMethodContext = inputMethodContext;
1923 bool Control::Impl::FilterKeyEvent(const KeyEvent& event)
1925 bool consumed(false);
1927 if(mInputMethodContext)
1929 consumed = mInputMethodContext.FilterEventKey(event);
1934 DevelControl::VisualEventSignalType& Control::Impl::VisualEventSignal()
1936 return mVisualEventSignal;
1939 void Control::Impl::SetShadow(const Property::Map& map)
1941 Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual(map);
1942 visual.SetName("shadow");
1946 mControlImpl.mImpl->RegisterVisual(Toolkit::DevelControl::Property::SHADOW, visual, DepthIndex::BACKGROUND_EFFECT);
1948 mControlImpl.RelayoutRequest();
1952 void Control::Impl::ClearShadow()
1954 mControlImpl.mImpl->UnregisterVisual(Toolkit::DevelControl::Property::SHADOW);
1956 // Trigger a size negotiation request that may be needed when unregistering a visual.
1957 mControlImpl.RelayoutRequest();
1960 Dali::Property Control::Impl::GetVisualProperty(Dali::Property::Index index, Dali::Property::Key visualPropertyKey)
1962 Toolkit::Visual::Base visual = GetVisualByIndex(mVisuals, index);
1965 Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual);
1966 return visualImpl.GetPropertyObject(visualPropertyKey);
1970 return Dali::Property(handle, Property::INVALID_INDEX);
1973 void Control::Impl::MakeVisualTransition(Dali::Animation& animation, Dali::Toolkit::Control source, Dali::Property::Index visualIndex, AlphaFunction alphaFunction, TimePeriod timePeriod)
1975 Dali::Toolkit::Control sourceHandle = Dali::Toolkit::Control::DownCast(source);
1976 Property::Map sourceMap = sourceHandle.GetProperty<Property::Map>(visualIndex);
1977 Dali::Toolkit::Control destinationHandle = Dali::Toolkit::Control::DownCast(mControlImpl.Self());
1978 Property::Map destinationMap = destinationHandle.GetProperty<Property::Map>(visualIndex);
1980 Vector4 mixColor(1.0f, 1.0f, 1.0f, 1.0f);
1981 Vector4 cornerRadius(0.0f, 0.0f, 0.0f, 0.0f);
1982 float borderlineWidth(0.0f);
1983 Vector4 borderlineColor(0.0f, 0.0f, 0.0f, 1.0f);
1984 float borderlineOffset(0.0f);
1986 if(!destinationMap.Empty())
1988 static auto findValueVector4 = [](const Property::Map& map, Property::Index index, const Vector4& defaultValue = Vector4()) -> Vector4 {
1989 Property::Value* propertyValue = map.Find(index);
1992 return propertyValue->Get<Vector4>();
1994 return defaultValue;
1997 static auto findValueFloat = [](const Property::Map& map, Property::Index index, const float& defaultValue = 0.0f) -> float {
1998 Property::Value* propertyValue = map.Find(index);
2001 return propertyValue->Get<float>();
2003 return defaultValue;
2006 mixColor = findValueVector4(destinationMap, Dali::Toolkit::Visual::Property::MIX_COLOR, mixColor);
2007 cornerRadius = findValueVector4(destinationMap, Toolkit::DevelVisual::Property::CORNER_RADIUS, cornerRadius);
2008 borderlineWidth = findValueFloat(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth);
2009 borderlineColor = findValueVector4(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_COLOR, borderlineColor);
2010 borderlineOffset = findValueFloat(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset);
2012 if(sourceMap.Empty())
2014 sourceMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
2015 sourceMap.Insert(Dali::Toolkit::Visual::Property::MIX_COLOR, Color::TRANSPARENT);
2016 sourceMap.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, cornerRadius);
2017 sourceMap.Insert(Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth);
2018 sourceMap.Insert(Toolkit::DevelVisual::Property::BORDERLINE_COLOR, borderlineColor);
2019 sourceMap.Insert(Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset);
2022 Vector4 sourceMixColor = findValueVector4(sourceMap, Dali::Toolkit::Visual::Property::MIX_COLOR, mixColor);
2023 Vector4 sourceCornerRadius = findValueVector4(sourceMap, Toolkit::DevelVisual::Property::CORNER_RADIUS, cornerRadius);
2024 float sourceBorderlineWidth = findValueFloat(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth);
2025 Vector4 sourceBorderlineColor = findValueVector4(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_COLOR, borderlineColor);
2026 float sourceBorderlineOffset = findValueFloat(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset);
2028 std::vector<Dali::Property> properties;
2029 std::vector<std::pair<Property::Value, Property::Value>> values;
2031 if(Vector3(sourceMixColor) != Vector3(mixColor))
2033 properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::Visual::Property::MIX_COLOR));
2034 values.push_back(std::make_pair(Vector3(sourceMixColor), Vector3(mixColor)));
2037 if(std::abs(sourceMixColor.a - mixColor.a) > Math::MACHINE_EPSILON_1)
2039 properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::Visual::Property::OPACITY));
2040 values.push_back(std::make_pair(sourceMixColor.a, mixColor.a));
2043 if(sourceCornerRadius != cornerRadius)
2045 properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::CORNER_RADIUS));
2046 values.push_back(std::make_pair(sourceCornerRadius, cornerRadius));
2049 if(sourceBorderlineWidth != borderlineWidth)
2051 properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::BORDERLINE_WIDTH));
2052 values.push_back(std::make_pair(sourceBorderlineWidth, borderlineWidth));
2055 if(sourceBorderlineColor != borderlineColor)
2057 properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::BORDERLINE_COLOR));
2058 values.push_back(std::make_pair(sourceBorderlineColor, borderlineColor));
2061 if(sourceBorderlineOffset != borderlineOffset)
2063 properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::BORDERLINE_OFFSET));
2064 values.push_back(std::make_pair(sourceBorderlineOffset, borderlineOffset));
2067 for(uint32_t i = 0; i < properties.size(); ++i)
2069 if(timePeriod.delaySeconds > 0.0f)
2071 Dali::KeyFrames initialKeyframes = Dali::KeyFrames::New();
2072 initialKeyframes.Add(0.0f, values[i].first);
2073 initialKeyframes.Add(1.0f, values[i].first);
2074 animation.AnimateBetween(properties[i], initialKeyframes, TimePeriod(timePeriod.delaySeconds));
2076 Dali::KeyFrames keyframes = Dali::KeyFrames::New();
2077 keyframes.Add(0.0f, values[i].first);
2078 keyframes.Add(1.0f, values[i].second);
2079 animation.AnimateBetween(properties[i], keyframes, alphaFunction, timePeriod);
2084 void Control::Impl::EmitResourceReadySignal()
2086 if(!mIsEmittingResourceReadySignal)
2088 // Guard against calls to emit the signal during the callback
2089 mIsEmittingResourceReadySignal = true;
2091 // If the signal handler changes visual, it may become ready during this call & therefore this method will
2092 // get called again recursively. If so, mNeedToEmitResourceReady is set below, and we act on it after that secondary
2093 // invocation has completed by notifying in an Idle callback to prevent further recursion.
2094 Dali::Toolkit::Control handle(mControlImpl.GetOwner());
2095 mResourceReadySignal.Emit(handle);
2097 if(mNeedToEmitResourceReady)
2099 // Add idler to emit the signal again
2102 // The callback manager takes the ownership of the callback object.
2103 mIdleCallback = MakeCallback(this, &Control::Impl::OnIdleCallback);
2104 Adaptor::Get().AddIdle(mIdleCallback, false);
2108 mIsEmittingResourceReadySignal = false;
2112 mNeedToEmitResourceReady = true;
2116 void Control::Impl::OnIdleCallback()
2118 if(mNeedToEmitResourceReady)
2121 mNeedToEmitResourceReady = false;
2123 // A visual is ready so control may need relayouting if staged
2124 if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
2126 mControlImpl.RelayoutRequest();
2129 EmitResourceReadySignal();
2132 // Set the pointer to null as the callback manager deletes the callback after execute it.
2133 mIdleCallback = nullptr;
2136 Dali::Accessibility::Accessible* Control::Impl::GetAccessibilityObject()
2138 if(!mAccessibilityObject)
2140 mAccessibilityObject = mAccessibilityConstructor(mControlImpl.Self());
2142 return mAccessibilityObject.get();
2145 Dali::Accessibility::Accessible* Control::Impl::GetAccessibilityObject(Dali::Actor actor)
2149 auto control = Dali::Toolkit::Control::DownCast(actor);
2152 auto controlImpl = static_cast<Internal::Control*>(&control.GetImplementation());
2153 return controlImpl->mImpl->GetAccessibilityObject();
2159 } // namespace Internal
2161 } // namespace Toolkit