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 #include "core/components_ng/property/calc_length.h"
36 #include "core/pipeline_ng/ui_task_scheduler.h"
37 
38 namespace OHOS::Ace::NG {
39 namespace {
40 // Datepicker style modification
41 const Dimension PRESS_INTERVAL = 4.0_vp;
42 const Dimension PRESS_RADIUS = 8.0_vp;
43 constexpr uint32_t RATE = 2;
44 const Dimension OFFSET = 3.5_vp;
45 const Dimension OFFSET_LENGTH = 5.5_vp;
46 const Dimension DIALOG_OFFSET = 1.0_vp;
47 const Dimension DIALOG_OFFSET_LENGTH = 1.0_vp;
48 constexpr uint32_t HALF = 2;
49 const Dimension FOUCS_WIDTH = 2.0_vp;
50 const Dimension MARGIN_SIZE = 12.0_vp;
51 constexpr float DISABLE_ALPHA = 0.6f;
52 } // namespace
53 
OnAttachToFrameNode()54 void TextPickerPattern::OnAttachToFrameNode()
55 {
56     auto host = GetHost();
57     CHECK_NULL_VOID(host);
58     host->GetRenderContext()->SetClipToFrame(true);
59     host->GetRenderContext()->UpdateClipEdge(true);
60 }
61 
SetLayoutDirection(TextDirection textDirection)62 void TextPickerPattern::SetLayoutDirection(TextDirection textDirection)
63 {
64     auto textPickerNode = GetHost();
65     std::function<void (decltype(textPickerNode))> updateDirectionFunc = [&](decltype(textPickerNode) node) {
66         CHECK_NULL_VOID(node);
67         auto updateProperty = node->GetLayoutProperty();
68         updateProperty->UpdateLayoutDirection(textDirection);
69         for (auto child : node->GetAllChildrenWithBuild()) {
70             auto frameNode = AceType::DynamicCast<FrameNode>(child);
71             if (!frameNode) {
72                 continue;
73             }
74             updateDirectionFunc(frameNode);
75         }
76     };
77     updateDirectionFunc(textPickerNode);
78 }
79 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)80 bool TextPickerPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
81 {
82     CHECK_NULL_RETURN(dirty, false);
83     SetButtonIdeaSize();
84     if (GetIsShowInDialog()) {
85         auto host = GetHost();
86         CHECK_NULL_RETURN(host, false);
87         auto parentNode = host->GetParent();
88         CHECK_NULL_RETURN(parentNode, false);
89         parentNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
90     }
91     return true;
92 }
93 
UpdateConfirmButtonMargin(const RefPtr<FrameNode> & buttonConfirmNode,const RefPtr<DialogTheme> & dialogTheme)94 void TextPickerPattern::UpdateConfirmButtonMargin(
95     const RefPtr<FrameNode>& buttonConfirmNode, const RefPtr<DialogTheme>& dialogTheme)
96 {
97     MarginProperty margin;
98     bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
99     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
100         margin.top = CalcLength(dialogTheme->GetDividerHeight());
101         margin.bottom = CalcLength(dialogTheme->GetDividerPadding().Bottom());
102         if (isRtl) {
103             margin.right = CalcLength(0.0_vp);
104             margin.left = CalcLength(dialogTheme->GetDividerPadding().Left());
105         } else {
106             margin.right = CalcLength(dialogTheme->GetDividerPadding().Right());
107             margin.left = CalcLength(0.0_vp);
108         }
109 
110     } else {
111         margin.top = CalcLength(dialogTheme->GetActionsPadding().Top());
112         margin.bottom = CalcLength(dialogTheme->GetActionsPadding().Bottom());
113         if (isRtl) {
114             margin.right = CalcLength(0.0_vp);
115             margin.left = CalcLength(dialogTheme->GetActionsPadding().Left());
116         } else {
117             margin.right = CalcLength(dialogTheme->GetActionsPadding().Right());
118             margin.left = CalcLength(0.0_vp);
119         }
120     }
121     buttonConfirmNode->GetLayoutProperty()->UpdateMargin(margin);
122 }
123 
UpdateCancelButtonMargin(const RefPtr<FrameNode> & buttonCancelNode,const RefPtr<DialogTheme> & dialogTheme)124 void TextPickerPattern::UpdateCancelButtonMargin(
125     const RefPtr<FrameNode>& buttonCancelNode, const RefPtr<DialogTheme>& dialogTheme)
126 {
127     MarginProperty margin;
128     bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
129     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
130         margin.top = CalcLength(dialogTheme->GetDividerHeight());
131         margin.bottom = CalcLength(dialogTheme->GetDividerPadding().Bottom());
132         if (isRtl) {
133             margin.right = CalcLength(dialogTheme->GetDividerPadding().Right());
134             margin.left = CalcLength(0.0_vp);
135         } else {
136             margin.right = CalcLength(0.0_vp);
137             margin.left = CalcLength(dialogTheme->GetDividerPadding().Left());
138         }
139     } else {
140         margin.top = CalcLength(dialogTheme->GetActionsPadding().Top());
141         margin.bottom = CalcLength(dialogTheme->GetActionsPadding().Bottom());
142         if (isRtl) {
143             margin.right = CalcLength(dialogTheme->GetActionsPadding().Right());
144             margin.left = CalcLength(0.0_vp);
145         } else {
146             margin.right = CalcLength(0.0_vp);
147             margin.left = CalcLength(dialogTheme->GetActionsPadding().Left());
148         }
149     }
150     buttonCancelNode->GetLayoutProperty()->UpdateMargin(margin);
151 }
152 
OnLanguageConfigurationUpdate()153 void TextPickerPattern::OnLanguageConfigurationUpdate()
154 {
155     auto buttonConfirmNode = weakButtonConfirm_.Upgrade();
156     CHECK_NULL_VOID(buttonConfirmNode);
157     auto confirmNode = AceType::DynamicCast<FrameNode>(buttonConfirmNode->GetFirstChild());
158     CHECK_NULL_VOID(confirmNode);
159     auto confirmNodeLayout = confirmNode->GetLayoutProperty<TextLayoutProperty>();
160     CHECK_NULL_VOID(confirmNodeLayout);
161     confirmNodeLayout->UpdateContent(Localization::GetInstance()->GetEntryLetters("common.ok"));
162     auto buttonConfirmLayoutProperty = buttonConfirmNode->GetLayoutProperty<ButtonLayoutProperty>();
163     CHECK_NULL_VOID(buttonConfirmLayoutProperty);
164     buttonConfirmLayoutProperty->UpdateLabel(Localization::GetInstance()->GetEntryLetters("common.ok"));
165     auto pipeline = confirmNode->GetContextRefPtr();
166     CHECK_NULL_VOID(pipeline);
167     auto dialogTheme = pipeline->GetTheme<DialogTheme>();
168     CHECK_NULL_VOID(dialogTheme);
169     UpdateConfirmButtonMargin(buttonConfirmNode, dialogTheme);
170     confirmNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
171 
172     auto buttonCancelNode = weakButtonCancel_.Upgrade();
173     CHECK_NULL_VOID(buttonCancelNode);
174     auto cancelNode = AceType::DynamicCast<FrameNode>(buttonCancelNode->GetFirstChild());
175     CHECK_NULL_VOID(cancelNode);
176     auto cancelNodeLayout = cancelNode->GetLayoutProperty<TextLayoutProperty>();
177     CHECK_NULL_VOID(cancelNodeLayout);
178     cancelNodeLayout->UpdateContent(Localization::GetInstance()->GetEntryLetters("common.cancel"));
179     UpdateCancelButtonMargin(buttonCancelNode, dialogTheme);
180     auto buttonCancelLayoutProperty = buttonCancelNode->GetLayoutProperty<ButtonLayoutProperty>();
181     CHECK_NULL_VOID(buttonCancelLayoutProperty);
182     buttonCancelLayoutProperty->UpdateLabel(Localization::GetInstance()->GetEntryLetters("common.cancel"));
183     cancelNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
184 }
185 
OnFontConfigurationUpdate()186 void TextPickerPattern::OnFontConfigurationUpdate()
187 {
188     CHECK_NULL_VOID(closeDialogEvent_);
189     closeDialogEvent_();
190 }
191 
SetButtonIdeaSize()192 void TextPickerPattern::SetButtonIdeaSize()
193 {
194     auto host = GetHost();
195     CHECK_NULL_VOID(host);
196     auto context = host->GetContext();
197     CHECK_NULL_VOID(context);
198     auto pickerTheme = context->GetTheme<PickerTheme>();
199     CHECK_NULL_VOID(pickerTheme);
200     auto children = host->GetChildren();
201     for (const auto& child : children) {
202         auto stackNode = DynamicCast<FrameNode>(child);
203         CHECK_NULL_VOID(stackNode);
204         auto width = stackNode->GetGeometryNode()->GetFrameSize().Width();
205         auto buttonNode = DynamicCast<FrameNode>(child->GetFirstChild());
206         CHECK_NULL_VOID(buttonNode);
207         auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
208         CHECK_NULL_VOID(buttonLayoutProperty);
209         buttonLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT_MAIN_AXIS);
210         buttonLayoutProperty->UpdateType(ButtonType::NORMAL);
211         buttonLayoutProperty->UpdateBorderRadius(BorderRadiusProperty(PRESS_RADIUS));
212         auto buttonHeight = CalculateHeight() - PRESS_INTERVAL.ConvertToPx() * RATE;
213         if (resizeFlag_) {
214             buttonHeight = resizePickerItemHeight_ - PRESS_INTERVAL.ConvertToPx() * RATE;
215         }
216         buttonLayoutProperty->
217             UpdateUserDefinedIdealSize(CalcSize(CalcLength(width - PRESS_INTERVAL.ConvertToPx() * RATE),
218                 CalcLength(buttonHeight)));
219         auto buttonConfirmRenderContext = buttonNode->GetRenderContext();
220         CHECK_NULL_VOID(buttonConfirmRenderContext);
221         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
222         CHECK_NULL_VOID(blendNode);
223         auto columnNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
224         CHECK_NULL_VOID(columnNode);
225         auto columnPattern = columnNode->GetPattern<TextPickerColumnPattern>();
226         CHECK_NULL_VOID(columnPattern);
227         if (!columnPattern->isHover()) {
228             buttonConfirmRenderContext->UpdateBackgroundColor(Color::TRANSPARENT);
229         }
230         buttonNode->MarkModifyDone();
231         buttonNode->MarkDirtyNode();
232     }
233 }
234 
OnModifyDone()235 void TextPickerPattern::OnModifyDone()
236 {
237     if (isFiredSelectsChange_) {
238         isFiredSelectsChange_ = false;
239         return;
240     }
241     auto host = GetHost();
242     CHECK_NULL_VOID(host);
243     auto layoutProperty = host->GetLayoutProperty<LinearLayoutProperty>();
244     CHECK_NULL_VOID(layoutProperty);
245 
246     auto layoutDirection = layoutProperty->GetLayoutDirection();
247     if (layoutDirection != TextDirection::AUTO) {
248         SetLayoutDirection(layoutDirection);
249     }
250     OnColumnsBuilding();
251     FlushOptions();
252     CalculateHeight();
253     if (cascadeOptions_.size() > 0) {
254         SetChangeCallback([weak = WeakClaim(this)](const RefPtr<FrameNode>& tag,
255             bool add, uint32_t index, bool notify) {
256                 auto refPtr = weak.Upgrade();
257                 CHECK_NULL_VOID(refPtr);
258                 refPtr->HandleColumnChange(tag, add, index, notify);
259             });
260     }
261     SetEventCallback([weak = WeakClaim(this)](bool refresh) {
262         auto refPtr = weak.Upgrade();
263         CHECK_NULL_VOID(refPtr);
264         refPtr->FireChangeEvent(refresh);
265     });
266     SetScrollStopEventCallback([weak = WeakClaim(this)](bool refresh) {
267         auto refPtr = weak.Upgrade();
268         CHECK_NULL_VOID(refPtr);
269         refPtr->FireScrollStopEvent(refresh);
270     });
271     auto focusHub = host->GetFocusHub();
272     CHECK_NULL_VOID(focusHub);
273     InitOnKeyEvent(focusHub);
274     InitDisabled();
275     isNeedUpdateSelectedIndex_ = true;
276 }
277 
SetEventCallback(EventCallback && value)278 void TextPickerPattern::SetEventCallback(EventCallback&& value)
279 {
280     auto host = GetHost();
281     CHECK_NULL_VOID(host);
282     auto children = host->GetChildren();
283     for (const auto& child : children) {
284         auto stackNode = DynamicCast<FrameNode>(child);
285         CHECK_NULL_VOID(stackNode);
286         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
287         CHECK_NULL_VOID(blendNode);
288         auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
289         CHECK_NULL_VOID(childNode);
290         auto pickerColumnPattern = childNode->GetPattern<TextPickerColumnPattern>();
291         CHECK_NULL_VOID(pickerColumnPattern);
292         pickerColumnPattern->SetEventCallback(std::move(value));
293     }
294 }
295 
FireChangeEvent(bool refresh)296 void TextPickerPattern::FireChangeEvent(bool refresh)
297 {
298     auto frameNodes = GetColumnNodes();
299     std::vector<std::string> value;
300     std::vector<double> index;
301     std::vector<uint32_t> selectedIdx;
302     for (auto it : frameNodes) {
303         CHECK_NULL_VOID(it.second);
304         auto textPickerColumnPattern = it.second->GetPattern<TextPickerColumnPattern>();
305         if (refresh) {
306             auto currentIndex = textPickerColumnPattern->GetCurrentIndex();
307             index.emplace_back(currentIndex);
308             selectedIdx.emplace_back(currentIndex);
309             auto currentValue = textPickerColumnPattern->GetOption(currentIndex);
310             value.emplace_back(currentValue);
311         }
312     }
313     auto textPickerEventHub = GetEventHub<TextPickerEventHub>();
314     CHECK_NULL_VOID(textPickerEventHub);
315     textPickerEventHub->FireChangeEvent(value, index);
316     textPickerEventHub->FireDialogChangeEvent(GetSelectedObject(true, 1));
317     std::string idx_str;
318     idx_str.assign(selectedIdx.begin(), selectedIdx.end());
319     firedSelectsStr_ = idx_str;
320 }
321 
SetScrollStopEventCallback(EventCallback && value)322 void TextPickerPattern::SetScrollStopEventCallback(EventCallback&& value)
323 {
324     auto host = GetHost();
325     CHECK_NULL_VOID(host);
326     auto children = host->GetChildren();
327     for (const auto& child : children) {
328         auto stackNode = DynamicCast<FrameNode>(child);
329         CHECK_NULL_VOID(stackNode);
330         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
331         CHECK_NULL_VOID(blendNode);
332         auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
333         CHECK_NULL_VOID(childNode);
334         auto pickerColumnPattern = childNode->GetPattern<TextPickerColumnPattern>();
335         CHECK_NULL_VOID(pickerColumnPattern);
336         pickerColumnPattern->SetScrollStopEventCallback(std::move(value));
337     }
338 }
339 
FireScrollStopEvent(bool refresh)340 void TextPickerPattern::FireScrollStopEvent(bool refresh)
341 {
342     auto frameNodes = GetColumnNodes();
343     std::vector<std::string> value;
344     std::vector<double> index;
345     for (auto it : frameNodes) {
346         CHECK_NULL_VOID(it.second);
347         auto textPickerColumnPattern = it.second->GetPattern<TextPickerColumnPattern>();
348         if (refresh) {
349             auto currentIndex = textPickerColumnPattern->GetCurrentIndex();
350             index.emplace_back(currentIndex);
351             auto currentValue = textPickerColumnPattern->GetOption(currentIndex);
352             value.emplace_back(currentValue);
353         }
354     }
355     auto textPickerEventHub = GetEventHub<TextPickerEventHub>();
356     CHECK_NULL_VOID(textPickerEventHub);
357     textPickerEventHub->FireScrollStopEvent(value, index);
358     textPickerEventHub->FireDialogScrollStopEvent(GetSelectedObject(true, 1));
359 }
360 
InitDisabled()361 void TextPickerPattern::InitDisabled()
362 {
363     auto host = GetHost();
364     CHECK_NULL_VOID(host);
365     auto eventHub = host->GetEventHub<EventHub>();
366     CHECK_NULL_VOID(eventHub);
367     enabled_ = eventHub->IsEnabled();
368     auto renderContext = host->GetRenderContext();
369     CHECK_NULL_VOID(renderContext);
370     if (!enabled_) {
371         renderContext->UpdateOpacity(curOpacity_ * DISABLE_ALPHA);
372     }
373     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
374 }
375 
GetColumnNode()376 RefPtr<FrameNode> TextPickerPattern::GetColumnNode()
377 {
378     auto host = GetHost();
379     CHECK_NULL_RETURN(host, nullptr);
380 
381     auto stackNode = host->GetChildAtIndex(focusKeyID_);
382     CHECK_NULL_RETURN(stackNode, nullptr);
383 
384     auto blendNode = stackNode->GetLastChild();
385     CHECK_NULL_RETURN(blendNode, nullptr);
386 
387     auto columnNode = blendNode->GetLastChild();
388     CHECK_NULL_RETURN(columnNode, nullptr);
389 
390     return DynamicCast<FrameNode>(columnNode);
391 }
392 
GetColumnNodes()393 std::map<uint32_t, RefPtr<FrameNode>> TextPickerPattern::GetColumnNodes()
394 {
395     std::map<uint32_t, RefPtr<FrameNode>> allChildNode;
396     auto host = GetHost();
397     CHECK_NULL_RETURN(host, allChildNode);
398     auto children = host->GetChildren();
399     uint32_t index = 0;
400     for (auto iter = children.begin(); iter != children.end(); iter++) {
401         CHECK_NULL_RETURN(*iter, allChildNode);
402         auto stackNode = DynamicCast<FrameNode>(*iter);
403         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
404         CHECK_NULL_RETURN(blendNode, allChildNode);
405         auto currentNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
406         allChildNode[index] = currentNode;
407         index++;
408     }
409     return allChildNode;
410 }
411 
OnColumnsBuildingCascade()412 void TextPickerPattern::OnColumnsBuildingCascade()
413 {
414     auto frameNodes = GetColumnNodes();
415     auto count = frameNodes.size();
416     for (size_t index = 0; index < count; index++) {
417         CHECK_NULL_VOID(frameNodes[index]);
418         auto textPickerColumnPattern = frameNodes[index]->GetPattern<TextPickerColumnPattern>();
419         CHECK_NULL_VOID(textPickerColumnPattern);
420         if (cascadeOptions_.size() > index) {
421             selectedIndex_ = selecteds_.size() <= index || cascadeOptions_[index].rangeResult.empty()
422                                  ? 0 : selecteds_[index] % cascadeOptions_[index].rangeResult.size();
423             textPickerColumnPattern->SetCurrentIndex(
424                 isNeedUpdateSelectedIndex_ ? selectedIndex_ : textPickerColumnPattern->GetCurrentIndex());
425             std::vector<NG::RangeContent> rangeContents;
426             for (uint32_t i = 0; i < cascadeOptions_[index].rangeResult.size(); i++) {
427                 NG::RangeContent rangeContent;
428                 rangeContent.text_ = cascadeOptions_[index].rangeResult[i];
429                 rangeContents.emplace_back(rangeContent);
430             }
431             textPickerColumnPattern->SetOptions(rangeContents);
432             textPickerColumnPattern->SetColumnKind(NG::TEXT);
433             optionsWithNode_[frameNodes[index]] = rangeContents;
434             frameNodes[index]->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
435         }
436     }
437 }
438 
OnColumnsBuildingUnCascade()439 void TextPickerPattern::OnColumnsBuildingUnCascade()
440 {
441     auto frameNodes = GetColumnNodes();
442     for (auto it : frameNodes) {
443         CHECK_NULL_VOID(it.second);
444         auto textPickerColumnPattern = it.second->GetPattern<TextPickerColumnPattern>();
445         CHECK_NULL_VOID(textPickerColumnPattern);
446         if (cascadeOptions_.size() > it.first) {
447             selectedIndex_ = selecteds_.size() <= it.first || cascadeOptions_[it.first].rangeResult.empty()
448                                  ? 0 : selecteds_[it.first] % cascadeOptions_[it.first].rangeResult.size();
449             textPickerColumnPattern->SetCurrentIndex(
450                 isNeedUpdateSelectedIndex_ ? selectedIndex_ : textPickerColumnPattern->GetCurrentIndex());
451             std::vector<NG::RangeContent> rangeContents;
452             for (uint32_t i = 0; i < cascadeOptions_[it.first].rangeResult.size(); i++) {
453                 NG::RangeContent rangeContent;
454                 rangeContent.text_ = cascadeOptions_[it.first].rangeResult[i];
455                 rangeContents.emplace_back(rangeContent);
456             }
457             textPickerColumnPattern->SetOptions(rangeContents);
458             textPickerColumnPattern->SetColumnKind(NG::TEXT);
459             optionsWithNode_[it.second] = rangeContents;
460             it.second->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
461         } else {
462             ClearOption();
463             for (const auto& item : range_) {
464                 AppendOption(item);
465             }
466             selectedIndex_ = range_.empty() ? 0 : GetSelected() % range_.size();
467             textPickerColumnPattern->SetCurrentIndex(
468                 isNeedUpdateSelectedIndex_ ? selectedIndex_ : textPickerColumnPattern->GetCurrentIndex());
469             textPickerColumnPattern->SetOptions(options_);
470             textPickerColumnPattern->SetColumnKind(columnsKind_);
471             it.second->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
472         }
473     }
474 }
475 
OnColumnsBuilding()476 void TextPickerPattern::OnColumnsBuilding()
477 {
478     if (!isCascade_) {
479         OnColumnsBuildingUnCascade();
480     } else {
481         OnColumnsBuildingCascade();
482     }
483 }
484 
SetSelecteds(const std::vector<uint32_t> & values)485 void TextPickerPattern::SetSelecteds(const std::vector<uint32_t>& values)
486 {
487     std::string values_str;
488     values_str.assign(values.begin(), values.end());
489     isFiredSelectsChange_ = firedSelectsStr_.has_value() && firedSelectsStr_.value() == values_str;
490     firedSelectsStr_.reset();
491     selecteds_.clear();
492     for (auto& value : values) {
493         selecteds_.emplace_back(value);
494     }
495     if (isCascade_) {
496         auto columnCount = cascadeOptions_.size();
497         cascadeOptions_.clear();
498         ProcessCascadeOptions(cascadeOriginptions_, cascadeOptions_, 0);
499         if (cascadeOptions_.size() < columnCount) {
500             auto differ = columnCount - cascadeOptions_.size();
501             for (uint32_t i = 0; i < differ; i++) {
502                 NG::TextCascadePickerOptions differOption;
503                 memset_s(&differOption, sizeof(differOption), 0, sizeof(differOption));
504                 cascadeOptions_.emplace_back(differOption);
505             }
506         }
507     }
508 }
509 
FlushOptions()510 void TextPickerPattern::FlushOptions()
511 {
512     auto frameNodes = GetColumnNodes();
513     for (auto it : frameNodes) {
514         CHECK_NULL_VOID(it.second);
515         auto columnPattern = it.second->GetPattern<TextPickerColumnPattern>();
516         CHECK_NULL_VOID(columnPattern);
517         columnPattern->FlushCurrentOptions();
518         it.second->MarkModifyDone();
519         it.second->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
520     }
521 }
522 
CalculateHeight()523 double TextPickerPattern::CalculateHeight()
524 {
525     double height = 0.0;
526     auto host = GetHost();
527     CHECK_NULL_RETURN(host, height);
528     auto textPickerLayoutProperty = host->GetLayoutProperty<TextPickerLayoutProperty>();
529     CHECK_NULL_RETURN(textPickerLayoutProperty, height);
530     auto context = host->GetContext();
531     CHECK_NULL_RETURN(context, height);
532     auto pickerTheme = context->GetTheme<PickerTheme>();
533     CHECK_NULL_RETURN(pickerTheme, height);
534     if (textPickerLayoutProperty->HasDefaultPickerItemHeight()) {
535         auto defaultPickerItemHeightValue = textPickerLayoutProperty->GetDefaultPickerItemHeightValue();
536         if (context->NormalizeToPx(defaultPickerItemHeightValue) <= 0) {
537             height = pickerTheme->GetDividerSpacing().ConvertToPx();
538             return height;
539         }
540         if (defaultPickerItemHeightValue.Unit() == DimensionUnit::PERCENT) {
541             height = pickerTheme->GetGradientHeight().ConvertToPx() * defaultPickerItemHeightValue.Value();
542         } else {
543             height = context->NormalizeToPx(defaultPickerItemHeightValue);
544         }
545     } else {
546         height = pickerTheme->GetDividerSpacing().ConvertToPx();
547     }
548     if (defaultPickerItemHeight_ != height) {
549         defaultPickerItemHeight_ = height;
550         PaintFocusState();
551         SetButtonIdeaSize();
552     }
553     auto frameNodes = GetColumnNodes();
554     for (auto it : frameNodes) {
555         CHECK_NULL_RETURN(it.second, height);
556         auto textPickerColumnPattern = it.second->GetPattern<TextPickerColumnPattern>();
557         CHECK_NULL_RETURN(textPickerColumnPattern, height);
558         textPickerColumnPattern->SetDefaultPickerItemHeight(height);
559         textPickerColumnPattern->ResetOptionPropertyHeight();
560         textPickerColumnPattern->NeedResetOptionPropertyHeight(true);
561     }
562     return height;
563 }
564 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)565 void TextPickerPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
566 {
567     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
568         auto pattern = wp.Upgrade();
569         CHECK_NULL_RETURN(pattern, false);
570         return pattern->OnKeyEvent(event);
571     };
572     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
573 
574     auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
575         auto pattern = wp.Upgrade();
576         if (pattern) {
577             pattern->GetInnerFocusPaintRect(paintRect);
578         }
579     };
580     focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
581 }
582 
PaintFocusState()583 void TextPickerPattern::PaintFocusState()
584 {
585     auto host = GetHost();
586     CHECK_NULL_VOID(host);
587 
588     RoundRect focusRect;
589     GetInnerFocusPaintRect(focusRect);
590     auto focusHub = host->GetFocusHub();
591     CHECK_NULL_VOID(focusHub);
592     focusHub->PaintInnerFocusState(focusRect);
593 
594     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
595 }
596 
SetFocusCornerRadius(RoundRect & paintRect)597 void TextPickerPattern::SetFocusCornerRadius(RoundRect& paintRect)
598 {
599     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
600         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
601     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
602         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
603     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
604         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
605     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
606         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
607 }
608 
CalculatePaintRect(int32_t currentFocusIndex,float centerX,float centerY,float piantRectWidth,float piantRectHeight,float columnWidth)609 RectF TextPickerPattern::CalculatePaintRect(int32_t currentFocusIndex,
610     float centerX, float centerY, float piantRectWidth, float piantRectHeight, float columnWidth)
611 {
612     if (!GetIsShowInDialog()) {
613         piantRectHeight = piantRectHeight - OFFSET_LENGTH.ConvertToPx();
614         centerY = centerY + OFFSET.ConvertToPx();
615     } else {
616         piantRectHeight = piantRectHeight - DIALOG_OFFSET.ConvertToPx();
617         centerY = centerY + DIALOG_OFFSET_LENGTH.ConvertToPx();
618         centerX = centerX + FOUCS_WIDTH.ConvertToPx();
619     }
620     if (!GetIsShowInDialog()) {
621         if (piantRectWidth > columnWidth) {
622             piantRectWidth = columnWidth - FOUCS_WIDTH.ConvertToPx() - PRESS_INTERVAL.ConvertToPx();
623             centerX = currentFocusIndex * (piantRectWidth + FOUCS_WIDTH.ConvertToPx() + PRESS_INTERVAL.ConvertToPx()) +
624                       FOUCS_WIDTH.ConvertToPx();
625         } else {
626             centerX = centerX - MARGIN_SIZE.ConvertToPx() / HALF;
627         }
628     } else {
629         piantRectWidth = columnWidth - FOUCS_WIDTH.ConvertToPx() - PRESS_RADIUS.ConvertToPx();
630         centerX = currentFocusIndex * columnWidth + (columnWidth - piantRectWidth) / HALF;
631     }
632     return RectF(centerX, centerY, piantRectWidth, piantRectHeight);
633 }
634 
GetInnerFocusPaintRect(RoundRect & paintRect)635 void TextPickerPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
636 {
637     auto host = GetHost();
638     CHECK_NULL_VOID(host);
639     auto childSize = static_cast<int32_t>(host->GetChildren().size());
640     if (childSize == 0) {
641         return;
642     }
643     auto columnNode = GetColumnNode();
644     CHECK_NULL_VOID(columnNode);
645     auto pipeline = PipelineBase::GetCurrentContext();
646     CHECK_NULL_VOID(pipeline);
647     auto pickerTheme = pipeline->GetTheme<PickerTheme>();
648     CHECK_NULL_VOID(pickerTheme);
649     auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
650     CHECK_NULL_VOID(stackChild);
651     auto blendChild = DynamicCast<FrameNode>(stackChild->GetLastChild());
652     CHECK_NULL_VOID(blendChild);
653     auto pickerChild = DynamicCast<FrameNode>(blendChild->GetLastChild());
654     CHECK_NULL_VOID(pickerChild);
655     auto columnWidth = pickerChild->GetGeometryNode()->GetFrameSize().Width();
656     auto frameSize = host->GetGeometryNode()->GetFrameSize();
657     auto dividerSpacing = pipeline->NormalizeToPx(pickerTheme->GetDividerSpacing());
658     auto pickerThemeWidth = dividerSpacing * RATE;
659     auto currentFocusIndex = focusKeyID_;
660     bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
661     if (isRtl) {
662         currentFocusIndex = childSize - 1 - focusKeyID_;
663     }
664     auto centerX = (frameSize.Width() / childSize - pickerThemeWidth) / RATE +
665                    columnNode->GetGeometryNode()->GetFrameRect().Width() * currentFocusIndex +
666                    PRESS_INTERVAL.ConvertToPx() * RATE;
667     auto centerY = (frameSize.Height() - dividerSpacing) / RATE + PRESS_INTERVAL.ConvertToPx();
668     float piantRectWidth = (dividerSpacing - PRESS_INTERVAL.ConvertToPx()) * RATE;
669     float piantRectHeight = dividerSpacing - PRESS_INTERVAL.ConvertToPx() * RATE;
670     auto focusPaintRect = CalculatePaintRect(currentFocusIndex,
671         centerX, centerY, piantRectWidth, piantRectHeight, columnWidth);
672     paintRect.SetRect(focusPaintRect);
673     SetFocusCornerRadius(paintRect);
674 }
675 
OnKeyEvent(const KeyEvent & event)676 bool TextPickerPattern::OnKeyEvent(const KeyEvent& event)
677 {
678     if (event.action != KeyAction::DOWN) {
679         return false;
680     }
681 
682     if (event.code == KeyCode::KEY_SPACE || event.code == KeyCode::KEY_ENTER) {
683         if (!operationOn_ && event.code == KeyCode::KEY_ENTER) {
684             HandleDirectionKey(event.code);
685         }
686         operationOn_ = (event.code == KeyCode::KEY_SPACE) || (event.code == KeyCode::KEY_ENTER);
687         return true;
688     }
689 
690     if (event.code == KeyCode::KEY_TAB) {
691         operationOn_ = false;
692         return false;
693     }
694 
695     if (event.code == KeyCode::KEY_DPAD_UP || event.code == KeyCode::KEY_DPAD_DOWN ||
696         event.code == KeyCode::KEY_DPAD_LEFT || event.code == KeyCode::KEY_DPAD_RIGHT) {
697         if (operationOn_) {
698             HandleDirectionKey(event.code);
699         }
700         return true;
701     }
702     return false;
703 }
704 
SetChangeCallback(ColumnChangeCallback && value)705 void TextPickerPattern::SetChangeCallback(ColumnChangeCallback&& value)
706 {
707     auto host = GetHost();
708     CHECK_NULL_VOID(host);
709     auto children = host->GetChildren();
710     for (const auto& child : children) {
711         auto stackNode = DynamicCast<FrameNode>(child);
712         CHECK_NULL_VOID(stackNode);
713         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
714         CHECK_NULL_VOID(blendNode);
715         auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
716         CHECK_NULL_VOID(childNode);
717         auto textPickerColumnPattern = childNode->GetPattern<TextPickerColumnPattern>();
718         CHECK_NULL_VOID(textPickerColumnPattern);
719         textPickerColumnPattern->SetChangeCallback(std::move(value));
720     }
721 }
722 
ProcessCascadeOptionDepth(const NG::TextCascadePickerOptions & option)723 size_t TextPickerPattern::ProcessCascadeOptionDepth(const NG::TextCascadePickerOptions& option)
724 {
725     size_t depth = 1;
726     if (option.children.empty()) {
727         return depth;
728     }
729 
730     for (auto& pos : option.children) {
731         size_t tmpDep = 1;
732         tmpDep += ProcessCascadeOptionDepth(pos);
733         if (tmpDep > depth) {
734             depth = tmpDep;
735         }
736     }
737     return depth;
738 }
739 
ChangeCurrentOptionValue(NG::TextCascadePickerOptions & option,uint32_t value,uint32_t curColumn,uint32_t replaceColumn)740 bool TextPickerPattern::ChangeCurrentOptionValue(NG::TextCascadePickerOptions& option,
741     uint32_t value, uint32_t curColumn, uint32_t replaceColumn)
742 {
743     if (curColumn >= replaceColumn) {
744         selecteds_[curColumn] = value;
745         values_[curColumn] = "";
746     }
747 
748     for (uint32_t valueIndex = 0; valueIndex < option.children.size(); valueIndex++) {
749         if (curColumn >= replaceColumn) {
750             if (ChangeCurrentOptionValue(option.children[valueIndex], 0, curColumn + 1, replaceColumn)) {
751                 return true;
752             }
753         } else {
754             if (ChangeCurrentOptionValue(option.children[valueIndex], value, curColumn + 1, replaceColumn)) {
755                 return true;
756             }
757         }
758     }
759     return false;
760 }
761 
ProcessCascadeOptionsValues(const std::vector<std::string> & rangeResultValue,uint32_t index)762 void TextPickerPattern::ProcessCascadeOptionsValues(const std::vector<std::string>& rangeResultValue,
763     uint32_t index)
764 {
765     auto valueIterator = std::find(rangeResultValue.begin(), rangeResultValue.end(), values_[index]);
766     if (valueIterator != rangeResultValue.end()) {
767         if (index < selecteds_.size()) {
768             selecteds_[index] = static_cast<uint32_t>(std::distance(rangeResultValue.begin(), valueIterator));
769         } else {
770             selecteds_.emplace_back(std::distance(rangeResultValue.begin(), valueIterator));
771         }
772     } else {
773         if (index < selecteds_.size()) {
774             selecteds_[index] = 0;
775         } else {
776             selecteds_.emplace_back(0);
777         }
778     }
779 }
780 
ProcessCascadeOptions(const std::vector<NG::TextCascadePickerOptions> & options,std::vector<NG::TextCascadePickerOptions> & reOptions,uint32_t index)781 void TextPickerPattern::ProcessCascadeOptions(const std::vector<NG::TextCascadePickerOptions>& options,
782     std::vector<NG::TextCascadePickerOptions>& reOptions, uint32_t index)
783 {
784     std::vector<std::string> rangeResultValue;
785     NG::TextCascadePickerOptions option;
786     for (size_t i = 0; i < options.size(); i++) {
787         if (!options[i].rangeResult.empty()) {
788             rangeResultValue.emplace_back(options[i].rangeResult[0]);
789         }
790     }
791     option.rangeResult = rangeResultValue;
792     for (size_t i = 0; i < options.size(); i++) {
793         if (index < selecteds_.size() &&
794             ((selecteds_[index] != 0 && !isHasSelectAttr_) || isHasSelectAttr_)) {
795             if (selecteds_[index] < 0 && selecteds_[index] > options.size()) {
796                 selecteds_[index] = 0;
797             }
798             option.children = options[selecteds_[index]].children;
799             reOptions.emplace_back(option);
800             return ProcessCascadeOptions(options[selecteds_[index]].children, reOptions, index + 1);
801         }
802         if (index < values_.size() && values_[index] != "") {
803             ProcessCascadeOptionsValues(rangeResultValue, index);
804             option.children = options[selecteds_[index]].children;
805             reOptions.emplace_back(option);
806             return ProcessCascadeOptions(options[selecteds_[index]].children, reOptions, index + 1);
807         }
808         if (options.size() > 0 && options.size() == i + 1) {
809             option.children = options[0].children;
810             reOptions.emplace_back(option);
811             return ProcessCascadeOptions(options[0].children, reOptions, index + 1);
812         }
813     }
814 }
815 
SupplementOption(const std::vector<NG::TextCascadePickerOptions> & reOptions,std::vector<NG::RangeContent> & rangeContents,uint32_t patterIndex)816 void TextPickerPattern::SupplementOption(const std::vector<NG::TextCascadePickerOptions>& reOptions,
817     std::vector<NG::RangeContent>& rangeContents, uint32_t patterIndex)
818 {
819     for (uint32_t i = 0; i < reOptions[patterIndex].rangeResult.size(); i++) {
820         NG::RangeContent rangeContent;
821         rangeContent.text_ = reOptions[patterIndex].rangeResult[i];
822         rangeContents.emplace_back(rangeContent);
823     }
824 }
825 
HandleColumnChange(const RefPtr<FrameNode> & tag,bool isAdd,uint32_t index,bool needNotify)826 void TextPickerPattern::HandleColumnChange(const RefPtr<FrameNode>& tag, bool isAdd,
827     uint32_t index, bool needNotify)
828 {
829     if (isCascade_) {
830         auto frameNodes = GetColumnNodes();
831         uint32_t columnIndex = 0;
832         for (auto iter = frameNodes.begin(); iter != frameNodes.end(); iter++) {
833             if (iter->second->GetId() == tag->GetId()) {
834                 break;
835             }
836             columnIndex++;
837         }
838         for (uint32_t valueIndex = 0; valueIndex < cascadeOriginptions_.size(); valueIndex++) {
839             ChangeCurrentOptionValue(cascadeOriginptions_[valueIndex], index, 0, columnIndex);
840         }
841 
842         std::vector<NG::TextCascadePickerOptions> reOptions;
843         ProcessCascadeOptions(cascadeOriginptions_, reOptions, 0);
844         // Next Column Update Value
845         columnIndex = columnIndex + 1;
846         for (uint32_t patterIndex = columnIndex; patterIndex < frameNodes.size(); patterIndex++) {
847             auto patternNode = frameNodes[patterIndex];
848             CHECK_NULL_VOID(patternNode);
849             auto textPickerColumnPattern = patternNode->GetPattern<TextPickerColumnPattern>();
850             CHECK_NULL_VOID(textPickerColumnPattern);
851             if (patterIndex < reOptions.size()) {
852                 auto currentSelectedIndex = reOptions[patterIndex].rangeResult.empty() ? 0 :
853                              selecteds_[patterIndex] % reOptions[patterIndex].rangeResult.size();
854                 std::vector<NG::RangeContent> rangeContents;
855                 SupplementOption(reOptions, rangeContents, patterIndex);
856                 textPickerColumnPattern->SetCurrentIndex(currentSelectedIndex);
857                 textPickerColumnPattern->SetOptions(rangeContents);
858                 textPickerColumnPattern->FlushCurrentOptions();
859             } else {
860                 textPickerColumnPattern->ClearOptions();
861                 textPickerColumnPattern->SetCurrentIndex(0);
862                 textPickerColumnPattern->FlushCurrentOptions(false, false, true);
863             }
864         }
865     }
866 }
867 
CheckFocusID(int32_t childSize)868 void TextPickerPattern::CheckFocusID(int32_t childSize)
869 {
870     if (focusKeyID_ > childSize - 1) {
871         focusKeyID_ = childSize - 1;
872     } else if (focusKeyID_ < 0) {
873         focusKeyID_ = 0;
874     }
875 }
876 
ParseDirectionKey(RefPtr<TextPickerColumnPattern> & textPickerColumnPattern,KeyCode & code,int32_t childSize)877 bool TextPickerPattern::ParseDirectionKey(
878     RefPtr<TextPickerColumnPattern>& textPickerColumnPattern, KeyCode& code, int32_t childSize)
879 {
880     bool result = true;
881     bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
882     switch (code) {
883         case KeyCode::KEY_DPAD_UP:
884             if (textPickerColumnPattern->InnerHandleScroll(0, false)) {
885                 textPickerColumnPattern->HandleScrollStopEventCallback(true);
886             }
887             break;
888         case KeyCode::KEY_DPAD_DOWN:
889             if (textPickerColumnPattern->InnerHandleScroll(1, false)) {
890                 textPickerColumnPattern->HandleScrollStopEventCallback(true);
891             }
892             break;
893 
894         case KeyCode::KEY_ENTER:
895             focusKeyID_ = 0;
896             PaintFocusState();
897             break;
898 
899         case KeyCode::KEY_DPAD_LEFT:
900             if (isRtl) {
901                 focusKeyID_ += 1;
902             } else {
903                 focusKeyID_ -= 1;
904             }
905             CheckFocusID(childSize);
906             PaintFocusState();
907             break;
908 
909         case KeyCode::KEY_DPAD_RIGHT:
910             if (isRtl) {
911                 focusKeyID_ -= 1;
912             } else {
913                 focusKeyID_ += 1;
914             }
915             CheckFocusID(childSize);
916             PaintFocusState();
917             break;
918 
919         default:
920             result = false;
921             break;
922     }
923     return result;
924 }
925 
HandleDirectionKey(KeyCode code)926 bool TextPickerPattern::HandleDirectionKey(KeyCode code)
927 {
928     auto host = GetHost();
929     CHECK_NULL_RETURN(host, false);
930     auto childSize = host->GetChildren().size();
931     auto frameNode = GetColumnNode();
932     CHECK_NULL_RETURN(frameNode, false);
933     auto textPickerColumnPattern = frameNode->GetPattern<TextPickerColumnPattern>();
934     CHECK_NULL_RETURN(textPickerColumnPattern, false);
935     auto totalOptionCount = textPickerColumnPattern->GetOptionCount();
936     if (totalOptionCount == 0) {
937         return false;
938     }
939     return ParseDirectionKey(textPickerColumnPattern, code, static_cast<int32_t>(childSize));
940 }
941 
GetSelectedObjectMulti(const std::vector<std::string> & values,const std::vector<uint32_t> & indexs,int32_t status) const942 std::string TextPickerPattern::GetSelectedObjectMulti(const std::vector<std::string>& values,
943     const std::vector<uint32_t>& indexs, int32_t status) const
944 {
945     std::string result = "";
946     result = std::string("{\"value\":") + "[";
947     for (uint32_t i = 0; i < values.size(); i++) {
948         result += "\"" + values[i];
949         if (values.size() > 0 && i != values.size() - 1) {
950             result += "\",";
951         } else {
952             result += "\"]";
953         }
954     }
955     result += std::string(",\"index\":") + "[";
956     for (uint32_t i = 0; i < indexs.size(); i++) {
957         result += std::to_string(indexs[i]);
958         if (indexs.size() > 0 && indexs.size() != i + 1) {
959             result += ",";
960         } else {
961             result += "]";
962         }
963     }
964     result += ",\"status\":" + std::to_string(status) + "}";
965     return result;
966 }
967 
GetSelectedObject(bool isColumnChange,int32_t status) const968 std::string TextPickerPattern::GetSelectedObject(bool isColumnChange, int32_t status) const
969 {
970     std::vector<std::string> values;
971     std::vector<uint32_t> indexs;
972     auto host = GetHost();
973     CHECK_NULL_RETURN(host, "");
974     auto children = host->GetChildren();
975     for (const auto& child : children) {
976         CHECK_NULL_RETURN(child, "");
977         auto stackNode = DynamicCast<FrameNode>(child);
978         CHECK_NULL_RETURN(stackNode, "");
979         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
980         CHECK_NULL_RETURN(blendNode, "");
981         auto currentNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
982         CHECK_NULL_RETURN(currentNode, "");
983         auto textPickerColumnPattern = currentNode->GetPattern<TextPickerColumnPattern>();
984         CHECK_NULL_RETURN(textPickerColumnPattern, "");
985         auto value = textPickerColumnPattern->GetOption(textPickerColumnPattern->GetSelected());
986         auto index = textPickerColumnPattern->GetSelected();
987         if (isColumnChange) {
988             value = textPickerColumnPattern->GetCurrentText();
989             index = textPickerColumnPattern->GetCurrentIndex();
990         }
991         values.emplace_back(value);
992         indexs.emplace_back(index);
993     }
994 
995     auto context = host->GetContext();
996     CHECK_NULL_RETURN(context, "");
997     if (context->GetIsDeclarative()) {
998         if (values.size() == 1) {
999             return std::string("{\"value\":") + "\"" + values[0] + "\"" + ",\"index\":" + std::to_string(indexs[0]) +
1000                    ",\"status\":" + std::to_string(status) + "}";
1001         } else {
1002             return GetSelectedObjectMulti(values, indexs, status);
1003         }
1004     } else {
1005         return std::string("{\"newValue\":") + "\"" +
1006                 values[0] + "\"" + ",\"newSelected\":" + std::to_string(indexs[0]) +
1007                ",\"status\":" + std::to_string(status) + "}";
1008     }
1009 }
1010 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const1011 void TextPickerPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
1012 {
1013     /* no fixed attr below, just return */
1014     if (filter.IsFastFilter()) {
1015         return;
1016     }
1017     if (!range_.empty()) {
1018         json->PutExtAttr("range", GetRangeStr().c_str(), filter);
1019     } else {
1020         if (!cascadeOriginptions_.empty()) {
1021             if (!isCascade_) {
1022                 json->PutExtAttr("range", GetOptionsMultiStr().c_str(), filter);
1023             } else {
1024                 json->PutExtAttr("range", GetOptionsCascadeStr(cascadeOriginptions_).c_str(), filter);
1025             }
1026         }
1027     }
1028 }
1029 
GetRangeStr() const1030 std::string TextPickerPattern::GetRangeStr() const
1031 {
1032     if (!range_.empty()) {
1033         std::string result = "[";
1034         for (const auto& item : range_) {
1035             result += "\"";
1036             result += "icon:";
1037             result += item.icon_;
1038             result += ",";
1039             result += "text:";
1040             result += item.text_;
1041             result += "\"";
1042             result += ",";
1043         }
1044         result.pop_back();
1045         result += "]";
1046         return result;
1047     }
1048     return "";
1049 }
1050 
GetOptionsCascadeStr(const std::vector<NG::TextCascadePickerOptions> & options) const1051 std::string TextPickerPattern::GetOptionsCascadeStr(
1052     const std::vector<NG::TextCascadePickerOptions>& options) const
1053 {
1054     std::string result = "[";
1055     for (uint32_t i = 0; i < options.size(); i++) {
1056         result += std::string("{\"text\":\"");
1057         result += options[i].rangeResult[0];
1058         result += "\"";
1059         if (options[i].children.size() > 0) {
1060             result += std::string(", \"children\":");
1061             result += GetOptionsCascadeStr(options[i].children);
1062         }
1063         if (options.size() > 0 && options.size() != i + 1) {
1064             result += "},";
1065         } else {
1066             result += "}]";
1067         }
1068     }
1069     return result;
1070 }
1071 
GetOptionsMultiStrInternal() const1072 std::string TextPickerPattern::GetOptionsMultiStrInternal() const
1073 {
1074     std::string result = "[";
1075     for (uint32_t i = 0; i < cascadeOptions_.size(); i++) {
1076         result += "[";
1077         for (uint32_t j = 0; j < cascadeOptions_[i].rangeResult.size(); j++) {
1078             result += "\"" + cascadeOptions_[i].rangeResult[j];
1079             if (j + 1 != cascadeOptions_[i].rangeResult.size()) {
1080                 result += "\",";
1081             } else {
1082                 result += "\"]";
1083             }
1084         }
1085         if (cascadeOptions_.size() > 0 && i != cascadeOptions_.size() - 1) {
1086             result += ",";
1087         } else {
1088             result += "]";
1089         }
1090     }
1091     return result;
1092 }
1093 
GetOptionsMultiStr() const1094 std::string TextPickerPattern::GetOptionsMultiStr() const
1095 {
1096     std::string result = "";
1097     if (!cascadeOptions_.empty()) {
1098         result = GetOptionsMultiStrInternal();
1099     }
1100     return result;
1101 }
1102 
OnColorConfigurationUpdate()1103 void TextPickerPattern::OnColorConfigurationUpdate()
1104 {
1105     auto host = GetHost();
1106     CHECK_NULL_VOID(host);
1107     host->SetNeedCallChildrenUpdate(false);
1108     auto context = host->GetContext();
1109     CHECK_NULL_VOID(context);
1110     auto pickerTheme = context->GetTheme<PickerTheme>();
1111     CHECK_NULL_VOID(pickerTheme);
1112     auto disappearStyle = pickerTheme->GetDisappearOptionStyle();
1113     auto normalStyle = pickerTheme->GetOptionStyle(false, false);
1114     auto pickerProperty = host->GetLayoutProperty<TextPickerLayoutProperty>();
1115     CHECK_NULL_VOID(pickerProperty);
1116     pickerProperty->UpdateColor(GetTextProperties().normalTextStyle_.textColor.value_or(normalStyle.GetTextColor()));
1117     pickerProperty->UpdateDisappearColor(
1118         GetTextProperties().disappearTextStyle_.textColor.value_or(disappearStyle.GetTextColor()));
1119     if (isPicker_) {
1120         return;
1121     }
1122     auto dialogTheme = context->GetTheme<DialogTheme>();
1123     CHECK_NULL_VOID(dialogTheme);
1124     SetBackgroundColor(dialogTheme->GetBackgroundColor());
1125     auto contentRowNode = contentRowNode_.Upgrade();
1126     if (contentRowNode) {
1127         auto layoutRenderContext = contentRowNode->GetRenderContext();
1128         CHECK_NULL_VOID(layoutRenderContext);
1129         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN) ||
1130             !layoutRenderContext->IsUniRenderEnabled()) {
1131             layoutRenderContext->UpdateBackgroundColor(dialogTheme->GetButtonBackgroundColor());
1132         }
1133     }
1134     auto frameNode = DynamicCast<FrameNode>(host);
1135     CHECK_NULL_VOID(frameNode);
1136     FrameNode::ProcessOffscreenNode(frameNode);
1137     host->MarkModifyDone();
1138 }
1139 
OnDirectionConfigurationUpdate()1140 void TextPickerPattern::OnDirectionConfigurationUpdate()
1141 {
1142     isNeedUpdateSelectedIndex_ = false;
1143 }
1144 
CheckAndUpdateColumnSize(SizeF & size,bool isNeedAdaptForAging)1145 void TextPickerPattern::CheckAndUpdateColumnSize(SizeF& size, bool isNeedAdaptForAging)
1146 {
1147     auto host = GetHost();
1148     CHECK_NULL_VOID(host);
1149     auto pickerNode = DynamicCast<FrameNode>(host);
1150     CHECK_NULL_VOID(pickerNode);
1151     auto stackNode = DynamicCast<FrameNode>(pickerNode->GetFirstChild());
1152     CHECK_NULL_VOID(stackNode);
1153 
1154     auto pickerLayoutProperty = pickerNode->GetLayoutProperty();
1155     CHECK_NULL_VOID(pickerLayoutProperty);
1156     auto pickerLayoutConstraint = pickerLayoutProperty->GetLayoutConstraint();
1157 
1158     auto stackLayoutProperty = stackNode->GetLayoutProperty();
1159     CHECK_NULL_VOID(stackLayoutProperty);
1160     auto stackLayoutConstraint = stackLayoutProperty->GetLayoutConstraint();
1161 
1162     auto childCount = static_cast<float>(pickerNode->GetChildren().size());
1163     auto pickerContentSize = SizeF(size.Width() * childCount, size.Height());
1164     auto parentIdealSize = stackLayoutConstraint->parentIdealSize;
1165     if (parentIdealSize.Width().has_value()) {
1166         pickerContentSize.SetWidth(parentIdealSize.Width().value());
1167     }
1168     if (parentIdealSize.Height().has_value()) {
1169         pickerContentSize.SetHeight(parentIdealSize.Height().value());
1170     }
1171 
1172     PaddingPropertyF padding = pickerLayoutProperty->CreatePaddingAndBorder();
1173     auto minSize = SizeF(pickerLayoutConstraint->minSize.Width(), pickerLayoutConstraint->minSize.Height());
1174     MinusPaddingToSize(padding, minSize);
1175     auto context = GetContext();
1176     CHECK_NULL_VOID(context);
1177     auto version10OrLarger = context->GetMinPlatformVersion() > 9;
1178     pickerContentSize.Constrain(minSize, stackLayoutConstraint->maxSize, version10OrLarger);
1179 
1180     if (isNeedAdaptForAging && GetIsShowInDialog()) {
1181         size.SetWidth(pickerContentSize.Width());
1182     } else {
1183         size.SetWidth(pickerContentSize.Width() / std::max(childCount, 1.0f));
1184     }
1185     size.SetHeight(std::min(pickerContentSize.Height(), size.Height()));
1186 }
1187 
SetCanLoop(bool isLoop)1188 void TextPickerPattern::SetCanLoop(bool isLoop)
1189 {
1190     auto host = GetHost();
1191     CHECK_NULL_VOID(host);
1192     auto children = host->GetChildren();
1193     canloop_ = isLoop;
1194     for (const auto& child : children) {
1195         auto stackNode = DynamicCast<FrameNode>(child);
1196         CHECK_NULL_VOID(stackNode);
1197         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
1198         CHECK_NULL_VOID(blendNode);
1199         auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
1200         CHECK_NULL_VOID(childNode);
1201         auto pickerColumnPattern = childNode->GetPattern<TextPickerColumnPattern>();
1202         CHECK_NULL_VOID(pickerColumnPattern);
1203         pickerColumnPattern->SetCanLoop(isLoop);
1204     }
1205 }
1206 
NeedAdaptForAging()1207 bool TextPickerPattern::NeedAdaptForAging()
1208 {
1209     auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
1210     CHECK_NULL_RETURN(pipeline, false);
1211     auto pickerTheme = pipeline->GetTheme<PickerTheme>();
1212     CHECK_NULL_RETURN(pickerTheme, false);
1213 
1214     if (GreatOrEqual(pipeline->GetFontScale(), pickerTheme->GetMaxOneFontScale())) {
1215         return true;
1216     }
1217     return false;
1218 }
1219 } // namespace OHOS::Ace::NG
1220