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