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/bar_item_layout_algorithm.h"
17 
18 #include "base/geometry/ng/offset_t.h"
19 #include "base/geometry/ng/size_t.h"
20 #include "base/memory/ace_type.h"
21 #include "base/utils/utils.h"
22 #include "core/components_ng/base/frame_node.h"
23 #include "core/components_ng/pattern/image/image_layout_property.h"
24 #include "core/components_ng/pattern/navigation/bar_item_node.h"
25 #include "core/components_ng/pattern/navigation/navigation_declaration.h"
26 #include "core/components_ng/property/layout_constraint.h"
27 #include "core/components_ng/property/measure_property.h"
28 #include "core/components_ng/property/measure_utils.h"
29 #include "core/components_ng/pattern/text/text_layout_property.h"
30 
31 namespace OHOS::Ace::NG {
32 
MeasureIcon(LayoutWrapper * layoutWrapper,const RefPtr<BarItemNode> & hostNode,const RefPtr<LayoutProperty> & barItemLayoutProperty)33 void BarItemLayoutAlgorithm::MeasureIcon(LayoutWrapper* layoutWrapper, const RefPtr<BarItemNode>& hostNode,
34     const RefPtr<LayoutProperty>& barItemLayoutProperty)
35 {
36     auto iconNode = hostNode->GetIconNode();
37     CHECK_NULL_VOID(iconNode);
38     auto index = hostNode->GetChildIndexById(iconNode->GetId());
39     auto iconWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
40     CHECK_NULL_VOID(iconWrapper);
41     auto constraint = barItemLayoutProperty->CreateChildConstraint();
42 
43     constraint.selfIdealSize =
44         OptionalSizeF(static_cast<float>(iconSize_.ConvertToPx()), static_cast<float>(iconSize_.ConvertToPx()));
45     iconWrapper->Measure(constraint);
46 }
47 
MeasureToolbarItemText(LayoutWrapper * layoutWrapper,const RefPtr<BarItemNode> & hostNode,const RefPtr<LayoutProperty> & barItemLayoutProperty)48 void BarItemLayoutAlgorithm::MeasureToolbarItemText(LayoutWrapper* layoutWrapper, const RefPtr<BarItemNode>& hostNode,
49     const RefPtr<LayoutProperty>& barItemLayoutProperty)
50 {
51     auto theme = NavigationGetTheme();
52     CHECK_NULL_VOID(theme);
53     auto textNode = hostNode->GetTextNode();
54     CHECK_NULL_VOID(textNode);
55     auto index = hostNode->GetChildIndexById(textNode->GetId());
56     auto textWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
57     CHECK_NULL_VOID(textWrapper);
58     auto constraint = barItemLayoutProperty->CreateChildConstraint();
59 
60     auto contentConstraint = textWrapper->GetLayoutProperty()->GetContentLayoutConstraint();
61     textWrapper->Measure(contentConstraint);
62     auto textWidth = textWrapper->GetGeometryNode()->GetContentSize().Width();
63     auto textLayoutProperty = DynamicCast<TextLayoutProperty>(textWrapper->GetLayoutProperty());
64 
65     if (GreatOrEqual(textWidth, constraint.maxSize.Width())) {
66         constraint.maxSize.SetWidth(textWidth);
67     }
68     auto barItemConstraint = barItemLayoutProperty->GetLayoutConstraint().value();
69     auto textHeight = textWrapper->GetGeometryNode()->GetContentSize().Height();
70     float barItemChildrenTotalHeight = textHeight + (theme->GetToolbarIconSize() + TEXT_TOP_PADDING).ConvertToPx();
71     if (GreatOrEqual(barItemChildrenTotalHeight, constraint.maxSize.Height())) {
72         constraint.maxSize.SetHeight(barItemChildrenTotalHeight);
73     }
74 
75     if (GreatNotEqual(constraint.maxSize.Height(), barItemConstraint.maxSize.Height())) {
76         barItemConstraint.maxSize.SetHeight(constraint.maxSize.Height());
77         barItemLayoutProperty->UpdateLayoutConstraint(barItemConstraint);
78     }
79 
80     textWrapper->Measure(constraint);
81 }
82 
MeasureText(LayoutWrapper * layoutWrapper,const RefPtr<BarItemNode> & hostNode,const RefPtr<LayoutProperty> & barItemLayoutProperty)83 void BarItemLayoutAlgorithm::MeasureText(LayoutWrapper* layoutWrapper, const RefPtr<BarItemNode>& hostNode,
84     const RefPtr<LayoutProperty>& barItemLayoutProperty)
85 {
86     if (hostNode->IsBarItemUsedInToolbarConfiguration()) {
87         MeasureToolbarItemText(layoutWrapper, hostNode, barItemLayoutProperty);
88         return;
89     }
90 
91     auto textNode = hostNode->GetTextNode();
92     CHECK_NULL_VOID(textNode);
93     auto index = hostNode->GetChildIndexById(textNode->GetId());
94     auto textWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
95     CHECK_NULL_VOID(textWrapper);
96     auto constraint = barItemLayoutProperty->CreateChildConstraint();
97     textWrapper->Measure(constraint);
98 }
99 
LayoutIcon(LayoutWrapper * layoutWrapper,const RefPtr<BarItemNode> & hostNode,const RefPtr<LayoutProperty> & barItemLayoutProperty,float textHeight)100 float BarItemLayoutAlgorithm::LayoutIcon(LayoutWrapper* layoutWrapper, const RefPtr<BarItemNode>& hostNode,
101     const RefPtr<LayoutProperty>& barItemLayoutProperty, float textHeight)
102 {
103     auto iconNode = hostNode->GetIconNode();
104     CHECK_NULL_RETURN(iconNode, 0.0f);
105     auto index = hostNode->GetChildIndexById(iconNode->GetId());
106     auto iconWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
107     CHECK_NULL_RETURN(iconWrapper, 0.0f);
108     auto geometryNode = iconWrapper->GetGeometryNode();
109 
110     const auto& constraint = barItemLayoutProperty->GetLayoutConstraint();
111     CHECK_NULL_RETURN(constraint, 0.0f);
112     auto offsetX = (constraint->maxSize.Width() - iconSize_.ConvertToPx()) / 2;
113 
114     if (!hostNode->IsBarItemUsedInToolbarConfiguration()) {
115         offsetX = 0.0f;
116     }
117 
118     auto offset = OffsetF(offsetX, 0.0f);
119     geometryNode->SetMarginFrameOffset(offset);
120     iconWrapper->Layout();
121     return 0.0f;
122 }
123 
LayoutText(LayoutWrapper * layoutWrapper,const RefPtr<BarItemNode> & hostNode,const RefPtr<LayoutProperty> & barItemLayoutProperty,float iconOffsetY)124 void BarItemLayoutAlgorithm::LayoutText(LayoutWrapper* layoutWrapper, const RefPtr<BarItemNode>& hostNode,
125     const RefPtr<LayoutProperty>& barItemLayoutProperty, float iconOffsetY)
126 {
127     auto textNode = hostNode->GetTextNode();
128     CHECK_NULL_VOID(textNode);
129     auto index = hostNode->GetChildIndexById(textNode->GetId());
130     auto textWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
131     CHECK_NULL_VOID(textWrapper);
132     auto geometryNode = textWrapper->GetGeometryNode();
133     auto textOffsetY = iconSize_ + TEXT_TOP_PADDING;
134 
135     const auto& constraint = barItemLayoutProperty->GetLayoutConstraint();
136     CHECK_NULL_VOID(constraint);
137     auto textWidth = geometryNode->GetFrameSize().Width();
138     auto offsetX = (constraint->maxSize.Width() - textWidth) / 2;
139 
140     if (!hostNode->IsBarItemUsedInToolbarConfiguration()) {
141         offsetX = 0.0f;
142     }
143     auto offset = OffsetF(offsetX, iconOffsetY + static_cast<float>(textOffsetY.ConvertToPx()));
144     geometryNode->SetMarginFrameOffset(offset);
145     textWrapper->Layout();
146 }
147 
Measure(LayoutWrapper * layoutWrapper)148 void BarItemLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
149 {
150     auto hostNode = AceType::DynamicCast<BarItemNode>(layoutWrapper->GetHostNode());
151     CHECK_NULL_VOID(hostNode);
152     auto barItemLayoutProperty = AceType::DynamicCast<LayoutProperty>(layoutWrapper->GetLayoutProperty());
153     CHECK_NULL_VOID(barItemLayoutProperty);
154     bool isUsedInToolbarConfiguratuon = hostNode->IsBarItemUsedInToolbarConfiguration();
155 
156     // get parameters from theme
157     auto theme = NavigationGetTheme();
158     CHECK_NULL_VOID(theme);
159     iconSize_ = isUsedInToolbarConfiguratuon ? theme->GetToolbarIconSize() : theme->GetMenuIconSize();
160     auto size = SizeF(static_cast<float>(iconSize_.ConvertToPx()), static_cast<float>(iconSize_.ConvertToPx()));
161     MeasureIcon(layoutWrapper, hostNode, barItemLayoutProperty);
162     MeasureText(layoutWrapper, hostNode, barItemLayoutProperty);
163 
164     if (isUsedInToolbarConfiguratuon) {
165         const auto& constraint = barItemLayoutProperty->GetLayoutConstraint();
166         CHECK_NULL_VOID(constraint);
167         size = constraint->maxSize;
168     }
169     layoutWrapper->GetGeometryNode()->SetFrameSize(size);
170 }
171 
Layout(LayoutWrapper * layoutWrapper)172 void BarItemLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
173 {
174     auto hostNode = AceType::DynamicCast<BarItemNode>(layoutWrapper->GetHostNode());
175     CHECK_NULL_VOID(hostNode);
176     auto barItemLayoutProperty = AceType::DynamicCast<LayoutProperty>(layoutWrapper->GetLayoutProperty());
177     CHECK_NULL_VOID(barItemLayoutProperty);
178 
179     float textHeight = 0.0f;
180     auto textNode = hostNode->GetTextNode();
181     if (textNode) {
182         auto index = hostNode->GetChildIndexById(textNode->GetId());
183         auto textWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
184         CHECK_NULL_VOID(textWrapper);
185         auto geometryNode = textWrapper->GetGeometryNode();
186         textHeight = geometryNode->GetFrameSize().Height();
187     }
188 
189     float iconOffsetY = LayoutIcon(layoutWrapper, hostNode, barItemLayoutProperty, textHeight);
190     LayoutText(layoutWrapper, hostNode, barItemLayoutProperty, iconOffsetY);
191 }
192 
193 } // namespace OHOS::Ace::NG
194