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