• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/navigation/navigation_layout_algorithm.h"
17 
18 #include "core/components_ng/pattern/navigation/navigation_layout_util.h"
19 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
20 #include "core/components_ng/property/measure_utils.h"
21 
22 namespace OHOS::Ace::NG {
23 
24 constexpr static float HALF = 0.5f;
25 constexpr static int32_t PLATFORM_VERSION_TEN = 10;
26 constexpr Dimension WINDOW_WIDTH = 520.0_vp;
27 
28 namespace {
29 constexpr NavigationMode INITIAL_MODE = NavigationMode::AUTO;
30 constexpr int32_t MODE_SWITCH_ANIMATION_DURATION = 500; // ms
31 const RefPtr<CubicCurve> MODE_SWITCH_CURVE = AceType::MakeRefPtr<CubicCurve>(0.2f, 0.2f, 0.1f, 1.0f);
32 constexpr Dimension DIVIDER_DRAG_BAR_WIDTH = 12.0_vp;
33 constexpr Dimension DIVIDER_DRAG_BAR_HEIGHT = 48.0_vp;
34 constexpr Dimension DRAG_BAR_ITEM_WIDTH = 2.0_vp;
35 constexpr Dimension DRAG_BAR_ITEM_HEIGHT = 24.0_vp;
36 
IsNavBarVisible(const RefPtr<NavigationGroupNode> & navigation)37 bool IsNavBarVisible(const RefPtr<NavigationGroupNode>& navigation)
38 {
39     CHECK_NULL_RETURN(navigation, false);
40     auto navBar = AceType::DynamicCast<FrameNode>(navigation->GetNavBarNode());
41     CHECK_NULL_RETURN(navBar, false);
42     auto navBarProperty = navBar->GetLayoutProperty();
43     CHECK_NULL_RETURN(navBarProperty, false);
44     return navBarProperty->GetVisibilityValue(VisibleType::INVISIBLE) == VisibleType::VISIBLE;
45 }
46 
MeasureDivider(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & dividerSize)47 void MeasureDivider(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
48     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& dividerSize)
49 {
50     auto dividerNode = hostNode->GetDividerNode();
51     CHECK_NULL_VOID(dividerNode);
52     auto index = hostNode->GetChildIndexById(dividerNode->GetId());
53     auto dividerWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
54     CHECK_NULL_VOID(dividerWrapper);
55     auto constraint = navigationLayoutProperty->CreateChildConstraint();
56     constraint.selfIdealSize = OptionalSizeF(dividerSize.Width(), dividerSize.Height());
57     dividerWrapper->Measure(constraint);
58 }
59 
MeasureSplitPlaceholder(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & splitPlaceholderSize)60 void MeasureSplitPlaceholder(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
61     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& splitPlaceholderSize)
62 {
63     auto splitPlaceholder = hostNode->GetPlaceholderContentNode();
64     CHECK_NULL_VOID(splitPlaceholder);
65     auto index = hostNode->GetChildIndexById(splitPlaceholder->GetId());
66     auto splitPlaceholderWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
67     CHECK_NULL_VOID(splitPlaceholderWrapper);
68     auto constraint = navigationLayoutProperty->CreateChildConstraint();
69     auto placeholderLayoutProperty = AceType::DynamicCast<FrameNode>(splitPlaceholder)->GetLayoutProperty();
70     CHECK_NULL_VOID(placeholderLayoutProperty);
71     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
72     CHECK_NULL_VOID(navigationPattern);
73     auto navigationStack = navigationPattern->GetNavigationStack();
74     CHECK_NULL_VOID(navigationStack);
75     bool isHideNavBar = navigationLayoutProperty->GetHideNavBar().value_or(false);
76     // cases that require measure of placeholder content
77     // 1. navigation stack is empty
78     // 2. navigation mode is SPLIT
79     // 3. navBar is not hidden
80     if (navigationStack->Empty() && navigationPattern->GetNavigationMode() == NavigationMode::SPLIT && !isHideNavBar) {
81         placeholderLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
82         if (NavigationLayoutAlgorithm::IsAutoHeight(navigationLayoutProperty)) {
83             constraint.selfIdealSize.SetWidth(splitPlaceholderSize.Width());
84         } else {
85             constraint.selfIdealSize = OptionalSizeF(splitPlaceholderSize.Width(), splitPlaceholderSize.Height());
86         }
87     } else {
88         placeholderLayoutProperty->UpdateVisibility(VisibleType::GONE);
89         constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
90     }
91     splitPlaceholderWrapper->Measure(constraint);
92 }
93 
MeasureDragBar(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & dividerSize)94 void MeasureDragBar(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
95     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& dividerSize)
96 {
97     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
98     CHECK_NULL_VOID(navigationPattern);
99     auto dragNode = hostNode->GetDragBarNode();
100     CHECK_NULL_VOID(dragNode);
101     auto index = hostNode->GetChildIndexById(dragNode->GetId());
102     auto dargWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
103     CHECK_NULL_VOID(dargWrapper);
104     auto dragBarItem = AceType::DynamicCast<FrameNode>(dragNode->GetChildAtIndex(0));
105     CHECK_NULL_VOID(dragBarItem);
106     auto dragBarItemLayoutProperty = dragBarItem->GetLayoutProperty();
107     CHECK_NULL_VOID(dragBarItemLayoutProperty);
108     auto constraint = navigationLayoutProperty->CreateChildConstraint();
109     if (NearZero(dividerSize.Width()) || !navigationPattern->GetEnableDragBar()) {
110         constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
111         dragBarItemLayoutProperty->UpdateUserDefinedIdealSize(
112             CalcSize(CalcLength(0.0f), CalcLength(0.0f)));
113     } else {
114         constraint.selfIdealSize = OptionalSizeF(static_cast<float>(DIVIDER_DRAG_BAR_WIDTH.ConvertToPx()),
115             static_cast<float>(DIVIDER_DRAG_BAR_HEIGHT.ConvertToPx()));
116         dragBarItemLayoutProperty->UpdateUserDefinedIdealSize(
117             CalcSize(CalcLength(DRAG_BAR_ITEM_WIDTH), CalcLength(DRAG_BAR_ITEM_HEIGHT)));
118     }
119     dargWrapper->Measure(constraint);
120 }
121 
LayoutDragBar(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float navBarWidth,const NavBarPosition & position)122 void LayoutDragBar(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
123     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float navBarWidth, const NavBarPosition& position)
124 {
125     auto dargNode = hostNode->GetDragBarNode();
126     CHECK_NULL_VOID(dargNode);
127     auto index = hostNode->GetChildIndexById(dargNode->GetId());
128     auto dargWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
129     CHECK_NULL_VOID(dargWrapper);
130     auto geometryNode = dargWrapper->GetGeometryNode();
131     CHECK_NULL_VOID(geometryNode);
132     auto navigationGeometryNode = layoutWrapper->GetGeometryNode();
133     CHECK_NULL_VOID(navigationGeometryNode);
134     auto navigationWidth = navigationGeometryNode->GetFrameSize().Width();
135     auto navigationHeight = navigationGeometryNode->GetFrameSize().Height();
136     auto offsetX = navBarWidth - geometryNode->GetFrameSize().Width() * HALF;
137     auto offsetY = navigationHeight * HALF - geometryNode->GetFrameSize().Height() * HALF;
138     OffsetT<float> dragOffset = OffsetT<float>(offsetX, offsetY);
139     bool isNavBarInRight = (position == NavBarPosition::END && !AceApplicationInfo::GetInstance().IsRightToLeft()) ||
140         (position == NavBarPosition::START && AceApplicationInfo::GetInstance().IsRightToLeft());
141     if (isNavBarInRight) {
142         dragOffset.SetX(navigationWidth - navBarWidth - geometryNode->GetFrameSize().Width() * HALF);
143     }
144     const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
145     dragOffset.AddX(padding.left.value_or(0.0f));
146     dragOffset.AddY(padding.top.value_or(0.0f));
147     geometryNode->SetMarginFrameOffset(dragOffset);
148     dargWrapper->Layout();
149 }
150 
LayoutPrimaryContentNode(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty)151 float LayoutPrimaryContentNode(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
152     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty)
153 {
154     CHECK_NULL_RETURN(hostNode, 0.0f);
155     auto primaryContentNode = hostNode->GetPrimaryContentNode();
156     CHECK_NULL_RETURN(primaryContentNode, 0.0f);
157     auto navigationGeometryNode = layoutWrapper->GetGeometryNode();
158     bool isNavBarInRight = AceApplicationInfo::GetInstance().IsRightToLeft();
159     const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
160     auto index = hostNode->GetChildIndexById(primaryContentNode->GetId());
161     auto nodeWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
162     CHECK_NULL_RETURN(nodeWrapper, 0.0f);
163     auto geometryNode = nodeWrapper->GetGeometryNode();
164     auto nodeOffset = OffsetT<float>(0.0f, 0.0f);
165     if (isNavBarInRight) {
166         nodeOffset.SetX(navigationGeometryNode->GetFrameSize().Width() - geometryNode->GetFrameSize().Width());
167     }
168     nodeOffset.AddX(padding.left.value_or(0.0f));
169     nodeOffset.AddY(padding.top.value_or(0.0f));
170     geometryNode->SetMarginFrameOffset(nodeOffset);
171     nodeWrapper->Layout();
172     return geometryNode->GetFrameSize().Width();
173 }
174 
LayoutNavBarOrHomeDestination(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,NavBarPosition position,OffsetF & returnNavBarOffset)175 float LayoutNavBarOrHomeDestination(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
176     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, NavBarPosition position,
177     OffsetF& returnNavBarOffset)
178 {
179     CHECK_NULL_RETURN(hostNode, 0.0f);
180     auto navigationPattern = hostNode->GetPattern<NavigationPattern>();
181     CHECK_NULL_RETURN(navigationPattern, 0.0f);
182     auto targetNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarOrHomeDestinationNode());
183     CHECK_NULL_RETURN(targetNode, 0.0f);
184     auto contentNode = hostNode->GetContentNode();
185     CHECK_NULL_RETURN(contentNode, 0.0f);
186     auto index = hostNode->GetChildIndexById(targetNode->GetId());
187     auto targetNodeWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
188     CHECK_NULL_RETURN(targetNodeWrapper, 0.0f);
189     auto geometryNode = targetNodeWrapper->GetGeometryNode();
190     auto navigationGeometryNode = layoutWrapper->GetGeometryNode();
191     auto navBarOffset = OffsetT<float>(0.0f, 0.0f);
192     bool isNavBarInRight = (position == NavBarPosition::END && !AceApplicationInfo::GetInstance().IsRightToLeft()) ||
193         (position == NavBarPosition::START && AceApplicationInfo::GetInstance().IsRightToLeft());
194     bool isHideNavBar = navigationLayoutProperty->GetHideNavBar().value_or(false);
195     NavigationMode navigationMode = navigationPattern->GetNavigationMode();
196     if (isNavBarInRight && !isHideNavBar && navigationMode == NavigationMode::SPLIT) {
197         // only in SPLIT mode can navBar show on the left or right side of navigation, otherwise it is centered.
198         navBarOffset.SetX(navigationGeometryNode->GetFrameSize().Width() - geometryNode->GetFrameSize().Width());
199     }
200     const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
201     navBarOffset.AddX(padding.left.value_or(0.0f));
202     navBarOffset.AddY(padding.top.value_or(0.0f));
203     geometryNode->SetMarginFrameOffset(navBarOffset);
204     targetNodeWrapper->Layout();
205     returnNavBarOffset = navBarOffset;
206     return isHideNavBar && navigationMode == NavigationMode::SPLIT ? 0.0f : geometryNode->GetFrameSize().Width();
207 }
208 
LayoutDivider(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float navBarWidth,const NavBarPosition & position)209 float LayoutDivider(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
210     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float navBarWidth, const NavBarPosition& position)
211 {
212     auto dividerNode = hostNode->GetDividerNode();
213     CHECK_NULL_RETURN(dividerNode, 0.0f);
214     auto index = hostNode->GetChildIndexById(dividerNode->GetId());
215     auto dividerWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
216     CHECK_NULL_RETURN(dividerWrapper, 0.0f);
217     auto geometryNode = dividerWrapper->GetGeometryNode();
218     auto navigationGeometryNode = layoutWrapper->GetGeometryNode();
219     auto dividerOffsetX = navBarWidth;
220     if (position == NavBarPosition::END) {
221         dividerOffsetX =
222             navigationGeometryNode->GetFrameSize().Width() - geometryNode->GetFrameSize().Width() - dividerOffsetX;
223     }
224     if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
225         dividerOffsetX =
226             navigationGeometryNode->GetFrameSize().Width() - geometryNode->GetFrameSize().Width() - dividerOffsetX;
227     }
228     OffsetT<float> dividerOffset = OffsetT<float>(dividerOffsetX, 0.0f);
229     const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
230     dividerOffset.AddX(padding.left.value_or(0));
231     dividerOffset.AddY(padding.top.value_or(0));
232     geometryNode->SetMarginFrameOffset(dividerOffset);
233     dividerWrapper->Layout();
234     return geometryNode->GetFrameSize().Width();
235 }
236 
LayoutContent(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float navBarWidth,float dividerWidth,const NavBarPosition & position)237 void LayoutContent(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
238     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float navBarWidth, float dividerWidth,
239     const NavBarPosition& position)
240 {
241     auto pattern = hostNode->GetPattern<NavigationPattern>();
242     CHECK_NULL_VOID(pattern);
243     auto contentNode = hostNode->GetContentNode();
244     CHECK_NULL_VOID(contentNode);
245     auto index = hostNode->GetChildIndexById(contentNode->GetId());
246     auto contentWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
247     CHECK_NULL_VOID(contentWrapper);
248     auto geometryNode = contentWrapper->GetGeometryNode();
249     CHECK_NULL_VOID(geometryNode);
250 
251     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
252     auto contentChildSize = contentNode->GetChildren().size();
253 
254     if (pattern->IsForceSplitSuccess()) {
255         auto contentOffset = OffsetT<float>(0.0f, 0.0f);
256         if (!AceApplicationInfo::GetInstance().IsRightToLeft()) {
257             contentOffset = OffsetF(navBarWidth + dividerWidth, 0.0f);
258         }
259         const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
260         contentOffset.AddX(padding.left.value_or(0));
261         contentOffset.AddY(padding.top.value_or(0));
262         geometryNode->SetMarginFrameOffset(contentOffset);
263         contentWrapper->Layout();
264         return;
265     }
266 
267     // cases that content layouts from start
268     // 1. displaying content pages in STACK mode
269     // 2. placing navBar at the end
270     // 3. hiding navBar in SPLIT mode
271     auto contentOffset = OffsetT<float>(0.0f, 0.0f);
272     if ((contentChildSize != 0 && navigationPattern->GetNavigationMode() == NavigationMode::STACK) ||
273         position == NavBarPosition::END ||
274         (navigationLayoutProperty->GetHideNavBar().value_or(false) &&
275             navigationPattern->GetNavigationMode() == NavigationMode::SPLIT)) {
276         if (AceApplicationInfo::GetInstance().IsRightToLeft() &&
277             navigationPattern->GetNavigationMode() == NavigationMode::SPLIT) {
278             contentOffset = OffsetT<float>(navBarWidth + dividerWidth, 0.0f);
279         }
280         const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
281         contentOffset.AddX(padding.left.value_or(0));
282         contentOffset.AddY(padding.top.value_or(0));
283         geometryNode->SetMarginFrameOffset(contentOffset);
284         contentWrapper->Layout();
285         return;
286     }
287     if (!AceApplicationInfo::GetInstance().IsRightToLeft()) {
288         contentOffset = OffsetT<float>(navBarWidth + dividerWidth, 0.0f);
289     }
290     const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
291     contentOffset.AddX(padding.left.value_or(0));
292     contentOffset.AddY(padding.top.value_or(0));
293     geometryNode->SetMarginFrameOffset(contentOffset);
294     contentWrapper->Layout();
295 }
296 
LayoutSplitPalceholderContent(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float splitPlaceholderOffsetX,const NavBarPosition & position)297 void LayoutSplitPalceholderContent(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
298     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float splitPlaceholderOffsetX,
299     const NavBarPosition& position)
300 {
301     CHECK_NULL_VOID(hostNode);
302     auto splitPlaceholder = hostNode->GetPlaceholderContentNode();
303     CHECK_NULL_VOID(splitPlaceholder);
304     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
305     auto navigationStack = navigationPattern->GetNavigationStack();
306     CHECK_NULL_VOID(navigationStack);
307     bool isHideNavBar = navigationLayoutProperty->GetHideNavBar().value_or(false);
308     // cases that require layout of placeholder content
309     // 1. navigation stack is empty
310     // 2. navigation mode is SPLIT
311     // 3. navBar is not hidden
312     if (navigationStack->Empty() && navigationPattern->GetNavigationMode() == NavigationMode::SPLIT && !isHideNavBar) {
313         bool isNavBarInRight =
314             (position == NavBarPosition::END && !AceApplicationInfo::GetInstance().IsRightToLeft()) ||
315             (position == NavBarPosition::START && AceApplicationInfo::GetInstance().IsRightToLeft());
316         auto index = hostNode->GetChildIndexById(splitPlaceholder->GetId());
317         auto splitPlaceholderWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
318         CHECK_NULL_VOID(splitPlaceholderWrapper);
319         auto splitPlaceholderGeometryNode = splitPlaceholderWrapper->GetGeometryNode();
320         CHECK_NULL_VOID(splitPlaceholderGeometryNode);
321         if (isNavBarInRight) {
322             splitPlaceholderOffsetX = 0.0f;
323         }
324         auto splitPlaceholderOffset = OffsetT<float>(splitPlaceholderOffsetX, 0.0f);
325         const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
326         splitPlaceholderOffset.AddX(padding.left.value_or(0));
327         splitPlaceholderOffset.AddY(padding.top.value_or(0));
328         splitPlaceholderGeometryNode->SetMarginFrameOffset(splitPlaceholderOffset);
329         splitPlaceholderWrapper->Layout();
330     }
331 }
332 
FitScrollFullWindow(SizeF & frameSize)333 void FitScrollFullWindow(SizeF& frameSize)
334 {
335     auto pipeline = PipelineContext::GetCurrentContext();
336     CHECK_NULL_VOID(pipeline);
337     if (frameSize.Width() == Infinity<float>()) {
338         frameSize.SetWidth(pipeline->GetRootWidth());
339     }
340     if (frameSize.Height() == Infinity<float>()) {
341         frameSize.SetHeight(pipeline->GetRootHeight());
342     }
343 }
344 
SwitchModeWithAnimation(const RefPtr<NavigationGroupNode> & hostNode)345 void SwitchModeWithAnimation(const RefPtr<NavigationGroupNode>& hostNode)
346 {
347     CHECK_NULL_VOID(hostNode);
348     hostNode->SetDoingModeSwitchAnimationFlag(true);
349     hostNode->SetNeedSetInvisible(false);
350     AnimationOption option;
351     option.SetCurve(MODE_SWITCH_CURVE);
352     option.SetFillMode(FillMode::FORWARDS);
353     option.SetDuration(MODE_SWITCH_ANIMATION_DURATION);
354     option.SetOnFinishEvent([weakHost = WeakPtr<NavigationGroupNode>(hostNode)]() {
355         auto hostNode = weakHost.Upgrade();
356         CHECK_NULL_VOID(hostNode);
357         hostNode->ReduceModeSwitchAnimationCnt();
358         if (hostNode->GetModeSwitchAnimationCnt() == 0) {
359             auto dividerNode = AceType::DynamicCast<FrameNode>(hostNode->GetDividerNode());
360             CHECK_NULL_VOID(dividerNode);
361             auto layoutProperty = dividerNode->GetLayoutProperty();
362             CHECK_NULL_VOID(layoutProperty);
363             layoutProperty->UpdateVisibility(VisibleType::VISIBLE);
364             auto pattern = hostNode->GetPattern<NavigationPattern>();
365             CHECK_NULL_VOID(pattern);
366             auto lastStandardIndex = hostNode->GetLastStandardIndex();
367             auto navigationLayoutProperty = hostNode->GetLayoutProperty<NavigationLayoutProperty>();
368             CHECK_NULL_VOID(navigationLayoutProperty);
369             bool navbarIsHidden = (pattern->GetNavigationMode() == NavigationMode::STACK && lastStandardIndex >= 0) ||
370                                   navigationLayoutProperty->GetHideNavBar().value_or(false);
371             hostNode->SetNeedSetInvisible(navbarIsHidden);
372             hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
373         }
374     });
375     AnimationUtils::Animate(option, [weakHost = WeakPtr<NavigationGroupNode>(hostNode)]() {
376         auto hostNode = weakHost.Upgrade();
377         CHECK_NULL_VOID(hostNode);
378         auto dividerNode = AceType::DynamicCast<FrameNode>(hostNode->GetDividerNode());
379         CHECK_NULL_VOID(dividerNode);
380         auto layoutProperty = dividerNode->GetLayoutProperty();
381         CHECK_NULL_VOID(layoutProperty);
382         layoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
383         hostNode->IncreaseModeSwitchAnimationCnt();
384         hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
385         hostNode->GetContext()->FlushUITasks();
386         hostNode->SetDoingModeSwitchAnimationFlag(false);
387     }, option.GetOnFinishEvent(), nullptr /* repeatCallback */, hostNode->GetContextRefPtr());
388 }
389 
390 } // namespace
391 
LayoutForceSplitPlaceHolderNode(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float navBarWidth,float dividerWidth)392 void NavigationLayoutAlgorithm::LayoutForceSplitPlaceHolderNode(
393     LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
394     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float navBarWidth, float dividerWidth)
395 {
396     auto phNode = AceType::DynamicCast<FrameNode>(hostNode->GetForceSplitPlaceHolderNode());
397     CHECK_NULL_VOID(phNode);
398     auto index = hostNode->GetChildIndexById(phNode->GetId());
399     auto phWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
400     CHECK_NULL_VOID(phWrapper);
401     auto geometryNode = phWrapper->GetGeometryNode();
402     CHECK_NULL_VOID(geometryNode);
403     auto phOffset = OffsetT<float>(0.0f, 0.0f);
404     if (!AceApplicationInfo::GetInstance().IsRightToLeft()) {
405         phOffset = OffsetF(navBarWidth + dividerWidth, 0.0f);
406     }
407     const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
408     phOffset.AddX(padding.left.value_or(0));
409     phOffset.AddY(padding.top.value_or(0));
410     geometryNode->SetMarginFrameOffset(phOffset);
411     phWrapper->Layout();
412 }
413 
IsAutoHeight(const RefPtr<LayoutProperty> & layoutProperty)414 bool NavigationLayoutAlgorithm::IsAutoHeight(const RefPtr<LayoutProperty>& layoutProperty)
415 {
416     CHECK_NULL_RETURN(layoutProperty, false);
417     auto& calcLayoutConstraint = layoutProperty->GetCalcLayoutConstraint();
418     if (!calcLayoutConstraint || !calcLayoutConstraint->selfIdealSize.has_value() ||
419         !calcLayoutConstraint->selfIdealSize->Height().has_value() ||
420         (calcLayoutConstraint->selfIdealSize->Height().value().ToString().find("auto") == std::string::npos)) {
421         return false;
422     }
423     return true;
424 }
425 
RangeCalculation(const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty)426 void NavigationLayoutAlgorithm::RangeCalculation(
427     const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty)
428 {
429     const auto& constraint = navigationLayoutProperty->GetLayoutConstraint();
430     CHECK_NULL_VOID(constraint);
431     auto parentSize = CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
432     auto frameSize = parentSize.ConvertToSizeT();
433     float frameSizeWidth = frameSize.Width();
434     Dimension defaultValue = Dimension(-1.0);
435     auto pipeline = PipelineContext::GetCurrentContext();
436     CHECK_NULL_VOID(pipeline);
437 
438     minContentWidthValue_ = navigationLayoutProperty->GetMinContentWidthValue(defaultValue);
439     if (minContentWidthValue_ == defaultValue) {
440         userSetMinContentFlag_ = false;
441         minContentWidthValue_ = DEFAULT_MIN_CONTENT_WIDTH;
442     } else {
443         userSetMinContentFlag_ = true;
444     }
445     minNavBarWidthValue_ = navigationLayoutProperty->GetMinNavBarWidthValue(DEFAULT_MIN_NAV_BAR_WIDTH);
446     auto userSetMaxNavBarWidthValue = navigationLayoutProperty->GetMaxNavBarWidthValue(defaultValue);
447 
448     float minNavBarWidth =
449         std::min(static_cast<float>(minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f))),
450             frameSizeWidth);
451     float maxNavBarWidth = 0.0f;
452     if (userSetMaxNavBarWidthValue == defaultValue) {
453         userSetNavBarRangeFlag_ = false;
454         maxNavBarWidth = std::min(
455             static_cast<float>(DEFAULT_MAX_NAV_BAR_WIDTH.ConvertToPx()), frameSizeWidth * MAX_NAV_BAR_WIDTH_SCALE);
456     } else {
457         userSetNavBarRangeFlag_ = true;
458         maxNavBarWidth =
459             static_cast<float>(userSetMaxNavBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f)));
460     }
461     maxNavBarWidthValue_ = Dimension(Dimension(std::max(maxNavBarWidth, minNavBarWidth)).ConvertToVp(),
462         DimensionUnit::VP);
463     auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
464     if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
465         auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
466         auto maxNavBarWidth = maxNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
467         realNavBarWidth_ = std::max(realNavBarWidth_, static_cast<float>(minNavBarWidth));
468         realNavBarWidth_ = std::min(realNavBarWidth_, static_cast<float>(maxNavBarWidth));
469     }
470     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
471     CHECK_NULL_VOID(navigationPattern);
472     navigationPattern->SetMinNavBarWidthValue(minNavBarWidthValue_);
473     navigationPattern->SetMaxNavBarWidthValue(maxNavBarWidthValue_);
474     navigationPattern->SetMinContentWidthValue(minContentWidthValue_);
475     navigationPattern->SetUserSetNavBarRangeFlag(userSetNavBarRangeFlag_);
476     navigationPattern->SetUserSetMinContentFlag(userSetMinContentFlag_);
477 }
478 
GetRange(const RefPtr<NavigationGroupNode> & hostNode)479 void NavigationLayoutAlgorithm::GetRange(const RefPtr<NavigationGroupNode>& hostNode)
480 {
481     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
482     CHECK_NULL_VOID(navigationPattern);
483     minNavBarWidthValue_ = navigationPattern->GetMinNavBarWidthValue();
484     maxNavBarWidthValue_ = navigationPattern->GetMaxNavBarWidthValue();
485     minContentWidthValue_ = navigationPattern->GetMinContentWidthValue();
486     userSetNavBarRangeFlag_ = navigationPattern->GetUserSetNavBarRangeFlag();
487     userSetMinContentFlag_ = navigationPattern->GetUserSetMinContentFlag();
488     userSetNavBarWidthFlag_ = navigationPattern->GetUserSetNavBarWidthFlag();
489 }
490 
CalculateNavigationWidth(const RefPtr<NavigationGroupNode> & hostNode)491 float NavigationLayoutAlgorithm::CalculateNavigationWidth(const RefPtr<NavigationGroupNode>& hostNode)
492 {
493     auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(hostNode->GetLayoutProperty());
494     auto pipeline = hostNode->GetContext();
495     CHECK_NULL_RETURN(pipeline, 0.0f);
496     auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
497     auto navigationWidth = 0.0f;
498     if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
499         CHECK_NULL_RETURN(navigationLayoutProperty, navigationWidth);
500         const auto& constraint = navigationLayoutProperty->GetLayoutConstraint();
501         auto parentSize = CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
502         auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
503         navigationWidth = static_cast<float>(minNavBarWidth + minContentWidthValue_.ConvertToPx());
504     } else {
505         navigationWidth = static_cast<float>(WINDOW_WIDTH.ConvertToPx());
506     }
507     return navigationWidth;
508 }
509 
UpdateNavigationMode(const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize,const RefPtr<NavigationGroupNode> & hostNode)510 void NavigationLayoutAlgorithm::UpdateNavigationMode(const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty,
511     const SizeF& frameSize, const RefPtr<NavigationGroupNode>& hostNode)
512 {
513     CHECK_NULL_VOID(hostNode);
514     CHECK_NULL_VOID(navigationLayoutProperty);
515     auto usrNavigationMode = navigationLayoutProperty->GetUsrNavigationModeValue(NavigationMode::AUTO);
516     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
517     CHECK_NULL_VOID(navigationPattern);
518     if (navigationPattern->IsForceSplitSuccess()) {
519         usrNavigationMode = NavigationMode::SPLIT;
520     }
521     if (usrNavigationMode == NavigationMode::AUTO) {
522         if (frameSize.Width() >= CalculateNavigationWidth(hostNode)) {
523             usrNavigationMode = NavigationMode::SPLIT;
524             auto targetNode = hostNode->GetNavBarOrHomeDestinationNode();
525             if (targetNode) {
526                 targetNode->SetJSViewActive(true);
527             }
528         } else {
529             usrNavigationMode = NavigationMode::STACK;
530         }
531     }
532     bool modeChange = navigationPattern->GetNavigationMode() != usrNavigationMode;
533     bool isFirstTimeLayout = (navigationPattern->GetNavigationMode() == INITIAL_MODE);
534     bool enableModeChangeAnimation = navigationLayoutProperty->GetEnableModeChangeAnimation().value_or(true);
535     bool doModeSwitchAnimationInAnotherTask =
536         enableModeChangeAnimation && modeChange && !isFirstTimeLayout && !hostNode->IsOnModeSwitchAnimation();
537     if (doModeSwitchAnimationInAnotherTask) {
538         auto container = Container::Current();
539         CHECK_NULL_VOID(container);
540         if (container->IsFoldable()) {
541             // If screen-fold-state changed, no need to do mode switch animation.
542             // Only when navigation-mode changed, it is necessary to update the current screen-fold-state.
543             doModeSwitchAnimationInAnotherTask =
544                 !navigationPattern->JudgeFoldStateChangeAndUpdateState() && doModeSwitchAnimationInAnotherTask;
545         }
546     }
547     if (!doModeSwitchAnimationInAnotherTask) {
548         navigationPattern->SetNavigationMode(usrNavigationMode);
549         navigationPattern->SetNavigationModeChange(modeChange);
550     }
551 
552     auto pipeline = hostNode->GetContext();
553     CHECK_NULL_VOID(pipeline);
554     pipeline->AddAfterLayoutTask([weakNavigationPattern = WeakPtr<NavigationPattern>(navigationPattern),
555         modeChange, doModeSwitchAnimationInAnotherTask]() {
556         auto navigationPattern = weakNavigationPattern.Upgrade();
557         CHECK_NULL_VOID(navigationPattern);
558         if (doModeSwitchAnimationInAnotherTask) {
559             navigationPattern->OnNavBarStateChange(false);
560             SwitchModeWithAnimation(AceType::DynamicCast<NavigationGroupNode>(navigationPattern->GetHost()));
561         } else {
562             if (navigationPattern->IsHomeDestinationVisible()) {
563                 navigationPattern->FireHomeDestinationLifeCycleIfNeeded(NavDestinationLifecycle::ON_SHOW, true);
564                 navigationPattern->FireHomeDestinationLifeCycleIfNeeded(NavDestinationLifecycle::ON_ACTIVE, true);
565             } else {
566                 navigationPattern->FireHomeDestinationLifeCycleIfNeeded(NavDestinationLifecycle::ON_INACTIVE, true);
567                 navigationPattern->FireHomeDestinationLifeCycleIfNeeded(NavDestinationLifecycle::ON_HIDE, true);
568             }
569             navigationPattern->OnNavBarStateChange(modeChange);
570             navigationPattern->OnNavigationModeChange(modeChange);
571         }
572     });
573 }
574 
SizeCalculationForForceSplit(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)575 void NavigationLayoutAlgorithm::SizeCalculationForForceSplit(
576     LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
577     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& frameSize)
578 {
579     auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
580     dividerSize_ = SizeF(dividerWidth, frameSize.Height());
581     auto halfWidth = (frameSize.Width() - dividerWidth) / 2.0f;
582     navBarSize_ = SizeF(halfWidth, frameSize.Height());
583     primaryNodeSize_ = SizeF(halfWidth, frameSize.Height());
584     contentSize_ = SizeF(halfWidth, frameSize.Height());
585     realNavBarWidth_ = halfWidth;
586     realContentWidth_ = halfWidth;
587     realDividerWidth_ = halfWidth;
588 }
589 
SizeCalculation(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)590 void NavigationLayoutAlgorithm::SizeCalculation(LayoutWrapper* layoutWrapper,
591     const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty,
592     const SizeF& frameSize)
593 {
594     auto pipeline = PipelineContext::GetCurrentContext();
595     CHECK_NULL_VOID(pipeline);
596     auto constraint = navigationLayoutProperty->GetLayoutConstraint();
597     auto parentSize = CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
598     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
599     auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
600     if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
601         auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
602         auto maxNavBarWidth = maxNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
603         realNavBarWidth_ = std::min(realNavBarWidth_, static_cast<float>(maxNavBarWidth));
604         realNavBarWidth_ = std::max(realNavBarWidth_, static_cast<float>(minNavBarWidth));
605     } else {
606         auto navBarWidthValue = navigationLayoutProperty->GetNavBarWidthValue(DEFAULT_NAV_BAR_WIDTH);
607         auto navBarWidth = navBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
608         realNavBarWidth_ = navBarWidth;
609     }
610     navBarSize_ = frameSize;
611     contentSize_ = frameSize;
612     dividerSize_ = SizeF(0.0f, frameSize.Height());
613     if (navigationPattern->GetNavigationMode() == NavigationMode::SPLIT ||
614         (navigationPattern->IsForceSplitSuccess() && navigationPattern->IsForceSplitUseNavBar())) {
615         SizeCalculationSplit(hostNode, navigationLayoutProperty, frameSize);
616     } else {
617         SizeCalculationStack(hostNode, navigationLayoutProperty, frameSize);
618     }
619 }
620 
SizeCalculationSplit(const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)621 void NavigationLayoutAlgorithm::SizeCalculationSplit(const RefPtr<NavigationGroupNode>& hostNode,
622     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& frameSize)
623 {
624     auto pattern = hostNode->GetPattern<NavigationPattern>();
625     CHECK_NULL_VOID(pattern);
626     float frameWidth = frameSize.Width();
627     auto parentSize = CreateIdealSizeByPercentRef(
628         navigationLayoutProperty->GetLayoutConstraint().value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
629     auto navBarWidthValue = navigationLayoutProperty->GetNavBarWidthValue(DEFAULT_NAV_BAR_WIDTH);
630     auto userSetNavBarWidth = navBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
631     auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
632     auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
633     auto minContentWidth = minContentWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
634     realContentWidth_ = minContentWidth;
635 
636     bool isHideNavbar = navigationLayoutProperty->GetHideNavBar().value_or(false);
637     if (pattern->IsForceSplitSuccess() && pattern->IsForceSplitUseNavBar()) {
638         dividerSize_.SetWidth(dividerWidth);
639         auto halfWidth = (frameSize.Width() - dividerWidth) / 2.0f;
640         navBarSize_.SetWidth(halfWidth);
641         realNavBarWidth_ = halfWidth;
642         realContentWidth_ = halfWidth;
643     } else if (isHideNavbar) {
644         CHECK_NULL_VOID(hostNode);
645         auto targetNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarOrHomeDestinationNode());
646         CHECK_NULL_VOID(targetNode);
647         auto geometryNode = targetNode->GetGeometryNode();
648         CHECK_NULL_VOID(geometryNode);
649         navBarSize_.SetWidth(geometryNode->GetFrameSize().Width());
650         dividerSize_.SetWidth(0.0f);
651         realNavBarWidth_ = 0.0f;
652         realContentWidth_ = frameWidth;
653     } else {
654         CheckSizeInSplit(frameWidth, userSetNavBarWidth, minNavBarWidth, minContentWidth);
655     }
656 
657     realDividerWidth_ = std::max(realDividerWidth_, 0.0f);
658     realContentWidth_ = std::max(realContentWidth_, 0.0f);
659     realNavBarWidth_ = std::min(realNavBarWidth_, frameWidth);
660     realContentWidth_ = std::min(realContentWidth_, frameWidth);
661     if (realNavBarWidth_ == 0.0f || realContentWidth_ == 0.0f) {
662         realDividerWidth_ = 0.0f;
663     } else {
664         realDividerWidth_ = dividerWidth;
665     }
666     if (!isHideNavbar) {
667         navBarSize_.SetWidth(realNavBarWidth_);
668         dividerSize_.SetWidth(realDividerWidth_);
669     }
670     contentSize_.SetWidth(realContentWidth_);
671 }
672 
CheckSizeInSplit(const float frameWidth,const float userSetNavBarWidth,const float minNavBarWidth,const float minContentWidth)673 void NavigationLayoutAlgorithm::CheckSizeInSplit(
674     const float frameWidth, const float userSetNavBarWidth, const float minNavBarWidth, const float minContentWidth)
675 {
676     auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
677 
678     if (userSetMinContentFlag_ && !userSetNavBarRangeFlag_) {
679         if (minContentWidth >= frameWidth) {
680             realContentWidth_ = frameWidth;
681             realNavBarWidth_ = 0.0f;
682         } else if (realNavBarWidth_ + dividerWidth + minContentWidth <= frameWidth) {
683             realContentWidth_ = frameWidth - realNavBarWidth_ - dividerWidth;
684         } else {
685             realContentWidth_ = minContentWidth;
686             realNavBarWidth_ = frameWidth - realContentWidth_ - dividerWidth;
687         }
688     } else if (!userSetNavBarRangeFlag_ && !userSetMinContentFlag_ && userSetNavBarWidthFlag_) {
689         realNavBarWidth_ = userSetNavBarWidth;
690         realContentWidth_ = frameWidth - realNavBarWidth_ - dividerWidth;
691     } else {
692         float remainingSpace = frameWidth - realNavBarWidth_ - dividerWidth;
693         float remainingMaxSpace = frameWidth - minNavBarWidth - dividerWidth;
694         if (remainingSpace >= minContentWidth) {
695             realContentWidth_ = remainingSpace;
696         } else if (remainingSpace < minContentWidth && remainingMaxSpace > minContentWidth &&
697                    realNavBarWidth_ > minNavBarWidth) {
698             realContentWidth_ = minContentWidth;
699             realNavBarWidth_ = frameWidth - minContentWidth - dividerWidth;
700         } else {
701             realNavBarWidth_ = minNavBarWidth;
702             realContentWidth_ = frameWidth - minNavBarWidth - dividerWidth;
703         }
704     }
705 }
706 
SizeCalculationStack(const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)707 void NavigationLayoutAlgorithm::SizeCalculationStack(const RefPtr<NavigationGroupNode>& hostNode,
708     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& frameSize)
709 {
710     auto contentNode = hostNode->GetContentNode();
711     CHECK_NULL_VOID(contentNode);
712     realDividerWidth_ = 0.0f;
713     float frameWidth = frameSize.Width();
714     navBarSize_.SetWidth(frameWidth);
715     dividerSize_.SetWidth(realDividerWidth_);
716     contentSize_.SetWidth(frameWidth);
717     realContentWidth_ = frameWidth;
718 }
719 
MeasurePrimaryContentNode(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & primaryNodeSize)720 void NavigationLayoutAlgorithm::MeasurePrimaryContentNode(
721     LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
722     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& primaryNodeSize)
723 {
724     CHECK_NULL_VOID(hostNode);
725     auto primaryContentNode = hostNode->GetPrimaryContentNode();
726     CHECK_NULL_VOID(primaryContentNode);
727     auto constraint = navigationLayoutProperty->CreateChildConstraint();
728     bool isAutoHeight = IsAutoHeight(navigationLayoutProperty);
729     auto index = hostNode->GetChildIndexById(primaryContentNode->GetId());
730     auto nodeWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
731     CHECK_NULL_VOID(nodeWrapper);
732     if (isAutoHeight) {
733         nodeWrapper->GetLayoutProperty()->UpdateUserDefinedIdealSize(
734             navigationLayoutProperty->GetCalcLayoutConstraint()->selfIdealSize.value());
735         constraint.selfIdealSize.SetWidth(primaryNodeSize.Width());
736     } else {
737         constraint.selfIdealSize = OptionalSizeF(primaryNodeSize.Width(), primaryNodeSize.Height());
738     }
739     nodeWrapper->Measure(constraint);
740     realNavBarHeight_ = nodeWrapper->GetGeometryNode()->GetFrameSize().Height();
741 }
742 
MeasureNavBarOrHomeDestination(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & navBarSize)743 void NavigationLayoutAlgorithm::MeasureNavBarOrHomeDestination(
744     LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
745     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& navBarSize)
746 {
747     CHECK_NULL_VOID(hostNode);
748     auto targetNode = AceType::DynamicCast<NavDestinationNodeBase>(hostNode->GetNavBarOrHomeDestinationNode());
749     CHECK_NULL_VOID(targetNode);
750     auto index = hostNode->GetChildIndexById(targetNode->GetId());
751     auto targetNodeWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
752     CHECK_NULL_VOID(targetNodeWrapper);
753     auto constraint = navigationLayoutProperty->CreateChildConstraint();
754     if (IsAutoHeight(navigationLayoutProperty)) {
755         targetNodeWrapper->GetLayoutProperty()->UpdateUserDefinedIdealSize(
756             navigationLayoutProperty->GetCalcLayoutConstraint()->selfIdealSize.value());
757         constraint.selfIdealSize.SetWidth(navBarSize.Width());
758     } else {
759         constraint.selfIdealSize = OptionalSizeF(navBarSize.Width(), navBarSize.Height());
760     }
761     auto adjustConstraint = targetNode->AdjustLayoutConstarintIfNeeded(constraint);
762     targetNodeWrapper->Measure(adjustConstraint);
763     realNavBarHeight_ = targetNodeWrapper->GetGeometryNode()->GetFrameSize().Height();
764     realNavBarWidth_ = targetNodeWrapper->GetGeometryNode()->GetFrameSize().Width();
765 }
766 
MeasureContentChild(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & contentSize)767 void NavigationLayoutAlgorithm::MeasureContentChild(LayoutWrapper* layoutWrapper,
768     const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty,
769     const SizeF& contentSize)
770 {
771     auto contentNode = hostNode->GetContentNode();
772     CHECK_NULL_VOID(contentNode);
773     auto index = hostNode->GetChildIndexById(contentNode->GetId());
774     auto contentWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
775     CHECK_NULL_VOID(contentWrapper);
776     auto constraint = navigationLayoutProperty->CreateChildConstraint();
777     if (contentNode->GetChildren().empty()) {
778         constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
779     } else {
780         NavigationLayoutUtil::UpdateConstraintWhenFixOrWrap(navigationLayoutProperty, constraint, contentSize);
781     }
782     contentWrapper->Measure(constraint);
783     realContentHeight_ = contentWrapper->GetGeometryNode()->GetFrameSize().Height();
784     realContentWidth_ = contentWrapper->GetGeometryNode()->GetFrameSize().Width();
785 }
786 
MeasureForceSplitPlaceHolderNode(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & phSize)787 void NavigationLayoutAlgorithm::MeasureForceSplitPlaceHolderNode(
788     LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
789     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& phSize)
790 {
791     auto phNode = AceType::DynamicCast<FrameNode>(hostNode->GetForceSplitPlaceHolderNode());
792     CHECK_NULL_VOID(phNode);
793     auto phProperty = phNode->GetLayoutProperty();
794     CHECK_NULL_VOID(phProperty);
795     auto index = hostNode->GetChildIndexById(phNode->GetId());
796     auto phWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
797     CHECK_NULL_VOID(phWrapper);
798     auto constraint = navigationLayoutProperty->CreateChildConstraint();
799     if (phProperty->GetVisibilityValue(VisibleType::VISIBLE) != VisibleType::VISIBLE) {
800         constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
801     } else {
802         if (IsAutoHeight(navigationLayoutProperty)) {
803             constraint.selfIdealSize.SetWidth(phSize.Width());
804         } else {
805             constraint.selfIdealSize = OptionalSizeF(phSize.Width(), phSize.Height());
806         }
807     }
808     phWrapper->Measure(constraint);
809 }
810 
Measure(LayoutWrapper * layoutWrapper)811 void NavigationLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
812 {
813     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
814     CHECK_NULL_VOID(hostNode);
815     auto pattern = hostNode->GetPattern<NavigationPattern>();
816     CHECK_NULL_VOID(pattern);
817     auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(layoutWrapper->GetLayoutProperty());
818     CHECK_NULL_VOID(navigationLayoutProperty);
819     const auto& constraint = navigationLayoutProperty->GetLayoutConstraint();
820     CHECK_NULL_VOID(constraint);
821     auto geometryNode = layoutWrapper->GetGeometryNode();
822     auto size =
823         CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT).ConvertToSizeT();
824     FitScrollFullWindow(size);
825     pattern->SetNavigationSize(size);
826 
827     const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
828     MinusPaddingToSize(padding, size);
829 
830     pattern->TryForceSplitIfNeeded(size);
831     if (ifNeedInit_) {
832         RangeCalculation(hostNode, navigationLayoutProperty);
833     }
834     if (size.Width() == 0.0f) {
835         auto layoutAlgorithm = layoutWrapper->GetLayoutAlgorithm();
836         if (layoutAlgorithm) {
837             layoutAlgorithm->SetSkipLayout();
838         }
839         return;
840     }
841     GetRange(hostNode);
842     UpdateNavigationMode(navigationLayoutProperty, size, hostNode);
843 
844     if (pattern->IsForceSplitSuccess() && !pattern->IsForceSplitUseNavBar()) {
845         SizeCalculationForForceSplit(layoutWrapper, hostNode, navigationLayoutProperty, size);
846         if (IsNavBarVisible(hostNode)) {
847             MeasureNavBarOrHomeDestination(layoutWrapper, hostNode, navigationLayoutProperty, navBarSize_);
848         }
849         MeasurePrimaryContentNode(layoutWrapper, hostNode, navigationLayoutProperty, primaryNodeSize_);
850     } else {
851         SizeCalculation(layoutWrapper, hostNode, navigationLayoutProperty, size);
852         MeasureNavBarOrHomeDestination(layoutWrapper, hostNode, navigationLayoutProperty, navBarSize_);
853     }
854     if (pattern->IsForceSplitSuccess()) {
855         MeasureForceSplitPlaceHolderNode(layoutWrapper, hostNode, navigationLayoutProperty, contentSize_);
856     }
857 
858     MeasureContentChild(layoutWrapper, hostNode, navigationLayoutProperty, contentSize_);
859     MeasureDivider(layoutWrapper, hostNode, navigationLayoutProperty, dividerSize_);
860     MeasureDragBar(layoutWrapper, hostNode, navigationLayoutProperty, dividerSize_);
861     MeasureSplitPlaceholder(layoutWrapper, hostNode, navigationLayoutProperty, contentSize_);
862 
863     ReCalcNavigationSize(layoutWrapper, size);
864 }
865 
Layout(LayoutWrapper * layoutWrapper)866 void NavigationLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
867 {
868     auto layoutAlgorithm = layoutWrapper->GetLayoutAlgorithm();
869     if (layoutAlgorithm && layoutAlgorithm->SkipLayout()) {
870         return;
871     }
872     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
873     CHECK_NULL_VOID(hostNode);
874     auto pattern = hostNode->GetPattern<NavigationPattern>();
875     CHECK_NULL_VOID(pattern);
876     auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(layoutWrapper->GetLayoutProperty());
877     CHECK_NULL_VOID(navigationLayoutProperty);
878 
879     NavBarPosition navBarPosition = NavBarPosition::START;
880     float navBarOrPrimarNodeWidth = 0.0f;
881     if (pattern->IsForceSplitSuccess() && !pattern->IsForceSplitUseNavBar()) {
882         if (IsNavBarVisible(hostNode)) {
883             OffsetF navBarOffset(0.0, 0.0);
884             LayoutNavBarOrHomeDestination(
885                 layoutWrapper, hostNode, navigationLayoutProperty, navBarPosition, navBarOffset);
886         }
887         navBarOrPrimarNodeWidth = LayoutPrimaryContentNode(layoutWrapper, hostNode, navigationLayoutProperty);
888     } else {
889         navBarPosition = pattern->IsForceSplitUseNavBar() ? NavBarPosition::START :
890             navigationLayoutProperty->GetNavBarPositionValue(NavBarPosition::START);
891         OffsetF navBarOffset(0.0, 0.0);
892         navBarOrPrimarNodeWidth = LayoutNavBarOrHomeDestination(
893             layoutWrapper, hostNode, navigationLayoutProperty, navBarPosition, navBarOffset);
894     }
895 
896     float dividerWidth = LayoutDivider(
897         layoutWrapper, hostNode, navigationLayoutProperty, navBarOrPrimarNodeWidth, navBarPosition);
898     auto splitPlaceholderOffsetX = navBarOrPrimarNodeWidth + dividerWidth;
899     LayoutSplitPalceholderContent(
900         layoutWrapper, hostNode, navigationLayoutProperty, splitPlaceholderOffsetX, navBarPosition);
901     LayoutContent(
902         layoutWrapper, hostNode, navigationLayoutProperty, navBarOrPrimarNodeWidth, dividerWidth, navBarPosition);
903     LayoutDragBar(layoutWrapper, hostNode, navigationLayoutProperty, navBarOrPrimarNodeWidth, navBarPosition);
904     if (pattern->IsForceSplitSuccess()) {
905         LayoutForceSplitPlaceHolderNode(
906             layoutWrapper, hostNode, navigationLayoutProperty, navBarOrPrimarNodeWidth, dividerWidth);
907     }
908 
909     auto&& opts = navigationLayoutProperty->GetSafeAreaExpandOpts();
910     if (opts) {
911         auto geometryNode = hostNode->GetGeometryNode();
912         CHECK_NULL_VOID(geometryNode);
913         TAG_LOGD(AceLogTag::ACE_NAVIGATION,
914             "Navigation id is %{public}d, frameRect is %{public}s",
915             hostNode->GetId(), geometryNode->GetFrameRect().ToString().c_str());
916     }
917 }
918 
SetNavigationHeight(LayoutWrapper * layoutWrapper,SizeF & size)919 void NavigationLayoutAlgorithm::SetNavigationHeight(LayoutWrapper* layoutWrapper, SizeF& size)
920 {
921     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
922     CHECK_NULL_VOID(hostNode);
923     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
924     CHECK_NULL_VOID(navigationPattern);
925     auto navigationStack = navigationPattern->GetNavigationStack();
926     CHECK_NULL_VOID(navigationStack);
927     if (navigationStack->Empty()) {
928         size.SetHeight(realNavBarHeight_);
929     } else if (navigationPattern->GetNavigationMode() == NavigationMode::STACK) {
930         size.SetHeight(realContentHeight_);
931     } else if (navigationPattern->GetNavigationMode() == NavigationMode::SPLIT) {
932         float navHeight = std::max(realContentHeight_, realNavBarHeight_);
933         size.SetHeight(navHeight);
934     }
935 }
936 
SetNavigationWidth(LayoutWrapper * layoutWrapper,SizeF & size)937 void NavigationLayoutAlgorithm::SetNavigationWidth(LayoutWrapper* layoutWrapper, SizeF& size)
938 {
939     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
940     CHECK_NULL_VOID(hostNode);
941     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
942     CHECK_NULL_VOID(navigationPattern);
943     auto navigationStack = navigationPattern->GetNavigationStack();
944     CHECK_NULL_VOID(navigationStack);
945     auto navigationLayoutProperty = hostNode->GetLayoutProperty<NavigationLayoutProperty>();
946     CHECK_NULL_VOID(navigationLayoutProperty);
947     if (navigationStack->Empty()) {
948         size.SetWidth(realNavBarWidth_);
949     } else if (navigationPattern->GetNavigationMode() == NavigationMode::STACK) {
950         size.SetWidth(realContentWidth_);
951     } else if (navigationPattern->GetNavigationMode() == NavigationMode::SPLIT) {
952         float navWidth = realContentWidth_ + realNavBarWidth_;
953         size.SetWidth(navWidth);
954         size.AddWidth(realDividerWidth_);
955     }
956 }
957 
ReCalcNavigationSize(LayoutWrapper * layoutWrapper,SizeF & size)958 void NavigationLayoutAlgorithm::ReCalcNavigationSize(LayoutWrapper* layoutWrapper, SizeF& size)
959 {
960     auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(layoutWrapper->GetLayoutProperty());
961     CHECK_NULL_VOID(navigationLayoutProperty);
962     const auto& padding = navigationLayoutProperty->CreatePaddingAndBorder();
963 
964     auto layoutPolicy = navigationLayoutProperty->GetLayoutPolicyProperty();
965     bool isHeightWrapOrFix =
966         layoutPolicy.has_value() ? (layoutPolicy->IsHeightWrap() || layoutPolicy->IsHeightFix()) : false;
967     bool isWidthWrapOrFix =
968         layoutPolicy.has_value() ? (layoutPolicy->IsWidthWrap() || layoutPolicy->IsWidthFix()) : false;
969     if (IsAutoHeight(navigationLayoutProperty) || isHeightWrapOrFix) {
970         SetNavigationHeight(layoutWrapper, size);
971     }
972     if (isWidthWrapOrFix) {
973         SetNavigationWidth(layoutWrapper, size);
974     }
975     size.AddWidth(padding.left.value_or(0.0f) + padding.right.value_or(0.0f));
976     size.AddHeight(padding.top.value_or(0.0f) + padding.bottom.value_or(0.0f));
977 
978     auto realSize = UpdateOptionSizeByCalcLayoutConstraint(OptionalSizeF(size.Width(), size.Height()),
979         navigationLayoutProperty->GetCalcLayoutConstraint(),
980         navigationLayoutProperty->GetLayoutConstraint()->percentReference);
981 
982     layoutWrapper->GetGeometryNode()->SetFrameSize(realSize.ConvertToSizeT());
983 }
984 
985 } // namespace OHOS::Ace::NG
986