• 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 <cmath>
19 
20 #include "base/geometry/dimension.h"
21 #include "base/geometry/ng/offset_t.h"
22 #include "base/geometry/ng/size_t.h"
23 #include "base/log/ace_trace.h"
24 #include "base/memory/ace_type.h"
25 #include "base/utils/utils.h"
26 #include "core/components/common/layout/constants.h"
27 #include "core/components_ng/base/frame_node.h"
28 #include "core/components_ng/layout/layout_algorithm.h"
29 #include "core/components_ng/pattern/linear_layout/linear_layout_property.h"
30 #include "core/components_ng/pattern/navigation/nav_bar_layout_property.h"
31 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
32 #include "core/components_ng/pattern/navigation/navigation_declaration.h"
33 #include "core/components_ng/pattern/navigation/navigation_group_node.h"
34 #include "core/components_ng/pattern/navigation/navigation_layout_property.h"
35 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
36 #include "core/components_ng/pattern/navrouter/navdestination_group_node.h"
37 #include "core/components_ng/property/calc_length.h"
38 #include "core/components_ng/property/layout_constraint.h"
39 #include "core/components_ng/property/measure_property.h"
40 #include "core/components_ng/property/measure_utils.h"
41 #include "core/pipeline_ng/pipeline_context.h"
42 
43 namespace OHOS::Ace::NG {
44 
45 constexpr static int32_t PLATFORM_VERSION_TEN = 10;
46 constexpr Dimension WINDOW_WIDTH = 520.0_vp;
47 
48 namespace {
49 
MeasureDivider(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & dividerSize)50 void MeasureDivider(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
51     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& dividerSize)
52 {
53     auto dividerNode = hostNode->GetDividerNode();
54     CHECK_NULL_VOID(dividerNode);
55     auto index = hostNode->GetChildIndexById(dividerNode->GetId());
56     auto dividerWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
57     CHECK_NULL_VOID(dividerWrapper);
58     auto constraint = navigationLayoutProperty->CreateChildConstraint();
59     constraint.selfIdealSize = OptionalSizeF(dividerSize.Width(), dividerSize.Height());
60     dividerWrapper->Measure(constraint);
61 }
62 
LayoutNavBar(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const NavBarPosition & position,OffsetF & returnNavBarOffset)63 float LayoutNavBar(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
64     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const NavBarPosition& position,
65     OffsetF& returnNavBarOffset)
66 {
67     auto layoutAlgorithmWrapper = AceType::DynamicCast<LayoutAlgorithmWrapper>(layoutWrapper->GetLayoutAlgorithm());
68     CHECK_NULL_RETURN(layoutAlgorithmWrapper, 0.0f);
69     auto navigationLayoutAlgorithm =
70         AceType::DynamicCast<NavigationLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
71     if (navigationLayoutProperty->GetHideNavBar().value_or(false) &&
72         navigationLayoutAlgorithm->GetNavigationMode() == NavigationMode::SPLIT) {
73         return 0.0f;
74     }
75     auto contentNode = hostNode->GetContentNode();
76     CHECK_NULL_RETURN(contentNode, 0.0f);
77     auto navBarNode = hostNode->GetNavBarNode();
78     CHECK_NULL_RETURN(navBarNode, 0.0f);
79     auto index = hostNode->GetChildIndexById(navBarNode->GetId());
80     auto navBarWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
81     CHECK_NULL_RETURN(navBarWrapper, 0.0f);
82     auto geometryNode = navBarWrapper->GetGeometryNode();
83     auto navigationGeometryNode = layoutWrapper->GetGeometryNode();
84     if (position == NavBarPosition::END) {
85         auto navBarOffset =
86             OffsetT<float>(navigationGeometryNode->GetFrameSize().Width() - geometryNode->GetFrameSize().Width(),
87                 geometryNode->GetFrameOffset().GetY());
88         geometryNode->SetMarginFrameOffset(navBarOffset);
89         navBarWrapper->Layout();
90         returnNavBarOffset = navBarOffset;
91         return geometryNode->GetFrameSize().Width();
92     }
93     auto navBarOffset = OffsetT<float>(0.0f, 0.0f);
94     geometryNode->SetMarginFrameOffset(navBarOffset);
95     navBarWrapper->Layout();
96     returnNavBarOffset = navBarOffset;
97     return geometryNode->GetFrameSize().Width();
98 }
99 
LayoutDivider(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float navBarWidth,const NavBarPosition & position)100 float LayoutDivider(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
101     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float navBarWidth, const NavBarPosition& position)
102 {
103     auto dividerNode = hostNode->GetDividerNode();
104     CHECK_NULL_RETURN(dividerNode, 0.0f);
105     auto index = hostNode->GetChildIndexById(dividerNode->GetId());
106     auto dividerWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
107     CHECK_NULL_RETURN(dividerWrapper, 0.0f);
108     auto geometryNode = dividerWrapper->GetGeometryNode();
109     auto navigationGeometryNode = layoutWrapper->GetGeometryNode();
110     OffsetT<float> dividerOffset;
111     if (position == NavBarPosition::END) {
112         dividerOffset = OffsetT<float>(
113             navigationGeometryNode->GetFrameSize().Width() - geometryNode->GetFrameSize().Width() - navBarWidth,
114             geometryNode->GetFrameOffset().GetY());
115     } else {
116         dividerOffset = OffsetT<float>(navBarWidth, geometryNode->GetFrameOffset().GetY());
117     }
118     geometryNode->SetMarginFrameOffset(dividerOffset);
119     dividerWrapper->Layout();
120     return geometryNode->GetFrameSize().Width();
121 }
122 
LayoutContent(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,float navBarWidth,float dividerWidth,const NavBarPosition & position)123 void LayoutContent(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
124     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, float navBarWidth, float dividerWidth,
125     const NavBarPosition& position)
126 {
127     auto contentNode = hostNode->GetContentNode();
128     CHECK_NULL_VOID(contentNode);
129     auto index = hostNode->GetChildIndexById(contentNode->GetId());
130     auto contentWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
131     CHECK_NULL_VOID(contentWrapper);
132     auto geometryNode = contentWrapper->GetGeometryNode();
133     CHECK_NULL_VOID(geometryNode);
134 
135     auto layoutAlgorithmWrapper = AceType::DynamicCast<LayoutAlgorithmWrapper>(layoutWrapper->GetLayoutAlgorithm());
136     CHECK_NULL_VOID(layoutAlgorithmWrapper);
137     auto navigationLayoutAlgorithm =
138         AceType::DynamicCast<NavigationLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
139     auto contentChildSize = contentNode->GetChildren().size();
140 
141     // cases that content layouts from start
142     // 1. displaying content pages in STACK mode
143     // 2. placing navBar at the end
144     // 3. hiding navBar in SPLIT mode
145     if ((contentChildSize != 0 && navigationLayoutAlgorithm->GetNavigationMode() == NavigationMode::STACK) ||
146         position == NavBarPosition::END ||
147         (navigationLayoutProperty->GetHideNavBar().value_or(false) &&
148             navigationLayoutAlgorithm->GetNavigationMode() == NavigationMode::SPLIT)) {
149         auto contentOffset = OffsetT<float>(0.0f, 0.0f);
150         geometryNode->SetMarginFrameOffset(contentOffset);
151         contentWrapper->Layout();
152         return;
153     }
154     auto contentOffset = OffsetT<float>(navBarWidth + dividerWidth, geometryNode->GetFrameOffset().GetY());
155     geometryNode->SetMarginFrameOffset(contentOffset);
156     contentWrapper->Layout();
157 }
158 
FitScrollFullWindow(SizeF & frameSize)159 void FitScrollFullWindow(SizeF& frameSize)
160 {
161     auto pipeline = PipelineContext::GetCurrentContext();
162     CHECK_NULL_VOID_NOLOG(pipeline);
163     if (frameSize.Width() == Infinity<float>()) {
164         frameSize.SetWidth(pipeline->GetRootWidth());
165     }
166     if (frameSize.Height() == Infinity<float>()) {
167         frameSize.SetHeight(pipeline->GetRootHeight());
168     }
169 }
170 
171 } // namespace
172 
IsAutoHeight(const RefPtr<LayoutProperty> & layoutProperty)173 bool NavigationLayoutAlgorithm::IsAutoHeight(const RefPtr<LayoutProperty>& layoutProperty)
174 {
175     CHECK_NULL_RETURN(layoutProperty, false);
176     auto& calcLayoutConstraint = layoutProperty->GetCalcLayoutConstraint();
177     if (!calcLayoutConstraint || !calcLayoutConstraint->selfIdealSize.has_value() ||
178         !calcLayoutConstraint->selfIdealSize->Height().has_value() ||
179         (calcLayoutConstraint->selfIdealSize->Height().value().ToString().find("auto") == std::string::npos)) {
180         return false;
181     }
182     return true;
183 }
184 
RangeCalculation(const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty)185 void NavigationLayoutAlgorithm::RangeCalculation(
186     const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty)
187 {
188     const auto& constraint = navigationLayoutProperty->GetLayoutConstraint();
189     CHECK_NULL_VOID(constraint);
190     auto parentSize = CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
191     auto frameSize = parentSize.ConvertToSizeT();
192     float frameSizeWidth = frameSize.Width();
193     Dimension defaultValue = Dimension(-1.0);
194     auto pipeline = PipelineContext::GetCurrentContext();
195     CHECK_NULL_VOID(pipeline);
196 
197     minContentWidthValue_ = navigationLayoutProperty->GetMinContentWidthValue(defaultValue);
198     if (minContentWidthValue_ == defaultValue) {
199         userSetMinContentFlag_ = false;
200         minContentWidthValue_ = DEFAULT_MIN_CONTENT_WIDTH;
201     } else {
202         userSetMinContentFlag_ = true;
203     }
204     minNavBarWidthValue_ = navigationLayoutProperty->GetMinNavBarWidthValue(DEFAULT_MIN_NAV_BAR_WIDTH);
205     auto userSetMaxNavBarWidthValue = navigationLayoutProperty->GetMaxNavBarWidthValue(defaultValue);
206 
207     float minNavBarWidth =
208         std::min(static_cast<float>(minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f))),
209             frameSizeWidth);
210     float maxNavBarWidth = 0.0f;
211     if (userSetMaxNavBarWidthValue == defaultValue) {
212         userSetNavBarRangeFlag_ = false;
213         maxNavBarWidth = std::min(
214             static_cast<float>(DEFAULT_MAX_NAV_BAR_WIDTH.ConvertToPx()), frameSizeWidth * MAX_NAV_BAR_WIDTH_SCALE);
215     } else {
216         userSetNavBarRangeFlag_ = true;
217         maxNavBarWidth =
218             static_cast<float>(userSetMaxNavBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f)));
219     }
220     maxNavBarWidthValue_ = Dimension(std::max(maxNavBarWidth, minNavBarWidth), DimensionUnit::PX);
221     auto navBarWidthValue = navigationLayoutProperty->GetNavBarWidthValue(DEFAULT_NAV_BAR_WIDTH);
222     auto navBarWidth = navBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
223     realNavBarWidth_ = navBarWidth;
224     auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
225     if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
226         auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
227         auto maxNavBarWidth = maxNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
228         realNavBarWidth_ = std::max(realNavBarWidth_, static_cast<float>(minNavBarWidth));
229         realNavBarWidth_ = std::min(realNavBarWidth_, static_cast<float>(maxNavBarWidth));
230     }
231     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
232     CHECK_NULL_VOID(navigationPattern);
233     navigationPattern->SetMinNavBarWidthValue(minNavBarWidthValue_);
234     navigationPattern->SetMaxNavBarWidthValue(maxNavBarWidthValue_);
235     navigationPattern->SetMinContentWidthValue(minContentWidthValue_);
236     navigationPattern->SetUserSetNavBarRangeFlag(userSetNavBarRangeFlag_);
237     navigationPattern->SetUserSetMinContentFlag(userSetMinContentFlag_);
238 }
239 
GetRange(const RefPtr<NavigationGroupNode> & hostNode)240 void NavigationLayoutAlgorithm::GetRange(const RefPtr<NavigationGroupNode>& hostNode)
241 {
242     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
243     CHECK_NULL_VOID(navigationPattern);
244     minNavBarWidthValue_ = navigationPattern->GetMinNavBarWidthValue();
245     maxNavBarWidthValue_ = navigationPattern->GetMaxNavBarWidthValue();
246     minContentWidthValue_ = navigationPattern->GetMinContentWidthValue();
247     userSetNavBarRangeFlag_ = navigationPattern->GetUserSetNavBarRangeFlag();
248     userSetMinContentFlag_ = navigationPattern->GetUserSetMinContentFlag();
249     userSetNavBarWidthFlag_ = navigationPattern->GetUserSetNavBarWidthFlag();
250 }
251 
UpdateNavigationMode(const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)252 void NavigationLayoutAlgorithm::UpdateNavigationMode(
253     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& frameSize)
254 {
255     auto usrNavigationMode = navigationLayoutProperty->GetUsrNavigationModeValue(NavigationMode::AUTO);
256     auto pipeline = PipelineContext::GetCurrentContext();
257     CHECK_NULL_VOID(pipeline);
258     auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
259 
260     auto navigationWidth = 0.0f;
261     if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
262         navigationWidth = static_cast<float>(minNavBarWidthValue_.ConvertToPx() + minContentWidthValue_.ConvertToPx());
263     } else {
264         navigationWidth = static_cast<float>(WINDOW_WIDTH.ConvertToPx());
265     }
266     if (usrNavigationMode == NavigationMode::AUTO) {
267         if (frameSize.Width() >= navigationWidth) {
268             usrNavigationMode = NavigationMode::SPLIT;
269         } else {
270             usrNavigationMode = NavigationMode::STACK;
271         }
272     }
273     SetNavigationMode(usrNavigationMode);
274 }
275 
SizeCalculation(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)276 void NavigationLayoutAlgorithm::SizeCalculation(LayoutWrapper* layoutWrapper,
277     const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty,
278     const SizeF& frameSize)
279 {
280     auto pipeline = PipelineContext::GetCurrentContext();
281     CHECK_NULL_VOID(pipeline);
282     auto constraint = navigationLayoutProperty->GetLayoutConstraint();
283     auto parentSize = CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
284     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(layoutWrapper->GetLayoutAlgorithm());
285     CHECK_NULL_VOID(layoutAlgorithmWrapper);
286     auto navigationLayoutAlgorithm =
287         AceType::DynamicCast<NavigationLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
288     auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
289     if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
290         auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
291         auto maxNavBarWidth = maxNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
292         realNavBarWidth_ = std::min(realNavBarWidth_, static_cast<float>(maxNavBarWidth));
293         realNavBarWidth_ = std::max(realNavBarWidth_, static_cast<float>(minNavBarWidth));
294     } else {
295         auto navBarWidthValue = navigationLayoutProperty->GetNavBarWidthValue(DEFAULT_NAV_BAR_WIDTH);
296         auto navBarWidth = navBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
297         realNavBarWidth_ = navBarWidth;
298     }
299     navBarSize_ = frameSize;
300     contentSize_ = frameSize;
301     dividerSize_ = SizeF(0.0f, frameSize.Height());
302     if (GetNavigationMode() == NavigationMode::SPLIT) {
303         SizeCalculationSplit(navigationLayoutProperty, frameSize);
304     } else {
305         SizeCalculationStack(hostNode, navigationLayoutProperty, frameSize);
306     }
307 }
308 
SizeCalculationSplit(const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)309 void NavigationLayoutAlgorithm::SizeCalculationSplit(
310     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& frameSize)
311 {
312     float frameWidth = frameSize.Width();
313     auto parentSize = CreateIdealSizeByPercentRef(
314         navigationLayoutProperty->GetLayoutConstraint().value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
315     auto navBarWidthValue = navigationLayoutProperty->GetNavBarWidthValue(DEFAULT_NAV_BAR_WIDTH);
316     auto userSetNavBarWidth = navBarWidthValue.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
317     auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
318     auto minNavBarWidth = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
319     auto minContentWidth = minContentWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
320     realContentWidth_ = minContentWidth;
321 
322     if (navigationLayoutProperty->GetHideNavBar().value_or(false)) {
323         navBarSize_ = SizeF(0.0f, 0.0f);
324         dividerSize_ = SizeF(0.0f, 0.0f);
325         realNavBarWidth_ = 0.0f;
326         realContentWidth_ = frameWidth;
327     } else {
328         CheckSizeInSplit(frameWidth, userSetNavBarWidth, minNavBarWidth, minContentWidth);
329     }
330 
331     realDividerWidth_ = std::max(realDividerWidth_, 0.0f);
332     realContentWidth_ = std::max(realContentWidth_, 0.0f);
333     realNavBarWidth_ = std::min(realNavBarWidth_, frameWidth);
334     realContentWidth_ = std::min(realContentWidth_, frameWidth);
335     if (realNavBarWidth_ == 0.0f || realContentWidth_ == 0.0f) {
336         realDividerWidth_ = 0.0f;
337     } else {
338         realDividerWidth_ = dividerWidth;
339     }
340     navBarSize_.SetWidth(realNavBarWidth_);
341     dividerSize_.SetWidth(realDividerWidth_);
342     contentSize_.SetWidth(realContentWidth_);
343 }
344 
CheckSizeInSplit(const float frameWidth,const float userSetNavBarWidth,const float minNavBarWidth,const float minContentWidth)345 void NavigationLayoutAlgorithm::CheckSizeInSplit(
346     const float frameWidth, const float userSetNavBarWidth, const float minNavBarWidth, const float minContentWidth)
347 {
348     auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
349 
350     if (userSetMinContentFlag_ && !userSetNavBarRangeFlag_) {
351         if (minContentWidth >= frameWidth) {
352             realContentWidth_ = frameWidth;
353             realNavBarWidth_ = 0.0f;
354         } else if (realNavBarWidth_ + dividerWidth + minContentWidth <= frameWidth) {
355             realContentWidth_ = frameWidth - realNavBarWidth_ - dividerWidth;
356         } else {
357             realContentWidth_ = minContentWidth;
358             realNavBarWidth_ = frameWidth - realContentWidth_ - dividerWidth;
359         }
360     } else if (!userSetNavBarRangeFlag_ && !userSetMinContentFlag_ && userSetNavBarWidthFlag_) {
361         realNavBarWidth_ = userSetNavBarWidth;
362         realContentWidth_ = frameWidth - realNavBarWidth_ - dividerWidth;
363     } else {
364         float remainingSpace = frameWidth - realNavBarWidth_ - dividerWidth;
365         float remainingMaxSpace = frameWidth - minNavBarWidth - dividerWidth;
366         if (remainingSpace >= minContentWidth) {
367             realContentWidth_ = remainingSpace;
368         } else if (remainingSpace < minContentWidth && remainingMaxSpace > minContentWidth &&
369                    realNavBarWidth_ > minNavBarWidth) {
370             realContentWidth_ = minContentWidth;
371             realNavBarWidth_ = frameWidth - minContentWidth - dividerWidth;
372         } else {
373             realNavBarWidth_ = minNavBarWidth;
374             realContentWidth_ = frameWidth - minNavBarWidth - dividerWidth;
375         }
376     }
377 }
378 
SizeCalculationStack(const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & frameSize)379 void NavigationLayoutAlgorithm::SizeCalculationStack(const RefPtr<NavigationGroupNode>& hostNode,
380     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& frameSize)
381 {
382     auto contentNode = hostNode->GetContentNode();
383     CHECK_NULL_VOID(contentNode);
384     realDividerWidth_ = 0.0f;
385     float frameWidth = frameSize.Width();
386     navBarSize_.SetWidth(frameWidth);
387     dividerSize_.SetWidth(realDividerWidth_);
388     contentSize_.SetWidth(frameWidth);
389     realContentWidth_ = frameWidth;
390 }
391 
MeasureNavBar(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & navBarSize)392 void NavigationLayoutAlgorithm::MeasureNavBar(LayoutWrapper* layoutWrapper, const RefPtr<NavigationGroupNode>& hostNode,
393     const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty, const SizeF& navBarSize)
394 {
395     auto navBarNode = hostNode->GetNavBarNode();
396     CHECK_NULL_VOID(navBarNode);
397     auto index = hostNode->GetChildIndexById(navBarNode->GetId());
398     auto navBarWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
399     CHECK_NULL_VOID(navBarWrapper);
400     auto constraint = navigationLayoutProperty->CreateChildConstraint();
401     if (IsAutoHeight(navigationLayoutProperty)) {
402         navBarWrapper->GetLayoutProperty()->UpdateUserDefinedIdealSize(
403             navigationLayoutProperty->GetCalcLayoutConstraint()->selfIdealSize.value());
404         constraint.selfIdealSize.SetWidth(navBarSize.Width());
405     } else {
406         constraint.selfIdealSize = OptionalSizeF(navBarSize.Width(), navBarSize.Height());
407     }
408     navBarWrapper->Measure(constraint);
409     realNavBarHeight_ = navBarWrapper->GetGeometryNode()->GetFrameSize().Height();
410 }
411 
MeasureContentChild(LayoutWrapper * layoutWrapper,const RefPtr<NavigationGroupNode> & hostNode,const RefPtr<NavigationLayoutProperty> & navigationLayoutProperty,const SizeF & contentSize)412 void NavigationLayoutAlgorithm::MeasureContentChild(LayoutWrapper* layoutWrapper,
413     const RefPtr<NavigationGroupNode>& hostNode, const RefPtr<NavigationLayoutProperty>& navigationLayoutProperty,
414     const SizeF& contentSize)
415 {
416     auto contentNode = hostNode->GetContentNode();
417     CHECK_NULL_VOID(contentNode);
418     auto index = hostNode->GetChildIndexById(contentNode->GetId());
419     auto contentWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
420     CHECK_NULL_VOID(contentWrapper);
421     auto constraint = navigationLayoutProperty->CreateChildConstraint();
422     if (contentNode->GetChildren().empty()) {
423         constraint.selfIdealSize = OptionalSizeF(0.0f, 0.0f);
424     } else {
425         if (IsAutoHeight(navigationLayoutProperty)) {
426             constraint.selfIdealSize.SetWidth(contentSize.Width());
427         } else {
428             constraint.selfIdealSize = OptionalSizeF(contentSize.Width(), contentSize.Height());
429         }
430     }
431     contentWrapper->Measure(constraint);
432     realContentHeight_ = contentWrapper->GetGeometryNode()->GetFrameSize().Height();
433 }
434 
Measure(LayoutWrapper * layoutWrapper)435 void NavigationLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
436 {
437     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
438     CHECK_NULL_VOID(hostNode);
439     auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(layoutWrapper->GetLayoutProperty());
440     CHECK_NULL_VOID(navigationLayoutProperty);
441     const auto& constraint = navigationLayoutProperty->GetLayoutConstraint();
442     CHECK_NULL_VOID(constraint);
443     auto geometryNode = layoutWrapper->GetGeometryNode();
444     auto size =
445         CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT).ConvertToSizeT();
446     FitScrollFullWindow(size);
447     const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
448     MinusPaddingToSize(padding, size);
449     if (ifNeedInit_) {
450         RangeCalculation(hostNode, navigationLayoutProperty);
451     }
452     if (size.Width() == 0.0f) {
453         return;
454     }
455     GetRange(hostNode);
456     UpdateNavigationMode(navigationLayoutProperty, size);
457     SizeCalculation(layoutWrapper, hostNode, navigationLayoutProperty, size);
458 
459     MeasureNavBar(layoutWrapper, hostNode, navigationLayoutProperty, navBarSize_);
460     MeasureContentChild(layoutWrapper, hostNode, navigationLayoutProperty, contentSize_);
461     MeasureDivider(layoutWrapper, hostNode, navigationLayoutProperty, dividerSize_);
462     if (IsAutoHeight(navigationLayoutProperty)) {
463         SetNavigationHeight(layoutWrapper, size);
464     }
465     layoutWrapper->GetGeometryNode()->SetFrameSize(size);
466 }
467 
Layout(LayoutWrapper * layoutWrapper)468 void NavigationLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
469 {
470     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
471     CHECK_NULL_VOID(hostNode);
472     auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(layoutWrapper->GetLayoutProperty());
473     CHECK_NULL_VOID(navigationLayoutProperty);
474     auto navBarPosition = navigationLayoutProperty->GetNavBarPositionValue(NavBarPosition::START);
475     OffsetF navBarOffset(0.0, 0.0);
476     float navBarWidth = LayoutNavBar(layoutWrapper, hostNode, navigationLayoutProperty, navBarPosition, navBarOffset);
477     float dividerWidth = LayoutDivider(layoutWrapper, hostNode, navigationLayoutProperty, navBarWidth, navBarPosition);
478     LayoutContent(layoutWrapper, hostNode, navigationLayoutProperty, navBarWidth, dividerWidth, navBarPosition);
479     navBarOffset_ = navBarOffset;
480 }
481 
SetNavigationHeight(LayoutWrapper * layoutWrapper,SizeF & size)482 void NavigationLayoutAlgorithm::SetNavigationHeight(LayoutWrapper* layoutWrapper, SizeF& size)
483 {
484     auto hostNode = AceType::DynamicCast<NavigationGroupNode>(layoutWrapper->GetHostNode());
485     CHECK_NULL_VOID(hostNode);
486     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
487     CHECK_NULL_VOID(navigationPattern);
488     auto navigationStack = navigationPattern->GetNavigationStack();
489     CHECK_NULL_VOID(navigationStack);
490     if (navigationStack->Empty()) {
491         size.SetHeight(realNavBarHeight_);
492     } else if (navigationMode_ == NavigationMode::STACK) {
493         size.SetHeight(realContentHeight_);
494     } else if (navigationMode_ == NavigationMode::SPLIT) {
495         float navHeight = std::max(realContentHeight_, realNavBarHeight_);
496         size.SetHeight(navHeight);
497     }
498 }
499 
500 } // namespace OHOS::Ace::NG
501