• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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/text_picker/textpicker_pattern.h"
17 
18 #include <cstdint>
19 #include <functional>
20 #include <securec.h>
21 
22 #include "base/i18n/localization.h"
23 #include "base/geometry/dimension.h"
24 #include "base/geometry/ng/size_t.h"
25 #include "base/utils/utils.h"
26 #include "core/components/picker/picker_theme.h"
27 #include "core/components_ng/base/inspector_filter.h"
28 #include "core/components_ng/pattern/button/button_pattern.h"
29 #include "core/components_ng/pattern/text/text_layout_property.h"
30 #include "core/components_ng/pattern/text/text_pattern.h"
31 #include "core/components_ng/pattern/text_picker/textpicker_column_pattern.h"
32 #include "core/components_ng/pattern/text_picker/textpicker_event_hub.h"
33 #include "core/components_ng/pattern/text_picker/textpicker_layout_property.h"
34 #include "core/components_ng/pattern/text_picker/toss_animation_controller.h"
35 #include "core/components_ng/render/drawing.h"
36 #include "core/common/resource/resource_object.h"
37 #include "core/common/resource/resource_parse_utils.h"
38 
39 namespace OHOS::Ace::NG {
40 namespace {
41 // Datepicker style modification
42 const Dimension PRESS_INTERVAL = 4.0_vp;
43 const Dimension PRESS_RADIUS = 8.0_vp;
44 constexpr uint32_t RATE = 2;
45 const Dimension DIALOG_OFFSET = 1.0_vp;
46 const Dimension DIALOG_OFFSET_LENGTH = 1.0_vp;
47 constexpr uint32_t HALF = 2;
48 const Dimension FOCUS_WIDTH = 2.0_vp;
49 const Dimension FOCUS_INTERVAL = 2.0_vp;
50 const Dimension LINE_WIDTH = 1.5_vp;
51 constexpr float DISABLE_ALPHA = 0.6f;
52 constexpr float MAX_PERCENT = 100.0f;
53 const int32_t INVISIBLE_OPTIONS_COUNT = 2;
54 constexpr float PICKER_MAXFONTSCALE = 1.0f;
55 constexpr uint32_t PRECISION_TWO = 2;
56 constexpr float DEFAULT_SIZE_ZERO = 0.0f;
57 } // namespace
58 
OnAttachToFrameNode()59 void TextPickerPattern::OnAttachToFrameNode()
60 {
61     auto host = GetHost();
62     CHECK_NULL_VOID(host);
63     host->GetRenderContext()->SetClipToFrame(true);
64     host->GetRenderContext()->UpdateClipEdge(true);
65 }
66 
SetLayoutDirection(TextDirection textDirection)67 void TextPickerPattern::SetLayoutDirection(TextDirection textDirection)
68 {
69     auto textPickerNode = GetHost();
70     std::function<void (decltype(textPickerNode))> updateDirectionFunc = [&](decltype(textPickerNode) node) {
71         CHECK_NULL_VOID(node);
72         auto updateProperty = node->GetLayoutProperty();
73         updateProperty->UpdateLayoutDirection(textDirection);
74         for (auto child : node->GetAllChildrenWithBuild()) {
75             auto frameNode = AceType::DynamicCast<FrameNode>(child);
76             if (!frameNode) {
77                 continue;
78             }
79             updateDirectionFunc(frameNode);
80         }
81     };
82     updateDirectionFunc(textPickerNode);
83 }
84 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)85 bool TextPickerPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
86 {
87     if (config.skipLayout || config.skipMeasure) {
88         return false;
89     }
90 
91     CHECK_NULL_RETURN(dirty, false);
92     SetButtonIdeaSize();
93     if (GetIsShowInDialog()) {
94         auto host = GetHost();
95         CHECK_NULL_RETURN(host, false);
96         auto parentNode = host->GetParent();
97         CHECK_NULL_RETURN(parentNode, false);
98         parentNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
99     }
100     return true;
101 }
102 
UpdateButtonMargin(const RefPtr<FrameNode> & buttonNode,const RefPtr<DialogTheme> & dialogTheme,const bool isConfirmOrNextNode)103 void TextPickerPattern::UpdateButtonMargin(
104     const RefPtr<FrameNode>& buttonNode, const RefPtr<DialogTheme>& dialogTheme, const bool isConfirmOrNextNode)
105 {
106     MarginProperty margin;
107     bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
108     isRtl = isConfirmOrNextNode ? isRtl : !isRtl;
109     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
110         margin.top = CalcLength(dialogTheme->GetDividerHeight());
111         margin.bottom = CalcLength(dialogTheme->GetDividerPadding().Bottom());
112         if (isRtl) {
113             margin.right = CalcLength(0.0_vp);
114             margin.left = CalcLength(dialogTheme->GetDividerPadding().Left());
115         } else {
116             margin.right = CalcLength(dialogTheme->GetDividerPadding().Right());
117             margin.left = CalcLength(0.0_vp);
118         }
119     } else {
120         margin.top = CalcLength(dialogTheme->GetActionsPadding().Top());
121         margin.bottom = CalcLength(dialogTheme->GetActionsPadding().Bottom());
122         if (isRtl) {
123             margin.right = CalcLength(0.0_vp);
124             margin.left = CalcLength(dialogTheme->GetActionsPadding().Left());
125         } else {
126             margin.right = CalcLength(dialogTheme->GetActionsPadding().Right());
127             margin.left = CalcLength(0.0_vp);
128         }
129     }
130     buttonNode->GetLayoutProperty()->UpdateMargin(margin);
131 }
132 
UpdateDialogAgingButton(const RefPtr<FrameNode> & buttonNode,bool isNext)133 void TextPickerPattern::UpdateDialogAgingButton(const RefPtr<FrameNode>& buttonNode, bool isNext)
134 {
135     CHECK_NULL_VOID(buttonNode);
136     auto updateNode = AceType::DynamicCast<FrameNode>(buttonNode->GetFirstChild());
137     CHECK_NULL_VOID(updateNode);
138     auto updateNodeLayout = updateNode->GetLayoutProperty<TextLayoutProperty>();
139     CHECK_NULL_VOID(updateNodeLayout);
140 
141     auto pipeline = updateNode->GetContext();
142     CHECK_NULL_VOID(pipeline);
143     auto dialogTheme = pipeline->GetTheme<DialogTheme>();
144     CHECK_NULL_VOID(dialogTheme);
145     auto pickerTheme = pipeline->GetTheme<PickerTheme>();
146     CHECK_NULL_VOID(pickerTheme);
147     std::string lettersStr = isNext ? pickerTheme->GetNextText() : pickerTheme->GetPrevText();
148     updateNodeLayout->UpdateContent(lettersStr);
149     auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
150     CHECK_NULL_VOID(buttonLayoutProperty);
151     buttonLayoutProperty->UpdateLabel(lettersStr);
152 
153     UpdateButtonMargin(buttonNode, dialogTheme, isNext);
154     updateNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
155 }
156 
OnLanguageConfigurationUpdate()157 void TextPickerPattern::OnLanguageConfigurationUpdate()
158 {
159     auto buttonConfirmNode = weakButtonConfirm_.Upgrade();
160     CHECK_NULL_VOID(buttonConfirmNode);
161     auto confirmNode = AceType::DynamicCast<FrameNode>(buttonConfirmNode->GetFirstChild());
162     CHECK_NULL_VOID(confirmNode);
163     auto confirmNodeLayout = confirmNode->GetLayoutProperty<TextLayoutProperty>();
164     CHECK_NULL_VOID(confirmNodeLayout);
165     auto pipeline = confirmNode->GetContextRefPtr();
166     CHECK_NULL_VOID(pipeline);
167     auto dialogTheme = pipeline->GetTheme<DialogTheme>();
168     CHECK_NULL_VOID(dialogTheme);
169     confirmNodeLayout->UpdateContent(dialogTheme->GetConfirmText());
170     auto buttonConfirmLayoutProperty = buttonConfirmNode->GetLayoutProperty<ButtonLayoutProperty>();
171     CHECK_NULL_VOID(buttonConfirmLayoutProperty);
172     buttonConfirmLayoutProperty->UpdateLabel(dialogTheme->GetConfirmText());
173     UpdateButtonMargin(buttonConfirmNode, dialogTheme, true);
174     confirmNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
175 
176     auto buttonCancelNode = weakButtonCancel_.Upgrade();
177     CHECK_NULL_VOID(buttonCancelNode);
178     auto cancelNode = AceType::DynamicCast<FrameNode>(buttonCancelNode->GetFirstChild());
179     CHECK_NULL_VOID(cancelNode);
180     auto cancelNodeLayout = cancelNode->GetLayoutProperty<TextLayoutProperty>();
181     CHECK_NULL_VOID(cancelNodeLayout);
182     cancelNodeLayout->UpdateContent(dialogTheme->GetCancelText());
183     UpdateButtonMargin(buttonCancelNode, dialogTheme, false);
184     auto buttonCancelLayoutProperty = buttonCancelNode->GetLayoutProperty<ButtonLayoutProperty>();
185     CHECK_NULL_VOID(buttonCancelLayoutProperty);
186     buttonCancelLayoutProperty->UpdateLabel(dialogTheme->GetCancelText());
187     cancelNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
188 
189     auto buttonForwardNode = weakButtonForward_.Upgrade();
190     UpdateDialogAgingButton(buttonForwardNode, true);
191     auto buttonBackwardNode = weakButtonBackward_.Upgrade();
192     UpdateDialogAgingButton(buttonBackwardNode, false);
193 }
194 
OnFontConfigurationUpdate()195 void TextPickerPattern::OnFontConfigurationUpdate()
196 {
197     CHECK_NULL_VOID(closeDialogEvent_);
198     closeDialogEvent_();
199 }
200 
OnFontScaleConfigurationUpdate()201 void TextPickerPattern::OnFontScaleConfigurationUpdate()
202 {
203     CHECK_NULL_VOID(closeDialogEvent_);
204     closeDialogEvent_();
205 }
206 
SetButtonIdeaSize()207 void TextPickerPattern::SetButtonIdeaSize()
208 {
209     auto host = GetHost();
210     CHECK_NULL_VOID(host);
211     auto context = host->GetContext();
212     CHECK_NULL_VOID(context);
213     auto layoutProperty = host->GetLayoutProperty<TextPickerLayoutProperty>();
214     CHECK_NULL_VOID(layoutProperty);
215     auto pickerTheme = context->GetTheme<PickerTheme>();
216     CHECK_NULL_VOID(pickerTheme);
217     auto children = host->GetChildren();
218     auto currentFocusButtonNode = GetFocusButtonNode();
219     CHECK_NULL_VOID(currentFocusButtonNode);
220     for (const auto& child : children) {
221         CalculateButtonMetrics(child, pickerTheme);
222         auto stackNode = DynamicCast<FrameNode>(child);
223         auto buttonNode = DynamicCast<FrameNode>(child->GetFirstChild());
224         auto buttonConfirmRenderContext = buttonNode->GetRenderContext();
225         CHECK_NULL_VOID(buttonConfirmRenderContext);
226         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
227         CHECK_NULL_VOID(blendNode);
228         auto columnNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
229         CHECK_NULL_VOID(columnNode);
230         auto columnPattern = columnNode->GetPattern<TextPickerColumnPattern>();
231         CHECK_NULL_VOID(columnPattern);
232         if (!useButtonFocusArea_) {
233             if (!columnPattern->isHover()) {
234                 buttonConfirmRenderContext->UpdateBackgroundColor(Color::TRANSPARENT);
235             }
236         } else {
237             UpdateColumnButtonStyles(columnNode, haveFocus_ && (currentFocusButtonNode == buttonNode), false);
238         }
239         buttonNode->MarkModifyDone();
240         buttonNode->MarkDirtyNode();
241     }
242 }
243 
CalculateButtonMetrics(RefPtr<UINode> child,RefPtr<PickerTheme> pickerTheme)244 void TextPickerPattern::CalculateButtonMetrics(RefPtr<UINode> child, RefPtr<PickerTheme> pickerTheme)
245 {
246     auto host = GetHost();
247     CHECK_NULL_VOID(host);
248     auto children = host->GetChildren();
249     auto layoutProperty = host->GetLayoutProperty<TextPickerLayoutProperty>();
250     CHECK_NULL_VOID(layoutProperty);
251     auto stackNode = DynamicCast<FrameNode>(child);
252     CHECK_NULL_VOID(stackNode);
253     auto width = stackNode->GetGeometryNode()->GetFrameSize().Width();
254     auto buttonNode = DynamicCast<FrameNode>(child->GetFirstChild());
255     CHECK_NULL_VOID(buttonNode);
256     auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
257     CHECK_NULL_VOID(buttonLayoutProperty);
258     buttonLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT_MAIN_AXIS);
259     buttonLayoutProperty->UpdateType(ButtonType::NORMAL);
260     if (layoutProperty->HasSelectedBorderRadius()) {
261         buttonLayoutProperty->UpdateBorderRadius(layoutProperty->GetSelectedBorderRadiusValue());
262     } else {
263         buttonLayoutProperty->UpdateBorderRadius(BorderRadiusProperty(selectorItemRadius_));
264     }
265     auto buttonHeight = CalculateHeight() - PRESS_INTERVAL.ConvertToPx() * (useButtonFocusArea_ ? 1 : RATE);
266     if (resizeFlag_) {
267         buttonHeight = resizePickerItemHeight_ - PRESS_INTERVAL.ConvertToPx() * RATE;
268     }
269 
270     auto buttonSpace = useButtonFocusArea_ ? pickerTheme->GetSelectorItemSpace() : PRESS_INTERVAL * RATE;
271     if (children.size() == 1 && useButtonFocusArea_) {
272         buttonSpace = PRESS_INTERVAL * RATE;
273     }
274     buttonLayoutProperty->UpdateUserDefinedIdealSize(
275         CalcSize(CalcLength(width - buttonSpace.ConvertToPx()), CalcLength(buttonHeight)));
276 }
277 
InitSelectorProps()278 void TextPickerPattern::InitSelectorProps()
279 {
280     auto host = GetHost();
281     CHECK_NULL_VOID(host);
282     auto context = host->GetContextRefPtr();
283     CHECK_NULL_VOID(context);
284     auto pickerTheme = context->GetTheme<PickerTheme>();
285     CHECK_NULL_VOID(pickerTheme);
286 
287     selectorItemRadius_ = pickerTheme->GetSelectorItemRadius();
288     useButtonFocusArea_ = pickerTheme->NeedButtonFocusAreaType();
289 }
290 
InitFocusEvent()291 void TextPickerPattern::InitFocusEvent()
292 {
293     CHECK_NULL_VOID(!focusEventInitialized_);
294     auto host = GetHost();
295     CHECK_NULL_VOID(host);
296     auto focusHub = host->GetOrCreateFocusHub();
297     CHECK_NULL_VOID(focusHub);
298     auto focusTask = [weak = WeakClaim(this)](FocusReason reason) {
299         auto pattern = weak.Upgrade();
300         CHECK_NULL_VOID(pattern);
301         pattern->HandleFocusEvent();
302     };
303     focusHub->SetOnFocusInternal(focusTask);
304 
305     auto blurTask = [weak = WeakClaim(this)]() {
306         auto pattern = weak.Upgrade();
307         CHECK_NULL_VOID(pattern);
308         pattern->HandleBlurEvent();
309     };
310     focusHub->SetOnBlurInternal(blurTask);
311 
312     focusEventInitialized_ = true;
313 }
314 
SetHaveFocus(bool haveFocus)315 void TextPickerPattern::SetHaveFocus(bool haveFocus)
316 {
317     haveFocus_ = haveFocus;
318 }
319 
HandleFocusEvent()320 void TextPickerPattern::HandleFocusEvent()
321 {
322     auto host = GetHost();
323     CHECK_NULL_VOID(host);
324     auto context = host->GetContextRefPtr();
325     CHECK_NULL_VOID(context);
326 
327     AddIsFocusActiveUpdateEvent();
328     if (context->GetIsFocusActive()) {
329         SetHaveFocus(true);
330         UpdateFocusButtonState();
331     }
332 }
333 
HandleBlurEvent()334 void TextPickerPattern::HandleBlurEvent()
335 {
336     SetHaveFocus(false);
337     RemoveIsFocusActiveUpdateEvent();
338     UpdateFocusButtonState();
339 }
340 
AddIsFocusActiveUpdateEvent()341 void TextPickerPattern::AddIsFocusActiveUpdateEvent()
342 {
343     if (!isFocusActiveUpdateEvent_) {
344         isFocusActiveUpdateEvent_ = [weak = WeakClaim(this)](bool isFocusAcitve) {
345             auto pickerPattern = weak.Upgrade();
346             CHECK_NULL_VOID(pickerPattern);
347             pickerPattern->SetHaveFocus(isFocusAcitve);
348             pickerPattern->UpdateFocusButtonState();
349         };
350     }
351     auto context = GetContext();
352     CHECK_NULL_VOID(context);
353     context->AddIsFocusActiveUpdateEvent(GetHost(), isFocusActiveUpdateEvent_);
354 }
355 
RemoveIsFocusActiveUpdateEvent()356 void TextPickerPattern::RemoveIsFocusActiveUpdateEvent()
357 {
358     auto host = GetHost();
359     CHECK_NULL_VOID(host);
360     auto pipeline = host->GetContext();
361     CHECK_NULL_VOID(pipeline);
362     pipeline->RemoveIsFocusActiveUpdateEvent(host);
363 }
364 
UpdateFocusButtonState()365 void TextPickerPattern::UpdateFocusButtonState()
366 {
367     auto host = GetHost();
368     CHECK_NULL_VOID(host);
369 
370     if (useButtonFocusArea_) {
371         auto currentFocusStackNode = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
372         CHECK_NULL_VOID(currentFocusStackNode);
373         auto blendColumnNode = currentFocusStackNode->GetLastChild();
374         CHECK_NULL_VOID(blendColumnNode);
375         auto currentFocusColumnNode = DynamicCast<FrameNode>(blendColumnNode->GetLastChild());
376         CHECK_NULL_VOID(currentFocusColumnNode);
377 
378         UpdateColumnButtonStyles(currentFocusColumnNode, haveFocus_, true);
379     }
380 }
381 
GetFocusButtonNode() const382 const RefPtr<FrameNode> TextPickerPattern::GetFocusButtonNode() const
383 {
384     auto host = GetHost();
385     CHECK_NULL_RETURN(host, nullptr);
386     auto currentFocusStackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
387     CHECK_NULL_RETURN(currentFocusStackChild, nullptr);
388     auto currentFocusButtonNode = DynamicCast<FrameNode>(currentFocusStackChild->GetFirstChild());
389     return currentFocusButtonNode;
390 }
391 
UpdateColumnButtonStyles(const RefPtr<FrameNode> & columnNode,bool haveFocus,bool needMarkDirty)392 void TextPickerPattern::UpdateColumnButtonStyles(
393     const RefPtr<FrameNode>& columnNode, bool haveFocus, bool needMarkDirty)
394 {
395     CHECK_NULL_VOID(columnNode);
396 
397     auto textPickerColumnPattern = columnNode->GetPattern<TextPickerColumnPattern>();
398     CHECK_NULL_VOID(textPickerColumnPattern);
399     textPickerColumnPattern->UpdateColumnButtonFocusState(haveFocus, needMarkDirty);
400 }
401 
GetInnerFocusButtonPaintRect(RoundRect & paintRect,float focusButtonXOffset)402 void TextPickerPattern::GetInnerFocusButtonPaintRect(RoundRect& paintRect, float focusButtonXOffset)
403 {
404     auto host = GetHost();
405     CHECK_NULL_VOID(host);
406 
407     auto geometryNode = host->GetGeometryNode();
408     CHECK_NULL_VOID(geometryNode);
409     auto context = host->GetContext();
410     CHECK_NULL_VOID(context);
411     auto pickerTheme = context->GetTheme<PickerTheme>();
412     CHECK_NULL_VOID(pickerTheme);
413     auto stackNode = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
414     CHECK_NULL_VOID(stackNode);
415     auto buttonNode = DynamicCast<FrameNode>(stackNode->GetFirstChild());
416     CHECK_NULL_VOID(buttonNode);
417     auto focusButtonRect = buttonNode->GetGeometryNode()->GetFrameRect();
418     auto focusSpace = pickerTheme->GetFocusPadding().ConvertToPx();
419     auto stackRenderContext = stackNode->GetRenderContext();
420     CHECK_NULL_VOID(stackRenderContext);
421     auto leftPadding = 0.0f;
422     if (geometryNode->GetPadding()) {
423         leftPadding = geometryNode->GetPadding()->left.value_or(0.0f);
424     }
425     focusButtonRect -=
426         OffsetF(focusSpace - leftPadding, focusSpace - stackRenderContext->GetPaintRectWithoutTransform().GetY());
427     focusButtonRect += SizeF(focusSpace + focusSpace, focusSpace + focusSpace);
428     focusButtonRect += OffsetF(focusButtonXOffset, 0);
429 
430     paintRect.SetRect(focusButtonRect);
431     BorderRadiusProperty borderRadius;
432     borderRadius.SetRadius(selectorItemRadius_);
433     auto renderContext = buttonNode->GetRenderContext();
434     CHECK_NULL_VOID(renderContext);
435     auto radius = renderContext->GetBorderRadius().value_or(borderRadius);
436     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS,
437         static_cast<float>(radius.radiusTopLeft->ConvertToPx() + focusSpace),
438         static_cast<float>(radius.radiusTopLeft->ConvertToPx() + focusSpace));
439     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS,
440         static_cast<float>(radius.radiusTopRight->ConvertToPx() + focusSpace),
441         static_cast<float>(radius.radiusTopRight->ConvertToPx() + focusSpace));
442     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS,
443         static_cast<float>(radius.radiusBottomLeft->ConvertToPx() + focusSpace),
444         static_cast<float>(radius.radiusBottomLeft->ConvertToPx() + focusSpace));
445     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS,
446         static_cast<float>(radius.radiusBottomRight->ConvertToPx() + focusSpace),
447         static_cast<float>(radius.radiusBottomRight->ConvertToPx() + focusSpace));
448 }
449 
CalcLeftTotalColumnWidth(const RefPtr<FrameNode> & host,float & leftTotalColumnWidth,float childSize)450 void TextPickerPattern::CalcLeftTotalColumnWidth(
451     const RefPtr<FrameNode>& host, float& leftTotalColumnWidth, float childSize)
452 {
453     bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
454     if (isRtl) {
455         for (int32_t index = childSize - 1; index > focusKeyID_; --index) {
456             auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(index));
457             CHECK_NULL_VOID(stackChild);
458             auto geometryNode = stackChild->GetGeometryNode();
459             CHECK_NULL_VOID(geometryNode);
460             leftTotalColumnWidth += geometryNode->GetFrameSize().Width();
461         }
462     } else {
463         for (int32_t index = 0; index < focusKeyID_; ++index) {
464             auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(index));
465             CHECK_NULL_VOID(stackChild);
466             auto geometryNode = stackChild->GetGeometryNode();
467             CHECK_NULL_VOID(geometryNode);
468             leftTotalColumnWidth += geometryNode->GetFrameSize().Width();
469         }
470     }
471 }
472 
ColumnPatternInitHapticController()473 void TextPickerPattern::ColumnPatternInitHapticController()
474 {
475     auto host = GetHost();
476     CHECK_NULL_VOID(host);
477     if (host->LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
478         return;
479     }
480     if (!isHapticChanged_) {
481         return;
482     }
483 
484     isHapticChanged_ = false;
485     auto frameNodes = GetColumnNodes();
486     for (auto iter : frameNodes) {
487         auto columnNode = iter.second;
488         if (!columnNode) {
489             continue;
490         }
491         auto columnPattern = columnNode->GetPattern<TextPickerColumnPattern>();
492         if (!columnPattern) {
493             continue;
494         }
495         columnPattern->InitHapticController(columnNode);
496     }
497 }
498 
499 
IsCircle()500 bool TextPickerPattern::IsCircle()
501 {
502     auto host = GetHost();
503     CHECK_NULL_RETURN(host, false);
504     auto context = host->GetContext();
505     CHECK_NULL_RETURN(context, false);
506     auto pickerTheme = context->GetTheme<PickerTheme>();
507     CHECK_NULL_RETURN(pickerTheme, false);
508 
509     return pickerTheme->IsCircleDial();
510 }
511 
ClearFocus()512 void TextPickerPattern::ClearFocus()
513 {
514     if (!IsCircle()) {
515         return;
516     }
517 
518     if (selectedColumnId_ == INVALID_SELECTED_COLUMN_INDEX) {
519         return;
520     }
521     const auto& frameNodes = GetColumnNodes();
522     auto it = frameNodes.find(selectedColumnId_);
523     if (it != frameNodes.end()) {
524         auto textPickerColumnPattern = it->second->GetPattern<TextPickerColumnPattern>();
525         CHECK_NULL_VOID(textPickerColumnPattern);
526         textPickerColumnPattern->SetSelectedMark(false, false);
527     }
528     selectedColumnId_ = INVALID_SELECTED_COLUMN_INDEX;
529 }
530 
SetDefaultFocus()531 void TextPickerPattern::SetDefaultFocus()
532 {
533     if (!IsCircle()) {
534         return;
535     }
536 
537     std::function<void(int32_t& focusId)>  call = [weak = WeakClaim(this)](int32_t& focusId) {
538         auto pattern = weak.Upgrade();
539         CHECK_NULL_VOID(pattern);
540         if (pattern->selectedColumnId_ < 0) {
541             pattern->selectedColumnId_ = focusId;
542             return;
543         }
544 
545         const auto& frameNodes = pattern->GetColumnNodes();
546         auto it = frameNodes.find(pattern->selectedColumnId_);
547         if (it != frameNodes.end()) {
548             auto textPickerColumnPattern = it->second->GetPattern<TextPickerColumnPattern>();
549             CHECK_NULL_VOID(textPickerColumnPattern);
550             textPickerColumnPattern->SetSelectedMark(false, false);
551             pattern->selectedColumnId_ = focusId;
552         }
553     };
554 
555     const auto& frameNodes = GetColumnNodes();
556     int32_t index = 0;
557     for (const auto& it : frameNodes) {
558         CHECK_NULL_VOID(it.second);
559         auto textPickerColumnPattern = it.second->GetPattern<TextPickerColumnPattern>();
560         CHECK_NULL_VOID(textPickerColumnPattern);
561         textPickerColumnPattern->SetSelectedMarkId(index);
562         textPickerColumnPattern->SetSelectedMarkListener(call);
563         if (index == 0) {
564             textPickerColumnPattern->SetSelectedMark(true, false);
565             selectedColumnId_ = 0;
566         }
567         index++;
568     }
569 }
570 
571 #ifdef SUPPORT_DIGITAL_CROWN
InitOnCrownEvent(const RefPtr<FocusHub> & focusHub)572 void TextPickerPattern::InitOnCrownEvent(const RefPtr<FocusHub>& focusHub)
573 {
574     auto onCrowEvent = [wp = WeakClaim(this)](const CrownEvent& event) -> bool {
575         auto pattern = wp.Upgrade();
576         if (pattern) {
577             return pattern->OnCrownEvent(event);
578         }
579         return false;
580     };
581 
582     focusHub->SetOnCrownEventInternal(std::move(onCrowEvent));
583 }
584 
OnCrownEvent(const CrownEvent & event)585 bool TextPickerPattern::OnCrownEvent(const CrownEvent& event)
586 {
587     if (event.action == OHOS::Ace::CrownAction::BEGIN ||
588         event.action == OHOS::Ace::CrownAction::UPDATE ||
589         event.action == OHOS::Ace::CrownAction::END) {
590         auto host = GetHost();
591         CHECK_NULL_RETURN(host, false);
592         auto focusHub = host->GetFocusHub();
593         CHECK_NULL_RETURN(focusHub, false);
594 
595         RefPtr<TextPickerColumnPattern> crownPickerColumnPattern;
596         auto&& children = host->GetChildren();
597         for (const auto& child : children) {
598             auto stackNode = DynamicCast<FrameNode>(child);
599             if (!stackNode) {
600                 continue;
601             }
602             auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
603             if (!blendNode) {
604                 continue;
605             }
606             auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
607             if (!childNode) {
608                 continue;
609             }
610             auto pickerColumnPattern = childNode->GetPattern<TextPickerColumnPattern>();
611             if (!pickerColumnPattern) {
612                 continue;
613             }
614             auto columnID =  pickerColumnPattern->GetSelectedColumnId();
615             if (!pickerColumnPattern->IsCrownEventEnded()) {
616                 crownPickerColumnPattern = pickerColumnPattern;
617                 break;
618             } else if (columnID == selectedColumnId_) {
619                 crownPickerColumnPattern= pickerColumnPattern;
620             }
621         }
622         if (crownPickerColumnPattern != nullptr) {
623             return crownPickerColumnPattern->OnCrownEvent(event);
624         }
625     }
626     return false;
627 }
628 #endif
629 
SetDigitalCrownSensitivity(int32_t crownSensitivity)630 void TextPickerPattern::SetDigitalCrownSensitivity(int32_t crownSensitivity)
631 {
632 #ifdef SUPPORT_DIGITAL_CROWN
633     auto host = GetHost();
634     CHECK_NULL_VOID(host);
635     auto&& children = host->GetChildren();
636     for (const auto& child : children) {
637         auto stackNode = DynamicCast<FrameNode>(child);
638         CHECK_NULL_VOID(stackNode);
639         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
640         CHECK_NULL_VOID(blendNode);
641         auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
642         CHECK_NULL_VOID(childNode);
643         auto pickerColumnPattern = childNode->GetPattern<TextPickerColumnPattern>();
644         CHECK_NULL_VOID(pickerColumnPattern);
645         pickerColumnPattern->SetDigitalCrownSensitivity(crownSensitivity);
646     }
647 #endif
648 }
649 
InitCrownAndKeyEvent()650 void TextPickerPattern::InitCrownAndKeyEvent()
651 {
652     auto host = GetHost();
653     CHECK_NULL_VOID(host);
654     auto focusHub = host->GetFocusHub();
655     CHECK_NULL_VOID(focusHub);
656     InitOnKeyEvent(focusHub);
657 #ifdef SUPPORT_DIGITAL_CROWN
658     InitOnCrownEvent(focusHub);
659 #endif
660 }
661 
SetCallBack()662 void TextPickerPattern::SetCallBack()
663 {
664     if (cascadeOptions_.size() > 0) {
665         SetChangeCallback([weak = WeakClaim(this)](const RefPtr<FrameNode>& tag,
666             bool add, uint32_t index, bool notify) {
667                 auto refPtr = weak.Upgrade();
668                 CHECK_NULL_VOID(refPtr);
669                 refPtr->HandleColumnChange(tag, add, index, notify);
670             });
671     }
672     SetEventCallback([weak = WeakClaim(this)](bool refresh) {
673         auto refPtr = weak.Upgrade();
674         CHECK_NULL_VOID(refPtr);
675         refPtr->FireChangeEvent(refresh);
676     });
677     SetScrollStopEventCallback([weak = WeakClaim(this)](bool refresh) {
678         auto refPtr = weak.Upgrade();
679         CHECK_NULL_VOID(refPtr);
680         refPtr->FireScrollStopEvent(refresh);
681     });
682     SetEnterSelectedAreaEventCallback([weak = WeakClaim(this)](bool refresh) {
683         auto refPtr = weak.Upgrade();
684         CHECK_NULL_VOID(refPtr);
685         refPtr->FireEnterSelectedAreaEvent(refresh);
686     });
687 }
688 
OnModifyDone()689 void TextPickerPattern::OnModifyDone()
690 {
691     Pattern::CheckLocalized();
692     if (isFiredSelectsChange_) {
693         isFiredSelectsChange_ = false;
694         ColumnPatternInitHapticController();
695         return;
696     }
697     isHapticChanged_ = false;
698     auto host = GetHost();
699     CHECK_NULL_VOID(host);
700     auto layoutProperty = host->GetLayoutProperty<LinearLayoutProperty>();
701     CHECK_NULL_VOID(layoutProperty);
702 
703     auto layoutDirection = layoutProperty->GetLayoutDirection();
704     if (layoutDirection != TextDirection::AUTO) {
705         SetLayoutDirection(layoutDirection);
706     }
707     ClearFocus();
708     OnColumnsBuilding();
709     FlushOptions();
710     CalculateHeight();
711     SetCallBack();
712     InitFocusEvent();
713     InitDisabled();
714     InitCrownAndKeyEvent();
715     InitSelectorProps();
716     isNeedUpdateSelectedIndex_ = true;
717     SetDefaultFocus();
718 }
719 
SetEventCallback(EventCallback && value)720 void TextPickerPattern::SetEventCallback(EventCallback&& value)
721 {
722     auto host = GetHost();
723     CHECK_NULL_VOID(host);
724     auto children = host->GetChildren();
725     for (const auto& child : children) {
726         auto stackNode = DynamicCast<FrameNode>(child);
727         CHECK_NULL_VOID(stackNode);
728         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
729         CHECK_NULL_VOID(blendNode);
730         auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
731         CHECK_NULL_VOID(childNode);
732         auto pickerColumnPattern = childNode->GetPattern<TextPickerColumnPattern>();
733         CHECK_NULL_VOID(pickerColumnPattern);
734         pickerColumnPattern->SetEventCallback(std::move(value));
735     }
736 }
737 
FireChangeEvent(bool refresh)738 void TextPickerPattern::FireChangeEvent(bool refresh)
739 {
740     auto frameNodes = GetColumnNodes();
741     std::vector<std::string> value;
742     std::vector<double> index;
743     std::vector<uint32_t> selectedIdx;
744     for (auto it : frameNodes) {
745         CHECK_NULL_VOID(it.second);
746         auto textPickerColumnPattern = it.second->GetPattern<TextPickerColumnPattern>();
747         if (refresh) {
748             auto currentIndex = textPickerColumnPattern->GetCurrentIndex();
749             index.emplace_back(currentIndex);
750             selectedIdx.emplace_back(currentIndex);
751             auto currentValue = textPickerColumnPattern->GetOption(currentIndex);
752             value.emplace_back(currentValue);
753         }
754     }
755     auto textPickerEventHub = GetOrCreateEventHub<TextPickerEventHub>();
756     CHECK_NULL_VOID(textPickerEventHub);
757     textPickerEventHub->FireChangeEvent(value, index);
758     textPickerEventHub->FireDialogChangeEvent(GetSelectedObject(true, 1));
759     std::string idx_str;
760     idx_str.assign(selectedIdx.begin(), selectedIdx.end());
761     firedSelectsStr_ = idx_str;
762 }
763 
SetScrollStopEventCallback(EventCallback && value)764 void TextPickerPattern::SetScrollStopEventCallback(EventCallback&& value)
765 {
766     auto host = GetHost();
767     CHECK_NULL_VOID(host);
768     auto children = host->GetChildren();
769     for (const auto& child : children) {
770         auto stackNode = DynamicCast<FrameNode>(child);
771         CHECK_NULL_VOID(stackNode);
772         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
773         CHECK_NULL_VOID(blendNode);
774         auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
775         CHECK_NULL_VOID(childNode);
776         auto pickerColumnPattern = childNode->GetPattern<TextPickerColumnPattern>();
777         CHECK_NULL_VOID(pickerColumnPattern);
778         pickerColumnPattern->SetScrollStopEventCallback(std::move(value));
779     }
780 }
781 
FireScrollStopEvent(bool refresh)782 void TextPickerPattern::FireScrollStopEvent(bool refresh)
783 {
784     auto frameNodes = GetColumnNodes();
785     std::vector<std::string> value;
786     std::vector<double> index;
787     for (auto it : frameNodes) {
788         CHECK_NULL_VOID(it.second);
789         auto textPickerColumnPattern = it.second->GetPattern<TextPickerColumnPattern>();
790         if (refresh) {
791             auto currentIndex = textPickerColumnPattern->GetCurrentIndex();
792             index.emplace_back(currentIndex);
793             auto currentValue = textPickerColumnPattern->GetOption(currentIndex);
794             value.emplace_back(currentValue);
795         }
796     }
797     auto textPickerEventHub = GetOrCreateEventHub<TextPickerEventHub>();
798     CHECK_NULL_VOID(textPickerEventHub);
799     textPickerEventHub->FireScrollStopEvent(value, index);
800     textPickerEventHub->FireDialogScrollStopEvent(GetSelectedObject(true, 1));
801 }
802 
SetEnterSelectedAreaEventCallback(EventCallback && value)803 void TextPickerPattern::SetEnterSelectedAreaEventCallback(EventCallback&& value)
804 {
805     auto host = GetHost();
806     CHECK_NULL_VOID(host);
807     auto children = host->GetChildren();
808     for (const auto& child : children) {
809         auto stackNode = DynamicCast<FrameNode>(child);
810         CHECK_NULL_VOID(stackNode);
811         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
812         CHECK_NULL_VOID(blendNode);
813         auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
814         CHECK_NULL_VOID(childNode);
815         auto pickerColumnPattern = childNode->GetPattern<TextPickerColumnPattern>();
816         CHECK_NULL_VOID(pickerColumnPattern);
817         pickerColumnPattern->SetEnterSelectedAreaEventCallback(std::move(value));
818     }
819 }
820 
FireEnterSelectedAreaEvent(bool refresh)821 void TextPickerPattern::FireEnterSelectedAreaEvent(bool refresh)
822 {
823     auto frameNodes = GetColumnNodes();
824     std::vector<std::string> value;
825     std::vector<double> index;
826     for (auto it : frameNodes) {
827         CHECK_NULL_VOID(it.second);
828         auto textPickerColumnPattern = it.second->GetPattern<TextPickerColumnPattern>();
829         if (refresh) {
830             auto enterIndex = textPickerColumnPattern->GetEnterIndex();
831             index.emplace_back(enterIndex);
832             auto enterValue = textPickerColumnPattern->GetOption(enterIndex);
833             value.emplace_back(enterValue);
834         }
835     }
836     auto textPickerEventHub = GetOrCreateEventHub<TextPickerEventHub>();
837     CHECK_NULL_VOID(textPickerEventHub);
838     textPickerEventHub->FireEnterSelectedAreaEvent(value, index);
839     textPickerEventHub->FireDialogEnterSelectedAreaEvent(GetSelectedObject(true, 1, true));
840 }
841 
InitDisabled()842 void TextPickerPattern::InitDisabled()
843 {
844     auto host = GetHost();
845     CHECK_NULL_VOID(host);
846     auto eventHub = host->GetOrCreateEventHub<EventHub>();
847     CHECK_NULL_VOID(eventHub);
848     enabled_ = eventHub->IsEnabled();
849     auto renderContext = host->GetRenderContext();
850     CHECK_NULL_VOID(renderContext);
851     auto opacity = curOpacity_;
852     if (!enabled_) {
853         opacity *= DISABLE_ALPHA;
854         renderContext->UpdateOpacity(opacity);
855     } else if (host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
856         renderContext->UpdateOpacity(opacity);
857     }
858 
859     if (host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
860         for (const auto& child : host->GetChildren()) {
861             auto stackNode = DynamicCast<FrameNode>(child);
862             CHECK_NULL_VOID(stackNode);
863             auto renderContext = stackNode->GetRenderContext();
864             CHECK_NULL_VOID(renderContext);
865             renderContext->UpdateOpacity(opacity);
866         }
867     }
868     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
869 }
870 
GetColumnNode()871 RefPtr<FrameNode> TextPickerPattern::GetColumnNode()
872 {
873     auto host = GetHost();
874     CHECK_NULL_RETURN(host, nullptr);
875 
876     auto stackNode = host->GetChildAtIndex(focusKeyID_);
877     CHECK_NULL_RETURN(stackNode, nullptr);
878 
879     auto blendNode = stackNode->GetLastChild();
880     CHECK_NULL_RETURN(blendNode, nullptr);
881 
882     auto columnNode = blendNode->GetLastChild();
883     CHECK_NULL_RETURN(columnNode, nullptr);
884 
885     return DynamicCast<FrameNode>(columnNode);
886 }
887 
GetColumnNodes() const888 std::map<uint32_t, RefPtr<FrameNode>> TextPickerPattern::GetColumnNodes() const
889 {
890     std::map<uint32_t, RefPtr<FrameNode>> allChildNode;
891     auto host = GetHost();
892     CHECK_NULL_RETURN(host, allChildNode);
893     auto children = host->GetChildren();
894     uint32_t index = 0;
895     for (auto iter = children.begin(); iter != children.end(); iter++) {
896         CHECK_NULL_RETURN(*iter, allChildNode);
897         auto stackNode = DynamicCast<FrameNode>(*iter);
898         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
899         CHECK_NULL_RETURN(blendNode, allChildNode);
900         auto currentNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
901         allChildNode[index] = currentNode;
902         index++;
903     }
904     return allChildNode;
905 }
906 
OnColumnsBuildingCascade()907 void TextPickerPattern::OnColumnsBuildingCascade()
908 {
909     auto frameNodes = GetColumnNodes();
910     auto count = frameNodes.size();
911     for (size_t index = 0; index < count; index++) {
912         CHECK_NULL_VOID(frameNodes[index]);
913         auto textPickerColumnPattern = frameNodes[index]->GetPattern<TextPickerColumnPattern>();
914         CHECK_NULL_VOID(textPickerColumnPattern);
915         if (cascadeOptions_.size() > index) {
916             selectedIndex_ = selecteds_.size() <= index || cascadeOptions_[index].rangeResult.empty()
917                                  ? 0 : selecteds_[index] % cascadeOptions_[index].rangeResult.size();
918             textPickerColumnPattern->SetCurrentIndex(
919                 isNeedUpdateSelectedIndex_ ? selectedIndex_ : textPickerColumnPattern->GetCurrentIndex());
920             textPickerColumnPattern->SetEnterIndex(
921                 isNeedUpdateSelectedIndex_ ? selectedIndex_ : textPickerColumnPattern->GetCurrentIndex());
922             textPickerColumnPattern->HandleAccessibilityTextChange();
923             std::vector<NG::RangeContent> rangeContents;
924             for (uint32_t i = 0; i < cascadeOptions_[index].rangeResult.size(); i++) {
925                 NG::RangeContent rangeContent;
926                 rangeContent.text_ = cascadeOptions_[index].rangeResult[i];
927                 rangeContents.emplace_back(rangeContent);
928             }
929             textPickerColumnPattern->SetOptions(rangeContents);
930             textPickerColumnPattern->SetColumnKind(NG::TEXT);
931             optionsWithNode_[frameNodes[index]] = rangeContents;
932             frameNodes[index]->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
933         }
934     }
935 }
936 
OnColumnsBuildingUnCascade()937 void TextPickerPattern::OnColumnsBuildingUnCascade()
938 {
939     auto frameNodes = GetColumnNodes();
940     for (auto it : frameNodes) {
941         CHECK_NULL_VOID(it.second);
942         auto textPickerColumnPattern = it.second->GetPattern<TextPickerColumnPattern>();
943         CHECK_NULL_VOID(textPickerColumnPattern);
944         if (cascadeOptions_.size() > it.first) {
945             selectedIndex_ = selecteds_.size() <= it.first || cascadeOptions_[it.first].rangeResult.empty()
946                                  ? 0 : selecteds_[it.first] % cascadeOptions_[it.first].rangeResult.size();
947             textPickerColumnPattern->SetCurrentIndex(
948                 isNeedUpdateSelectedIndex_ ? selectedIndex_ : textPickerColumnPattern->GetCurrentIndex());
949             textPickerColumnPattern->SetEnterIndex(
950                 isNeedUpdateSelectedIndex_ ? selectedIndex_ : textPickerColumnPattern->GetCurrentIndex());
951             textPickerColumnPattern->HandleAccessibilityTextChange();
952             std::vector<NG::RangeContent> rangeContents;
953             for (uint32_t i = 0; i < cascadeOptions_[it.first].rangeResult.size(); i++) {
954                 NG::RangeContent rangeContent;
955                 rangeContent.text_ = cascadeOptions_[it.first].rangeResult[i];
956                 rangeContents.emplace_back(rangeContent);
957             }
958             textPickerColumnPattern->SetOptions(rangeContents);
959             textPickerColumnPattern->SetColumnKind(NG::TEXT);
960             optionsWithNode_[it.second] = rangeContents;
961             it.second->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
962         } else {
963             ClearOption();
964             for (const auto& item : range_) {
965                 AppendOption(item);
966             }
967             selectedIndex_ = range_.empty() ? 0 : GetSelected() % range_.size();
968             textPickerColumnPattern->SetCurrentIndex(
969                 isNeedUpdateSelectedIndex_ ? selectedIndex_ : textPickerColumnPattern->GetCurrentIndex());
970             textPickerColumnPattern->SetEnterIndex(
971                 isNeedUpdateSelectedIndex_ ? selectedIndex_ : textPickerColumnPattern->GetCurrentIndex());
972             textPickerColumnPattern->HandleAccessibilityTextChange();
973             textPickerColumnPattern->SetOptions(options_);
974             textPickerColumnPattern->SetColumnKind(columnsKind_);
975             it.second->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
976         }
977     }
978 }
979 
OnColumnsBuilding()980 void TextPickerPattern::OnColumnsBuilding()
981 {
982     if (!isCascade_) {
983         OnColumnsBuildingUnCascade();
984     } else {
985         OnColumnsBuildingCascade();
986     }
987 }
988 
SetSelecteds(const std::vector<uint32_t> & values)989 void TextPickerPattern::SetSelecteds(const std::vector<uint32_t>& values)
990 {
991     std::string values_str;
992     values_str.assign(values.begin(), values.end());
993     isFiredSelectsChange_ = firedSelectsStr_.has_value() && firedSelectsStr_.value() == values_str;
994     firedSelectsStr_.reset();
995     selecteds_.clear();
996     for (auto& value : values) {
997         selecteds_.emplace_back(value);
998     }
999     if (isCascade_) {
1000         auto columnCount = cascadeOptions_.size();
1001         cascadeOptions_.clear();
1002         ProcessCascadeOptions(cascadeOriginptions_, cascadeOptions_, 0);
1003         if (cascadeOptions_.size() < columnCount) {
1004             auto differ = columnCount - cascadeOptions_.size();
1005             for (uint32_t i = 0; i < differ; i++) {
1006                 NG::TextCascadePickerOptions differOption;
1007                 memset_s(&differOption, sizeof(differOption), 0, sizeof(differOption));
1008                 cascadeOptions_.emplace_back(differOption);
1009             }
1010         }
1011     }
1012 }
1013 
FlushOptions()1014 void TextPickerPattern::FlushOptions()
1015 {
1016     auto frameNodes = GetColumnNodes();
1017     for (auto it : frameNodes) {
1018         CHECK_NULL_VOID(it.second);
1019         auto columnPattern = it.second->GetPattern<TextPickerColumnPattern>();
1020         CHECK_NULL_VOID(columnPattern);
1021         columnPattern->FlushCurrentOptions();
1022         it.second->MarkModifyDone();
1023         it.second->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1024     }
1025 }
1026 
CalculateHeight()1027 double TextPickerPattern::CalculateHeight()
1028 {
1029     double height = 0.0;
1030     auto host = GetHost();
1031     CHECK_NULL_RETURN(host, height);
1032     auto textPickerLayoutProperty = host->GetLayoutProperty<TextPickerLayoutProperty>();
1033     CHECK_NULL_RETURN(textPickerLayoutProperty, height);
1034     auto context = host->GetContext();
1035     CHECK_NULL_RETURN(context, height);
1036     auto pickerTheme = context->GetTheme<PickerTheme>();
1037     CHECK_NULL_RETURN(pickerTheme, height);
1038     if (textPickerLayoutProperty->HasDefaultPickerItemHeight()) {
1039         auto defaultPickerItemHeightValue = textPickerLayoutProperty->GetDefaultPickerItemHeightValue();
1040         if (LessOrEqual(context->NormalizeToPx(defaultPickerItemHeightValue), 0.0f)) {
1041             height = pickerTheme->GetDividerSpacing().ConvertToPx();
1042             if (!NearEqual(defaultPickerItemHeight_, height)) {
1043                 defaultPickerItemHeight_ = height;
1044                 PaintFocusState();
1045                 SetButtonIdeaSize();
1046             }
1047             return height;
1048         }
1049         if (defaultPickerItemHeightValue.Unit() == DimensionUnit::PERCENT) {
1050             height = pickerTheme->GetGradientHeight().ConvertToPx() * defaultPickerItemHeightValue.Value();
1051         } else {
1052             height = context->NormalizeToPx(defaultPickerItemHeightValue);
1053         }
1054     } else {
1055         height = pickerTheme->GetDividerSpacing().ConvertToPx();
1056     }
1057     if (!NearEqual(defaultPickerItemHeight_, height)) {
1058         defaultPickerItemHeight_ = height;
1059         PaintFocusState();
1060         SetButtonIdeaSize();
1061     }
1062     auto frameNodes = GetColumnNodes();
1063     for (auto it : frameNodes) {
1064         CHECK_NULL_RETURN(it.second, height);
1065         auto textPickerColumnPattern = it.second->GetPattern<TextPickerColumnPattern>();
1066         CHECK_NULL_RETURN(textPickerColumnPattern, height);
1067         textPickerColumnPattern->SetDefaultPickerItemHeight(height);
1068         textPickerColumnPattern->ResetOptionPropertyHeight();
1069         textPickerColumnPattern->NeedResetOptionPropertyHeight(true);
1070     }
1071     return height;
1072 }
1073 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)1074 void TextPickerPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
1075 {
1076     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
1077         auto pattern = wp.Upgrade();
1078         CHECK_NULL_RETURN(pattern, false);
1079         return pattern->OnKeyEvent(event);
1080     };
1081     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
1082 
1083     auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
1084         auto pattern = wp.Upgrade();
1085         if (pattern) {
1086             pattern->GetInnerFocusPaintRect(paintRect);
1087         }
1088     };
1089     focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
1090 }
1091 
PaintFocusState()1092 void TextPickerPattern::PaintFocusState()
1093 {
1094     auto host = GetHost();
1095     CHECK_NULL_VOID(host);
1096 
1097     RoundRect focusRect;
1098     GetInnerFocusPaintRect(focusRect);
1099     auto focusHub = host->GetFocusHub();
1100     CHECK_NULL_VOID(focusHub);
1101     focusHub->PaintInnerFocusState(focusRect);
1102     UpdateFocusButtonState();
1103     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1104 }
1105 
SetFocusCornerRadius(RoundRect & paintRect,const BorderRadiusProperty & radius)1106 void TextPickerPattern::SetFocusCornerRadius(RoundRect& paintRect, const BorderRadiusProperty& radius)
1107 {
1108     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, static_cast<RSScalar>(
1109         radius.radiusTopLeft->ConvertToPx()), static_cast<RSScalar>(radius.radiusTopLeft->ConvertToPx()));
1110     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, static_cast<RSScalar>(
1111         radius.radiusTopRight->ConvertToPx()), static_cast<RSScalar>(radius.radiusTopRight->ConvertToPx()));
1112     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, static_cast<RSScalar>(
1113         radius.radiusBottomLeft->ConvertToPx()), static_cast<RSScalar>(radius.radiusBottomLeft->ConvertToPx()));
1114     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, static_cast<RSScalar>(
1115         radius.radiusBottomRight->ConvertToPx()), static_cast<RSScalar>(radius.radiusBottomRight->ConvertToPx()));
1116 }
1117 
CalculatePaintRect(int32_t currentFocusIndex,float centerX,float centerY,float paintRectWidth,float paintRectHeight,float columnWidth)1118 RectF TextPickerPattern::CalculatePaintRect(int32_t currentFocusIndex, float centerX, float centerY,
1119     float paintRectWidth, float paintRectHeight, float columnWidth)
1120 {
1121     auto columnWidthSum = GetColumnWidthSumForFirstIndexColumns(currentFocusIndex);
1122     if (!GetIsShowInDialog()) {
1123         paintRectWidth = columnWidth - FOCUS_WIDTH.ConvertToPx() - PRESS_RADIUS.ConvertToPx();
1124         centerX = columnWidthSum + (columnWidth - paintRectWidth) / HALF;
1125         AdjustFocusBoxOffset(centerX, centerY);
1126     } else {
1127         paintRectHeight = paintRectHeight - DIALOG_OFFSET.ConvertToPx();
1128         centerY = centerY + DIALOG_OFFSET_LENGTH.ConvertToPx();
1129         paintRectWidth = columnWidth - FOCUS_WIDTH.ConvertToPx() - PRESS_RADIUS.ConvertToPx();
1130         centerX = columnWidthSum + (columnWidth - paintRectWidth) / HALF;
1131     }
1132     return RectF(centerX, centerY, paintRectWidth, paintRectHeight);
1133 }
1134 
AdjustFocusBoxOffset(float & centerX,float & centerY)1135 void TextPickerPattern::AdjustFocusBoxOffset(float& centerX, float& centerY)
1136 {
1137     auto host = GetHost();
1138     CHECK_NULL_VOID(host);
1139     auto geometryNode = host->GetGeometryNode();
1140     CHECK_NULL_VOID(geometryNode);
1141     if (geometryNode->GetPadding()) {
1142         centerX += geometryNode->GetPadding()->left.value_or(0.0);
1143         centerY += geometryNode->GetPadding()->top.value_or(0.0);
1144     }
1145 }
1146 
GetInnerFocusPaintRect(RoundRect & paintRect)1147 void TextPickerPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
1148 {
1149     auto host = GetHost();
1150     CHECK_NULL_VOID(host);
1151     auto context = host->GetContext();
1152     CHECK_NULL_VOID(context);
1153     auto layoutProperty = host->GetLayoutProperty<TextPickerLayoutProperty>();
1154     CHECK_NULL_VOID(layoutProperty);
1155     auto childSize = static_cast<int32_t>(host->GetChildren().size());
1156     if (childSize == 0) {
1157         return;
1158     }
1159     if (useButtonFocusArea_) {
1160         auto leftTotalColumnWidth = 0.0f;
1161         CalcLeftTotalColumnWidth(host, leftTotalColumnWidth, childSize);
1162         return GetInnerFocusButtonPaintRect(paintRect, leftTotalColumnWidth);
1163     }
1164     auto columnNode = GetColumnNode();
1165     CHECK_NULL_VOID(columnNode);
1166     auto pipeline = PipelineBase::GetCurrentContext();
1167     CHECK_NULL_VOID(pipeline);
1168     auto pickerTheme = pipeline->GetTheme<PickerTheme>();
1169     CHECK_NULL_VOID(pickerTheme);
1170     auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
1171     CHECK_NULL_VOID(stackChild);
1172     auto blendChild = DynamicCast<FrameNode>(stackChild->GetLastChild());
1173     CHECK_NULL_VOID(blendChild);
1174     auto pickerChild = DynamicCast<FrameNode>(blendChild->GetLastChild());
1175     CHECK_NULL_VOID(pickerChild);
1176     auto columnWidth = pickerChild->GetGeometryNode()->GetFrameSize().Width();
1177     auto geometryNode = host->GetGeometryNode();
1178     CHECK_NULL_VOID(geometryNode);
1179     auto frameSize = geometryNode->GetPaddingSize();
1180     auto dividerSpacing = pipeline->NormalizeToPx(pickerTheme->GetDividerSpacing());
1181     auto pickerThemeWidth = dividerSpacing * RATE;
1182     auto itemHeight = GreatNotEqual(defaultPickerItemHeight_, 0.0f) ? defaultPickerItemHeight_ : dividerSpacing;
1183     auto centerX = (columnWidth - pickerThemeWidth) / RATE;
1184     auto centerY = (frameSize.Height() - itemHeight) / RATE + FOCUS_INTERVAL.ConvertToPx() + LINE_WIDTH.ConvertToPx();
1185     float paintRectWidth = columnWidth - FOCUS_INTERVAL.ConvertToPx() * RATE - LINE_WIDTH.ConvertToPx() * RATE;
1186     float paintRectHeight = itemHeight - FOCUS_INTERVAL.ConvertToPx() * RATE - LINE_WIDTH.ConvertToPx() * RATE;
1187     if (LessNotEqual(paintRectHeight, 0.0f)) {
1188         paintRectHeight = 0.0f;
1189     }
1190     auto focusPaintRect =
1191         CalculatePaintRect(focusKeyID_, centerX, centerY, paintRectWidth, paintRectHeight, columnWidth);
1192     paintRect.SetRect(focusPaintRect);
1193     if (layoutProperty->HasSelectedBorderRadius()) {
1194         SetFocusCornerRadius(paintRect, layoutProperty->GetSelectedBorderRadiusValue());
1195     } else {
1196         SetFocusCornerRadius(paintRect, NG::BorderRadiusProperty(PRESS_RADIUS));
1197     }
1198 }
1199 
GetColumnWidthSumForFirstIndexColumns(int32_t index)1200 float TextPickerPattern::GetColumnWidthSumForFirstIndexColumns(int32_t index)
1201 {
1202     float columnWidthSum = 0.0f;
1203     auto host = GetHost();
1204     CHECK_NULL_RETURN(host, columnWidthSum);
1205 
1206     bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
1207     int32_t childCount = static_cast<int32_t>(host->GetChildren().size());
1208 
1209     int32_t start = isRtl ? index + 1 : 0;
1210     int32_t end = isRtl ? childCount : index;
1211 
1212     for (int32_t i = start; i < end; ++i) {
1213         auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(i));
1214         CHECK_NULL_RETURN(stackChild, columnWidthSum);
1215         auto blendChild = DynamicCast<FrameNode>(stackChild->GetLastChild());
1216         CHECK_NULL_RETURN(blendChild, columnWidthSum);
1217         auto pickerChild = DynamicCast<FrameNode>(blendChild->GetLastChild());
1218         CHECK_NULL_RETURN(pickerChild, columnWidthSum);
1219         columnWidthSum += pickerChild->GetGeometryNode()->GetFrameSize().Width();
1220     }
1221     return columnWidthSum;
1222 }
1223 
OnKeyEvent(const KeyEvent & event)1224 bool TextPickerPattern::OnKeyEvent(const KeyEvent& event)
1225 {
1226     if (event.action != KeyAction::DOWN) {
1227         return false;
1228     }
1229 
1230     if (event.code == KeyCode::KEY_DPAD_UP || event.code == KeyCode::KEY_DPAD_DOWN ||
1231         event.code == KeyCode::KEY_DPAD_LEFT || event.code == KeyCode::KEY_DPAD_RIGHT ||
1232         event.code == KeyCode::KEY_MOVE_HOME || event.code == KeyCode::KEY_MOVE_END) {
1233         return HandleDirectionKey(event.code);
1234     }
1235     return false;
1236 }
1237 
SetChangeCallback(ColumnChangeCallback && value)1238 void TextPickerPattern::SetChangeCallback(ColumnChangeCallback&& value)
1239 {
1240     auto host = GetHost();
1241     CHECK_NULL_VOID(host);
1242     auto children = host->GetChildren();
1243     for (const auto& child : children) {
1244         auto stackNode = DynamicCast<FrameNode>(child);
1245         CHECK_NULL_VOID(stackNode);
1246         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
1247         CHECK_NULL_VOID(blendNode);
1248         auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
1249         CHECK_NULL_VOID(childNode);
1250         auto textPickerColumnPattern = childNode->GetPattern<TextPickerColumnPattern>();
1251         CHECK_NULL_VOID(textPickerColumnPattern);
1252         textPickerColumnPattern->SetChangeCallback(std::move(value));
1253     }
1254 }
1255 
ProcessCascadeOptionDepth(const NG::TextCascadePickerOptions & option)1256 size_t TextPickerPattern::ProcessCascadeOptionDepth(const NG::TextCascadePickerOptions& option)
1257 {
1258     size_t depth = 1;
1259     if (option.children.empty()) {
1260         return depth;
1261     }
1262 
1263     for (auto& pos : option.children) {
1264         size_t tmpDep = 1;
1265         tmpDep += ProcessCascadeOptionDepth(pos);
1266         if (tmpDep > depth) {
1267             depth = tmpDep;
1268         }
1269     }
1270     return depth;
1271 }
1272 
ChangeCurrentOptionValue(NG::TextCascadePickerOptions & option,uint32_t value,uint32_t curColumn,uint32_t replaceColumn)1273 bool TextPickerPattern::ChangeCurrentOptionValue(NG::TextCascadePickerOptions& option,
1274     uint32_t value, uint32_t curColumn, uint32_t replaceColumn)
1275 {
1276     if (curColumn >= replaceColumn) {
1277         selecteds_[curColumn] = value;
1278         values_[curColumn] = "";
1279     }
1280 
1281     for (uint32_t valueIndex = 0; valueIndex < option.children.size(); valueIndex++) {
1282         if (curColumn >= replaceColumn) {
1283             if (ChangeCurrentOptionValue(option.children[valueIndex], 0, curColumn + 1, replaceColumn)) {
1284                 return true;
1285             }
1286         } else {
1287             if (ChangeCurrentOptionValue(option.children[valueIndex], value, curColumn + 1, replaceColumn)) {
1288                 return true;
1289             }
1290         }
1291     }
1292     return false;
1293 }
1294 
ProcessCascadeOptionsValues(const std::vector<std::string> & rangeResultValue,uint32_t index)1295 void TextPickerPattern::ProcessCascadeOptionsValues(const std::vector<std::string>& rangeResultValue,
1296     uint32_t index)
1297 {
1298     auto valueIterator = std::find(rangeResultValue.begin(), rangeResultValue.end(), values_[index]);
1299     if (valueIterator != rangeResultValue.end()) {
1300         if (index < selecteds_.size()) {
1301             selecteds_[index] = static_cast<uint32_t>(std::distance(rangeResultValue.begin(), valueIterator));
1302         } else {
1303             selecteds_.emplace_back(std::distance(rangeResultValue.begin(), valueIterator));
1304         }
1305     } else {
1306         if (index < selecteds_.size()) {
1307             selecteds_[index] = 0;
1308         } else {
1309             selecteds_.emplace_back(0);
1310         }
1311     }
1312 }
1313 
ProcessCascadeOptions(const std::vector<NG::TextCascadePickerOptions> & options,std::vector<NG::TextCascadePickerOptions> & reOptions,uint32_t index)1314 void TextPickerPattern::ProcessCascadeOptions(const std::vector<NG::TextCascadePickerOptions>& options,
1315     std::vector<NG::TextCascadePickerOptions>& reOptions, uint32_t index)
1316 {
1317     std::vector<std::string> rangeResultValue;
1318     NG::TextCascadePickerOptions option;
1319     for (size_t i = 0; i < options.size(); i++) {
1320         if (!options[i].rangeResult.empty()) {
1321             rangeResultValue.emplace_back(options[i].rangeResult[0]);
1322         }
1323     }
1324     option.rangeResult = rangeResultValue;
1325     for (size_t i = 0; i < options.size(); i++) {
1326         if (index < selecteds_.size() &&
1327             ((selecteds_[index] != 0 && !isHasSelectAttr_) || isHasSelectAttr_)) {
1328             if (selecteds_[index] < 0 && selecteds_[index] > options.size()) {
1329                 selecteds_[index] = 0;
1330             }
1331             option.children = options[selecteds_[index]].children;
1332             reOptions.emplace_back(option);
1333             return ProcessCascadeOptions(options[selecteds_[index]].children, reOptions, index + 1);
1334         }
1335         if (index < values_.size() && values_[index] != "") {
1336             ProcessCascadeOptionsValues(rangeResultValue, index);
1337             option.children = options[selecteds_[index]].children;
1338             reOptions.emplace_back(option);
1339             return ProcessCascadeOptions(options[selecteds_[index]].children, reOptions, index + 1);
1340         }
1341         if (options.size() > 0 && options.size() == i + 1) {
1342             option.children = options[0].children;
1343             reOptions.emplace_back(option);
1344             return ProcessCascadeOptions(options[0].children, reOptions, index + 1);
1345         }
1346     }
1347 }
1348 
SupplementOption(const std::vector<NG::TextCascadePickerOptions> & reOptions,std::vector<NG::RangeContent> & rangeContents,uint32_t patterIndex)1349 void TextPickerPattern::SupplementOption(const std::vector<NG::TextCascadePickerOptions>& reOptions,
1350     std::vector<NG::RangeContent>& rangeContents, uint32_t patterIndex)
1351 {
1352     for (uint32_t i = 0; i < reOptions[patterIndex].rangeResult.size(); i++) {
1353         NG::RangeContent rangeContent;
1354         rangeContent.text_ = reOptions[patterIndex].rangeResult[i];
1355         rangeContents.emplace_back(rangeContent);
1356     }
1357 }
1358 
HandleColumnChange(const RefPtr<FrameNode> & tag,bool isAdd,uint32_t index,bool needNotify)1359 void TextPickerPattern::HandleColumnChange(const RefPtr<FrameNode>& tag, bool isAdd,
1360     uint32_t index, bool needNotify)
1361 {
1362     if (isCascade_) {
1363         auto frameNodes = GetColumnNodes();
1364         uint32_t columnIndex = 0;
1365         for (auto iter = frameNodes.begin(); iter != frameNodes.end(); iter++) {
1366             if (iter->second->GetId() == tag->GetId()) {
1367                 break;
1368             }
1369             columnIndex++;
1370         }
1371         for (uint32_t valueIndex = 0; valueIndex < cascadeOriginptions_.size(); valueIndex++) {
1372             ChangeCurrentOptionValue(cascadeOriginptions_[valueIndex], index, 0, columnIndex);
1373         }
1374 
1375         std::vector<NG::TextCascadePickerOptions> reOptions;
1376         ProcessCascadeOptions(cascadeOriginptions_, reOptions, 0);
1377         // Next Column Update Value
1378         columnIndex = columnIndex + 1;
1379         for (uint32_t patterIndex = columnIndex; patterIndex < frameNodes.size(); patterIndex++) {
1380             auto patternNode = frameNodes[patterIndex];
1381             CHECK_NULL_VOID(patternNode);
1382             auto textPickerColumnPattern = patternNode->GetPattern<TextPickerColumnPattern>();
1383             CHECK_NULL_VOID(textPickerColumnPattern);
1384             if (patterIndex < reOptions.size()) {
1385                 auto currentSelectedIndex = reOptions[patterIndex].rangeResult.empty() ? 0 :
1386                              selecteds_[patterIndex] % reOptions[patterIndex].rangeResult.size();
1387                 std::vector<NG::RangeContent> rangeContents;
1388                 SupplementOption(reOptions, rangeContents, patterIndex);
1389                 textPickerColumnPattern->SetCurrentIndex(currentSelectedIndex);
1390                 textPickerColumnPattern->SetOptions(rangeContents);
1391                 textPickerColumnPattern->HandleAccessibilityTextChange();
1392                 textPickerColumnPattern->FlushCurrentOptions();
1393             } else {
1394                 textPickerColumnPattern->ClearOptions();
1395                 textPickerColumnPattern->SetCurrentIndex(0);
1396                 textPickerColumnPattern->HandleAccessibilityTextChange();
1397                 textPickerColumnPattern->FlushCurrentOptions(false, false, true);
1398             }
1399         }
1400     }
1401 }
1402 
CheckFocusID(int32_t childSize)1403 void TextPickerPattern::CheckFocusID(int32_t childSize)
1404 {
1405     if (focusKeyID_ > childSize - 1) {
1406         focusKeyID_ = childSize - 1;
1407     } else if (focusKeyID_ < 0) {
1408         focusKeyID_ = 0;
1409     }
1410 }
1411 
ParseDirectionKey(RefPtr<TextPickerColumnPattern> & textPickerColumnPattern,KeyCode & code,uint32_t totalOptionCount,int32_t childSize)1412 bool TextPickerPattern::ParseDirectionKey(RefPtr<TextPickerColumnPattern>& textPickerColumnPattern,
1413     KeyCode& code, uint32_t totalOptionCount, int32_t childSize)
1414 {
1415     bool result = true;
1416     bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
1417     switch (code) {
1418         case KeyCode::KEY_DPAD_UP:
1419             textPickerColumnPattern->StopHaptic();
1420             if (textPickerColumnPattern->InnerHandleScroll(false, false)) {
1421                 textPickerColumnPattern->HandleScrollStopEventCallback(true);
1422             }
1423             break;
1424 
1425         case KeyCode::KEY_DPAD_DOWN:
1426             textPickerColumnPattern->StopHaptic();
1427             if (textPickerColumnPattern->InnerHandleScroll(true, false)) {
1428                 textPickerColumnPattern->HandleScrollStopEventCallback(true);
1429             }
1430             break;
1431 
1432         case KeyCode::KEY_MOVE_HOME:
1433             textPickerColumnPattern->SetCurrentIndex(1);
1434             if (textPickerColumnPattern->InnerHandleScroll(false, false)) {
1435                 textPickerColumnPattern->HandleScrollStopEventCallback(true);
1436             }
1437             break;
1438 
1439         case KeyCode::KEY_MOVE_END:
1440             textPickerColumnPattern->SetCurrentIndex(totalOptionCount - INVISIBLE_OPTIONS_COUNT);
1441             if (textPickerColumnPattern->InnerHandleScroll(true, false)) {
1442                 textPickerColumnPattern->HandleScrollStopEventCallback(true);
1443             }
1444             break;
1445 
1446         case KeyCode::KEY_DPAD_LEFT:
1447             focusKeyID_ = isRtl ? (focusKeyID_ + 1) : (focusKeyID_ - 1);
1448             CheckFocusID(childSize);
1449             PaintFocusState();
1450             break;
1451 
1452         case KeyCode::KEY_DPAD_RIGHT:
1453             focusKeyID_ = isRtl ? (focusKeyID_ - 1) : (focusKeyID_ + 1);
1454             CheckFocusID(childSize);
1455             PaintFocusState();
1456             break;
1457 
1458         default:
1459             result = false;
1460             break;
1461     }
1462     return result;
1463 }
1464 
HandleDirectionKey(KeyCode code)1465 bool TextPickerPattern::HandleDirectionKey(KeyCode code)
1466 {
1467     auto host = GetHost();
1468     CHECK_NULL_RETURN(host, false);
1469     auto childSize = host->GetChildren().size();
1470     auto frameNode = GetColumnNode();
1471     CHECK_NULL_RETURN(frameNode, false);
1472     auto textPickerColumnPattern = frameNode->GetPattern<TextPickerColumnPattern>();
1473     CHECK_NULL_RETURN(textPickerColumnPattern, false);
1474     auto totalOptionCount = textPickerColumnPattern->GetOptionCount();
1475     if (totalOptionCount == 0) {
1476         return false;
1477     }
1478     return ParseDirectionKey(textPickerColumnPattern, code, totalOptionCount, static_cast<int32_t>(childSize));
1479 }
1480 
GetSelectedObjectMulti(const std::vector<std::string> & values,const std::vector<uint32_t> & indexs,int32_t status) const1481 std::string TextPickerPattern::GetSelectedObjectMulti(const std::vector<std::string>& values,
1482     const std::vector<uint32_t>& indexs, int32_t status) const
1483 {
1484     std::string result = "";
1485     result = std::string("{\"value\":") + "[";
1486     const size_t valueSize = values.size();
1487     for (uint32_t i = 0; i < valueSize; i++) {
1488         result += "\"" + values[i];
1489         if (valueSize > 0 && i != valueSize - 1) {
1490             result += "\",";
1491         } else {
1492             result += "\"]";
1493         }
1494     }
1495     result += std::string(",\"index\":") + "[";
1496     const size_t indexSize = indexs.size();
1497     for (uint32_t i = 0; i < indexSize; i++) {
1498         result += std::to_string(indexs[i]);
1499         if (indexSize > 0 && indexSize != i + 1) {
1500             result += ",";
1501         } else {
1502             result += "]";
1503         }
1504     }
1505     result += ",\"status\":" + std::to_string(status) + "}";
1506     return result;
1507 }
1508 
GetSelectedObject(bool isColumnChange,int32_t status,bool isEnterSelectedAreaEvent) const1509 std::string TextPickerPattern::GetSelectedObject(
1510     bool isColumnChange, int32_t status, bool isEnterSelectedAreaEvent) const
1511 {
1512     std::vector<std::string> values;
1513     std::vector<uint32_t> indexs;
1514     auto host = GetHost();
1515     CHECK_NULL_RETURN(host, "");
1516     auto children = host->GetChildren();
1517     for (const auto& child : children) {
1518         CHECK_NULL_RETURN(child, "");
1519         auto stackNode = DynamicCast<FrameNode>(child);
1520         CHECK_NULL_RETURN(stackNode, "");
1521         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
1522         CHECK_NULL_RETURN(blendNode, "");
1523         auto currentNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
1524         CHECK_NULL_RETURN(currentNode, "");
1525         auto textPickerColumnPattern = currentNode->GetPattern<TextPickerColumnPattern>();
1526         CHECK_NULL_RETURN(textPickerColumnPattern, "");
1527         auto value = textPickerColumnPattern->GetOption(textPickerColumnPattern->GetSelected());
1528         auto index = textPickerColumnPattern->GetSelected();
1529         if (isColumnChange) {
1530             value = textPickerColumnPattern->GetCurrentText();
1531             index = textPickerColumnPattern->GetCurrentIndex();
1532         }
1533         if (isEnterSelectedAreaEvent) {
1534             value = textPickerColumnPattern->GetEnterText();
1535             index = textPickerColumnPattern->GetEnterIndex();
1536         }
1537         values.emplace_back(value);
1538         indexs.emplace_back(index);
1539     }
1540 
1541     auto context = host->GetContext();
1542     CHECK_NULL_RETURN(context, "");
1543     if (context->GetIsDeclarative()) {
1544         if (values.size() == 1) {
1545             return std::string("{\"value\":") + "\"" + values[0] + "\"" + ",\"index\":" + std::to_string(indexs[0]) +
1546                    ",\"status\":" + std::to_string(status) + "}";
1547         } else {
1548             return GetSelectedObjectMulti(values, indexs, status);
1549         }
1550     } else {
1551         return std::string("{\"newValue\":") + "\"" +
1552                 values[0] + "\"" + ",\"newSelected\":" + std::to_string(indexs[0]) +
1553                ",\"status\":" + std::to_string(status) + "}";
1554     }
1555 }
1556 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const1557 void TextPickerPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
1558 {
1559     /* no fixed attr below, just return */
1560     if (filter.IsFastFilter()) {
1561         return;
1562     }
1563     if (!range_.empty()) {
1564         json->PutExtAttr("range", GetRangeStr().c_str(), filter);
1565     } else {
1566         if (!cascadeOriginptions_.empty()) {
1567             if (!isCascade_) {
1568                 json->PutExtAttr("range", GetOptionsMultiStr().c_str(), filter);
1569             } else {
1570                 json->PutExtAttr("range", GetOptionsCascadeStr(cascadeOriginptions_).c_str(), filter);
1571             }
1572         }
1573     }
1574     json->PutExtAttr("enableHapticFeedback", isEnableHaptic_, filter);
1575     json->PutExtAttr("columnWidths", GetColumnWidthsStr().c_str(), filter);
1576 }
1577 
GetRangeStr() const1578 std::string TextPickerPattern::GetRangeStr() const
1579 {
1580     if (!range_.empty()) {
1581         std::string result = "[";
1582         for (const auto& item : range_) {
1583             result += "\"";
1584             result += "icon:";
1585             result += item.icon_;
1586             result += ",";
1587             result += "text:";
1588             result += item.text_;
1589             result += "\"";
1590             result += ",";
1591         }
1592         result.pop_back();
1593         result += "]";
1594         return result;
1595     }
1596     return "";
1597 }
1598 
GetOptionsCascadeStr(const std::vector<NG::TextCascadePickerOptions> & options) const1599 std::string TextPickerPattern::GetOptionsCascadeStr(
1600     const std::vector<NG::TextCascadePickerOptions>& options) const
1601 {
1602     std::string result = "[";
1603     for (uint32_t i = 0; i < options.size(); i++) {
1604         result += std::string("{\"text\":\"");
1605         result += options[i].rangeResult[0];
1606         result += "\"";
1607         if (options[i].children.size() > 0) {
1608             result += std::string(", \"children\":");
1609             result += GetOptionsCascadeStr(options[i].children);
1610         }
1611         if (options.size() > 0 && options.size() != i + 1) {
1612             result += "},";
1613         } else {
1614             result += "}]";
1615         }
1616     }
1617     return result;
1618 }
1619 
GetOptionsMultiStrInternal() const1620 std::string TextPickerPattern::GetOptionsMultiStrInternal() const
1621 {
1622     std::string result = "[";
1623     const size_t size = cascadeOptions_.size();
1624     for (uint32_t i = 0; i < size; i++) {
1625         result += "[";
1626         for (uint32_t j = 0; j < cascadeOptions_[i].rangeResult.size(); j++) {
1627             result += "\"" + cascadeOptions_[i].rangeResult[j];
1628             if (j + 1 != cascadeOptions_[i].rangeResult.size()) {
1629                 result += "\",";
1630             } else {
1631                 result += "\"]";
1632             }
1633         }
1634         if (size > 0 && i != size - 1) {
1635             result += ",";
1636         } else {
1637             result += "]";
1638         }
1639     }
1640     return result;
1641 }
1642 
GetOptionsMultiStr() const1643 std::string TextPickerPattern::GetOptionsMultiStr() const
1644 {
1645     std::string result = "";
1646     if (!cascadeOptions_.empty()) {
1647         result = GetOptionsMultiStrInternal();
1648     }
1649     return result;
1650 }
1651 
GetColumnWidthsStr() const1652 std::string TextPickerPattern::GetColumnWidthsStr() const
1653 {
1654     std::ostringstream oss;
1655     auto allChildNode = GetColumnNodes();
1656     for (const auto& child : allChildNode) {
1657         const auto& columnNode = child.second;
1658         CHECK_NULL_RETURN(columnNode, "");
1659         auto columnWidth = columnNode->GetGeometryNode()->GetFrameSize().Width();
1660         oss << std::fixed << std::setprecision(PRECISION_TWO) << columnWidth << "px,";
1661     }
1662     std::string result = oss.str();
1663     if (!result.empty()) {
1664         result.pop_back();
1665     }
1666     return result;
1667 }
1668 
OnColorConfigurationUpdate()1669 void TextPickerPattern::OnColorConfigurationUpdate()
1670 {
1671     auto host = GetHost();
1672     CHECK_NULL_VOID(host);
1673     auto context = host->GetContext();
1674     CHECK_NULL_VOID(context);
1675     auto pickerTheme = context->GetTheme<PickerTheme>(host->GetThemeScopeId());
1676     CHECK_NULL_VOID(pickerTheme);
1677     auto disappearStyle = pickerTheme->GetDisappearOptionStyle();
1678     auto normalStyle = pickerTheme->GetOptionStyle(false, false);
1679     auto selectedStyle = pickerTheme->GetOptionStyle(true, false);
1680     auto pickerProperty = host->GetLayoutProperty<TextPickerLayoutProperty>();
1681     CHECK_NULL_VOID(pickerProperty);
1682     if (!pickerProperty->GetNormalTextColorSetByUser().value_or(false)) {
1683         pickerProperty->UpdateColor(
1684             GetTextProperties().normalTextStyle_.textColor.value_or(normalStyle.GetTextColor()));
1685     }
1686 
1687     if (!pickerProperty->GetDisappearTextColorSetByUser().value_or(false)) {
1688         pickerProperty->UpdateDisappearColor(
1689             GetTextProperties().disappearTextStyle_.textColor.value_or(disappearStyle.GetTextColor()));
1690     }
1691 
1692     if (!pickerProperty->GetSelectedTextColorSetByUser().value_or(false)) {
1693         pickerProperty->UpdateSelectedColor(
1694             GetTextProperties().selectedTextStyle_.textColor.value_or(selectedStyle.GetTextColor()));
1695     }
1696 
1697     if (pickerProperty->GetDisableTextStyleAnimation().value_or(false) &&
1698         !pickerProperty->GetDefaultTextColorSetByUser().value_or(false)) {
1699         auto textTheme = context->GetTheme<TextTheme>(host->GetThemeScopeId());
1700         CHECK_NULL_VOID(textTheme);
1701         pickerProperty->UpdateDefaultColor(
1702             GetTextProperties().defaultTextStyle_.textColor.value_or(textTheme->GetTextStyle().GetTextColor()));
1703     }
1704     if (isPicker_) {
1705         return;
1706     }
1707     auto dialogTheme = context->GetTheme<DialogTheme>();
1708     CHECK_NULL_VOID(dialogTheme);
1709     SetBackgroundColor(dialogTheme->GetBackgroundColor());
1710     auto contentRowNode = contentRowNode_.Upgrade();
1711     if (contentRowNode) {
1712         auto layoutRenderContext = contentRowNode->GetRenderContext();
1713         CHECK_NULL_VOID(layoutRenderContext);
1714         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN) ||
1715             !layoutRenderContext->IsUniRenderEnabled()) {
1716             layoutRenderContext->UpdateBackgroundColor(dialogTheme->GetButtonBackgroundColor());
1717         }
1718     }
1719     auto frameNode = DynamicCast<FrameNode>(host);
1720     CHECK_NULL_VOID(frameNode);
1721     FrameNode::ProcessOffscreenNode(frameNode);
1722     host->MarkModifyDone();
1723 }
1724 
OnThemeScopeUpdate(int32_t themeScopeId)1725 bool TextPickerPattern::OnThemeScopeUpdate(int32_t themeScopeId)
1726 {
1727     bool result = false;
1728     auto host = GetHost();
1729     CHECK_NULL_RETURN(host, result);
1730     host->SetNeedCallChildrenUpdate(false);
1731     auto context = host->GetContext();
1732     CHECK_NULL_RETURN(context, result);
1733     auto pickerProperty = host->GetLayoutProperty<TextPickerLayoutProperty>();
1734     CHECK_NULL_RETURN(pickerProperty, result);
1735     // The following three attributes will be affected by withTheme.
1736     // If they are setted by user, then use the value by user set; Otherwise use the value from withTheme
1737     // When the "result" is true, mean to notify the framework to Re-render
1738     if ((!pickerProperty->HasColor()) || (!pickerProperty->HasDisappearColor()) ||
1739         (!pickerProperty->HasSelectedColor())) {
1740         result = true;
1741     }
1742     OnModifyDone();
1743     return result;
1744 }
1745 
OnDirectionConfigurationUpdate()1746 void TextPickerPattern::OnDirectionConfigurationUpdate()
1747 {
1748     isNeedUpdateSelectedIndex_ = false;
1749 }
1750 
CheckAndUpdateColumnSize(SizeF & size,RefPtr<FrameNode> & frameNode,bool isNeedAdaptForAging)1751 void TextPickerPattern::CheckAndUpdateColumnSize(SizeF& size, RefPtr<FrameNode>& frameNode, bool isNeedAdaptForAging)
1752 {
1753     auto host = GetHost();
1754     CHECK_NULL_VOID(host);
1755     auto pickerNode = DynamicCast<FrameNode>(host);
1756     CHECK_NULL_VOID(pickerNode);
1757     auto stackNode = DynamicCast<FrameNode>(pickerNode->GetFirstChild());
1758     CHECK_NULL_VOID(stackNode);
1759 
1760     auto pickerLayoutProperty = pickerNode->GetLayoutProperty();
1761     CHECK_NULL_VOID(pickerLayoutProperty);
1762     auto pickerLayoutConstraint = pickerLayoutProperty->GetLayoutConstraint();
1763 
1764     auto stackLayoutProperty = stackNode->GetLayoutProperty();
1765     CHECK_NULL_VOID(stackLayoutProperty);
1766     auto stackLayoutConstraint = stackLayoutProperty->GetLayoutConstraint();
1767 
1768     auto childCount = static_cast<float>(pickerNode->GetChildren().size());
1769     auto pickerContentSize = SizeF(size.Width() * childCount, size.Height());
1770     auto parentIdealSize = stackLayoutConstraint->parentIdealSize;
1771     if (parentIdealSize.Width().has_value()) {
1772         pickerContentSize.SetWidth(parentIdealSize.Width().value());
1773     }
1774     if (parentIdealSize.Height().has_value()) {
1775         pickerContentSize.SetHeight(parentIdealSize.Height().value());
1776     }
1777 
1778     PaddingPropertyF padding = pickerLayoutProperty->CreatePaddingAndBorder();
1779     auto minSize = SizeF(pickerLayoutConstraint->minSize.Width(), pickerLayoutConstraint->minSize.Height());
1780     MinusPaddingToSize(padding, minSize);
1781     auto context = GetContext();
1782     CHECK_NULL_VOID(context);
1783     auto version10OrLarger = context->GetMinPlatformVersion() > 9;
1784     if (!(minSize.Width() == 0 && minSize.Height() == 0 &&
1785         stackLayoutConstraint->maxSize.Width() == 0 && stackLayoutConstraint->maxSize.Height() == 0)) {
1786             pickerContentSize.Constrain(minSize, stackLayoutConstraint->maxSize, version10OrLarger);
1787     }
1788 
1789     if (isNeedAdaptForAging && GetIsShowInDialog()) {
1790         size.SetWidth(pickerContentSize.Width());
1791     } else {
1792         auto index = CalculateIndex(frameNode);
1793         if (index < 0 || index >= static_cast<int32_t>(childCount)) {
1794             return;
1795         }
1796         float width = CalculateColumnSize(index, childCount, pickerContentSize);
1797         size.SetWidth(width);
1798     }
1799     size.SetHeight(std::min(pickerContentSize.Height(), size.Height()));
1800 }
1801 
CalculateIndex(RefPtr<FrameNode> & frameNode)1802 int32_t TextPickerPattern::CalculateIndex(RefPtr<FrameNode>& frameNode)
1803 {
1804     auto allChildNode = GetColumnNodes();
1805     int32_t index = -1;
1806     for (const auto& child : allChildNode) {
1807         if (child.second == frameNode) {
1808             index = child.first;
1809             break;
1810         }
1811     }
1812     return index;
1813 }
1814 
CalculateColumnSize(int32_t index,float childCount,const SizeF & pickerContentSize)1815 float TextPickerPattern::CalculateColumnSize(int32_t index, float childCount, const SizeF& pickerContentSize)
1816 {
1817     float widthSum = 0.0f;
1818     if (columnWidths_.empty()) {
1819         return pickerContentSize.Width() / std::max(childCount, 1.0f);
1820     }
1821     auto columnWidth = columnWidths_;
1822     for (size_t i = 0; i < std::min(columnWidth.size(), static_cast<size_t>(childCount)); i++) {
1823         columnWidth[i] = columnWidth[i].Unit() != DimensionUnit::PERCENT ?
1824             Dimension(columnWidth[i].ConvertToPx(), DimensionUnit::PX) :
1825             Dimension(pickerContentSize.Width() * columnWidth[i].Value() / MAX_PERCENT, DimensionUnit::PX);
1826 
1827         if (LessNotEqual(columnWidth[i].Value(), 0.0f) && !NearZero(childCount)) {
1828             columnWidth[i].SetValue(pickerContentSize.Width() / childCount);
1829         }
1830 
1831         widthSum += columnWidth[i].Value();
1832     }
1833 
1834     if (GreatNotEqual(widthSum, pickerContentSize.Width())) {
1835         return pickerContentSize.Width() / std::max(childCount, 1.0f);
1836     }
1837 
1838     if (static_cast<size_t>(index) < columnWidth.size()) {
1839         return columnWidth[index].Value();
1840     } else if (!NearZero(childCount - columnWidth.size())) {
1841         return (pickerContentSize.Width() - widthSum) / (childCount - columnWidth.size());
1842     } else {
1843         return 0.0f;
1844     }
1845 }
1846 
SetCanLoop(bool isLoop)1847 void TextPickerPattern::SetCanLoop(bool isLoop)
1848 {
1849     auto host = GetHost();
1850     CHECK_NULL_VOID(host);
1851     auto children = host->GetChildren();
1852     canloop_ = isLoop;
1853     for (const auto& child : children) {
1854         auto stackNode = DynamicCast<FrameNode>(child);
1855         CHECK_NULL_VOID(stackNode);
1856         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
1857         CHECK_NULL_VOID(blendNode);
1858         auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
1859         CHECK_NULL_VOID(childNode);
1860         auto pickerColumnPattern = childNode->GetPattern<TextPickerColumnPattern>();
1861         CHECK_NULL_VOID(pickerColumnPattern);
1862         pickerColumnPattern->SetCanLoop(isLoop);
1863     }
1864 }
1865 
NeedAdaptForAging()1866 bool TextPickerPattern::NeedAdaptForAging()
1867 {
1868     auto host = GetHost();
1869     CHECK_NULL_RETURN(host, false);
1870     auto pipeline = host->GetContext();
1871     CHECK_NULL_RETURN(pipeline, false);
1872     auto pickerTheme = pipeline->GetTheme<PickerTheme>();
1873     CHECK_NULL_RETURN(pickerTheme, false);
1874 
1875     if (GreatOrEqual(pipeline->GetFontScale(), pickerTheme->GetMaxOneFontScale())) {
1876         return true;
1877     }
1878     return false;
1879 }
1880 
SetDisableTextStyleAnimation(bool isDisableTextStyleAnimation)1881 void TextPickerPattern::SetDisableTextStyleAnimation(bool isDisableTextStyleAnimation)
1882 {
1883     isDisableTextStyleAnimation_ = isDisableTextStyleAnimation;
1884 
1885     auto host = GetHost();
1886     CHECK_NULL_VOID(host);
1887     auto children = host->GetChildren();
1888     for (const auto& child : children) {
1889         auto stackNode = DynamicCast<FrameNode>(child);
1890         CHECK_NULL_VOID(stackNode);
1891         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
1892         CHECK_NULL_VOID(blendNode);
1893         auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
1894         CHECK_NULL_VOID(childNode);
1895         auto pickerColumnPattern = childNode->GetPattern<TextPickerColumnPattern>();
1896         CHECK_NULL_VOID(pickerColumnPattern);
1897         pickerColumnPattern->SetDisableTextStyleAnimation(isDisableTextStyleAnimation);
1898     }
1899 }
1900 
UpdateUserSetSelectColor()1901 void TextPickerPattern::UpdateUserSetSelectColor()
1902 {
1903     CHECK_EQUAL_VOID(IsCircle(), false);
1904     auto host = GetHost();
1905     CHECK_NULL_VOID(host);
1906     auto children = host->GetChildren();
1907     for (const auto& child : children) {
1908         auto stackNode = DynamicCast<FrameNode>(child);
1909         CHECK_NULL_VOID(stackNode);
1910         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
1911         CHECK_NULL_VOID(blendNode);
1912         auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
1913         CHECK_NULL_VOID(childNode);
1914         auto pickerColumnPattern = childNode->GetPattern<TextPickerColumnPattern>();
1915         CHECK_NULL_VOID(pickerColumnPattern);
1916         pickerColumnPattern->UpdateUserSetSelectColor();
1917     }
1918 }
1919 
GetTextPickerRange() const1920 std::string TextPickerPattern::GetTextPickerRange() const
1921 {
1922     std::string result;
1923     if (isSingleRange_) {
1924         for (auto range : range_) {
1925             result.append(range.text_ + ";");
1926         }
1927         if (result.length() > 0) {
1928             result = result.substr(0, result.length() > 0 ? result.length() - 1 : 0);
1929         }
1930     } else {
1931         for (auto option : cascadeOriginptions_) {
1932             for (auto range : option.rangeResult) {
1933                 result.append(range + ",");
1934             }
1935             result = result.substr(0, result.length() > 0 ? result.length() - 1 : 0);
1936             result.append(";");
1937         }
1938         if (result.length() > 0) {
1939             result = result.substr(0, result.length() - 1);
1940         }
1941     }
1942     return result;
1943 }
1944 
ConvertFontScaleValue(const Dimension & fontSizeValue)1945 Dimension TextPickerPattern::ConvertFontScaleValue(const Dimension& fontSizeValue)
1946 {
1947     auto host = GetHost();
1948     CHECK_NULL_RETURN(host, fontSizeValue);
1949     auto pipeline = host->GetContext();
1950     CHECK_NULL_RETURN(pipeline, fontSizeValue);
1951 
1952     auto maxAppFontScale = pipeline->GetMaxAppFontScale();
1953     auto follow = pipeline->IsFollowSystem();
1954     float fontScale = pipeline->GetFontScale();
1955     if (NearZero(fontScale) || (fontSizeValue.Unit() == DimensionUnit::VP)) {
1956         return fontSizeValue;
1957     }
1958     if (GreatOrEqualCustomPrecision(fontScale, PICKER_MAXFONTSCALE) && follow) {
1959         fontScale = std::clamp(fontScale, 0.0f, maxAppFontScale);
1960         if (!NearZero(fontScale)) {
1961             return Dimension(fontSizeValue / fontScale);
1962         }
1963     }
1964     return fontSizeValue;
1965 }
1966 
UpdateTextStyleCommon(const PickerTextStyle & textStyle,const TextStyle & defaultTextStyle,std::function<void (const Color &)> updateTextColorFunc,std::function<void (const Dimension &)> updateFontSizeFunc,std::function<void (const std::vector<std::string> &)> updateFontFamilyFunc,std::function<void (const Dimension &)> updateMinFontSizeFunc,std::function<void (const Dimension &)> updateMaxFontSizeFunc)1967 void TextPickerPattern::UpdateTextStyleCommon(
1968     const PickerTextStyle& textStyle,
1969     const TextStyle& defaultTextStyle,
1970     std::function<void(const Color&)> updateTextColorFunc,
1971     std::function<void(const Dimension&)> updateFontSizeFunc,
1972     std::function<void(const std::vector<std::string>&)> updateFontFamilyFunc,
1973     std::function<void(const Dimension&)> updateMinFontSizeFunc,
1974     std::function<void(const Dimension&)> updateMaxFontSizeFunc
1975 )
1976 {
1977     auto host = GetHost();
1978     CHECK_NULL_VOID(host);
1979     auto pickerProperty = GetLayoutProperty<TextPickerLayoutProperty>();
1980     CHECK_NULL_VOID(pickerProperty);
1981 
1982     auto pipelineContext = host->GetContext();
1983     CHECK_NULL_VOID(pipelineContext);
1984 
1985     if (pipelineContext->IsSystmColorChange()) {
1986         updateTextColorFunc(textStyle.textColor.value_or(defaultTextStyle.GetTextColor()));
1987 
1988         Dimension fontSize = defaultTextStyle.GetFontSize();
1989         if (textStyle.fontSize.has_value() && textStyle.fontSize->IsValid()) {
1990             fontSize = textStyle.fontSize.value();
1991         }
1992         updateFontSizeFunc(ConvertFontScaleValue(fontSize));
1993 
1994         updateFontFamilyFunc(textStyle.fontFamily.value_or(defaultTextStyle.GetFontFamilies()));
1995 
1996         Dimension minFontSize = Dimension();
1997         if (textStyle.minFontSize.has_value() && textStyle.minFontSize->IsValid()) {
1998             minFontSize = ConvertFontScaleValue(textStyle.minFontSize.value());
1999         }
2000         updateMinFontSizeFunc(minFontSize);
2001 
2002         Dimension maxFontSize = Dimension();
2003         if (textStyle.maxFontSize.has_value() && textStyle.maxFontSize->IsValid()) {
2004             maxFontSize = ConvertFontScaleValue(textStyle.maxFontSize.value());
2005         }
2006         updateMaxFontSizeFunc(maxFontSize);
2007     }
2008 
2009     if (host->GetRerenderable()) {
2010         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2011     }
2012 }
2013 
UpdateDisappearTextStyle(const PickerTextStyle & textStyle)2014 void TextPickerPattern::UpdateDisappearTextStyle(const PickerTextStyle& textStyle)
2015 {
2016     auto host = GetHost();
2017     CHECK_NULL_VOID(host);
2018     auto context = host->GetContext();
2019     CHECK_NULL_VOID(context);
2020     auto pickerTheme = context->GetTheme<PickerTheme>(host->GetThemeScopeId());
2021     CHECK_NULL_VOID(pickerTheme);
2022     auto defaultTextStyle = pickerTheme->GetDisappearOptionStyle();
2023     auto pickerProperty = GetLayoutProperty<TextPickerLayoutProperty>();
2024     CHECK_NULL_VOID(pickerProperty);
2025 
2026     if (pickerProperty->GetDisappearColor().has_value()) {
2027         defaultTextStyle.SetTextColor(pickerProperty->GetDisappearColor().value());
2028     }
2029 
2030     UpdateTextStyleCommon(
2031         textStyle,
2032         defaultTextStyle,
2033         [&](const Color& color) { pickerProperty->UpdateDisappearColor(color); },
2034         [&](const Dimension& fontSize) { pickerProperty->UpdateDisappearFontSize(fontSize); },
2035         [&](const std::vector<std::string>& fontFamily) { pickerProperty->UpdateDisappearFontFamily(fontFamily); },
2036         [&](const Dimension& minFontSize) { pickerProperty->UpdateDisappearMinFontSize(minFontSize); },
2037         [&](const Dimension& maxFontSize) { pickerProperty->UpdateDisappearMaxFontSize(maxFontSize); }
2038     );
2039 }
2040 
UpdateNormalTextStyle(const PickerTextStyle & textStyle)2041 void TextPickerPattern::UpdateNormalTextStyle(const PickerTextStyle& textStyle)
2042 {
2043     auto host = GetHost();
2044     CHECK_NULL_VOID(host);
2045     auto context = host->GetContext();
2046     CHECK_NULL_VOID(context);
2047     auto pickerTheme = context->GetTheme<PickerTheme>(host->GetThemeScopeId());
2048     CHECK_NULL_VOID(pickerTheme);
2049     auto defaultTextStyle = pickerTheme->GetOptionStyle(false, false);
2050     auto pickerProperty = GetLayoutProperty<TextPickerLayoutProperty>();
2051     CHECK_NULL_VOID(pickerProperty);
2052 
2053     if (pickerProperty->GetColor().has_value()) {
2054         defaultTextStyle.SetTextColor(pickerProperty->GetColor().value());
2055     }
2056 
2057     UpdateTextStyleCommon(
2058         textStyle,
2059         defaultTextStyle,
2060         [&](const Color& color) { pickerProperty->UpdateColor(color); },
2061         [&](const Dimension& fontSize) { pickerProperty->UpdateFontSize(fontSize); },
2062         [&](const std::vector<std::string>& fontFamily) { pickerProperty->UpdateFontFamily(fontFamily); },
2063         [&](const Dimension& minFontSize) { pickerProperty->UpdateMinFontSize(minFontSize); },
2064         [&](const Dimension& maxFontSize) { pickerProperty->UpdateMaxFontSize(maxFontSize); }
2065     );
2066 }
2067 
UpdateSelectedTextStyle(const PickerTextStyle & textStyle)2068 void TextPickerPattern::UpdateSelectedTextStyle(const PickerTextStyle& textStyle)
2069 {
2070     auto host = GetHost();
2071     CHECK_NULL_VOID(host);
2072     auto context = host->GetContext();
2073     CHECK_NULL_VOID(context);
2074     auto pickerTheme = context->GetTheme<PickerTheme>(host->GetThemeScopeId());
2075     CHECK_NULL_VOID(pickerTheme);
2076     auto defaultTextStyle = pickerTheme->GetOptionStyle(true, false);
2077     auto pickerProperty = GetLayoutProperty<TextPickerLayoutProperty>();
2078     CHECK_NULL_VOID(pickerProperty);
2079 
2080     if (pickerProperty->GetSelectedColor().has_value()) {
2081         defaultTextStyle.SetTextColor(pickerProperty->GetSelectedColor().value());
2082     }
2083 
2084     UpdateTextStyleCommon(
2085         textStyle,
2086         defaultTextStyle,
2087         [&](const Color& color) { pickerProperty->UpdateSelectedColor(color); },
2088         [&](const Dimension& fontSize) { pickerProperty->UpdateSelectedFontSize(fontSize); },
2089         [&](const std::vector<std::string>& fontFamily) { pickerProperty->UpdateSelectedFontFamily(fontFamily); },
2090         [&](const Dimension& minFontSize) { pickerProperty->UpdateSelectedMinFontSize(minFontSize); },
2091         [&](const Dimension& maxFontSize) { pickerProperty->UpdateSelectedMaxFontSize(maxFontSize); }
2092     );
2093 }
2094 
UpdateDefaultTextStyle(const PickerTextStyle & textStyle)2095 void TextPickerPattern::UpdateDefaultTextStyle(const PickerTextStyle& textStyle)
2096 {
2097     auto host = GetHost();
2098     CHECK_NULL_VOID(host);
2099     auto pipelineContext = host->GetContext();
2100     CHECK_NULL_VOID(pipelineContext);
2101     auto textTheme = pipelineContext->GetTheme<TextTheme>(host->GetThemeScopeId());
2102     CHECK_NULL_VOID(textTheme);
2103     auto defaultTextStyle = textTheme->GetTextStyle();
2104     auto pickerProperty = GetLayoutProperty<TextPickerLayoutProperty>();
2105     CHECK_NULL_VOID(pickerProperty);
2106 
2107     if (pickerProperty->GetDefaultColor().has_value()) {
2108         defaultTextStyle.SetTextColor(pickerProperty->GetDefaultColor().value());
2109     }
2110 
2111     UpdateTextStyleCommon(
2112         textStyle,
2113         defaultTextStyle,
2114         [&](const Color& color) { pickerProperty->UpdateDefaultColor(color); },
2115         [&](const Dimension& fontSize) { pickerProperty->UpdateDefaultFontSize(fontSize); },
2116         [&](const std::vector<std::string>& fontFamily) { pickerProperty->UpdateDefaultFontFamily(fontFamily); },
2117         [&](const Dimension& minFontSize) { pickerProperty->UpdateDefaultMinFontSize(minFontSize); },
2118         [&](const Dimension& maxFontSize) { pickerProperty->UpdateDefaultMaxFontSize(maxFontSize); }
2119     );
2120 }
2121 
ParseRangeResult(NG::TextCascadePickerOptions & option)2122 void TextPickerPattern::ParseRangeResult(NG::TextCascadePickerOptions& option)
2123 {
2124     std::string textStr = "";
2125 
2126     if (option.rangeResultResObj && ResourceParseUtils::ParseResString(option.rangeResultResObj, textStr)) {
2127         std::vector<std::string> rangeResultValue;
2128         rangeResultValue.emplace_back(textStr);
2129         option.rangeResult = rangeResultValue;
2130     }
2131 
2132     for (auto& child : option.children) {
2133         ParseRangeResult(child);
2134     }
2135 }
2136 
ParseCascadeRangeOptions(std::vector<NG::TextCascadePickerOptions> & options)2137 void TextPickerPattern::ParseCascadeRangeOptions(std::vector<NG::TextCascadePickerOptions>& options)
2138 {
2139     for (auto& option : options) {
2140         ParseRangeResult(option);
2141     }
2142 }
2143 
GetRealSelectedIndex(const std::vector<NG::TextCascadePickerOptions> & rangeOptions,const std::vector<std::string> & valueArr,uint32_t depth,std::vector<uint32_t> & selectedArr)2144 void TextPickerPattern::GetRealSelectedIndex(const std::vector<NG::TextCascadePickerOptions>& rangeOptions,
2145     const std::vector<std::string>& valueArr, uint32_t depth, std::vector<uint32_t>& selectedArr)
2146 {
2147     for (size_t j = 0; j < rangeOptions.size(); j++) {
2148         if (rangeOptions[j].rangeResult[0] == valueArr[depth]) {
2149             selectedArr[depth] = j;
2150             if (!rangeOptions[j].children.empty()) {
2151                 ++depth;
2152                 GetRealSelectedIndex(rangeOptions[j].children, valueArr, depth, selectedArr);
2153             } else {
2154                 break;
2155             }
2156         }
2157     }
2158 }
2159 
GetAndUpdateRealSelectedArr(const std::vector<NG::TextCascadePickerOptions> & rangeOptions,const std::vector<RefPtr<ResourceObject>> & valueArrResObj)2160 void TextPickerPattern::GetAndUpdateRealSelectedArr(const std::vector<NG::TextCascadePickerOptions>& rangeOptions,
2161     const std::vector<RefPtr<ResourceObject>>& valueArrResObj)
2162 {
2163     if (isHasSelectAttr_) {
2164         return;
2165     }
2166 
2167     std::vector<std::string> valueArr;
2168 
2169     for (auto& valueResObj : valueArrResObj) {
2170         std::string result = "";
2171         if (valueResObj) {
2172             ResourceParseUtils::ParseResString(valueResObj, result);
2173         }
2174         valueArr.emplace_back(result);
2175     }
2176 
2177     SetValues(valueArr);
2178     auto pickerProperty = GetLayoutProperty<TextPickerLayoutProperty>();
2179     CHECK_NULL_VOID(pickerProperty);
2180     pickerProperty->UpdateValues(valueArr);
2181 
2182     std::vector<uint32_t> selectedArr(valueArr.size(), 0);
2183     GetRealSelectedIndex(rangeOptions, valueArr, 0, selectedArr);
2184     SetSelecteds(selectedArr);
2185     pickerProperty->UpdateSelecteds(selectedArr);
2186     pickerProperty->UpdateSelectedIndex(selectedArr);
2187 }
2188 
BeforeCreateLayoutWrapper()2189 void TextPickerPattern::BeforeCreateLayoutWrapper()
2190 {
2191     auto host = GetHost();
2192     CHECK_NULL_VOID(host);
2193     auto layoutProperty = host->GetLayoutProperty<TextPickerLayoutProperty>();
2194     CHECK_NULL_VOID(layoutProperty);
2195     auto layoutPolicy = layoutProperty->GetLayoutPolicyProperty();
2196     if (layoutPolicy.has_value() && (layoutPolicy->IsWrap() || layoutPolicy->IsFix())) {
2197         layoutProperty->UpdateUserDefinedIdealSize(
2198             CalcSize(CalcLength(DEFAULT_SIZE_ZERO), CalcLength(DEFAULT_SIZE_ZERO)));
2199     }
2200 }
2201 
2202 } // namespace OHOS::Ace::NG
2203