From: David Steele Date: Mon, 15 Nov 2021 13:37:20 +0000 (+0000) Subject: Refactored actor size negotiation X-Git-Tag: dali_2.0.53~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F83%2F266583%2F3;p=platform%2Fcore%2Fuifw%2Fdali-core.git Refactored actor size negotiation Moved all size negotiation implementation to a new ActorSizer class. This handles size negotiation and target / animated size. Moved static methods from ActorRelayouter into ActorSizer. Change-Id: I5137bb333d0254c80ede361ee7d36899830de21f Signed-off-by: David Steele --- diff --git a/automated-tests/src/dali-internal/utc-Dali-Internal-ActorRelayout.cpp b/automated-tests/src/dali-internal/utc-Dali-Internal-ActorRelayout.cpp index 11babca..2e77750 100644 --- a/automated-tests/src/dali-internal/utc-Dali-Internal-ActorRelayout.cpp +++ b/automated-tests/src/dali-internal/utc-Dali-Internal-ActorRelayout.cpp @@ -39,7 +39,7 @@ void utc_dali_internal_actor_relayouter_cleanup() test_return_value = TET_PASS; } -int UtcDaliActorRelayouter_CalculateSize(void) +int UtcDaliActorSizer_CalculateSize(void) { TestApplication application; @@ -48,62 +48,78 @@ int UtcDaliActorRelayouter_CalculateSize(void) auto& testActorImpl = Test::Impl::GetImpl(actor); auto& actorImpl = GetImplementation(actor); - scene.Add(actor); - actorImpl.SetSize(Vector2(100.0f, 100.0f)); - actorImpl.SetPreferredSize(Vector2(200.0f, 350.0f)); - - Vector2 maxSize(400.0f, 500.0f); + DALI_TEST_EQUALS(testActorImpl.IsRelayoutEnabled(), false, TEST_LOCATION); + DALI_TEST_CHECK(true); - DALI_TEST_EQUALS(actorImpl.CalculateSize(Dimension::WIDTH, maxSize), 200.0f, 0.00001f, TEST_LOCATION); - DALI_TEST_EQUALS(actorImpl.CalculateSize(Dimension::HEIGHT, maxSize), 350.0f, 0.00001f, TEST_LOCATION); + actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS); + actor[Dali::Actor::Property::SIZE] = Vector2(150.0f, 100.0f); // Should automatically set preferred size + scene.Add(actor); - actor.SetResizePolicy(ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT); - DALI_TEST_EQUALS(actorImpl.CalculateSize(Dimension::WIDTH, maxSize), 200.0f, 0.00001f, TEST_LOCATION); - DALI_TEST_EQUALS(actorImpl.CalculateSize(Dimension::HEIGHT, maxSize), maxSize.y, 0.00001f, TEST_LOCATION); + DALI_TEST_EQUALS(actorImpl.IsRelayoutEnabled(), true, TEST_LOCATION); testActorImpl.SetNaturalSize(Vector3(150.0f, 180.0f, 150.0f)); actor.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS); - - DALI_TEST_EQUALS(actorImpl.CalculateSize(Dimension::WIDTH, maxSize), 150.0f, 0.00001f, TEST_LOCATION); - DALI_TEST_EQUALS(actorImpl.CalculateSize(Dimension::HEIGHT, maxSize), 180.0f, 0.00001f, TEST_LOCATION); - - actor.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS); - auto child = Test::TestCustomActor::New(); - child.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS); - child.SetProperty(Dali::Actor::Property::SIZE, Vector2(20.0f, 40.0f)); - auto& childImpl = GetImplementation(child); - actor.Add(child); - application.SendNotification(); application.Render(); - DALI_TEST_EQUALS(actorImpl.CalculateSize(Dimension::WIDTH, maxSize), 20.0f, 0.00001f, TEST_LOCATION); - DALI_TEST_EQUALS(actorImpl.CalculateSize(Dimension::HEIGHT, maxSize), 40.0f, 0.00001f, TEST_LOCATION); + Vector3 size = actor[Dali::Actor::Property::SIZE]; + DALI_TEST_EQUALS(size.width, 150.0f, 0.00001f, TEST_LOCATION); + DALI_TEST_EQUALS(size.height, 180.0f, 0.00001f, TEST_LOCATION); testActorImpl.SetWidthForHeightFactor(3.5f); testActorImpl.SetHeightForWidthFactor(1.7f); actor.SetResizePolicy(ResizePolicy::DIMENSION_DEPENDENCY, Dimension::WIDTH); - DALI_TEST_EQUALS(actorImpl.CalculateSize(Dimension::WIDTH, maxSize), 140.0f, 0.00001f, TEST_LOCATION); + application.SendNotification(); + application.Render(); + + size = Vector3(actor[Dali::Actor::Property::SIZE]); + DALI_TEST_EQUALS(size.width, 3.5f * 180.0f, 0.00001f, TEST_LOCATION); actor.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::WIDTH); actor.SetResizePolicy(ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT); application.SendNotification(); application.Render(); - DALI_TEST_EQUALS(actorImpl.CalculateSize(Dimension::HEIGHT, maxSize), 255.0f, 0.00001f, TEST_LOCATION); + size = Vector3(actor[Dali::Actor::Property::SIZE]); + DALI_TEST_EQUALS(size.height, 1.7f * 150.0f, 0.00001f, TEST_LOCATION); + + auto child = Test::TestCustomActor::New(); + child.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS); + child.SetProperty(Dali::Actor::Property::SIZE, Vector2(20.0f, 40.0f)); + auto& childImpl = GetImplementation(child); + actor.Add(child); + actor.TestRelayoutRequest(); + + tet_infoline("Test actor takes child size"); + actor.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS); + application.SendNotification(); + application.Render(); + Vector3 parentSize = actor[Dali::Actor::Property::SIZE]; + DALI_TEST_EQUALS(parentSize.width, 20.0f, 0.00001f, TEST_LOCATION); + DALI_TEST_EQUALS(parentSize.height, 40.0f, 0.00001f, TEST_LOCATION); + tet_infoline("Test child actor is the right factor of the parent"); + actor[Dali::Actor::Property::SIZE] = Vector2(150.0f, 100.0f); // Should automatically set preferred size child.SetResizePolicy(ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS); child[Dali::Actor::Property::SIZE_MODE_FACTOR] = Vector3(0.5f, 1.0f, 1.0f); + + childImpl.RelayoutRequest(); application.SendNotification(); application.Render(); - DALI_TEST_EQUALS(childImpl.CalculateSize(Dimension::WIDTH, maxSize), 75.0f, 0.00001f, TEST_LOCATION); - DALI_TEST_EQUALS(childImpl.CalculateSize(Dimension::HEIGHT, maxSize), 255.0f, 0.00001f, TEST_LOCATION); + Vector3 childSize = child[Dali::Actor::Property::SIZE]; + DALI_TEST_EQUALS(childSize.width, 75.0f, 0.00001f, TEST_LOCATION); + DALI_TEST_EQUALS(childSize.height, 100.0f, 0.00001f, TEST_LOCATION); + + tet_infoline("Test child actor is the right delta of the parent"); child.SetResizePolicy(ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS); child[Dali::Actor::Property::SIZE_MODE_FACTOR] = Vector3(-40.0f, -20.0f, 1.0f); + child.TestRelayoutRequest(); application.SendNotification(); application.Render(); - DALI_TEST_EQUALS(childImpl.CalculateSize(Dimension::WIDTH, maxSize), 110.0f, 0.00001f, TEST_LOCATION); - DALI_TEST_EQUALS(childImpl.CalculateSize(Dimension::HEIGHT, maxSize), 235.0f, 0.00001f, TEST_LOCATION); + + Vector3 size2 = child[Dali::Actor::Property::SIZE]; + DALI_TEST_EQUALS(size2.width, 110.0f, 0.00001f, TEST_LOCATION); + DALI_TEST_EQUALS(size2.height, 80.0f, 0.00001f, TEST_LOCATION); END_TEST; } diff --git a/automated-tests/src/dali/dali-test-suite-utils/test-custom-actor.cpp b/automated-tests/src/dali/dali-test-suite-utils/test-custom-actor.cpp index 6c7b1d6..8fff834 100644 --- a/automated-tests/src/dali/dali-test-suite-utils/test-custom-actor.cpp +++ b/automated-tests/src/dali/dali-test-suite-utils/test-custom-actor.cpp @@ -397,7 +397,7 @@ void TestCustomActor::OnLayoutNegotiated(float size, Dimension::Type dimension) bool TestCustomActor::RelayoutDependentOnChildren(Dimension::Type dimension) { - return false; + return CustomActorImpl::RelayoutDependentOnChildrenBase(dimension); } void TestCustomActor::SetTransparent(bool transparent) diff --git a/dali/internal/event/actors/actor-impl.cpp b/dali/internal/event/actors/actor-impl.cpp index b201786..174f5e3 100644 --- a/dali/internal/event/actors/actor-impl.cpp +++ b/dali/internal/event/actors/actor-impl.cpp @@ -20,7 +20,6 @@ // EXTERNAL INCLUDES #include -#include #include // INTERNAL INCLUDES @@ -39,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -51,9 +49,9 @@ #include #include #include -#include #include #include +#include using Dali::Internal::SceneGraph::AnimatableProperty; using Dali::Internal::SceneGraph::Node; @@ -766,14 +764,12 @@ void Actor::SetInheritOrientation(bool inherit) void Actor::SetSizeModeFactor(const Vector3& factor) { - EnsureRelayouter(); - - mRelayoutData->sizeModeFactor = factor; + mSizer.SetSizeModeFactor(factor); } const Vector3& Actor::GetSizeModeFactor() const { - return mRelayoutData ? mRelayoutData->sizeModeFactor : Relayouter::DEFAULT_SIZE_MODE_FACTOR; + return mSizer.GetSizeModeFactor(); } void Actor::SetColorMode(ColorMode colorMode) @@ -799,154 +795,31 @@ void Actor::SetSize(const Vector2& size) SetSize(Vector3(size.width, size.height, 0.f)); } -void Actor::SetSizeInternal(const Vector2& size) -{ - SetSizeInternal(Vector3(size.width, size.height, 0.f)); -} - void Actor::SetSize(const Vector3& size) { - if(IsRelayoutEnabled() && !mRelayoutData->insideRelayout) - { - // TODO we cannot just ignore the given Z but that means rewrite the size negotiation!! - SetPreferredSize(size.GetVectorXY()); - } - else - { - SetSizeInternal(size); - } -} - -void Actor::SetSizeInternal(const Vector3& size) -{ - // dont allow recursive loop - DALI_ASSERT_ALWAYS(!mInsideOnSizeSet && "Cannot call SetSize from OnSizeSet"); - // check that we have a node AND the new size width, height or depth is at least a little bit different from the old one - Vector3 currentSize = GetCurrentSize(); - - if((fabsf(mTargetSize.width - size.width) > Math::MACHINE_EPSILON_1) || - (fabsf(mTargetSize.height - size.height) > Math::MACHINE_EPSILON_1) || - (fabsf(mTargetSize.depth - size.depth) > Math::MACHINE_EPSILON_1) || - (fabsf(mTargetSize.width - currentSize.width) > Math::MACHINE_EPSILON_1) || - (fabsf(mTargetSize.height - currentSize.height) > Math::MACHINE_EPSILON_1) || - (fabsf(mTargetSize.depth - currentSize.depth) > Math::MACHINE_EPSILON_1)) - { - mTargetSize = size; - - // Update the preferred size after relayoutting - // It should be used in the next relayoutting - if(mUseAnimatedSize & AnimatedSizeFlag::WIDTH && mRelayoutData) - { - mRelayoutData->preferredSize.width = mAnimatedSize.width; - } - - if(mUseAnimatedSize & AnimatedSizeFlag::HEIGHT && mRelayoutData) - { - mRelayoutData->preferredSize.height = mAnimatedSize.height; - } - - // node is being used in a separate thread; queue a message to set the value & base value - SceneGraph::NodeTransformPropertyMessage::Send(GetEventThreadServices(), &GetNode(), &GetNode().mSize, &SceneGraph::TransformManagerPropertyHandler::Bake, mTargetSize); - - // Notification for derived classes - mInsideOnSizeSet = true; - OnSizeSet(mTargetSize); - mInsideOnSizeSet = false; - - // Raise a relayout request if the flag is not locked - if(mRelayoutData && !mRelayoutData->insideRelayout) - { - RelayoutRequest(); - } - } + mSizer.SetSize(size); } void Actor::SetWidth(float width) { - if(IsRelayoutEnabled() && !mRelayoutData->insideRelayout) - { - SetResizePolicy(ResizePolicy::FIXED, Dimension::WIDTH); - mRelayoutData->preferredSize.width = width; - } - else - { - mTargetSize.width = width; - - // node is being used in a separate thread; queue a message to set the value & base value - SceneGraph::NodeTransformComponentMessage::Send(GetEventThreadServices(), &GetNode(), &GetNode().mSize, &SceneGraph::TransformManagerPropertyHandler::BakeX, width); - } - - mUseAnimatedSize &= ~AnimatedSizeFlag::WIDTH; - - RelayoutRequest(); + mSizer.SetWidth(width); } void Actor::SetHeight(float height) { - if(IsRelayoutEnabled() && !mRelayoutData->insideRelayout) - { - SetResizePolicy(ResizePolicy::FIXED, Dimension::HEIGHT); - mRelayoutData->preferredSize.height = height; - } - else - { - mTargetSize.height = height; - - // node is being used in a separate thread; queue a message to set the value & base value - SceneGraph::NodeTransformComponentMessage::Send(GetEventThreadServices(), &GetNode(), &GetNode().mSize, &SceneGraph::TransformManagerPropertyHandler::BakeY, height); - } - - mUseAnimatedSize &= ~AnimatedSizeFlag::HEIGHT; - - RelayoutRequest(); + mSizer.SetHeight(height); } void Actor::SetDepth(float depth) { - mTargetSize.depth = depth; - - mUseAnimatedSize &= ~AnimatedSizeFlag::DEPTH; - + mSizer.SetDepth(depth); // node is being used in a separate thread; queue a message to set the value & base value SceneGraph::NodeTransformComponentMessage::Send(GetEventThreadServices(), &GetNode(), &GetNode().mSize, &SceneGraph::TransformManagerPropertyHandler::BakeZ, depth); } Vector3 Actor::GetTargetSize() const { - Vector3 size = mTargetSize; - - if(mUseAnimatedSize & AnimatedSizeFlag::WIDTH) - { - // Should return animated size if size is animated - size.width = mAnimatedSize.width; - } - else - { - // Should return preferred size if size is fixed as set by SetSize - if(GetResizePolicy(Dimension::WIDTH) == ResizePolicy::FIXED) - { - size.width = GetPreferredSize().width; - } - } - - if(mUseAnimatedSize & AnimatedSizeFlag::HEIGHT) - { - size.height = mAnimatedSize.height; - } - else - { - if(GetResizePolicy(Dimension::HEIGHT) == ResizePolicy::FIXED) - { - size.height = GetPreferredSize().height; - } - } - - if(mUseAnimatedSize & AnimatedSizeFlag::DEPTH) - { - size.depth = mAnimatedSize.depth; - } - - return size; + return mSizer.GetTargetSize(); } const Vector3& Actor::GetCurrentSize() const @@ -963,83 +836,42 @@ Vector3 Actor::GetNaturalSize() const void Actor::SetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension) { - EnsureRelayouter().SetResizePolicy(policy, dimension, mTargetSize); - - OnSetResizePolicy(policy, dimension); - - // Trigger relayout on this control - RelayoutRequest(); + mSizer.SetResizePolicy(policy, dimension); } ResizePolicy::Type Actor::GetResizePolicy(Dimension::Type dimension) const { - return mRelayoutData ? mRelayoutData->GetResizePolicy(dimension) : ResizePolicy::DEFAULT; -} - -void Actor::SetSizeScalePolicy(SizeScalePolicy::Type policy) -{ - EnsureRelayouter(); - - mRelayoutData->sizeSetPolicy = policy; - - // Trigger relayout on this control - RelayoutRequest(); -} - -SizeScalePolicy::Type Actor::GetSizeScalePolicy() const -{ - return mRelayoutData ? mRelayoutData->sizeSetPolicy : Relayouter::DEFAULT_SIZE_SCALE_POLICY; -} - -void Actor::SetDimensionDependency(Dimension::Type dimension, Dimension::Type dependency) -{ - EnsureRelayouter().SetDimensionDependency(dimension, dependency); -} - -Dimension::Type Actor::GetDimensionDependency(Dimension::Type dimension) const -{ - return mRelayoutData ? mRelayoutData->GetDimensionDependency(dimension) : Dimension::ALL_DIMENSIONS; + return mSizer.GetResizePolicy(dimension); } void Actor::SetRelayoutEnabled(bool relayoutEnabled) { - // If relayout data has not been allocated yet and the client is requesting - // to disable it, do nothing - if(mRelayoutData || relayoutEnabled) - { - EnsureRelayouter(); - - DALI_ASSERT_DEBUG(mRelayoutData && "mRelayoutData not created"); - - mRelayoutData->relayoutEnabled = relayoutEnabled; - } + mSizer.SetRelayoutEnabled(relayoutEnabled); } bool Actor::IsRelayoutEnabled() const { - // Assume that if relayout data has not been allocated yet then - // relayout is disabled - return mRelayoutData && mRelayoutData->relayoutEnabled; + return mSizer.IsRelayoutEnabled(); } void Actor::SetLayoutDirty(bool dirty, Dimension::Type dimension) { - EnsureRelayouter().SetLayoutDirty(dirty, dimension); + mSizer.SetLayoutDirty(dirty, dimension); } bool Actor::IsLayoutDirty(Dimension::Type dimension) const { - return mRelayoutData && mRelayoutData->IsLayoutDirty(dimension); + return mSizer.IsLayoutDirty(dimension); } bool Actor::RelayoutPossible(Dimension::Type dimension) const { - return mRelayoutData && mRelayoutData->relayoutEnabled && !IsLayoutDirty(dimension); + return mSizer.RelayoutPossible(dimension); } bool Actor::RelayoutRequired(Dimension::Type dimension) const { - return mRelayoutData && mRelayoutData->relayoutEnabled && IsLayoutDirty(dimension); + return mSizer.RelayoutRequired(dimension); } uint32_t Actor::AddRenderer(Renderer& renderer) @@ -1200,12 +1032,12 @@ DevelActor::ChildOrderChangedSignalType& Actor::ChildOrderChangedSignal() Actor::Actor(DerivedType derivedType, const SceneGraph::Node& node) : Object(&node), mParentImpl(*this), + mSizer(*this), mParent(nullptr), mScene(nullptr), mRenderers(nullptr), mParentOrigin(nullptr), mAnchorPoint(nullptr), - mRelayoutData(nullptr), mGestureData(nullptr), mInterceptTouchedSignal(), mTouchedSignal(), @@ -1218,15 +1050,12 @@ Actor::Actor(DerivedType derivedType, const SceneGraph::Node& node) mLayoutDirectionChangedSignal(), mTargetOrientation(Quaternion::IDENTITY), mTargetColor(Color::WHITE), - mTargetSize(Vector3::ZERO), mTargetPosition(Vector3::ZERO), mTargetScale(Vector3::ONE), - mAnimatedSize(Vector3::ZERO), mTouchAreaOffset(0, 0, 0, 0), mName(), mSortedDepth(0u), mDepth(0u), - mUseAnimatedSize(AnimatedSizeFlag::CLEAR), mIsRoot(ROOT_LAYER == derivedType), mIsLayer(LAYER == derivedType || ROOT_LAYER == derivedType), mIsOnScene(false), @@ -1236,7 +1065,6 @@ Actor::Actor(DerivedType derivedType, const SceneGraph::Node& node) mKeyboardFocusableChildren(true), mTouchFocusable(false), mOnSceneSignalled(false), - mInsideOnSizeSet(false), mInheritPosition(true), mInheritOrientation(true), mInheritScale(true), @@ -1286,9 +1114,6 @@ Actor::~Actor() // Cleanup optional parent origin and anchor delete mParentOrigin; delete mAnchorPoint; - - // Delete optional relayout data - delete mRelayoutData; } void Actor::Add(Actor& child, bool notify) @@ -1677,238 +1502,115 @@ bool Actor::GetCurrentPropertyValue(Property::Index index, Property::Value& valu return PropertyHandler::GetCurrentPropertyValue(*this, index, value); } -Actor::Relayouter& Actor::EnsureRelayouter() -{ - // Assign relayouter - if(!mRelayoutData) - { - mRelayoutData = new Relayouter(); - } - - return *mRelayoutData; -} - bool Actor::RelayoutDependentOnParent(Dimension::Type dimension) { - return mRelayoutData && mRelayoutData->GetRelayoutDependentOnParent(dimension); + return mSizer.RelayoutDependentOnParent(dimension); } bool Actor::RelayoutDependentOnChildren(Dimension::Type dimension) { - return mRelayoutData && mRelayoutData->GetRelayoutDependentOnChildren(dimension); -} - -bool Actor::RelayoutDependentOnChildrenBase(Dimension::Type dimension) -{ - return Actor::RelayoutDependentOnChildren(dimension); + return mSizer.RelayoutDependentOnChildrenBase(dimension); } bool Actor::RelayoutDependentOnDimension(Dimension::Type dimension, Dimension::Type dependentDimension) { - return mRelayoutData && mRelayoutData->GetRelayoutDependentOnDimension(dimension, dependentDimension); -} - -void Actor::SetNegotiatedDimension(float negotiatedDimension, Dimension::Type dimension) -{ - if(mRelayoutData) - { - mRelayoutData->SetNegotiatedDimension(negotiatedDimension, dimension); - } -} - -float Actor::GetNegotiatedDimension(Dimension::Type dimension) const -{ - return mRelayoutData ? mRelayoutData->GetNegotiatedDimension(dimension) : 0.0f; + return mSizer.RelayoutDependentOnDimension(dimension, dependentDimension); } void Actor::SetPadding(const Vector2& padding, Dimension::Type dimension) { - EnsureRelayouter().SetPadding(padding, dimension); + mSizer.SetPadding(padding, dimension); } Vector2 Actor::GetPadding(Dimension::Type dimension) const { - return mRelayoutData ? mRelayoutData->GetPadding(dimension) : Relayouter::DEFAULT_DIMENSION_PADDING; + return mSizer.GetPadding(dimension); } void Actor::SetLayoutNegotiated(bool negotiated, Dimension::Type dimension) { - EnsureRelayouter().SetLayoutNegotiated(negotiated, dimension); + mSizer.SetLayoutNegotiated(negotiated, dimension); } bool Actor::IsLayoutNegotiated(Dimension::Type dimension) const { - return mRelayoutData && mRelayoutData->IsLayoutNegotiated(dimension); + return mSizer.IsLayoutNegotiated(dimension); } float Actor::GetHeightForWidthBase(float width) { - const Vector3 naturalSize = GetNaturalSize(); - return naturalSize.width > 0.0f ? naturalSize.height * width / naturalSize.width : width; + // Can be overridden in derived class + return mSizer.GetHeightForWidthBase(width); } float Actor::GetWidthForHeightBase(float height) { - const Vector3 naturalSize = GetNaturalSize(); - return naturalSize.height > 0.0f ? naturalSize.width * height / naturalSize.height : height; + // Can be overridden in derived class + return mSizer.GetWidthForHeightBase(height); } float Actor::CalculateChildSizeBase(const Dali::Actor& child, Dimension::Type dimension) { - return Actor::Relayouter::CalculateChildSize(*this, GetImplementation(child), dimension); + // Can be overridden in derived class + return mSizer.CalculateChildSizeBase(child, dimension); +} + +bool Actor::RelayoutDependentOnChildrenBase(Dimension::Type dimension) +{ + return mSizer.RelayoutDependentOnChildrenBase(dimension); } float Actor::CalculateChildSize(const Dali::Actor& child, Dimension::Type dimension) { // Can be overridden in derived class - return CalculateChildSizeBase(child, dimension); + return mSizer.CalculateChildSizeBase(child, dimension); } float Actor::GetHeightForWidth(float width) { // Can be overridden in derived class - return GetHeightForWidthBase(width); + return mSizer.GetHeightForWidthBase(width); } float Actor::GetWidthForHeight(float height) { // Can be overridden in derived class - return GetWidthForHeightBase(height); -} - -float Actor::GetLatestSize(Dimension::Type dimension) const -{ - return IsLayoutNegotiated(dimension) ? GetNegotiatedDimension(dimension) : GetSize(dimension); + return mSizer.GetWidthForHeightBase(height); } float Actor::GetRelayoutSize(Dimension::Type dimension) const { - Vector2 padding = GetPadding(dimension); - - return GetLatestSize(dimension) + padding.x + padding.y; -} - -float Actor::NegotiateFromParent(Dimension::Type dimension) -{ - return Relayouter::NegotiateDimensionFromParent(*this, dimension); -} - -float Actor::NegotiateFromChildren(Dimension::Type dimension) -{ - return Relayouter::NegotiateDimensionFromChildren(*this, dimension); -} - -float Actor::GetSize(Dimension::Type dimension) const -{ - return Relayouter::GetDimensionValue(mTargetSize, dimension); -} - -float Actor::GetNaturalSize(Dimension::Type dimension) const -{ - return Relayouter::GetDimensionValue(GetNaturalSize(), dimension); -} - -float Actor::CalculateSize(Dimension::Type dimension, const Vector2& maximumSize) -{ - return Relayouter::CalculateSize(*this, dimension, maximumSize); -} - -Vector2 Actor::ApplySizeSetPolicy(const Vector2& size) -{ - return mRelayoutData->ApplySizeSetPolicy(*this, size); -} - -void Actor::SetNegotiatedSize(RelayoutContainer& container) -{ - // Do the set actor size - Vector2 negotiatedSize(GetLatestSize(Dimension::WIDTH), GetLatestSize(Dimension::HEIGHT)); - - // Adjust for size set policy - negotiatedSize = ApplySizeSetPolicy(negotiatedSize); - - // Lock the flag to stop recursive relayouts on set size - mRelayoutData->insideRelayout = true; - SetSize(negotiatedSize); - mRelayoutData->insideRelayout = false; - - // Clear flags for all dimensions - SetLayoutDirty(false); - - // Give deriving classes a chance to respond - OnRelayout(negotiatedSize, container); - - if(!mOnRelayoutSignal.Empty()) - { - Dali::Actor handle(this); - mOnRelayoutSignal.Emit(handle); - } - - mRelayoutData->relayoutRequested = false; + return mSizer.GetRelayoutSize(dimension); } void Actor::NegotiateSize(const Vector2& allocatedSize, RelayoutContainer& container) { - Relayouter::NegotiateSize(*this, allocatedSize, container); -} - -void Actor::SetUseAssignedSize(bool use, Dimension::Type dimension) -{ - if(mRelayoutData) - { - mRelayoutData->SetUseAssignedSize(use, dimension); - } -} - -bool Actor::GetUseAssignedSize(Dimension::Type dimension) const -{ - return mRelayoutData && mRelayoutData->GetUseAssignedSize(dimension); + mSizer.NegotiateSize(allocatedSize, container); } void Actor::RelayoutRequest(Dimension::Type dimension) { - Internal::RelayoutController* relayoutController = Internal::RelayoutController::Get(); - if(relayoutController) - { - Dali::Actor self(this); - relayoutController->RequestRelayout(self, dimension); - - if(mRelayoutData) - { - mRelayoutData->relayoutRequested = true; - } - } -} - -void Actor::SetPreferredSize(const Vector2& size) -{ - EnsureRelayouter().SetPreferredSize(*this, size); -} - -Vector2 Actor::GetPreferredSize() const -{ - return mRelayoutData ? Vector2(mRelayoutData->preferredSize) : Relayouter::DEFAULT_PREFERRED_SIZE; + mSizer.RelayoutRequest(dimension); } void Actor::SetMinimumSize(float size, Dimension::Type dimension) { - EnsureRelayouter().SetMinimumSize(size, dimension); - RelayoutRequest(); + mSizer.SetMinimumSize(size, dimension); } float Actor::GetMinimumSize(Dimension::Type dimension) const { - return mRelayoutData ? mRelayoutData->GetMinimumSize(dimension) : 0.0f; + return mSizer.GetMinimumSize(dimension); } void Actor::SetMaximumSize(float size, Dimension::Type dimension) { - EnsureRelayouter().SetMaximumSize(size, dimension); - RelayoutRequest(); + mSizer.SetMaximumSize(size, dimension); } float Actor::GetMaximumSize(Dimension::Type dimension) const { - return mRelayoutData ? mRelayoutData->GetMaximumSize(dimension) : FLT_MAX; + return mSizer.GetMaximumSize(dimension); } void Actor::SetVisibleInternal(bool visible, SendMessage::Type sendMessage) diff --git a/dali/internal/event/actors/actor-impl.h b/dali/internal/event/actors/actor-impl.h index 73a98aa..8f72b23 100644 --- a/dali/internal/event/actors/actor-impl.h +++ b/dali/internal/event/actors/actor-impl.h @@ -22,8 +22,17 @@ #include // INTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include + #include #include + #include #include #include @@ -31,16 +40,10 @@ #include #include #include +#include #include #include #include -#include -#include -#include -#include -#include -#include -#include namespace Dali { @@ -75,41 +78,6 @@ class Actor : public Object, public ActorParent { public: /** - * @brief Struct to hold an actor and a dimension - */ - struct ActorDimensionPair - { - /** - * @brief Constructor - * - * @param[in] newActor The actor to assign - * @param[in] newDimension The dimension to assign - */ - ActorDimensionPair(Actor* newActor, Dimension::Type newDimension) - : actor(newActor), - dimension(newDimension) - { - } - - /** - * @brief Equality operator - * - * @param[in] lhs The left hand side argument - * @param[in] rhs The right hand side argument - */ - bool operator==(const ActorDimensionPair& rhs) - { - return (actor == rhs.actor) && (dimension == rhs.dimension); - } - - Actor* actor; ///< The actor to hold - Dimension::Type dimension; ///< The dimension to hold - }; - - using ActorDimensionStack = std::vector; - -public: - /** * Create a new actor. * @return A smart-pointer to the newly allocated Actor. */ @@ -297,13 +265,6 @@ public: void SetSize(const Vector2& size); /** - * Sets the update size for an actor. - * - * @param[in] size The size to set. - */ - void SetSizeInternal(const Vector2& size); - - /** * Sets the size of an actor. * This does not interfere with the actors scale factor. * @param [in] size The new size. @@ -311,13 +272,6 @@ public: void SetSize(const Vector3& size); /** - * Sets the update size for an actor. - * - * @param[in] size The size to set. - */ - void SetSizeInternal(const Vector3& size); - - /** * Set the width component of the Actor's size. * @param [in] width The new width component. */ @@ -857,16 +811,6 @@ public: virtual bool RelayoutDependentOnChildren(Dimension::Type dimension = Dimension::ALL_DIMENSIONS); /** - * @brief Determine if this actor is dependent on it's children for relayout. - * - * Called from deriving classes - * - * @param dimension The dimension(s) to check for - * @return Return if the actor is dependent on it's children - */ - virtual bool RelayoutDependentOnChildrenBase(Dimension::Type dimension = Dimension::ALL_DIMENSIONS); - - /** * @brief Calculate the size for a child * * @param[in] child The child actor to calculate the size for @@ -913,24 +857,6 @@ public: void NegotiateSize(const Vector2& size, RelayoutContainer& container); /** - * @brief Set whether size negotiation should use the assigned size of the actor - * during relayout for the given dimension(s) - * - * @param[in] use Whether the assigned size of the actor should be used - * @param[in] dimension The dimension(s) to set. Can be a bitfield of multiple dimensions - */ - void SetUseAssignedSize(bool use, Dimension::Type dimension = Dimension::ALL_DIMENSIONS); - - /** - * @brief Returns whether size negotiation should use the assigned size of the actor - * during relayout for a single dimension - * - * @param[in] dimension The dimension to get - * @return Return whether the assigned size of the actor should be used. If more than one dimension is requested, just return the first one found - */ - bool GetUseAssignedSize(Dimension::Type dimension) const; - - /** * @copydoc Dali::Actor::SetResizePolicy() */ void SetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension = Dimension::ALL_DIMENSIONS); @@ -941,26 +867,6 @@ public: ResizePolicy::Type GetResizePolicy(Dimension::Type dimension) const; /** - * @copydoc Dali::Actor::SetSizeScalePolicy() - */ - void SetSizeScalePolicy(SizeScalePolicy::Type policy); - - /** - * @copydoc Dali::Actor::GetSizeScalePolicy() - */ - SizeScalePolicy::Type GetSizeScalePolicy() const; - - /** - * @copydoc Dali::Actor::SetDimensionDependency() - */ - void SetDimensionDependency(Dimension::Type dimension, Dimension::Type dependency); - - /** - * @copydoc Dali::Actor::GetDimensionDependency() - */ - Dimension::Type GetDimensionDependency(Dimension::Type dimension) const; - - /** * @brief Set the size negotiation relayout enabled on this actor * * @param[in] relayoutEnabled Boolean to enable or disable relayout @@ -976,6 +882,7 @@ public: /** * @brief Mark an actor as having it's layout dirty + * @note Only called from RelayoutController * * @param dirty Whether to mark actor as dirty or not * @param dimension The dimension(s) to mark as dirty @@ -984,6 +891,7 @@ public: /** * @brief Return if any of an actor's dimensions are marked as dirty + * @note Only called from RelayoutController * * @param dimension The dimension(s) to check * @return Return if any of the requested dimensions are dirty @@ -992,6 +900,7 @@ public: /** * @brief Returns if relayout is enabled and the actor is not dirty + * @note Only called from RelayoutController * * @return Return if it is possible to relayout the actor */ @@ -999,6 +908,7 @@ public: /** * @brief Returns if relayout is enabled and the actor is dirty + * @note Only called from RelayoutController * * @return Return if it is required to relayout the actor */ @@ -1021,6 +931,7 @@ public: /** * @brief Determine if this actor is dependent on it's parent for relayout + * @note Only called from RelayoutController * * @param dimension The dimension(s) to check for * @return Return if the actor is dependent on it's parent @@ -1029,6 +940,7 @@ public: /** * @brief Determine if this actor has another dimension depedent on the specified one + * @note Only called from RelayoutController * * @param dimension The dimension to check for * @param dependentDimension The dimension to check for dependency with @@ -1037,47 +949,6 @@ public: bool RelayoutDependentOnDimension(Dimension::Type dimension, Dimension::Type dependentDimension); /** - * @brief Calculate the size of a dimension - * - * @param[in] dimension The dimension to calculate the size for - * @param[in] maximumSize The upper bounds on the size - * @return Return the calculated size for the dimension - */ - float CalculateSize(Dimension::Type dimension, const Vector2& maximumSize); - - /** - * Negotiate a dimension based on the size of the parent - * - * @param[in] dimension The dimension to negotiate on - * @return Return the negotiated size - */ - float NegotiateFromParent(Dimension::Type dimension); - - /** - * @brief Negotiate a dimension based on the size of the children - * - * @param[in] dimension The dimension to negotiate on - * @return Return the negotiated size - */ - float NegotiateFromChildren(Dimension::Type dimension); - - /** - * Set the negotiated dimension value for the given dimension(s) - * - * @param negotiatedDimension The value to set - * @param dimension The dimension(s) to set the value for - */ - void SetNegotiatedDimension(float negotiatedDimension, Dimension::Type dimension = Dimension::ALL_DIMENSIONS); - - /** - * Return the value of negotiated dimension for the given dimension - * - * @param dimension The dimension to retrieve - * @return Return the value of the negotiated dimension - */ - float GetNegotiatedDimension(Dimension::Type dimension) const; - - /** * @brief Set the padding for a dimension * * @param[in] padding Padding for the dimension. X = start (e.g. left, bottom), y = end (e.g. right, top) @@ -1094,22 +965,6 @@ public: Vector2 GetPadding(Dimension::Type dimension) const; /** - * Return the actor size for a given dimension - * - * @param[in] dimension The dimension to retrieve the size for - * @return Return the size for the given dimension - */ - float GetSize(Dimension::Type dimension) const; - - /** - * Return the natural size of the actor for a given dimension - * - * @param[in] dimension The dimension to retrieve the size for - * @return Return the natural size for the given dimension - */ - float GetNaturalSize(Dimension::Type dimension) const; - - /** * @brief Return the amount of size allocated for relayout * * May include padding @@ -1120,21 +975,6 @@ public: float GetRelayoutSize(Dimension::Type dimension) const; /** - * @brief If the size has been negotiated return that else return normal size - * - * @param[in] dimension The dimension to retrieve - * @return Return the size - */ - float GetLatestSize(Dimension::Type dimension) const; - - /** - * Apply the negotiated size to the actor - * - * @param[in] container The container to fill with actors that require further relayout - */ - void SetNegotiatedSize(RelayoutContainer& container); - - /** * @brief Flag the actor as having it's layout dimension negotiated. * * @param[in] negotiated The status of the flag to set. @@ -1165,7 +1005,7 @@ public: float GetWidthForHeightBase(float height); /** - * @brief Calculate the size for a child + * @brief provides the Actor implementation of CalculateChildSize * * @param[in] child The child actor to calculate the size for * @param[in] dimension The dimension to calculate the size for. E.g. width or height. @@ -1174,18 +1014,12 @@ public: float CalculateChildSizeBase(const Dali::Actor& child, Dimension::Type dimension); /** - * @brief Set the preferred size for size negotiation - * - * @param[in] size The preferred size to set - */ - void SetPreferredSize(const Vector2& size); - - /** - * @brief Return the preferred size used for size negotiation + * @brief Determine if this actor is dependent on it's children for relayout. * - * @return Return the preferred size + * @param dimension The dimension(s) to check for + * @return Return if the actor is dependent on it's children */ - Vector2 GetPreferredSize() const; + bool RelayoutDependentOnChildrenBase(Dimension::Type dimension = Dimension::ALL_DIMENSIONS); /** * @copydoc Dali::Actor::SetMinimumSize @@ -1799,19 +1633,6 @@ private: }; }; - struct AnimatedSizeFlag - { - enum Type - { - CLEAR = 0, - WIDTH = 1, - HEIGHT = 2, - DEPTH = 4 - }; - }; - - struct Relayouter; - // Remove default constructor and copy constructor Actor() = delete; Actor(const Actor&) = delete; @@ -1906,19 +1727,6 @@ private: bool GetCurrentPropertyValue(Property::Index index, Property::Value& value) const; /** - * @brief Ensure the relayouter is allocated - */ - Relayouter& EnsureRelayouter(); - - /** - * @brief Apply the size set policy to the input size - * - * @param[in] size The size to apply the policy to - * @return Return the adjusted size - */ - Vector2 ApplySizeSetPolicy(const Vector2& size); - - /** * Retrieve the parent object of an Actor. * @return The parent object, or NULL if the Actor does not have a parent. */ @@ -2004,12 +1812,12 @@ private: protected: ActorParentImpl mParentImpl; ///< Implementation of ActorParent; + ActorSizer mSizer; ///< Implementation for managing actor size ActorParent* mParent; ///< Each actor (except the root) can have one parent Scene* mScene; ///< The scene the actor is added to RendererContainer* mRenderers; ///< Renderer container Vector3* mParentOrigin; ///< NULL means ParentOrigin::DEFAULT. ParentOrigin is non-animatable Vector3* mAnchorPoint; ///< NULL means AnchorPoint::DEFAULT. AnchorPoint is non-animatable - Relayouter* mRelayoutData; ///< Struct to hold optional collection of relayout variables ActorGestureData* mGestureData; ///< Optional Gesture data. Only created when actor requires gestures // Signals @@ -2025,16 +1833,13 @@ protected: Quaternion mTargetOrientation; ///< Event-side storage for orientation Vector4 mTargetColor; ///< Event-side storage for color - Vector3 mTargetSize; ///< Event-side storage for size (not a pointer as most actors will have a size) Vector3 mTargetPosition; ///< Event-side storage for position (not a pointer as most actors will have a position) Vector3 mTargetScale; ///< Event-side storage for scale - Vector3 mAnimatedSize; ///< Event-side storage for size animation Rect mTouchAreaOffset; ///< touch area offset (left, right, bottom, top) - ConstString mName; ///< Name of the actor - uint32_t mSortedDepth; ///< The sorted depth index. A combination of tree traversal and sibling order. - int16_t mDepth; ///< The depth in the hierarchy of the actor. Only 32,767 levels of depth are supported - uint16_t mUseAnimatedSize; ///< Whether the size is animated. + ConstString mName; ///< Name of the actor + uint32_t mSortedDepth; ///< The sorted depth index. A combination of tree traversal and sibling order. + int16_t mDepth; ///< The depth in the hierarchy of the actor. Only 32,767 levels of depth are supported const bool mIsRoot : 1; ///< Flag to identify the root actor const bool mIsLayer : 1; ///< Flag to identify that this is a layer @@ -2068,6 +1873,7 @@ private: struct SiblingHandler; friend class ActorParentImpl; // Allow impl to call private methods on actor + friend class ActorSizer; // Allow sizer to call private methods on actor }; } // namespace Internal diff --git a/dali/internal/event/actors/actor-property-handler.cpp b/dali/internal/event/actors/actor-property-handler.cpp index cce13c8..2012ed1 100644 --- a/dali/internal/event/actors/actor-property-handler.cpp +++ b/dali/internal/event/actors/actor-property-handler.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -423,30 +424,30 @@ void Actor::PropertyHandler::SetDefaultProperty(Internal::Actor& actor, Property case Dali::Actor::Property::WIDTH_RESIZE_POLICY: { - ResizePolicy::Type type = actor.GetResizePolicy(Dimension::WIDTH); + ResizePolicy::Type type = actor.mSizer.GetResizePolicy(Dimension::WIDTH); if(Scripting::GetEnumerationProperty(property, RESIZE_POLICY_TABLE, RESIZE_POLICY_TABLE_COUNT, type)) { - actor.SetResizePolicy(type, Dimension::WIDTH); + actor.mSizer.SetResizePolicy(type, Dimension::WIDTH); } break; } case Dali::Actor::Property::HEIGHT_RESIZE_POLICY: { - ResizePolicy::Type type = actor.GetResizePolicy(Dimension::HEIGHT); + ResizePolicy::Type type = actor.mSizer.GetResizePolicy(Dimension::HEIGHT); if(Scripting::GetEnumerationProperty(property, RESIZE_POLICY_TABLE, RESIZE_POLICY_TABLE_COUNT, type)) { - actor.SetResizePolicy(type, Dimension::HEIGHT); + actor.mSizer.SetResizePolicy(type, Dimension::HEIGHT); } break; } case Dali::Actor::Property::SIZE_SCALE_POLICY: { - SizeScalePolicy::Type type = actor.GetSizeScalePolicy(); + SizeScalePolicy::Type type = actor.mSizer.GetSizeScalePolicy(); if(Scripting::GetEnumerationProperty(property, SIZE_SCALE_POLICY_TABLE, SIZE_SCALE_POLICY_TABLE_COUNT, type)) { - actor.SetSizeScalePolicy(type); + actor.mSizer.SetSizeScalePolicy(type); } break; } @@ -455,7 +456,7 @@ void Actor::PropertyHandler::SetDefaultProperty(Internal::Actor& actor, Property { if(property.Get()) { - actor.SetResizePolicy(ResizePolicy::DIMENSION_DEPENDENCY, Dimension::WIDTH); + actor.mSizer.SetResizePolicy(ResizePolicy::DIMENSION_DEPENDENCY, Dimension::WIDTH); } break; } @@ -464,7 +465,7 @@ void Actor::PropertyHandler::SetDefaultProperty(Internal::Actor& actor, Property { if(property.Get()) { - actor.SetResizePolicy(ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT); + actor.mSizer.SetResizePolicy(ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT); } break; } @@ -797,68 +798,40 @@ void Actor::PropertyHandler::OnNotifyDefaultPropertyAnimation(Internal::Actor& a { case Dali::Actor::Property::SIZE: { - if(value.Get(actor.mTargetSize)) + Vector3 targetSize; + if(value.Get(targetSize)) { - actor.mAnimatedSize = actor.mTargetSize; - actor.mUseAnimatedSize = AnimatedSizeFlag::WIDTH | AnimatedSizeFlag::HEIGHT | AnimatedSizeFlag::DEPTH; - - if(actor.mRelayoutData && !actor.mRelayoutData->relayoutRequested) - { - actor.mRelayoutData->preferredSize.width = actor.mAnimatedSize.width; - actor.mRelayoutData->preferredSize.height = actor.mAnimatedSize.height; - } - - // Notify deriving classes - actor.OnSizeAnimation(animation, actor.mTargetSize); + actor.mSizer.OnAnimateSize(animation, targetSize, false); } break; } case Dali::Actor::Property::SIZE_WIDTH: { - if(value.Get(actor.mTargetSize.width)) + float width; + if(value.Get(width)) { - actor.mAnimatedSize.width = actor.mTargetSize.width; - actor.mUseAnimatedSize |= AnimatedSizeFlag::WIDTH; - - if(actor.mRelayoutData && !actor.mRelayoutData->relayoutRequested) - { - actor.mRelayoutData->preferredSize.width = actor.mAnimatedSize.width; - } - - // Notify deriving classes - actor.OnSizeAnimation(animation, actor.mTargetSize); + actor.mSizer.OnAnimateWidth(animation, width, false); } break; } case Dali::Actor::Property::SIZE_HEIGHT: { - if(value.Get(actor.mTargetSize.height)) + float height; + if(value.Get(height)) { - actor.mAnimatedSize.height = actor.mTargetSize.height; - actor.mUseAnimatedSize |= AnimatedSizeFlag::HEIGHT; - - if(actor.mRelayoutData && !actor.mRelayoutData->relayoutRequested) - { - actor.mRelayoutData->preferredSize.height = actor.mAnimatedSize.height; - } - - // Notify deriving classes - actor.OnSizeAnimation(animation, actor.mTargetSize); + actor.mSizer.OnAnimateHeight(animation, height, false); } break; } case Dali::Actor::Property::SIZE_DEPTH: { - if(value.Get(actor.mTargetSize.depth)) + float depth; + if(value.Get(depth)) { - actor.mAnimatedSize.depth = actor.mTargetSize.depth; - actor.mUseAnimatedSize |= AnimatedSizeFlag::DEPTH; - - // Notify deriving classes - actor.OnSizeAnimation(animation, actor.mTargetSize); + actor.mSizer.OnAnimateDepth(animation, depth, false); } break; } @@ -969,68 +942,40 @@ void Actor::PropertyHandler::OnNotifyDefaultPropertyAnimation(Internal::Actor& a { case Dali::Actor::Property::SIZE: { - if(AdjustValue(actor.mTargetSize, value)) + Vector3 targetSize; + if(value.Get(targetSize)) { - actor.mAnimatedSize = actor.mTargetSize; - actor.mUseAnimatedSize = AnimatedSizeFlag::WIDTH | AnimatedSizeFlag::HEIGHT | AnimatedSizeFlag::DEPTH; - - if(actor.mRelayoutData && !actor.mRelayoutData->relayoutRequested) - { - actor.mRelayoutData->preferredSize.width = actor.mAnimatedSize.width; - actor.mRelayoutData->preferredSize.height = actor.mAnimatedSize.height; - } - - // Notify deriving classes - actor.OnSizeAnimation(animation, actor.mTargetSize); + actor.mSizer.OnAnimateSize(animation, targetSize, true); } break; } case Dali::Actor::Property::SIZE_WIDTH: { - if(AdjustValue(actor.mTargetSize.width, value)) + float width; + if(value.Get(width)) { - actor.mAnimatedSize.width = actor.mTargetSize.width; - actor.mUseAnimatedSize |= AnimatedSizeFlag::WIDTH; - - if(actor.mRelayoutData && !actor.mRelayoutData->relayoutRequested) - { - actor.mRelayoutData->preferredSize.width = actor.mAnimatedSize.width; - } - - // Notify deriving classes - actor.OnSizeAnimation(animation, actor.mTargetSize); + actor.mSizer.OnAnimateWidth(animation, width, true); } break; } case Dali::Actor::Property::SIZE_HEIGHT: { - if(AdjustValue(actor.mTargetSize.height, value)) + float height; + if(value.Get(height)) { - actor.mAnimatedSize.height = actor.mTargetSize.height; - actor.mUseAnimatedSize |= AnimatedSizeFlag::HEIGHT; - - if(actor.mRelayoutData && !actor.mRelayoutData->relayoutRequested) - { - actor.mRelayoutData->preferredSize.height = actor.mAnimatedSize.height; - } - - // Notify deriving classes - actor.OnSizeAnimation(animation, actor.mTargetSize); + actor.mSizer.OnAnimateHeight(animation, height, true); } break; } case Dali::Actor::Property::SIZE_DEPTH: { - if(AdjustValue(actor.mTargetSize.depth, value)) + float depth; + if(value.Get(depth)) { - actor.mAnimatedSize.depth = actor.mTargetSize.depth; - actor.mUseAnimatedSize |= AnimatedSizeFlag::DEPTH; - - // Notify deriving classes - actor.OnSizeAnimation(animation, actor.mTargetSize); + actor.mSizer.OnAnimateDepth(animation, depth, true); } break; } @@ -1553,31 +1498,31 @@ bool Actor::PropertyHandler::GetCachedPropertyValue(const Internal::Actor& actor case Dali::Actor::Property::WIDTH_RESIZE_POLICY: { - value = Scripting::GetLinearEnumerationName(actor.GetResizePolicy(Dimension::WIDTH), RESIZE_POLICY_TABLE, RESIZE_POLICY_TABLE_COUNT); + value = Scripting::GetLinearEnumerationName(actor.mSizer.GetResizePolicy(Dimension::WIDTH), RESIZE_POLICY_TABLE, RESIZE_POLICY_TABLE_COUNT); break; } case Dali::Actor::Property::HEIGHT_RESIZE_POLICY: { - value = Scripting::GetLinearEnumerationName(actor.GetResizePolicy(Dimension::HEIGHT), RESIZE_POLICY_TABLE, RESIZE_POLICY_TABLE_COUNT); + value = Scripting::GetLinearEnumerationName(actor.mSizer.GetResizePolicy(Dimension::HEIGHT), RESIZE_POLICY_TABLE, RESIZE_POLICY_TABLE_COUNT); break; } case Dali::Actor::Property::SIZE_SCALE_POLICY: { - value = actor.GetSizeScalePolicy(); + value = actor.mSizer.GetSizeScalePolicy(); break; } case Dali::Actor::Property::WIDTH_FOR_HEIGHT: { - value = (actor.GetResizePolicy(Dimension::WIDTH) == ResizePolicy::DIMENSION_DEPENDENCY) && (actor.GetDimensionDependency(Dimension::WIDTH) == Dimension::HEIGHT); + value = (actor.mSizer.GetResizePolicy(Dimension::WIDTH) == ResizePolicy::DIMENSION_DEPENDENCY) && (actor.mSizer.GetDimensionDependency(Dimension::WIDTH) == Dimension::HEIGHT); break; } case Dali::Actor::Property::HEIGHT_FOR_WIDTH: { - value = (actor.GetResizePolicy(Dimension::HEIGHT) == ResizePolicy::DIMENSION_DEPENDENCY) && (actor.GetDimensionDependency(Dimension::HEIGHT) == Dimension::WIDTH); + value = (actor.mSizer.GetResizePolicy(Dimension::HEIGHT) == ResizePolicy::DIMENSION_DEPENDENCY) && (actor.mSizer.GetDimensionDependency(Dimension::HEIGHT) == Dimension::WIDTH); break; } diff --git a/dali/internal/event/actors/actor-relayouter.cpp b/dali/internal/event/actors/actor-relayouter.cpp index f8e57d1..cfebf86 100644 --- a/dali/internal/event/actors/actor-relayouter.cpp +++ b/dali/internal/event/actors/actor-relayouter.cpp @@ -24,48 +24,18 @@ #include #include +#include #include -namespace -{ #if defined(DEBUG_ENABLED) Debug::Filter* gLogRelayoutFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RELAYOUT_TIMER"); #endif -/** - * @brief Extract a given dimension from a Vector2 - * - * @param[in] values The values to extract from - * @param[in] dimension The dimension to extract - * @return Return the value for the dimension - */ -constexpr float GetDimensionValue(const Dali::Vector2& values, const Dali::Dimension::Type dimension) -{ - switch(dimension) - { - case Dali::Dimension::WIDTH: - { - return values.width; - } - case Dali::Dimension::HEIGHT: - { - return values.height; - } - default: - { - break; - } - } - return 0.0f; -} - -} // unnamed namespace - namespace Dali { namespace Internal { -Actor::Relayouter::Relayouter() +ActorSizer::Relayouter::Relayouter() : sizeModeFactor(DEFAULT_SIZE_MODE_FACTOR), preferredSize(DEFAULT_PREFERRED_SIZE), sizeSetPolicy(DEFAULT_SIZE_SCALE_POLICY), @@ -88,7 +58,7 @@ Actor::Relayouter::Relayouter() } } -ResizePolicy::Type Actor::Relayouter::GetResizePolicy(Dimension::Type dimension) const +ResizePolicy::Type ActorSizer::Relayouter::GetResizePolicy(Dimension::Type dimension) const { // If more than one dimension is requested, just return the first one found for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) @@ -109,55 +79,7 @@ ResizePolicy::Type Actor::Relayouter::GetResizePolicy(Dimension::Type dimension) return ResizePolicy::DEFAULT; } -void Actor::Relayouter::SetPadding(const Vector2& padding, Dimension::Type dimension) -{ - for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) - { - if(dimension & (1 << i)) - { - dimensionPadding[i] = padding; - } - } -} - -Vector2 Actor::Relayouter::GetPadding(Dimension::Type dimension) -{ - // If more than one dimension is requested, just return the first one found - for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) - { - if((dimension & (1 << i))) - { - return dimensionPadding[i]; - } - } - - return DEFAULT_DIMENSION_PADDING; -} - -void Actor::Relayouter::SetLayoutNegotiated(bool negotiated, Dimension::Type dimension) -{ - for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) - { - if(dimension & (1 << i)) - { - dimensionNegotiated[i] = negotiated; - } - } -} - -bool Actor::Relayouter::IsLayoutNegotiated(Dimension::Type dimension) const -{ - for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) - { - if((dimension & (1 << i)) && dimensionNegotiated[i]) - { - return true; - } - } - return false; -} - -Vector2 Actor::Relayouter::ApplySizeSetPolicy(Internal::Actor& actor, const Vector2& size) +Vector2 ActorSizer::Relayouter::ApplySizeSetPolicy(Internal::Actor& actor, const Vector2& size) { switch(sizeSetPolicy) { @@ -226,7 +148,7 @@ Vector2 Actor::Relayouter::ApplySizeSetPolicy(Internal::Actor& actor, const Vect return size; } -void Actor::Relayouter::SetUseAssignedSize(bool use, Dimension::Type dimension) +void ActorSizer::Relayouter::SetUseAssignedSize(bool use, Dimension::Type dimension) { for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) { @@ -237,7 +159,7 @@ void Actor::Relayouter::SetUseAssignedSize(bool use, Dimension::Type dimension) } } -bool Actor::Relayouter::GetUseAssignedSize(Dimension::Type dimension) const +bool ActorSizer::Relayouter::GetUseAssignedSize(Dimension::Type dimension) const { // If more than one dimension is requested, just return the first one found for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) @@ -251,7 +173,7 @@ bool Actor::Relayouter::GetUseAssignedSize(Dimension::Type dimension) const return false; } -void Actor::Relayouter::SetMinimumSize(float size, Dimension::Type dimension) +void ActorSizer::Relayouter::SetMinimumSize(float size, Dimension::Type dimension) { for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) { @@ -262,7 +184,7 @@ void Actor::Relayouter::SetMinimumSize(float size, Dimension::Type dimension) } } -float Actor::Relayouter::GetMinimumSize(Dimension::Type dimension) const +float ActorSizer::Relayouter::GetMinimumSize(Dimension::Type dimension) const { for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) { @@ -275,7 +197,7 @@ float Actor::Relayouter::GetMinimumSize(Dimension::Type dimension) const return 0.0f; // Default } -void Actor::Relayouter::SetMaximumSize(float size, Dimension::Type dimension) +void ActorSizer::Relayouter::SetMaximumSize(float size, Dimension::Type dimension) { for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) { @@ -286,7 +208,7 @@ void Actor::Relayouter::SetMaximumSize(float size, Dimension::Type dimension) } } -float Actor::Relayouter::GetMaximumSize(Dimension::Type dimension) const +float ActorSizer::Relayouter::GetMaximumSize(Dimension::Type dimension) const { for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) { @@ -299,7 +221,7 @@ float Actor::Relayouter::GetMaximumSize(Dimension::Type dimension) const return FLT_MAX; // Default } -void Actor::Relayouter::SetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension, Vector3& targetSize) +void ActorSizer::Relayouter::SetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension, Vector3& targetSize) { ResizePolicy::Type originalWidthPolicy = GetResizePolicy(Dimension::WIDTH); ResizePolicy::Type originalHeightPolicy = GetResizePolicy(Dimension::HEIGHT); @@ -365,7 +287,7 @@ void Actor::Relayouter::SetResizePolicy(ResizePolicy::Type policy, Dimension::Ty } } -bool Actor::Relayouter::GetRelayoutDependentOnParent(Dimension::Type dimension) +bool ActorSizer::Relayouter::GetRelayoutDependentOnParent(Dimension::Type dimension) { // Check if actor is dependent on parent for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) @@ -382,7 +304,7 @@ bool Actor::Relayouter::GetRelayoutDependentOnParent(Dimension::Type dimension) return false; } -bool Actor::Relayouter::GetRelayoutDependentOnChildren(Dimension::Type dimension) +bool ActorSizer::Relayouter::GetRelayoutDependentOnChildren(Dimension::Type dimension) { // Check if actor is dependent on children for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) @@ -401,7 +323,7 @@ bool Actor::Relayouter::GetRelayoutDependentOnChildren(Dimension::Type dimension return false; } -bool Actor::Relayouter::GetRelayoutDependentOnDimension(Dimension::Type dimension, Dimension::Type dependency) +bool ActorSizer::Relayouter::GetRelayoutDependentOnDimension(Dimension::Type dimension, Dimension::Type dependency) { // Check each possible dimension and see if it is dependent on the input one for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) @@ -415,7 +337,7 @@ bool Actor::Relayouter::GetRelayoutDependentOnDimension(Dimension::Type dimensio return false; } -void Actor::Relayouter::SetDimensionDependency(Dimension::Type dimension, Dimension::Type dependency) +void ActorSizer::Relayouter::SetDimensionDependency(Dimension::Type dimension, Dimension::Type dependency) { for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) { @@ -426,7 +348,7 @@ void Actor::Relayouter::SetDimensionDependency(Dimension::Type dimension, Dimens } } -Dimension::Type Actor::Relayouter::GetDimensionDependency(Dimension::Type dimension) const +Dimension::Type ActorSizer::Relayouter::GetDimensionDependency(Dimension::Type dimension) const { // If more than one dimension is requested, just return the first one found for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) @@ -440,7 +362,7 @@ Dimension::Type Actor::Relayouter::GetDimensionDependency(Dimension::Type dimens return Dimension::ALL_DIMENSIONS; // Default } -void Actor::Relayouter::SetLayoutDirty(bool dirty, Dimension::Type dimension) +void ActorSizer::Relayouter::SetLayoutDirty(bool dirty, Dimension::Type dimension) { for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) { @@ -451,7 +373,7 @@ void Actor::Relayouter::SetLayoutDirty(bool dirty, Dimension::Type dimension) } } -bool Actor::Relayouter::IsLayoutDirty(Dimension::Type dimension) const +bool ActorSizer::Relayouter::IsLayoutDirty(Dimension::Type dimension) const { for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) { @@ -464,38 +386,7 @@ bool Actor::Relayouter::IsLayoutDirty(Dimension::Type dimension) const return false; } -void Actor::Relayouter::SetPreferredSize(Actor& actor, const Vector2& size) -{ - // If valid width or height, then set the resize policy to FIXED - // A 0 width or height may also be required so if the resize policy has not been changed, i.e. is still set to DEFAULT, - // then change to FIXED as well - - if(size.width > 0.0f || GetResizePolicy(Dimension::WIDTH) == ResizePolicy::DEFAULT) - { - actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::WIDTH); - } - - if(size.height > 0.0f || GetResizePolicy(Dimension::HEIGHT) == ResizePolicy::DEFAULT) - { - actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::HEIGHT); - } - - actor.mRelayoutData->preferredSize = size; - - actor.mUseAnimatedSize = AnimatedSizeFlag::CLEAR; - - actor.RelayoutRequest(); -} - -float Actor::Relayouter::ClampDimension(const Internal::Actor& actor, float size, Dimension::Type dimension) -{ - const float minSize = actor.GetMinimumSize(dimension); - const float maxSize = actor.GetMaximumSize(dimension); - - return std::max(minSize, std::min(size, maxSize)); -} - -void Actor::Relayouter::SetNegotiatedDimension(float negotiatedDimension, Dimension::Type dimension) +void ActorSizer::Relayouter::SetNegotiatedDimension(float negotiatedDimension, Dimension::Type dimension) { for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) { @@ -506,7 +397,7 @@ void Actor::Relayouter::SetNegotiatedDimension(float negotiatedDimension, Dimens } } -float Actor::Relayouter::GetNegotiatedDimension(Dimension::Type dimension) +float ActorSizer::Relayouter::GetNegotiatedDimension(Dimension::Type dimension) { // If more than one dimension is requested, just return the first one found for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) @@ -520,286 +411,52 @@ float Actor::Relayouter::GetNegotiatedDimension(Dimension::Type dimension) return 0.0f; // Default } -float Actor::Relayouter::NegotiateDimensionFromParent(Actor& actor, Dimension::Type dimension) +void ActorSizer::Relayouter::SetPadding(const Vector2& padding, Dimension::Type dimension) { - Actor* parent = actor.GetParent(); - if(parent) - { - Vector2 padding(actor.GetPadding(dimension)); - Vector2 parentPadding(parent->GetPadding(dimension)); - - // Need to use actor API here to allow deriving actors to layout their children - return parent->CalculateChildSize(Dali::Actor(&actor), dimension) - parentPadding.x - parentPadding.y - padding.x - padding.y; - } - - return 0.0f; -} - -float Actor::Relayouter::NegotiateDimensionFromChildren(Actor& actor, Dimension::Type dimension) -{ - float maxDimensionPoint = 0.0f; - - for(uint32_t i = 0, count = actor.GetChildCount(); i < count; ++i) - { - ActorPtr child = actor.GetChildAt(i); - - if(!child->RelayoutDependentOnParent(dimension)) - { - // Calculate the min and max points that the children range across - float childPosition = GetDimensionValue(child->GetTargetPosition(), dimension); - float dimensionSize = child->GetRelayoutSize(dimension); - maxDimensionPoint = std::max(maxDimensionPoint, childPosition + dimensionSize); - } - } - - return maxDimensionPoint; -} - -void Actor::Relayouter::NegotiateDimension(Actor& actor, Dimension::Type dimension, const Vector2& allocatedSize, Actor::ActorDimensionStack& recursionStack) -{ - // Check if it needs to be negotiated - if(actor.IsLayoutDirty(dimension) && !actor.IsLayoutNegotiated(dimension)) + for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) { - // Check that we havn't gotten into an infinite loop - Actor::ActorDimensionPair searchActor = Actor::ActorDimensionPair(&actor, dimension); - bool recursionFound = false; - for(auto& element : recursionStack) - { - if(element == searchActor) - { - recursionFound = true; - break; - } - } - - if(!recursionFound) - { - // Record the path that we have taken - recursionStack.push_back(Actor::ActorDimensionPair(&actor, dimension)); - - // Dimension dependency check - for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) - { - Dimension::Type dimensionToCheck = static_cast(1 << i); - - if(actor.RelayoutDependentOnDimension(dimension, dimensionToCheck)) - { - NegotiateDimension(actor, dimensionToCheck, allocatedSize, recursionStack); - } - } - - // Parent dependency check - Actor* parent = actor.GetParent(); - if(parent && actor.RelayoutDependentOnParent(dimension)) - { - NegotiateDimension(*parent, dimension, allocatedSize, recursionStack); - } - - // Children dependency check - if(actor.RelayoutDependentOnChildren(dimension)) - { - for(uint32_t i = 0, count = actor.GetChildCount(); i < count; ++i) - { - ActorPtr child = actor.GetChildAt(i); - - // Only relayout child first if it is not dependent on this actor - if(!child->RelayoutDependentOnParent(dimension)) - { - NegotiateDimension(*child, dimension, allocatedSize, recursionStack); - } - } - } - - // For deriving classes - actor.OnCalculateRelayoutSize(dimension); - - // All dependencies checked, calculate the size and set negotiated flag - const float newSize = ClampDimension(actor, actor.CalculateSize(dimension, allocatedSize), dimension); - - actor.SetNegotiatedDimension(newSize, dimension); - actor.SetLayoutNegotiated(true, dimension); - - // For deriving classes - actor.OnLayoutNegotiated(newSize, dimension); - - // This actor has been successfully processed, pop it off the recursion stack - recursionStack.pop_back(); - } - else + if(dimension & (1 << i)) { - // TODO: Break infinite loop - actor.SetLayoutNegotiated(true, dimension); + dimensionPadding[i] = padding; } } } -void Actor::Relayouter::NegotiateDimensions(Actor& actor, const Vector2& allocatedSize) +Vector2 ActorSizer::Relayouter::GetPadding(Dimension::Type dimension) { - // Negotiate all dimensions that require it - ActorDimensionStack recursionStack; - + // If more than one dimension is requested, just return the first one found for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) { - const Dimension::Type dimension = static_cast(1 << i); - - // Negotiate - NegotiateDimension(actor, dimension, allocatedSize, recursionStack); - } -} - -void Actor::Relayouter::NegotiateSize(Actor& actor, const Vector2& allocatedSize, RelayoutContainer& container) -{ - // Force a size negotiation for actors that has assigned size during relayout - // This is required as otherwise the flags that force a relayout will not - // necessarilly be set. This will occur if the actor has already been laid out. - // The dirty flags are then cleared. Then if the actor is added back into the - // relayout container afterwards, the dirty flags would still be clear... - // causing a relayout to be skipped. Here we force any actors added to the - // container to be relayed out. - DALI_LOG_TIMER_START(NegSizeTimer1); - - if(actor.GetUseAssignedSize(Dimension::WIDTH)) - { - actor.SetLayoutNegotiated(false, Dimension::WIDTH); - } - if(actor.GetUseAssignedSize(Dimension::HEIGHT)) - { - actor.SetLayoutNegotiated(false, Dimension::HEIGHT); - } - - // Do the negotiation - NegotiateDimensions(actor, allocatedSize); - - // Set the actor size - actor.SetNegotiatedSize(container); - - // Negotiate down to children - for(uint32_t i = 0, count = actor.GetChildCount(); i < count; ++i) - { - ActorPtr child = actor.GetChildAt(i); - - // Forces children that have already been laid out to be relayed out - // if they have assigned size during relayout. - if(child->GetUseAssignedSize(Dimension::WIDTH)) - { - child->SetLayoutNegotiated(false, Dimension::WIDTH); - child->SetLayoutDirty(true, Dimension::WIDTH); - } - - if(child->GetUseAssignedSize(Dimension::HEIGHT)) - { - child->SetLayoutNegotiated(false, Dimension::HEIGHT); - child->SetLayoutDirty(true, Dimension::HEIGHT); - } - - // Only relayout if required - if(child->RelayoutRequired()) + if((dimension & (1 << i))) { - container.Add(Dali::Actor(child.Get()), actor.mTargetSize.GetVectorXY()); + return dimensionPadding[i]; } } - DALI_LOG_TIMER_END(NegSizeTimer1, gLogRelayoutFilter, Debug::Concise, "NegotiateSize() took: "); -} -/** - * @brief Extract a given dimension from a Vector3 - * - * @param[in] values The values to extract from - * @param[in] dimension The dimension to extract - * @return Return the value for the dimension - */ -float Actor::Relayouter::GetDimensionValue(const Vector3& values, const Dimension::Type dimension) -{ - return ::GetDimensionValue(values.GetVectorXY(), dimension); + return DEFAULT_DIMENSION_PADDING; } -float Actor::Relayouter::CalculateSize(Actor& actor, Dimension::Type dimension, const Vector2& maximumSize) +void ActorSizer::Relayouter::SetLayoutNegotiated(bool negotiated, Dimension::Type dimension) { - switch(actor.GetResizePolicy(dimension)) + for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) { - case ResizePolicy::USE_NATURAL_SIZE: - { - return actor.GetNaturalSize(dimension); - } - - case ResizePolicy::FIXED: - { - return ::GetDimensionValue(actor.GetPreferredSize(), dimension); - } - - case ResizePolicy::USE_ASSIGNED_SIZE: - { - return ::GetDimensionValue(maximumSize, dimension); - } - - case ResizePolicy::FILL_TO_PARENT: - case ResizePolicy::SIZE_RELATIVE_TO_PARENT: - case ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT: - { - return NegotiateDimensionFromParent(actor, dimension); - } - - case ResizePolicy::FIT_TO_CHILDREN: - { - return NegotiateDimensionFromChildren(actor, dimension); - } - - case ResizePolicy::DIMENSION_DEPENDENCY: - { - const Dimension::Type dimensionDependency = actor.GetDimensionDependency(dimension); - - // Custom rules - if(dimension == Dimension::WIDTH && dimensionDependency == Dimension::HEIGHT) - { - return actor.GetWidthForHeight(actor.GetNegotiatedDimension(Dimension::HEIGHT)); - } - - if(dimension == Dimension::HEIGHT && dimensionDependency == Dimension::WIDTH) - { - return actor.GetHeightForWidth(actor.GetNegotiatedDimension(Dimension::WIDTH)); - } - - break; - } - - default: + if(dimension & (1 << i)) { - break; + dimensionNegotiated[i] = negotiated; } } - - return 0.0f; // Default } -float Actor::Relayouter::CalculateChildSize(Actor& actor, const Actor& child, Dimension::Type dimension) +bool ActorSizer::Relayouter::IsLayoutNegotiated(Dimension::Type dimension) const { - // Fill to parent, taking size mode factor into account - switch(child.GetResizePolicy(dimension)) + for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) { - case ResizePolicy::FILL_TO_PARENT: - { - return actor.GetLatestSize(dimension); - } - - case ResizePolicy::SIZE_RELATIVE_TO_PARENT: - { - Property::Value value = child.GetProperty(Dali::Actor::Property::SIZE_MODE_FACTOR); - Vector3 childSizeModeFactor = value.Get(); - return actor.GetLatestSize(dimension) * GetDimensionValue(childSizeModeFactor, dimension); - } - - case ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT: - { - Property::Value value = child.GetProperty(Dali::Actor::Property::SIZE_MODE_FACTOR); - Vector3 childSizeModeFactor = value.Get(); - return actor.GetLatestSize(dimension) + GetDimensionValue(childSizeModeFactor, dimension); - } - - default: + if((dimension & (1 << i)) && dimensionNegotiated[i]) { - return actor.GetLatestSize(dimension); + return true; } } + return false; } } // namespace Internal diff --git a/dali/internal/event/actors/actor-relayouter.h b/dali/internal/event/actors/actor-relayouter.h index 40c4911..f1ade33 100644 --- a/dali/internal/event/actors/actor-relayouter.h +++ b/dali/internal/event/actors/actor-relayouter.h @@ -20,6 +20,7 @@ // INTERNAL INCLUDES #include + #include #include @@ -30,7 +31,7 @@ namespace Internal /** * Struct to do some actor specific relayouting and store related variables */ -struct Actor::Relayouter +struct ActorSizer::Relayouter { // Defaults static constexpr Vector3 DEFAULT_SIZE_MODE_FACTOR{1.0f, 1.0f, 1.0f}; @@ -47,18 +48,6 @@ struct Actor::Relayouter /// @copydoc Actor::GetResizePolicy ResizePolicy::Type GetResizePolicy(Dimension::Type dimension) const; - /// @copydoc Actor::SetPadding - void SetPadding(const Vector2& padding, Dimension::Type dimension); - - /// @copydoc Actor::GetPadding - Vector2 GetPadding(Dimension::Type dimension); - - /// @copydoc Actor::SetLayoutNegotiated - void SetLayoutNegotiated(bool negotiated, Dimension::Type dimension); - - /// @copydoc Actor::IsLayoutNegotiated - bool IsLayoutNegotiated(Dimension::Type dimension) const; - /// @copydoc Actor::ApplySizeSetPolicy Vector2 ApplySizeSetPolicy(Internal::Actor& actor, const Vector2& size); @@ -104,95 +93,23 @@ struct Actor::Relayouter /// @copydoc Actor::IsLayoutDirty bool IsLayoutDirty(Dimension::Type dimension) const; - /// @copydoc Actor::SetPreferredSize - /// @actor[in] actor The Actor whose preferred size we wish to set - void SetPreferredSize(Actor& actor, const Vector2& size); - - /** - * @brief Clamp a dimension given the relayout constraints on given actor - * - * @param[in] actor The actor to clamp - * @param[in] size The size to constrain - * @param[in] dimension The dimension the size exists in - * @return Return the clamped size - */ - static float ClampDimension(const Internal::Actor& actor, float size, Dimension::Type dimension); - /// @copydoc Actor::SetNegotiatedDimension void SetNegotiatedDimension(float negotiatedDimension, Dimension::Type dimension); /// @copydoc Actor::GetNegotiatedDimension float GetNegotiatedDimension(Dimension::Type dimension); - /** - * Negotiate a dimension based on the size of the parent - * - * @param[in] dimension The dimension to negotiate on - * @return Return the negotiated size - */ - static float NegotiateDimensionFromParent(Actor& actor, Dimension::Type dimension); - - /** - * @brief Negotiate a dimension based on the size of the children - * - * @param[in] dimension The dimension to negotiate on - * @return Return the negotiated size - */ - static float NegotiateDimensionFromChildren(Actor& actor, Dimension::Type dimension); - - /** - * Negotiate size for a specific dimension - * - * The algorithm adopts a recursive dependency checking approach. Meaning, that wherever dependencies - * are found, e.g. an actor dependent on its parent, the dependency will be calculated first with NegotiatedDimension and - * LayoutDimensionNegotiated flags being filled in on the actor. - * - * @post All actors that exist in the dependency chain connected to the given actor will have had their NegotiatedDimensions - * calculated and set as well as the LayoutDimensionNegotiated flags. - * - * @param[in] actor The actor whose dimension we are negotiating - * @param[in] dimension The dimension to negotiate on - * @param[in] allocatedSize The size constraint that the actor must respect - */ - static void NegotiateDimension(Actor& actor, Dimension::Type dimension, const Vector2& allocatedSize, Actor::ActorDimensionStack& recursionStack); - - /** - * Negotiate sizes for a control in all dimensions - * - * @param[in] actor The actor whose dimensions we are negotiating - * @param[in] allocatedSize The size constraint that the control must respect - */ - static void NegotiateDimensions(Actor& actor, const Vector2& allocatedSize); - - /** - * @brief Called by the RelayoutController to negotiate the size of an actor. - * - * The size allocated by the the algorithm is passed in which the - * actor must adhere to. A container is passed in as well which - * the actor should populate with actors it has not / or does not - * need to handle in its size negotiation. - * - * @param[in] actor The actor whose size we are negotiating - * @param[in] size The allocated size. - * @param[in,out] container The container that holds actors that are fed back into the - * RelayoutController algorithm. - */ - static void NegotiateSize(Actor& actor, const Vector2& allocatedSize, RelayoutContainer& container); - - /** - * Get the value for the given dimension - * - * @param[in] values The vector to get values from - * @param[in] dimension The dimension to fetch - * @return the value of the given dimension - */ - static float GetDimensionValue(const Vector3& values, const Dimension::Type dimension); - - /// @copydoc Actor::CalculateSize - static float CalculateSize(Actor& actor, Dimension::Type dimension, const Vector2& maximumSize); - - /// @copydoc Actor::CalculateChildSizeBase - static float CalculateChildSize(Actor& actor, const Actor& child, Dimension::Type dimension); + /// @copydoc Actor::SetPadding + void SetPadding(const Vector2& padding, Dimension::Type dimension); + + /// @copydoc Actor::GetPadding + Vector2 GetPadding(Dimension::Type dimension); + + /// @copydoc Actor::SetLayoutNegotiated + void SetLayoutNegotiated(bool negotiated, Dimension::Type dimension); + + /// @copydoc Actor::IsLayoutNegotiated + bool IsLayoutNegotiated(Dimension::Type dimension) const; public: ResizePolicy::Type resizePolicies[Dimension::DIMENSION_COUNT]; ///< Resize policies diff --git a/dali/internal/event/actors/actor-sizer.cpp b/dali/internal/event/actors/actor-sizer.cpp new file mode 100644 index 0000000..d5c00ea --- /dev/null +++ b/dali/internal/event/actors/actor-sizer.cpp @@ -0,0 +1,868 @@ +/* + * Copyright (c) 2021 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// CLASS HEADER +#include + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(DEBUG_ENABLED) +extern Debug::Filter* gLogRelayoutFilter; +#endif + +namespace +{ +/** + * @brief Extract a given dimension from a Vector2 + * + * @param[in] values The values to extract from + * @param[in] dimension The dimension to extract + * @return Return the value for the dimension + */ +constexpr float GetDimensionValue(const Dali::Vector2& values, const Dali::Dimension::Type dimension) +{ + switch(dimension) + { + case Dali::Dimension::WIDTH: + { + return values.width; + } + case Dali::Dimension::HEIGHT: + { + return values.height; + } + default: + { + break; + } + } + return 0.0f; +} +} // namespace + +namespace Dali::Internal +{ +ActorSizer::ActorSizer(Internal::Actor& owner) +: mOwner(owner), + mRelayoutData(nullptr), + mTargetSize(Vector3::ZERO), + mAnimatedSize(Vector3::ZERO), + mUseAnimatedSize(AnimatedSizeFlag::CLEAR), + mInsideOnSizeSet(false) +{ +} + +ActorSizer::~ActorSizer() +{ + // Delete optional relayout data + delete mRelayoutData; +} + +void ActorSizer::SetSizeModeFactor(const Vector3& factor) +{ + EnsureRelayouter(); + + mRelayoutData->sizeModeFactor = factor; +} +const Vector3& ActorSizer::GetSizeModeFactor() const +{ + return mRelayoutData ? mRelayoutData->sizeModeFactor : Relayouter::DEFAULT_SIZE_MODE_FACTOR; +} + +void ActorSizer::SetSize(const Vector3& size) +{ + if(IsRelayoutEnabled() && !mRelayoutData->insideRelayout) + { + // TODO we cannot just ignore the given Z but that means rewrite the size negotiation!! + SetPreferredSize(size.GetVectorXY()); + } + else + { + SetSizeInternal(size); + } +} + +void ActorSizer::SetSizeInternal(const Vector3& size) +{ + // dont allow recursive loop + DALI_ASSERT_ALWAYS(!mInsideOnSizeSet && "Cannot call SetSize from OnSizeSet"); + // check that we have a node AND the new size width, height or depth is at least a little bit different from the old one + Vector3 currentSize = mOwner.GetCurrentSize(); + + if((fabsf(mTargetSize.width - size.width) > Math::MACHINE_EPSILON_1) || + (fabsf(mTargetSize.height - size.height) > Math::MACHINE_EPSILON_1) || + (fabsf(mTargetSize.depth - size.depth) > Math::MACHINE_EPSILON_1) || + (fabsf(mTargetSize.width - currentSize.width) > Math::MACHINE_EPSILON_1) || + (fabsf(mTargetSize.height - currentSize.height) > Math::MACHINE_EPSILON_1) || + (fabsf(mTargetSize.depth - currentSize.depth) > Math::MACHINE_EPSILON_1)) + { + mTargetSize = size; + + // Update the preferred size after relayoutting + // It should be used in the next relayoutting + if(mUseAnimatedSize & AnimatedSizeFlag::WIDTH && mRelayoutData) + { + mRelayoutData->preferredSize.width = mAnimatedSize.width; + } + + if(mUseAnimatedSize & AnimatedSizeFlag::HEIGHT && mRelayoutData) + { + mRelayoutData->preferredSize.height = mAnimatedSize.height; + } + + // node is being used in a separate thread; queue a message to set the value & base value + auto& node = mOwner.GetNode(); + SceneGraph::NodeTransformPropertyMessage::Send(mOwner.GetEventThreadServices(), &node, &node.mSize, &SceneGraph::TransformManagerPropertyHandler::Bake, mTargetSize); + + // Notification for derived classes + mInsideOnSizeSet = true; + mOwner.OnSizeSet(mTargetSize); + mInsideOnSizeSet = false; + + // Raise a relayout request if the flag is not locked + if(mRelayoutData && !mRelayoutData->insideRelayout) + { + RelayoutRequest(); + } + } +} + +void ActorSizer::SetWidth(float width) +{ + if(IsRelayoutEnabled() && !mRelayoutData->insideRelayout) + { + SetResizePolicy(ResizePolicy::FIXED, Dimension::WIDTH); + mRelayoutData->preferredSize.width = width; + } + else + { + mTargetSize.width = width; + + // node is being used in a separate thread; queue a message to set the value & base value + auto& node = mOwner.GetNode(); + SceneGraph::NodeTransformComponentMessage::Send(mOwner.GetEventThreadServices(), &node, &node.mSize, &SceneGraph::TransformManagerPropertyHandler::BakeX, width); + } + + mUseAnimatedSize &= ~AnimatedSizeFlag::WIDTH; + RelayoutRequest(); +} + +void ActorSizer::SetHeight(float height) +{ + if(IsRelayoutEnabled() && !mRelayoutData->insideRelayout) + { + SetResizePolicy(ResizePolicy::FIXED, Dimension::HEIGHT); + mRelayoutData->preferredSize.height = height; + } + else + { + mTargetSize.height = height; + + // node is being used in a separate thread; queue a message to set the value & base value + auto& node = mOwner.GetNode(); + SceneGraph::NodeTransformComponentMessage::Send(mOwner.GetEventThreadServices(), &node, &node.mSize, &SceneGraph::TransformManagerPropertyHandler::BakeY, height); + } + + mUseAnimatedSize &= ~AnimatedSizeFlag::HEIGHT; + RelayoutRequest(); +} + +void ActorSizer::SetDepth(float depth) +{ + mTargetSize.depth = depth; + + mUseAnimatedSize &= ~AnimatedSizeFlag::DEPTH; + + // node is being used in a separate thread; queue a message to set the value & base value + auto& node = mOwner.GetNode(); + SceneGraph::NodeTransformComponentMessage::Send(mOwner.GetEventThreadServices(), &node, &node.mSize, &SceneGraph::TransformManagerPropertyHandler::BakeZ, depth); +} + +Vector3 ActorSizer::GetTargetSize() const +{ + Vector3 size = mTargetSize; + + if(mUseAnimatedSize & AnimatedSizeFlag::WIDTH) + { + // Should return animated size if size is animated + size.width = mAnimatedSize.width; + } + else + { + // Should return preferred size if size is fixed as set by SetSize + if(GetResizePolicy(Dimension::WIDTH) == ResizePolicy::FIXED) + { + size.width = GetPreferredSize().width; + } + } + + if(mUseAnimatedSize & AnimatedSizeFlag::HEIGHT) + { + size.height = mAnimatedSize.height; + } + else + { + if(GetResizePolicy(Dimension::HEIGHT) == ResizePolicy::FIXED) + { + size.height = GetPreferredSize().height; + } + } + + if(mUseAnimatedSize & AnimatedSizeFlag::DEPTH) + { + size.depth = mAnimatedSize.depth; + } + + return size; +} + +void ActorSizer::SetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension) +{ + EnsureRelayouter().SetResizePolicy(policy, dimension, mTargetSize); + mOwner.OnSetResizePolicy(policy, dimension); + RelayoutRequest(); +} + +ResizePolicy::Type ActorSizer::GetResizePolicy(Dimension::Type dimension) const +{ + return mRelayoutData ? mRelayoutData->GetResizePolicy(dimension) : ResizePolicy::DEFAULT; +} + +void ActorSizer::SetSizeScalePolicy(SizeScalePolicy::Type policy) +{ + EnsureRelayouter(); + mRelayoutData->sizeSetPolicy = policy; + RelayoutRequest(); +} + +SizeScalePolicy::Type ActorSizer::GetSizeScalePolicy() const +{ + return mRelayoutData ? mRelayoutData->sizeSetPolicy : Relayouter::DEFAULT_SIZE_SCALE_POLICY; +} + +Dimension::Type ActorSizer::GetDimensionDependency(Dimension::Type dimension) const +{ + return mRelayoutData ? mRelayoutData->GetDimensionDependency(dimension) : Dimension::ALL_DIMENSIONS; +} + +void ActorSizer::SetRelayoutEnabled(bool relayoutEnabled) +{ + // If relayout data has not been allocated yet and the client is requesting + // to disable it, do nothing + if(mRelayoutData || relayoutEnabled) + { + EnsureRelayouter(); + + DALI_ASSERT_DEBUG(mRelayoutData && "mRelayoutData not created"); + + mRelayoutData->relayoutEnabled = relayoutEnabled; + } +} + +bool ActorSizer::IsRelayoutEnabled() const +{ + // Assume that if relayout data has not been allocated yet then relayout is disabled + return mRelayoutData && mRelayoutData->relayoutEnabled; +} + +void ActorSizer::SetLayoutDirty(bool dirty, Dimension::Type dimension) +{ + EnsureRelayouter().SetLayoutDirty(dirty, dimension); +} + +bool ActorSizer::IsLayoutDirty(Dimension::Type dimension) const +{ + return mRelayoutData && mRelayoutData->IsLayoutDirty(dimension); +} + +bool ActorSizer::RelayoutPossible(Dimension::Type dimension) const +{ + return mRelayoutData && mRelayoutData->relayoutEnabled && !IsLayoutDirty(dimension); +} + +bool ActorSizer::RelayoutRequired(Dimension::Type dimension) const +{ + return mRelayoutData && mRelayoutData->relayoutEnabled && IsLayoutDirty(dimension); +} + +ActorSizer::Relayouter& ActorSizer::EnsureRelayouter() +{ + // Assign relayouter + if(!mRelayoutData) + { + mRelayoutData = new Relayouter(); + } + + return *mRelayoutData; +} + +bool ActorSizer::RelayoutDependentOnParent(Dimension::Type dimension) +{ + return mRelayoutData && mRelayoutData->GetRelayoutDependentOnParent(dimension); +} + +bool ActorSizer::RelayoutDependentOnChildrenBase(Dimension::Type dimension) +{ + return mRelayoutData && mRelayoutData->GetRelayoutDependentOnChildren(dimension); +} + +bool ActorSizer::RelayoutDependentOnDimension(Dimension::Type dimension, Dimension::Type dependentDimension) +{ + return mRelayoutData && mRelayoutData->GetRelayoutDependentOnDimension(dimension, dependentDimension); +} + +void ActorSizer::SetNegotiatedDimension(float negotiatedDimension, Dimension::Type dimension) +{ + if(mRelayoutData) + { + mRelayoutData->SetNegotiatedDimension(negotiatedDimension, dimension); + } +} + +float ActorSizer::GetNegotiatedDimension(Dimension::Type dimension) const +{ + return mRelayoutData ? mRelayoutData->GetNegotiatedDimension(dimension) : 0.0f; +} + +void ActorSizer::SetPadding(const Vector2& padding, Dimension::Type dimension) +{ + EnsureRelayouter().SetPadding(padding, dimension); +} + +Vector2 ActorSizer::GetPadding(Dimension::Type dimension) const +{ + return mRelayoutData ? mRelayoutData->GetPadding(dimension) : Relayouter::DEFAULT_DIMENSION_PADDING; +} + +void ActorSizer::SetLayoutNegotiated(bool negotiated, Dimension::Type dimension) +{ + EnsureRelayouter().SetLayoutNegotiated(negotiated, dimension); +} + +bool ActorSizer::IsLayoutNegotiated(Dimension::Type dimension) const +{ + return mRelayoutData && mRelayoutData->IsLayoutNegotiated(dimension); +} + +float ActorSizer::GetHeightForWidthBase(float width) +{ + const Vector3 naturalSize = mOwner.GetNaturalSize(); + return naturalSize.width > 0.0f ? naturalSize.height * width / naturalSize.width : width; +} + +float ActorSizer::GetWidthForHeightBase(float height) +{ + const Vector3 naturalSize = mOwner.GetNaturalSize(); + return naturalSize.height > 0.0f ? naturalSize.width * height / naturalSize.height : height; +} + +float ActorSizer::CalculateChildSizeBase(const Dali::Actor& child, Dimension::Type dimension) +{ + // Fill to parent, taking size mode factor into account + switch(child.GetResizePolicy(dimension)) + { + case ResizePolicy::FILL_TO_PARENT: + { + return GetLatestSize(dimension); + } + + case ResizePolicy::SIZE_RELATIVE_TO_PARENT: + { + Property::Value value = child.GetProperty(Dali::Actor::Property::SIZE_MODE_FACTOR); + Vector3 childSizeModeFactor = value.Get(); + return GetLatestSize(dimension) * GetDimensionValue(childSizeModeFactor, dimension); + } + + case ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT: + { + Property::Value value = child.GetProperty(Dali::Actor::Property::SIZE_MODE_FACTOR); + Vector3 childSizeModeFactor = value.Get(); + return GetLatestSize(dimension) + GetDimensionValue(childSizeModeFactor, dimension); + } + + default: + { + return GetLatestSize(dimension); + } + } +} + +float ActorSizer::GetLatestSize(Dimension::Type dimension) const +{ + return IsLayoutNegotiated(dimension) ? GetNegotiatedDimension(dimension) : GetSize(dimension); +} + +float ActorSizer::GetRelayoutSize(Dimension::Type dimension) const +{ + Vector2 padding = GetPadding(dimension); + + return GetLatestSize(dimension) + padding.x + padding.y; +} + +float ActorSizer::NegotiateFromParent(Dimension::Type dimension) +{ + Actor* parent = mOwner.GetParent(); + if(parent) + { + Vector2 padding(GetPadding(dimension)); + Vector2 parentPadding(parent->mSizer.GetPadding(dimension)); + + // Need to use actor API here to allow deriving actors to layout their children + return parent->CalculateChildSize(Dali::Actor(&mOwner), dimension) - parentPadding.x - parentPadding.y - padding.x - padding.y; + } + + return 0.0f; +} + +float ActorSizer::NegotiateFromChildren(Dimension::Type dimension) +{ + float maxDimensionPoint = 0.0f; + + for(uint32_t i = 0, count = mOwner.GetChildCount(); i < count; ++i) + { + ActorPtr child = mOwner.GetChildAt(i); + + if(!child->RelayoutDependentOnParent(dimension)) + { + // Calculate the min and max points that the children range across + float childPosition = GetDimensionValue(child->GetTargetPosition(), dimension); + float dimensionSize = child->mSizer.GetRelayoutSize(dimension); + maxDimensionPoint = std::max(maxDimensionPoint, childPosition + dimensionSize); + } + } + + return maxDimensionPoint; +} + +float ActorSizer::GetSize(Dimension::Type dimension) const +{ + return GetDimensionValue(mTargetSize, dimension); +} + +float ActorSizer::GetNaturalSize(Dimension::Type dimension) const +{ + return GetDimensionValue(mOwner.GetNaturalSize(), dimension); +} + +Vector2 ActorSizer::ApplySizeSetPolicy(const Vector2& size) +{ + return mRelayoutData->ApplySizeSetPolicy(mOwner, size); +} + +void ActorSizer::SetNegotiatedSize(RelayoutContainer& container) +{ + // Do the set actor size + Vector2 negotiatedSize(GetLatestSize(Dimension::WIDTH), GetLatestSize(Dimension::HEIGHT)); + + // Adjust for size set policy + negotiatedSize = ApplySizeSetPolicy(negotiatedSize); + + // Lock the flag to stop recursive relayouts on set size + mRelayoutData->insideRelayout = true; + SetSize(Vector3(negotiatedSize.width, negotiatedSize.height, 0.0f)); + mRelayoutData->insideRelayout = false; + + // Clear flags for all dimensions + SetLayoutDirty(false); + + // Give deriving classes a chance to respond + mOwner.OnRelayout(negotiatedSize, container); + + if(!mOwner.mOnRelayoutSignal.Empty()) + { + Dali::Actor handle(&mOwner); + mOwner.mOnRelayoutSignal.Emit(handle); + } + + mRelayoutData->relayoutRequested = false; +} + +void ActorSizer::NegotiateSize(const Vector2& allocatedSize, RelayoutContainer& container) +{ + // Force a size negotiation for actors that has assigned size during relayout + // This is required as otherwise the flags that force a relayout will not + // necessarilly be set. This will occur if the actor has already been laid out. + // The dirty flags are then cleared. Then if the actor is added back into the + // relayout container afterwards, the dirty flags would still be clear... + // causing a relayout to be skipped. Here we force any actors added to the + // container to be relayed out. + DALI_LOG_TIMER_START(NegSizeTimer1); + + if(GetUseAssignedSize(Dimension::WIDTH)) + { + SetLayoutNegotiated(false, Dimension::WIDTH); + } + if(GetUseAssignedSize(Dimension::HEIGHT)) + { + SetLayoutNegotiated(false, Dimension::HEIGHT); + } + + // Do the negotiation + NegotiateDimensions(allocatedSize); + + // Set the actor size + SetNegotiatedSize(container); + + // Negotiate down to children + for(uint32_t i = 0, count = mOwner.GetChildCount(); i < count; ++i) + { + ActorPtr child = mOwner.GetChildAt(i); + ActorSizer& childSizer = child->mSizer; + + // Forces children that have already been laid out to be relayed out + // if they have assigned size during relayout. + if(childSizer.GetUseAssignedSize(Dimension::WIDTH)) + { + childSizer.SetLayoutNegotiated(false, Dimension::WIDTH); + childSizer.SetLayoutDirty(true, Dimension::WIDTH); + } + + if(childSizer.GetUseAssignedSize(Dimension::HEIGHT)) + { + childSizer.SetLayoutNegotiated(false, Dimension::HEIGHT); + childSizer.SetLayoutDirty(true, Dimension::HEIGHT); + } + + // Only relayout if required + if(childSizer.RelayoutRequired()) + { + container.Add(Dali::Actor(child.Get()), mTargetSize.GetVectorXY()); + } + } + + // Reset the flag so that size negotiation will respect the actor's original resize policy + SetUseAssignedSize(false); + DALI_LOG_TIMER_END(NegSizeTimer1, gLogRelayoutFilter, Debug::Concise, "NegotiateSize() took: "); +} + +void ActorSizer::SetUseAssignedSize(bool use, Dimension::Type dimension) +{ + if(mRelayoutData) + { + mRelayoutData->SetUseAssignedSize(use, dimension); + } +} + +bool ActorSizer::GetUseAssignedSize(Dimension::Type dimension) const +{ + return mRelayoutData && mRelayoutData->GetUseAssignedSize(dimension); +} + +void ActorSizer::RelayoutRequest(Dimension::Type dimension) +{ + Internal::RelayoutController* relayoutController = Internal::RelayoutController::Get(); + if(relayoutController) + { + Dali::Actor owner(&mOwner); + relayoutController->RequestRelayout(owner, dimension); + + if(mRelayoutData) + { + mRelayoutData->relayoutRequested = true; + } + } +} + +void ActorSizer::SetPreferredSize(const Vector2& size) +{ + EnsureRelayouter(); + + // If valid width or height, then set the resize policy to FIXED + // A 0 width or height may also be required so if the resize policy has not been changed, i.e. is still set to DEFAULT, + // then change to FIXED as well + + if(size.width > 0.0f || GetResizePolicy(Dimension::WIDTH) == ResizePolicy::DEFAULT) + { + SetResizePolicy(ResizePolicy::FIXED, Dimension::WIDTH); + } + + if(size.height > 0.0f || GetResizePolicy(Dimension::HEIGHT) == ResizePolicy::DEFAULT) + { + SetResizePolicy(ResizePolicy::FIXED, Dimension::HEIGHT); + } + + mRelayoutData->preferredSize = size; + mUseAnimatedSize = AnimatedSizeFlag::CLEAR; + RelayoutRequest(); +} + +Vector2 ActorSizer::GetPreferredSize() const +{ + return mRelayoutData ? Vector2(mRelayoutData->preferredSize) : Relayouter::DEFAULT_PREFERRED_SIZE; +} + +void ActorSizer::SetMinimumSize(float size, Dimension::Type dimension) +{ + EnsureRelayouter().SetMinimumSize(size, dimension); + RelayoutRequest(); +} + +float ActorSizer::GetMinimumSize(Dimension::Type dimension) const +{ + return mRelayoutData ? mRelayoutData->GetMinimumSize(dimension) : 0.0f; +} + +void ActorSizer::SetMaximumSize(float size, Dimension::Type dimension) +{ + EnsureRelayouter().SetMaximumSize(size, dimension); + RelayoutRequest(); +} + +float ActorSizer::GetMaximumSize(Dimension::Type dimension) const +{ + return mRelayoutData ? mRelayoutData->GetMaximumSize(dimension) : FLT_MAX; +} + +void ActorSizer::OnAnimateSize(Animation& animation, Vector3 targetSize, bool relative) +{ + mTargetSize = targetSize + mTargetSize * float(relative); + mAnimatedSize = mTargetSize; + mUseAnimatedSize = AnimatedSizeFlag::WIDTH | AnimatedSizeFlag::HEIGHT | AnimatedSizeFlag::DEPTH; + + if(mRelayoutData && !mRelayoutData->relayoutRequested) + { + mRelayoutData->preferredSize.width = mAnimatedSize.width; + mRelayoutData->preferredSize.height = mAnimatedSize.height; + } + + // Notify deriving classes + mOwner.OnSizeAnimation(animation, mTargetSize); +} + +void ActorSizer::OnAnimateWidth(Animation& animation, float width, bool relative) +{ + mTargetSize.width = width + float(relative) * mTargetSize.width; + mAnimatedSize.width = mTargetSize.width; + mUseAnimatedSize |= AnimatedSizeFlag::WIDTH; + + if(mRelayoutData && !mRelayoutData->relayoutRequested) + { + mRelayoutData->preferredSize.width = mAnimatedSize.width; + } + + // Notify deriving classes + mOwner.OnSizeAnimation(animation, mTargetSize); +} + +void ActorSizer::OnAnimateHeight(Animation& animation, float height, bool relative) +{ + mTargetSize.height = height + float(relative) * mTargetSize.height; + mAnimatedSize.height = mTargetSize.height; + mUseAnimatedSize |= AnimatedSizeFlag::HEIGHT; + + if(mRelayoutData && !mRelayoutData->relayoutRequested) + { + mRelayoutData->preferredSize.height = mAnimatedSize.height; + } + + // Notify deriving classes + mOwner.OnSizeAnimation(animation, mTargetSize); +} + +void ActorSizer::OnAnimateDepth(Animation& animation, float depth, bool relative) +{ + mTargetSize.depth = depth + float(relative) * mTargetSize.depth; + mAnimatedSize.depth = mTargetSize.depth; + mUseAnimatedSize |= AnimatedSizeFlag::DEPTH; + + // Notify deriving classes + mOwner.OnSizeAnimation(animation, mTargetSize); +} + +/** + * @brief Extract a given dimension from a Vector3 + * + * @param[in] values The values to extract from + * @param[in] dimension The dimension to extract + * @return Return the value for the dimension + */ +float ActorSizer::GetDimensionValue(const Vector3& values, const Dimension::Type dimension) const +{ + return ::GetDimensionValue(values.GetVectorXY(), dimension); +} + +float ActorSizer::ClampDimension(float size, Dimension::Type dimension) const +{ + const float minSize = GetMinimumSize(dimension); + const float maxSize = GetMaximumSize(dimension); + + return std::max(minSize, std::min(size, maxSize)); +} + +void ActorSizer::NegotiateDimension(Dimension::Type dimension, const Vector2& allocatedSize, ActorDimensionStack& recursionStack) +{ + // Check if it needs to be negotiated + if(IsLayoutDirty(dimension) && !IsLayoutNegotiated(dimension)) + { + // Check that we havn't gotten into an infinite loop + ActorDimensionPair searchActor = ActorDimensionPair(&mOwner, dimension); + bool recursionFound = false; + for(auto& element : recursionStack) + { + if(element == searchActor) + { + recursionFound = true; + break; + } + } + + if(!recursionFound) + { + // Record the path that we have taken + recursionStack.push_back(ActorDimensionPair(&mOwner, dimension)); + + // Dimension dependency check + for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) + { + Dimension::Type dimensionToCheck = static_cast(1 << i); + + if(RelayoutDependentOnDimension(dimension, dimensionToCheck)) + { + NegotiateDimension(dimensionToCheck, allocatedSize, recursionStack); + } + } + + // Parent dependency check + Actor* parent = mOwner.GetParent(); + if(parent && RelayoutDependentOnParent(dimension)) + { + parent->mSizer.NegotiateDimension(dimension, allocatedSize, recursionStack); + } + + // Children dependency check + if(mOwner.RelayoutDependentOnChildren(dimension)) + { + for(uint32_t i = 0, count = mOwner.GetChildCount(); i < count; ++i) + { + ActorPtr child = mOwner.GetChildAt(i); + + // Only relayout child first if it is not dependent on this actor + if(!child->RelayoutDependentOnParent(dimension)) + { + child->mSizer.NegotiateDimension(dimension, allocatedSize, recursionStack); + } + } + } + + // For deriving classes + mOwner.OnCalculateRelayoutSize(dimension); + + // All dependencies checked, calculate the size and set negotiated flag + const float newSize = ClampDimension(CalculateSize(dimension, allocatedSize), dimension); + + SetNegotiatedDimension(newSize, dimension); + SetLayoutNegotiated(true, dimension); + + // For deriving classes + mOwner.OnLayoutNegotiated(newSize, dimension); + + // This actor has been successfully processed, pop it off the recursion stack + recursionStack.pop_back(); + } + else + { + // TODO: Break infinite loop + SetLayoutNegotiated(true, dimension); + } + } +} + +void ActorSizer::NegotiateDimensions(const Vector2& allocatedSize) +{ + // Negotiate all dimensions that require it + ActorDimensionStack recursionStack; + + for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i) + { + const Dimension::Type dimension = static_cast(1 << i); + + // Negotiate + NegotiateDimension(dimension, allocatedSize, recursionStack); + } +} + +float ActorSizer::CalculateSize(Dimension::Type dimension, const Vector2& maximumSize) +{ + switch(GetResizePolicy(dimension)) + { + case ResizePolicy::USE_NATURAL_SIZE: + { + return GetNaturalSize(dimension); + } + + case ResizePolicy::FIXED: + { + return ::GetDimensionValue(GetPreferredSize(), dimension); + } + + case ResizePolicy::USE_ASSIGNED_SIZE: + { + return ::GetDimensionValue(maximumSize, dimension); + } + + case ResizePolicy::FILL_TO_PARENT: + case ResizePolicy::SIZE_RELATIVE_TO_PARENT: + case ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT: + { + return NegotiateFromParent(dimension); + } + + case ResizePolicy::FIT_TO_CHILDREN: + { + return NegotiateFromChildren(dimension); + } + + case ResizePolicy::DIMENSION_DEPENDENCY: + { + const Dimension::Type dimensionDependency = GetDimensionDependency(dimension); + + // Custom rules + if(dimension == Dimension::WIDTH && dimensionDependency == Dimension::HEIGHT) + { + // Use actor API to allow deriving actors to layout their content + return mOwner.GetWidthForHeight(GetNegotiatedDimension(Dimension::HEIGHT)); + } + + if(dimension == Dimension::HEIGHT && dimensionDependency == Dimension::WIDTH) + { + // Use actor API to allow deriving actors to layout their content + return mOwner.GetHeightForWidth(GetNegotiatedDimension(Dimension::WIDTH)); + } + + break; + } + + default: + { + break; + } + } + + return 0.0f; // Default +} + +} // namespace Dali::Internal diff --git a/dali/internal/event/actors/actor-sizer.h b/dali/internal/event/actors/actor-sizer.h new file mode 100644 index 0000000..2149694 --- /dev/null +++ b/dali/internal/event/actors/actor-sizer.h @@ -0,0 +1,368 @@ +#ifndef DALI_INTERNAL_ACTOR_SIZER_H +#define DALI_INTERNAL_ACTOR_SIZER_H + +/* + * Copyright (c) 2021 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace Dali::Internal +{ +class Actor; +class Animation; + +/** + * Class to handle sizing of actor. Uses size negotiation and animation. + */ +class ActorSizer +{ +public: + struct AnimatedSizeFlag + { + enum Type + { + CLEAR = 0, + WIDTH = 1, + HEIGHT = 2, + DEPTH = 4 + }; + }; + + /** + * @brief Struct to hold an actor and a dimension + */ + struct ActorDimensionPair + { + /** + * @brief Constructor + * + * @param[in] newActor The actor to assign + * @param[in] newDimension The dimension to assign + */ + ActorDimensionPair(Actor* newActor, Dimension::Type newDimension) + : actor(newActor), + dimension(newDimension) + { + } + + /** + * @brief Equality operator + * + * @param[in] lhs The left hand side argument + * @param[in] rhs The right hand side argument + */ + bool operator==(const ActorDimensionPair& rhs) + { + return (actor == rhs.actor) && (dimension == rhs.dimension); + } + + Actor* actor; ///< The actor to hold + Dimension::Type dimension; ///< The dimension to hold + }; + + using ActorDimensionStack = std::vector; + +public: + /// Constructor + ActorSizer(Internal::Actor& owner); + + /// Destructor + ~ActorSizer(); + + // Remove default constructor, copy constructor and assignment operator + ActorSizer() = delete; + ActorSizer(const ActorSizer&) = delete; + ActorSizer& operator=(const ActorSizer) = delete; + + ///@copydoc Actor::SetSizerModeFactor + void SetSizeModeFactor(const Vector3& factor); + + ///@copydoc Actor:: + const Vector3& GetSizeModeFactor() const; + + ///@copydoc Actor::SetSize + void SetSize(const Vector3& size); + + ///@ Set the target size / preferred size + void SetSizeInternal(const Vector3& size); + + ///@copydoc Actor::SetWidth + void SetWidth(float width); + + ///@copydoc Actor::SetHeight + void SetHeight(float height); + + ///@copydoc Actor::SetDepth + void SetDepth(float depth); + + ///@copydoc Actor::GetTargetSize + Vector3 GetTargetSize() const; + + ///@copydoc Actor::SetResizePolicy + void SetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension = Dimension::ALL_DIMENSIONS); + + ///@copydoc Actor:::Type + ResizePolicy::Type GetResizePolicy(Dimension::Type dimension) const; + + ///@copydoc Actor::SetSizeScalePolicy + void SetSizeScalePolicy(SizeScalePolicy::Type policy); + + ///@copydoc Actor:::GetSizeScalePolicy + SizeScalePolicy::Type GetSizeScalePolicy() const; + + ///@copydoc Actor::SetDimensionDependency + void SetDimensionDependency(Dimension::Type dimension, Dimension::Type dependency); + + ///@copydoc Actor::GetDimensionDependency + Dimension::Type GetDimensionDependency(Dimension::Type dimension) const; + + ///@copydoc Actor::SetRelayoutEnabled + void SetRelayoutEnabled(bool relayoutEnabled); + + ///@copydoc Actor::IsRelayoutEnabled + bool IsRelayoutEnabled() const; + + ///@copydoc Actor::SetLayoutDirty + void SetLayoutDirty(bool dirty, Dimension::Type dimension = Dimension::ALL_DIMENSIONS); + + ///@copydoc Actor::IsLayoutDirty + bool IsLayoutDirty(Dimension::Type dimension = Dimension::ALL_DIMENSIONS) const; + + ///@copydoc Actor::RelayoutPossible + bool RelayoutPossible(Dimension::Type dimension = Dimension::ALL_DIMENSIONS) const; + + ///@copydoc Actor::RelayoutRequired + bool RelayoutRequired(Dimension::Type dimension = Dimension::ALL_DIMENSIONS) const; + + ///@copydoc Actor::RelayoutDependentOnParent + bool RelayoutDependentOnParent(Dimension::Type dimension = Dimension::ALL_DIMENSIONS); + + ///@copydoc Actor::RelayoutDependentOnChildren + bool RelayoutDependentOnChildrenBase(Dimension::Type dimension = Dimension::ALL_DIMENSIONS); + + ///@copydoc Actor::RelayoutDependentOnDimension + bool RelayoutDependentOnDimension(Dimension::Type dimension, Dimension::Type dependentDimension); + + ///@copydoc Actor::SetNegotiatedDimension + void SetNegotiatedDimension(float negotiatedDimension, Dimension::Type dimension = Dimension::ALL_DIMENSIONS); + + ///@copydoc Actor::GetNegotiatedDimension + float GetNegotiatedDimension(Dimension::Type dimension) const; + + ///@copydoc Actor::SetPadding + void SetPadding(const Vector2& padding, Dimension::Type dimension); + + ///@copydoc Actor::GetPadding + Vector2 GetPadding(Dimension::Type dimension) const; + + ///@copydoc Actor::SetLayoutNegotiated + void SetLayoutNegotiated(bool negotiated, Dimension::Type dimension); + + ///@copydoc Actor::IsLayoutNegotiated + bool IsLayoutNegotiated(Dimension::Type dimension) const; + + ///@copydoc Actor::GetHeightForWidth + float GetHeightForWidthBase(float width); + + ///@copydoc Actor::GetWidthForHeight + float GetWidthForHeightBase(float height); + + ///@copydoc Actor::CalculateChildSize + float CalculateChildSizeBase(const Dali::Actor& child, Dimension::Type dimension); + + ///@copydoc Actor::GetLatestSize + float GetLatestSize(Dimension::Type dimension) const; + + ///@copydoc Actor::GetRelayoutSize + float GetRelayoutSize(Dimension::Type dimension) const; + + ///@copydoc Actor::GetSize + float GetSize(Dimension::Type dimension) const; + + ///@copydoc Actor::GetNaturalSize + float GetNaturalSize(Dimension::Type dimension) const; + + ///@copydoc Actor::ApplySizeSetPolicy + Vector2 ApplySizeSetPolicy(const Vector2& size); + + ///@copydoc Actor::SetNegotiatedSize + void SetNegotiatedSize(RelayoutContainer& container); + + ///@copydoc Actor::NegotiateSize + void NegotiateSize(const Vector2& allocatedSize, RelayoutContainer& container); + + ///@copydoc Actor::RelayoutRequest + void RelayoutRequest(Dimension::Type dimension = Dimension::ALL_DIMENSIONS); + + ///@copydoc Actor::SetMinimumSize + void SetMinimumSize(float size, Dimension::Type dimension = Dimension::ALL_DIMENSIONS); + + ///@copydoc Actor::GetMinimumSize + float GetMinimumSize(Dimension::Type dimension) const; + + ///@copydoc Actor::SetMaximumSize + void SetMaximumSize(float size, Dimension::Type dimension = Dimension::ALL_DIMENSIONS); + + ///@copydoc Actor::GetMaximumSize + float GetMaximumSize(Dimension::Type dimension) const; + + /** + * Update target / preferred / animated size when size animation starts + * @param[in] animation The animation modifying the size + * @param[in] targetSize The new target size + */ + void OnAnimateSize(Animation& animation, Vector3 targetSize, bool relative); + + /** + * Update target / preferred / animated width when size animation starts + * @param[in] animation The animation modifying the width + * @param[in] targetWidth The new target width + */ + void OnAnimateWidth(Animation& animation, float targetWidth, bool relative); + + /** + * Update target / preferred / animated height when size animation starts + * @param[in] animation The animation modifying the height + * @param[in] targetHeight The new target height + */ + void OnAnimateHeight(Animation& animation, float targetHeight, bool relative); + + /** + * Update target / preferred / animated depth when size animation starts + * @param[in] animation The animation modifying the depth + * @param[in] targetDepth The new target depth + */ + void OnAnimateDepth(Animation& animation, float targetDepth, bool relative); + +private: + struct Relayouter; + + /** + * @brief Ensure the relayouter is allocated + */ + Relayouter& EnsureRelayouter(); + + /** + * @brief Extract a given dimension from a Vector3 + * + * @param[in] values The values to extract from + * @param[in] dimension The dimension to extract + * @return Return the value for the dimension + */ + float GetDimensionValue(const Vector3& values, const Dimension::Type dimension) const; + + /** + * @brief Clamp a dimension given the relayout constraints on given actor + * + * @param[in] size The size to constrain + * @param[in] dimension The dimension the size exists in + * @return Return the clamped size + */ + float ClampDimension(float size, Dimension::Type dimension) const; + + /** + * Negotiate a dimension based on the size of the parent + * + * @param[in] dimension The dimension to negotiate on + * @return Return the negotiated size + */ + float NegotiateFromParent(Dimension::Type dimension); + + /** + * @brief Negotiate a dimension based on the size of the children + * + * @param[in] dimension The dimension to negotiate on + * @return Return the negotiated size + */ + float NegotiateFromChildren(Dimension::Type dimension); + + /** + * Negotiate size for a specific dimension + * + * The algorithm adopts a recursive dependency checking approach. Meaning, that wherever dependencies + * are found, e.g. an actor dependent on its parent, the dependency will be calculated first with NegotiatedDimension and + * LayoutDimensionNegotiated flags being filled in on the actor. + * + * @post All actors that exist in the dependency chain connected to the given actor will have had their NegotiatedDimensions + * calculated and set as well as the LayoutDimensionNegotiated flags. + * + * @param[in] dimension The dimension to negotiate on + * @param[in] allocatedSize The size constraint that the actor must respect + */ + void NegotiateDimension(Dimension::Type dimension, const Vector2& allocatedSize, ActorDimensionStack& recursionStack); + + /** + * Negotiate sizes for a control in all dimensions + * + * @param[in] allocatedSize The size constraint that the control must respect + */ + void NegotiateDimensions(const Vector2& allocatedSize); + + /** + * @brief Set whether size negotiation should use the assigned size of the actor + * during relayout for the given dimension(s) + * + * @param[in] use Whether the assigned size of the actor should be used + * @param[in] dimension The dimension(s) to set. Can be a bitfield of multiple dimensions + */ + void SetUseAssignedSize(bool use, Dimension::Type dimension = Dimension::ALL_DIMENSIONS); + + /** + * @brief Returns whether size negotiation should use the assigned size of the actor + * during relayout for a single dimension + * + * @param[in] dimension The dimension to get + * @return Return whether the assigned size of the actor should be used. If more than one dimension is requested, just return the first one found + */ + bool GetUseAssignedSize(Dimension::Type dimension) const; + + /** + * @brief Calculate the size of a dimension + * + * @param[in] dimension The dimension to calculate the size for + * @param[in] maximumSize The upper bounds on the size + * @return Return the calculated size for the dimension + */ + float CalculateSize(Dimension::Type dimension, const Vector2& maximumSize); + + /** + * @brief Set the preferred size for size negotiation + * + * @param[in] size The preferred size to set + */ + void SetPreferredSize(const Vector2& size); + + /** + * @brief Get the preferred size for size negotiation + * + * @return size The preferred size to set + */ + Vector2 GetPreferredSize() const; + +private: + Internal::Actor& mOwner; // Owner of this actor sizer + Relayouter* mRelayoutData; ///< Struct to hold optional collection of relayout variables + Dali::Vector3 mTargetSize; ///< Event-side storage for size (not a pointer as most actors will have a size) + Dali::Vector3 mAnimatedSize; ///< Event-side storage for size animation + uint16_t mUseAnimatedSize; ///< Whether the size is animated. + bool mInsideOnSizeSet : 1; +}; + +} // namespace Dali::Internal + +#endif //DALI_INTERNAL_ACTOR_SIZER_H diff --git a/dali/internal/event/size-negotiation/relayout-controller-impl.cpp b/dali/internal/event/size-negotiation/relayout-controller-impl.cpp index 653b20a..622db16 100644 --- a/dali/internal/event/size-negotiation/relayout-controller-impl.cpp +++ b/dali/internal/event/size-negotiation/relayout-controller-impl.cpp @@ -444,11 +444,7 @@ void RelayoutController::Relayout() // 3. Negotiate the size with the current actor. Pass it an empty container which the actor // has to fill with all the actors it has not done any size negotiation for. - actorImpl.NegotiateSize(size, *mRelayoutStack); - - // Reset the flag so that size negotiation will respect the actor's original resize policy - actorImpl.SetUseAssignedSize(false); } } diff --git a/dali/internal/file.list b/dali/internal/file.list index 9f4ad89..bd014f7 100644 --- a/dali/internal/file.list +++ b/dali/internal/file.list @@ -18,6 +18,7 @@ SET( internal_src_files ${internal_src_dir}/event/actors/actor-renderer-container.cpp ${internal_src_dir}/event/actors/actor-relayouter.cpp ${internal_src_dir}/event/actors/actor-parent-impl.cpp + ${internal_src_dir}/event/actors/actor-sizer.cpp ${internal_src_dir}/event/actors/custom-actor-internal.cpp ${internal_src_dir}/event/actors/layer-impl.cpp ${internal_src_dir}/event/actors/layer-list.cpp