• 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 #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     auto focusHub = host->GetFocusHub();
267     CHECK_NULL_VOID(focusHub);
268     InitOnKeyEvent(focusHub);
269     InitDisabled();
270     isNeedUpdateSelectedIndex_ = true;
271 }
272 
SetEventCallback(EventCallback && value)273 void TextPickerPattern::SetEventCallback(EventCallback&& value)
274 {
275     auto host = GetHost();
276     CHECK_NULL_VOID(host);
277     auto children = host->GetChildren();
278     for (const auto& child : children) {
279         auto stackNode = DynamicCast<FrameNode>(child);
280         CHECK_NULL_VOID(stackNode);
281         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
282         CHECK_NULL_VOID(blendNode);
283         auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
284         CHECK_NULL_VOID(childNode);
285         auto pickerColumnPattern = childNode->GetPattern<TextPickerColumnPattern>();
286         CHECK_NULL_VOID(pickerColumnPattern);
287         pickerColumnPattern->SetEventCallback(std::move(value));
288     }
289 }
290 
FireChangeEvent(bool refresh)291 void TextPickerPattern::FireChangeEvent(bool refresh)
292 {
293     auto frameNodes = GetColumnNodes();
294     std::vector<std::string> value;
295     std::vector<double> index;
296     std::vector<uint32_t> selectedIdx;
297     for (auto it : frameNodes) {
298         CHECK_NULL_VOID(it.second);
299         auto textPickerColumnPattern = it.second->GetPattern<TextPickerColumnPattern>();
300         if (refresh) {
301             auto currentIndex = textPickerColumnPattern->GetCurrentIndex();
302             index.emplace_back(currentIndex);
303             selectedIdx.emplace_back(currentIndex);
304             auto currentValue = textPickerColumnPattern->GetOption(currentIndex);
305             value.emplace_back(currentValue);
306         }
307     }
308     auto textPickerEventHub = GetEventHub<TextPickerEventHub>();
309     CHECK_NULL_VOID(textPickerEventHub);
310     textPickerEventHub->FireChangeEvent(value, index);
311     textPickerEventHub->FireDialogChangeEvent(GetSelectedObject(true, 1));
312     std::string idx_str;
313     idx_str.assign(selectedIdx.begin(), selectedIdx.end());
314     firedSelectsStr_ = idx_str;
315 }
316 
InitDisabled()317 void TextPickerPattern::InitDisabled()
318 {
319     auto host = GetHost();
320     CHECK_NULL_VOID(host);
321     auto eventHub = host->GetEventHub<EventHub>();
322     CHECK_NULL_VOID(eventHub);
323     enabled_ = eventHub->IsEnabled();
324     auto renderContext = host->GetRenderContext();
325     CHECK_NULL_VOID(renderContext);
326     if (!enabled_) {
327         renderContext->UpdateOpacity(curOpacity_ * DISABLE_ALPHA);
328     }
329     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
330 }
331 
GetColumnNode()332 RefPtr<FrameNode> TextPickerPattern::GetColumnNode()
333 {
334     auto host = GetHost();
335     CHECK_NULL_RETURN(host, nullptr);
336 
337     auto stackNode = host->GetChildAtIndex(focusKeyID_);
338     CHECK_NULL_RETURN(stackNode, nullptr);
339 
340     auto blendNode = stackNode->GetLastChild();
341     CHECK_NULL_RETURN(blendNode, nullptr);
342 
343     auto columnNode = blendNode->GetLastChild();
344     CHECK_NULL_RETURN(columnNode, nullptr);
345 
346     return DynamicCast<FrameNode>(columnNode);
347 }
348 
GetColumnNodes()349 std::map<uint32_t, RefPtr<FrameNode>> TextPickerPattern::GetColumnNodes()
350 {
351     std::map<uint32_t, RefPtr<FrameNode>> allChildNode;
352     auto host = GetHost();
353     CHECK_NULL_RETURN(host, allChildNode);
354     auto children = host->GetChildren();
355     uint32_t index = 0;
356     for (auto iter = children.begin(); iter != children.end(); iter++) {
357         CHECK_NULL_RETURN(*iter, allChildNode);
358         auto stackNode = DynamicCast<FrameNode>(*iter);
359         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
360         CHECK_NULL_RETURN(blendNode, allChildNode);
361         auto currentNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
362         allChildNode[index] = currentNode;
363         index++;
364     }
365     return allChildNode;
366 }
367 
OnColumnsBuildingCascade()368 void TextPickerPattern::OnColumnsBuildingCascade()
369 {
370     auto frameNodes = GetColumnNodes();
371     auto count = frameNodes.size();
372     for (size_t index = 0; index < count; index++) {
373         CHECK_NULL_VOID(frameNodes[index]);
374         auto textPickerColumnPattern = frameNodes[index]->GetPattern<TextPickerColumnPattern>();
375         CHECK_NULL_VOID(textPickerColumnPattern);
376         if (cascadeOptions_.size() > index) {
377             selectedIndex_ = selecteds_.size() <= index || cascadeOptions_[index].rangeResult.empty()
378                                  ? 0 : selecteds_[index] % cascadeOptions_[index].rangeResult.size();
379             textPickerColumnPattern->SetCurrentIndex(
380                 isNeedUpdateSelectedIndex_ ? selectedIndex_ : textPickerColumnPattern->GetCurrentIndex());
381             std::vector<NG::RangeContent> rangeContents;
382             for (uint32_t i = 0; i < cascadeOptions_[index].rangeResult.size(); i++) {
383                 NG::RangeContent rangeContent;
384                 rangeContent.text_ = cascadeOptions_[index].rangeResult[i];
385                 rangeContents.emplace_back(rangeContent);
386             }
387             textPickerColumnPattern->SetOptions(rangeContents);
388             textPickerColumnPattern->SetColumnKind(NG::TEXT);
389             optionsWithNode_[frameNodes[index]] = rangeContents;
390             frameNodes[index]->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
391         }
392     }
393 }
394 
OnColumnsBuildingUnCascade()395 void TextPickerPattern::OnColumnsBuildingUnCascade()
396 {
397     auto frameNodes = GetColumnNodes();
398     for (auto it : frameNodes) {
399         CHECK_NULL_VOID(it.second);
400         auto textPickerColumnPattern = it.second->GetPattern<TextPickerColumnPattern>();
401         CHECK_NULL_VOID(textPickerColumnPattern);
402         if (cascadeOptions_.size() > it.first) {
403             selectedIndex_ = selecteds_.size() <= it.first || cascadeOptions_[it.first].rangeResult.empty()
404                                  ? 0 : selecteds_[it.first] % cascadeOptions_[it.first].rangeResult.size();
405             textPickerColumnPattern->SetCurrentIndex(
406                 isNeedUpdateSelectedIndex_ ? selectedIndex_ : textPickerColumnPattern->GetCurrentIndex());
407             std::vector<NG::RangeContent> rangeContents;
408             for (uint32_t i = 0; i < cascadeOptions_[it.first].rangeResult.size(); i++) {
409                 NG::RangeContent rangeContent;
410                 rangeContent.text_ = cascadeOptions_[it.first].rangeResult[i];
411                 rangeContents.emplace_back(rangeContent);
412             }
413             textPickerColumnPattern->SetOptions(rangeContents);
414             textPickerColumnPattern->SetColumnKind(NG::TEXT);
415             optionsWithNode_[it.second] = rangeContents;
416             it.second->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
417         } else {
418             ClearOption();
419             for (const auto& item : range_) {
420                 AppendOption(item);
421             }
422             selectedIndex_ = range_.empty() ? 0 : GetSelected() % range_.size();
423             textPickerColumnPattern->SetCurrentIndex(
424                 isNeedUpdateSelectedIndex_ ? selectedIndex_ : textPickerColumnPattern->GetCurrentIndex());
425             textPickerColumnPattern->SetOptions(options_);
426             textPickerColumnPattern->SetColumnKind(columnsKind_);
427             it.second->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
428         }
429     }
430 }
431 
OnColumnsBuilding()432 void TextPickerPattern::OnColumnsBuilding()
433 {
434     if (!isCascade_) {
435         OnColumnsBuildingUnCascade();
436     } else {
437         OnColumnsBuildingCascade();
438     }
439 }
440 
SetSelecteds(const std::vector<uint32_t> & values)441 void TextPickerPattern::SetSelecteds(const std::vector<uint32_t>& values)
442 {
443     std::string values_str;
444     values_str.assign(values.begin(), values.end());
445     isFiredSelectsChange_ = firedSelectsStr_.has_value() && firedSelectsStr_.value() == values_str;
446     firedSelectsStr_.reset();
447     selecteds_.clear();
448     for (auto& value : values) {
449         selecteds_.emplace_back(value);
450     }
451     if (isCascade_) {
452         auto columnCount = cascadeOptions_.size();
453         cascadeOptions_.clear();
454         ProcessCascadeOptions(cascadeOriginptions_, cascadeOptions_, 0);
455         if (cascadeOptions_.size() < columnCount) {
456             auto differ = columnCount - cascadeOptions_.size();
457             for (uint32_t i = 0; i < differ; i++) {
458                 NG::TextCascadePickerOptions differOption;
459                 memset_s(&differOption, sizeof(differOption), 0, sizeof(differOption));
460                 cascadeOptions_.emplace_back(differOption);
461             }
462         }
463     }
464 }
465 
FlushOptions()466 void TextPickerPattern::FlushOptions()
467 {
468     auto frameNodes = GetColumnNodes();
469     for (auto it : frameNodes) {
470         CHECK_NULL_VOID(it.second);
471         auto columnPattern = it.second->GetPattern<TextPickerColumnPattern>();
472         CHECK_NULL_VOID(columnPattern);
473         columnPattern->FlushCurrentOptions();
474         it.second->MarkModifyDone();
475         it.second->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
476     }
477 }
478 
CalculateHeight()479 double TextPickerPattern::CalculateHeight()
480 {
481     double height = 0.0;
482     auto host = GetHost();
483     CHECK_NULL_RETURN(host, height);
484     auto textPickerLayoutProperty = host->GetLayoutProperty<TextPickerLayoutProperty>();
485     CHECK_NULL_RETURN(textPickerLayoutProperty, height);
486     auto context = host->GetContext();
487     CHECK_NULL_RETURN(context, height);
488     auto pickerTheme = context->GetTheme<PickerTheme>();
489     CHECK_NULL_RETURN(pickerTheme, height);
490     if (textPickerLayoutProperty->HasDefaultPickerItemHeight()) {
491         auto defaultPickerItemHeightValue = textPickerLayoutProperty->GetDefaultPickerItemHeightValue();
492         if (context->NormalizeToPx(defaultPickerItemHeightValue) <= 0) {
493             height = pickerTheme->GetDividerSpacing().ConvertToPx();
494             return height;
495         }
496         if (defaultPickerItemHeightValue.Unit() == DimensionUnit::PERCENT) {
497             height = pickerTheme->GetGradientHeight().ConvertToPx() * defaultPickerItemHeightValue.Value();
498         } else {
499             height = context->NormalizeToPx(defaultPickerItemHeightValue);
500         }
501     } else {
502         height = pickerTheme->GetDividerSpacing().ConvertToPx();
503     }
504     if (defaultPickerItemHeight_ != height) {
505         defaultPickerItemHeight_ = height;
506         PaintFocusState();
507         SetButtonIdeaSize();
508     }
509     auto frameNodes = GetColumnNodes();
510     for (auto it : frameNodes) {
511         CHECK_NULL_RETURN(it.second, height);
512         auto textPickerColumnPattern = it.second->GetPattern<TextPickerColumnPattern>();
513         CHECK_NULL_RETURN(textPickerColumnPattern, height);
514         textPickerColumnPattern->SetDefaultPickerItemHeight(height);
515         textPickerColumnPattern->ResetOptionPropertyHeight();
516         textPickerColumnPattern->NeedResetOptionPropertyHeight(true);
517     }
518     return height;
519 }
520 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)521 void TextPickerPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
522 {
523     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
524         auto pattern = wp.Upgrade();
525         CHECK_NULL_RETURN(pattern, false);
526         return pattern->OnKeyEvent(event);
527     };
528     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
529 
530     auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
531         auto pattern = wp.Upgrade();
532         if (pattern) {
533             pattern->GetInnerFocusPaintRect(paintRect);
534         }
535     };
536     focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
537 }
538 
PaintFocusState()539 void TextPickerPattern::PaintFocusState()
540 {
541     auto host = GetHost();
542     CHECK_NULL_VOID(host);
543 
544     RoundRect focusRect;
545     GetInnerFocusPaintRect(focusRect);
546     auto focusHub = host->GetFocusHub();
547     CHECK_NULL_VOID(focusHub);
548     focusHub->PaintInnerFocusState(focusRect);
549 
550     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
551 }
552 
SetFocusCornerRadius(RoundRect & paintRect)553 void TextPickerPattern::SetFocusCornerRadius(RoundRect& paintRect)
554 {
555     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
556         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
557     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
558         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
559     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
560         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
561     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
562         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
563 }
564 
CalculatePaintRect(int32_t currentFocusIndex,float centerX,float centerY,float piantRectWidth,float piantRectHeight,float columnWidth)565 RectF TextPickerPattern::CalculatePaintRect(int32_t currentFocusIndex,
566     float centerX, float centerY, float piantRectWidth, float piantRectHeight, float columnWidth)
567 {
568     if (!GetIsShowInDialog()) {
569         piantRectHeight = piantRectHeight - OFFSET_LENGTH.ConvertToPx();
570         centerY = centerY + OFFSET.ConvertToPx();
571     } else {
572         piantRectHeight = piantRectHeight - DIALOG_OFFSET.ConvertToPx();
573         centerY = centerY + DIALOG_OFFSET_LENGTH.ConvertToPx();
574         centerX = centerX + FOUCS_WIDTH.ConvertToPx();
575     }
576     if (!GetIsShowInDialog()) {
577         if (piantRectWidth > columnWidth) {
578             piantRectWidth = columnWidth - FOUCS_WIDTH.ConvertToPx() - PRESS_INTERVAL.ConvertToPx();
579             centerX = currentFocusIndex * (piantRectWidth + FOUCS_WIDTH.ConvertToPx() + PRESS_INTERVAL.ConvertToPx()) +
580                       FOUCS_WIDTH.ConvertToPx();
581         } else {
582             centerX = centerX - MARGIN_SIZE.ConvertToPx() / HALF;
583         }
584     } else {
585         piantRectWidth = columnWidth - FOUCS_WIDTH.ConvertToPx() - PRESS_RADIUS.ConvertToPx();
586         centerX = currentFocusIndex * columnWidth + (columnWidth - piantRectWidth) / HALF;
587     }
588     return RectF(centerX, centerY, piantRectWidth, piantRectHeight);
589 }
590 
GetInnerFocusPaintRect(RoundRect & paintRect)591 void TextPickerPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
592 {
593     auto host = GetHost();
594     CHECK_NULL_VOID(host);
595     auto childSize = static_cast<int32_t>(host->GetChildren().size());
596     if (childSize == 0) {
597         return;
598     }
599     auto columnNode = GetColumnNode();
600     CHECK_NULL_VOID(columnNode);
601     auto pipeline = PipelineBase::GetCurrentContext();
602     CHECK_NULL_VOID(pipeline);
603     auto pickerTheme = pipeline->GetTheme<PickerTheme>();
604     CHECK_NULL_VOID(pickerTheme);
605     auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
606     CHECK_NULL_VOID(stackChild);
607     auto blendChild = DynamicCast<FrameNode>(stackChild->GetLastChild());
608     CHECK_NULL_VOID(blendChild);
609     auto pickerChild = DynamicCast<FrameNode>(blendChild->GetLastChild());
610     CHECK_NULL_VOID(pickerChild);
611     auto columnWidth = pickerChild->GetGeometryNode()->GetFrameSize().Width();
612     auto frameSize = host->GetGeometryNode()->GetFrameSize();
613     auto dividerSpacing = pipeline->NormalizeToPx(pickerTheme->GetDividerSpacing());
614     auto pickerThemeWidth = dividerSpacing * RATE;
615     auto currentFocusIndex = focusKeyID_;
616     bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
617     if (isRtl) {
618         currentFocusIndex = childSize - 1 - focusKeyID_;
619     }
620     auto centerX = (frameSize.Width() / childSize - pickerThemeWidth) / RATE +
621                    columnNode->GetGeometryNode()->GetFrameRect().Width() * currentFocusIndex +
622                    PRESS_INTERVAL.ConvertToPx() * RATE;
623     auto centerY = (frameSize.Height() - dividerSpacing) / RATE + PRESS_INTERVAL.ConvertToPx();
624     float piantRectWidth = (dividerSpacing - PRESS_INTERVAL.ConvertToPx()) * RATE;
625     float piantRectHeight = dividerSpacing - PRESS_INTERVAL.ConvertToPx() * RATE;
626     auto focusPaintRect = CalculatePaintRect(currentFocusIndex,
627         centerX, centerY, piantRectWidth, piantRectHeight, columnWidth);
628     paintRect.SetRect(focusPaintRect);
629     SetFocusCornerRadius(paintRect);
630 }
631 
OnKeyEvent(const KeyEvent & event)632 bool TextPickerPattern::OnKeyEvent(const KeyEvent& event)
633 {
634     if (event.action != KeyAction::DOWN) {
635         return false;
636     }
637 
638     if (event.code == KeyCode::KEY_SPACE || event.code == KeyCode::KEY_ENTER) {
639         if (!operationOn_ && event.code == KeyCode::KEY_ENTER) {
640             HandleDirectionKey(event.code);
641         }
642         operationOn_ = (event.code == KeyCode::KEY_SPACE) || (event.code == KeyCode::KEY_ENTER);
643         return true;
644     }
645 
646     if (event.code == KeyCode::KEY_TAB) {
647         operationOn_ = false;
648         return false;
649     }
650 
651     if (event.code == KeyCode::KEY_DPAD_UP || event.code == KeyCode::KEY_DPAD_DOWN ||
652         event.code == KeyCode::KEY_DPAD_LEFT || event.code == KeyCode::KEY_DPAD_RIGHT) {
653         if (operationOn_) {
654             HandleDirectionKey(event.code);
655         }
656         return true;
657     }
658     return false;
659 }
660 
SetChangeCallback(ColumnChangeCallback && value)661 void TextPickerPattern::SetChangeCallback(ColumnChangeCallback&& value)
662 {
663     auto host = GetHost();
664     CHECK_NULL_VOID(host);
665     auto children = host->GetChildren();
666     for (const auto& child : children) {
667         auto stackNode = DynamicCast<FrameNode>(child);
668         CHECK_NULL_VOID(stackNode);
669         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
670         CHECK_NULL_VOID(blendNode);
671         auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
672         CHECK_NULL_VOID(childNode);
673         auto textPickerColumnPattern = childNode->GetPattern<TextPickerColumnPattern>();
674         CHECK_NULL_VOID(textPickerColumnPattern);
675         textPickerColumnPattern->SetChangeCallback(std::move(value));
676     }
677 }
678 
ProcessCascadeOptionDepth(const NG::TextCascadePickerOptions & option)679 size_t TextPickerPattern::ProcessCascadeOptionDepth(const NG::TextCascadePickerOptions& option)
680 {
681     size_t depth = 1;
682     if (option.children.empty()) {
683         return depth;
684     }
685 
686     for (auto& pos : option.children) {
687         size_t tmpDep = 1;
688         tmpDep += ProcessCascadeOptionDepth(pos);
689         if (tmpDep > depth) {
690             depth = tmpDep;
691         }
692     }
693     return depth;
694 }
695 
ChangeCurrentOptionValue(NG::TextCascadePickerOptions & option,uint32_t value,uint32_t curColumn,uint32_t replaceColumn)696 bool TextPickerPattern::ChangeCurrentOptionValue(NG::TextCascadePickerOptions& option,
697     uint32_t value, uint32_t curColumn, uint32_t replaceColumn)
698 {
699     if (curColumn >= replaceColumn) {
700         selecteds_[curColumn] = value;
701         values_[curColumn] = "";
702     }
703 
704     for (uint32_t valueIndex = 0; valueIndex < option.children.size(); valueIndex++) {
705         if (curColumn >= replaceColumn) {
706             if (ChangeCurrentOptionValue(option.children[valueIndex], 0, curColumn + 1, replaceColumn)) {
707                 return true;
708             }
709         } else {
710             if (ChangeCurrentOptionValue(option.children[valueIndex], value, curColumn + 1, replaceColumn)) {
711                 return true;
712             }
713         }
714     }
715     return false;
716 }
717 
ProcessCascadeOptionsValues(const std::vector<std::string> & rangeResultValue,uint32_t index)718 void TextPickerPattern::ProcessCascadeOptionsValues(const std::vector<std::string>& rangeResultValue,
719     uint32_t index)
720 {
721     auto valueIterator = std::find(rangeResultValue.begin(), rangeResultValue.end(), values_[index]);
722     if (valueIterator != rangeResultValue.end()) {
723         if (index < selecteds_.size()) {
724             selecteds_[index] = static_cast<uint32_t>(std::distance(rangeResultValue.begin(), valueIterator));
725         } else {
726             selecteds_.emplace_back(std::distance(rangeResultValue.begin(), valueIterator));
727         }
728     } else {
729         if (index < selecteds_.size()) {
730             selecteds_[index] = 0;
731         } else {
732             selecteds_.emplace_back(0);
733         }
734     }
735 }
736 
ProcessCascadeOptions(const std::vector<NG::TextCascadePickerOptions> & options,std::vector<NG::TextCascadePickerOptions> & reOptions,uint32_t index)737 void TextPickerPattern::ProcessCascadeOptions(const std::vector<NG::TextCascadePickerOptions>& options,
738     std::vector<NG::TextCascadePickerOptions>& reOptions, uint32_t index)
739 {
740     std::vector<std::string> rangeResultValue;
741     NG::TextCascadePickerOptions option;
742     for (size_t i = 0; i < options.size(); i++) {
743         if (!options[i].rangeResult.empty()) {
744             rangeResultValue.emplace_back(options[i].rangeResult[0]);
745         }
746     }
747     option.rangeResult = rangeResultValue;
748     for (size_t i = 0; i < options.size(); i++) {
749         if (index < selecteds_.size() &&
750             ((selecteds_[index] != 0 && !isHasSelectAttr_) || isHasSelectAttr_)) {
751             if (selecteds_[index] < 0 && selecteds_[index] > options.size()) {
752                 selecteds_[index] = 0;
753             }
754             option.children = options[selecteds_[index]].children;
755             reOptions.emplace_back(option);
756             return ProcessCascadeOptions(options[selecteds_[index]].children, reOptions, index + 1);
757         }
758         if (index < values_.size() && values_[index] != "") {
759             ProcessCascadeOptionsValues(rangeResultValue, index);
760             option.children = options[selecteds_[index]].children;
761             reOptions.emplace_back(option);
762             return ProcessCascadeOptions(options[selecteds_[index]].children, reOptions, index + 1);
763         }
764         if (options.size() > 0 && options.size() == i + 1) {
765             option.children = options[0].children;
766             reOptions.emplace_back(option);
767             return ProcessCascadeOptions(options[0].children, reOptions, index + 1);
768         }
769     }
770 }
771 
SupplementOption(const std::vector<NG::TextCascadePickerOptions> & reOptions,std::vector<NG::RangeContent> & rangeContents,uint32_t patterIndex)772 void TextPickerPattern::SupplementOption(const std::vector<NG::TextCascadePickerOptions>& reOptions,
773     std::vector<NG::RangeContent>& rangeContents, uint32_t patterIndex)
774 {
775     for (uint32_t i = 0; i < reOptions[patterIndex].rangeResult.size(); i++) {
776         NG::RangeContent rangeContent;
777         rangeContent.text_ = reOptions[patterIndex].rangeResult[i];
778         rangeContents.emplace_back(rangeContent);
779     }
780 }
781 
HandleColumnChange(const RefPtr<FrameNode> & tag,bool isAdd,uint32_t index,bool needNotify)782 void TextPickerPattern::HandleColumnChange(const RefPtr<FrameNode>& tag, bool isAdd,
783     uint32_t index, bool needNotify)
784 {
785     if (isCascade_) {
786         auto frameNodes = GetColumnNodes();
787         uint32_t columnIndex = 0;
788         for (auto iter = frameNodes.begin(); iter != frameNodes.end(); iter++) {
789             if (iter->second->GetId() == tag->GetId()) {
790                 break;
791             }
792             columnIndex++;
793         }
794         for (uint32_t valueIndex = 0; valueIndex < cascadeOriginptions_.size(); valueIndex++) {
795             ChangeCurrentOptionValue(cascadeOriginptions_[valueIndex], index, 0, columnIndex);
796         }
797 
798         std::vector<NG::TextCascadePickerOptions> reOptions;
799         ProcessCascadeOptions(cascadeOriginptions_, reOptions, 0);
800         // Next Column Update Value
801         columnIndex = columnIndex + 1;
802         for (uint32_t patterIndex = columnIndex; patterIndex < frameNodes.size(); patterIndex++) {
803             auto patternNode = frameNodes[patterIndex];
804             CHECK_NULL_VOID(patternNode);
805             auto textPickerColumnPattern = patternNode->GetPattern<TextPickerColumnPattern>();
806             CHECK_NULL_VOID(textPickerColumnPattern);
807             if (patterIndex < reOptions.size()) {
808                 auto currentSelectedIndex = reOptions[patterIndex].rangeResult.empty() ? 0 :
809                              selecteds_[patterIndex] % reOptions[patterIndex].rangeResult.size();
810                 std::vector<NG::RangeContent> rangeContents;
811                 SupplementOption(reOptions, rangeContents, patterIndex);
812                 textPickerColumnPattern->SetCurrentIndex(currentSelectedIndex);
813                 textPickerColumnPattern->SetOptions(rangeContents);
814                 textPickerColumnPattern->FlushCurrentOptions();
815             } else {
816                 textPickerColumnPattern->ClearOptions();
817                 textPickerColumnPattern->SetCurrentIndex(0);
818                 textPickerColumnPattern->FlushCurrentOptions(false, false, true);
819             }
820         }
821     }
822 }
823 
CheckFocusID(int32_t childSize)824 void TextPickerPattern::CheckFocusID(int32_t childSize)
825 {
826     if (focusKeyID_ > childSize - 1) {
827         focusKeyID_ = childSize - 1;
828     } else if (focusKeyID_ < 0) {
829         focusKeyID_ = 0;
830     }
831 }
832 
ParseDirectionKey(RefPtr<TextPickerColumnPattern> & textPickerColumnPattern,KeyCode & code,int32_t childSize)833 bool TextPickerPattern::ParseDirectionKey(
834     RefPtr<TextPickerColumnPattern>& textPickerColumnPattern, KeyCode& code, int32_t childSize)
835 {
836     bool result = true;
837     bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
838     switch (code) {
839         case KeyCode::KEY_DPAD_UP:
840             textPickerColumnPattern->InnerHandleScroll(0, false);
841             break;
842         case KeyCode::KEY_DPAD_DOWN:
843             textPickerColumnPattern->InnerHandleScroll(1, false);
844             break;
845 
846         case KeyCode::KEY_ENTER:
847             focusKeyID_ = 0;
848             PaintFocusState();
849             break;
850 
851         case KeyCode::KEY_DPAD_LEFT:
852             if (isRtl) {
853                 focusKeyID_ += 1;
854             } else {
855                 focusKeyID_ -= 1;
856             }
857             CheckFocusID(childSize);
858             PaintFocusState();
859             break;
860 
861         case KeyCode::KEY_DPAD_RIGHT:
862             if (isRtl) {
863                 focusKeyID_ -= 1;
864             } else {
865                 focusKeyID_ += 1;
866             }
867             CheckFocusID(childSize);
868             PaintFocusState();
869             break;
870 
871         default:
872             result = false;
873             break;
874     }
875     return result;
876 }
877 
HandleDirectionKey(KeyCode code)878 bool TextPickerPattern::HandleDirectionKey(KeyCode code)
879 {
880     auto host = GetHost();
881     CHECK_NULL_RETURN(host, false);
882     auto childSize = host->GetChildren().size();
883     auto frameNode = GetColumnNode();
884     CHECK_NULL_RETURN(frameNode, false);
885     auto textPickerColumnPattern = frameNode->GetPattern<TextPickerColumnPattern>();
886     CHECK_NULL_RETURN(textPickerColumnPattern, false);
887     auto totalOptionCount = textPickerColumnPattern->GetOptionCount();
888     if (totalOptionCount == 0) {
889         return false;
890     }
891     return ParseDirectionKey(textPickerColumnPattern, code, static_cast<int32_t>(childSize));
892 }
893 
GetSelectedObjectMulti(const std::vector<std::string> & values,const std::vector<uint32_t> & indexs,int32_t status) const894 std::string TextPickerPattern::GetSelectedObjectMulti(const std::vector<std::string>& values,
895     const std::vector<uint32_t>& indexs, int32_t status) const
896 {
897     std::string result = "";
898     result = std::string("{\"value\":") + "[";
899     for (uint32_t i = 0; i < values.size(); i++) {
900         result += "\"" + values[i];
901         if (values.size() > 0 && i != values.size() - 1) {
902             result += "\",";
903         } else {
904             result += "\"]";
905         }
906     }
907     result += std::string(",\"index\":") + "[";
908     for (uint32_t i = 0; i < indexs.size(); i++) {
909         result += std::to_string(indexs[i]);
910         if (indexs.size() > 0 && indexs.size() != i + 1) {
911             result += ",";
912         } else {
913             result += "]";
914         }
915     }
916     result += ",\"status\":" + std::to_string(status) + "}";
917     return result;
918 }
919 
GetSelectedObject(bool isColumnChange,int32_t status) const920 std::string TextPickerPattern::GetSelectedObject(bool isColumnChange, int32_t status) const
921 {
922     std::vector<std::string> values;
923     std::vector<uint32_t> indexs;
924     auto host = GetHost();
925     CHECK_NULL_RETURN(host, "");
926     auto children = host->GetChildren();
927     for (const auto& child : children) {
928         CHECK_NULL_RETURN(child, "");
929         auto stackNode = DynamicCast<FrameNode>(child);
930         CHECK_NULL_RETURN(stackNode, "");
931         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
932         CHECK_NULL_RETURN(blendNode, "");
933         auto currentNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
934         CHECK_NULL_RETURN(currentNode, "");
935         auto textPickerColumnPattern = currentNode->GetPattern<TextPickerColumnPattern>();
936         CHECK_NULL_RETURN(textPickerColumnPattern, "");
937         auto value = textPickerColumnPattern->GetOption(textPickerColumnPattern->GetSelected());
938         auto index = textPickerColumnPattern->GetSelected();
939         if (isColumnChange) {
940             value = textPickerColumnPattern->GetCurrentText();
941             index = textPickerColumnPattern->GetCurrentIndex();
942         }
943         values.emplace_back(value);
944         indexs.emplace_back(index);
945     }
946 
947     auto context = host->GetContext();
948     CHECK_NULL_RETURN(context, "");
949     if (context->GetIsDeclarative()) {
950         if (values.size() == 1) {
951             return std::string("{\"value\":") + "\"" + values[0] + "\"" + ",\"index\":" + std::to_string(indexs[0]) +
952                    ",\"status\":" + std::to_string(status) + "}";
953         } else {
954             return GetSelectedObjectMulti(values, indexs, status);
955         }
956     } else {
957         return std::string("{\"newValue\":") + "\"" +
958                 values[0] + "\"" + ",\"newSelected\":" + std::to_string(indexs[0]) +
959                ",\"status\":" + std::to_string(status) + "}";
960     }
961 }
962 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const963 void TextPickerPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
964 {
965     /* no fixed attr below, just return */
966     if (filter.IsFastFilter()) {
967         return;
968     }
969     if (!range_.empty()) {
970         json->PutExtAttr("range", GetRangeStr().c_str(), filter);
971     } else {
972         if (!cascadeOriginptions_.empty()) {
973             if (!isCascade_) {
974                 json->PutExtAttr("range", GetOptionsMultiStr().c_str(), filter);
975             } else {
976                 json->PutExtAttr("range", GetOptionsCascadeStr(cascadeOriginptions_).c_str(), filter);
977             }
978         }
979     }
980 }
981 
GetRangeStr() const982 std::string TextPickerPattern::GetRangeStr() const
983 {
984     if (!range_.empty()) {
985         std::string result = "[";
986         for (const auto& item : range_) {
987             result += "\"";
988             result += "icon:";
989             result += item.icon_;
990             result += ",";
991             result += "text:";
992             result += item.text_;
993             result += "\"";
994             result += ",";
995         }
996         result.pop_back();
997         result += "]";
998         return result;
999     }
1000     return "";
1001 }
1002 
GetOptionsCascadeStr(const std::vector<NG::TextCascadePickerOptions> & options) const1003 std::string TextPickerPattern::GetOptionsCascadeStr(
1004     const std::vector<NG::TextCascadePickerOptions>& options) const
1005 {
1006     std::string result = "[";
1007     for (uint32_t i = 0; i < options.size(); i++) {
1008         result += std::string("{\"text\":\"");
1009         result += options[i].rangeResult[0];
1010         result += "\"";
1011         if (options[i].children.size() > 0) {
1012             result += std::string(", \"children\":");
1013             result += GetOptionsCascadeStr(options[i].children);
1014         }
1015         if (options.size() > 0 && options.size() != i + 1) {
1016             result += "},";
1017         } else {
1018             result += "}]";
1019         }
1020     }
1021     return result;
1022 }
1023 
GetOptionsMultiStrInternal() const1024 std::string TextPickerPattern::GetOptionsMultiStrInternal() const
1025 {
1026     std::string result = "[";
1027     for (uint32_t i = 0; i < cascadeOptions_.size(); i++) {
1028         result += "[";
1029         for (uint32_t j = 0; j < cascadeOptions_[i].rangeResult.size(); j++) {
1030             result += "\"" + cascadeOptions_[i].rangeResult[j];
1031             if (j + 1 != cascadeOptions_[i].rangeResult.size()) {
1032                 result += "\",";
1033             } else {
1034                 result += "\"]";
1035             }
1036         }
1037         if (cascadeOptions_.size() > 0 && i != cascadeOptions_.size() - 1) {
1038             result += ",";
1039         } else {
1040             result += "]";
1041         }
1042     }
1043     return result;
1044 }
1045 
GetOptionsMultiStr() const1046 std::string TextPickerPattern::GetOptionsMultiStr() const
1047 {
1048     std::string result = "";
1049     if (!cascadeOptions_.empty()) {
1050         result = GetOptionsMultiStrInternal();
1051     }
1052     return result;
1053 }
1054 
OnColorConfigurationUpdate()1055 void TextPickerPattern::OnColorConfigurationUpdate()
1056 {
1057     auto host = GetHost();
1058     CHECK_NULL_VOID(host);
1059     host->SetNeedCallChildrenUpdate(false);
1060     auto context = host->GetContext();
1061     CHECK_NULL_VOID(context);
1062     auto pickerTheme = context->GetTheme<PickerTheme>();
1063     CHECK_NULL_VOID(pickerTheme);
1064     auto disappearStyle = pickerTheme->GetDisappearOptionStyle();
1065     auto normalStyle = pickerTheme->GetOptionStyle(false, false);
1066     auto pickerProperty = host->GetLayoutProperty<TextPickerLayoutProperty>();
1067     CHECK_NULL_VOID(pickerProperty);
1068     pickerProperty->UpdateColor(GetTextProperties().normalTextStyle_.textColor.value_or(normalStyle.GetTextColor()));
1069     pickerProperty->UpdateDisappearColor(
1070         GetTextProperties().disappearTextStyle_.textColor.value_or(disappearStyle.GetTextColor()));
1071     if (isPicker_) {
1072         return;
1073     }
1074     auto dialogTheme = context->GetTheme<DialogTheme>();
1075     CHECK_NULL_VOID(dialogTheme);
1076     SetBackgroundColor(dialogTheme->GetBackgroundColor());
1077     auto contentRowNode = contentRowNode_.Upgrade();
1078     if (contentRowNode) {
1079         auto layoutRenderContext = contentRowNode->GetRenderContext();
1080         CHECK_NULL_VOID(layoutRenderContext);
1081         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN) ||
1082             !layoutRenderContext->IsUniRenderEnabled()) {
1083             layoutRenderContext->UpdateBackgroundColor(dialogTheme->GetButtonBackgroundColor());
1084         }
1085     }
1086     auto frameNode = DynamicCast<FrameNode>(host);
1087     CHECK_NULL_VOID(frameNode);
1088     FrameNode::ProcessOffscreenNode(frameNode);
1089     host->MarkModifyDone();
1090 }
1091 
OnDirectionConfigurationUpdate()1092 void TextPickerPattern::OnDirectionConfigurationUpdate()
1093 {
1094     isNeedUpdateSelectedIndex_ = false;
1095 }
1096 
CheckAndUpdateColumnSize(SizeF & size,bool isNeedAdaptForAging)1097 void TextPickerPattern::CheckAndUpdateColumnSize(SizeF& size, bool isNeedAdaptForAging)
1098 {
1099     auto host = GetHost();
1100     CHECK_NULL_VOID(host);
1101     auto pickerNode = DynamicCast<FrameNode>(host);
1102     CHECK_NULL_VOID(pickerNode);
1103     auto stackNode = DynamicCast<FrameNode>(pickerNode->GetFirstChild());
1104     CHECK_NULL_VOID(stackNode);
1105 
1106     auto pickerLayoutProperty = pickerNode->GetLayoutProperty();
1107     CHECK_NULL_VOID(pickerLayoutProperty);
1108     auto pickerLayoutConstraint = pickerLayoutProperty->GetLayoutConstraint();
1109 
1110     auto stackLayoutProperty = stackNode->GetLayoutProperty();
1111     CHECK_NULL_VOID(stackLayoutProperty);
1112     auto stackLayoutConstraint = stackLayoutProperty->GetLayoutConstraint();
1113 
1114     auto childCount = static_cast<float>(pickerNode->GetChildren().size());
1115     auto pickerContentSize = SizeF(size.Width() * childCount, size.Height());
1116     auto parentIdealSize = stackLayoutConstraint->parentIdealSize;
1117     if (parentIdealSize.Width().has_value()) {
1118         pickerContentSize.SetWidth(parentIdealSize.Width().value());
1119     }
1120     if (parentIdealSize.Height().has_value()) {
1121         pickerContentSize.SetHeight(parentIdealSize.Height().value());
1122     }
1123 
1124     PaddingPropertyF padding = pickerLayoutProperty->CreatePaddingAndBorder();
1125     auto minSize = SizeF(pickerLayoutConstraint->minSize.Width(), pickerLayoutConstraint->minSize.Height());
1126     MinusPaddingToSize(padding, minSize);
1127     auto context = GetContext();
1128     CHECK_NULL_VOID(context);
1129     auto version10OrLarger = context->GetMinPlatformVersion() > 9;
1130     pickerContentSize.Constrain(minSize, stackLayoutConstraint->maxSize, version10OrLarger);
1131 
1132     if (isNeedAdaptForAging && GetIsShowInDialog()) {
1133         size.SetWidth(pickerContentSize.Width());
1134     } else {
1135         size.SetWidth(pickerContentSize.Width() / std::max(childCount, 1.0f));
1136     }
1137     size.SetHeight(std::min(pickerContentSize.Height(), size.Height()));
1138 }
1139 
SetCanLoop(bool isLoop)1140 void TextPickerPattern::SetCanLoop(bool isLoop)
1141 {
1142     auto host = GetHost();
1143     CHECK_NULL_VOID(host);
1144     auto children = host->GetChildren();
1145     canloop_ = isLoop;
1146     for (const auto& child : children) {
1147         auto stackNode = DynamicCast<FrameNode>(child);
1148         CHECK_NULL_VOID(stackNode);
1149         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
1150         CHECK_NULL_VOID(blendNode);
1151         auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
1152         CHECK_NULL_VOID(childNode);
1153         auto pickerColumnPattern = childNode->GetPattern<TextPickerColumnPattern>();
1154         CHECK_NULL_VOID(pickerColumnPattern);
1155         pickerColumnPattern->SetCanLoop(isLoop);
1156     }
1157 }
1158 
NeedAdaptForAging()1159 bool TextPickerPattern::NeedAdaptForAging()
1160 {
1161     auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
1162     CHECK_NULL_RETURN(pipeline, false);
1163     auto pickerTheme = pipeline->GetTheme<PickerTheme>();
1164     CHECK_NULL_RETURN(pickerTheme, false);
1165 
1166     if (GreatOrEqual(pipeline->GetFontScale(), pickerTheme->GetMaxOneFontScale())) {
1167         return true;
1168     }
1169     return false;
1170 }
1171 } // namespace OHOS::Ace::NG
1172