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