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