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 * @brief Default relayout dependent on parent when relayout is not setuped before.
69 static constexpr bool DEFAULT_RELAYOUT_DEPENDENT_ON_PARENT = ((Dali::ResizePolicy::DEFAULT == Dali::ResizePolicy::FILL_TO_PARENT) ||
70 (Dali::ResizePolicy::DEFAULT == Dali::ResizePolicy::SIZE_RELATIVE_TO_PARENT) ||
71 (Dali::ResizePolicy::DEFAULT == Dali::ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT));
74 * @brief Default relayout dependent on child when relayout is not setuped before.
76 static constexpr bool DEFAULT_RELAYOUT_DEPENDENT_ON_CHILD = ((Dali::ResizePolicy::DEFAULT == Dali::ResizePolicy::FIT_TO_CHILDREN) ||
77 (Dali::ResizePolicy::DEFAULT == Dali::ResizePolicy::USE_NATURAL_SIZE));
81 namespace Dali::Internal
83 ActorSizer::ActorSizer(Internal::Actor& owner)
85 mRelayoutData(nullptr),
86 mTargetSize(Vector3::ZERO),
87 mAnimatedSize(Vector3::ZERO),
88 mUseAnimatedSize(AnimatedSizeFlag::CLEAR),
89 mInsideOnSizeSet(false)
93 ActorSizer::~ActorSizer()
95 // Delete optional relayout data
99 void ActorSizer::SetSizeModeFactor(const Vector3& factor)
103 mRelayoutData->sizeModeFactor = factor;
105 const Vector3& ActorSizer::GetSizeModeFactor() const
107 return mRelayoutData ? mRelayoutData->sizeModeFactor : Relayouter::DEFAULT_SIZE_MODE_FACTOR;
110 void ActorSizer::SetSize(const Vector3& size)
112 if(IsRelayoutEnabled() && !mRelayoutData->insideRelayout)
114 // TODO we cannot just ignore the given Z but that means rewrite the size negotiation!!
115 SetPreferredSize(size.GetVectorXY());
119 SetSizeInternal(size);
123 void ActorSizer::SetSizeInternal(const Vector3& size)
125 // dont allow recursive loop
126 DALI_ASSERT_ALWAYS(!mInsideOnSizeSet && "Cannot call SetSize from OnSizeSet");
127 // 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
128 Vector3 currentSize = mOwner.GetCurrentSize();
130 if((fabsf(mTargetSize.width - size.width) > Math::MACHINE_EPSILON_1) ||
131 (fabsf(mTargetSize.height - size.height) > Math::MACHINE_EPSILON_1) ||
132 (fabsf(mTargetSize.depth - size.depth) > Math::MACHINE_EPSILON_1) ||
133 (fabsf(mTargetSize.width - currentSize.width) > Math::MACHINE_EPSILON_1) ||
134 (fabsf(mTargetSize.height - currentSize.height) > Math::MACHINE_EPSILON_1) ||
135 (fabsf(mTargetSize.depth - currentSize.depth) > Math::MACHINE_EPSILON_1))
139 // Update the preferred size after relayoutting
140 // It should be used in the next relayoutting
141 if(mUseAnimatedSize & AnimatedSizeFlag::WIDTH && mRelayoutData)
143 mRelayoutData->preferredSize.width = mAnimatedSize.width;
146 if(mUseAnimatedSize & AnimatedSizeFlag::HEIGHT && mRelayoutData)
148 mRelayoutData->preferredSize.height = mAnimatedSize.height;
151 // node is being used in a separate thread; queue a message to set the value & base value
152 auto& node = mOwner.GetNode();
153 SceneGraph::NodeTransformPropertyMessage<Vector3>::Send(mOwner.GetEventThreadServices(), &node, &node.mSize, &SceneGraph::TransformManagerPropertyHandler<Vector3>::Bake, mTargetSize);
155 // Notification for derived classes
156 mInsideOnSizeSet = true;
157 mOwner.OnSizeSet(mTargetSize);
158 mInsideOnSizeSet = false;
160 // Raise a relayout request if the flag is not locked
161 if(mRelayoutData && !mRelayoutData->insideRelayout)
168 void ActorSizer::SetWidth(float width)
170 if(IsRelayoutEnabled() && !mRelayoutData->insideRelayout)
172 SetResizePolicy(ResizePolicy::FIXED, Dimension::WIDTH);
173 mRelayoutData->preferredSize.width = width;
177 mTargetSize.width = width;
179 // node is being used in a separate thread; queue a message to set the value & base value
180 auto& node = mOwner.GetNode();
181 SceneGraph::NodeTransformComponentMessage<Vector3>::Send(mOwner.GetEventThreadServices(), &node, &node.mSize, &SceneGraph::TransformManagerPropertyHandler<Vector3>::BakeX, width);
184 mUseAnimatedSize &= ~AnimatedSizeFlag::WIDTH;
188 void ActorSizer::SetHeight(float height)
190 if(IsRelayoutEnabled() && !mRelayoutData->insideRelayout)
192 SetResizePolicy(ResizePolicy::FIXED, Dimension::HEIGHT);
193 mRelayoutData->preferredSize.height = height;
197 mTargetSize.height = height;
199 // node is being used in a separate thread; queue a message to set the value & base value
200 auto& node = mOwner.GetNode();
201 SceneGraph::NodeTransformComponentMessage<Vector3>::Send(mOwner.GetEventThreadServices(), &node, &node.mSize, &SceneGraph::TransformManagerPropertyHandler<Vector3>::BakeY, height);
204 mUseAnimatedSize &= ~AnimatedSizeFlag::HEIGHT;
208 void ActorSizer::SetDepth(float depth)
210 mTargetSize.depth = depth;
212 mUseAnimatedSize &= ~AnimatedSizeFlag::DEPTH;
214 // node is being used in a separate thread; queue a message to set the value & base value
215 auto& node = mOwner.GetNode();
216 SceneGraph::NodeTransformComponentMessage<Vector3>::Send(mOwner.GetEventThreadServices(), &node, &node.mSize, &SceneGraph::TransformManagerPropertyHandler<Vector3>::BakeZ, depth);
219 Vector3 ActorSizer::GetTargetSize() const
221 Vector3 size = mTargetSize;
223 if(mUseAnimatedSize & AnimatedSizeFlag::WIDTH)
225 // Should return animated size if size is animated
226 size.width = mAnimatedSize.width;
230 // Should return preferred size if size is fixed as set by SetSize
231 if(GetResizePolicy(Dimension::WIDTH) == ResizePolicy::FIXED)
233 size.width = GetPreferredSize().width;
237 if(mUseAnimatedSize & AnimatedSizeFlag::HEIGHT)
239 size.height = mAnimatedSize.height;
243 if(GetResizePolicy(Dimension::HEIGHT) == ResizePolicy::FIXED)
245 size.height = GetPreferredSize().height;
249 if(mUseAnimatedSize & AnimatedSizeFlag::DEPTH)
251 size.depth = mAnimatedSize.depth;
257 void ActorSizer::SetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension)
259 EnsureRelayouter().SetResizePolicy(policy, dimension, mTargetSize);
260 mOwner.OnSetResizePolicy(policy, dimension);
264 ResizePolicy::Type ActorSizer::GetResizePolicy(Dimension::Type dimension) const
266 return mRelayoutData ? mRelayoutData->GetResizePolicy(dimension) : ResizePolicy::DEFAULT;
269 void ActorSizer::SetSizeScalePolicy(SizeScalePolicy::Type policy)
272 mRelayoutData->sizeSetPolicy = policy;
276 SizeScalePolicy::Type ActorSizer::GetSizeScalePolicy() const
278 return mRelayoutData ? mRelayoutData->sizeSetPolicy : Relayouter::DEFAULT_SIZE_SCALE_POLICY;
281 Dimension::Type ActorSizer::GetDimensionDependency(Dimension::Type dimension) const
283 return mRelayoutData ? mRelayoutData->GetDimensionDependency(dimension) : Dimension::ALL_DIMENSIONS;
286 void ActorSizer::SetRelayoutEnabled(bool relayoutEnabled)
288 // If relayout data has not been allocated yet and the client is requesting
289 // to disable it, do nothing
290 if(mRelayoutData || relayoutEnabled)
294 DALI_ASSERT_DEBUG(mRelayoutData && "mRelayoutData not created");
296 mRelayoutData->relayoutEnabled = relayoutEnabled;
300 bool ActorSizer::IsRelayoutEnabled() const
302 // Assume that if relayout data has not been allocated yet then relayout is disabled
303 return mRelayoutData && mRelayoutData->relayoutEnabled;
306 void ActorSizer::SetLayoutDirty(bool dirty, Dimension::Type dimension)
308 EnsureRelayouter().SetLayoutDirty(dirty, dimension);
311 bool ActorSizer::IsLayoutDirty(Dimension::Type dimension) const
313 return mRelayoutData && mRelayoutData->IsLayoutDirty(dimension);
316 bool ActorSizer::RelayoutPossible(Dimension::Type dimension) const
318 return mRelayoutData && mRelayoutData->relayoutEnabled && !IsLayoutDirty(dimension);
321 bool ActorSizer::RelayoutRequired(Dimension::Type dimension) const
323 return mRelayoutData && mRelayoutData->relayoutEnabled && IsLayoutDirty(dimension);
326 ActorSizer::Relayouter& ActorSizer::EnsureRelayouter()
331 mRelayoutData = new Relayouter();
334 return *mRelayoutData;
337 bool ActorSizer::RelayoutDependentOnParent(Dimension::Type dimension)
339 return mRelayoutData ? mRelayoutData->GetRelayoutDependentOnParent(dimension) : DEFAULT_RELAYOUT_DEPENDENT_ON_PARENT;
342 bool ActorSizer::RelayoutDependentOnChildrenBase(Dimension::Type dimension)
344 return mRelayoutData ? mRelayoutData->GetRelayoutDependentOnChildren(dimension) : DEFAULT_RELAYOUT_DEPENDENT_ON_CHILD;
347 bool ActorSizer::RelayoutDependentOnDimension(Dimension::Type dimension, Dimension::Type dependentDimension)
349 return mRelayoutData && mRelayoutData->GetRelayoutDependentOnDimension(dimension, dependentDimension);
352 void ActorSizer::SetNegotiatedDimension(float negotiatedDimension, Dimension::Type dimension)
356 mRelayoutData->SetNegotiatedDimension(negotiatedDimension, dimension);
360 float ActorSizer::GetNegotiatedDimension(Dimension::Type dimension) const
362 return mRelayoutData ? mRelayoutData->GetNegotiatedDimension(dimension) : 0.0f;
365 void ActorSizer::SetPadding(const Vector2& padding, Dimension::Type dimension)
367 EnsureRelayouter().SetPadding(padding, dimension);
370 Vector2 ActorSizer::GetPadding(Dimension::Type dimension) const
372 return mRelayoutData ? mRelayoutData->GetPadding(dimension) : Relayouter::DEFAULT_DIMENSION_PADDING;
375 void ActorSizer::SetLayoutNegotiated(bool negotiated, Dimension::Type dimension)
377 EnsureRelayouter().SetLayoutNegotiated(negotiated, dimension);
380 bool ActorSizer::IsLayoutNegotiated(Dimension::Type dimension) const
382 return mRelayoutData && mRelayoutData->IsLayoutNegotiated(dimension);
385 float ActorSizer::GetHeightForWidthBase(float width)
387 const Vector3 naturalSize = mOwner.GetNaturalSize();
388 return naturalSize.width > 0.0f ? naturalSize.height * width / naturalSize.width : width;
391 float ActorSizer::GetWidthForHeightBase(float height)
393 const Vector3 naturalSize = mOwner.GetNaturalSize();
394 return naturalSize.height > 0.0f ? naturalSize.width * height / naturalSize.height : height;
397 float ActorSizer::CalculateChildSizeBase(const Dali::Actor& child, Dimension::Type dimension)
399 // Fill to parent, taking size mode factor into account
400 switch(child.GetResizePolicy(dimension))
402 case ResizePolicy::FILL_TO_PARENT:
404 return GetLatestSize(dimension);
407 case ResizePolicy::SIZE_RELATIVE_TO_PARENT:
409 Property::Value value = child.GetProperty(Dali::Actor::Property::SIZE_MODE_FACTOR);
410 Vector3 childSizeModeFactor = value.Get<Vector3>();
411 return GetLatestSize(dimension) * GetDimensionValue(childSizeModeFactor, dimension);
414 case ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT:
416 Property::Value value = child.GetProperty(Dali::Actor::Property::SIZE_MODE_FACTOR);
417 Vector3 childSizeModeFactor = value.Get<Vector3>();
418 return GetLatestSize(dimension) + GetDimensionValue(childSizeModeFactor, dimension);
423 return GetLatestSize(dimension);
428 float ActorSizer::GetLatestSize(Dimension::Type dimension) const
430 return IsLayoutNegotiated(dimension) ? GetNegotiatedDimension(dimension) : GetSize(dimension);
433 float ActorSizer::GetRelayoutSize(Dimension::Type dimension) const
435 Vector2 padding = GetPadding(dimension);
437 return GetLatestSize(dimension) + padding.x + padding.y;
440 float ActorSizer::NegotiateFromParent(Dimension::Type dimension)
442 Actor* parent = mOwner.GetParent();
445 Vector2 padding(GetPadding(dimension));
446 Vector2 parentPadding(parent->mSizer.GetPadding(dimension));
448 // Need to use actor API here to allow deriving actors to layout their children
449 return parent->CalculateChildSize(Dali::Actor(&mOwner), dimension) - parentPadding.x - parentPadding.y - padding.x - padding.y;
455 float ActorSizer::NegotiateFromChildren(Dimension::Type dimension)
457 float maxDimensionPoint = 0.0f;
459 for(uint32_t i = 0, count = mOwner.GetChildCount(); i < count; ++i)
461 ActorPtr child = mOwner.GetChildAt(i);
463 if(!child->RelayoutDependentOnParent(dimension))
465 // Calculate the min and max points that the children range across
466 float childPosition = GetDimensionValue(child->GetTargetPosition(), dimension);
467 float dimensionSize = child->mSizer.GetRelayoutSize(dimension);
468 maxDimensionPoint = std::max(maxDimensionPoint, childPosition + dimensionSize);
472 return maxDimensionPoint;
475 float ActorSizer::GetSize(Dimension::Type dimension) const
477 return GetDimensionValue(mTargetSize, dimension);
480 float ActorSizer::GetNaturalSize(Dimension::Type dimension) const
482 return GetDimensionValue(mOwner.GetNaturalSize(), dimension);
485 Vector2 ActorSizer::ApplySizeSetPolicy(const Vector2& size)
487 return mRelayoutData->ApplySizeSetPolicy(mOwner, size);
490 void ActorSizer::SetNegotiatedSize(RelayoutContainer& container)
492 // Do the set actor size
493 Vector2 negotiatedSize(GetLatestSize(Dimension::WIDTH), GetLatestSize(Dimension::HEIGHT));
495 // Adjust for size set policy
496 negotiatedSize = ApplySizeSetPolicy(negotiatedSize);
498 // Lock the flag to stop recursive relayouts on set size
499 mRelayoutData->insideRelayout = true;
500 SetSize(Vector3(negotiatedSize.width, negotiatedSize.height, 0.0f));
501 mRelayoutData->insideRelayout = false;
503 // Clear flags for all dimensions
504 SetLayoutDirty(false);
506 // Give deriving classes a chance to respond
507 mOwner.OnRelayout(negotiatedSize, container);
509 if(!mOwner.mOnRelayoutSignal.Empty())
511 Dali::Actor handle(&mOwner);
512 mOwner.mOnRelayoutSignal.Emit(handle);
515 mRelayoutData->relayoutRequested = false;
518 void ActorSizer::NegotiateSize(const Vector2& allocatedSize, RelayoutContainer& container)
520 // Force a size negotiation for actors that has assigned size during relayout
521 // This is required as otherwise the flags that force a relayout will not
522 // necessarilly be set. This will occur if the actor has already been laid out.
523 // The dirty flags are then cleared. Then if the actor is added back into the
524 // relayout container afterwards, the dirty flags would still be clear...
525 // causing a relayout to be skipped. Here we force any actors added to the
526 // container to be relayed out.
527 DALI_LOG_TIMER_START(NegSizeTimer1);
529 if(GetUseAssignedSize(Dimension::WIDTH))
531 SetLayoutNegotiated(false, Dimension::WIDTH);
533 if(GetUseAssignedSize(Dimension::HEIGHT))
535 SetLayoutNegotiated(false, Dimension::HEIGHT);
538 // Do the negotiation
539 NegotiateDimensions(allocatedSize);
541 // Set the actor size
542 SetNegotiatedSize(container);
544 // Negotiate down to children
545 for(uint32_t i = 0, count = mOwner.GetChildCount(); i < count; ++i)
547 ActorPtr child = mOwner.GetChildAt(i);
548 ActorSizer& childSizer = child->mSizer;
550 // Forces children that have already been laid out to be relayed out
551 // if they have assigned size during relayout.
552 if(childSizer.GetUseAssignedSize(Dimension::WIDTH))
554 childSizer.SetLayoutNegotiated(false, Dimension::WIDTH);
555 childSizer.SetLayoutDirty(true, Dimension::WIDTH);
558 if(childSizer.GetUseAssignedSize(Dimension::HEIGHT))
560 childSizer.SetLayoutNegotiated(false, Dimension::HEIGHT);
561 childSizer.SetLayoutDirty(true, Dimension::HEIGHT);
564 // Only relayout if required
565 if(childSizer.RelayoutRequired())
567 container.Add(Dali::Actor(child.Get()), mTargetSize.GetVectorXY());
571 // Reset the flag so that size negotiation will respect the actor's original resize policy
572 SetUseAssignedSize(false);
573 DALI_LOG_TIMER_END(NegSizeTimer1, gLogRelayoutFilter, Debug::Concise, "NegotiateSize() took: ");
576 void ActorSizer::SetUseAssignedSize(bool use, Dimension::Type dimension)
580 mRelayoutData->SetUseAssignedSize(use, dimension);
584 bool ActorSizer::GetUseAssignedSize(Dimension::Type dimension) const
586 return mRelayoutData && mRelayoutData->GetUseAssignedSize(dimension);
589 void ActorSizer::RelayoutRequest(Dimension::Type dimension)
591 Internal::RelayoutController* relayoutController = Internal::RelayoutController::Get();
592 if(relayoutController)
594 Dali::Actor owner(&mOwner);
595 relayoutController->RequestRelayout(owner, dimension);
599 mRelayoutData->relayoutRequested = true;
604 void ActorSizer::SetPreferredSize(const Vector2& size)
608 // If valid width or height, then set the resize policy to FIXED
609 // 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,
610 // then change to FIXED as well
612 if(size.width > 0.0f || GetResizePolicy(Dimension::WIDTH) == ResizePolicy::DEFAULT)
614 SetResizePolicy(ResizePolicy::FIXED, Dimension::WIDTH);
617 if(size.height > 0.0f || GetResizePolicy(Dimension::HEIGHT) == ResizePolicy::DEFAULT)
619 SetResizePolicy(ResizePolicy::FIXED, Dimension::HEIGHT);
622 mRelayoutData->preferredSize = size;
623 mUseAnimatedSize = AnimatedSizeFlag::CLEAR;
627 Vector2 ActorSizer::GetPreferredSize() const
629 return mRelayoutData ? Vector2(mRelayoutData->preferredSize) : Relayouter::DEFAULT_PREFERRED_SIZE;
632 void ActorSizer::SetMinimumSize(float size, Dimension::Type dimension)
634 EnsureRelayouter().SetMinimumSize(size, dimension);
638 float ActorSizer::GetMinimumSize(Dimension::Type dimension) const
640 return mRelayoutData ? mRelayoutData->GetMinimumSize(dimension) : 0.0f;
643 void ActorSizer::SetMaximumSize(float size, Dimension::Type dimension)
645 EnsureRelayouter().SetMaximumSize(size, dimension);
649 float ActorSizer::GetMaximumSize(Dimension::Type dimension) const
651 return mRelayoutData ? mRelayoutData->GetMaximumSize(dimension) : FLT_MAX;
654 void ActorSizer::OnAnimateSize(Animation& animation, Vector3 targetSize, bool relative)
656 mTargetSize = targetSize + mTargetSize * float(relative);
657 mAnimatedSize = mTargetSize;
658 mUseAnimatedSize = AnimatedSizeFlag::WIDTH | AnimatedSizeFlag::HEIGHT | AnimatedSizeFlag::DEPTH;
660 if(mRelayoutData && !mRelayoutData->relayoutRequested)
662 mRelayoutData->preferredSize.width = mAnimatedSize.width;
663 mRelayoutData->preferredSize.height = mAnimatedSize.height;
666 // Notify deriving classes
667 mOwner.OnSizeAnimation(animation, mTargetSize);
670 void ActorSizer::OnAnimateWidth(Animation& animation, float width, bool relative)
672 mTargetSize.width = width + float(relative) * mTargetSize.width;
673 mAnimatedSize.width = mTargetSize.width;
674 mUseAnimatedSize |= AnimatedSizeFlag::WIDTH;
676 if(mRelayoutData && !mRelayoutData->relayoutRequested)
678 mRelayoutData->preferredSize.width = mAnimatedSize.width;
681 // Notify deriving classes
682 mOwner.OnSizeAnimation(animation, mTargetSize);
685 void ActorSizer::OnAnimateHeight(Animation& animation, float height, bool relative)
687 mTargetSize.height = height + float(relative) * mTargetSize.height;
688 mAnimatedSize.height = mTargetSize.height;
689 mUseAnimatedSize |= AnimatedSizeFlag::HEIGHT;
691 if(mRelayoutData && !mRelayoutData->relayoutRequested)
693 mRelayoutData->preferredSize.height = mAnimatedSize.height;
696 // Notify deriving classes
697 mOwner.OnSizeAnimation(animation, mTargetSize);
700 void ActorSizer::OnAnimateDepth(Animation& animation, float depth, bool relative)
702 mTargetSize.depth = depth + float(relative) * mTargetSize.depth;
703 mAnimatedSize.depth = mTargetSize.depth;
704 mUseAnimatedSize |= AnimatedSizeFlag::DEPTH;
706 // Notify deriving classes
707 mOwner.OnSizeAnimation(animation, mTargetSize);
711 * @brief Extract a given dimension from a Vector3
713 * @param[in] values The values to extract from
714 * @param[in] dimension The dimension to extract
715 * @return Return the value for the dimension
717 float ActorSizer::GetDimensionValue(const Vector3& values, const Dimension::Type dimension) const
719 return ::GetDimensionValue(values.GetVectorXY(), dimension);
722 float ActorSizer::ClampDimension(float size, Dimension::Type dimension) const
724 const float minSize = GetMinimumSize(dimension);
725 const float maxSize = GetMaximumSize(dimension);
727 return std::max(minSize, std::min(size, maxSize));
730 void ActorSizer::NegotiateDimension(Dimension::Type dimension, const Vector2& allocatedSize, ActorDimensionStack& recursionStack)
732 // Check if it needs to be negotiated
733 if(IsLayoutDirty(dimension) && !IsLayoutNegotiated(dimension))
735 // Check that we havn't gotten into an infinite loop
736 ActorDimensionPair searchActor = ActorDimensionPair(&mOwner, dimension);
737 bool recursionFound = false;
738 for(auto& element : recursionStack)
740 if(element == searchActor)
742 recursionFound = true;
749 // Record the path that we have taken
750 recursionStack.push_back(ActorDimensionPair(&mOwner, dimension));
752 // Dimension dependency check
753 for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
755 Dimension::Type dimensionToCheck = static_cast<Dimension::Type>(1 << i);
757 if(RelayoutDependentOnDimension(dimension, dimensionToCheck))
759 NegotiateDimension(dimensionToCheck, allocatedSize, recursionStack);
763 // Parent dependency check
764 Actor* parent = mOwner.GetParent();
765 if(parent && RelayoutDependentOnParent(dimension))
767 parent->mSizer.NegotiateDimension(dimension, allocatedSize, recursionStack);
770 // Children dependency check
771 if(mOwner.RelayoutDependentOnChildren(dimension))
773 for(uint32_t i = 0, count = mOwner.GetChildCount(); i < count; ++i)
775 ActorPtr child = mOwner.GetChildAt(i);
777 // Only relayout child first if it is not dependent on this actor
778 if(!child->RelayoutDependentOnParent(dimension))
780 child->mSizer.NegotiateDimension(dimension, allocatedSize, recursionStack);
785 // For deriving classes
786 mOwner.OnCalculateRelayoutSize(dimension);
788 // All dependencies checked, calculate the size and set negotiated flag
789 const float newSize = ClampDimension(CalculateSize(dimension, allocatedSize), dimension);
791 SetNegotiatedDimension(newSize, dimension);
792 SetLayoutNegotiated(true, dimension);
794 // For deriving classes
795 mOwner.OnLayoutNegotiated(newSize, dimension);
797 // This actor has been successfully processed, pop it off the recursion stack
798 recursionStack.pop_back();
802 // TODO: Break infinite loop
803 SetLayoutNegotiated(true, dimension);
808 void ActorSizer::NegotiateDimensions(const Vector2& allocatedSize)
810 // Negotiate all dimensions that require it
811 ActorDimensionStack recursionStack;
813 for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
815 const Dimension::Type dimension = static_cast<Dimension::Type>(1 << i);
818 NegotiateDimension(dimension, allocatedSize, recursionStack);
822 float ActorSizer::CalculateSize(Dimension::Type dimension, const Vector2& maximumSize)
824 switch(GetResizePolicy(dimension))
826 case ResizePolicy::USE_NATURAL_SIZE:
828 return GetNaturalSize(dimension);
831 case ResizePolicy::FIXED:
833 return ::GetDimensionValue(GetPreferredSize(), dimension);
836 case ResizePolicy::USE_ASSIGNED_SIZE:
838 return ::GetDimensionValue(maximumSize, dimension);
841 case ResizePolicy::FILL_TO_PARENT:
842 case ResizePolicy::SIZE_RELATIVE_TO_PARENT:
843 case ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT:
845 return NegotiateFromParent(dimension);
848 case ResizePolicy::FIT_TO_CHILDREN:
850 return NegotiateFromChildren(dimension);
853 case ResizePolicy::DIMENSION_DEPENDENCY:
855 const Dimension::Type dimensionDependency = GetDimensionDependency(dimension);
858 if(dimension == Dimension::WIDTH && dimensionDependency == Dimension::HEIGHT)
860 // Use actor API to allow deriving actors to layout their content
861 return mOwner.GetWidthForHeight(GetNegotiatedDimension(Dimension::HEIGHT));
864 if(dimension == Dimension::HEIGHT && dimensionDependency == Dimension::WIDTH)
866 // Use actor API to allow deriving actors to layout their content
867 return mOwner.GetHeightForWidth(GetNegotiatedDimension(Dimension::WIDTH));
879 return 0.0f; // Default
882 } // namespace Dali::Internal