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/stepper/stepper_layout_algorithm.h"
17
18 #include <optional>
19
20 #include "base/utils/utils.h"
21 #include "core/components/stepper/stepper_theme.h"
22 #include "core/components_ng/layout/layout_wrapper.h"
23 #include "core/components_ng/pattern/stepper/stepper_node.h"
24 #include "core/components_ng/pattern/swiper/swiper_layout_property.h"
25 #include "core/components_v2/inspector/inspector_constants.h"
26 #include "core/pipeline/pipeline_base.h"
27
28 namespace OHOS::Ace::NG {
29
Measure(LayoutWrapper * layoutWrapper)30 void StepperLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
31 {
32 CHECK_NULL_VOID(layoutWrapper);
33 auto layoutProperty = layoutWrapper->GetLayoutProperty();
34 CHECK_NULL_VOID(layoutProperty);
35 auto geometryNode = layoutWrapper->GetGeometryNode();
36 CHECK_NULL_VOID(geometryNode);
37 auto constraint = layoutProperty->GetLayoutConstraint();
38 auto idealSize =
39 CreateIdealSize(constraint.value(), Axis::HORIZONTAL, layoutProperty->GetMeasureType(), true);
40 if (GreaterOrEqualToInfinity(idealSize.Width()) || GreaterOrEqualToInfinity(idealSize.Height())) {
41 LOGW("Size is infinity.");
42 geometryNode->SetFrameSize(SizeF());
43 return;
44 }
45 geometryNode->SetFrameSize(idealSize);
46
47 const auto& padding = layoutProperty->CreatePaddingAndBorder();
48 MinusPaddingToSize(padding, idealSize);
49
50 auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
51 childLayoutConstraint.parentIdealSize = OptionalSizeF(idealSize);
52
53 MeasureSwiper(layoutWrapper, childLayoutConstraint);
54 MeasureLeftButton(layoutWrapper, childLayoutConstraint);
55 MeasureRightButton(layoutWrapper, childLayoutConstraint);
56 }
57
MeasureSwiper(LayoutWrapper * layoutWrapper,LayoutConstraintF swiperLayoutConstraint)58 void StepperLayoutAlgorithm::MeasureSwiper(LayoutWrapper* layoutWrapper, LayoutConstraintF swiperLayoutConstraint)
59 {
60 auto pipeline = PipelineBase::GetCurrentContext();
61 CHECK_NULL_VOID(pipeline);
62 auto stepperTheme = pipeline->GetTheme<StepperTheme>();
63 CHECK_NULL_VOID(stepperTheme);
64 auto hostNode = AceType::DynamicCast<StepperNode>(layoutWrapper->GetHostNode());
65 CHECK_NULL_VOID(hostNode);
66 auto index = hostNode->GetChildIndexById(hostNode->GetSwiperId());
67 auto swiperWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
68 CHECK_NULL_VOID(swiperWrapper);
69 auto swiperWidth = swiperLayoutConstraint.parentIdealSize.Width().value_or(0.0);
70 auto swiperHeight = swiperLayoutConstraint.parentIdealSize.Height().value_or(0.0) -
71 static_cast<float>(stepperTheme->GetControlHeight().ConvertToPx());
72 auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(swiperWrapper->GetLayoutProperty());
73 CHECK_NULL_VOID(swiperLayoutProperty);
74 swiperLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(swiperWidth), CalcLength(swiperHeight)));
75 swiperLayoutConstraint.maxSize.SetHeight(swiperHeight);
76 swiperLayoutConstraint.selfIdealSize.SetHeight(swiperHeight);
77 swiperLayoutConstraint.selfIdealSize.SetWidth(swiperWidth);
78 swiperWrapper->Measure(swiperLayoutConstraint);
79 }
MeasureLeftButton(LayoutWrapper * layoutWrapper,LayoutConstraintF buttonLayoutConstraint)80 void StepperLayoutAlgorithm::MeasureLeftButton(LayoutWrapper* layoutWrapper, LayoutConstraintF buttonLayoutConstraint)
81 {
82 auto hostNode = AceType::DynamicCast<StepperNode>(layoutWrapper->GetHostNode());
83 CHECK_NULL_VOID(hostNode);
84 CHECK_NULL_VOID_NOLOG(hostNode->HasLeftButtonNode());
85
86 auto pipeline = PipelineBase::GetCurrentContext();
87 CHECK_NULL_VOID(pipeline);
88 auto stepperTheme = pipeline->GetTheme<StepperTheme>();
89 CHECK_NULL_VOID(stepperTheme);
90 auto padding =
91 static_cast<float>((stepperTheme->GetDefaultPaddingStart() + stepperTheme->GetControlPadding()).ConvertToPx());
92 auto margin = static_cast<float>(stepperTheme->GetControlMargin().ConvertToPx());
93 auto buttonWidth = (buttonLayoutConstraint.parentIdealSize.Width().value() / 2) - padding - margin;
94 auto buttonHeight = static_cast<float>(
95 stepperTheme->GetArrowHeight().ConvertToPx() + 2 * stepperTheme->GetControlMargin().ConvertToPx());
96 buttonLayoutConstraint.minSize = { 0, buttonHeight };
97 buttonLayoutConstraint.maxSize = { buttonWidth, buttonHeight };
98 buttonLayoutConstraint.selfIdealSize = OptionalSizeF(std::nullopt, buttonHeight);
99
100 auto index = hostNode->GetChildIndexById(hostNode->GetLeftButtonId());
101 auto leftButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
102 leftButtonWrapper->Measure(buttonLayoutConstraint);
103 MeasureText(leftButtonWrapper, buttonLayoutConstraint, true);
104 }
MeasureRightButton(LayoutWrapper * layoutWrapper,LayoutConstraintF buttonLayoutConstraint)105 void StepperLayoutAlgorithm::MeasureRightButton(LayoutWrapper* layoutWrapper, LayoutConstraintF buttonLayoutConstraint)
106 {
107 auto hostNode = AceType::DynamicCast<StepperNode>(layoutWrapper->GetHostNode());
108 CHECK_NULL_VOID(hostNode);
109 CHECK_NULL_VOID_NOLOG(hostNode->HasRightButtonNode());
110
111 auto pipeline = PipelineBase::GetCurrentContext();
112 CHECK_NULL_VOID(pipeline);
113 auto stepperTheme = pipeline->GetTheme<StepperTheme>();
114 CHECK_NULL_VOID(stepperTheme);
115 auto padding =
116 static_cast<float>((stepperTheme->GetDefaultPaddingEnd() + stepperTheme->GetControlPadding()).ConvertToPx());
117 auto margin = static_cast<float>(stepperTheme->GetControlMargin().ConvertToPx());
118 auto buttonWidth = (buttonLayoutConstraint.parentIdealSize.Width().value() / 2) - padding - margin;
119 auto buttonHeight = static_cast<float>(
120 stepperTheme->GetArrowHeight().ConvertToPx() + 2 * stepperTheme->GetControlMargin().ConvertToPx());
121 buttonLayoutConstraint.minSize = { 0, buttonHeight };
122 buttonLayoutConstraint.maxSize = { buttonWidth, buttonHeight };
123 buttonLayoutConstraint.selfIdealSize = OptionalSizeF(std::nullopt, buttonHeight);
124
125 auto index = hostNode->GetChildIndexById(hostNode->GetRightButtonId());
126 auto rightButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
127 rightButtonWrapper->Measure(buttonLayoutConstraint);
128 MeasureText(rightButtonWrapper, buttonLayoutConstraint, false);
129 }
130
MeasureText(const RefPtr<LayoutWrapper> & layoutWrapper,const LayoutConstraintF & buttonLayoutConstraint,bool isLeft)131 void StepperLayoutAlgorithm::MeasureText(
132 const RefPtr<LayoutWrapper>& layoutWrapper, const LayoutConstraintF& buttonLayoutConstraint, bool isLeft)
133 {
134 CHECK_NULL_VOID_NOLOG(layoutWrapper->GetHostTag() == std::string(V2::BUTTON_ETS_TAG));
135 auto rowWrapper = layoutWrapper->GetOrCreateChildByIndex(0);
136 CHECK_NULL_VOID_NOLOG(rowWrapper->GetHostTag() == std::string(V2::ROW_ETS_TAG));
137 auto textWrapper = rowWrapper->GetOrCreateChildByIndex(isLeft ? 1 : 0);
138 CHECK_NULL_VOID(textWrapper->GetHostTag() == std::string(V2::TEXT_ETS_TAG));
139
140 auto pipeline = PipelineBase::GetCurrentContext();
141 CHECK_NULL_VOID(pipeline);
142 auto stepperTheme = pipeline->GetTheme<StepperTheme>();
143 CHECK_NULL_VOID(stepperTheme);
144
145 LayoutConstraintF textLayoutConstraint = buttonLayoutConstraint;
146 auto controlPadding = static_cast<float>(stepperTheme->GetControlPadding().ConvertToPx());
147 auto arrowWidth = static_cast<float>(stepperTheme->GetArrowWidth().ConvertToPx());
148 auto textMaxWidth =
149 buttonLayoutConstraint.maxSize.Width() - controlPadding - controlPadding - arrowWidth - controlPadding;
150 textLayoutConstraint.minSize = { 0, 0 };
151 textLayoutConstraint.maxSize.SetWidth(textMaxWidth);
152 textLayoutConstraint.selfIdealSize = OptionalSizeF(std::nullopt, std::nullopt);
153 textWrapper->Measure(textLayoutConstraint);
154 }
155
Layout(LayoutWrapper * layoutWrapper)156 void StepperLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
157 {
158 auto pipeline = PipelineBase::GetCurrentContext();
159 CHECK_NULL_VOID(pipeline);
160 auto stepperTheme = pipeline->GetTheme<StepperTheme>();
161 CHECK_NULL_VOID(stepperTheme);
162 CHECK_NULL_VOID(layoutWrapper);
163 auto geometryNode = layoutWrapper->GetGeometryNode();
164 CHECK_NULL_VOID(geometryNode);
165 auto frameSize = geometryNode->GetFrameSize();
166 if (!frameSize.IsPositive()) {
167 LOGW("Frame size is not positive.");
168 return;
169 }
170 LayoutSwiper(layoutWrapper);
171 LayoutLeftButton(layoutWrapper);
172 LayoutRightButton(layoutWrapper);
173 }
174
LayoutSwiper(LayoutWrapper * layoutWrapper)175 void StepperLayoutAlgorithm::LayoutSwiper(LayoutWrapper* layoutWrapper)
176 {
177 auto hostNode = AceType::DynamicCast<StepperNode>(layoutWrapper->GetHostNode());
178 CHECK_NULL_VOID(hostNode);
179 auto index = hostNode->GetChildIndexById(hostNode->GetSwiperId());
180 auto swiperWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
181 CHECK_NULL_VOID(swiperWrapper);
182 OffsetF swiperOffset = { 0.0f, 0.0f };
183 auto layoutProperty = layoutWrapper->GetLayoutProperty();
184 CHECK_NULL_VOID(layoutProperty);
185 const auto& padding = layoutProperty->CreatePaddingAndBorder();
186 swiperOffset += OffsetF(padding.left.value_or(0.0), padding.top.value_or(0.0));
187 swiperWrapper->GetGeometryNode()->SetMarginFrameOffset(swiperOffset);
188 swiperWrapper->Layout();
189 }
190
LayoutLeftButton(LayoutWrapper * layoutWrapper)191 void StepperLayoutAlgorithm::LayoutLeftButton(LayoutWrapper* layoutWrapper)
192 {
193 auto hostNode = AceType::DynamicCast<StepperNode>(layoutWrapper->GetHostNode());
194 CHECK_NULL_VOID(hostNode);
195 CHECK_NULL_VOID_NOLOG(hostNode->HasLeftButtonNode());
196 auto index = hostNode->GetChildIndexById(hostNode->GetLeftButtonId());
197 auto leftButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
198 auto pipeline = PipelineBase::GetCurrentContext();
199 CHECK_NULL_VOID(pipeline);
200 auto stepperTheme = pipeline->GetTheme<StepperTheme>();
201 CHECK_NULL_VOID(stepperTheme);
202 auto controlHeight = static_cast<float>(stepperTheme->GetControlHeight().ConvertToPx());
203 auto buttonHeight = leftButtonWrapper->GetGeometryNode()->GetFrameSize().Height();
204 auto buttonHeightOffset = layoutWrapper->GetGeometryNode()->GetFrameSize().Height() - controlHeight;
205 buttonHeightOffset += (controlHeight - buttonHeight) / 2;
206 auto padding = static_cast<float>(stepperTheme->GetDefaultPaddingStart().ConvertToPx());
207 auto margin = static_cast<float>(stepperTheme->GetControlMargin().ConvertToPx());
208 auto buttonWidthOffset = padding + margin;
209 OffsetF buttonOffset = { buttonWidthOffset, buttonHeightOffset };
210 auto layoutProperty = layoutWrapper->GetLayoutProperty();
211 CHECK_NULL_VOID(layoutProperty);
212 const auto& stepperPadding = layoutProperty->CreatePaddingAndBorder();
213 buttonOffset += OffsetF(stepperPadding.left.value_or(0.0), -stepperPadding.bottom.value_or(0.0));
214 auto geometryNode = leftButtonWrapper->GetGeometryNode();
215 geometryNode->SetMarginFrameOffset(buttonOffset);
216 leftButtonWrapper->Layout();
217 }
218
LayoutRightButton(LayoutWrapper * layoutWrapper)219 void StepperLayoutAlgorithm::LayoutRightButton(LayoutWrapper* layoutWrapper)
220 {
221 auto hostNode = AceType::DynamicCast<StepperNode>(layoutWrapper->GetHostNode());
222 CHECK_NULL_VOID(hostNode);
223 CHECK_NULL_VOID_NOLOG(hostNode->HasRightButtonNode());
224 auto index = hostNode->GetChildIndexById(hostNode->GetRightButtonId());
225 auto rightButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
226 auto pipeline = PipelineBase::GetCurrentContext();
227 CHECK_NULL_VOID(pipeline);
228 auto stepperTheme = pipeline->GetTheme<StepperTheme>();
229 CHECK_NULL_VOID(stepperTheme);
230 auto frameSizeWidth = layoutWrapper->GetGeometryNode()->GetFrameSize().Width();
231 auto rightButtonWidth = rightButtonWrapper->GetGeometryNode()->GetMarginFrameSize().Width();
232 auto padding = static_cast<float>(stepperTheme->GetDefaultPaddingEnd().ConvertToPx());
233 auto margin = static_cast<float>(stepperTheme->GetControlMargin().ConvertToPx());
234 auto buttonWidthOffset = frameSizeWidth - rightButtonWidth - padding - margin;
235 auto controlHeight = static_cast<float>(stepperTheme->GetControlHeight().ConvertToPx());
236 auto buttonHeight = rightButtonWrapper->GetGeometryNode()->GetFrameSize().Height();
237 auto buttonHeightOffset = layoutWrapper->GetGeometryNode()->GetFrameSize().Height() - controlHeight;
238 buttonHeightOffset += (controlHeight - buttonHeight) / 2;
239 OffsetF buttonOffset = { buttonWidthOffset, buttonHeightOffset };
240 auto layoutProperty = layoutWrapper->GetLayoutProperty();
241 CHECK_NULL_VOID(layoutProperty);
242 const auto& stepperPadding = layoutProperty->CreatePaddingAndBorder();
243 buttonOffset -= OffsetF(stepperPadding.right.value_or(0.0), stepperPadding.bottom.value_or(0.0));
244 rightButtonWrapper->GetGeometryNode()->SetMarginFrameOffset(buttonOffset);
245 rightButtonWrapper->Layout();
246 }
247
248 } // namespace OHOS::Ace::NG
249