• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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/menu/multi_menu_layout_algorithm.h"
17 
18 #include "base/geometry/dimension.h"
19 #include "base/geometry/ng/offset_t.h"
20 #include "base/utils/utils.h"
21 #include "core/components/common/layout/grid_system_manager.h"
22 #include "core/components_ng/layout/box_layout_algorithm.h"
23 #include "core/components_ng/property/measure_utils.h"
24 
25 namespace OHOS::Ace::NG {
Measure(LayoutWrapper * layoutWrapper)26 void MultiMenuLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
27 {
28     CHECK_NULL_VOID(layoutWrapper);
29     auto layoutProperty = layoutWrapper->GetLayoutProperty();
30     CHECK_NULL_VOID(layoutProperty);
31     auto layoutConstraint = layoutProperty->GetLayoutConstraint();
32     CHECK_NULL_VOID(layoutConstraint);
33     auto childConstraint = layoutProperty->CreateChildConstraint();
34     childConstraint.maxSize.SetWidth(layoutConstraint->maxSize.Width());
35     // constraint max size minus padding
36     const auto& padding = layoutProperty->CreatePaddingAndBorder();
37     MinusPaddingToSize(padding, childConstraint.maxSize);
38     if (layoutConstraint->selfIdealSize.Width().has_value()) {
39         // when Menu is set self ideal width, make children node adaptively fill up.
40         auto idealWidth =
41             std::max(layoutConstraint->minSize.Width(),
42                 std::min(layoutConstraint->maxSize.Width(), layoutConstraint->selfIdealSize.Width().value())) -
43             padding.Width();
44         childConstraint.selfIdealSize.SetWidth(idealWidth);
45     } else {
46         // constraint min width base on grid column
47         auto columnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::MENU);
48         CHECK_NULL_VOID(columnInfo);
49         CHECK_NULL_VOID(columnInfo->GetParent());
50         columnInfo->GetParent()->BuildColumnWidth();
51         auto minWidth = static_cast<float>(columnInfo->GetWidth()) - padding.Width();
52         childConstraint.minSize.SetWidth(minWidth);
53     }
54     // Calculate max width of menu items
55     UpdateConstraintBaseOnMenuItems(layoutWrapper, childConstraint);
56 
57     float contentHeight = 0.0f;
58     float contentWidth = childConstraint.selfIdealSize.Width().value();
59     for (const auto& child : layoutWrapper->GetAllChildrenWithBuild()) {
60         child->Measure(ResetLayoutConstraintMinWidth(child, childConstraint));
61         auto childSize = child->GetGeometryNode()->GetMarginFrameSize();
62         LOGD("child finish measure, child %{public}s size = %{public}s", child->GetHostTag().c_str(),
63             child->GetGeometryNode()->GetMarginFrameSize().ToString().c_str());
64         contentHeight += childSize.Height();
65     }
66     layoutWrapper->GetGeometryNode()->SetContentSize(SizeF(contentWidth, contentHeight));
67     BoxLayoutAlgorithm::PerformMeasureSelf(layoutWrapper);
68 
69     if (layoutConstraint->selfIdealSize.Width().has_value()) {
70         auto idealWidth = std::max(layoutConstraint->minSize.Width(),
71             std::min(layoutConstraint->maxSize.Width(), layoutConstraint->selfIdealSize.Width().value()));
72         auto idealSize = layoutWrapper->GetGeometryNode()->GetFrameSize();
73         idealSize.SetWidth(idealWidth);
74         layoutWrapper->GetGeometryNode()->SetFrameSize(idealSize);
75     }
76 }
77 
Layout(LayoutWrapper * layoutWrapper)78 void MultiMenuLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
79 {
80     CHECK_NULL_VOID(layoutWrapper);
81     BoxLayoutAlgorithm::PerformLayout(layoutWrapper);
82 
83     auto pipeline = PipelineBase::GetCurrentContext();
84     CHECK_NULL_VOID(pipeline);
85     auto theme = pipeline->GetTheme<SelectTheme>();
86     CHECK_NULL_VOID(theme);
87     auto layoutProperty = layoutWrapper->GetLayoutProperty();
88     CHECK_NULL_VOID(layoutProperty);
89     // translate each option by the height of previous options
90     auto outPadding = static_cast<float>(theme->GetOutPadding().ConvertToPx());
91     const auto& padding = layoutProperty->CreatePaddingAndBorder();
92     OffsetF translate(padding.left.value_or(outPadding), padding.top.value_or(outPadding));
93     for (const auto& child : layoutWrapper->GetAllChildrenWithBuild()) {
94         child->GetGeometryNode()->SetMarginFrameOffset(translate);
95         child->Layout();
96         translate.AddY(child->GetGeometryNode()->GetMarginFrameSize().Height());
97     }
98 }
99 
UpdateConstraintBaseOnMenuItems(LayoutWrapper * layoutWrapper,LayoutConstraintF & constraint)100 void MultiMenuLayoutAlgorithm::UpdateConstraintBaseOnMenuItems(
101     LayoutWrapper* layoutWrapper, LayoutConstraintF& constraint)
102 {
103     // multiMenu children are menuItem or menuItemGroup, constrain width is same as the menu
104     auto maxChildrenWidth = GetChildrenMaxWidth(layoutWrapper, constraint);
105     constraint.selfIdealSize.SetWidth(maxChildrenWidth);
106 }
107 
GetChildrenMaxWidth(LayoutWrapper * layoutWrapper,const LayoutConstraintF & layoutConstraint)108 float MultiMenuLayoutAlgorithm::GetChildrenMaxWidth(
109     LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint)
110 {
111     float maxWidth = 0.0f;
112     for (const auto& child : layoutWrapper->GetAllChildrenWithBuild()) {
113         auto childConstraint = ResetLayoutConstraintMinWidth(child, layoutConstraint);
114         child->Measure(childConstraint);
115         auto childSize = child->GetGeometryNode()->GetFrameSize();
116         maxWidth = std::max(maxWidth, childSize.Width());
117     }
118     return maxWidth;
119 }
120 
ResetLayoutConstraintMinWidth(const RefPtr<LayoutWrapper> & child,const LayoutConstraintF & layoutConstraint)121 LayoutConstraintF MultiMenuLayoutAlgorithm::ResetLayoutConstraintMinWidth(
122     const RefPtr<LayoutWrapper>& child, const LayoutConstraintF& layoutConstraint)
123 {
124     auto childLayoutProps = child->GetLayoutProperty();
125     CHECK_NULL_RETURN(childLayoutProps, layoutConstraint);
126     auto childConstraint = layoutConstraint;
127     const auto& calcConstraint = childLayoutProps->GetCalcLayoutConstraint();
128     if (calcConstraint && calcConstraint->selfIdealSize.has_value() &&
129         calcConstraint->selfIdealSize.value().Width().has_value()) {
130         childConstraint.minSize.Reset();
131     }
132     return childConstraint;
133 }
134 } // namespace OHOS::Ace::NG
135