1 /*
2  * Copyright (c) 2022-2024 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_pattern.h"
17 
18 #include <algorithm>
19 
20 #include "base/i18n/localization.h"
21 #include "core/components_ng/pattern/button/button_event_hub.h"
22 #include "core/components_ng/pattern/button/button_pattern.h"
23 #include "core/components_ng/pattern/image/image_pattern.h"
24 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
25 #include "core/components_ng/pattern/loading_progress/loading_progress_pattern.h"
26 #include "core/components_ng/pattern/stepper/stepper_item_layout_property.h"
27 #include "core/components_ng/pattern/stepper/stepper_node.h"
28 #include "core/components_ng/pattern/swiper/swiper_pattern.h"
29 #include "core/components_ng/pattern/text/text_pattern.h"
30 
31 namespace OHOS::Ace::NG {
32 
OnModifyDone()33 void StepperPattern::OnModifyDone()
34 {
35     Pattern::OnModifyDone();
36     auto hostNode = DynamicCast<StepperNode>(GetHost());
37     CHECK_NULL_VOID(hostNode);
38     auto swiperNode =
39         DynamicCast<FrameNode>(hostNode->GetChildAtIndex(hostNode->GetChildIndexById(hostNode->GetSwiperId())));
40     CHECK_NULL_VOID(swiperNode);
41     index_ = swiperNode->GetLayoutProperty<SwiperLayoutProperty>()->GetIndex().value_or(0);
42 
43     auto swiperEventHub = swiperNode->GetEventHub<SwiperEventHub>();
44     CHECK_NULL_VOID(swiperEventHub);
45     maxIndex_ = TotalCount();
46     if (index_ > maxIndex_) {
47         index_ = 0;
48         hostNode->GetLayoutProperty<StepperLayoutProperty>()->UpdateIndex(index_);
49         swiperNode->GetLayoutProperty<SwiperLayoutProperty>()->UpdateIndex(index_);
50         swiperNode->MarkModifyDone();
51         swiperNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
52     }
53     InitSwiperChangeEvent(swiperEventHub);
54     UpdateOrCreateLeftButtonNode(index_);
55     UpdateOrCreateRightButtonNode(index_);
56     InitButtonClickEvent();
57     SetAccessibilityAction();
58 }
59 
OnAttachToFrameNode()60 void StepperPattern::OnAttachToFrameNode()
61 {
62     auto host = GetHost();
63     CHECK_NULL_VOID(host);
64     host->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT);
65     host->GetRenderContext()->UpdateClipEdge(true);
66 }
67 
InitSwiperChangeEvent(const RefPtr<SwiperEventHub> & swiperEventHub)68 void StepperPattern::InitSwiperChangeEvent(const RefPtr<SwiperEventHub>& swiperEventHub)
69 {
70     ChangeEvent changeEvent = [weak = WeakClaim(this)](int32_t index) {
71         auto stepperPattern = weak.Upgrade();
72         CHECK_NULL_VOID(stepperPattern->TotalCount() > -1);
73         stepperPattern->UpdateIndexWithoutMeasure(index);
74         stepperPattern->UpdateOrCreateLeftButtonNode(index);
75         stepperPattern->UpdateOrCreateRightButtonNode(index);
76         stepperPattern->InitButtonClickEvent();
77     };
78     if (swiperChangeEvent_) {
79         (*swiperChangeEvent_).swap(changeEvent);
80     } else {
81         swiperChangeEvent_ = std::make_shared<ChangeEvent>(std::move(changeEvent));
82         swiperEventHub->AddOnChangeEvent(swiperChangeEvent_);
83     }
84 }
85 
UpdateIndexWithoutMeasure(int32_t index)86 void StepperPattern::UpdateIndexWithoutMeasure(int32_t index)
87 {
88     auto hostNode = DynamicCast<StepperNode>(GetHost());
89     CHECK_NULL_VOID(hostNode);
90     auto stepperLayoutProperty = hostNode->GetLayoutProperty<StepperLayoutProperty>();
91     CHECK_NULL_VOID(stepperLayoutProperty);
92     stepperLayoutProperty->UpdateIndexWithoutMeasure(index);
93 
94     auto swiperNode =
95         DynamicCast<FrameNode>(hostNode->GetChildAtIndex(hostNode->GetChildIndexById(hostNode->GetSwiperId())));
96     CHECK_NULL_VOID(swiperNode);
97     auto swiperLayoutProperty = swiperNode->GetLayoutProperty<SwiperLayoutProperty>();
98     CHECK_NULL_VOID(swiperLayoutProperty);
99     swiperLayoutProperty->UpdateIndexWithoutMeasure(index);
100 }
101 
UpdateOrCreateLeftButtonNode(int32_t index)102 void StepperPattern::UpdateOrCreateLeftButtonNode(int32_t index)
103 {
104     auto hostNode = DynamicCast<StepperNode>(GetHost());
105     CHECK_NULL_VOID(hostNode);
106     auto stepperLayoutProperty = hostNode->GetLayoutProperty<StepperLayoutProperty>();
107     CHECK_NULL_VOID(stepperLayoutProperty);
108     isRightToLeft_ = stepperLayoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
109     if (index <= 0) {
110         hostNode->RemoveLeftButtonNode();
111     } else if (!hostNode->HasLeftButtonNode()) {
112         CreateLeftButtonNode();
113         UpdateLeftButtonNode(index);
114     } else {
115         UpdateLeftButtonNode(index);
116     }
117     index_ = index;
118     hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
119 }
120 
CreateLeftButtonNode()121 void StepperPattern::CreateLeftButtonNode()
122 {
123     auto stepperTheme = GetTheme();
124     CHECK_NULL_VOID(stepperTheme);
125     auto hostNode = DynamicCast<StepperNode>(GetHost());
126     CHECK_NULL_VOID(hostNode);
127     // Create buttonNode
128     auto buttonId = hostNode->GetLeftButtonId();
129     auto buttonPattern = AceType::MakeRefPtr<NG::ButtonPattern>();
130     CHECK_NULL_VOID(buttonPattern);
131     buttonPattern->setComponentButtonType(ComponentButtonType::STEPPER);
132     buttonPattern->SetFocusBorderColor(stepperTheme->GetFocusColor());
133     auto buttonNode = FrameNode::CreateFrameNode(V2::BUTTON_ETS_TAG, buttonId, buttonPattern);
134     auto focusHub = buttonNode->GetOrCreateFocusHub();
135     CHECK_NULL_VOID(focusHub);
136     focusHub->SetFocusDependence(FocusDependence::SELF);
137     buttonNode->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
138     auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
139     CHECK_NULL_VOID(buttonLayoutProperty);
140     buttonLayoutProperty->UpdateType(ButtonType::NORMAL);
141     buttonLayoutProperty->UpdateMeasureType(MeasureType::MATCH_CONTENT);
142     buttonLayoutProperty->UpdateBorderRadius(BorderRadiusProperty(stepperTheme->GetRadius()));
143     buttonNode->MountToParent(hostNode);
144     buttonNode->MarkModifyDone();
145 
146     // Create rowNode
147     auto rowNode = FrameNode::GetOrCreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
148         []() { return AceType::MakeRefPtr<LinearLayoutPattern>(false); });
149     auto rowLayoutProperty = rowNode->GetLayoutProperty<LinearLayoutProperty>();
150     CHECK_NULL_VOID(rowLayoutProperty);
151     rowLayoutProperty->UpdateSpace(stepperTheme->GetControlPadding());
152     rowLayoutProperty->UpdateMargin(
153         { CalcLength(stepperTheme->GetControlPadding()), CalcLength(stepperTheme->GetControlPadding()) });
154     rowLayoutProperty->UpdateMeasureType(MeasureType::MATCH_CONTENT);
155     rowNode->MountToParent(buttonNode);
156     rowNode->MarkModifyDone();
157 
158     // Create imageNode
159     auto imageNode = FrameNode::GetOrCreateFrameNode(V2::IMAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
160         []() { return AceType::MakeRefPtr<ImagePattern>(); });
161     auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
162     CHECK_NULL_VOID(imageLayoutProperty);
163     imageLayoutProperty->UpdateUserDefinedIdealSize(
164         CalcSize(CalcLength(stepperTheme->GetArrowWidth()), CalcLength(stepperTheme->GetArrowHeight())));
165     imageLayoutProperty->UpdateImageFit(ImageFit::FILL);
166     ImageSourceInfo imageSourceInfo;
167     auto stepperLayoutProperty = hostNode->GetLayoutProperty<StepperLayoutProperty>();
168     CHECK_NULL_VOID(stepperLayoutProperty);
169     if (isRightToLeft_) {
170         rowNode->GetLayoutProperty()->UpdateLayoutDirection(TextDirection::RTL);
171         imageSourceInfo.SetResourceId(InternalResource::ResourceId::STEPPER_NEXT_ARROW);
172     } else {
173         rowNode->GetLayoutProperty()->UpdateLayoutDirection(TextDirection::LTR);
174         imageSourceInfo.SetResourceId(InternalResource::ResourceId::STEPPER_BACK_ARROW);
175     }
176     leftImage_ = imageNode;
177     imageSourceInfo.SetFillColor(stepperTheme->GetArrowColor());
178     imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
179     SizeF sourceSize(static_cast<float>(stepperTheme->GetArrowWidth().ConvertToPx()),
180         static_cast<float>(stepperTheme->GetArrowHeight().ConvertToPx()));
181     imageLayoutProperty->UpdateSourceSize(sourceSize);
182     imageNode->MountToParent(rowNode);
183     imageNode->MarkModifyDone();
184 
185     // Create textNode
186     auto textNode = FrameNode::GetOrCreateFrameNode(V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
187         []() { return AceType::MakeRefPtr<TextPattern>(); });
188     textNode->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
189     auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
190     CHECK_NULL_VOID(textLayoutProperty);
191     textLayoutProperty->UpdateMeasureType(MeasureType::MATCH_CONTENT);
192     textLayoutProperty->UpdateTextColor(stepperTheme->GetTextStyle().GetTextColor());
193     textLayoutProperty->UpdateTextOverflow(TextOverflow::ELLIPSIS);
194     textLayoutProperty->UpdateFontSize(stepperTheme->GetTextStyle().GetFontSize());
195     textLayoutProperty->UpdateAdaptMinFontSize(stepperTheme->GetMinFontSize());
196     textLayoutProperty->UpdateAdaptMaxFontSize(stepperTheme->GetTextStyle().GetFontSize());
197     textLayoutProperty->UpdateFontWeight(stepperTheme->GetTextStyle().GetFontWeight());
198     textLayoutProperty->UpdateMaxLines(stepperTheme->GetTextMaxLines());
199     textNode->GetLayoutProperty()->UpdateAlignment(Alignment::CENTER);
200     textNode->GetFocusHub()->SetFocusable(true);
201     textNode->MountToParent(rowNode);
202     textNode->MarkModifyDone();
203 }
204 
UpdateLeftButtonNode(int32_t index)205 void StepperPattern::UpdateLeftButtonNode(int32_t index)
206 {
207     auto hostNode = DynamicCast<StepperNode>(GetHost());
208     CHECK_NULL_VOID(hostNode);
209     auto buttonNode = hostNode->GetChildAtIndex(hostNode->GetChildIndexById(hostNode->GetLeftButtonId()));
210     auto rowNode = buttonNode->GetChildAtIndex(0);
211     auto textNode = DynamicCast<FrameNode>(rowNode->GetChildAtIndex(1));
212 
213     auto swiperNode = hostNode->GetChildAtIndex(hostNode->GetChildIndexById(hostNode->GetSwiperId()));
214     auto stepperItemNode = DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(static_cast<int32_t>(index)));
215     CHECK_NULL_VOID(stepperItemNode);
216     auto stepperItemLayoutProperty = stepperItemNode->GetLayoutProperty<StepperItemLayoutProperty>();
217     auto buttonBackText = Localization::GetInstance()->GetEntryLetters("stepper.back");
218     auto leftLabel = stepperItemLayoutProperty->GetLeftLabel().value_or(buttonBackText);
219     textNode->GetLayoutProperty<TextLayoutProperty>()->UpdateContent(leftLabel);
220 
221     textNode->MarkModifyDone();
222     textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
223 }
224 
UpdateOrCreateRightButtonNode(int32_t index)225 void StepperPattern::UpdateOrCreateRightButtonNode(int32_t index)
226 {
227     auto hostNode = DynamicCast<StepperNode>(GetHost());
228     CHECK_NULL_VOID(hostNode);
229     CreateRightButtonNode(index);
230     index_ = index;
231     hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
232 }
CreateRightButtonNode(int32_t index)233 void StepperPattern::CreateRightButtonNode(int32_t index)
234 {
235     auto hostNode = DynamicCast<StepperNode>(GetHost());
236     CHECK_NULL_VOID(hostNode);
237     auto swiperNode = hostNode->GetChildAtIndex(hostNode->GetChildIndexById(hostNode->GetSwiperId()));
238     auto stepperItemNode = DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(static_cast<int32_t>(index)));
239     CHECK_NULL_VOID(stepperItemNode);
240     auto labelStatus =
241         stepperItemNode->GetLayoutProperty<StepperItemLayoutProperty>()->GetLabelStatus().value_or("normal");
242     if (labelStatus == "normal") {
243         if (index == maxIndex_) {
244             CreateArrowlessRightButtonNode(index, false, Localization::GetInstance()->GetEntryLetters("stepper.start"));
245         } else {
246             CreateArrowRightButtonNode(index, false);
247         }
248     } else if (labelStatus == "disabled") {
249         if (index == maxIndex_) {
250             CreateArrowlessRightButtonNode(index, true, Localization::GetInstance()->GetEntryLetters("stepper.start"));
251         } else {
252             CreateArrowRightButtonNode(index, true);
253         }
254     } else if (labelStatus == "waiting") {
255         CreateWaitingRightButtonNode();
256     } else if (labelStatus == "skip") {
257         CreateArrowlessRightButtonNode(index, false, Localization::GetInstance()->GetEntryLetters("stepper.skip"));
258     }
259 }
260 
CreateArrowRightButtonNode(int32_t index,bool isDisabled)261 void StepperPattern::CreateArrowRightButtonNode(int32_t index, bool isDisabled)
262 {
263     auto stepperTheme = GetTheme();
264     CHECK_NULL_VOID(stepperTheme);
265     auto hostNode = DynamicCast<StepperNode>(GetHost());
266     CHECK_NULL_VOID(hostNode);
267     // get rightLabel
268     auto swiperNode = hostNode->GetChildAtIndex(hostNode->GetChildIndexById(hostNode->GetSwiperId()));
269     auto stepperItemNode = DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(static_cast<int32_t>(index)));
270     CHECK_NULL_VOID(stepperItemNode);
271     auto buttonNextText = Localization::GetInstance()->GetEntryLetters("stepper.next");
272     auto rightLabel =
273         stepperItemNode->GetLayoutProperty<StepperItemLayoutProperty>()->GetRightLabel().value_or(buttonNextText);
274     // Create or get buttonNode
275     if (isLoadingButton_) {
276         hostNode->RemoveRightButtonNode();
277         isLoadingButton_ = false;
278     }
279     auto hasRightButton = hostNode->HasRightButtonNode();
280     auto buttonNode = FrameNode::GetOrCreateFrameNode(
281         V2::BUTTON_ETS_TAG, hostNode->GetRightButtonId(), []() { return AceType::MakeRefPtr<ButtonPattern>(); });
282     if (hasRightButton) {
283         buttonNode->Clean(true);
284         buttonNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
285     } else {
286         auto buttonPattern = buttonNode->GetPattern<ButtonPattern>();
287         CHECK_NULL_VOID(buttonPattern);
288         buttonPattern->setComponentButtonType(ComponentButtonType::STEPPER);
289         buttonPattern->SetFocusBorderColor(stepperTheme->GetFocusColor());
290         buttonNode->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
291         auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
292         CHECK_NULL_VOID(buttonLayoutProperty);
293         buttonLayoutProperty->UpdateType(ButtonType::NORMAL);
294         buttonLayoutProperty->UpdateMeasureType(MeasureType::MATCH_CONTENT);
295         buttonLayoutProperty->UpdateBorderRadius(BorderRadiusProperty(stepperTheme->GetRadius()));
296         buttonNode->MountToParent(hostNode);
297     }
298     isDisabled ? buttonNode->GetEventHub<ButtonEventHub>()->SetEnabled(false)
299                : buttonNode->GetEventHub<ButtonEventHub>()->SetEnabled(true);
300     if (!isDisabled) {
301         auto focusHub = buttonNode->GetOrCreateFocusHub();
302         CHECK_NULL_VOID(focusHub);
303         focusHub->SetFocusDependence(FocusDependence::SELF);
304     }
305     buttonNode->MarkModifyDone();
306 
307     // Create rowNode
308     auto rowNode = FrameNode::GetOrCreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
309         []() { return AceType::MakeRefPtr<LinearLayoutPattern>(false); });
310     auto rowLayoutProperty = rowNode->GetLayoutProperty<LinearLayoutProperty>();
311     CHECK_NULL_VOID(rowLayoutProperty);
312     rowLayoutProperty->UpdateSpace(stepperTheme->GetControlPadding());
313     rowLayoutProperty->UpdateMargin(
314         { CalcLength(stepperTheme->GetControlPadding()), CalcLength(stepperTheme->GetControlPadding()) });
315     rowNode->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_CONTENT);
316     rowNode->MountToParent(buttonNode);
317     rowNode->MarkModifyDone();
318 
319     // Create textNode
320     auto textNode = FrameNode::GetOrCreateFrameNode(V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
321         []() { return AceType::MakeRefPtr<TextPattern>(); });
322     auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
323     CHECK_NULL_VOID(textLayoutProperty);
324     textLayoutProperty->UpdateMeasureType(MeasureType::MATCH_CONTENT);
325     textLayoutProperty->UpdateContent(rightLabel);
326     auto textColor = stepperTheme->GetTextStyle().GetTextColor();
327     if (isDisabled) {
328         textColor = textColor.BlendOpacity(stepperTheme->GetDisabledAlpha());
329     }
330     textLayoutProperty->UpdateTextColor(textColor);
331     textLayoutProperty->UpdateTextOverflow(TextOverflow::ELLIPSIS);
332     textLayoutProperty->UpdateFontSize(stepperTheme->GetTextStyle().GetFontSize());
333     textLayoutProperty->UpdateAdaptMinFontSize(stepperTheme->GetMinFontSize());
334     textLayoutProperty->UpdateAdaptMaxFontSize(stepperTheme->GetTextStyle().GetFontSize());
335     textLayoutProperty->UpdateFontWeight(stepperTheme->GetTextStyle().GetFontWeight());
336     textLayoutProperty->UpdateMaxLines(stepperTheme->GetTextMaxLines());
337     textLayoutProperty->UpdateAlignment(Alignment::CENTER);
338     textNode->GetFocusHub()->SetFocusable(true);
339     textNode->MountToParent(rowNode);
340     textNode->MarkModifyDone();
341 
342     // Create imageNode
343     auto imageNode = FrameNode::GetOrCreateFrameNode(V2::IMAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
344         []() { return AceType::MakeRefPtr<ImagePattern>(); });
345     auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
346     CHECK_NULL_VOID(imageLayoutProperty);
347     imageLayoutProperty->UpdateUserDefinedIdealSize(
348         CalcSize(CalcLength(stepperTheme->GetArrowWidth()), CalcLength(stepperTheme->GetArrowHeight())));
349     imageLayoutProperty->UpdateImageFit(ImageFit::FILL);
350     ImageSourceInfo imageSourceInfo;
351     if (isRightToLeft_) {
352         rowNode->GetLayoutProperty()->UpdateLayoutDirection(TextDirection::RTL);
353         imageSourceInfo.SetResourceId(InternalResource::ResourceId::STEPPER_BACK_ARROW);
354     } else {
355         rowNode->GetLayoutProperty()->UpdateLayoutDirection(TextDirection::LTR);
356         imageSourceInfo.SetResourceId(InternalResource::ResourceId::STEPPER_NEXT_ARROW);
357     }
358     rightImage_ = imageNode;
359     auto imageColor = stepperTheme->GetArrowColor();
360     if (isDisabled) {
361         imageColor = imageColor.BlendOpacity(stepperTheme->GetDisabledAlpha());
362     }
363     imageSourceInfo.SetFillColor(imageColor);
364     imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
365     SizeF sourceSize(static_cast<float>(stepperTheme->GetArrowWidth().ConvertToPx()),
366         static_cast<float>(stepperTheme->GetArrowHeight().ConvertToPx()));
367     imageLayoutProperty->UpdateSourceSize(sourceSize);
368     imageNode->MountToParent(rowNode);
369     imageNode->MarkModifyDone();
370 }
371 
CreateArrowlessRightButtonNode(int32_t index,bool isDisabled,const std::string & defaultContent)372 void StepperPattern::CreateArrowlessRightButtonNode(int32_t index, bool isDisabled, const std::string& defaultContent)
373 {
374     auto stepperTheme = GetTheme();
375     CHECK_NULL_VOID(stepperTheme);
376     auto hostNode = DynamicCast<StepperNode>(GetHost());
377     CHECK_NULL_VOID(hostNode);
378     // get rightLabel
379     auto swiperNode = hostNode->GetChildAtIndex(hostNode->GetChildIndexById(hostNode->GetSwiperId()));
380     auto stepperItemNode = DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(static_cast<int32_t>(index)));
381     auto rightLabel =
382         stepperItemNode->GetLayoutProperty<StepperItemLayoutProperty>()->GetRightLabel().value_or(defaultContent);
383     // Create or get buttonNode
384     if (isLoadingButton_) {
385         hostNode->RemoveRightButtonNode();
386         isLoadingButton_ = false;
387     }
388     auto hasRightButton = hostNode->HasRightButtonNode();
389     auto buttonNode = FrameNode::GetOrCreateFrameNode(
390         V2::BUTTON_ETS_TAG, hostNode->GetRightButtonId(), []() { return AceType::MakeRefPtr<ButtonPattern>(); });
391     if (hasRightButton) {
392         buttonNode->Clean(true);
393         buttonNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
394     } else {
395         auto buttonPattern = buttonNode->GetPattern<ButtonPattern>();
396         CHECK_NULL_VOID(buttonPattern);
397         buttonPattern->setComponentButtonType(ComponentButtonType::STEPPER);
398         buttonPattern->SetFocusBorderColor(stepperTheme->GetFocusColor());
399         buttonNode->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
400         auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
401         CHECK_NULL_VOID(buttonLayoutProperty);
402         buttonLayoutProperty->UpdateType(ButtonType::NORMAL);
403         buttonLayoutProperty->UpdateMeasureType(MeasureType::MATCH_CONTENT);
404         buttonLayoutProperty->UpdateBorderRadius(BorderRadiusProperty(stepperTheme->GetRadius()));
405         buttonNode->MountToParent(hostNode);
406     }
407     isDisabled ? buttonNode->GetEventHub<ButtonEventHub>()->SetEnabled(false)
408                : buttonNode->GetEventHub<ButtonEventHub>()->SetEnabled(true);
409     if (!isDisabled) {
410         auto focusHub = buttonNode->GetOrCreateFocusHub();
411         CHECK_NULL_VOID(focusHub);
412         focusHub->SetFocusDependence(FocusDependence::SELF);
413     }
414     buttonNode->MarkModifyDone();
415 
416     // Create textNode
417     auto textNode = FrameNode::GetOrCreateFrameNode(V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
418         []() { return AceType::MakeRefPtr<TextPattern>(); });
419     auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
420     CHECK_NULL_VOID(textLayoutProperty);
421     textLayoutProperty->UpdateContent(rightLabel);
422     textLayoutProperty->UpdateFontSize(stepperTheme->GetTextStyle().GetFontSize());
423     textLayoutProperty->UpdateAdaptMinFontSize(stepperTheme->GetMinFontSize());
424     textLayoutProperty->UpdateAdaptMaxFontSize(stepperTheme->GetTextStyle().GetFontSize());
425     textLayoutProperty->UpdateMaxLines(stepperTheme->GetTextMaxLines());
426     textLayoutProperty->UpdateFontWeight(stepperTheme->GetTextStyle().GetFontWeight());
427     auto textColor = stepperTheme->GetTextStyle().GetTextColor();
428     if (isDisabled) {
429         textColor = textColor.BlendOpacity(stepperTheme->GetDisabledAlpha());
430     }
431     textLayoutProperty->UpdateTextColor(textColor);
432     textLayoutProperty->UpdateTextOverflow(TextOverflow::ELLIPSIS);
433     textLayoutProperty->UpdateAlignment(Alignment::CENTER);
434     textLayoutProperty->UpdateMargin(
435         { CalcLength(stepperTheme->GetControlPadding()), CalcLength(stepperTheme->GetControlPadding()) });
436     textNode->GetFocusHub()->SetFocusable(true);
437     textNode->MountToParent(buttonNode);
438     textNode->MarkModifyDone();
439 }
440 
CreateWaitingRightButtonNode()441 void StepperPattern::CreateWaitingRightButtonNode()
442 {
443     auto stepperTheme = GetTheme();
444     CHECK_NULL_VOID(stepperTheme);
445     auto hostNode = DynamicCast<StepperNode>(GetHost());
446     CHECK_NULL_VOID(hostNode);
447     // Create loadingProgressNode
448     hostNode->RemoveRightButtonNode();
449     auto loadingProgressNode = FrameNode::GetOrCreateFrameNode(V2::LOADING_PROGRESS_ETS_TAG,
450         hostNode->GetRightButtonId(), []() { return AceType::MakeRefPtr<LoadingProgressPattern>(); });
451     loadingProgressNode->GetLayoutProperty()->UpdateUserDefinedIdealSize(
452         CalcSize(CalcLength(stepperTheme->GetProgressDiameter()), CalcLength(stepperTheme->GetProgressDiameter())));
453     loadingProgressNode->GetPaintProperty<LoadingProgressPaintProperty>()->UpdateColor(
454         stepperTheme->GetProgressColor());
455     loadingProgressNode->GetRenderContext()->UpdateForegroundColor(stepperTheme->GetProgressColor());
456     loadingProgressNode->MountToParent(hostNode);
457     loadingProgressNode->MarkModifyDone();
458     isLoadingButton_ = true;
459 }
460 
InitButtonClickEvent()461 void StepperPattern::InitButtonClickEvent()
462 {
463     auto hostNode = DynamicCast<StepperNode>(GetHost());
464     CHECK_NULL_VOID(hostNode);
465 
466     if (hostNode->HasLeftButtonNode()) {
467         auto leftButtonNode =
468             DynamicCast<FrameNode>(hostNode->GetChildAtIndex(hostNode->GetChildIndexById(hostNode->GetLeftButtonId())));
469         CHECK_NULL_VOID(leftButtonNode);
470         auto leftGestureHub = leftButtonNode->GetOrCreateGestureEventHub();
471         CHECK_NULL_VOID(leftGestureHub);
472         if (leftGestureHub->IsClickEventsEmpty()) {
473             auto leftClickEvent = [weak = WeakClaim(this)](const GestureEvent& info) {
474                 auto stepperPattern = weak.Upgrade();
475                 CHECK_NULL_VOID(stepperPattern);
476                 stepperPattern->HandlingLeftButtonClickEvent();
477             };
478             leftGestureHub->AddClickEvent(MakeRefPtr<ClickEvent>(std::move(leftClickEvent)));
479         }
480     }
481 
482     if (hostNode->HasRightButtonNode()) {
483         auto rightButtonNode = DynamicCast<FrameNode>(
484             hostNode->GetChildAtIndex(hostNode->GetChildIndexById(hostNode->GetRightButtonId())));
485         CHECK_NULL_VOID(rightButtonNode);
486         auto rightGestureHub = rightButtonNode->GetOrCreateGestureEventHub();
487         CHECK_NULL_VOID(rightGestureHub);
488         if (rightGestureHub->IsClickEventsEmpty()) {
489             auto rightClickEvent = [weak = WeakClaim(this)](const GestureEvent& info) {
490                 auto stepperPattern = weak.Upgrade();
491                 CHECK_NULL_VOID(stepperPattern);
492                 stepperPattern->HandlingRightButtonClickEvent();
493             };
494             rightGestureHub->AddClickEvent(MakeRefPtr<ClickEvent>(std::move(rightClickEvent)));
495         }
496     }
497 }
498 
HandlingLeftButtonClickEvent()499 void StepperPattern::HandlingLeftButtonClickEvent()
500 {
501     auto hostNode = DynamicCast<StepperNode>(GetHost());
502     CHECK_NULL_VOID(hostNode);
503     auto stepperHub = hostNode->GetEventHub<StepperEventHub>();
504     CHECK_NULL_VOID(stepperHub);
505     auto swiperNode =
506         DynamicCast<FrameNode>(hostNode->GetChildAtIndex(hostNode->GetChildIndexById(hostNode->GetSwiperId())));
507     auto swiperAnimationController = swiperNode->GetPattern<SwiperPattern>()->GetController();
508     if (swiperAnimationController && !swiperAnimationController->IsStopped()) {
509         return;
510     }
511     auto swiperController = swiperNode->GetPattern<SwiperPattern>()->GetSwiperController();
512     stepperHub->FireChangeEvent(index_, std::clamp<int32_t>(index_ - 1, 0, maxIndex_));
513     stepperHub->FirePreviousEvent(index_, std::clamp<int32_t>(index_ - 1, 0, maxIndex_));
514     swiperController->SwipeTo(std::clamp<int32_t>(index_ - 1, 0, maxIndex_));
515 }
516 
HandlingRightButtonClickEvent()517 void StepperPattern::HandlingRightButtonClickEvent()
518 {
519     auto hostNode = DynamicCast<StepperNode>(GetHost());
520     CHECK_NULL_VOID(hostNode);
521     auto stepperHub = hostNode->GetEventHub<StepperEventHub>();
522     CHECK_NULL_VOID(stepperHub);
523     auto swiperNode =
524         DynamicCast<FrameNode>(hostNode->GetChildAtIndex(hostNode->GetChildIndexById(hostNode->GetSwiperId())));
525     auto swiperAnimationController = swiperNode->GetPattern<SwiperPattern>()->GetController();
526     if (swiperAnimationController && !swiperAnimationController->IsStopped()) {
527         return;
528     }
529     auto stepperItemNode = DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(static_cast<int32_t>(index_)));
530     CHECK_NULL_VOID(stepperItemNode);
531     auto labelStatus =
532         stepperItemNode->GetLayoutProperty<StepperItemLayoutProperty>()->GetLabelStatus().value_or("normal");
533     if (labelStatus == "skip") {
534         stepperHub->FireSkipEvent(index_);
535     } else if (labelStatus == "normal") {
536         if (index_ == maxIndex_) {
537             stepperHub->FireFinishEvent(index_);
538         } else {
539             stepperHub->FireChangeEvent(index_, std::clamp<int32_t>(index_ + 1, 0, maxIndex_));
540             stepperHub->FireNextEvent(index_, std::clamp<int32_t>(index_ + 1, 0, maxIndex_));
541             auto swiperController = swiperNode->GetPattern<SwiperPattern>()->GetSwiperController();
542             swiperController->SwipeTo(std::clamp<int32_t>(index_ + 1, 0, maxIndex_));
543         }
544     }
545 }
546 
TotalCount() const547 int32_t StepperPattern::TotalCount() const
548 {
549     auto hostNode = DynamicCast<StepperNode>(GetHost());
550     CHECK_NULL_RETURN(hostNode, 0);
551     auto swiperNode =
552         DynamicCast<FrameNode>(hostNode->GetChildAtIndex(hostNode->GetChildIndexById(hostNode->GetSwiperId())));
553     CHECK_NULL_RETURN(swiperNode, 0);
554     return swiperNode->TotalChildCount() - 1;
555 }
556 
SetAccessibilityAction()557 void StepperPattern::SetAccessibilityAction()
558 {
559     auto host = GetHost();
560     CHECK_NULL_VOID(host);
561     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
562     CHECK_NULL_VOID(accessibilityProperty);
563     accessibilityProperty->SetActionScrollForward([weakPtr = WeakClaim(this)]() {
564         const auto& pattern = weakPtr.Upgrade();
565         CHECK_NULL_VOID(pattern);
566         pattern->HandlingRightButtonClickEvent();
567     });
568 
569     accessibilityProperty->SetActionScrollBackward([weakPtr = WeakClaim(this)]() {
570         const auto& pattern = weakPtr.Upgrade();
571         CHECK_NULL_VOID(pattern);
572         pattern->HandlingLeftButtonClickEvent();
573     });
574 }
575 
GetFocusNode(FocusStep step,const WeakPtr<FocusHub> & currentFocusNode)576 WeakPtr<FocusHub> StepperPattern::GetFocusNode(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode)
577 {
578     auto curFocusNode = currentFocusNode.Upgrade();
579     CHECK_NULL_RETURN(curFocusNode, nullptr);
580     auto hostNode = DynamicCast<StepperNode>(GetHost());
581     CHECK_NULL_RETURN(hostNode, nullptr);
582 
583     auto swiperNode = hostNode->GetChildAtIndex(hostNode->GetChildIndexById(hostNode->GetSwiperId()));
584     CHECK_NULL_RETURN(swiperNode, nullptr);
585     auto stepperItemNode = DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(static_cast<int32_t>(index_)));
586     CHECK_NULL_RETURN(stepperItemNode, nullptr);
587     auto buttonFocusHub = stepperItemNode->GetOrCreateFocusHub();
588     CHECK_NULL_RETURN(buttonFocusHub, nullptr);
589 
590     auto stepperItemLayoutProperty = stepperItemNode->GetLayoutProperty<StepperItemLayoutProperty>();
591     CHECK_NULL_RETURN(stepperItemLayoutProperty, nullptr);
592     auto labelStatus = stepperItemLayoutProperty->GetLabelStatus().value_or("normal");
593 
594     if (hostNode->HasLeftButtonNode()) {
595         auto leftButtonNode =
596             DynamicCast<FrameNode>(hostNode->GetChildAtIndex(hostNode->GetChildIndexById(hostNode->GetLeftButtonId())));
597         CHECK_NULL_RETURN(leftButtonNode, nullptr);
598         leftFocusHub_ = leftButtonNode->GetOrCreateFocusHub();
599     }
600 
601     auto rightButtonNode =
602         DynamicCast<FrameNode>(hostNode->GetChildAtIndex(hostNode->GetChildIndexById(hostNode->GetRightButtonId())));
603     CHECK_NULL_RETURN(rightButtonNode, nullptr);
604     auto rightFocusHub = rightButtonNode->GetOrCreateFocusHub();
605     CHECK_NULL_RETURN(rightFocusHub, nullptr);
606 
607     if (labelStatus == "normal" || labelStatus == "skip") {
608         if (step == FocusStep::UP || step == FocusStep::LEFT || step == FocusStep::SHIFT_TAB) {
609             return curFocusNode == leftFocusHub_ ? buttonFocusHub : leftFocusHub_;
610         }
611 
612         if (curFocusNode != leftFocusHub_ && curFocusNode != rightFocusHub) {
613             return hostNode->HasLeftButtonNode() ? leftFocusHub_ : rightFocusHub;
614         }
615 
616         if (curFocusNode == rightFocusHub && !hostNode->HasLeftButtonNode()) {
617             return buttonFocusHub;
618         }
619 
620         if (step == FocusStep::DOWN || step == FocusStep::RIGHT || step == FocusStep::TAB) {
621             return curFocusNode == buttonFocusHub ? leftFocusHub_ : rightFocusHub;
622         }
623     } else if (labelStatus == "disabled" || labelStatus == "waiting") {
624         return curFocusNode == leftFocusHub_ ? buttonFocusHub : leftFocusHub_;
625     }
626     return nullptr;
627 }
628 
OnColorConfigurationUpdate()629 void StepperPattern::OnColorConfigurationUpdate()
630 {
631     auto host = GetHost();
632     CHECK_NULL_VOID(host);
633     auto hostNode = DynamicCast<StepperNode>(GetHost());
634     CHECK_NULL_VOID(hostNode);
635     auto stepperTheme = GetTheme();
636     CHECK_NULL_VOID(stepperTheme);
637     auto textColor = stepperTheme->GetTextStyle().GetTextColor();
638     auto leftButtonNode = hostNode->GetChildAtIndex(hostNode->GetChildIndexById(hostNode->GetLeftButtonId()));
639     if (leftButtonNode) {
640         auto leftButtonFrameNode = DynamicCast<FrameNode>(leftButtonNode);
641         CHECK_NULL_VOID(leftButtonFrameNode);
642         ButtonSkipColorConfigurationUpdate(leftButtonFrameNode);
643         auto renderContext = leftButtonFrameNode->GetRenderContext();
644         CHECK_NULL_VOID(renderContext);
645         renderContext->UpdateBackgroundColor(stepperTheme->GetMouseHoverColor().ChangeOpacity(0));
646         auto rowNode = leftButtonFrameNode->GetChildAtIndex(0);
647         CHECK_NULL_VOID(rowNode);
648         auto textFrameNode = DynamicCast<FrameNode>(rowNode->GetChildAtIndex(1));
649         CHECK_NULL_VOID(textFrameNode);
650         auto layoutProperty = textFrameNode->GetLayoutProperty<TextLayoutProperty>();
651         CHECK_NULL_VOID(layoutProperty);
652         layoutProperty->UpdateTextColor(textColor);
653     }
654     auto rightButtonNode = hostNode->GetChildAtIndex(hostNode->GetChildIndexById(hostNode->GetRightButtonId()));
655     if (rightButtonNode) {
656         auto rightButtonFrameNode = DynamicCast<FrameNode>(rightButtonNode);
657         CHECK_NULL_VOID(rightButtonFrameNode);
658         ButtonSkipColorConfigurationUpdate(rightButtonFrameNode);
659         auto renderContext = rightButtonFrameNode->GetRenderContext();
660         CHECK_NULL_VOID(renderContext);
661         renderContext->UpdateBackgroundColor(stepperTheme->GetMouseHoverColor().ChangeOpacity(0));
662         auto firstChild = rightButtonFrameNode->GetFirstChild();
663         CHECK_NULL_VOID(firstChild);
664         if (firstChild->GetTag() == V2::ROW_ETS_TAG) {
665             auto textFrameNode = DynamicCast<FrameNode>(firstChild->GetChildAtIndex(0));
666             CHECK_NULL_VOID(textFrameNode);
667             auto layoutProperty = textFrameNode->GetLayoutProperty<TextLayoutProperty>();
668             CHECK_NULL_VOID(layoutProperty);
669             layoutProperty->UpdateTextColor(textColor);
670         }
671         if (firstChild->GetTag() == V2::TEXT_ETS_TAG) {
672             auto textFrameNode = DynamicCast<FrameNode>(firstChild);
673             CHECK_NULL_VOID(textFrameNode);
674             auto layoutProperty = textFrameNode->GetLayoutProperty<TextLayoutProperty>();
675             CHECK_NULL_VOID(layoutProperty);
676             layoutProperty->UpdateTextColor(textColor);
677         }
678     }
679 }
680 
ButtonSkipColorConfigurationUpdate(const RefPtr<FrameNode> & buttonNode)681 void StepperPattern::ButtonSkipColorConfigurationUpdate(const RefPtr<FrameNode>& buttonNode)
682 {
683     auto pattern = buttonNode->GetPattern<ButtonPattern>();
684     CHECK_NULL_VOID(pattern);
685     pattern->SetSkipColorConfigurationUpdate();
686 }
687 
OnLanguageConfigurationUpdate()688 void StepperPattern::OnLanguageConfigurationUpdate()
689 {
690     auto hostNode = DynamicCast<StepperNode>(GetHost());
691     CHECK_NULL_VOID(hostNode);
692     auto stepperLayoutProperty = hostNode->GetLayoutProperty<StepperLayoutProperty>();
693     CHECK_NULL_VOID(stepperLayoutProperty);
694     auto isRightToLeft = stepperLayoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
695     if (isRightToLeft != isRightToLeft_) {
696         auto hostNode = AceType::DynamicCast<StepperNode>(GetHost());
697         CHECK_NULL_VOID(hostNode);
698         hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
699         isRightToLeft_ = isRightToLeft;
700 
701         auto stepperTheme = GetTheme();
702         CHECK_NULL_VOID(stepperTheme);
703         if (leftImage_) {
704             auto leftimageLayoutProperty = leftImage_->GetLayoutProperty<ImageLayoutProperty>();
705             CHECK_NULL_VOID(leftimageLayoutProperty);
706             auto leftRow = DynamicCast<FrameNode>(leftImage_->GetParent());
707             CHECK_NULL_VOID(leftRow);
708 
709             ImageSourceInfo leftimageSourceInfo;
710             if (isRightToLeft_) {
711                 leftRow->GetLayoutProperty()->UpdateLayoutDirection(TextDirection::RTL);
712                 leftimageSourceInfo.SetResourceId(InternalResource::ResourceId::STEPPER_NEXT_ARROW);
713             } else {
714                 leftRow->GetLayoutProperty()->UpdateLayoutDirection(TextDirection::LTR);
715                 leftimageSourceInfo.SetResourceId(InternalResource::ResourceId::STEPPER_BACK_ARROW);
716             }
717             leftimageSourceInfo.SetFillColor(stepperTheme->GetArrowColor());
718             leftimageLayoutProperty->UpdateImageSourceInfo(leftimageSourceInfo);
719             leftImage_->MarkModifyDone();
720         }
721         if (rightImage_) {
722             auto rightimageLayoutProperty = rightImage_->GetLayoutProperty<ImageLayoutProperty>();
723             CHECK_NULL_VOID(rightimageLayoutProperty);
724             auto rightRow = DynamicCast<FrameNode>(rightImage_->GetParent());
725             CHECK_NULL_VOID(rightRow);
726             ImageSourceInfo rightimageSourceInfo;
727             if (isRightToLeft_) {
728                 rightRow->GetLayoutProperty()->UpdateLayoutDirection(TextDirection::RTL);
729                 rightimageSourceInfo.SetResourceId(InternalResource::ResourceId::STEPPER_BACK_ARROW);
730             } else {
731                 rightRow->GetLayoutProperty()->UpdateLayoutDirection(TextDirection::LTR);
732                 rightimageSourceInfo.SetResourceId(InternalResource::ResourceId::STEPPER_NEXT_ARROW);
733             }
734             rightimageSourceInfo.SetFillColor(stepperTheme->GetArrowColor());
735             rightimageLayoutProperty->UpdateImageSourceInfo(rightimageSourceInfo);
736             rightImage_->MarkModifyDone();
737         }
738     }
739 }
740 } // namespace OHOS::Ace::NG
741