diff --git a/frameworks/bridge/declarative_frontend/engine/jsEnumStyle.js b/frameworks/bridge/declarative_frontend/engine/jsEnumStyle.js index 31d77c6a9e1f8a8071a36df876b2590117ce18df..7a480ebe8b7bb7b5c4b220b66751ab452cbdeb8d 100644 --- a/frameworks/bridge/declarative_frontend/engine/jsEnumStyle.js +++ b/frameworks/bridge/declarative_frontend/engine/jsEnumStyle.js @@ -274,6 +274,21 @@ var Alignment; Alignment[Alignment["BottomEnd"] = 8] = "BottomEnd"; })(Alignment || (Alignment = {})); +var ChainStyle; +(function (ChainStyle) { + ChainStyle[ChainStyle["SPREAD"] = 0] = "SPREAD"; + ChainStyle[ChainStyle["SPREAD_INSIDE"] = 1] = "SPREAD_INSIDE"; + ChainStyle[ChainStyle["PACKED"] = 2] = "PACKED"; +})(ChainStyle || (ChainStyle = {})); + +var BarrierDirection; +(function (BarrierDirection) { + BarrierDirection[BarrierDirection["LEFT"] = 0] = "LEFT"; + BarrierDirection[BarrierDirection["RIGHT"] = 1] = "RIGHT"; + BarrierDirection[BarrierDirection["TOP"] = 2] = "TOP"; + BarrierDirection[BarrierDirection["BOTTOM"] = 3] = "BOTTOM"; +})(BarrierDirection || (BarrierDirection = {})); + var BlendMode; (function (BlendMode) { BlendMode[BlendMode["NORMAL"] = 0] = "NORMAL"; diff --git a/frameworks/bridge/declarative_frontend/jsview/js_relative_container.cpp b/frameworks/bridge/declarative_frontend/jsview/js_relative_container.cpp index 411d909c021bf020ae67420d98f697c89f00b479..73f1ca894a71b662ed2013f6635158abdc6f5de2 100644 --- a/frameworks/bridge/declarative_frontend/jsview/js_relative_container.cpp +++ b/frameworks/bridge/declarative_frontend/jsview/js_relative_container.cpp @@ -63,6 +63,8 @@ void JSRelativeContainer::JSBind(BindingTarget globalObj) JSClass::StaticMethod("onAppear", &JSInteractableView::JsOnAppear); JSClass::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear); JSClass::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage); + JSClass::StaticMethod("barrier", &JSRelativeContainer::JsBarrier); + JSClass::StaticMethod("guideLine", &JSRelativeContainer::JsGuideline); JSClass::InheritAndBind(globalObj); } @@ -71,4 +73,111 @@ void JSRelativeContainer::Create(const JSCallbackInfo& info) RelativeContainerModel::GetInstance()->Create(); } +void JSRelativeContainer::ParseBarrierInfo(const JSRef& args, BarrierInfo& barrierInfoItem) +{ + JSRef barrierInfoObj = JSRef::Cast(args); + JSRef idVal = barrierInfoObj->GetProperty("id"); + JSRef directionVal = barrierInfoObj->GetProperty("direction"); + JSRef referencedIdVal = barrierInfoObj->GetProperty("referencedId"); + + if (idVal->IsString()) { + barrierInfoItem.id = idVal->ToString(); + } + + if (directionVal->IsNumber()) { + auto direction = directionVal->ToNumber(); + barrierInfoItem.direction = static_cast(direction); + } + + if (referencedIdVal->IsArray()) { + JSRef array = JSRef::Cast(referencedIdVal); + for (size_t i = 0; i < array->Length(); i++) { + JSRef idVal = array->GetValueAt(i); + if (idVal->IsString()) { + barrierInfoItem.referencedId.emplace_back(idVal->ToString()); + } + } + } +} + +void JSRelativeContainer::JsBarrier(const JSCallbackInfo& info) +{ + auto tmpInfo = info[0]; + std::vector barrierInfos; + if (tmpInfo->IsUndefined()) { + RelativeContainerModel::GetInstance()->SetBarrier(barrierInfos); + return; + } + if (!tmpInfo->IsArray() && !tmpInfo->IsObject()) { + RelativeContainerModel::GetInstance()->SetBarrier(barrierInfos); + return; + } + + if (tmpInfo->IsArray()) { + JSRef array = JSRef::Cast(tmpInfo); + for (size_t i = 0; i < array->Length(); i++) { + BarrierInfo barrierInfoItem; + ParseBarrierInfo(array->GetValueAt(i), barrierInfoItem); + barrierInfos.emplace_back(barrierInfoItem); + } + } + + RelativeContainerModel::GetInstance()->SetBarrier(barrierInfos); +} + +void JSRelativeContainer::ParseGuideline(const JSRef& args, GuidelineInfo& guidelineInfoItem) +{ + JSRef guildLineInfoObj = JSRef::Cast(args); + JSRef idVal = guildLineInfoObj->GetProperty("id"); + JSRef directionVal = guildLineInfoObj->GetProperty("direction"); + JSRef positionVal = guildLineInfoObj->GetProperty("position"); + + if (idVal->IsString()) { + guidelineInfoItem.id = idVal->ToString(); + } + + if (directionVal->IsNumber()) { + auto direction = directionVal->ToNumber(); + guidelineInfoItem.direction = static_cast(direction); + } + + CalcDimension start; + CalcDimension end; + if (positionVal->IsObject()) { + JSRef val = JSRef::Cast(positionVal); + JSRef startVal = val->GetProperty("start"); + JSRef endVal = val->GetProperty("end"); + + if (JSViewAbstract::ParseJsDimensionVpNG(startVal, start)) { + guidelineInfoItem.start = start; + } + if (JSViewAbstract::ParseJsDimensionVpNG(endVal, end)) { + guidelineInfoItem.end = end; + } + } +} + +void JSRelativeContainer::JsGuideline(const JSCallbackInfo& info) +{ + auto tmpInfo = info[0]; + std::vector guidelineInfos; + if (tmpInfo->IsUndefined()) { + RelativeContainerModel::GetInstance()->SetGuideline(guidelineInfos); + return; + } + if (!tmpInfo->IsArray() && !tmpInfo->IsObject()) { + RelativeContainerModel::GetInstance()->SetGuideline(guidelineInfos); + return; + } + + if (tmpInfo->IsArray()) { + JSRef array = JSRef::Cast(tmpInfo); + for (size_t i = 0; i < array->Length(); i++) { + GuidelineInfo guidelineInfoItem; + ParseGuideline(array->GetValueAt(i), guidelineInfoItem); + guidelineInfos.emplace_back(guidelineInfoItem); + } + } + RelativeContainerModel::GetInstance()->SetGuideline(guidelineInfos); +} } // namespace OHOS::Ace::Framework diff --git a/frameworks/bridge/declarative_frontend/jsview/js_relative_container.h b/frameworks/bridge/declarative_frontend/jsview/js_relative_container.h index a63453e184fcbebc3466fd071cb17d012a4c2b34..b3c9a141c86b2881e0bbbf92db13db685a83683f 100644 --- a/frameworks/bridge/declarative_frontend/jsview/js_relative_container.h +++ b/frameworks/bridge/declarative_frontend/jsview/js_relative_container.h @@ -24,6 +24,10 @@ class JSRelativeContainer : public JSContainerBase { public: static void Create(const JSCallbackInfo& info); static void JSBind(BindingTarget globalObj); + static void ParseBarrierInfo(const JSRef& args, BarrierInfo& barrierInfoItem); + static void JsBarrier(const JSCallbackInfo& info); + static void ParseGuideline(const JSRef& args, GuidelineInfo& guidelineInfoItem); + static void JsGuideline(const JSCallbackInfo& info); }; } // namespace OHOS::Ace::Framework diff --git a/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.cpp b/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.cpp index dfd9b951d6765420c00af30179fb689b21276963..a34f700abe7ebc9a69a67ab487f787607bb71981 100755 --- a/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.cpp +++ b/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.cpp @@ -6680,6 +6680,7 @@ void JSViewAbstract::JSBind(BindingTarget globalObj) JSClass::StaticMethod("accessibilityVirtualNode", &JSViewAbstract::JsAccessibilityVirtualNode); JSClass::StaticMethod("onAccessibility", &JSInteractableView::JsOnAccessibility); JSClass::StaticMethod("alignRules", &JSViewAbstract::JsAlignRules); + JSClass::StaticMethod("chainStyle", &JSViewAbstract::JsChainStyle); JSClass::StaticMethod("onVisibleAreaChange", &JSViewAbstract::JsOnVisibleAreaChange); JSClass::StaticMethod("hitTestBehavior", &JSViewAbstract::JsHitTestBehavior); JSClass::StaticMethod("onChildTouchTest", &JSViewAbstract::JsOnChildTouchTest); @@ -6796,6 +6797,20 @@ void JSViewAbstract::JsAlignRules(const JSCallbackInfo& info) ViewAbstractModel::GetInstance()->SetBias(biasPair); } +void JSViewAbstract::JsChainStyle(const JSCallbackInfo& info) +{ + ChainInfo chainInfo; + if (info.Length() >= 1 && info[0]->IsNumber()) { + auto direction = info[0]->ToNumber(); + chainInfo.direction = static_cast(direction); + } + if (info.Length() >= 2 && info[1]->IsNumber()) { // 2 : two args + auto style = info[1]->ToNumber(); + chainInfo.style = static_cast(style); + } + ViewAbstractModel::GetInstance()->SetChainStyle(chainInfo); +} + void JSViewAbstract::SetMarginTop(const JSCallbackInfo& info) { CalcDimension value; diff --git a/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.h b/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.h index 63bda63276830d366de0094856ff787e1cbd27dd..48caca9082e98a974c042df0e0a0a58910311d86 100755 --- a/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.h +++ b/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.h @@ -267,6 +267,7 @@ public: static void JsOverlay(const JSCallbackInfo& info); static Alignment ParseAlignment(int32_t align); static void JsAlignRules(const JSCallbackInfo& info); + static void JsChainStyle(const JSCallbackInfo& info); static void SetVisibility(const JSCallbackInfo& info); static void Pop(); diff --git a/frameworks/bridge/declarative_frontend/jsview/models/relative_container_model_impl.h b/frameworks/bridge/declarative_frontend/jsview/models/relative_container_model_impl.h index 4d421ec291e577874e7e29814e272ab7a4623425..439fe9742293cd7034012af6bfb5af20c8b1a445 100644 --- a/frameworks/bridge/declarative_frontend/jsview/models/relative_container_model_impl.h +++ b/frameworks/bridge/declarative_frontend/jsview/models/relative_container_model_impl.h @@ -24,6 +24,8 @@ namespace OHOS::Ace::Framework { class ACE_EXPORT RelativeContainerModelImpl : public OHOS::Ace::RelativeContainerModel { public: void Create() override; + void SetBarrier(const std::vector& barrierInfo) override {} + void SetGuideline(const std::vector& guidelineInfo) override {} }; } // namespace OHOS::Ace::Framework diff --git a/frameworks/bridge/declarative_frontend/jsview/models/view_abstract_model_impl.h b/frameworks/bridge/declarative_frontend/jsview/models/view_abstract_model_impl.h index a1b05245b2471de5cc800db26473c107c3895191..9345b9c20e17ec3f8f4b609ed1bce78c32f56fc1 100755 --- a/frameworks/bridge/declarative_frontend/jsview/models/view_abstract_model_impl.h +++ b/frameworks/bridge/declarative_frontend/jsview/models/view_abstract_model_impl.h @@ -90,6 +90,7 @@ public: void ResetAspectRatio() override {}; void SetAlign(const Alignment& alignment) override; void SetAlignRules(const std::map& alignRules) override; + void SetChainStyle(const ChainInfo& chainInfo) override {} void SetBias(const BiasPair& biasPair) override {} void SetUseAlign( AlignDeclarationPtr declaration, AlignDeclaration::Edge edge, const std::optional& offset) override; diff --git a/frameworks/core/components/common/layout/position_param.h b/frameworks/core/components/common/layout/position_param.h index 0f8eaac994de3fb43528cbea1b552e9cfd340c9a..2cb6f0b921bf6ae7a5ad7ee7c0f4d4b691f35691 100644 --- a/frameworks/core/components/common/layout/position_param.h +++ b/frameworks/core/components/common/layout/position_param.h @@ -55,6 +55,58 @@ struct AlignRule { } }; +enum class ChainStyle { + SPREAD, + SPREAD_INSIDE, + PACKED, +}; + +enum class LineDirection { + VERTICAL, + HORIZONTAL, +}; + +enum class BarrierDirection { + LEFT, + RIGHT, + TOP, + BOTTOM, +}; + +struct GuidelineInfo { + std::string id; + LineDirection direction = LineDirection::VERTICAL; + std::optional start; + std::optional end; + + bool operator==(const GuidelineInfo& right) const + { + return ((this->id == right.id) && (this->direction == right.direction) && + (this->start == right.start) && (this->end == right.end)); + } +}; + +struct ChainInfo { + LineDirection direction = LineDirection::VERTICAL; + ChainStyle style = ChainStyle::SPREAD; + + bool operator==(const ChainInfo& right) const + { + return ((this->direction == right.direction) && (this->style == right.style)); + } +}; + +struct BarrierInfo { + std::string id; + BarrierDirection direction = BarrierDirection::LEFT; + std::vector referencedId; + + bool operator==(const BarrierInfo& right) const + { + return ((this->id == right.id) && (this->direction == right.direction) && + (this->referencedId == right.referencedId)); + } +}; } // namespace OHOS::Ace #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_BASE_LAYOUT_POSITION_PARAM_H diff --git a/frameworks/core/components/flex/flex_item_component.h b/frameworks/core/components/flex/flex_item_component.h index 9e437e3a159caf5f5251e2a26141bdcd451e48dd..49e1e0c0477663f39b7d81089fa19ad622a353a6 100644 --- a/frameworks/core/components/flex/flex_item_component.h +++ b/frameworks/core/components/flex/flex_item_component.h @@ -191,6 +191,8 @@ public: return nullptr; } } + void SetChainStyle(const ChainInfo& chainInfo) {} + void SetAlignRules(const std::map& alignRules) { alignRules_ = alignRules; diff --git a/frameworks/core/components_ng/base/view_abstract.cpp b/frameworks/core/components_ng/base/view_abstract.cpp index e7b7c048b2bf7836ebcdb8e9efb3b0827b526a36..927598cc2f7238419e487e464e84979f345c9cd3 100755 --- a/frameworks/core/components_ng/base/view_abstract.cpp +++ b/frameworks/core/components_ng/base/view_abstract.cpp @@ -406,6 +406,14 @@ void ViewAbstract::SetAlignRules(const std::map &alig ACE_UPDATE_LAYOUT_PROPERTY(LayoutProperty, AlignRules, alignRules); } +void ViewAbstract::SetChainStyle(const ChainInfo& chainInfo) +{ + if (!ViewStackProcessor::GetInstance()->IsCurrentVisualStateProcess()) { + return; + } + ACE_UPDATE_LAYOUT_PROPERTY(LayoutProperty, ChainStyle, chainInfo); +} + void ViewAbstract::SetBias(const BiasPair& biasPair) { if (!ViewStackProcessor::GetInstance()->IsCurrentVisualStateProcess()) { @@ -2593,6 +2601,12 @@ void ViewAbstract::SetAlignRules(FrameNode* frameNode, const std::map span, std::optional offset, GridSizeType type) { diff --git a/frameworks/core/components_ng/base/view_abstract.h b/frameworks/core/components_ng/base/view_abstract.h index 779b53b238695dc9dbd9b71e19f8d479672588b6..9a6909efcd93ff4da99d96311d91da0305a71915 100644 --- a/frameworks/core/components_ng/base/view_abstract.h +++ b/frameworks/core/components_ng/base/view_abstract.h @@ -183,6 +183,7 @@ public: // layout static void SetAlign(Alignment alignment); static void SetAlignRules(const std::map &alignRules); + static void SetChainStyle(const ChainInfo& chainInfo); static void SetBias(const BiasPair& biasPair); static void SetVisibility(VisibleType visible); static void SetGrid(std::optional span, std::optional offset, @@ -444,6 +445,7 @@ public: static void SetMinHeight(FrameNode* frameNode, const CalcLength& minHeight); static void SetMaxHeight(FrameNode* frameNode, const CalcLength& maxHeight); static void SetAlignRules(FrameNode* frameNode, const std::map& alignRules); + static void SetChainStyle(FrameNode* frameNode, const ChainInfo& chainInfo); static void SetGrid(FrameNode* frameNode, std::optional span, std::optional offset, GridSizeType type = GridSizeType::UNDEFINED); static void ResetAspectRatio(FrameNode* frameNode); diff --git a/frameworks/core/components_ng/base/view_abstract_model.h b/frameworks/core/components_ng/base/view_abstract_model.h index 9f5a6357a5674b0267c0fa9d753ccd3bc2bf8855..6af470e7c3f153a4353698eda8ad87311b0f618a 100755 --- a/frameworks/core/components_ng/base/view_abstract_model.h +++ b/frameworks/core/components_ng/base/view_abstract_model.h @@ -133,6 +133,7 @@ public: virtual void ResetAspectRatio() = 0; virtual void SetAlign(const Alignment& alignment) = 0; virtual void SetAlignRules(const std::map& alignRules) = 0; + virtual void SetChainStyle(const ChainInfo& chainInfo) = 0; virtual void SetBias(const BiasPair& biasPair) = 0; virtual void SetUseAlign( AlignDeclarationPtr declaration, AlignDeclaration::Edge edge, const std::optional& offset) = 0; diff --git a/frameworks/core/components_ng/base/view_abstract_model_ng.h b/frameworks/core/components_ng/base/view_abstract_model_ng.h index 2d21eb4e9e5d5ed72e537932b5c74fc4eb4127f3..bc57546d4adf16c9b942bffb10439bf2d588268c 100755 --- a/frameworks/core/components_ng/base/view_abstract_model_ng.h +++ b/frameworks/core/components_ng/base/view_abstract_model_ng.h @@ -430,6 +430,11 @@ public: ViewAbstract::SetAlignRules(alignRules); } + void SetChainStyle(const ChainInfo& chainInfo) override + { + ViewAbstract::SetChainStyle(chainInfo); + } + void SetBias(const BiasPair& biasPair) override { ViewAbstract::SetBias(biasPair); diff --git a/frameworks/core/components_ng/layout/layout_property.cpp b/frameworks/core/components_ng/layout/layout_property.cpp index 062310ef189471a0ce8f9ba0cd3940b88a98c87a..69adfcd0a75ecc6b6692581f4218d35aa4f82051 100644 --- a/frameworks/core/components_ng/layout/layout_property.cpp +++ b/frameworks/core/components_ng/layout/layout_property.cpp @@ -936,6 +936,22 @@ void LayoutProperty::UpdateAlignRules(const std::map& } } +void LayoutProperty::UpdateChainStyle(const ChainInfo& chainInfo) +{ + if (!flexItemProperty_) { + flexItemProperty_ = std::make_unique(); + } + if (chainInfo.direction == LineDirection::HORIZONTAL) { + if (flexItemProperty_->UpdateHorizontalChainStyle(chainInfo)) { + propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE; + } + } else { + if (flexItemProperty_->UpdateVerticalChainStyle(chainInfo)) { + propertyChangeFlag_ = propertyChangeFlag_ | PROPERTY_UPDATE_MEASURE; + } + } +} + void LayoutProperty::UpdateBias(const BiasPair& biasPair) { if (!flexItemProperty_) { diff --git a/frameworks/core/components_ng/layout/layout_property.h b/frameworks/core/components_ng/layout/layout_property.h index fae3fd686fd93542ea0bb2b1acef1726c38beee8..606f82a5d515a3e4d332e29806e7efbd9162b2bd 100644 --- a/frameworks/core/components_ng/layout/layout_property.h +++ b/frameworks/core/components_ng/layout/layout_property.h @@ -210,6 +210,8 @@ public: void UpdateAlignRules(const std::map& alignRules); + void UpdateChainStyle(const ChainInfo& chainInfo); + void UpdateBias(const BiasPair& biasPair); void UpdateDisplayIndex(int32_t displayIndex); diff --git a/frameworks/core/components_ng/pattern/relative_container/relative_container_layout_algorithm.cpp b/frameworks/core/components_ng/pattern/relative_container/relative_container_layout_algorithm.cpp index 47d5f83386fc14d7a65378cba99face90aaeaaff..fd043fd2c19864a4ceb2a99c4bac4e5fbf065370 100644 --- a/frameworks/core/components_ng/pattern/relative_container/relative_container_layout_algorithm.cpp +++ b/frameworks/core/components_ng/pattern/relative_container/relative_container_layout_algorithm.cpp @@ -44,13 +44,8 @@ float RelativeContainerLayoutAlgorithm::GetVerticalAlignTopValue( std::string& anchor, std::optional& marginTop) { auto result = 0.0f; - if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) { - result = IsAnchorContainer(anchor) ? 0.0f : recordOffsetMap_[anchor].GetY(); - } else { - result = IsAnchorContainer(anchor) - ? 0.0f - : recordOffsetMap_[anchor].GetY() + marginTop.value_or(0); - } + auto extraMargin = Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN) ? 0.0f : marginTop.value_or(0); + result = IsAnchorContainer(anchor) ? 0.0f : recordOffsetMap_[anchor].GetY() + extraMargin; return result; } @@ -100,7 +95,9 @@ void RelativeContainerLayoutAlgorithm::UpdateVerticalTwoAlignValues( std::optional marginTop; if (!IsAnchorContainer(alignRule.anchor)) { auto anchorWrapper = idNodeMap_[alignRule.anchor]; - marginTop = anchorWrapper->GetGeometryNode()->GetMargin()->top; + if (anchorWrapper->GetGeometryNode()->GetMargin()) { + marginTop = anchorWrapper->GetGeometryNode()->GetMargin()->top; + } } switch (alignRule.vertical) { case VerticalAlign::TOP: @@ -128,13 +125,8 @@ float RelativeContainerLayoutAlgorithm::GetHorizontalAlignStartValue( std::string& anchor, std::optional& marginLeft) { auto result = 0.0f; - if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) { - result = IsAnchorContainer(anchor) ? 0.0f : recordOffsetMap_[anchor].GetX(); - } else { - result = IsAnchorContainer(anchor) - ? 0.0f - : recordOffsetMap_[anchor].GetX() + marginLeft.value_or(0); - } + auto extraMargin = Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN) ? 0.0f : marginLeft.value_or(0); + result = IsAnchorContainer(anchor) ? 0.0f : recordOffsetMap_[anchor].GetX() + extraMargin; return result; } @@ -184,7 +176,9 @@ void RelativeContainerLayoutAlgorithm::UpdateHorizontalTwoAlignValues( std::optional marginLeft; if (!IsAnchorContainer(alignRule.anchor)) { auto anchorWrapper = idNodeMap_[alignRule.anchor]; - marginLeft = anchorWrapper->GetGeometryNode()->GetMargin()->left; + if (anchorWrapper->GetGeometryNode()->GetMargin()) { + marginLeft = anchorWrapper->GetGeometryNode()->GetMargin()->left; + } } switch (alignRule.horizontal) { case HorizontalAlign::START: @@ -216,6 +210,8 @@ void RelativeContainerLayoutAlgorithm::DetermineTopologicalOrder(LayoutWrapper* reliedOnMap_.clear(); recordOffsetMap_.clear(); incomingDegreeMap_.clear(); + horizontalChainNodeMap_.clear(); + verticalChainNodeMap_.clear(); auto layoutConstraint = relativeContainerLayoutProperty->GetLayoutConstraint(); auto idealSize = CreateIdealSize(layoutConstraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT); containerSizeWithoutPaddingBorder_ = idealSize.ConvertToSizeT(); @@ -226,6 +222,7 @@ void RelativeContainerLayoutAlgorithm::DetermineTopologicalOrder(LayoutWrapper* MinusPaddingToSize(padding_, containerSizeWithoutPaddingBorder_); } CollectNodesById(layoutWrapper); + CheckChain(layoutWrapper); GetDependencyRelationship(); if (!PreTopologicalLoopDetection()) { const auto& childrenWrappers = layoutWrapper->GetAllChildrenWithBuild(); @@ -267,6 +264,605 @@ void RelativeContainerLayoutAlgorithm::UpdateSizeWhenChildrenEmpty(LayoutWrapper } } +void RelativeContainerLayoutAlgorithm::CalcHorizontalGuideline( + std::optional& selfIdealSize, const GuidelineInfo& guidelineInfo) +{ + ScaleProperty scaleProperty = ScaleProperty::CreateScaleProperty(); + bool widthAuto = (selfIdealSize->Width()->GetDimension().Unit() == DimensionUnit::AUTO); + if (guidelineInfo.start.has_value()) { + if (guidelineInfo.start.value().Unit() == DimensionUnit::PERCENT && widthAuto) { + guidelines_[guidelineInfo.id] = std::make_pair(LineDirection::HORIZONTAL, 0.0f); + } else { + auto start = ConvertToPx(guidelineInfo.start.value(), + scaleProperty, selfIdealSize->Width()->GetDimension().Value()); + guidelines_[guidelineInfo.id] = std::make_pair(LineDirection::HORIZONTAL, start.value_or(0)); + } + } else if (guidelineInfo.end.has_value()) { + if (widthAuto) { + guidelines_[guidelineInfo.id] = std::make_pair(LineDirection::HORIZONTAL, 0.0f); + } else { + auto end = ConvertToPx(guidelineInfo.end.value(), + scaleProperty, selfIdealSize->Width()->GetDimension().Value()); + guidelines_[guidelineInfo.id] = std::make_pair( + LineDirection::HORIZONTAL, (selfIdealSize->Width()->GetDimension().Value() - end.value_or(0))); + } + } +} + +void RelativeContainerLayoutAlgorithm::CalcVerticalGuideline( + std::optional& selfIdealSize, const GuidelineInfo& guidelineInfo) +{ + ScaleProperty scaleProperty = ScaleProperty::CreateScaleProperty(); + bool heightAuto = (selfIdealSize->Height()->GetDimension().Unit() == DimensionUnit::AUTO); + if (guidelineInfo.start.has_value()) { + if (guidelineInfo.start.value().Unit() == DimensionUnit::PERCENT && heightAuto) { + guidelines_[guidelineInfo.id] = std::make_pair(LineDirection::VERTICAL, 0.0f); + } else { + auto start = ConvertToPx(guidelineInfo.start.value(), scaleProperty, + selfIdealSize->Height()->GetDimension().Value()); + guidelines_[guidelineInfo.id] = std::make_pair(LineDirection::VERTICAL, start.value_or(0)); + } + } else if (guidelineInfo.end.has_value()) { + if (heightAuto) { + guidelines_[guidelineInfo.id] = std::make_pair(LineDirection::VERTICAL, 0.0f); + } else { + auto end = ConvertToPx(guidelineInfo.end.value(), scaleProperty, + selfIdealSize->Height()->GetDimension().Value()); + guidelines_[guidelineInfo.id] = std::make_pair( + LineDirection::VERTICAL, (selfIdealSize->Height()->GetDimension().Value() - end.value_or(0))); + } + } +} + +void RelativeContainerLayoutAlgorithm::CalcBarrier(LayoutWrapper* layoutWrapper) +{ + if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) { + return; + } + CHECK_NULL_VOID(layoutWrapper); + auto layoutProperty = DynamicCast(layoutWrapper->GetLayoutProperty()); + CHECK_NULL_VOID(layoutProperty); + + barriers_.clear(); + if (!layoutProperty->HasBarrier()) { + return; + } + + for (const auto& barrierInfo : layoutProperty->GetBarrierValue()) { + barriers_[barrierInfo.id] = std::make_pair(barrierInfo.direction, barrierInfo.referencedId); + } +} + +void RelativeContainerLayoutAlgorithm::CalcGuideline(LayoutWrapper* layoutWrapper) +{ + if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) { + return; + } + CHECK_NULL_VOID(layoutWrapper); + auto layoutProperty = DynamicCast(layoutWrapper->GetLayoutProperty()); + CHECK_NULL_VOID(layoutProperty); + const auto& calcLayoutConstraint = layoutProperty->GetCalcLayoutConstraint(); + CHECK_NULL_VOID(calcLayoutConstraint); + auto selfIdealSize = calcLayoutConstraint->selfIdealSize; + + guidelines_.clear(); + if (!layoutProperty->HasGuideline()) { + return; + } + + for (const auto& guidelineInfo : layoutProperty->GetGuidelineValue()) { + if (guidelineInfo.direction == LineDirection::HORIZONTAL) { + CalcHorizontalGuideline(selfIdealSize, guidelineInfo); + } else { + CalcVerticalGuideline(selfIdealSize, guidelineInfo); + } + } + + for (const auto& guideline : guidelines_) { + if (guideline.second.first == LineDirection::HORIZONTAL) { + recordOffsetMap_[guideline.first] = OffsetF(0.0f, guideline.second.second); + } else { + recordOffsetMap_[guideline.first] = OffsetF(guideline.second.second, 0.0f); + } + } +} + +bool RelativeContainerLayoutAlgorithm::IsGuideline(const std::string& id) +{ + if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) { + return false; + } + CHECK_NULL_RETURN(!guidelines_.empty(), false); + if (guidelines_.find(id) == guidelines_.end()) { + return false; + } + + return true; +} + +bool RelativeContainerLayoutAlgorithm::IsBarrier(const std::string& id) +{ + if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) { + return false; + } + CHECK_NULL_RETURN(!barriers_.empty(), false); + + if (barriers_.find(id) == barriers_.end()) { + return false; + } + + return true; +} + +RelativeContainerLayoutAlgorithm::BarrierRect RelativeContainerLayoutAlgorithm::GetBarrierRectByReferencedIds( + const std::vector& referencedIds) +{ + BarrierRect barrierRect; + for (const auto& nodeName : referencedIds) { + if (IsGuideline(nodeName)) { + if (guidelines_[nodeName].first == LineDirection::HORIZONTAL) { + barrierRect.minLeft = std::min(barrierRect.minLeft, recordOffsetMap_[nodeName].GetX()); + barrierRect.maxRight = std::max(barrierRect.maxRight, recordOffsetMap_[nodeName].GetX()); + } else { + barrierRect.minTop = std::min(barrierRect.minTop, recordOffsetMap_[nodeName].GetY()); + barrierRect.maxBottom = std::max(barrierRect.maxBottom, recordOffsetMap_[nodeName].GetY()); + } + continue; + } + + if (IsBarrier(nodeName)) { + switch (barriers_[nodeName].first) { + case BarrierDirection::LEFT: + barrierRect.minLeft = std::min(barrierRect.minLeft, recordOffsetMap_[nodeName].GetX()); + break; + case BarrierDirection::RIGHT: + barrierRect.maxRight = std::max(barrierRect.maxRight, recordOffsetMap_[nodeName].GetX()); + break; + case BarrierDirection::TOP: + barrierRect.minTop = std::min(barrierRect.minTop, recordOffsetMap_[nodeName].GetY()); + break; + case BarrierDirection::BOTTOM: + barrierRect.maxBottom = std::max(barrierRect.maxBottom, recordOffsetMap_[nodeName].GetY()); + break; + default: + break; + } + continue; + } + + auto childWrapper = idNodeMap_[nodeName]; + if (childWrapper->GetLayoutProperty()->GetVisibility() == VisibleType::GONE) { + continue; + } + + barrierRect.minLeft = std::min(barrierRect.minLeft, recordOffsetMap_[nodeName].GetX()); + barrierRect.minTop = std::min(barrierRect.minTop, recordOffsetMap_[nodeName].GetY()); + barrierRect.maxRight = std::max(barrierRect.maxRight, recordOffsetMap_[nodeName].GetX() + + childWrapper->GetGeometryNode()->GetMarginFrameSize().Width()); + barrierRect.maxBottom = std::max(barrierRect.maxBottom, recordOffsetMap_[nodeName].GetY() + + childWrapper->GetGeometryNode()->GetMarginFrameSize().Height()); + } + return barrierRect; +} + +void RelativeContainerLayoutAlgorithm::MeasureBarrier(const std::string& barrierName) +{ + BarrierRect barrierRect = GetBarrierRectByReferencedIds(barriers_[barrierName].second); + switch (barriers_[barrierName].first) { + case BarrierDirection::LEFT: + recordOffsetMap_[barrierName] = OffsetF(barrierRect.minLeft, 0.0f); + break; + case BarrierDirection::RIGHT: + recordOffsetMap_[barrierName] = OffsetF(barrierRect.maxRight, 0.0f); + break; + case BarrierDirection::TOP: + recordOffsetMap_[barrierName] = OffsetF(0.0f, barrierRect.minTop); + break; + case BarrierDirection::BOTTOM: + recordOffsetMap_[barrierName] = OffsetF(0.0f, barrierRect.maxBottom); + break; + default: + break; + } +} + +void RelativeContainerLayoutAlgorithm::CheckNodeInHorizontalChain(std::string& currentNode, std::string& nextNode, + AlignRulesItem& currentAlignRules, std::vector& chainNodes, AlignRule& rightAnchor) +{ + while (idNodeMap_.find(nextNode) != idNodeMap_.end()) { + if (currentAlignRules[AlignDirection::RIGHT].horizontal != HorizontalAlign::START) { + break; + } + auto nextNodeWrapper = idNodeMap_[nextNode]; + const auto& nextNodeFlexItem = nextNodeWrapper->GetLayoutProperty()->GetFlexItemProperty(); + if (!nextNodeFlexItem) { + break; + } + AlignRulesItem nextNodeAlignRules = nextNodeFlexItem->GetAlignRulesValue(); + if (nextNodeAlignRules.find(AlignDirection::LEFT) == nextNodeAlignRules.end() || + nextNodeAlignRules.find(AlignDirection::RIGHT) == nextNodeAlignRules.end()) { + break; + } + if (nextNodeAlignRules[AlignDirection::LEFT].anchor != currentNode || + nextNodeAlignRules[AlignDirection::LEFT].horizontal != HorizontalAlign::END) { + break; + } + + chainNodes.emplace_back(nextNode); + currentNode = nextNode; + currentAlignRules = nextNodeAlignRules; + nextNode = nextNodeAlignRules[AlignDirection::RIGHT].anchor; + rightAnchor = nextNodeAlignRules[AlignDirection::RIGHT]; + } +} + +void RelativeContainerLayoutAlgorithm::CheckHorizontalChain(const RefPtr& childWrapper) +{ + auto childHostNode = childWrapper->GetHostNode(); + const auto& flexItem = childWrapper->GetLayoutProperty()->GetFlexItemProperty(); + AlignRulesItem currentAlignRules = flexItem->GetAlignRulesValue(); + ChainInfo chainInfo = flexItem->GetHorizontalChainStyleValue(); + BiasPair bias(0.5f, 0.5f); + if (flexItem->HasBias()) { + bias = flexItem->GetBiasValue(); + } + if (currentAlignRules.find(AlignDirection::LEFT) == currentAlignRules.end() || + currentAlignRules.find(AlignDirection::RIGHT) == currentAlignRules.end()) { + return; + } + + AlignRule leftAnchor = currentAlignRules[AlignDirection::LEFT]; + if (idNodeMap_.find(leftAnchor.anchor) == idNodeMap_.end() && !IsBarrier(leftAnchor.anchor) && + !IsGuideline(leftAnchor.anchor) && !IsAnchorContainer(leftAnchor.anchor)) { + // left anchor is illegal + return; + } + + AlignRule rightAnchor = currentAlignRules[AlignDirection::RIGHT]; + std::string currentNode = childHostNode->GetInspectorIdValue(); + std::string nextNode = rightAnchor.anchor; + std::vector chainNodes; + chainNodes.emplace_back(currentNode); + + CheckNodeInHorizontalChain(currentNode, nextNode, currentAlignRules, chainNodes, rightAnchor); + + if (chainNodes.size() <= 1) { + return; + } + + ChainParam chainParam; + chainParam.ids = chainNodes; + chainParam.anchorHead = leftAnchor; + chainParam.anchorTail = rightAnchor; + chainParam.isCalculated = false; + chainParam.chainStyle = chainInfo.style; + chainParam.bias = bias; + for (const auto& id : chainParam.ids) { + chainParam.itemSize[id] = std::nullopt; + horizontalChainNodeMap_[id] = childHostNode->GetInspectorIdValue(); + } + horizontalChains_[childHostNode->GetInspectorIdValue()] = chainParam; +} + +void RelativeContainerLayoutAlgorithm::CheckNodeInVerticalChain(std::string& currentNode, std::string& nextNode, + AlignRulesItem& currentAlignRules, std::vector& chainNodes, AlignRule& bottomAnchor) +{ + while (idNodeMap_.find(nextNode) != idNodeMap_.end()) { + if (currentAlignRules[AlignDirection::BOTTOM].vertical != VerticalAlign::TOP) { + break; + } + auto nextNodeWrapper = idNodeMap_[nextNode]; + const auto& nextNodeFlexItem = nextNodeWrapper->GetLayoutProperty()->GetFlexItemProperty(); + if (!nextNodeFlexItem) { + break; + } + AlignRulesItem nextNodeAlignRules = nextNodeFlexItem->GetAlignRulesValue(); + if (nextNodeAlignRules.find(AlignDirection::TOP) == nextNodeAlignRules.end() || + nextNodeAlignRules.find(AlignDirection::BOTTOM) == nextNodeAlignRules.end()) { + break; + } + if (nextNodeAlignRules[AlignDirection::TOP].anchor != currentNode || + nextNodeAlignRules[AlignDirection::TOP].vertical != VerticalAlign::BOTTOM) { + break; + } + + chainNodes.emplace_back(nextNode); + currentNode = nextNode; + currentAlignRules = nextNodeAlignRules; + nextNode = nextNodeAlignRules[AlignDirection::BOTTOM].anchor; + bottomAnchor = nextNodeAlignRules[AlignDirection::BOTTOM]; + } +} + +void RelativeContainerLayoutAlgorithm::CheckVerticalChain(const RefPtr& childWrapper) +{ + auto childHostNode = childWrapper->GetHostNode(); + const auto& flexItem = childWrapper->GetLayoutProperty()->GetFlexItemProperty(); + AlignRulesItem currentAlignRules = flexItem->GetAlignRulesValue(); + ChainInfo chainInfo = flexItem->GetVerticalChainStyleValue(); + BiasPair bias(0.5f, 0.5f); + if (flexItem->HasBias()) { + bias = flexItem->GetBiasValue(); + } + if (currentAlignRules.find(AlignDirection::TOP) == currentAlignRules.end() || + currentAlignRules.find(AlignDirection::BOTTOM) == currentAlignRules.end()) { + return; + } + + AlignRule topAnchor = currentAlignRules[AlignDirection::TOP]; + if (idNodeMap_.find(topAnchor.anchor) == idNodeMap_.end() && !IsBarrier(topAnchor.anchor) && + !IsGuideline(topAnchor.anchor) && !IsAnchorContainer(topAnchor.anchor)) { + // top anchor is illegal + return; + } + + AlignRule bottomAnchor = currentAlignRules[AlignDirection::BOTTOM]; + std::string currentNode = childHostNode->GetInspectorIdValue(); + std::string nextNode = bottomAnchor.anchor; + std::vector chainNodes; + chainNodes.emplace_back(currentNode); + + CheckNodeInVerticalChain(currentNode, nextNode, currentAlignRules, chainNodes, bottomAnchor); + + if (chainNodes.size() <= 1) { + return; + } + + ChainParam chainParam; + chainParam.ids = chainNodes; + chainParam.anchorHead = topAnchor; + chainParam.anchorTail = bottomAnchor; + chainParam.isCalculated = false; + chainParam.chainStyle = chainInfo.style; + chainParam.bias = bias; + for (const auto& id : chainParam.ids) { + chainParam.itemSize[id] = std::nullopt; + verticalChainNodeMap_[id] = childHostNode->GetInspectorIdValue(); + } + verticalChains_[childHostNode->GetInspectorIdValue()] = chainParam; +} + +void RelativeContainerLayoutAlgorithm::CheckChain(LayoutWrapper* layoutWrapper) +{ + if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) { + return; + } + horizontalChains_.clear(); + verticalChains_.clear(); + for (const auto& node : idNodeMap_) { + auto childWrapper = node.second; + auto childLayoutProperty = childWrapper->GetLayoutProperty(); + CHECK_NULL_VOID(childLayoutProperty); + const auto& flexItem = childLayoutProperty->GetFlexItemProperty(); + if (!flexItem) { + continue; + } + + std::string chainName; + if (flexItem->HasHorizontalChainStyle() && + !IsNodeInHorizontalChain(node.first, chainName)) { + CheckHorizontalChain(childWrapper); + } + + if (flexItem->HasVerticalChainStyle() && + !IsNodeInVerticalChain(node.first, chainName)) { + CheckVerticalChain(childWrapper); + } + } +} + +void RelativeContainerLayoutAlgorithm::RecordSizeInChain(const std::string& nodeName) +{ + if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) { + return; + } + auto childWrapper = idNodeMap_[nodeName]; + std::string chainName; + if (IsNodeInHorizontalChain(nodeName, chainName)) { + horizontalChains_[chainName].itemSize[nodeName] = + childWrapper->GetGeometryNode()->GetMarginFrameSize().Width(); + } + if (IsNodeInVerticalChain(nodeName, chainName)) { + verticalChains_[chainName].itemSize[nodeName] = + childWrapper->GetGeometryNode()->GetMarginFrameSize().Height(); + } +} + +bool RelativeContainerLayoutAlgorithm::IsNodeInHorizontalChain(const std::string& nodeName, std::string& chainName) +{ + if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) { + return false; + } + CHECK_NULL_RETURN(!horizontalChains_.empty(), false); + + if (horizontalChainNodeMap_.find(nodeName) != horizontalChainNodeMap_.end()) { + chainName = horizontalChainNodeMap_[nodeName]; + return true; + } + return false; +} +bool RelativeContainerLayoutAlgorithm::IsNodeInVerticalChain(const std::string& nodeName, std::string& chainName) +{ + if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) { + return false; + } + CHECK_NULL_RETURN(!verticalChains_.empty(), false); + + if (verticalChainNodeMap_.find(nodeName) != verticalChainNodeMap_.end()) { + chainName = verticalChainNodeMap_[nodeName]; + return true; + } + return false; +} + +float RelativeContainerLayoutAlgorithm::GetHorizontalAnchorValueByAlignRule(AlignRule& alignRule) +{ + if (IsGuideline(alignRule.anchor) || IsBarrier(alignRule.anchor)) { + return recordOffsetMap_[alignRule.anchor].GetX(); + } + + float anchorWidth = 0.0f; + if (IsAnchorContainer(alignRule.anchor)) { + anchorWidth = containerSizeWithoutPaddingBorder_.Width(); + } else { + anchorWidth = idNodeMap_[alignRule.anchor]->GetGeometryNode()->GetFrameSize().Width(); + } + + std::optional marginLeft; + if (!IsAnchorContainer(alignRule.anchor)) { + auto anchorWrapper = idNodeMap_[alignRule.anchor]; + if (anchorWrapper->GetGeometryNode()->GetMargin()) { + marginLeft = anchorWrapper->GetGeometryNode()->GetMargin()->left; + } + } + + float offsetX = 0.0f; + switch (alignRule.horizontal) { + case HorizontalAlign::START: + offsetX = 0.0f; + break; + case HorizontalAlign::CENTER: + offsetX = anchorWidth / 2.0f; + break; + case HorizontalAlign::END: + offsetX = anchorWidth; + break; + default: + break; + } + + offsetX += + IsAnchorContainer(alignRule.anchor) ? 0.0f : recordOffsetMap_[alignRule.anchor].GetX() + marginLeft.value_or(0); + return offsetX; +} + +float RelativeContainerLayoutAlgorithm::GetVerticalAnchorValueByAlignRule(AlignRule& alignRule) +{ + if (IsGuideline(alignRule.anchor) || IsBarrier(alignRule.anchor)) { + return recordOffsetMap_[alignRule.anchor].GetY(); + } + + float anchorHeight = 0.0f; + if (IsAnchorContainer(alignRule.anchor)) { + anchorHeight = containerSizeWithoutPaddingBorder_.Height(); + } else { + anchorHeight = idNodeMap_[alignRule.anchor]->GetGeometryNode()->GetFrameSize().Height(); + } + + std::optional marginTop; + if (!IsAnchorContainer(alignRule.anchor)) { + auto anchorWrapper = idNodeMap_[alignRule.anchor]; + if (anchorWrapper->GetGeometryNode()->GetMargin()->top) { + marginTop = anchorWrapper->GetGeometryNode()->GetMargin()->top; + } + } + + float offsetY = 0.0f; + switch (alignRule.vertical) { + case VerticalAlign::TOP: + offsetY = 0.0f; + break; + case VerticalAlign::CENTER: + offsetY = anchorHeight / 2.0f; + break; + case VerticalAlign::BOTTOM: + offsetY = anchorHeight; + break; + default: + break; + } + + offsetY += + IsAnchorContainer(alignRule.anchor) ? 0.0f : recordOffsetMap_[alignRule.anchor].GetY() + marginTop.value_or(0); + return offsetY; +} + +std::pair RelativeContainerLayoutAlgorithm::CalcOffsetInChainGetStart(const float& anchorDistance, + const float& contentSize, const ChainParam& chainParam, LineDirection direction) +{ + float spaceSize = 0.0f; + float start = 0.0f; + float bias = (direction == LineDirection::HORIZONTAL) ? chainParam.bias.first : chainParam.bias.second; + if (GreatOrEqual(anchorDistance, contentSize)) { + switch (chainParam.chainStyle) { + case ChainStyle::SPREAD: + spaceSize = (anchorDistance - contentSize) / (chainParam.ids.size() + 1); + start = spaceSize; + break; + case ChainStyle::SPREAD_INSIDE: + spaceSize = (anchorDistance - contentSize) / (chainParam.ids.size() - 1); + break; + case ChainStyle::PACKED: + spaceSize = 0.0f; + start = (anchorDistance - contentSize) * bias; + break; + default: + break; + } + } else { + switch (chainParam.chainStyle) { + case ChainStyle::SPREAD: + case ChainStyle::SPREAD_INSIDE: + start = (anchorDistance - contentSize) / 2.0f; + break; + case ChainStyle::PACKED: + start = (anchorDistance - contentSize) * bias; + break; + default: + break; + } + } + return { spaceSize, start }; +} + +bool RelativeContainerLayoutAlgorithm::CalcOffsetInChain(const std::string& chainName, LineDirection direction) +{ + float contentSize = 0.0f; + float anchorDistance = 0.0f; + float spaceSize = 0.0f; + float start = 0.0f; + float end = 0.0f; + std::unordered_map& chains = + (direction == LineDirection::HORIZONTAL) ? horizontalChains_ : verticalChains_; + if (chains[chainName].isCalculated) { + return true; + } + for (const auto& itemSize : chains[chainName].itemSize) { + if (!itemSize.second.has_value()) { + return false; + } + contentSize += itemSize.second.value(); + } + + if (direction == LineDirection::HORIZONTAL) { + start = GetHorizontalAnchorValueByAlignRule(chains[chainName].anchorHead); + end = GetHorizontalAnchorValueByAlignRule(chains[chainName].anchorTail); + } else { + start = GetVerticalAnchorValueByAlignRule(chains[chainName].anchorHead); + end = GetVerticalAnchorValueByAlignRule(chains[chainName].anchorTail); + } + anchorDistance = end - start; + std::pair spaceSizeAndStart = + CalcOffsetInChainGetStart(anchorDistance, contentSize, chains[chainName], direction); + spaceSize = spaceSizeAndStart.first; + start += spaceSizeAndStart.second; + float offset = start; + if (direction == LineDirection::HORIZONTAL) { + for (const auto& nodeName : chains[chainName].ids) { + recordOffsetMap_[nodeName] = OffsetF(offset, recordOffsetMap_[nodeName].GetY()); + offset += chains[chainName].itemSize[nodeName].value() + spaceSize; + } + } else { + for (const auto& nodeName : chains[chainName].ids) { + recordOffsetMap_[nodeName] = OffsetF(recordOffsetMap_[nodeName].GetX(), offset); + offset += chains[chainName].itemSize[nodeName].value() + spaceSize; + } + } + chains[chainName].isCalculated = true; + return true; +} + + void RelativeContainerLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper) { CHECK_NULL_VOID(layoutWrapper); @@ -277,6 +873,7 @@ void RelativeContainerLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper) return; } + CalcGuideline(layoutWrapper); DetermineTopologicalOrder(layoutWrapper); if (SystemProperties::GetDebugEnabled()) { std::string result = "["; @@ -288,7 +885,12 @@ void RelativeContainerLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper) } result += "]"; } + for (const auto& nodeName : renderList_) { + if (IsBarrier(nodeName)) { + MeasureBarrier(nodeName); + } + if (idNodeMap_.find(nodeName) == idNodeMap_.end()) { continue; } @@ -400,6 +1002,7 @@ void RelativeContainerLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper) void RelativeContainerLayoutAlgorithm::CollectNodesById(LayoutWrapper* layoutWrapper) { idNodeMap_.clear(); + CalcBarrier(layoutWrapper); auto relativeContainerLayoutProperty = layoutWrapper->GetLayoutProperty(); auto left = padding_.left.value_or(0); auto top = padding_.top.value_or(0); @@ -427,6 +1030,61 @@ void RelativeContainerLayoutAlgorithm::CollectNodesById(LayoutWrapper* layoutWra } } +void RelativeContainerLayoutAlgorithm::GetDependencyRelationshipInChain( + const std::string& anchor, const std::string& nodeName) +{ + if (IsAnchorContainer(anchor) || IsGuideline(anchor)) { + return; + } + if (IsBarrier(anchor) || idNodeMap_.find(anchor) != idNodeMap_.end()) { + InsertToReliedOnMap(anchor, nodeName); + } +} + +void RelativeContainerLayoutAlgorithm::GetDependencyRelationshipInBarrier() +{ + if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) { + return; + } + for (const auto& barrier : barriers_) { + for (const auto& nodeName : barrier.second.second) { + InsertToReliedOnMap(nodeName, barrier.first); + } + } +} + +bool RelativeContainerLayoutAlgorithm::IsAlignRuleInChain(const AlignDirection& direction, const std::string& nodeName) +{ + if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) { + return false; + } + std::string chainName; + if ((direction == AlignDirection::LEFT || direction == AlignDirection::RIGHT) && + IsNodeInHorizontalChain(nodeName, chainName)) { + GetDependencyRelationshipInChain(horizontalChains_[chainName].anchorHead.anchor, nodeName); + GetDependencyRelationshipInChain(horizontalChains_[chainName].anchorTail.anchor, nodeName); + return true; + } + if ((direction == AlignDirection::TOP || direction == AlignDirection::BOTTOM) && + IsNodeInVerticalChain(nodeName, chainName)) { + GetDependencyRelationshipInChain(verticalChains_[chainName].anchorHead.anchor, nodeName); + GetDependencyRelationshipInChain(verticalChains_[chainName].anchorTail.anchor, nodeName); + return true; + } + return false; +} + +void RelativeContainerLayoutAlgorithm::InsertToReliedOnMap(const std::string& anchorName, const std::string& nodeName) +{ + if (reliedOnMap_.count(anchorName) == 0) { + std::set reliedList; + reliedList.insert(nodeName); + reliedOnMap_[anchorName] = reliedList; + return; + } + reliedOnMap_[anchorName].insert(nodeName); +} + void RelativeContainerLayoutAlgorithm::GetDependencyRelationship() { for (const auto& node : idNodeMap_) { @@ -437,8 +1095,16 @@ void RelativeContainerLayoutAlgorithm::GetDependencyRelationship() continue; } for (const auto& alignRule : flexItem->GetAlignRulesValue()) { - if (IsAnchorContainer(alignRule.second.anchor) || - idNodeMap_.find(alignRule.second.anchor) == idNodeMap_.end()) { + if (IsAlignRuleInChain(alignRule.first, node.first)) { + continue; + } + + if (IsBarrier(alignRule.second.anchor)) { + InsertToReliedOnMap(alignRule.second.anchor, childHostNode->GetInspectorIdValue()); + continue; + } + + if (IsAnchorContainer(alignRule.second.anchor) || IsGuideline(alignRule.second.anchor)) { if (static_cast(alignRule.first) < HORIZONTAL_DIRECTION_RANGE) { isHorizontalRelyOnContainer_ = true; } else if (static_cast(alignRule.first) < VERTICAL_DIRECTION_RANGE) { @@ -446,6 +1112,10 @@ void RelativeContainerLayoutAlgorithm::GetDependencyRelationship() } continue; } + + if (idNodeMap_.find(alignRule.second.anchor) == idNodeMap_.end()) { + continue; + } auto anchorChildWrapper = idNodeMap_[alignRule.second.anchor]; auto anchorChildLayoutProp = anchorChildWrapper->GetLayoutProperty(); auto anchorChildVisibility = anchorChildLayoutProp->GetVisibility(); @@ -454,14 +1124,45 @@ void RelativeContainerLayoutAlgorithm::GetDependencyRelationship() } // if a is the anchor of b, then reliedOnMap should place for the first appearance // of key a. Otherwise b will be inserted into the exsiting value list - if (reliedOnMap_.count(alignRule.second.anchor) == 0) { - std::set reliedList; - reliedList.insert(childHostNode->GetInspectorIdValue()); - reliedOnMap_[alignRule.second.anchor] = reliedList; - continue; + InsertToReliedOnMap(alignRule.second.anchor, childHostNode->GetInspectorIdValue()); + } + } + + GetDependencyRelationshipInBarrier(); +} + +void RelativeContainerLayoutAlgorithm::PreTopologicalLoopDetectionGetAnchorSet(const std::string& nodeName, + const AlignRulesItem& alignRulesItem, std::set& anchorSet) +{ + for (const auto& alignRule : alignRulesItem) { + std::string anchor; + std::string chainName; + if (IsNodeInHorizontalChain(nodeName, chainName)) { + if (alignRule.first == AlignDirection::LEFT) { + anchor = horizontalChains_[chainName].anchorHead.anchor; + } else { + anchor = horizontalChains_[chainName].anchorTail.anchor; } - reliedOnMap_[alignRule.second.anchor].insert(childHostNode->GetInspectorIdValue()); + } else if (IsNodeInVerticalChain(nodeName, chainName)) { + if (alignRule.first == AlignDirection::TOP) { + anchor = verticalChains_[chainName].anchorHead.anchor; + } else { + anchor = verticalChains_[chainName].anchorTail.anchor; + } + } else { + anchor = alignRule.second.anchor; } + + if (IsBarrier(anchor)) { + anchorSet.insert(anchor); + continue; + } + + if (IsAnchorContainer(anchor) || IsGuideline(anchor) || + idNodeMap_.find(anchor) == idNodeMap_.end()) { + continue; + } + anchorSet.insert(anchor); } } @@ -480,18 +1181,28 @@ bool RelativeContainerLayoutAlgorithm::PreTopologicalLoopDetection() continue; } std::set anchorSet; - for (const auto& alignRule : flexItem->GetAlignRulesValue()) { - if (IsAnchorContainer(alignRule.second.anchor) || - idNodeMap_.find(alignRule.second.anchor) == idNodeMap_.end()) { - continue; - } - anchorSet.insert(alignRule.second.anchor); - } + PreTopologicalLoopDetectionGetAnchorSet(node.first, flexItem->GetAlignRulesValue(), anchorSet); incomingDegreeMap_[childHostNode->GetInspectorIdValue()] = anchorSet.size(); if (incomingDegreeMap_[childHostNode->GetInspectorIdValue()] == 0) { layoutQueue.push(childHostNode->GetInspectorIdValue()); } } + + for (const auto& barrier : barriers_) { + std::set anchorSet; + for (const auto& nodeName : barrier.second.second) { + if (IsBarrier(nodeName)) { + anchorSet.insert(nodeName); + continue; + } + if (IsGuideline(nodeName) || idNodeMap_.find(nodeName) == idNodeMap_.end()) { + continue; + } + anchorSet.insert(nodeName); + } + incomingDegreeMap_[barrier.first] = anchorSet.size(); + } + std::map incomingDegreeMapCopy; incomingDegreeMapCopy.insert(incomingDegreeMap_.begin(), incomingDegreeMap_.end()); while (!layoutQueue.empty()) { @@ -551,6 +1262,7 @@ void RelativeContainerLayoutAlgorithm::TopologicalSort(std::list& r void RelativeContainerLayoutAlgorithm::CalcSizeParam(LayoutWrapper* layoutWrapper, const std::string& nodeName) { + std::string chainName; if (idNodeMap_.find(nodeName) == idNodeMap_.end()) { return; } @@ -583,8 +1295,8 @@ void RelativeContainerLayoutAlgorithm::CalcSizeParam(LayoutWrapper* layoutWrappe std::optional childIdealHeight; for (const auto& alignRule : alignRules) { - if (idNodeMap_.find(alignRule.second.anchor) == idNodeMap_.end() && - !IsAnchorContainer(alignRule.second.anchor)) { + if (idNodeMap_.find(alignRule.second.anchor) == idNodeMap_.end() && !IsBarrier(alignRule.second.anchor) && + !IsAnchorContainer(alignRule.second.anchor) && !IsGuideline(alignRule.second.anchor)) { continue; } if (static_cast(alignRule.first) < HORIZONTAL_DIRECTION_RANGE) { @@ -613,10 +1325,12 @@ void RelativeContainerLayoutAlgorithm::CalcSizeParam(LayoutWrapper* layoutWrappe childFlexItemProperty->GetAlignValue(AlignDirection::LEFT), 0.0f); } - if (childIdealWidth.has_value() && LessOrEqual(childIdealWidth.value(), 0.0f)) { + if (childIdealWidth.has_value() && LessOrEqual(childIdealWidth.value(), 0.0f) && + !IsNodeInHorizontalChain(nodeName, chainName)) { childConstraint.selfIdealSize.SetWidth(0.0f); childConstraint.selfIdealSize.SetHeight(0.0f); childWrapper->Measure(childConstraint); + RecordSizeInChain(nodeName); return; } } @@ -638,10 +1352,12 @@ void RelativeContainerLayoutAlgorithm::CalcSizeParam(LayoutWrapper* layoutWrappe childFlexItemProperty->GetAlignValue(AlignDirection::TOP), 0.0f); } - if (childIdealHeight.has_value() && LessOrEqual(childIdealHeight.value(), 0.0f)) { + if (childIdealHeight.has_value() && LessOrEqual(childIdealHeight.value(), 0.0f) && + !IsNodeInVerticalChain(nodeName, chainName)) { childConstraint.selfIdealSize.SetWidth(0.0f); childConstraint.selfIdealSize.SetHeight(0.0f); childWrapper->Measure(childConstraint); + RecordSizeInChain(nodeName); return; } } @@ -649,6 +1365,7 @@ void RelativeContainerLayoutAlgorithm::CalcSizeParam(LayoutWrapper* layoutWrappe // for api 11 or larger, alignRules will not effect child component size as described in doc if (horizontalHasIdealSize && verticalHasIdealSize) { childWrapper->Measure(childConstraint); + RecordSizeInChain(nodeName); return; } @@ -659,6 +1376,7 @@ void RelativeContainerLayoutAlgorithm::CalcSizeParam(LayoutWrapper* layoutWrappe childConstraint.selfIdealSize.SetHeight(childIdealHeight.value()); } childWrapper->Measure(childConstraint); + RecordSizeInChain(nodeName); } void RelativeContainerLayoutAlgorithm::CalcOffsetParam(LayoutWrapper* layoutWrapper, const std::string& nodeName) @@ -669,9 +1387,24 @@ void RelativeContainerLayoutAlgorithm::CalcOffsetParam(LayoutWrapper* layoutWrap bool offsetXCalculated = false; float offsetY = 0.0f; bool offsetYCalculated = false; + std::string chainName; + if (IsNodeInHorizontalChain(nodeName, chainName)) { + if (CalcOffsetInChain(chainName, LineDirection::HORIZONTAL)) { + offsetX = recordOffsetMap_[nodeName].GetX(); + } + offsetXCalculated = true; + } + if (IsNodeInVerticalChain(nodeName, chainName)) { + if (CalcOffsetInChain(chainName, LineDirection::VERTICAL)) { + offsetY = recordOffsetMap_[nodeName].GetY(); + } + offsetYCalculated = true; + } + for (const auto& alignRule : alignRules) { - if (idNodeMap_.find(alignRule.second.anchor) == idNodeMap_.end() && - !IsAnchorContainer(alignRule.second.anchor)) { + if (idNodeMap_.find(alignRule.second.anchor) == idNodeMap_.end() && !IsGuideline(alignRule.second.anchor) && + !IsAnchorContainer(alignRule.second.anchor) && !IsBarrier(alignRule.second.anchor)) { + // anchor is illegal continue; } if (static_cast(alignRule.first) < HORIZONTAL_DIRECTION_RANGE) { @@ -688,7 +1421,7 @@ void RelativeContainerLayoutAlgorithm::CalcOffsetParam(LayoutWrapper* layoutWrap } } } - recordOffsetMap_[nodeName] = OffsetF(offsetX, offsetY) + CalcBias(childWrapper); + recordOffsetMap_[nodeName] = OffsetF(offsetX, offsetY) + CalcBias(nodeName); } bool RelativeContainerLayoutAlgorithm::IsValidBias(float bias) @@ -696,19 +1429,42 @@ bool RelativeContainerLayoutAlgorithm::IsValidBias(float bias) return GreatOrEqual(bias, 0.0f); } -OffsetF RelativeContainerLayoutAlgorithm::CalcBias(const RefPtr& childWrapper) +void RelativeContainerLayoutAlgorithm::CalcBiasTowDirection( + std::pair& alignedValuesOnTwoDirections, + ChildIdealSize& childIdealSize, BiasPair& biasPair, float& horizontalOffset, float& verticalOffset) +{ + auto horizontalValues = alignedValuesOnTwoDirections.first; + auto verticalValues = alignedValuesOnTwoDirections.second; + auto biasX = biasPair.first; + auto biasY = biasPair.second; + if (horizontalValues.first.has_value() && horizontalValues.second.has_value() && childIdealSize.first.has_value()) { + auto alignDiff = std::abs(horizontalValues.first.value() - horizontalValues.second.value()); + horizontalOffset = (alignDiff - childIdealSize.first.value()) * (IsValidBias(biasX) ? biasX : DEFAULT_BIAS); + } + if (verticalValues.first.has_value() && verticalValues.second.has_value() && childIdealSize.second.has_value()) { + auto alignDiff = std::abs(verticalValues.first.value() - verticalValues.second.value()); + verticalOffset = (alignDiff - childIdealSize.second.value()) * (IsValidBias(biasY) ? biasY : DEFAULT_BIAS); + } +} + +OffsetF RelativeContainerLayoutAlgorithm::CalcBias(const std::string& nodeName) { OffsetF emptyBiasOffset; + std::string chainName; if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) { return emptyBiasOffset; } + + if (IsNodeInHorizontalChain(nodeName, chainName) && IsNodeInVerticalChain(nodeName, chainName)) { + return emptyBiasOffset; + } + auto childWrapper = idNodeMap_[nodeName]; auto layoutProperty = childWrapper->GetLayoutProperty(); CHECK_NULL_RETURN(layoutProperty, emptyBiasOffset); const auto& flexItemProperty = layoutProperty->GetFlexItemProperty(); CHECK_NULL_RETURN(flexItemProperty, emptyBiasOffset); CHECK_NULL_RETURN(flexItemProperty->HasBias(), emptyBiasOffset); - auto biasX = flexItemProperty->GetBiasValue().first; - auto biasY = flexItemProperty->GetBiasValue().second; + auto biasPair = flexItemProperty->GetBiasValue(); CHECK_NULL_RETURN(flexItemProperty->HasAlignRules(), emptyBiasOffset); auto alignRules = flexItemProperty->GetAlignRulesValue(); const auto& calcLayoutConstraint = layoutProperty->GetCalcLayoutConstraint(); @@ -728,16 +1484,9 @@ OffsetF RelativeContainerLayoutAlgorithm::CalcBias(const RefPtr& auto alignedValuesOnTwoDirections = GetFirstTwoAlignValues(childWrapper, flexItemProperty, childIdealSize); auto horizontalOffset = 0.0f; auto verticalOffset = 0.0f; - auto horizontalValues = alignedValuesOnTwoDirections.first; - auto verticalValues = alignedValuesOnTwoDirections.second; - if (horizontalValues.first.has_value() && horizontalValues.second.has_value() && childIdealSize.first.has_value()) { - auto alignDiff = std::abs(horizontalValues.first.value() - horizontalValues.second.value()); - horizontalOffset = (alignDiff - childIdealSize.first.value()) * (IsValidBias(biasX) ? biasX : DEFAULT_BIAS); - } - if (verticalValues.first.has_value() && verticalValues.second.has_value() && childIdealSize.second.has_value()) { - auto alignDiff = std::abs(verticalValues.first.value() - verticalValues.second.value()); - verticalOffset = (alignDiff - childIdealSize.second.value()) * (IsValidBias(biasY) ? biasY : DEFAULT_BIAS); - } + CalcBiasTowDirection(alignedValuesOnTwoDirections, childIdealSize, biasPair, horizontalOffset, verticalOffset); + horizontalOffset = (IsNodeInHorizontalChain(nodeName, chainName)) ? 0.0f : horizontalOffset; + verticalOffset = ((IsNodeInHorizontalChain(nodeName, chainName))) ? 0.0f : verticalOffset; return OffsetF(horizontalOffset, verticalOffset); } @@ -781,6 +1530,25 @@ void RelativeContainerLayoutAlgorithm::CalcHorizontalLayoutParam(AlignDirection auto childLayoutProperty = childWrapper->GetLayoutProperty(); CHECK_NULL_VOID(childLayoutProperty); const auto& childFlexItemProperty = childLayoutProperty->GetFlexItemProperty(); + if (IsGuideline(alignRule.anchor)) { + if (guidelines_[alignRule.anchor].first == LineDirection::VERTICAL) { + childFlexItemProperty->SetAlignValue(alignDirection, recordOffsetMap_[alignRule.anchor].GetX()); + } else { + childFlexItemProperty->SetAlignValue(alignDirection, 0.0f); + } + return; + } + + if (IsBarrier(alignRule.anchor)) { + if (barriers_[alignRule.anchor].first == BarrierDirection::LEFT || + barriers_[alignRule.anchor].first == BarrierDirection::RIGHT) { + childFlexItemProperty->SetAlignValue(alignDirection, recordOffsetMap_[alignRule.anchor].GetX()); + } else { + childFlexItemProperty->SetAlignValue(alignDirection, 0.0f); + } + return; + } + switch (alignRule.horizontal) { case HorizontalAlign::START: childFlexItemProperty->SetAlignValue( @@ -815,6 +1583,25 @@ void RelativeContainerLayoutAlgorithm::CalcVerticalLayoutParam(AlignDirection al auto childLayoutProperty = childWrapper->GetLayoutProperty(); CHECK_NULL_VOID(childLayoutProperty); const auto& childFlexItemProperty = childLayoutProperty->GetFlexItemProperty(); + if (IsGuideline(alignRule.anchor)) { + if (guidelines_[alignRule.anchor].first == LineDirection::HORIZONTAL) { + childFlexItemProperty->SetAlignValue(alignDirection, recordOffsetMap_[alignRule.anchor].GetY()); + } else { + childFlexItemProperty->SetAlignValue(alignDirection, 0.0f); + } + return; + } + + if (IsBarrier(alignRule.anchor)) { + if (barriers_[alignRule.anchor].first == BarrierDirection::TOP || + barriers_[alignRule.anchor].first == BarrierDirection::BOTTOM) { + childFlexItemProperty->SetAlignValue(alignDirection, recordOffsetMap_[alignRule.anchor].GetY()); + } else { + childFlexItemProperty->SetAlignValue(alignDirection, 0.0f); + } + return; + } + switch (alignRule.vertical) { case VerticalAlign::TOP: childFlexItemProperty->SetAlignValue( @@ -912,14 +1699,20 @@ float RelativeContainerLayoutAlgorithm::CalcHorizontalOffset( ? containerWidth : idNodeMap_[alignRule.anchor]->GetGeometryNode()->GetMarginFrameSize().Width(); } else { - anchorWidth = IsAnchorContainer(alignRule.anchor) - ? containerWidth - : idNodeMap_[alignRule.anchor]->GetGeometryNode()->GetFrameSize().Width(); + if (IsGuideline(alignRule.anchor) || IsBarrier(alignRule.anchor)) { + anchorWidth = 0; + } else if (IsAnchorContainer(alignRule.anchor)) { + anchorWidth = containerWidth; + } else { + anchorWidth = idNodeMap_[alignRule.anchor]->GetGeometryNode()->GetFrameSize().Width(); + } } std::optional marginLeft; - if (!IsAnchorContainer(alignRule.anchor)) { + if (!IsAnchorContainer(alignRule.anchor) && !IsGuideline(alignRule.anchor) && !IsBarrier(alignRule.anchor)) { auto anchorWrapper = idNodeMap_[alignRule.anchor]; - marginLeft = anchorWrapper->GetGeometryNode()->GetMargin()->left; + if (anchorWrapper->GetGeometryNode()->GetMargin()) { + marginLeft = anchorWrapper->GetGeometryNode()->GetMargin()->left; + } } switch (alignDirection) { case AlignDirection::LEFT: @@ -1017,14 +1810,20 @@ float RelativeContainerLayoutAlgorithm::CalcVerticalOffset( ? containerHeight : idNodeMap_[alignRule.anchor]->GetGeometryNode()->GetMarginFrameSize().Height(); } else { - anchorHeight = IsAnchorContainer(alignRule.anchor) - ? containerHeight - : idNodeMap_[alignRule.anchor]->GetGeometryNode()->GetFrameSize().Height(); + if (IsGuideline(alignRule.anchor) || IsBarrier(alignRule.anchor)) { + anchorHeight = 0; + } else if (IsAnchorContainer(alignRule.anchor)) { + anchorHeight = containerHeight; + } else { + anchorHeight = idNodeMap_[alignRule.anchor]->GetGeometryNode()->GetFrameSize().Height(); + } } std::optional marginTop; - if (!IsAnchorContainer(alignRule.anchor)) { + if (!IsAnchorContainer(alignRule.anchor) && !IsGuideline(alignRule.anchor) && !IsBarrier(alignRule.anchor)) { auto anchorWrapper = idNodeMap_[alignRule.anchor]; - marginTop = anchorWrapper->GetGeometryNode()->GetMargin()->top; + if (anchorWrapper->GetGeometryNode()->GetMargin()) { + marginTop = anchorWrapper->GetGeometryNode()->GetMargin()->top; + } } switch (alignDirection) { case AlignDirection::TOP: diff --git a/frameworks/core/components_ng/pattern/relative_container/relative_container_layout_algorithm.h b/frameworks/core/components_ng/pattern/relative_container/relative_container_layout_algorithm.h index 466697b4edab16c33ec49288f63806055203e2d6..aa6eec722e6a49161919b8d01ecdf3468a72eff5 100644 --- a/frameworks/core/components_ng/pattern/relative_container/relative_container_layout_algorithm.h +++ b/frameworks/core/components_ng/pattern/relative_container/relative_container_layout_algorithm.h @@ -28,6 +28,9 @@ namespace OHOS::Ace::NG { using AlignRulesItem = std::map; using TwoAlignedValues = std::pair, std::optional>; using ChildIdealSize = TwoAlignedValues; +using GuidelineParams = std::pair; +using BarrierParams = std::pair>; + class ACE_EXPORT RelativeContainerLayoutAlgorithm : public LayoutAlgorithm { DECLARE_ACE_TYPE(RelativeContainerLayoutAlgorithm, LayoutAlgorithm); @@ -38,11 +41,59 @@ public: void Measure(LayoutWrapper* layoutWrapper) override; void Layout(LayoutWrapper* layoutWrapper) override; + struct BarrierRect + { + float minLeft = Infinity(); + float maxRight = 0.0f; + float minTop = Infinity(); + float maxBottom = 0.0f; + }; + + struct ChainParam + { + std::vector ids; + std::map> itemSize; + AlignRule anchorHead; + AlignRule anchorTail; + ChainStyle chainStyle; + BiasPair bias; + bool isCalculated = false; + }; + private: void DetermineTopologicalOrder(LayoutWrapper* layoutWrapper); void MeasureSelf(LayoutWrapper* layoutWrapper); void CollectNodesById(LayoutWrapper* layoutWrapper); + bool IsAlignRuleInChain(const AlignDirection& direction, const std::string& nodeName); + void InsertToReliedOnMap(const std::string& anchorName, const std::string& nodeName); void GetDependencyRelationship(); + void GetDependencyRelationshipInChain(const std::string& anchor, const std::string& nodeName); + void GetDependencyRelationshipInBarrier(); + void CalcHorizontalGuideline(std::optional& selfIdealSize, const GuidelineInfo& guidelineInfo); + void CalcVerticalGuideline(std::optional& selfIdealSize, const GuidelineInfo& guidelineInfo); + void CalcGuideline(LayoutWrapper* layoutWrapper); + void CalcBarrier(LayoutWrapper* layoutWrapper); + bool IsGuideline(const std::string& id); + bool IsBarrier(const std::string& id); + BarrierRect GetBarrierRectByReferencedIds(const std::vector& referencedIds); + void MeasureBarrier(const std::string& barrierName); + void CheckNodeInHorizontalChain(std::string& currentNode, std::string& nextNode, + AlignRulesItem& currentAlignRules, std::vector& chainNodes, AlignRule& rightAnchor); + void CheckHorizontalChain(const RefPtr& childWrapper); + void CheckNodeInVerticalChain(std::string& currentNode, std::string& nextNode, AlignRulesItem& currentAlignRules, + std::vector& chainNodes, AlignRule& bottomAnchor); + void CheckVerticalChain(const RefPtr& childWrapper); + void CheckChain(LayoutWrapper* layoutWrapper); + void RecordSizeInChain(const std::string& nodeName); + bool IsNodeInHorizontalChain(const std::string& nodeName, std::string& chainName); + bool IsNodeInVerticalChain(const std::string& nodeName, std::string& chainName); + float GetHorizontalAnchorValueByAlignRule(AlignRule& alignRule); + float GetVerticalAnchorValueByAlignRule(AlignRule& alignRule); + std::pair CalcOffsetInChainGetStart(const float& anchorDistance, const float& contentSize, + const ChainParam& chainParam, LineDirection direction); + bool CalcOffsetInChain(const std::string& chainName, LineDirection direction); + void PreTopologicalLoopDetectionGetAnchorSet( + const std::string& nodeName, const AlignRulesItem& alignRulesItem, std::set& anchorSet); bool PreTopologicalLoopDetection(); void TopologicalSort(std::list& renderList); void CalcSizeParam(LayoutWrapper* layoutWrapper, const std::string& nodeName); @@ -63,7 +114,9 @@ private: AlignDirection alignDirection, const AlignRule& alignRule, float containerHeight, const std::string& nodeName); bool IsValidBias(float bias); - OffsetF CalcBias(const RefPtr& childWrapper); + void CalcBiasTowDirection(std::pair& alignedValuesOnTwoDirections, + ChildIdealSize& childIdealSize, BiasPair& biasPair, float& horizontalOffset, float& verticalOffset); + OffsetF CalcBias(const std::string& nodeName); std::pair GetFirstTwoAlignValues(const RefPtr& childWrapper, const std::unique_ptr& flexItemProperty, const ChildIdealSize& childIdealSize); @@ -85,6 +138,12 @@ private: std::map incomingDegreeMap_; std::map> reliedOnMap_; std::map recordOffsetMap_; + std::unordered_map barriers_; + std::unordered_map guidelines_; + std::unordered_map horizontalChains_; + std::unordered_map verticalChains_; + std::unordered_map horizontalChainNodeMap_; + std::unordered_map verticalChainNodeMap_; PaddingPropertyF padding_; SizeF containerSizeWithoutPaddingBorder_; }; diff --git a/frameworks/core/components_ng/pattern/relative_container/relative_container_layout_property.h b/frameworks/core/components_ng/pattern/relative_container/relative_container_layout_property.h index aaad05ae196e612b18983067f1416a3e579790f2..e9de10b093136067800c7f6f1441d13cb4a638f7 100644 --- a/frameworks/core/components_ng/pattern/relative_container/relative_container_layout_property.h +++ b/frameworks/core/components_ng/pattern/relative_container/relative_container_layout_property.h @@ -35,13 +35,20 @@ public: { auto value = MakeRefPtr(); value->LayoutProperty::UpdateLayoutProperty(DynamicCast(this)); + value->propBarrier_ = CloneBarrier(); + value->propGuideline_ = CloneGuideline(); return value; } void Reset() override { LayoutProperty::Reset(); + ResetBarrier(); + ResetGuideline(); } + + ACE_DEFINE_PROPERTY_ITEM_WITHOUT_GROUP(Barrier, std::vector, PROPERTY_UPDATE_MEASURE); + ACE_DEFINE_PROPERTY_ITEM_WITHOUT_GROUP(Guideline, std::vector, PROPERTY_UPDATE_MEASURE); }; } // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/relative_container/relative_container_model.h b/frameworks/core/components_ng/pattern/relative_container/relative_container_model.h index 75b447205d75906d0237b5cf10e9202450d88ba4..1324781c50f041966a8aeb55cf1e4afbb7a21a27 100644 --- a/frameworks/core/components_ng/pattern/relative_container/relative_container_model.h +++ b/frameworks/core/components_ng/pattern/relative_container/relative_container_model.h @@ -30,7 +30,8 @@ public: virtual ~RelativeContainerModel() = default; virtual void Create(); - + virtual void SetBarrier(const std::vector& barrierInfo) = 0; + virtual void SetGuideline(const std::vector& guidelineInfo) = 0; private: static std::unique_ptr instance_; static std::mutex mutex_; diff --git a/frameworks/core/components_ng/pattern/relative_container/relative_container_model_ng.cpp b/frameworks/core/components_ng/pattern/relative_container/relative_container_model_ng.cpp index 4e364009a37f3a076f360ecd55cd1a8eee679d7e..18924220e32e6ca877c376a4d675f755f9aa1864 100644 --- a/frameworks/core/components_ng/pattern/relative_container/relative_container_model_ng.cpp +++ b/frameworks/core/components_ng/pattern/relative_container/relative_container_model_ng.cpp @@ -31,4 +31,19 @@ void RelativeContainerModelNG::Create() ViewStackProcessor::GetInstance()->Push(frameNode); } +void RelativeContainerModelNG::SetBarrier(const std::vector& barrierInfo) +{ + if (!ViewStackProcessor::GetInstance()->IsCurrentVisualStateProcess()) { + return; + } + ACE_UPDATE_LAYOUT_PROPERTY(RelativeContainerLayoutProperty, Barrier, barrierInfo); +} + +void RelativeContainerModelNG::SetGuideline(const std::vector& guidelineInfo) +{ + if (!ViewStackProcessor::GetInstance()->IsCurrentVisualStateProcess()) { + return; + } + ACE_UPDATE_LAYOUT_PROPERTY(RelativeContainerLayoutProperty, Guideline, guidelineInfo); +} } // namespace OHOS::Ace::NG \ No newline at end of file diff --git a/frameworks/core/components_ng/pattern/relative_container/relative_container_model_ng.h b/frameworks/core/components_ng/pattern/relative_container/relative_container_model_ng.h index 8ddb3dfb07091ab464ff601dff5b42ecb6e72379..16b9b08edf413c74d07af8ac33b7c008661ab7b2 100644 --- a/frameworks/core/components_ng/pattern/relative_container/relative_container_model_ng.h +++ b/frameworks/core/components_ng/pattern/relative_container/relative_container_model_ng.h @@ -22,6 +22,8 @@ namespace OHOS::Ace::NG { class ACE_EXPORT RelativeContainerModelNG : public OHOS::Ace::RelativeContainerModel { public: void Create() override; + void SetBarrier(const std::vector& barrierInfo) override; + void SetGuideline(const std::vector& guidelineInfo) override; }; } // namespace OHOS::Ace::NG #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_RELATIVE_CONTAINER_RELATIVE_CONTAINER_MODEL_NG_H \ No newline at end of file diff --git a/frameworks/core/components_ng/pattern/relative_container/relative_container_pattern.h b/frameworks/core/components_ng/pattern/relative_container/relative_container_pattern.h index d276a6f11630c57e79d6d5c08a2d7abe6886ab43..04d55d93a36c206882aba7be4745ff40f4c576d9 100644 --- a/frameworks/core/components_ng/pattern/relative_container/relative_container_pattern.h +++ b/frameworks/core/components_ng/pattern/relative_container/relative_container_pattern.h @@ -36,7 +36,7 @@ public: RefPtr CreateLayoutProperty() override { - return MakeRefPtr(); + return MakeRefPtr(); } bool IsAtomicNode() const override diff --git a/frameworks/core/components_ng/property/flex_property.h b/frameworks/core/components_ng/property/flex_property.h index ac5371cf22840e2e44d97d7a80630905d351890c..f45f30bdc7cae46b51614512a7eb283e40c05839 100644 --- a/frameworks/core/components_ng/property/flex_property.h +++ b/frameworks/core/components_ng/property/flex_property.h @@ -27,6 +27,8 @@ namespace OHOS::Ace::NG { using AlignRulesItem = std::map; using BiasPair = std::pair; +using GuidelineItem = std::vector; +using BarrierItem = std::vector; struct FlexItemProperty { ACE_DEFINE_PROPERTY_GROUP_ITEM(FlexGrow, float); ACE_DEFINE_PROPERTY_GROUP_ITEM(FlexShrink, float); @@ -34,6 +36,8 @@ struct FlexItemProperty { ACE_DEFINE_PROPERTY_GROUP_ITEM(FlexBasis, Dimension); ACE_DEFINE_PROPERTY_GROUP_ITEM(DisplayIndex, int32_t); ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignRules, AlignRulesItem); + ACE_DEFINE_PROPERTY_GROUP_ITEM(HorizontalChainStyle, ChainInfo); + ACE_DEFINE_PROPERTY_GROUP_ITEM(VerticalChainStyle, ChainInfo); ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignLeft, float); ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignMiddle, float); ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignRight, float); @@ -41,6 +45,8 @@ struct FlexItemProperty { ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignCenter, float); ACE_DEFINE_PROPERTY_GROUP_ITEM(AlignBottom, float); ACE_DEFINE_PROPERTY_GROUP_ITEM(Bias, BiasPair); + ACE_DEFINE_PROPERTY_GROUP_ITEM(Barrier, BarrierItem); + ACE_DEFINE_PROPERTY_GROUP_ITEM(Guideline, GuidelineItem); void ToJsonValue(std::unique_ptr& json) const {