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