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 
30 namespace {
31 constexpr float LEVEL_ONE = 1.75f;
32 constexpr float LEVEL_TWO = 2.0f;
33 constexpr float LEVEL_THREE = 3.2f;
34 constexpr Dimension PADDING = 4.0_vp;
35 constexpr float HEIGHT_HALF_RATIO = 0.5f;
36 constexpr float HEIGHT_DOUBLE_RATIO = 2.0f;
37 } // namespace
38 
Measure(LayoutWrapper * layoutWrapper)39 void StepperLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
40 {
41     CHECK_NULL_VOID(layoutWrapper);
42     auto layoutProperty = layoutWrapper->GetLayoutProperty();
43     CHECK_NULL_VOID(layoutProperty);
44     auto geometryNode = layoutWrapper->GetGeometryNode();
45     CHECK_NULL_VOID(geometryNode);
46     auto constraint = layoutProperty->GetLayoutConstraint();
47     auto idealSize = CreateIdealSize(constraint.value(), Axis::HORIZONTAL, layoutProperty->GetMeasureType(), true);
48     if (GreaterOrEqualToInfinity(idealSize.Width()) || GreaterOrEqualToInfinity(idealSize.Height())) {
49         geometryNode->SetFrameSize(SizeF());
50         return;
51     }
52     geometryNode->SetFrameSize(idealSize);
53 
54     const auto& padding = layoutProperty->CreatePaddingAndBorder();
55     MinusPaddingToSize(padding, idealSize);
56 
57     auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
58     childLayoutConstraint.parentIdealSize = OptionalSizeF(idealSize);
59     auto pipeline = PipelineBase::GetCurrentContext();
60     CHECK_NULL_VOID(pipeline);
61     auto hostNode = layoutWrapper->GetHostNode();
62     CHECK_NULL_VOID(hostNode);
63     auto stepperPattern = hostNode->GetPattern<StepperPattern>();
64     CHECK_NULL_VOID(stepperPattern);
65     isLoadingButton_ = stepperPattern->GetIsLoadingButton();
66     if ((pipeline->GetFontScale() == LEVEL_ONE || pipeline->GetFontScale() == LEVEL_TWO ||
67         pipeline->GetFontScale() == LEVEL_THREE)) {
68         MeasureLeftButton(layoutWrapper, childLayoutConstraint);
69         MeasureRightButton(layoutWrapper, childLayoutConstraint);
70         auto rightButtonHeight = CaluateButtonHeight(layoutWrapper, true);
71         auto leftButtonHeight = CaluateButtonHeight(layoutWrapper, false);
72         MeasureSwiper(layoutWrapper, childLayoutConstraint, rightButtonHeight, leftButtonHeight);
73     } else {
74         MeasureSwiper(layoutWrapper, childLayoutConstraint, 0, 0);
75         MeasureLeftButton(layoutWrapper, childLayoutConstraint);
76         MeasureRightButton(layoutWrapper, childLayoutConstraint);
77     }
78 }
79 
MeasureSwiper(LayoutWrapper * layoutWrapper,LayoutConstraintF swiperLayoutConstraint,float rightButtonHeight,float leftButtonHeight)80 void StepperLayoutAlgorithm::MeasureSwiper(LayoutWrapper* layoutWrapper, LayoutConstraintF swiperLayoutConstraint,
81     float rightButtonHeight, float leftButtonHeight)
82 {
83     auto pipeline = PipelineBase::GetCurrentContext();
84     CHECK_NULL_VOID(pipeline);
85     auto stepperTheme = pipeline->GetTheme<StepperTheme>();
86     CHECK_NULL_VOID(stepperTheme);
87     auto hostNode = AceType::DynamicCast<StepperNode>(layoutWrapper->GetHostNode());
88     CHECK_NULL_VOID(hostNode);
89     auto index = hostNode->GetChildIndexById(hostNode->GetSwiperId());
90     auto swiperWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
91     CHECK_NULL_VOID(swiperWrapper);
92     auto swiperWidth = swiperLayoutConstraint.parentIdealSize.Width().value_or(0.0);
93     auto swiperHeight = swiperLayoutConstraint.parentIdealSize.Height().value_or(0.0) -
94                         static_cast<float>(stepperTheme->GetControlHeight().ConvertToPx());
95     auto stepperHeight = layoutWrapper->GetGeometryNode()->GetFrameSize().Height();
96     auto swiperCaluateHeight = stepperHeight -
97                                (rightButtonHeight > leftButtonHeight ? rightButtonHeight : leftButtonHeight) -
98                                (PADDING.ConvertToPx() * HEIGHT_DOUBLE_RATIO);
99     if (swiperCaluateHeight < swiperHeight) {
100         swiperHeight = swiperCaluateHeight;
101     }
102     auto swiperLayoutProperty = AceType::DynamicCast<SwiperLayoutProperty>(swiperWrapper->GetLayoutProperty());
103     CHECK_NULL_VOID(swiperLayoutProperty);
104     swiperLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(swiperWidth), CalcLength(swiperHeight)));
105     swiperLayoutConstraint.maxSize.SetHeight(swiperHeight);
106     swiperLayoutConstraint.selfIdealSize.SetHeight(swiperHeight);
107     swiperLayoutConstraint.selfIdealSize.SetWidth(swiperWidth);
108     swiperWrapper->Measure(swiperLayoutConstraint);
109 }
MeasureLeftButton(LayoutWrapper * layoutWrapper,LayoutConstraintF buttonLayoutConstraint)110 void StepperLayoutAlgorithm::MeasureLeftButton(LayoutWrapper* layoutWrapper, LayoutConstraintF buttonLayoutConstraint)
111 {
112     auto hostNode = AceType::DynamicCast<StepperNode>(layoutWrapper->GetHostNode());
113     CHECK_NULL_VOID(hostNode);
114     CHECK_NULL_VOID(hostNode->HasLeftButtonNode());
115     auto pipeline = PipelineBase::GetCurrentContext();
116     CHECK_NULL_VOID(pipeline);
117     auto stepperTheme = pipeline->GetTheme<StepperTheme>();
118     CHECK_NULL_VOID(stepperTheme);
119     auto padding =
120         static_cast<float>((stepperTheme->GetDefaultPaddingStart() + stepperTheme->GetControlPadding()).ConvertToPx());
121     auto margin = static_cast<float>(stepperTheme->GetControlMargin().ConvertToPx());
122     auto buttonWidth = (buttonLayoutConstraint.parentIdealSize.Width().value() / 2) - padding - margin;
123     auto buttonHeight = static_cast<float>(
124         stepperTheme->GetArrowHeight().ConvertToPx() + 2 * stepperTheme->GetControlMargin().ConvertToPx());
125     auto index = hostNode->GetChildIndexById(hostNode->GetLeftButtonId());
126     auto leftButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
127     buttonLayoutConstraint.minSize = { 0, buttonHeight };
128     if (pipeline->GetFontScale() == LEVEL_ONE || pipeline->GetFontScale() == LEVEL_TWO ||
129         pipeline->GetFontScale() == LEVEL_THREE) {
130         auto stepperHeight = layoutWrapper->GetGeometryNode()->GetFrameSize().Height();
131         buttonLayoutConstraint.maxSize = { buttonWidth, stepperHeight };
132         auto ButtonRow = leftButtonWrapper->GetChildByIndex(0);
133         CHECK_NULL_VOID(ButtonRow);
134         auto ButtonText = ButtonRow->GetChildByIndex(1);
135         CHECK_NULL_VOID(ButtonText);
136         auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(ButtonText->GetLayoutProperty());
137         CHECK_NULL_VOID(textLayoutProperty);
138         textLayoutProperty->UpdateMaxFontScale(LEVEL_TWO);
139         MeasureText(leftButtonWrapper, buttonLayoutConstraint, true);
140         float TextHeight = ButtonText->GetGeometryNode()->GetFrameSize().Height();
141         buttonLayoutConstraint.selfIdealSize =
142             OptionalSizeF(std::nullopt, TextHeight + PADDING.ConvertToPx() * HEIGHT_DOUBLE_RATIO);
143     } else {
144         buttonLayoutConstraint.maxSize = { buttonWidth, buttonHeight };
145         buttonLayoutConstraint.selfIdealSize = OptionalSizeF(std::nullopt, buttonHeight);
146     }
147     leftButtonWrapper->Measure(buttonLayoutConstraint);
148     MeasureText(leftButtonWrapper, buttonLayoutConstraint, true);
149 }
MeasureRightButton(LayoutWrapper * layoutWrapper,LayoutConstraintF buttonLayoutConstraint)150 void StepperLayoutAlgorithm::MeasureRightButton(LayoutWrapper* layoutWrapper, LayoutConstraintF buttonLayoutConstraint)
151 {
152     auto hostNode = AceType::DynamicCast<StepperNode>(layoutWrapper->GetHostNode());
153     CHECK_NULL_VOID(hostNode);
154     CHECK_NULL_VOID(hostNode->HasRightButtonNode());
155 
156     auto pipeline = PipelineBase::GetCurrentContext();
157     CHECK_NULL_VOID(pipeline);
158     auto stepperTheme = pipeline->GetTheme<StepperTheme>();
159     CHECK_NULL_VOID(stepperTheme);
160     auto padding =
161         static_cast<float>((stepperTheme->GetDefaultPaddingEnd() + stepperTheme->GetControlPadding()).ConvertToPx());
162     auto margin = static_cast<float>(stepperTheme->GetControlMargin().ConvertToPx());
163     auto buttonWidth = (buttonLayoutConstraint.parentIdealSize.Width().value() / 2) - padding - margin;
164     auto buttonHeight = static_cast<float>(
165         stepperTheme->GetArrowHeight().ConvertToPx() + 2 * stepperTheme->GetControlMargin().ConvertToPx());
166     auto index = hostNode->GetChildIndexById(hostNode->GetRightButtonId());
167     auto rightButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
168     buttonLayoutConstraint.minSize = { 0, buttonHeight };
169     if ((pipeline->GetFontScale() == LEVEL_ONE || pipeline->GetFontScale() == LEVEL_TWO ||
170         pipeline->GetFontScale() == LEVEL_THREE) && !isLoadingButton_) {
171         auto stepperHeight = hostNode->GetGeometryNode()->GetFrameSize().Height();
172         buttonLayoutConstraint.maxSize = { buttonWidth, stepperHeight };
173         auto ButtonRow = rightButtonWrapper->GetChildByIndex(0);
174         CHECK_NULL_VOID(ButtonRow);
175         auto ButtonText = ButtonRow->GetChildByIndex(0);
176         if (!ButtonText) {
177             auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(ButtonRow->GetLayoutProperty());
178             CHECK_NULL_VOID(textLayoutProperty);
179             textLayoutProperty->UpdateMaxFontScale(LEVEL_TWO);
180             PaddingProperty textPadding;
181             textPadding.top = CalcLength(PADDING.ConvertToPx(), DimensionUnit::PX);
182             textPadding.bottom = CalcLength(PADDING.ConvertToPx(), DimensionUnit::PX);
183             rightButtonWrapper->GetLayoutProperty()->UpdatePadding(textPadding);
184             buttonLayoutConstraint.selfIdealSize = OptionalSizeF(std::nullopt, std::nullopt);
185         } else {
186             auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(ButtonText->GetLayoutProperty());
187             CHECK_NULL_VOID(textLayoutProperty);
188             textLayoutProperty->UpdateMaxFontScale(LEVEL_TWO);
189             MeasureText(rightButtonWrapper, buttonLayoutConstraint, false);
190             float TextHeight = ButtonText->GetGeometryNode()->GetFrameSize().Height();
191             buttonLayoutConstraint.selfIdealSize =
192                 OptionalSizeF(std::nullopt, TextHeight + PADDING.ConvertToPx() * HEIGHT_DOUBLE_RATIO);
193         }
194     } else {
195         buttonLayoutConstraint.maxSize = { buttonWidth, buttonHeight };
196         buttonLayoutConstraint.selfIdealSize = OptionalSizeF(std::nullopt, buttonHeight);
197     }
198     rightButtonWrapper->Measure(buttonLayoutConstraint);
199     MeasureText(rightButtonWrapper, buttonLayoutConstraint, false);
200 }
201 
MeasureText(const RefPtr<LayoutWrapper> & layoutWrapper,const LayoutConstraintF & buttonLayoutConstraint,bool isLeft)202 void StepperLayoutAlgorithm::MeasureText(
203     const RefPtr<LayoutWrapper>& layoutWrapper, const LayoutConstraintF& buttonLayoutConstraint, bool isLeft)
204 {
205     CHECK_NULL_VOID(layoutWrapper->GetHostTag() == std::string(V2::BUTTON_ETS_TAG));
206     auto rowWrapper = layoutWrapper->GetOrCreateChildByIndex(0);
207     CHECK_NULL_VOID(rowWrapper->GetHostTag() == std::string(V2::ROW_ETS_TAG));
208     auto textWrapper = rowWrapper->GetOrCreateChildByIndex(isLeft ? 1 : 0);
209     CHECK_NULL_VOID(textWrapper->GetHostTag() == std::string(V2::TEXT_ETS_TAG));
210 
211     auto pipeline = PipelineBase::GetCurrentContext();
212     CHECK_NULL_VOID(pipeline);
213     auto stepperTheme = pipeline->GetTheme<StepperTheme>();
214     CHECK_NULL_VOID(stepperTheme);
215 
216     LayoutConstraintF textLayoutConstraint = buttonLayoutConstraint;
217     auto controlPadding = static_cast<float>(stepperTheme->GetControlPadding().ConvertToPx());
218     auto arrowWidth = static_cast<float>(stepperTheme->GetArrowWidth().ConvertToPx());
219     auto textMaxWidth =
220         buttonLayoutConstraint.maxSize.Width() - controlPadding - controlPadding - arrowWidth - controlPadding;
221     textLayoutConstraint.minSize = { 0, 0 };
222     textLayoutConstraint.maxSize.SetWidth(textMaxWidth);
223     textLayoutConstraint.selfIdealSize = OptionalSizeF(std::nullopt, std::nullopt);
224     textWrapper->Measure(textLayoutConstraint);
225 }
226 
Layout(LayoutWrapper * layoutWrapper)227 void StepperLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
228 {
229     auto pipeline = PipelineBase::GetCurrentContext();
230     CHECK_NULL_VOID(pipeline);
231     auto stepperTheme = pipeline->GetTheme<StepperTheme>();
232     CHECK_NULL_VOID(stepperTheme);
233     CHECK_NULL_VOID(layoutWrapper);
234     auto geometryNode = layoutWrapper->GetGeometryNode();
235     CHECK_NULL_VOID(geometryNode);
236     auto frameSize = geometryNode->GetFrameSize();
237     if (!frameSize.IsPositive()) {
238         return;
239     }
240     LayoutSwiper(layoutWrapper);
241     if (pipeline->GetFontScale() == LEVEL_ONE || pipeline->GetFontScale() == LEVEL_TWO ||
242         pipeline->GetFontScale() == LEVEL_THREE) {
243         auto layoutProperty = layoutWrapper->GetLayoutProperty();
244         CHECK_NULL_VOID(layoutProperty);
245         auto constraint = layoutProperty->GetLayoutConstraint();
246         auto idealSize = CreateIdealSize(constraint.value(), Axis::HORIZONTAL, layoutProperty->GetMeasureType(), true);
247         if (GreaterOrEqualToInfinity(idealSize.Width()) || GreaterOrEqualToInfinity(idealSize.Height())) {
248             LOGW("Size is infinity.");
249             geometryNode->SetFrameSize(SizeF());
250             return;
251         }
252         geometryNode->SetFrameSize(idealSize);
253 
254         const auto& padding = layoutProperty->CreatePaddingAndBorder();
255         MinusPaddingToSize(padding, idealSize);
256 
257         auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
258         childLayoutConstraint.parentIdealSize = OptionalSizeF(idealSize);
259         auto rightButtonHeight = CaluateButtonHeight(layoutWrapper, true);
260         auto leftButtonHeight = CaluateButtonHeight(layoutWrapper, false);
261         SuitAgeLayoutButton(layoutWrapper, rightButtonHeight, leftButtonHeight, true);
262         SuitAgeLayoutButton(layoutWrapper, rightButtonHeight, leftButtonHeight, false);
263     } else {
264         LayoutLeftButton(layoutWrapper);
265         LayoutRightButton(layoutWrapper);
266     }
267 }
268 
SuitAgeLayoutButton(LayoutWrapper * layoutWrapper,float rightButtonHeight,float leftButtonHeight,bool isRight)269 void StepperLayoutAlgorithm::SuitAgeLayoutButton(
270     LayoutWrapper* layoutWrapper, float rightButtonHeight, float leftButtonHeight, bool isRight)
271 {
272     auto hostNode = AceType::DynamicCast<StepperNode>(layoutWrapper->GetHostNode());
273     CHECK_NULL_VOID(hostNode);
274     if (!isRight) {
275         CHECK_NULL_VOID(hostNode->HasLeftButtonNode());
276     }
277     auto buttonIndex = isRight ? hostNode->GetChildIndexById(hostNode->GetRightButtonId())
278                                : hostNode->GetChildIndexById(hostNode->GetLeftButtonId());
279     auto ButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(buttonIndex);
280     CHECK_NULL_VOID(ButtonWrapper);
281     auto pipeline = PipelineBase::GetCurrentContext();
282     CHECK_NULL_VOID(pipeline);
283     auto stepperTheme = pipeline->GetTheme<StepperTheme>();
284     CHECK_NULL_VOID(stepperTheme);
285     auto frameSizeWidth = layoutWrapper->GetGeometryNode()->GetFrameSize().Width();
286     auto ButtonWidth = ButtonWrapper->GetGeometryNode()->GetMarginFrameSize().Width();
287     auto padding = static_cast<float>(stepperTheme->GetDefaultPaddingEnd().ConvertToPx());
288     auto margin = static_cast<float>(stepperTheme->GetControlMargin().ConvertToPx());
289     auto buttonWidthOffset = isRight ? (frameSizeWidth - ButtonWidth - padding - margin) : (padding + margin);
290     auto buttonHeightOffset = layoutWrapper->GetGeometryNode()->GetFrameSize().Height();
291     auto maxButtonHeight = rightButtonHeight > leftButtonHeight ? rightButtonHeight : leftButtonHeight;
292     auto ButtonHeight = isRight ? rightButtonHeight : leftButtonHeight;
293     buttonHeightOffset -=
294         maxButtonHeight * HEIGHT_HALF_RATIO + PADDING.ConvertToPx() + ButtonHeight * HEIGHT_HALF_RATIO;
295     OffsetF buttonOffset = { buttonWidthOffset, buttonHeightOffset };
296     auto layoutProperty = layoutWrapper->GetLayoutProperty();
297     CHECK_NULL_VOID(layoutProperty);
298     const auto& stepperPadding = layoutProperty->CreatePaddingAndBorder();
299     if (isRight) {
300         buttonOffset -= OffsetF(stepperPadding.right.value_or(0.0), stepperPadding.bottom.value_or(0.0));
301     } else {
302         buttonOffset += OffsetF(stepperPadding.left.value_or(0.0), -stepperPadding.bottom.value_or(0.0));
303     }
304     auto stepperLayoutProperty = hostNode->GetLayoutProperty<StepperLayoutProperty>();
305     CHECK_NULL_VOID(stepperLayoutProperty);
306     auto isRightToLeft = stepperLayoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
307     if (isRightToLeft) {
308         auto frameWidth = layoutWrapper->GetGeometryNode()->GetFrameSize().Width();
309         auto offsetX = frameWidth - ButtonWrapper->GetGeometryNode()->GetFrameSize().Width() - buttonOffset.GetX();
310         buttonOffset.SetX(offsetX);
311     }
312     ButtonWrapper->GetGeometryNode()->SetMarginFrameOffset(buttonOffset);
313     ButtonWrapper->Layout();
314 }
315 
CaluateButtonHeight(LayoutWrapper * layoutWrapper,bool isRight)316 float StepperLayoutAlgorithm::CaluateButtonHeight(LayoutWrapper* layoutWrapper, bool isRight)
317 {
318     auto hostNode = AceType::DynamicCast<StepperNode>(layoutWrapper->GetHostNode());
319     CHECK_NULL_RETURN(hostNode, 0.0f);
320     auto hasButtonNode = isRight ? hostNode->HasRightButtonNode() : hostNode->HasLeftButtonNode();
321     if (!hasButtonNode) {
322         return 0.0f;
323     }
324     auto buttonId = isRight ? hostNode->GetRightButtonId() : hostNode->GetLeftButtonId();
325     auto ButtonIndex = hostNode->GetChildIndexById(buttonId);
326     CHECK_NULL_RETURN(ButtonIndex, 0.0f);
327     auto ButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(ButtonIndex);
328     CHECK_NULL_RETURN(ButtonWrapper, 0.0f);
329     auto ButtonHeight = ButtonWrapper->GetGeometryNode()->GetFrameSize().Height();
330     return ButtonHeight;
331 }
332 
LayoutSwiper(LayoutWrapper * layoutWrapper)333 void StepperLayoutAlgorithm::LayoutSwiper(LayoutWrapper* layoutWrapper)
334 {
335     auto hostNode = AceType::DynamicCast<StepperNode>(layoutWrapper->GetHostNode());
336     CHECK_NULL_VOID(hostNode);
337     auto index = hostNode->GetChildIndexById(hostNode->GetSwiperId());
338     auto swiperWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
339     CHECK_NULL_VOID(swiperWrapper);
340     OffsetF swiperOffset = { 0.0f, 0.0f };
341     auto layoutProperty = layoutWrapper->GetLayoutProperty();
342     CHECK_NULL_VOID(layoutProperty);
343     const auto& padding = layoutProperty->CreatePaddingAndBorder();
344     swiperOffset += OffsetF(padding.left.value_or(0.0), padding.top.value_or(0.0));
345     swiperWrapper->GetGeometryNode()->SetMarginFrameOffset(swiperOffset);
346     swiperWrapper->Layout();
347 }
348 
LayoutLeftButton(LayoutWrapper * layoutWrapper)349 void StepperLayoutAlgorithm::LayoutLeftButton(LayoutWrapper* layoutWrapper)
350 {
351     auto hostNode = AceType::DynamicCast<StepperNode>(layoutWrapper->GetHostNode());
352     CHECK_NULL_VOID(hostNode);
353     CHECK_NULL_VOID(hostNode->HasLeftButtonNode());
354     auto index = hostNode->GetChildIndexById(hostNode->GetLeftButtonId());
355     auto leftButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
356     auto pipeline = PipelineBase::GetCurrentContext();
357     CHECK_NULL_VOID(pipeline);
358     auto stepperTheme = pipeline->GetTheme<StepperTheme>();
359     CHECK_NULL_VOID(stepperTheme);
360     auto controlHeight = static_cast<float>(stepperTheme->GetControlHeight().ConvertToPx());
361     auto buttonHeight = leftButtonWrapper->GetGeometryNode()->GetFrameSize().Height();
362     auto buttonHeightOffset = layoutWrapper->GetGeometryNode()->GetFrameSize().Height() - controlHeight;
363     buttonHeightOffset += (controlHeight - buttonHeight) / 2;
364     auto padding = static_cast<float>(stepperTheme->GetDefaultPaddingStart().ConvertToPx());
365     auto margin = static_cast<float>(stepperTheme->GetControlMargin().ConvertToPx());
366     auto buttonWidthOffset = padding + margin;
367     OffsetF buttonOffset = { buttonWidthOffset, buttonHeightOffset };
368     auto layoutProperty = layoutWrapper->GetLayoutProperty();
369     CHECK_NULL_VOID(layoutProperty);
370     const auto& stepperPadding = layoutProperty->CreatePaddingAndBorder();
371     buttonOffset += OffsetF(stepperPadding.left.value_or(0.0), -stepperPadding.bottom.value_or(0.0));
372     auto geometryNode = leftButtonWrapper->GetGeometryNode();
373     auto stepperLayoutProperty = hostNode->GetLayoutProperty<StepperLayoutProperty>();
374     CHECK_NULL_VOID(stepperLayoutProperty);
375     auto isRightToLeft = stepperLayoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
376     if (isRightToLeft) {
377         auto frameWidth = layoutWrapper->GetGeometryNode()->GetFrameSize().Width();
378         auto offsetX = frameWidth - geometryNode->GetFrameSize().Width() - buttonOffset.GetX();
379         buttonOffset.SetX(offsetX);
380     }
381     geometryNode->SetMarginFrameOffset(buttonOffset);
382     leftButtonWrapper->Layout();
383 }
384 
LayoutRightButton(LayoutWrapper * layoutWrapper)385 void StepperLayoutAlgorithm::LayoutRightButton(LayoutWrapper* layoutWrapper)
386 {
387     auto hostNode = AceType::DynamicCast<StepperNode>(layoutWrapper->GetHostNode());
388     CHECK_NULL_VOID(hostNode);
389     CHECK_NULL_VOID(hostNode->HasRightButtonNode());
390     auto index = hostNode->GetChildIndexById(hostNode->GetRightButtonId());
391     auto rightButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
392     auto pipeline = PipelineBase::GetCurrentContext();
393     CHECK_NULL_VOID(pipeline);
394     auto stepperTheme = pipeline->GetTheme<StepperTheme>();
395     CHECK_NULL_VOID(stepperTheme);
396     auto frameSizeWidth = layoutWrapper->GetGeometryNode()->GetFrameSize().Width();
397     auto rightButtonWidth = rightButtonWrapper->GetGeometryNode()->GetMarginFrameSize().Width();
398     auto padding = static_cast<float>(stepperTheme->GetDefaultPaddingEnd().ConvertToPx());
399     auto margin = static_cast<float>(stepperTheme->GetControlMargin().ConvertToPx());
400     auto buttonWidthOffset = frameSizeWidth - rightButtonWidth - padding - margin;
401     auto controlHeight = static_cast<float>(stepperTheme->GetControlHeight().ConvertToPx());
402     auto buttonHeight = rightButtonWrapper->GetGeometryNode()->GetFrameSize().Height();
403     auto buttonHeightOffset = layoutWrapper->GetGeometryNode()->GetFrameSize().Height() - controlHeight;
404     buttonHeightOffset += (controlHeight - buttonHeight) / 2;
405     OffsetF buttonOffset = { buttonWidthOffset, buttonHeightOffset };
406     auto layoutProperty = layoutWrapper->GetLayoutProperty();
407     CHECK_NULL_VOID(layoutProperty);
408     const auto& stepperPadding = layoutProperty->CreatePaddingAndBorder();
409     buttonOffset -= OffsetF(stepperPadding.right.value_or(0.0), stepperPadding.bottom.value_or(0.0));
410 
411     auto stepperLayoutProperty = hostNode->GetLayoutProperty<StepperLayoutProperty>();
412     CHECK_NULL_VOID(stepperLayoutProperty);
413     auto isRightToLeft = stepperLayoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
414     if (isRightToLeft) {
415         auto offsetX = frameSizeWidth - rightButtonWidth - buttonOffset.GetX();
416         buttonOffset.SetX(offsetX);
417     }
418     rightButtonWrapper->GetGeometryNode()->SetMarginFrameOffset(buttonOffset);
419     rightButtonWrapper->Layout();
420 }
421 
422 } // namespace OHOS::Ace::NG
423