X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fcontrols%2Fcontrol%2Fcontrol-data-impl.cpp;h=1202c26011ec87a8150c45c290bfe3e86228115d;hb=refs%2Fchanges%2F06%2F301106%2F9;hp=ced845ae5b5d2324cdb4e8eb220d89cecf56a88e;hpb=311e5010e011ee0b93a4a7ee48a7ae150cdc0dbd;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/controls/control/control-data-impl.cpp b/dali-toolkit/internal/controls/control/control-data-impl.cpp index ced845a..1202c26 100644 --- a/dali-toolkit/internal/controls/control/control-data-impl.cpp +++ b/dali-toolkit/internal/controls/control/control-data-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -50,12 +52,12 @@ namespace { -const std::string READING_INFO_TYPE_NAME = "name"; -const std::string READING_INFO_TYPE_ROLE = "role"; -const std::string READING_INFO_TYPE_DESCRIPTION = "description"; -const std::string READING_INFO_TYPE_STATE = "state"; -const std::string READING_INFO_TYPE_ATTRIBUTE_NAME = "reading_info_type"; -const std::string READING_INFO_TYPE_SEPARATOR = "|"; +const char* READING_INFO_TYPE_NAME = "name"; +const char* READING_INFO_TYPE_ROLE = "role"; +const char* READING_INFO_TYPE_DESCRIPTION = "description"; +const char* READING_INFO_TYPE_STATE = "state"; +const char* READING_INFO_TYPE_ATTRIBUTE_NAME = "reading_info_type"; +const char* READING_INFO_TYPE_SEPARATOR = "|"; } // namespace namespace Dali @@ -127,6 +129,38 @@ bool FindVisual(std::string visualName, const RegisteredVisualContainer& visuals return false; } +/** + * Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter + */ +bool FindVisual(const Toolkit::Visual::Base findVisual, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter) +{ + for(iter = visuals.Begin(); iter != visuals.End(); iter++) + { + Toolkit::Visual::Base visual = (*iter)->visual; + if(visual && visual == findVisual) + { + return true; + } + } + return false; +} + +/** + * Finds internal visual in given array, returning true if found along with the iterator for that visual as a out parameter + */ +bool FindVisual(const Visual::Base& findInternalVisual, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter) +{ + for(iter = visuals.Begin(); iter != visuals.End(); iter++) + { + Visual::Base& visual = Toolkit::GetImplementation((*iter)->visual); + if((&visual == &findInternalVisual)) + { + return true; + } + } + return false; +} + void FindChangableVisuals(Dictionary& stateVisualsToAdd, Dictionary& stateVisualsToChange, DictionaryKeys& stateVisualsToRemove) @@ -199,6 +233,23 @@ void MoveVisual(RegisteredVisualContainer::Iterator sourceIter, RegisteredVisual } /** + * Discard visual from source to visual factory. + */ +void DiscardVisual(RegisteredVisualContainer::Iterator sourceIter, RegisteredVisualContainer& source) +{ + Toolkit::Visual::Base visual = (*sourceIter)->visual; + if(visual) + { + if(Stage::IsInstalled()) + { + Toolkit::VisualFactory::Get().DiscardVisual(visual); + } + } + + source.Erase(sourceIter); +} + +/** * Performs actions as requested using the action name. * @param[in] object The object on which to perform the action. * @param[in] actionName The action to perform. @@ -410,11 +461,11 @@ void SetVisualsOffScene(const RegisteredVisualContainer& container, Actor parent } } -Dali::Rect<> GetShowingGeometry(Dali::Rect<> rect, Dali::Toolkit::DevelControl::AccessibleImpl* accessibleImpl) +Dali::Rect<> GetShowingGeometry(Dali::Rect<> rect, Dali::Toolkit::DevelControl::ControlAccessible* accessible) { Rect<> parentRect; Vector2 currentPosition; - auto parent = dynamic_cast(accessibleImpl->GetParent()); + auto parent = dynamic_cast(accessible->GetParent()); while(parent) { @@ -433,7 +484,7 @@ Dali::Rect<> GetShowingGeometry(Dali::Rect<> rect, Dali::Toolkit::DevelControl:: return rect; } - parent = dynamic_cast(parent->GetParent()); + parent = dynamic_cast(parent->GetParent()); } return rect; @@ -444,6 +495,19 @@ static bool IsShowingGeometryOnScreen(Dali::Rect<> rect) return rect.width > 0 && rect.height > 0; } +Dali::Accessibility::Accessible* ExternalAccessibleGetter(Dali::Actor actor) +{ + auto control = Toolkit::Control::DownCast(actor); + if(!control) + { + return nullptr; + } + + auto& controlImpl = Toolkit::Internal::GetImplementation(control); + + return controlImpl.GetAccessibleObject(); +} + } // unnamed namespace // clang-format off @@ -467,6 +531,12 @@ const PropertyRegistration Control::Impl::PROPERTY_18(typeRegistration, "accessi const PropertyRegistration Control::Impl::PROPERTY_19(typeRegistration, "accessibilityRole", Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty); const PropertyRegistration Control::Impl::PROPERTY_20(typeRegistration, "accessibilityHighlightable", Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty); const PropertyRegistration Control::Impl::PROPERTY_21(typeRegistration, "accessibilityAttributes", Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty); +const PropertyRegistration Control::Impl::PROPERTY_22(typeRegistration, "dispatchKeyEvents", Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty); +const PropertyRegistration Control::Impl::PROPERTY_23(typeRegistration, "accessibilityHidden", Toolkit::DevelControl::Property::ACCESSIBILITY_HIDDEN, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty); +const PropertyRegistration Control::Impl::PROPERTY_24(typeRegistration, "clockwiseFocusableActorId", Toolkit::DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty); +const PropertyRegistration Control::Impl::PROPERTY_25(typeRegistration, "counterClockwiseFocusableActorId", Toolkit::DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty); +const PropertyRegistration Control::Impl::PROPERTY_26(typeRegistration, "automationId", Toolkit::DevelControl::Property::AUTOMATION_ID, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty); + // clang-format on Control::Impl::Impl(Control& controlImpl) @@ -477,6 +547,8 @@ Control::Impl::Impl(Control& controlImpl) mRightFocusableActorId(-1), mUpFocusableActorId(-1), mDownFocusableActorId(-1), + mClockwiseFocusableActorId(-1), + mCounterClockwiseFocusableActorId(-1), mStyleName(""), mBackgroundColor(Color::TRANSPARENT), mStartingPinchScale(nullptr), @@ -501,23 +573,10 @@ Control::Impl::Impl(Control& controlImpl) mIsKeyboardNavigationSupported(false), mIsKeyboardFocusGroup(false), mIsEmittingResourceReadySignal(false), - mNeedToEmitResourceReady(false) + mIdleCallbackRegistered(false), + mDispatchKeyEvents(true) { - Dali::Accessibility::Accessible::RegisterControlAccessibilityGetter( - [](Dali::Actor actor) -> Dali::Accessibility::Accessible* { - return Control::Impl::GetAccessibilityObject(actor); - }); - - mAccessibilityConstructor = [](Dali::Actor actor) -> std::unique_ptr { - return std::unique_ptr(new DevelControl::AccessibleImpl(actor, Dali::Accessibility::Role::UNKNOWN)); - }; - - size_t length = static_cast(Dali::Accessibility::RelationType::MAX_COUNT); - mAccessibilityRelations.reserve(length); - for(auto i = 0u; i < length; ++i) - { - mAccessibilityRelations.push_back({}); - } + Dali::Accessibility::Accessible::RegisterExternalAccessibleGetter(&ExternalAccessibleGetter); } Control::Impl::~Impl() @@ -544,74 +603,75 @@ Control::Impl::~Impl() Control::Impl& Control::Impl::Get(Internal::Control& internalControl) { + DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?"); + return *internalControl.mImpl; } const Control::Impl& Control::Impl::Get(const Internal::Control& internalControl) { + DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?"); + return *internalControl.mImpl; } void Control::Impl::CheckHighlightedObjectGeometry() { - auto accessibleImpl = dynamic_cast(mAccessibilityObject.get()); - if(!accessibleImpl) + auto accessible = GetAccessibleObject(); + if(DALI_LIKELY(accessible)) { - DALI_LOG_ERROR("accessibleImpl is not a pointer to a DevelControl::AccessibleImpl type"); - return; - } - - auto lastPosition = accessibleImpl->GetLastPosition(); - auto accessibleRect = accessibleImpl->GetExtents(Dali::Accessibility::CoordinateType::WINDOW); - auto rect = GetShowingGeometry(accessibleRect, accessibleImpl); + auto lastPosition = accessible->GetLastPosition(); + auto accessibleRect = accessible->GetExtents(Dali::Accessibility::CoordinateType::WINDOW); + auto rect = GetShowingGeometry(accessibleRect, accessible); - switch(mAccessibilityLastScreenRelativeMoveType) - { - case Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE: - { - if(IsShowingGeometryOnScreen(rect)) - { - mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE; - } - break; - } - case Dali::Accessibility::ScreenRelativeMoveType::INSIDE: + switch(mAccessibilityLastScreenRelativeMoveType) { - if(rect.width < 0 && accessibleRect.x != lastPosition.x) - { - mAccessibilityLastScreenRelativeMoveType = (accessibleRect.x < lastPosition.x) ? Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT : Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT; - } - if(rect.height < 0 && accessibleRect.y != lastPosition.y) + case Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE: { - mAccessibilityLastScreenRelativeMoveType = (accessibleRect.y < lastPosition.y) ? Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT : Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT; + if(IsShowingGeometryOnScreen(rect)) + { + mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE; + } + break; } - // notify AT-clients on outgoing moves only - if(mAccessibilityLastScreenRelativeMoveType != Dali::Accessibility::ScreenRelativeMoveType::INSIDE) + case Dali::Accessibility::ScreenRelativeMoveType::INSIDE: { - mAccessibilityObject.get()->EmitMovedOutOfScreen(mAccessibilityLastScreenRelativeMoveType); + if(rect.width < 0 && !Dali::Equals(accessibleRect.x, lastPosition.x)) + { + mAccessibilityLastScreenRelativeMoveType = (accessibleRect.x < lastPosition.x) ? Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT : Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT; + } + if(rect.height < 0 && !Dali::Equals(accessibleRect.y, lastPosition.y)) + { + mAccessibilityLastScreenRelativeMoveType = (accessibleRect.y < lastPosition.y) ? Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT : Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT; + } + // notify AT-clients on outgoing moves only + if(mAccessibilityLastScreenRelativeMoveType != Dali::Accessibility::ScreenRelativeMoveType::INSIDE) + { + accessible->EmitMovedOutOfScreen(mAccessibilityLastScreenRelativeMoveType); + } + break; } - break; - } - case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT: - case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT: - { - if(IsShowingGeometryOnScreen(rect)) + case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT: + case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT: { - mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE; + if(IsShowingGeometryOnScreen(rect)) + { + mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE; + } + else + { + mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE; + } + break; } - else + default: { - mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE; + break; } - break; } - default: - { - break; - } - } - accessibleImpl->SetLastPosition(Vector2(accessibleRect.x, accessibleRect.y)); + accessible->SetLastPosition(Vector2(accessibleRect.x, accessibleRect.y)); + } } void Control::Impl::RegisterAccessibilityPositionPropertyNotification() @@ -624,9 +684,9 @@ void Control::Impl::RegisterAccessibilityPositionPropertyNotification() mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE; // recalculate mAccessibilityLastScreenRelativeMoveType accordingly to the initial position CheckHighlightedObjectGeometry(); - mAccessibilityPositionNotification = mControlImpl.Self().AddPropertyNotification(Actor::Property::WORLD_POSITION, StepCondition(1.0f, 1.0f)); + mAccessibilityPositionNotification = mControlImpl.Self().AddPropertyNotification(Actor::Property::WORLD_POSITION, StepCondition(1.0f, 1.0f)); mAccessibilityPositionNotification.SetNotifyMode(PropertyNotification::NOTIFY_ON_CHANGED); - mAccessibilityPositionNotification.NotifySignal().Connect(this, [this](PropertyNotification&){ CheckHighlightedObjectGeometry(); }); + mAccessibilityPositionNotification.NotifySignal().Connect(this, [this](PropertyNotification&) { CheckHighlightedObjectGeometry(); }); mIsAccessibilityPositionPropertyNotificationSet = true; } @@ -679,6 +739,8 @@ void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex) { + DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?"); + DALI_LOG_INFO(gLogFilter, Debug::Concise, "RegisterVisual:%d \n", index); bool visualReplaced(false); @@ -801,7 +863,7 @@ void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& { visualImpl.SetOnScene(self); } - else if(visualImpl.IsResourceReady()) // When not being staged, check if visual already 'ResourceReady' before it was Registered. ( Resource may have been loaded already ) + else if(enabled && visualImpl.IsResourceReady()) // When not being staged, check if visual already 'ResourceReady' before it was Registered. ( Resource may have been loaded already ) { ResourceReady(visualImpl); } @@ -812,6 +874,8 @@ void Control::Impl::RegisterVisual(Property::Index index, Toolkit::Visual::Base& void Control::Impl::UnregisterVisual(Property::Index index) { + DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?"); + RegisteredVisualContainer::Iterator iter; if(FindVisual(index, mVisuals, iter)) { @@ -829,8 +893,9 @@ void Control::Impl::UnregisterVisual(Property::Index index) Actor self(mControlImpl.Self()); Toolkit::GetImplementation((*iter)->visual).SetOffScene(self); (*iter)->pending = false; - (*iter)->visual.Reset(); - mRemoveVisuals.Erase(iter); + + // Discard removed visual. It will be destroyed at next Idle time. + DiscardVisual(iter, mRemoveVisuals); } } @@ -890,6 +955,23 @@ bool Control::Impl::IsVisualEnabled(Property::Index index) const return false; } +void Control::Impl::EnableReadyTransitionOverriden(Toolkit::Visual::Base& visual, bool enable) +{ + DALI_LOG_INFO(gLogFilter, Debug::General, "Control::EnableReadyTransitionOverriden(%p, %s)\n", visual, enable ? "T" : "F"); + + RegisteredVisualContainer::Iterator iter; + if(FindVisual(visual, mVisuals, iter)) + { + if((*iter)->overideReadyTransition == enable) + { + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Control::EnableReadyTransitionOverriden Visual %s(%p) already %s\n", (*iter)->visual.GetName().c_str(), visual, enable ? "enabled" : "disabled"); + return; + } + + (*iter)->overideReadyTransition = enable; + } +} + void Control::Impl::StopObservingVisual(Toolkit::Visual::Base& visual) { Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual); @@ -906,6 +988,17 @@ void Control::Impl::StartObservingVisual(Toolkit::Visual::Base& visual) visualImpl.AddEventObserver(*this); } +void Control::Impl::ResourceReady() +{ + DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?"); + + // Emit signal if all enabled visuals registered by the control are ready or there are no visuals. + if(IsResourceReady()) + { + EmitResourceReadySignal(); + } +} + // Called by a Visual when it's resource is ready void Control::Impl::ResourceReady(Visual::Base& object) { @@ -913,41 +1006,38 @@ void Control::Impl::ResourceReady(Visual::Base& object) Actor self = mControlImpl.Self(); + RegisteredVisualContainer::Iterator registeredIter; + // A resource is ready, find resource in the registered visuals container and get its index - for(auto registeredIter = mVisuals.Begin(), end = mVisuals.End(); registeredIter != end; ++registeredIter) + if(!FindVisual(object, mVisuals, registeredIter)) { - Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation((*registeredIter)->visual); + return; + } - if(&object == ®isteredVisualImpl) + RegisteredVisualContainer::Iterator visualToRemoveIter; + // Find visual with the same index in the removal container + // Set if off stage as it's replacement is now ready. + // Remove if from removal list as now removed from stage. + // Set Pending flag on the ready visual to false as now ready. + if(FindVisual((*registeredIter)->index, mRemoveVisuals, visualToRemoveIter)) + { + (*registeredIter)->pending = false; + if(!((*visualToRemoveIter)->overideReadyTransition)) { - RegisteredVisualContainer::Iterator visualToRemoveIter; - // Find visual with the same index in the removal container - // Set if off stage as it's replacement is now ready. - // Remove if from removal list as now removed from stage. - // Set Pending flag on the ready visual to false as now ready. - if(FindVisual((*registeredIter)->index, mRemoveVisuals, visualToRemoveIter)) - { - (*registeredIter)->pending = false; - Toolkit::GetImplementation((*visualToRemoveIter)->visual).SetOffScene(self); - mRemoveVisuals.Erase(visualToRemoveIter); - } - break; + Toolkit::GetImplementation((*visualToRemoveIter)->visual).SetOffScene(self); } + + // Discard removed visual. It will be destroyed at next Idle time. + DiscardVisual(visualToRemoveIter, mRemoveVisuals); } // A visual is ready so control may need relayouting if staged - if(self.GetProperty(Actor::Property::CONNECTED_TO_SCENE)) - { - mControlImpl.RelayoutRequest(); - } + RelayoutRequest(object); - // Emit signal if all enabled visuals registered by the control are ready. - if(IsResourceReady()) + // Called by a Visual when it's resource is ready + if(((*registeredIter)->enabled)) { - // Reset the flag - mNeedToEmitResourceReady = false; - - EmitResourceReadySignal(); + ResourceReady(); } } @@ -965,6 +1055,14 @@ void Control::Impl::NotifyVisualEvent(Visual::Base& object, Property::Index sign } } +void Control::Impl::RelayoutRequest(Visual::Base& object) +{ + if(mControlImpl.Self().GetProperty(Actor::Property::CONNECTED_TO_SCENE)) + { + mControlImpl.RelayoutRequest(); + } +} + bool Control::Impl::IsResourceReady() const { // Iterate through and check all the enabled visuals are ready @@ -1088,6 +1186,15 @@ void Control::Impl::DoAction(Dali::Property::Index visualIndex, Dali::Property:: } } +void Control::Impl::DoActionExtension(Dali::Property::Index visualIndex, Dali::Property::Index actionId, Dali::Any attributes) +{ + RegisteredVisualContainer::Iterator iter; + if(FindVisual(visualIndex, mVisuals, iter)) + { + Toolkit::GetImplementation((*iter)->visual).DoActionExtension(actionId, attributes); + } +} + void Control::Impl::AppendAccessibilityAttribute(const std::string& key, const std::string value) { Property::Value* checkedValue = mAccessibilityAttributes.Find(key); @@ -1103,6 +1210,8 @@ void Control::Impl::AppendAccessibilityAttribute(const std::string& key, const s void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value) { + DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?"); + Toolkit::Control control = Toolkit::Control::DownCast(BaseHandle(object)); if(control) @@ -1288,45 +1397,30 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const std::string name; if(value.Get(name)) { - controlImpl.mImpl->mAccessibilityName = name; - controlImpl.mImpl->mAccessibilityNameSet = true; - } - else - { - controlImpl.mImpl->mAccessibilityNameSet = false; + controlImpl.mImpl->mAccessibilityName = name; } + break; } - break; case Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION: { std::string text; if(value.Get(text)) { - controlImpl.mImpl->mAccessibilityDescription = text; - controlImpl.mImpl->mAccessibilityDescriptionSet = true; - } - else - { - controlImpl.mImpl->mAccessibilityDescriptionSet = false; + controlImpl.mImpl->mAccessibilityDescription = text; } + break; } - break; case Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN: { std::string text; if(value.Get(text)) { - controlImpl.mImpl->mAccessibilityTranslationDomain = text; - controlImpl.mImpl->mAccessibilityTranslationDomainSet = true; - } - else - { - controlImpl.mImpl->mAccessibilityTranslationDomainSet = false; + controlImpl.mImpl->mAccessibilityTranslationDomain = text; } + break; } - break; case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE: { @@ -1335,23 +1429,18 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const { controlImpl.mImpl->mAccessibilityRole = role; } + break; } - break; case Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE: { bool highlightable; if(value.Get(highlightable)) { - controlImpl.mImpl->mAccessibilityHighlightable = highlightable; - controlImpl.mImpl->mAccessibilityHighlightableSet = true; - } - else - { - controlImpl.mImpl->mAccessibilityHighlightableSet = false; + controlImpl.mImpl->mAccessibilityHighlightable = highlightable; } + break; } - break; case Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES: { @@ -1362,12 +1451,72 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const } break; } + + case Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS: + { + bool dispatch; + if(value.Get(dispatch)) + { + controlImpl.mImpl->mDispatchKeyEvents = dispatch; + } + break; + } + + case Toolkit::DevelControl::Property::ACCESSIBILITY_HIDDEN: + { + bool hidden; + if(value.Get(hidden)) + { + controlImpl.mImpl->mAccessibilityHidden = hidden; + + auto* accessible = controlImpl.GetAccessibleObject(); + if(DALI_LIKELY(accessible)) + { + auto* parent = dynamic_cast(accessible->GetParent()); + if(parent) + { + parent->OnChildrenChanged(); + } + } + } + break; + } + case Toolkit::DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID: + { + int focusId; + if(value.Get(focusId)) + { + controlImpl.mImpl->mClockwiseFocusableActorId = focusId; + } + break; + } + case Toolkit::DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID: + { + int focusId; + if(value.Get(focusId)) + { + controlImpl.mImpl->mCounterClockwiseFocusableActorId = focusId; + } + break; + } + + case Toolkit::DevelControl::Property::AUTOMATION_ID: + { + std::string automationId; + if(value.Get(automationId)) + { + controlImpl.mImpl->mAutomationId = automationId; + } + break; + } } } } Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index index) { + DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?"); + Property::Value value; Toolkit::Control control = Toolkit::Control::DownCast(BaseHandle(object)); @@ -1477,28 +1626,19 @@ Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index i case Toolkit::DevelControl::Property::ACCESSIBILITY_NAME: { - if(controlImpl.mImpl->mAccessibilityNameSet) - { - value = controlImpl.mImpl->mAccessibilityName; - } + value = controlImpl.mImpl->mAccessibilityName; break; } case Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION: { - if(controlImpl.mImpl->mAccessibilityDescriptionSet) - { - value = controlImpl.mImpl->mAccessibilityDescription; - } + value = controlImpl.mImpl->mAccessibilityDescription; break; } case Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN: { - if(controlImpl.mImpl->mAccessibilityTranslationDomainSet) - { - value = controlImpl.mImpl->mAccessibilityTranslationDomain; - } + value = controlImpl.mImpl->mAccessibilityTranslationDomain; break; } @@ -1510,10 +1650,7 @@ Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index i case Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE: { - if(controlImpl.mImpl->mAccessibilityHighlightableSet) - { - value = controlImpl.mImpl->mAccessibilityHighlightable; - } + value = controlImpl.mImpl->mAccessibilityHighlightable; break; } @@ -1522,6 +1659,36 @@ Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index i value = controlImpl.mImpl->mAccessibilityAttributes; break; } + + case Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS: + { + value = controlImpl.mImpl->mDispatchKeyEvents; + break; + } + + case Toolkit::DevelControl::Property::ACCESSIBILITY_HIDDEN: + { + value = controlImpl.mImpl->mAccessibilityHidden; + break; + } + + case Toolkit::DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID: + { + value = controlImpl.mImpl->mClockwiseFocusableActorId; + break; + } + + case Toolkit::DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID: + { + value = controlImpl.mImpl->mCounterClockwiseFocusableActorId; + break; + } + + case Toolkit::DevelControl::Property::AUTOMATION_ID: + { + value = controlImpl.mImpl->mAutomationId; + break; + } } } @@ -1721,6 +1888,8 @@ void Control::Impl::RecreateChangedVisuals(Dictionary& stateVisua void Control::Impl::ReplaceStateVisualsAndProperties(const StylePtr oldState, const StylePtr newState, const std::string& subState) { + DALI_ASSERT_ALWAYS(Stage::IsCoreThread() && "Core is not installed. Might call this API from worker thread?"); + // Collect all old visual names DictionaryKeys stateVisualsToRemove; if(oldState) @@ -1858,17 +2027,25 @@ void Control::Impl::OnSceneDisconnection() // Visuals pending replacement can now be taken out of the removal list and set off scene // Iterate through all replacement visuals and add to a move queue then set off scene - for(auto removalIter = mRemoveVisuals.Begin(), end = mRemoveVisuals.End(); removalIter != end; removalIter++) + + if(!mRemoveVisuals.Empty()) { - Toolkit::GetImplementation((*removalIter)->visual).SetOffScene(self); + std::reverse(mRemoveVisuals.Begin(), mRemoveVisuals.End()); + + while(!mRemoveVisuals.Empty()) + { + auto removalIter = mRemoveVisuals.End() - 1u; + Toolkit::GetImplementation((*removalIter)->visual).SetOffScene(self); + + // Discard removed visual. It will be destroyed at next Idle time. + DiscardVisual(removalIter, mRemoveVisuals); + } } for(auto replacedIter = mVisuals.Begin(), end = mVisuals.End(); replacedIter != end; replacedIter++) { (*replacedIter)->pending = false; } - - mRemoveVisuals.Clear(); } void Control::Impl::SetMargin(Extents margin) @@ -1945,122 +2122,54 @@ Dali::Property Control::Impl::GetVisualProperty(Dali::Property::Index index, Dal if(visual) { Internal::Visual::Base& visualImpl = Toolkit::GetImplementation(visual); - return visualImpl.GetPropertyObject(visualPropertyKey); + return visualImpl.GetPropertyObject(std::move(visualPropertyKey)); } Handle handle; return Dali::Property(handle, Property::INVALID_INDEX); } -void Control::Impl::MakeVisualTransition(Dali::Animation& animation, Dali::Toolkit::Control source, Dali::Property::Index visualIndex, AlphaFunction alphaFunction, TimePeriod timePeriod) +void Control::Impl::CreateTransitions(std::vector>& sourceProperties, + std::vector>& destinationProperties, + Dali::Toolkit::Control source, + Dali::Toolkit::Control destination) { - Dali::Toolkit::Control sourceHandle = Dali::Toolkit::Control::DownCast(source); - Property::Map sourceMap = sourceHandle.GetProperty(visualIndex); - Dali::Toolkit::Control destinationHandle = Dali::Toolkit::Control::DownCast(mControlImpl.Self()); - Property::Map destinationMap = destinationHandle.GetProperty(visualIndex); - - Vector4 mixColor(1.0f, 1.0f, 1.0f, 1.0f); - Vector4 cornerRadius(0.0f, 0.0f, 0.0f, 0.0f); - float borderlineWidth(0.0f); - Vector4 borderlineColor(0.0f, 0.0f, 0.0f, 1.0f); - float borderlineOffset(0.0f); - - if(!destinationMap.Empty()) + // Retrieves background properties to be transitioned. + Dali::Property::Map backgroundSourcePropertyMap, backgroundDestinationPropertyMap; + mControlImpl.MakeVisualTransition(backgroundSourcePropertyMap, backgroundDestinationPropertyMap, source, destination, Toolkit::Control::Property::BACKGROUND); + if(backgroundSourcePropertyMap.Count() > 0) { - static auto findValueVector4 = [](const Property::Map& map, Property::Index index, const Vector4& defaultValue = Vector4()) -> Vector4 { - Property::Value* propertyValue = map.Find(index); - if(propertyValue) - { - return propertyValue->Get(); - } - return defaultValue; - }; - - static auto findValueFloat = [](const Property::Map& map, Property::Index index, const float& defaultValue = 0.0f) -> float { - Property::Value* propertyValue = map.Find(index); - if(propertyValue) - { - return propertyValue->Get(); - } - return defaultValue; - }; - - mixColor = findValueVector4(destinationMap, Dali::Toolkit::Visual::Property::MIX_COLOR, mixColor); - cornerRadius = findValueVector4(destinationMap, Toolkit::DevelVisual::Property::CORNER_RADIUS, cornerRadius); - borderlineWidth = findValueFloat(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth); - borderlineColor = findValueVector4(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_COLOR, borderlineColor); - borderlineOffset = findValueFloat(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset); - - if(sourceMap.Empty()) - { - sourceMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR); - sourceMap.Insert(Dali::Toolkit::Visual::Property::MIX_COLOR, Color::TRANSPARENT); - sourceMap.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, cornerRadius); - sourceMap.Insert(Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth); - sourceMap.Insert(Toolkit::DevelVisual::Property::BORDERLINE_COLOR, borderlineColor); - sourceMap.Insert(Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset); - } - - Vector4 sourceMixColor = findValueVector4(sourceMap, Dali::Toolkit::Visual::Property::MIX_COLOR, mixColor); - Vector4 sourceCornerRadius = findValueVector4(sourceMap, Toolkit::DevelVisual::Property::CORNER_RADIUS, cornerRadius); - float sourceBorderlineWidth = findValueFloat(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth); - Vector4 sourceBorderlineColor = findValueVector4(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_COLOR, borderlineColor); - float sourceBorderlineOffset = findValueFloat(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset); - - std::vector properties; - std::vector> values; - - if(Vector3(sourceMixColor) != Vector3(mixColor)) - { - properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::Visual::Property::MIX_COLOR)); - values.push_back(std::make_pair(Vector3(sourceMixColor), Vector3(mixColor))); - } - - if(std::abs(sourceMixColor.a - mixColor.a) > Math::MACHINE_EPSILON_1) - { - properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::Visual::Property::OPACITY)); - values.push_back(std::make_pair(sourceMixColor.a, mixColor.a)); - } - - if(sourceCornerRadius != cornerRadius) - { - properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::CORNER_RADIUS)); - values.push_back(std::make_pair(sourceCornerRadius, cornerRadius)); - } + sourceProperties.push_back(std::pair(Toolkit::Control::Property::BACKGROUND, backgroundSourcePropertyMap)); + destinationProperties.push_back(std::pair(Toolkit::Control::Property::BACKGROUND, backgroundDestinationPropertyMap)); + } - if(sourceBorderlineWidth != borderlineWidth) - { - properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::BORDERLINE_WIDTH)); - values.push_back(std::make_pair(sourceBorderlineWidth, borderlineWidth)); - } + // Retrieves shadow properties to be transitioned. + Dali::Property::Map shadowSourcePropertyMap, shadowDestinationPropertyMap; + mControlImpl.MakeVisualTransition(shadowSourcePropertyMap, shadowDestinationPropertyMap, source, destination, Toolkit::DevelControl::Property::SHADOW); + if(shadowSourcePropertyMap.Count() > 0) + { + sourceProperties.push_back(std::pair(Toolkit::DevelControl::Property::SHADOW, shadowSourcePropertyMap)); + destinationProperties.push_back(std::pair(Toolkit::DevelControl::Property::SHADOW, shadowDestinationPropertyMap)); + } - if(sourceBorderlineColor != borderlineColor) - { - properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::BORDERLINE_COLOR)); - values.push_back(std::make_pair(sourceBorderlineColor, borderlineColor)); - } + // Retrieves transition from inherited class. + mControlImpl.OnCreateTransitions(sourceProperties, destinationProperties, source, destination); +} - if(sourceBorderlineOffset != borderlineOffset) +void Control::Impl::UpdateVisualProperties(const std::vector>& properties) +{ + for(auto&& data : properties) + { + if(data.first == Toolkit::Control::Property::BACKGROUND) { - properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::BORDERLINE_OFFSET)); - values.push_back(std::make_pair(sourceBorderlineOffset, borderlineOffset)); + DoAction(Toolkit::Control::Property::BACKGROUND, DevelVisual::Action::UPDATE_PROPERTY, data.second); } - - for(uint32_t i = 0; i < properties.size(); ++i) + else if(data.first == Toolkit::DevelControl::Property::SHADOW) { - if(timePeriod.delaySeconds > 0.0f) - { - Dali::KeyFrames initialKeyframes = Dali::KeyFrames::New(); - initialKeyframes.Add(0.0f, values[i].first); - initialKeyframes.Add(1.0f, values[i].first); - animation.AnimateBetween(properties[i], initialKeyframes, TimePeriod(timePeriod.delaySeconds)); - } - Dali::KeyFrames keyframes = Dali::KeyFrames::New(); - keyframes.Add(0.0f, values[i].first); - keyframes.Add(1.0f, values[i].second); - animation.AnimateBetween(properties[i], keyframes, alphaFunction, timePeriod); + DoAction(Toolkit::DevelControl::Property::SHADOW, DevelVisual::Action::UPDATE_PROPERTY, data.second); } } + mControlImpl.OnUpdateVisualProperties(properties); } void Control::Impl::EmitResourceReadySignal() @@ -2071,71 +2180,76 @@ void Control::Impl::EmitResourceReadySignal() mIsEmittingResourceReadySignal = true; // If the signal handler changes visual, it may become ready during this call & therefore this method will - // get called again recursively. If so, mNeedToEmitResourceReady is set below, and we act on it after that secondary + // get called again recursively. If so, mIdleCallbackRegistered is set below, and we act on it after that secondary // invocation has completed by notifying in an Idle callback to prevent further recursion. Dali::Toolkit::Control handle(mControlImpl.GetOwner()); mResourceReadySignal.Emit(handle); - if(mNeedToEmitResourceReady) + mIsEmittingResourceReadySignal = false; + } + else + { + if(!mIdleCallbackRegistered) { + mIdleCallbackRegistered = true; + // Add idler to emit the signal again if(!mIdleCallback) { // The callback manager takes the ownership of the callback object. mIdleCallback = MakeCallback(this, &Control::Impl::OnIdleCallback); - Adaptor::Get().AddIdle(mIdleCallback, false); + Adaptor::Get().AddIdle(mIdleCallback, true); } } - - mIsEmittingResourceReadySignal = false; - } - else - { - mNeedToEmitResourceReady = true; } } -void Control::Impl::OnIdleCallback() +bool Control::Impl::OnIdleCallback() { - if(mNeedToEmitResourceReady) + // Reset the flag + mIdleCallbackRegistered = false; + + // A visual is ready so control may need relayouting if staged + if(mControlImpl.Self().GetProperty(Actor::Property::CONNECTED_TO_SCENE)) { - // Reset the flag - mNeedToEmitResourceReady = false; + mControlImpl.RelayoutRequest(); + } - // A visual is ready so control may need relayouting if staged - if(mControlImpl.Self().GetProperty(Actor::Property::CONNECTED_TO_SCENE)) - { - mControlImpl.RelayoutRequest(); - } + EmitResourceReadySignal(); - EmitResourceReadySignal(); + if(!mIdleCallbackRegistered) + { + // Set the pointer to null as the callback manager deletes the callback after execute it. + mIdleCallback = nullptr; } - // Set the pointer to null as the callback manager deletes the callback after execute it. - mIdleCallback = nullptr; + // Repeat idle if mIdleCallbackRegistered become true one more time. + return mIdleCallbackRegistered; } -Dali::Accessibility::Accessible* Control::Impl::GetAccessibilityObject() +Toolkit::DevelControl::ControlAccessible* Control::Impl::GetAccessibleObject() { - if(!mAccessibilityObject) + if(mAccessibleCreatable && !mAccessibleObject) { - mAccessibilityObject = mAccessibilityConstructor(mControlImpl.Self()); + mAccessibleObject.reset(mControlImpl.CreateAccessibleObject()); } - return mAccessibilityObject.get(); + + return mAccessibleObject.get(); } -Dali::Accessibility::Accessible* Control::Impl::GetAccessibilityObject(Dali::Actor actor) +bool Control::Impl::IsAccessibleCreated() const { - if(actor) - { - auto control = Dali::Toolkit::Control::DownCast(actor); - if(control) - { - auto controlImpl = static_cast(&control.GetImplementation()); - return controlImpl->mImpl->GetAccessibilityObject(); - } - } - return nullptr; + return !!mAccessibleObject; +} + +void Control::Impl::EnableCreateAccessible(bool enable) +{ + mAccessibleCreatable = enable; +} + +bool Control::Impl::IsCreateAccessibleEnabled() const +{ + return mAccessibleCreatable; } } // namespace Internal