2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <dali/internal/event/actors/actor-sizer.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/internal/event/actors/actor-relayouter.h>
26 #include <dali/internal/event/animation/animation-impl.h>
27 #include <dali/internal/event/size-negotiation/relayout-controller-impl.h>
28 #include <dali/internal/update/manager/update-manager.h>
29 #include <dali/internal/update/nodes/node-declarations.h>
30 #include <dali/internal/update/nodes/node-messages.h>
31 #include <dali/internal/update/nodes/node.h>
33 #if defined(DEBUG_ENABLED)
34 extern Debug::Filter* gLogRelayoutFilter;
40 * @brief Extract a given dimension from a Vector2
42 * @param[in] values The values to extract from
43 * @param[in] dimension The dimension to extract
44 * @return Return the value for the dimension
46 constexpr float GetDimensionValue(const Dali::Vector2& values, const Dali::Dimension::Type dimension)
50 case Dali::Dimension::WIDTH:
54 case Dali::Dimension::HEIGHT:
67 namespace Dali::Internal
69 ActorSizer::ActorSizer(Internal::Actor& owner)
71 mRelayoutData(nullptr),
72 mTargetSize(Vector3::ZERO),
73 mAnimatedSize(Vector3::ZERO),
74 mUseAnimatedSize(AnimatedSizeFlag::CLEAR),
75 mInsideOnSizeSet(false)
79 ActorSizer::~ActorSizer()
81 // Delete optional relayout data
85 void ActorSizer::SetSizeModeFactor(const Vector3& factor)
89 mRelayoutData->sizeModeFactor = factor;
91 const Vector3& ActorSizer::GetSizeModeFactor() const
93 return mRelayoutData ? mRelayoutData->sizeModeFactor : Relayouter::DEFAULT_SIZE_MODE_FACTOR;
96 void ActorSizer::SetSize(const Vector3& size)
98 if(IsRelayoutEnabled() && !mRelayoutData->insideRelayout)
100 // TODO we cannot just ignore the given Z but that means rewrite the size negotiation!!
101 SetPreferredSize(size.GetVectorXY());
105 SetSizeInternal(size);
109 void ActorSizer::SetSizeInternal(const Vector3& size)
111 // dont allow recursive loop
112 DALI_ASSERT_ALWAYS(!mInsideOnSizeSet && "Cannot call SetSize from OnSizeSet");
113 // 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
114 Vector3 currentSize = mOwner.GetCurrentSize();
116 if((fabsf(mTargetSize.width - size.width) > Math::MACHINE_EPSILON_1) ||
117 (fabsf(mTargetSize.height - size.height) > Math::MACHINE_EPSILON_1) ||
118 (fabsf(mTargetSize.depth - size.depth) > Math::MACHINE_EPSILON_1) ||
119 (fabsf(mTargetSize.width - currentSize.width) > Math::MACHINE_EPSILON_1) ||
120 (fabsf(mTargetSize.height - currentSize.height) > Math::MACHINE_EPSILON_1) ||
121 (fabsf(mTargetSize.depth - currentSize.depth) > Math::MACHINE_EPSILON_1))
125 // Update the preferred size after relayoutting
126 // It should be used in the next relayoutting
127 if(mUseAnimatedSize & AnimatedSizeFlag::WIDTH && mRelayoutData)
129 mRelayoutData->preferredSize.width = mAnimatedSize.width;
132 if(mUseAnimatedSize & AnimatedSizeFlag::HEIGHT && mRelayoutData)
134 mRelayoutData->preferredSize.height = mAnimatedSize.height;
137 // node is being used in a separate thread; queue a message to set the value & base value
138 auto& node = mOwner.GetNode();
139 SceneGraph::NodeTransformPropertyMessage<Vector3>::Send(mOwner.GetEventThreadServices(), &node, &node.mSize, &SceneGraph::TransformManagerPropertyHandler<Vector3>::Bake, mTargetSize);
141 // Notification for derived classes
142 mInsideOnSizeSet = true;
143 mOwner.OnSizeSet(mTargetSize);
144 mInsideOnSizeSet = false;
146 // Raise a relayout request if the flag is not locked
147 if(mRelayoutData && !mRelayoutData->insideRelayout)
154 void ActorSizer::SetWidth(float width)
156 if(IsRelayoutEnabled() && !mRelayoutData->insideRelayout)
158 SetResizePolicy(ResizePolicy::FIXED, Dimension::WIDTH);
159 mRelayoutData->preferredSize.width = width;
163 mTargetSize.width = width;
165 // node is being used in a separate thread; queue a message to set the value & base value
166 auto& node = mOwner.GetNode();
167 SceneGraph::NodeTransformComponentMessage<Vector3>::Send(mOwner.GetEventThreadServices(), &node, &node.mSize, &SceneGraph::TransformManagerPropertyHandler<Vector3>::BakeX, width);
170 mUseAnimatedSize &= ~AnimatedSizeFlag::WIDTH;
174 void ActorSizer::SetHeight(float height)
176 if(IsRelayoutEnabled() && !mRelayoutData->insideRelayout)
178 SetResizePolicy(ResizePolicy::FIXED, Dimension::HEIGHT);
179 mRelayoutData->preferredSize.height = height;
183 mTargetSize.height = height;
185 // node is being used in a separate thread; queue a message to set the value & base value
186 auto& node = mOwner.GetNode();
187 SceneGraph::NodeTransformComponentMessage<Vector3>::Send(mOwner.GetEventThreadServices(), &node, &node.mSize, &SceneGraph::TransformManagerPropertyHandler<Vector3>::BakeY, height);
190 mUseAnimatedSize &= ~AnimatedSizeFlag::HEIGHT;
194 void ActorSizer::SetDepth(float depth)
196 mTargetSize.depth = depth;
198 mUseAnimatedSize &= ~AnimatedSizeFlag::DEPTH;
200 // node is being used in a separate thread; queue a message to set the value & base value
201 auto& node = mOwner.GetNode();
202 SceneGraph::NodeTransformComponentMessage<Vector3>::Send(mOwner.GetEventThreadServices(), &node, &node.mSize, &SceneGraph::TransformManagerPropertyHandler<Vector3>::BakeZ, depth);
205 Vector3 ActorSizer::GetTargetSize() const
207 Vector3 size = mTargetSize;
209 if(mUseAnimatedSize & AnimatedSizeFlag::WIDTH)
211 // Should return animated size if size is animated
212 size.width = mAnimatedSize.width;
216 // Should return preferred size if size is fixed as set by SetSize
217 if(GetResizePolicy(Dimension::WIDTH) == ResizePolicy::FIXED)
219 size.width = GetPreferredSize().width;
223 if(mUseAnimatedSize & AnimatedSizeFlag::HEIGHT)
225 size.height = mAnimatedSize.height;
229 if(GetResizePolicy(Dimension::HEIGHT) == ResizePolicy::FIXED)
231 size.height = GetPreferredSize().height;
235 if(mUseAnimatedSize & AnimatedSizeFlag::DEPTH)
237 size.depth = mAnimatedSize.depth;
243 void ActorSizer::SetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension)
245 EnsureRelayouter().SetResizePolicy(policy, dimension, mTargetSize);
246 mOwner.OnSetResizePolicy(policy, dimension);
250 ResizePolicy::Type ActorSizer::GetResizePolicy(Dimension::Type dimension) const
252 return mRelayoutData ? mRelayoutData->GetResizePolicy(dimension) : ResizePolicy::DEFAULT;
255 void ActorSizer::SetSizeScalePolicy(SizeScalePolicy::Type policy)
258 mRelayoutData->sizeSetPolicy = policy;
262 SizeScalePolicy::Type ActorSizer::GetSizeScalePolicy() const
264 return mRelayoutData ? mRelayoutData->sizeSetPolicy : Relayouter::DEFAULT_SIZE_SCALE_POLICY;
267 Dimension::Type ActorSizer::GetDimensionDependency(Dimension::Type dimension) const
269 return mRelayoutData ? mRelayoutData->GetDimensionDependency(dimension) : Dimension::ALL_DIMENSIONS;
272 void ActorSizer::SetRelayoutEnabled(bool relayoutEnabled)
274 // If relayout data has not been allocated yet and the client is requesting
275 // to disable it, do nothing
276 if(mRelayoutData || relayoutEnabled)
280 DALI_ASSERT_DEBUG(mRelayoutData && "mRelayoutData not created");
282 mRelayoutData->relayoutEnabled = relayoutEnabled;
286 bool ActorSizer::IsRelayoutEnabled() const
288 // Assume that if relayout data has not been allocated yet then relayout is disabled
289 return mRelayoutData && mRelayoutData->relayoutEnabled;
292 void ActorSizer::SetLayoutDirty(bool dirty, Dimension::Type dimension)
294 EnsureRelayouter().SetLayoutDirty(dirty, dimension);
297 bool ActorSizer::IsLayoutDirty(Dimension::Type dimension) const
299 return mRelayoutData && mRelayoutData->IsLayoutDirty(dimension);
302 bool ActorSizer::RelayoutPossible(Dimension::Type dimension) const
304 return mRelayoutData && mRelayoutData->relayoutEnabled && !IsLayoutDirty(dimension);
307 bool ActorSizer::RelayoutRequired(Dimension::Type dimension) const
309 return mRelayoutData && mRelayoutData->relayoutEnabled && IsLayoutDirty(dimension);
312 ActorSizer::Relayouter& ActorSizer::EnsureRelayouter()
317 mRelayoutData = new Relayouter();
320 return *mRelayoutData;
323 bool ActorSizer::RelayoutDependentOnParent(Dimension::Type dimension)
325 return mRelayoutData && mRelayoutData->GetRelayoutDependentOnParent(dimension);
328 bool ActorSizer::RelayoutDependentOnChildrenBase(Dimension::Type dimension)
330 return mRelayoutData && mRelayoutData->GetRelayoutDependentOnChildren(dimension);
333 bool ActorSizer::RelayoutDependentOnDimension(Dimension::Type dimension, Dimension::Type dependentDimension)
335 return mRelayoutData && mRelayoutData->GetRelayoutDependentOnDimension(dimension, dependentDimension);
338 void ActorSizer::SetNegotiatedDimension(float negotiatedDimension, Dimension::Type dimension)
342 mRelayoutData->SetNegotiatedDimension(negotiatedDimension, dimension);
346 float ActorSizer::GetNegotiatedDimension(Dimension::Type dimension) const
348 return mRelayoutData ? mRelayoutData->GetNegotiatedDimension(dimension) : 0.0f;
351 void ActorSizer::SetPadding(const Vector2& padding, Dimension::Type dimension)
353 EnsureRelayouter().SetPadding(padding, dimension);
356 Vector2 ActorSizer::GetPadding(Dimension::Type dimension) const
358 return mRelayoutData ? mRelayoutData->GetPadding(dimension) : Relayouter::DEFAULT_DIMENSION_PADDING;
361 void ActorSizer::SetLayoutNegotiated(bool negotiated, Dimension::Type dimension)
363 EnsureRelayouter().SetLayoutNegotiated(negotiated, dimension);
366 bool ActorSizer::IsLayoutNegotiated(Dimension::Type dimension) const
368 return mRelayoutData && mRelayoutData->IsLayoutNegotiated(dimension);
371 float ActorSizer::GetHeightForWidthBase(float width)
373 const Vector3 naturalSize = mOwner.GetNaturalSize();
374 return naturalSize.width > 0.0f ? naturalSize.height * width / naturalSize.width : width;
377 float ActorSizer::GetWidthForHeightBase(float height)
379 const Vector3 naturalSize = mOwner.GetNaturalSize();
380 return naturalSize.height > 0.0f ? naturalSize.width * height / naturalSize.height : height;
383 float ActorSizer::CalculateChildSizeBase(const Dali::Actor& child, Dimension::Type dimension)
385 // Fill to parent, taking size mode factor into account
386 switch(child.GetResizePolicy(dimension))
388 case ResizePolicy::FILL_TO_PARENT:
390 return GetLatestSize(dimension);
393 case ResizePolicy::SIZE_RELATIVE_TO_PARENT:
395 Property::Value value = child.GetProperty(Dali::Actor::Property::SIZE_MODE_FACTOR);
396 Vector3 childSizeModeFactor = value.Get<Vector3>();
397 return GetLatestSize(dimension) * GetDimensionValue(childSizeModeFactor, dimension);
400 case ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT:
402 Property::Value value = child.GetProperty(Dali::Actor::Property::SIZE_MODE_FACTOR);
403 Vector3 childSizeModeFactor = value.Get<Vector3>();
404 return GetLatestSize(dimension) + GetDimensionValue(childSizeModeFactor, dimension);
409 return GetLatestSize(dimension);
414 float ActorSizer::GetLatestSize(Dimension::Type dimension) const
416 return IsLayoutNegotiated(dimension) ? GetNegotiatedDimension(dimension) : GetSize(dimension);
419 float ActorSizer::GetRelayoutSize(Dimension::Type dimension) const
421 Vector2 padding = GetPadding(dimension);
423 return GetLatestSize(dimension) + padding.x + padding.y;
426 float ActorSizer::NegotiateFromParent(Dimension::Type dimension)
428 Actor* parent = mOwner.GetParent();
431 Vector2 padding(GetPadding(dimension));
432 Vector2 parentPadding(parent->mSizer.GetPadding(dimension));
434 // Need to use actor API here to allow deriving actors to layout their children
435 return parent->CalculateChildSize(Dali::Actor(&mOwner), dimension) - parentPadding.x - parentPadding.y - padding.x - padding.y;
441 float ActorSizer::NegotiateFromChildren(Dimension::Type dimension)
443 float maxDimensionPoint = 0.0f;
445 for(uint32_t i = 0, count = mOwner.GetChildCount(); i < count; ++i)
447 ActorPtr child = mOwner.GetChildAt(i);
449 if(!child->RelayoutDependentOnParent(dimension))
451 // Calculate the min and max points that the children range across
452 float childPosition = GetDimensionValue(child->GetTargetPosition(), dimension);
453 float dimensionSize = child->mSizer.GetRelayoutSize(dimension);
454 maxDimensionPoint = std::max(maxDimensionPoint, childPosition + dimensionSize);
458 return maxDimensionPoint;
461 float ActorSizer::GetSize(Dimension::Type dimension) const
463 return GetDimensionValue(mTargetSize, dimension);
466 float ActorSizer::GetNaturalSize(Dimension::Type dimension) const
468 return GetDimensionValue(mOwner.GetNaturalSize(), dimension);
471 Vector2 ActorSizer::ApplySizeSetPolicy(const Vector2& size)
473 return mRelayoutData->ApplySizeSetPolicy(mOwner, size);
476 void ActorSizer::SetNegotiatedSize(RelayoutContainer& container)
478 // Do the set actor size
479 Vector2 negotiatedSize(GetLatestSize(Dimension::WIDTH), GetLatestSize(Dimension::HEIGHT));
481 // Adjust for size set policy
482 negotiatedSize = ApplySizeSetPolicy(negotiatedSize);
484 // Lock the flag to stop recursive relayouts on set size
485 mRelayoutData->insideRelayout = true;
486 SetSize(Vector3(negotiatedSize.width, negotiatedSize.height, 0.0f));
487 mRelayoutData->insideRelayout = false;
489 // Clear flags for all dimensions
490 SetLayoutDirty(false);
492 // Give deriving classes a chance to respond
493 mOwner.OnRelayout(negotiatedSize, container);
495 if(!mOwner.mOnRelayoutSignal.Empty())
497 Dali::Actor handle(&mOwner);
498 mOwner.mOnRelayoutSignal.Emit(handle);
501 mRelayoutData->relayoutRequested = false;
504 void ActorSizer::NegotiateSize(const Vector2& allocatedSize, RelayoutContainer& container)
506 // Force a size negotiation for actors that has assigned size during relayout
507 // This is required as otherwise the flags that force a relayout will not
508 // necessarilly be set. This will occur if the actor has already been laid out.
509 // The dirty flags are then cleared. Then if the actor is added back into the
510 // relayout container afterwards, the dirty flags would still be clear...
511 // causing a relayout to be skipped. Here we force any actors added to the
512 // container to be relayed out.
513 DALI_LOG_TIMER_START(NegSizeTimer1);
515 if(GetUseAssignedSize(Dimension::WIDTH))
517 SetLayoutNegotiated(false, Dimension::WIDTH);
519 if(GetUseAssignedSize(Dimension::HEIGHT))
521 SetLayoutNegotiated(false, Dimension::HEIGHT);
524 // Do the negotiation
525 NegotiateDimensions(allocatedSize);
527 // Set the actor size
528 SetNegotiatedSize(container);
530 // Negotiate down to children
531 for(uint32_t i = 0, count = mOwner.GetChildCount(); i < count; ++i)
533 ActorPtr child = mOwner.GetChildAt(i);
534 ActorSizer& childSizer = child->mSizer;
536 // Forces children that have already been laid out to be relayed out
537 // if they have assigned size during relayout.
538 if(childSizer.GetUseAssignedSize(Dimension::WIDTH))
540 childSizer.SetLayoutNegotiated(false, Dimension::WIDTH);
541 childSizer.SetLayoutDirty(true, Dimension::WIDTH);
544 if(childSizer.GetUseAssignedSize(Dimension::HEIGHT))
546 childSizer.SetLayoutNegotiated(false, Dimension::HEIGHT);
547 childSizer.SetLayoutDirty(true, Dimension::HEIGHT);
550 // Only relayout if required
551 if(childSizer.RelayoutRequired())
553 container.Add(Dali::Actor(child.Get()), mTargetSize.GetVectorXY());
557 // Reset the flag so that size negotiation will respect the actor's original resize policy
558 SetUseAssignedSize(false);
559 DALI_LOG_TIMER_END(NegSizeTimer1, gLogRelayoutFilter, Debug::Concise, "NegotiateSize() took: ");
562 void ActorSizer::SetUseAssignedSize(bool use, Dimension::Type dimension)
566 mRelayoutData->SetUseAssignedSize(use, dimension);
570 bool ActorSizer::GetUseAssignedSize(Dimension::Type dimension) const
572 return mRelayoutData && mRelayoutData->GetUseAssignedSize(dimension);
575 void ActorSizer::RelayoutRequest(Dimension::Type dimension)
577 Internal::RelayoutController* relayoutController = Internal::RelayoutController::Get();
578 if(relayoutController)
580 Dali::Actor owner(&mOwner);
581 relayoutController->RequestRelayout(owner, dimension);
585 mRelayoutData->relayoutRequested = true;
590 void ActorSizer::SetPreferredSize(const Vector2& size)
594 // If valid width or height, then set the resize policy to FIXED
595 // 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,
596 // then change to FIXED as well
598 if(size.width > 0.0f || GetResizePolicy(Dimension::WIDTH) == ResizePolicy::DEFAULT)
600 SetResizePolicy(ResizePolicy::FIXED, Dimension::WIDTH);
603 if(size.height > 0.0f || GetResizePolicy(Dimension::HEIGHT) == ResizePolicy::DEFAULT)
605 SetResizePolicy(ResizePolicy::FIXED, Dimension::HEIGHT);
608 mRelayoutData->preferredSize = size;
609 mUseAnimatedSize = AnimatedSizeFlag::CLEAR;
613 Vector2 ActorSizer::GetPreferredSize() const
615 return mRelayoutData ? Vector2(mRelayoutData->preferredSize) : Relayouter::DEFAULT_PREFERRED_SIZE;
618 void ActorSizer::SetMinimumSize(float size, Dimension::Type dimension)
620 EnsureRelayouter().SetMinimumSize(size, dimension);
624 float ActorSizer::GetMinimumSize(Dimension::Type dimension) const
626 return mRelayoutData ? mRelayoutData->GetMinimumSize(dimension) : 0.0f;
629 void ActorSizer::SetMaximumSize(float size, Dimension::Type dimension)
631 EnsureRelayouter().SetMaximumSize(size, dimension);
635 float ActorSizer::GetMaximumSize(Dimension::Type dimension) const
637 return mRelayoutData ? mRelayoutData->GetMaximumSize(dimension) : FLT_MAX;
640 void ActorSizer::OnAnimateSize(Animation& animation, Vector3 targetSize, bool relative)
642 mTargetSize = targetSize + mTargetSize * float(relative);
643 mAnimatedSize = mTargetSize;
644 mUseAnimatedSize = AnimatedSizeFlag::WIDTH | AnimatedSizeFlag::HEIGHT | AnimatedSizeFlag::DEPTH;
646 if(mRelayoutData && !mRelayoutData->relayoutRequested)
648 mRelayoutData->preferredSize.width = mAnimatedSize.width;
649 mRelayoutData->preferredSize.height = mAnimatedSize.height;
652 // Notify deriving classes
653 mOwner.OnSizeAnimation(animation, mTargetSize);
656 void ActorSizer::OnAnimateWidth(Animation& animation, float width, bool relative)
658 mTargetSize.width = width + float(relative) * mTargetSize.width;
659 mAnimatedSize.width = mTargetSize.width;
660 mUseAnimatedSize |= AnimatedSizeFlag::WIDTH;
662 if(mRelayoutData && !mRelayoutData->relayoutRequested)
664 mRelayoutData->preferredSize.width = mAnimatedSize.width;
667 // Notify deriving classes
668 mOwner.OnSizeAnimation(animation, mTargetSize);
671 void ActorSizer::OnAnimateHeight(Animation& animation, float height, bool relative)
673 mTargetSize.height = height + float(relative) * mTargetSize.height;
674 mAnimatedSize.height = mTargetSize.height;
675 mUseAnimatedSize |= AnimatedSizeFlag::HEIGHT;
677 if(mRelayoutData && !mRelayoutData->relayoutRequested)
679 mRelayoutData->preferredSize.height = mAnimatedSize.height;
682 // Notify deriving classes
683 mOwner.OnSizeAnimation(animation, mTargetSize);
686 void ActorSizer::OnAnimateDepth(Animation& animation, float depth, bool relative)
688 mTargetSize.depth = depth + float(relative) * mTargetSize.depth;
689 mAnimatedSize.depth = mTargetSize.depth;
690 mUseAnimatedSize |= AnimatedSizeFlag::DEPTH;
692 // Notify deriving classes
693 mOwner.OnSizeAnimation(animation, mTargetSize);
697 * @brief Extract a given dimension from a Vector3
699 * @param[in] values The values to extract from
700 * @param[in] dimension The dimension to extract
701 * @return Return the value for the dimension
703 float ActorSizer::GetDimensionValue(const Vector3& values, const Dimension::Type dimension) const
705 return ::GetDimensionValue(values.GetVectorXY(), dimension);
708 float ActorSizer::ClampDimension(float size, Dimension::Type dimension) const
710 const float minSize = GetMinimumSize(dimension);
711 const float maxSize = GetMaximumSize(dimension);
713 return std::max(minSize, std::min(size, maxSize));
716 void ActorSizer::NegotiateDimension(Dimension::Type dimension, const Vector2& allocatedSize, ActorDimensionStack& recursionStack)
718 // Check if it needs to be negotiated
719 if(IsLayoutDirty(dimension) && !IsLayoutNegotiated(dimension))
721 // Check that we havn't gotten into an infinite loop
722 ActorDimensionPair searchActor = ActorDimensionPair(&mOwner, dimension);
723 bool recursionFound = false;
724 for(auto& element : recursionStack)
726 if(element == searchActor)
728 recursionFound = true;
735 // Record the path that we have taken
736 recursionStack.push_back(ActorDimensionPair(&mOwner, dimension));
738 // Dimension dependency check
739 for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
741 Dimension::Type dimensionToCheck = static_cast<Dimension::Type>(1 << i);
743 if(RelayoutDependentOnDimension(dimension, dimensionToCheck))
745 NegotiateDimension(dimensionToCheck, allocatedSize, recursionStack);
749 // Parent dependency check
750 Actor* parent = mOwner.GetParent();
751 if(parent && RelayoutDependentOnParent(dimension))
753 parent->mSizer.NegotiateDimension(dimension, allocatedSize, recursionStack);
756 // Children dependency check
757 if(mOwner.RelayoutDependentOnChildren(dimension))
759 for(uint32_t i = 0, count = mOwner.GetChildCount(); i < count; ++i)
761 ActorPtr child = mOwner.GetChildAt(i);
763 // Only relayout child first if it is not dependent on this actor
764 if(!child->RelayoutDependentOnParent(dimension))
766 child->mSizer.NegotiateDimension(dimension, allocatedSize, recursionStack);
771 // For deriving classes
772 mOwner.OnCalculateRelayoutSize(dimension);
774 // All dependencies checked, calculate the size and set negotiated flag
775 const float newSize = ClampDimension(CalculateSize(dimension, allocatedSize), dimension);
777 SetNegotiatedDimension(newSize, dimension);
778 SetLayoutNegotiated(true, dimension);
780 // For deriving classes
781 mOwner.OnLayoutNegotiated(newSize, dimension);
783 // This actor has been successfully processed, pop it off the recursion stack
784 recursionStack.pop_back();
788 // TODO: Break infinite loop
789 SetLayoutNegotiated(true, dimension);
794 void ActorSizer::NegotiateDimensions(const Vector2& allocatedSize)
796 // Negotiate all dimensions that require it
797 ActorDimensionStack recursionStack;
799 for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
801 const Dimension::Type dimension = static_cast<Dimension::Type>(1 << i);
804 NegotiateDimension(dimension, allocatedSize, recursionStack);
808 float ActorSizer::CalculateSize(Dimension::Type dimension, const Vector2& maximumSize)
810 switch(GetResizePolicy(dimension))
812 case ResizePolicy::USE_NATURAL_SIZE:
814 return GetNaturalSize(dimension);
817 case ResizePolicy::FIXED:
819 return ::GetDimensionValue(GetPreferredSize(), dimension);
822 case ResizePolicy::USE_ASSIGNED_SIZE:
824 return ::GetDimensionValue(maximumSize, dimension);
827 case ResizePolicy::FILL_TO_PARENT:
828 case ResizePolicy::SIZE_RELATIVE_TO_PARENT:
829 case ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT:
831 return NegotiateFromParent(dimension);
834 case ResizePolicy::FIT_TO_CHILDREN:
836 return NegotiateFromChildren(dimension);
839 case ResizePolicy::DIMENSION_DEPENDENCY:
841 const Dimension::Type dimensionDependency = GetDimensionDependency(dimension);
844 if(dimension == Dimension::WIDTH && dimensionDependency == Dimension::HEIGHT)
846 // Use actor API to allow deriving actors to layout their content
847 return mOwner.GetWidthForHeight(GetNegotiatedDimension(Dimension::HEIGHT));
850 if(dimension == Dimension::HEIGHT && dimensionDependency == Dimension::WIDTH)
852 // Use actor API to allow deriving actors to layout their content
853 return mOwner.GetHeightForWidth(GetNegotiatedDimension(Dimension::WIDTH));
865 return 0.0f; // Default
868 } // namespace Dali::Internal