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_column_pattern.h"
17
18 #include <cstdint>
19 #include <cstdlib>
20
21 #include "adapter/ohos/entrance/picker/picker_haptic_factory.h"
22 #include "base/geometry/dimension.h"
23 #include "base/geometry/ng/size_t.h"
24 #include "base/utils/measure_util.h"
25 #include "base/utils/multi_thread.h"
26 #include "base/utils/utils.h"
27 #include "bridge/common/utils/utils.h"
28 #include "core/common/container.h"
29 #include "core/common/font_manager.h"
30 #include "core/components/picker/picker_theme.h"
31 #include "core/components_ng/base/frame_scene_status.h"
32 #include "core/components_ng/pattern/image/image_layout_property.h"
33 #include "core/components_ng/pattern/image/image_pattern.h"
34 #include "core/components_ng/pattern/text/text_pattern.h"
35 #include "core/components_ng/pattern/text_picker/textpicker_event_hub.h"
36 #include "core/components_ng/pattern/button/button_layout_property.h"
37
38 namespace OHOS::Ace::NG {
39 namespace {
40 const Dimension FONT_SIZE = Dimension(2.0);
41 const Dimension FOCUS_SIZE = Dimension(1.0);
42 const float MOVE_DISTANCE = 5.0f;
43 const double MOVE_THRESHOLD = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) ? 2.0 : 1.0;
44 constexpr float FONTWEIGHT = 0.5f;
45 constexpr float FONT_SIZE_PERCENT = 1.0f;
46 constexpr int32_t HOVER_ANIMATION_DURATION = 40;
47 constexpr int32_t CLICK_ANIMATION_DURATION = 300;
48 constexpr size_t MIXTURE_CHILD_COUNT = 2;
49 const uint32_t OPTION_COUNT_PHONE_LANDSCAPE = 3;
50 const Dimension ICON_SIZE = 24.0_vp;
51 const Dimension ICON_TEXT_SPACE = 8.0_vp;
52 const std::vector<std::string> FONT_FAMILY_DEFAULT = { "sans-serif" };
53 const std::string MEASURE_STRING = "TEST";
54 const int32_t HALF_NUMBER = 2;
55 const int32_t BUFFER_NODE_NUMBER = 2;
56 const double CURVE_MOVE_THRESHOLD = 0.5;
57 constexpr char PICKER_DRAG_SCENE[] = "picker_drag_scene";
58 const uint32_t NEXT_COLOUM_DIFF = 1;
59 } // namespace
60
OnAttachToFrameNode()61 void TextPickerColumnPattern::OnAttachToFrameNode()
62 {
63 auto host = GetHost();
64 CHECK_NULL_VOID(host);
65 THREAD_SAFE_NODE_CHECK(host, OnAttachToFrameNode); // picker multi-thread security
66
67 auto context = host->GetContextRefPtr();
68 CHECK_NULL_VOID(context);
69 auto pickerTheme = context->GetTheme<PickerTheme>();
70 CHECK_NULL_VOID(pickerTheme);
71 auto hub = host->GetOrCreateEventHub<EventHub>();
72 CHECK_NULL_VOID(hub);
73 auto gestureHub = hub->GetOrCreateGestureEventHub();
74 CHECK_NULL_VOID(gestureHub);
75
76 tossAnimationController_->SetPipelineContext(context);
77 tossAnimationController_->SetColumn(AceType::WeakClaim(this));
78 overscroller_.SetColumn(AceType::WeakClaim(this));
79 jumpInterval_ = pickerTheme->GetJumpInterval().ConvertToPx();
80 CreateAnimation();
81 InitPanEvent(gestureHub);
82 host->GetRenderContext()->SetClipToFrame(true);
83 InitHapticController(host);
84 RegisterWindowStateChangedCallback();
85 }
86
OnDetachFromFrameNode(FrameNode * frameNode)87 void TextPickerColumnPattern::OnDetachFromFrameNode(FrameNode* frameNode)
88 {
89 THREAD_SAFE_NODE_CHECK(frameNode, OnDetachFromFrameNode, frameNode); // picker multi-thread security
90
91 if (hapticController_) {
92 hapticController_->Stop();
93 }
94 UnregisterWindowStateChangedCallback(frameNode);
95 }
96
OnAttachToMainTree()97 void TextPickerColumnPattern::OnAttachToMainTree()
98 {
99 auto host = GetHost();
100 CHECK_NULL_VOID(host);
101 THREAD_SAFE_NODE_CHECK(host, OnAttachToMainTree); // picker multi-thread security
102 }
103
OnDetachFromMainTree()104 void TextPickerColumnPattern::OnDetachFromMainTree()
105 {
106 auto host = GetHost();
107 CHECK_NULL_VOID(host);
108 THREAD_SAFE_NODE_CHECK(host, OnDetachFromMainTree); // picker multi-thread security
109 }
110
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)111 bool TextPickerColumnPattern::OnDirtyLayoutWrapperSwap(
112 const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
113 {
114 bool isChange =
115 config.frameSizeChange || config.frameOffsetChange || config.contentSizeChange || config.contentOffsetChange;
116
117 CHECK_NULL_RETURN(isChange, false);
118 CHECK_NULL_RETURN(dirty, false);
119 auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
120 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
121 auto layoutAlgorithm = DynamicCast<TextPickerLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
122 CHECK_NULL_RETURN(layoutAlgorithm, false);
123 halfDisplayCounts_ = layoutAlgorithm->GetHalfDisplayCounts();
124 return true;
125 }
126
OnModifyDone()127 void TextPickerColumnPattern::OnModifyDone()
128 {
129 auto host = GetHost();
130 CHECK_NULL_VOID(host);
131 auto pipeline = host->GetContext();
132 CHECK_NULL_VOID(pipeline);
133 auto theme = pipeline->GetTheme<PickerTheme>(GetThemeScopeId());
134 CHECK_NULL_VOID(theme);
135 pressColor_ = theme->GetPressColor();
136 hoverColor_ = theme->GetHoverColor();
137 useButtonFocusArea_ = theme->NeedButtonFocusAreaType();
138 InitTextFadeOut();
139 InitSelectorButtonProperties(theme);
140 InitMouseAndPressEvent();
141 SetAccessibilityAction();
142 if (optionProperties_.size() <= 0) {
143 dividerSpacing_ = pipeline->NormalizeToPx(theme->GetDividerSpacing());
144 gradientHeight_ = static_cast<float>(pipeline->NormalizeToPx(theme->GetGradientHeight()));
145
146 auto showCount = GetShowOptionCount();
147 auto midIndex = showCount / HALF_NUMBER;
148 uint32_t childIndex = 0;
149 while (childIndex < showCount) {
150 TextPickerOptionProperty prop;
151 InitTextHeightAndFontHeight(childIndex, midIndex, prop);
152 optionProperties_.emplace_back(prop);
153 childIndex++;
154 }
155 SetOptionShiftDistance();
156 }
157 InitHapticController(host);
158 }
159
InitHapticController(const RefPtr<FrameNode> & host)160 void TextPickerColumnPattern::InitHapticController(const RefPtr<FrameNode>& host)
161 {
162 CHECK_NULL_VOID(host);
163 if (host->LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
164 return;
165 }
166 auto blendNode = DynamicCast<FrameNode>(host->GetParent());
167 CHECK_NULL_VOID(blendNode);
168 auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
169 CHECK_NULL_VOID(stackNode);
170 auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
171 CHECK_NULL_VOID(parentNode);
172 auto textPickerPattern = parentNode->GetPattern<TextPickerPattern>();
173 CHECK_NULL_VOID(textPickerPattern);
174 if (textPickerPattern->GetIsEnableHaptic()) {
175 isEnableHaptic_ = true;
176 if (!hapticController_) {
177 auto context = parentNode->GetContext();
178 CHECK_NULL_VOID(context);
179 context->AddAfterLayoutTask([weak = WeakClaim(this)]() {
180 auto pattern = weak.Upgrade();
181 CHECK_NULL_VOID(pattern);
182 pattern->hapticController_ = PickerAudioHapticFactory::GetInstance();
183 });
184 }
185 } else {
186 isEnableHaptic_ = false;
187 if (hapticController_) {
188 hapticController_->Stop();
189 }
190 }
191 }
192
RegisterWindowStateChangedCallback()193 void TextPickerColumnPattern::RegisterWindowStateChangedCallback()
194 {
195 auto host = GetHost();
196 CHECK_NULL_VOID(host);
197 auto pipeline = host->GetContext();
198 CHECK_NULL_VOID(pipeline);
199 pipeline->AddWindowStateChangedCallback(host->GetId());
200 }
201
UnregisterWindowStateChangedCallback(FrameNode * frameNode)202 void TextPickerColumnPattern::UnregisterWindowStateChangedCallback(FrameNode* frameNode)
203 {
204 CHECK_NULL_VOID(frameNode);
205 auto pipeline = frameNode->GetContext();
206 CHECK_NULL_VOID(pipeline);
207 pipeline->RemoveWindowStateChangedCallback(frameNode->GetId());
208 }
209
OnWindowHide()210 void TextPickerColumnPattern::OnWindowHide()
211 {
212 isShow_ = false;
213 if (hapticController_) {
214 hapticController_->Stop();
215 }
216 }
217
StopHapticController()218 void TextPickerColumnPattern::StopHapticController()
219 {
220 if (hapticController_) {
221 hapticController_->Stop();
222 }
223 }
224
OnWindowShow()225 void TextPickerColumnPattern::OnWindowShow()
226 {
227 isShow_ = true;
228 }
229
OnMiddleButtonTouchDown()230 void TextPickerColumnPattern::OnMiddleButtonTouchDown()
231 {
232 PlayPressAnimation(pressColor_);
233 }
234
OnMiddleButtonTouchMove()235 void TextPickerColumnPattern::OnMiddleButtonTouchMove()
236 {
237 PlayPressAnimation(Color::TRANSPARENT);
238 }
239
OnMiddleButtonTouchUp()240 void TextPickerColumnPattern::OnMiddleButtonTouchUp()
241 {
242 PlayPressAnimation(isHover_ ? GetButtonHoverColor() : buttonBgColor_);
243
244 if (useButtonFocusArea_) {
245 FlushCurrentOptions();
246 }
247 }
248
InitSelectorButtonProperties(const RefPtr<PickerTheme> & pickerTheme)249 void TextPickerColumnPattern::InitSelectorButtonProperties(const RefPtr<PickerTheme>& pickerTheme)
250 {
251 CHECK_NULL_VOID(pickerTheme);
252 if (useButtonFocusArea_) {
253 buttonDefaultBgColor_ = pickerTheme->GetSelectorItemNormalBgColor();
254 buttonFocusBgColor_ = pickerTheme->GetSelectorItemFocusBgColor();
255 buttonDefaultBorderColor_ = pickerTheme->GetSelectorItemBorderColor();
256 buttonFocusBorderColor_ = pickerTheme->GetSelectorItemFocusBorderColor();
257 selectorTextFocusColor_ = pickerTheme->GetOptionStyle(true, true).GetTextColor();
258 pressColor_ = buttonDefaultBgColor_.BlendColor(pickerTheme->GetPressColor());
259 hoverColor_ = buttonDefaultBgColor_.BlendColor(pickerTheme->GetHoverColor());
260
261 buttonFocusBorderWidth_ = pickerTheme->GetSelectorItemFocusBorderWidth();
262 buttonDefaultBorderWidth_ = pickerTheme->GetSelectorItemBorderWidth();
263 }
264 }
265
GetButtonHoverColor() const266 const Color& TextPickerColumnPattern::GetButtonHoverColor() const
267 {
268 return useButtonFocusArea_ && isFocusColumn_ ? buttonFocusBgColor_ : hoverColor_;
269 }
270
UpdateColumnButtonFocusState(bool haveFocus,bool needMarkDirty)271 void TextPickerColumnPattern::UpdateColumnButtonFocusState(bool haveFocus, bool needMarkDirty)
272 {
273 auto isInitUpdate = isFirstTimeUpdateButtonProps_ && !haveFocus;
274 auto isFocusChanged = isFocusColumn_ != haveFocus;
275
276 if (isFocusChanged || isInitUpdate) {
277 isFocusColumn_ = haveFocus;
278 UpdateSelectorButtonProps(isFocusColumn_, needMarkDirty);
279 }
280 if (isFocusChanged) {
281 FlushCurrentOptions();
282 }
283 if (isInitUpdate) {
284 isFirstTimeUpdateButtonProps_ = false;
285 }
286 }
287
UpdateSelectorButtonProps(bool haveFocus,bool needMarkDirty)288 void TextPickerColumnPattern::UpdateSelectorButtonProps(bool haveFocus, bool needMarkDirty)
289 {
290 auto host = GetHost();
291 CHECK_NULL_VOID(host);
292 auto blend = host->GetParent();
293 CHECK_NULL_VOID(blend);
294 auto stack = blend->GetParent();
295 CHECK_NULL_VOID(stack);
296 auto buttonNode = DynamicCast<FrameNode>(stack->GetFirstChild());
297 CHECK_NULL_VOID(buttonNode);
298 auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
299 CHECK_NULL_VOID(buttonLayoutProperty);
300 auto renderContext = buttonNode->GetRenderContext();
301 CHECK_NULL_VOID(renderContext);
302
303 BorderWidthProperty borderWidth;
304 BorderColorProperty borderColor;
305
306 if (haveFocus) {
307 buttonBgColor_ = buttonFocusBgColor_;
308 borderWidth.SetBorderWidth(buttonFocusBorderWidth_);
309 borderColor.SetColor(buttonFocusBorderColor_);
310 } else {
311 buttonBgColor_ = buttonDefaultBgColor_;
312 borderWidth.SetBorderWidth(buttonDefaultBorderWidth_);
313 borderColor.SetColor(buttonDefaultBorderColor_);
314 }
315
316 buttonLayoutProperty->UpdateBorderWidth(borderWidth);
317 renderContext->UpdateBorderColor(borderColor);
318 renderContext->UpdateBackgroundColor(buttonBgColor_);
319
320 if (needMarkDirty) {
321 buttonNode->MarkModifyDone();
322 buttonNode->MarkDirtyNode();
323 }
324 }
325
UpdateTextAreaPadding(const RefPtr<PickerTheme> & pickerTheme,const RefPtr<TextLayoutProperty> & textLayoutProperty)326 void TextPickerColumnPattern::UpdateTextAreaPadding(const RefPtr<PickerTheme>& pickerTheme,
327 const RefPtr<TextLayoutProperty>& textLayoutProperty)
328 {
329 if (useButtonFocusArea_) {
330 auto padding = pickerTheme->GetSelectorItemSpace();
331 PaddingProperty defaultPadding = { CalcLength(padding), CalcLength(padding),
332 CalcLength(0.0_vp), CalcLength(0.0_vp) };
333 textLayoutProperty->UpdatePadding(defaultPadding);
334 }
335 }
336
InitTextFadeOut()337 void TextPickerColumnPattern::InitTextFadeOut()
338 {
339 auto host = GetHost();
340 CHECK_NULL_VOID(host);
341 auto context = host->GetContextRefPtr();
342 CHECK_NULL_VOID(context);
343 auto textTheme = context->GetTheme<TextTheme>();
344 CHECK_NULL_VOID(textTheme);
345 isTextFadeOut_ = textTheme->GetIsTextFadeout();
346 }
347
UpdateTextOverflow(bool isSel,const RefPtr<TextLayoutProperty> & textLayoutProperty)348 void TextPickerColumnPattern::UpdateTextOverflow(bool isSel, const RefPtr<TextLayoutProperty>& textLayoutProperty)
349 {
350 if (isTextFadeOut_) {
351 textLayoutProperty->UpdateTextOverflow(TextOverflow::MARQUEE);
352 textLayoutProperty->UpdateTextMarqueeStartPolicy(MarqueeStartPolicy::DEFAULT);
353 textLayoutProperty->UpdateTextMarqueeFadeout(true);
354 textLayoutProperty->UpdateTextMarqueeStart(isSel && (isFocusColumn_ || isHover_));
355 }
356 }
357
GetMiddleButtonIndex()358 int32_t TextPickerColumnPattern::GetMiddleButtonIndex()
359 {
360 return GetShowOptionCount() / 2;
361 }
362
StopHaptic()363 void TextPickerColumnPattern::StopHaptic()
364 {
365 stopHaptic_ = true;
366 }
367
CreateItemTouchEventListener()368 RefPtr<TouchEventImpl> TextPickerColumnPattern::CreateItemTouchEventListener()
369 {
370 auto toss = GetToss();
371 CHECK_NULL_RETURN(toss, nullptr);
372 auto touchCallback = [weak = WeakClaim(this), toss](const TouchEventInfo& info) {
373 auto pattern = weak.Upgrade();
374 CHECK_NULL_VOID(pattern);
375 auto isToss = pattern->GetTossStatus();
376 if (info.GetTouches().empty()) {
377 return;
378 }
379 if (info.GetSourceTool() == SourceTool::MOUSE) {
380 pattern->stopHaptic_ = true;
381 } else {
382 pattern->stopHaptic_ = false;
383 }
384 if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
385 if (isToss) {
386 pattern->touchBreak_ = true;
387 pattern->animationBreak_ = true;
388 pattern->clickBreak_ = true;
389 auto TossEndPosition = toss->GetTossEndPosition();
390 pattern->SetYLast(TossEndPosition);
391 toss->StopTossAnimation();
392 pattern->StopHapticController();
393 } else {
394 pattern->animationBreak_ = false;
395 pattern->clickBreak_ = false;
396 }
397 }
398 if (info.GetTouches().front().GetTouchType() == TouchType::UP) {
399 pattern->touchBreak_ = false;
400 if (pattern->animationBreak_) {
401 pattern->PlayResetAnimation();
402 pattern->yOffset_ = 0.0;
403 }
404 }
405 };
406 auto listener = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
407 return listener;
408 }
409
CreateItemClickEventListener(RefPtr<EventParam> param)410 RefPtr<ClickEvent> TextPickerColumnPattern::CreateItemClickEventListener(RefPtr<EventParam> param)
411 {
412 auto clickEventHandler = [param, weak = WeakClaim(this)](const GestureEvent& /* info */) {
413 auto pattern = weak.Upgrade();
414 pattern->OnAroundButtonClick(param);
415 };
416
417 auto listener = AceType::MakeRefPtr<NG::ClickEvent>(clickEventHandler);
418 return listener;
419 }
420
CreateMouseHoverEventListener(RefPtr<EventParam> param)421 RefPtr<InputEvent> TextPickerColumnPattern::CreateMouseHoverEventListener(RefPtr<EventParam> param)
422 {
423 auto mouseTask = [weak = WeakClaim(this)](bool isHover) {
424 auto pattern = weak.Upgrade();
425 if (pattern) {
426 pattern->HandleMouseEvent(isHover);
427 }
428 };
429 auto hoverEventListener = MakeRefPtr<InputEvent>(std::move(mouseTask));
430 return hoverEventListener;
431 }
432
ParseTouchListener()433 void TextPickerColumnPattern::ParseTouchListener()
434 {
435 auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
436 auto pattern = weak.Upgrade();
437 CHECK_NULL_VOID(pattern);
438 if (info.GetTouches().empty()) {
439 return;
440 }
441 if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
442 pattern->SetLocalDownDistance(info.GetTouches().front().GetLocalLocation().GetDistance());
443 pattern->OnMiddleButtonTouchDown();
444 pattern->SetSelectedMark(true);
445 return;
446 }
447 if (info.GetTouches().front().GetTouchType() == TouchType::UP ||
448 info.GetTouches().front().GetTouchType() == TouchType::CANCEL) {
449 pattern->OnMiddleButtonTouchUp();
450 pattern->SetLocalDownDistance(0.0f);
451 return;
452 }
453 if (info.GetTouches().front().GetTouchType() == TouchType::MOVE) {
454 if (std::abs(info.GetTouches().front().GetLocalLocation().GetDistance() - pattern->GetLocalDownDistance()) >
455 MOVE_DISTANCE) {
456 pattern->OnMiddleButtonTouchUp();
457 }
458 }
459 };
460 touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
461 }
462
ParseMouseEvent()463 void TextPickerColumnPattern::ParseMouseEvent()
464 {
465 auto mouseTask = [weak = WeakClaim(this)](bool isHover) {
466 auto pattern = weak.Upgrade();
467 CHECK_NULL_VOID(pattern);
468 pattern->HandleMouseEvent(isHover);
469 };
470 mouseEvent_ = MakeRefPtr<InputEvent>(std::move(mouseTask));
471 }
472
InitMouseAndPressEvent()473 void TextPickerColumnPattern::InitMouseAndPressEvent()
474 {
475 if (mouseEvent_ || touchListener_) {
476 return;
477 }
478 auto host = GetHost();
479 CHECK_NULL_VOID(host);
480 auto columnEventHub = host->GetOrCreateEventHub<EventHub>();
481 CHECK_NULL_VOID(columnEventHub);
482 RefPtr<TouchEventImpl> touchListener = CreateItemTouchEventListener();
483 CHECK_NULL_VOID(touchListener);
484 auto columnGesture = columnEventHub->GetOrCreateGestureEventHub();
485 CHECK_NULL_VOID(columnGesture);
486 columnGesture->AddTouchEvent(touchListener);
487 auto childSize = static_cast<int32_t>(host->GetChildren().size());
488 RefPtr<FrameNode> middleChild = nullptr;
489 auto midSize = childSize / 2;
490 middleChild = DynamicCast<FrameNode>(host->GetChildAtIndex(midSize));
491 CHECK_NULL_VOID(middleChild);
492 auto eventHub = middleChild->GetOrCreateEventHub<EventHub>();
493 CHECK_NULL_VOID(eventHub);
494 auto inputHub = eventHub->GetOrCreateInputEventHub();
495 ParseMouseEvent();
496 inputHub->AddOnHoverEvent(mouseEvent_);
497 auto gesture = middleChild->GetOrCreateGestureEventHub();
498 CHECK_NULL_VOID(gesture);
499 ParseTouchListener();
500 gesture->AddTouchEvent(touchListener_);
501 int32_t i = 0;
502 for (const auto& child : host->GetChildren()) {
503 RefPtr<FrameNode> childNode = DynamicCast<FrameNode>(child);
504 CHECK_NULL_VOID(childNode);
505 RefPtr<EventParam> param = MakeRefPtr<EventParam>();
506 param->instance = childNode;
507 param->itemIndex = i;
508 param->itemTotalCounts = childSize;
509 auto eventHub = childNode->GetOrCreateEventHub<EventHub>();
510 CHECK_NULL_VOID(eventHub);
511 if (i != midSize) {
512 RefPtr<ClickEvent> clickListener = CreateItemClickEventListener(param);
513 CHECK_NULL_VOID(clickListener);
514 auto gesture = eventHub->GetOrCreateGestureEventHub();
515 CHECK_NULL_VOID(gesture);
516 gesture->AddClickEvent(clickListener);
517 }
518 i++;
519 }
520 }
521
HandleMouseEvent(bool isHover)522 void TextPickerColumnPattern::HandleMouseEvent(bool isHover)
523 {
524 PlayPressAnimation(isHover ? GetButtonHoverColor() : buttonBgColor_);
525 auto needUpdate = isHover_ != isHover;
526 isHover_ = isHover;
527
528 if (useButtonFocusArea_ && needUpdate) {
529 FlushCurrentOptions();
530 }
531 }
532
SetButtonBackgroundColor(const Color & pressColor)533 void TextPickerColumnPattern::SetButtonBackgroundColor(const Color& pressColor)
534 {
535 auto pipeline = GetContext();
536 CHECK_NULL_VOID(pipeline);
537 auto pickerTheme = pipeline->GetTheme<PickerTheme>();
538 CHECK_NULL_VOID(pickerTheme);
539 CHECK_EQUAL_VOID(pickerTheme->IsCircleDial(), true);
540
541 auto host = GetHost();
542 CHECK_NULL_VOID(host);
543 auto blend = host->GetParent();
544 CHECK_NULL_VOID(blend);
545 auto stack = blend->GetParent();
546 CHECK_NULL_VOID(stack);
547 auto buttonNode = DynamicCast<FrameNode>(stack->GetFirstChild());
548 auto renderContext = buttonNode->GetRenderContext();
549 renderContext->UpdateBackgroundColor(pressColor);
550 buttonNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
551 }
552
PlayPressAnimation(const Color & pressColor)553 void TextPickerColumnPattern::PlayPressAnimation(const Color& pressColor)
554 {
555 AnimationOption option = AnimationOption();
556 option.SetDuration(HOVER_ANIMATION_DURATION);
557 option.SetFillMode(FillMode::FORWARDS);
558 auto host = GetHost();
559 auto context = host? host->GetContextRefPtr(): nullptr;
560 AnimationUtils::Animate(option, [weak = AceType::WeakClaim(this), pressColor]() {
561 auto picker = weak.Upgrade();
562 if (picker) {
563 picker->SetButtonBackgroundColor(pressColor);
564 }
565 }, nullptr, nullptr, context);
566 }
567
GetShowOptionCount() const568 uint32_t TextPickerColumnPattern::GetShowOptionCount() const
569 {
570 auto host = GetHost();
571 CHECK_NULL_RETURN(host, 0);
572 auto context = host->GetContext();
573 CHECK_NULL_RETURN(context, 0);
574 auto pickerTheme = context->GetTheme<PickerTheme>();
575 CHECK_NULL_RETURN(pickerTheme, 0);
576 auto showCount = pickerTheme->GetShowOptionCount() + BUFFER_NODE_NUMBER;
577 return showCount;
578 }
579
ResetOptionPropertyHeight()580 void TextPickerColumnPattern::ResetOptionPropertyHeight()
581 {
582 if (needOptionPropertyHeightReset_) {
583 auto host = GetHost();
584 CHECK_NULL_VOID(host);
585 auto blendNode = DynamicCast<FrameNode>(host->GetParent());
586 CHECK_NULL_VOID(blendNode);
587 auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
588 CHECK_NULL_VOID(stackNode);
589 auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
590 CHECK_NULL_VOID(parentNode);
591 auto textPickerLayoutProperty = parentNode->GetLayoutProperty<TextPickerLayoutProperty>();
592 CHECK_NULL_VOID(textPickerLayoutProperty);
593 bool isDefaultPickerItemHeight_ = false;
594 if (textPickerLayoutProperty->HasDefaultPickerItemHeight()) {
595 auto defaultPickerItemHeightValue = textPickerLayoutProperty->GetDefaultPickerItemHeightValue();
596 isDefaultPickerItemHeight_ = LessOrEqual(defaultPickerItemHeightValue.Value(), 0.0) ? false : true;
597 }
598 if (isDefaultPickerItemHeight_) {
599 auto pickerItemHeight = 0.0;
600 auto pattern = parentNode->GetPattern<TextPickerPattern>();
601 CHECK_NULL_VOID(pattern);
602 pickerItemHeight =
603 pattern->GetResizeFlag() ? pattern->GetResizePickerItemHeight() : pattern->GetDefaultPickerItemHeight();
604 int32_t itemCounts = static_cast<int32_t>(GetShowOptionCount());
605 for (int32_t i = 0; i < itemCounts; i++) {
606 TextPickerOptionProperty& prop = optionProperties_[i];
607 prop.height = pickerItemHeight;
608 }
609 SetOptionShiftDistance();
610 }
611 needOptionPropertyHeightReset_ = false;
612 }
613 }
614
InitTextFontFamily()615 void TextPickerColumnPattern::InitTextFontFamily()
616 {
617 auto host = GetHost();
618 CHECK_NULL_VOID(host);
619 auto blendNode = DynamicCast<FrameNode>(host->GetParent());
620 CHECK_NULL_VOID(blendNode);
621 auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
622 CHECK_NULL_VOID(stackNode);
623 auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
624 CHECK_NULL_VOID(parentNode);
625 auto pipeline = parentNode->GetContext();
626 CHECK_NULL_VOID(pipeline);
627 auto pattern = parentNode->GetPattern<TextPickerPattern>();
628 CHECK_NULL_VOID(pattern);
629 auto textPickerLayoutProperty = parentNode->GetLayoutProperty<TextPickerLayoutProperty>();
630 CHECK_NULL_VOID(textPickerLayoutProperty);
631 hasUserDefinedDisappearFontFamily_ = pattern->GetHasUserDefinedDisappearFontFamily();
632 hasUserDefinedNormalFontFamily_ = pattern->GetHasUserDefinedNormalFontFamily();
633 hasUserDefinedSelectedFontFamily_ = pattern->GetHasUserDefinedSelectedFontFamily();
634 auto fontManager = pipeline->GetFontManager();
635 CHECK_NULL_VOID(fontManager);
636 if (!(fontManager->GetAppCustomFont().empty())) {
637 hasAppCustomFont_ = true;
638 }
639 auto appCustomFontFamily = Framework::ConvertStrToFontFamilies(fontManager->GetAppCustomFont());
640 if (hasAppCustomFont_ && !hasUserDefinedDisappearFontFamily_) {
641 textPickerLayoutProperty->UpdateDisappearFontFamily(appCustomFontFamily);
642 }
643 if (hasAppCustomFont_ && !hasUserDefinedNormalFontFamily_) {
644 textPickerLayoutProperty->UpdateFontFamily(appCustomFontFamily);
645 }
646 if (hasAppCustomFont_ && !hasUserDefinedSelectedFontFamily_) {
647 textPickerLayoutProperty->UpdateSelectedFontFamily(appCustomFontFamily);
648 }
649 }
650
FlushCurrentOptions(bool isDown,bool isUpdateTextContentOnly,bool isDirectlyClear,bool isUpdateAnimationProperties)651 void TextPickerColumnPattern::FlushCurrentOptions(
652 bool isDown, bool isUpdateTextContentOnly, bool isDirectlyClear, bool isUpdateAnimationProperties)
653 {
654 ResetOptionPropertyHeight();
655
656 auto host = GetHost();
657 CHECK_NULL_VOID(host);
658 auto blendNode = DynamicCast<FrameNode>(host->GetParent());
659 CHECK_NULL_VOID(blendNode);
660 auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
661 CHECK_NULL_VOID(stackNode);
662 auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
663 CHECK_NULL_VOID(parentNode);
664 auto textPickerLayoutProperty = parentNode->GetLayoutProperty<TextPickerLayoutProperty>();
665 CHECK_NULL_VOID(textPickerLayoutProperty);
666
667 InitTextFontFamily();
668
669 if (!isUpdateTextContentOnly) {
670 animationProperties_.clear();
671 }
672 if (columnKind_ == TEXT) {
673 FlushCurrentTextOptions(textPickerLayoutProperty, isUpdateTextContentOnly, isDirectlyClear);
674 } else if (columnKind_ == ICON) {
675 FlushCurrentImageOptions();
676 } else if (columnKind_ == MIXTURE) {
677 FlushCurrentMixtureOptions(textPickerLayoutProperty, isUpdateTextContentOnly);
678 }
679 if (isUpdateTextContentOnly && isUpdateAnimationProperties) {
680 FlushAnimationTextProperties(isDown);
681 }
682 }
683
ClearCurrentTextOptions(const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty,bool isUpdateTextContentOnly,bool isDirectlyClear)684 void TextPickerColumnPattern::ClearCurrentTextOptions(const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty,
685 bool isUpdateTextContentOnly, bool isDirectlyClear)
686 {
687 if (isDirectlyClear) {
688 auto host = GetHost();
689 CHECK_NULL_VOID(host);
690 auto child = host->GetChildren();
691 for (auto iter = child.begin(); iter != child.end(); iter++) {
692 auto textNode = DynamicCast<FrameNode>(*iter);
693 CHECK_NULL_VOID(textNode);
694 auto textPattern = textNode->GetPattern<TextPattern>();
695 CHECK_NULL_VOID(textPattern);
696 auto textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
697 CHECK_NULL_VOID(textLayoutProperty);
698 textLayoutProperty->UpdateContent(u"");
699 textNode->GetRenderContext()->SetClipToFrame(true);
700 textNode->MarkModifyDone();
701 textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
702 }
703 selectedIndex_ = 0;
704 }
705 }
706
FlushCurrentTextOptions(const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty,bool isUpdateTextContentOnly,bool isDirectlyClear)707 void TextPickerColumnPattern::FlushCurrentTextOptions(const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty,
708 bool isUpdateTextContentOnly, bool isDirectlyClear)
709 {
710 ClearCurrentTextOptions(textPickerLayoutProperty, isUpdateTextContentOnly, isDirectlyClear);
711 uint32_t totalOptionCount = GetOptionCount();
712 if (totalOptionCount == 0) {
713 return;
714 }
715 uint32_t currentIndex = GetCurrentIndex();
716 currentIndex = currentIndex % totalOptionCount;
717 uint32_t showCount = GetShowOptionCount();
718 auto middleIndex = showCount / 2; // the center option is selected.
719 auto host = GetHost();
720 CHECK_NULL_VOID(host);
721 auto child = host->GetChildren();
722 auto iter = child.begin();
723 if (child.size() != showCount) {
724 return;
725 }
726 for (uint32_t index = 0; index < showCount; index++) {
727 uint32_t optionIndex = (totalOptionCount + currentIndex + index - middleIndex) % totalOptionCount;
728 RangeContent optionValue = options_[optionIndex];
729 int32_t diffIndex = static_cast<int32_t>(index) - static_cast<int32_t>(middleIndex);
730 int32_t virtualIndex = static_cast<int32_t>(currentIndex) + diffIndex;
731 bool virtualIndexValidate = virtualIndex >= 0 && virtualIndex < static_cast<int32_t>(totalOptionCount);
732 auto textNode = DynamicCast<FrameNode>(*iter);
733 CHECK_NULL_VOID(textNode);
734 auto textPattern = textNode->GetPattern<TextPattern>();
735 CHECK_NULL_VOID(textPattern);
736 auto textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
737 CHECK_NULL_VOID(textLayoutProperty);
738 UpdateTextOverflow(index == middleIndex, textLayoutProperty);
739 if (!isUpdateTextContentOnly) {
740 UpdatePickerTextProperties(textLayoutProperty, textPickerLayoutProperty, index, middleIndex, showCount);
741 }
742 if (NotLoopOptions() && !virtualIndexValidate) {
743 textLayoutProperty->UpdateContent(u"");
744 } else {
745 textLayoutProperty->UpdateContent(optionValue.text_);
746 textLayoutProperty->UpdateTextAlign(TextAlign::CENTER);
747 }
748 UpdateTextAccessibilityProperty(virtualIndex, iter, virtualIndexValidate);
749 textNode->GetRenderContext()->SetClipToFrame(true);
750 textNode->MarkModifyDone();
751 textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
752 iter++;
753 }
754 selectedIndex_ = currentIndex;
755 }
756
UpdateTextAccessibilityProperty(int32_t virtualIndex,std::list<RefPtr<UINode>>::iterator & iter,bool virtualIndexValidate)757 void TextPickerColumnPattern::UpdateTextAccessibilityProperty(
758 int32_t virtualIndex, std::list<RefPtr<UINode>>::iterator& iter, bool virtualIndexValidate)
759 {
760 auto textNode = DynamicCast<FrameNode>(*(iter));
761 CHECK_NULL_VOID(textNode);
762 auto accessibilityProperty = textNode->GetAccessibilityProperty<AccessibilityProperty>();
763 CHECK_NULL_VOID(accessibilityProperty);
764 if (!NotLoopOptions() || virtualIndexValidate) {
765 accessibilityProperty->SetAccessibilityLevel(AccessibilityProperty::Level::AUTO);
766 return;
767 }
768 accessibilityProperty->SetAccessibilityLevel(AccessibilityProperty::Level::NO_STR);
769 auto isFocus = accessibilityProperty->GetAccessibilityFocusState();
770 if (virtualIndex == -1 && isFocus) {
771 auto nextTextNode = DynamicCast<FrameNode>(*(++iter));
772 if (nextTextNode) {
773 nextTextNode->OnAccessibilityEvent(AccessibilityEventType::REQUEST_FOCUS);
774 }
775 --iter;
776 } else if (virtualIndex == static_cast<int32_t>(GetOptionCount()) && isFocus) {
777 auto preTextNode = DynamicCast<FrameNode>(*(--iter));
778 if (preTextNode) {
779 preTextNode->OnAccessibilityEvent(AccessibilityEventType::REQUEST_FOCUS);
780 }
781 ++iter;
782 }
783 }
784
FlushCurrentImageOptions()785 void TextPickerColumnPattern::FlushCurrentImageOptions()
786 {
787 uint32_t totalOptionCount = GetOptionCount();
788 if (totalOptionCount == 0) {
789 return;
790 }
791 uint32_t currentIndex = GetCurrentIndex();
792 currentIndex = currentIndex % totalOptionCount;
793 uint32_t showCount = GetShowOptionCount();
794 auto middleIndex = showCount / 2; // the center option is selected.
795 auto host = GetHost();
796 CHECK_NULL_VOID(host);
797 auto child = host->GetChildren();
798 auto iter = child.begin();
799 if (child.size() != showCount) {
800 return;
801 }
802 for (uint32_t index = 0; index < showCount; index++) {
803 uint32_t optionIndex = (totalOptionCount + currentIndex + index - middleIndex) % totalOptionCount;
804 RangeContent optionValue = options_[optionIndex];
805 int32_t diffIndex = static_cast<int32_t>(index) - static_cast<int32_t>(middleIndex);
806 int32_t virtualIndex = static_cast<int32_t>(currentIndex) + diffIndex;
807 bool virtualIndexValidate = virtualIndex >= 0 && virtualIndex < static_cast<int32_t>(totalOptionCount);
808 auto rangeNode = DynamicCast<FrameNode>(*iter);
809 CHECK_NULL_VOID(rangeNode);
810 auto iconNode = DynamicCast<FrameNode>(rangeNode->GetFirstChild());
811 CHECK_NULL_VOID(iconNode);
812 auto iconPattern = iconNode->GetPattern<ImagePattern>();
813 CHECK_NULL_VOID(iconPattern);
814 auto iconLayoutProperty = iconPattern->GetLayoutProperty<ImageLayoutProperty>();
815 CHECK_NULL_VOID(iconLayoutProperty);
816 CalcSize idealSize = { CalcSize(CalcLength(ICON_SIZE), CalcLength(ICON_SIZE)) };
817 MeasureProperty layoutConstraint;
818 layoutConstraint.selfIdealSize = idealSize;
819 iconLayoutProperty->UpdateCalcLayoutProperty(layoutConstraint);
820 if (NotLoopOptions() && !virtualIndexValidate) {
821 iconLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
822 } else {
823 iconLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
824 iconLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(optionValue.icon_));
825 }
826 UpdateTextAccessibilityProperty(virtualIndex, iter, virtualIndexValidate);
827 iconNode->MarkModifyDone();
828 iconNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
829
830 rangeNode->GetRenderContext()->SetClipToFrame(true);
831 rangeNode->MarkModifyDone();
832 rangeNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
833 iter++;
834 }
835 selectedIndex_ = currentIndex;
836 }
837
FlushCurrentMixtureOptions(const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty,bool isUpdateTextContentOnly)838 void TextPickerColumnPattern::FlushCurrentMixtureOptions(
839 const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty, bool isUpdateTextContentOnly)
840 {
841 uint32_t totalOptionCount = GetOptionCount();
842 if (totalOptionCount == 0) {
843 return;
844 }
845 uint32_t currentIndex = GetCurrentIndex();
846 currentIndex = currentIndex % totalOptionCount;
847 uint32_t showCount = GetShowOptionCount();
848 auto middleIndex = showCount / 2; // the center option is selected.
849 auto host = GetHost();
850 CHECK_NULL_VOID(host);
851 auto child = host->GetChildren();
852 auto iter = child.begin();
853 if (child.size() != showCount) {
854 return;
855 }
856 for (uint32_t index = 0; index < showCount; index++) {
857 uint32_t optionIndex = (totalOptionCount + currentIndex + index - middleIndex) % totalOptionCount;
858 RangeContent optionValue = options_[optionIndex];
859 int32_t diffIndex = static_cast<int32_t>(index) - static_cast<int32_t>(middleIndex);
860 int32_t virtualIndex = static_cast<int32_t>(currentIndex) + diffIndex;
861 bool virtualIndexValidate = virtualIndex >= 0 && virtualIndex < static_cast<int32_t>(totalOptionCount);
862 auto linearLayoutNode = DynamicCast<FrameNode>(*iter);
863 CHECK_NULL_VOID(linearLayoutNode);
864 auto children = linearLayoutNode->GetChildren();
865 if (children.size() != MIXTURE_CHILD_COUNT) {
866 continue;
867 }
868 auto iconNode = DynamicCast<FrameNode>(linearLayoutNode->GetFirstChild());
869 auto iconPattern = iconNode->GetPattern<ImagePattern>();
870 CHECK_NULL_VOID(iconPattern);
871 iconPattern->SetSyncLoad(true);
872 auto iconLayoutProperty = iconPattern->GetLayoutProperty<ImageLayoutProperty>();
873 CHECK_NULL_VOID(iconLayoutProperty);
874 auto iconLayoutDirection = iconLayoutProperty->GetNonAutoLayoutDirection();
875 CalcSize idealSize = { CalcSize(CalcLength(ICON_SIZE), CalcLength(ICON_SIZE)) };
876 MeasureProperty layoutConstraint;
877 layoutConstraint.selfIdealSize = idealSize;
878 iconLayoutProperty->UpdateCalcLayoutProperty(layoutConstraint);
879 MarginProperty margin;
880 margin.right = CalcLength(ICON_TEXT_SPACE);
881 bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
882 if (isRtl || iconLayoutDirection == TextDirection::RTL) {
883 margin.left = CalcLength(ICON_TEXT_SPACE);
884 }
885 iconLayoutProperty->UpdateMargin(margin);
886
887 auto textNode = DynamicCast<FrameNode>(linearLayoutNode->GetLastChild());
888 auto textPattern = textNode->GetPattern<TextPattern>();
889 CHECK_NULL_VOID(textPattern);
890 auto textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
891 CHECK_NULL_VOID(textLayoutProperty);
892 UpdateTextOverflow(index == middleIndex, textLayoutProperty);
893 if (!isUpdateTextContentOnly) {
894 UpdatePickerTextProperties(textLayoutProperty, textPickerLayoutProperty, index, middleIndex, showCount);
895 }
896 if (NotLoopOptions() && !virtualIndexValidate) {
897 iconLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
898 textLayoutProperty->UpdateContent(u"");
899 } else {
900 textLayoutProperty->UpdateContent(optionValue.text_);
901 iconLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
902 iconLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(optionValue.icon_));
903 }
904 UpdateTextAccessibilityProperty(virtualIndex, iter, virtualIndexValidate);
905 iconNode->MarkModifyDone();
906 iconNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
907 textNode->MarkModifyDone();
908 textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
909
910 linearLayoutNode->GetRenderContext()->SetClipToFrame(true);
911 linearLayoutNode->MarkModifyDone();
912 linearLayoutNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
913 iter++;
914 }
915 selectedIndex_ = currentIndex;
916 }
917
FlushAnimationTextProperties(bool isDown)918 void TextPickerColumnPattern::FlushAnimationTextProperties(bool isDown)
919 {
920 const size_t size = animationProperties_.size();
921 if (size == 0) {
922 return;
923 }
924 if (isDown) {
925 for (size_t i = 0; i < size; i++) {
926 if (i > 0) {
927 animationProperties_[i - 1].upFontSize = animationProperties_[i].upFontSize;
928 animationProperties_[i - 1].fontSize = animationProperties_[i].fontSize;
929 animationProperties_[i - 1].downFontSize = animationProperties_[i].downFontSize;
930 animationProperties_[i - 1].upColor = animationProperties_[i].upColor;
931 animationProperties_[i - 1].currentColor = animationProperties_[i].currentColor;
932 animationProperties_[i - 1].downColor = animationProperties_[i].downColor;
933 }
934 if (i + 1 == size) {
935 animationProperties_[i].upFontSize = animationProperties_[i].fontSize;
936 animationProperties_[i].fontSize = animationProperties_[i].fontSize * 0.5;
937 animationProperties_[i].downFontSize = Dimension();
938 animationProperties_[i].upColor = animationProperties_[i].currentColor;
939 auto colorEvaluator = AceType::MakeRefPtr<LinearEvaluator<Color>>();
940 animationProperties_[i].currentColor =
941 colorEvaluator->Evaluate(Color(), animationProperties_[i].currentColor, 0.5);
942 animationProperties_[i].downColor = Color();
943 }
944 }
945 } else {
946 for (size_t i = size - 1;; i--) {
947 if (i == 0) {
948 animationProperties_[i].upFontSize = Dimension();
949 animationProperties_[i].downFontSize = animationProperties_[i].fontSize;
950 animationProperties_[i].fontSize = animationProperties_[i].fontSize * 0.5;
951 animationProperties_[i].upColor = Color();
952 animationProperties_[i].downColor = animationProperties_[i].currentColor;
953 auto colorEvaluator = AceType::MakeRefPtr<LinearEvaluator<Color>>();
954 animationProperties_[i].currentColor =
955 colorEvaluator->Evaluate(Color(), animationProperties_[i].currentColor, 0.5);
956 break;
957 } else {
958 animationProperties_[i].upFontSize = animationProperties_[i - 1].upFontSize;
959 animationProperties_[i].fontSize = animationProperties_[i - 1].fontSize;
960 animationProperties_[i].downFontSize = animationProperties_[i - 1].downFontSize;
961 animationProperties_[i].upColor = animationProperties_[i - 1].upColor;
962 animationProperties_[i].currentColor = animationProperties_[i - 1].currentColor;
963 animationProperties_[i].downColor = animationProperties_[i - 1].downColor;
964 }
965 }
966 }
967 }
968
UpdateDisappearTextProperties(const RefPtr<PickerTheme> & pickerTheme,const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty)969 void TextPickerColumnPattern::UpdateDisappearTextProperties(const RefPtr<PickerTheme>& pickerTheme,
970 const RefPtr<TextLayoutProperty>& textLayoutProperty,
971 const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty)
972 {
973 UpdateTextAreaPadding(pickerTheme, textLayoutProperty);
974 auto normalOptionSize = pickerTheme->GetOptionStyle(false, false).GetFontSize();
975 textLayoutProperty->UpdateTextColor(textPickerLayoutProperty->GetDisappearColor().value_or(
976 pickerTheme->GetOptionStyle(false, false).GetTextColor()));
977 if (textPickerLayoutProperty->HasDisappearFontSize()) {
978 textLayoutProperty->UpdateFontSize(textPickerLayoutProperty->GetDisappearFontSize().value());
979 textLayoutProperty->UpdateAdaptMaxFontSize(Dimension());
980 textLayoutProperty->UpdateAdaptMinFontSize(Dimension());
981 } else {
982 textLayoutProperty->UpdateAdaptMaxFontSize(normalOptionSize);
983 textLayoutProperty->UpdateAdaptMinFontSize(pickerTheme->GetOptionStyle(false, false).GetAdaptMinFontSize());
984 }
985 textLayoutProperty->UpdateFontWeight(textPickerLayoutProperty->GetDisappearWeight().value_or(
986 pickerTheme->GetOptionStyle(false, false).GetFontWeight()));
987 auto fontFamilyVector = textPickerLayoutProperty->GetDisappearFontFamily().value_or(
988 pickerTheme->GetOptionStyle(false, false).GetFontFamilies());
989 textLayoutProperty->UpdateFontFamily(fontFamilyVector.empty() ? FONT_FAMILY_DEFAULT : fontFamilyVector);
990 textLayoutProperty->UpdateItalicFontStyle(textPickerLayoutProperty->GetDisappearFontStyle().value_or(
991 pickerTheme->GetOptionStyle(false, false).GetFontStyle()));
992
993 if (textPickerLayoutProperty->GetDisappearMinFontSize().has_value()) {
994 textLayoutProperty->UpdateAdaptMinFontSize(textPickerLayoutProperty->GetDisappearMinFontSize().value());
995 }
996 if (textPickerLayoutProperty->GetDisappearMaxFontSize().has_value()) {
997 textLayoutProperty->UpdateAdaptMaxFontSize(textPickerLayoutProperty->GetDisappearMaxFontSize().value());
998 }
999 textLayoutProperty->UpdateHeightAdaptivePolicy(TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST);
1000 if (textPickerLayoutProperty->GetDisappearTextOverflow().has_value() &&
1001 textPickerLayoutProperty->GetDisappearTextOverflow().value() != TextOverflow::MARQUEE) {
1002 textLayoutProperty->UpdateTextOverflow(textPickerLayoutProperty->GetDisappearTextOverflow().value());
1003 } else {
1004 textLayoutProperty->UpdateTextOverflow(TextOverflow::CLIP);
1005 }
1006 }
1007
UpdateCandidateTextProperties(const RefPtr<PickerTheme> & pickerTheme,const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty)1008 void TextPickerColumnPattern::UpdateCandidateTextProperties(const RefPtr<PickerTheme>& pickerTheme,
1009 const RefPtr<TextLayoutProperty>& textLayoutProperty,
1010 const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty)
1011 {
1012 UpdateTextAreaPadding(pickerTheme, textLayoutProperty);
1013 auto focusOptionSize = pickerTheme->GetOptionStyle(false, false).GetFontSize() + FONT_SIZE;
1014 textLayoutProperty->UpdateTextColor(
1015 textPickerLayoutProperty->GetColor().value_or(pickerTheme->GetOptionStyle(false, false).GetTextColor()));
1016 if (textPickerLayoutProperty->HasFontSize()) {
1017 textLayoutProperty->UpdateFontSize(textPickerLayoutProperty->GetFontSize().value());
1018 textLayoutProperty->UpdateAdaptMaxFontSize(Dimension());
1019 textLayoutProperty->UpdateAdaptMinFontSize(Dimension());
1020 } else {
1021 textLayoutProperty->UpdateAdaptMaxFontSize(focusOptionSize);
1022 textLayoutProperty->UpdateAdaptMinFontSize(
1023 pickerTheme->GetOptionStyle(true, false).GetAdaptMinFontSize() - FOCUS_SIZE);
1024 }
1025 textLayoutProperty->UpdateFontWeight(
1026 textPickerLayoutProperty->GetWeight().value_or(pickerTheme->GetOptionStyle(false, false).GetFontWeight()));
1027 auto fontFamilyVector = textPickerLayoutProperty->GetFontFamily().value_or(
1028 pickerTheme->GetOptionStyle(false, false).GetFontFamilies());
1029 textLayoutProperty->UpdateFontFamily(fontFamilyVector.empty() ? FONT_FAMILY_DEFAULT : fontFamilyVector);
1030 textLayoutProperty->UpdateItalicFontStyle(
1031 textPickerLayoutProperty->GetFontStyle().value_or(pickerTheme->GetOptionStyle(false, false).GetFontStyle()));
1032
1033 if (textPickerLayoutProperty->GetMinFontSize().has_value()) {
1034 textLayoutProperty->UpdateAdaptMinFontSize(textPickerLayoutProperty->GetMinFontSize().value());
1035 }
1036 if (textPickerLayoutProperty->GetMaxFontSize().has_value()) {
1037 textLayoutProperty->UpdateAdaptMaxFontSize(textPickerLayoutProperty->GetMaxFontSize().value());
1038 }
1039 textLayoutProperty->UpdateHeightAdaptivePolicy(TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST);
1040 if (textPickerLayoutProperty->GetTextOverflow().has_value() &&
1041 textPickerLayoutProperty->GetTextOverflow().value() != TextOverflow::MARQUEE) {
1042 textLayoutProperty->UpdateTextOverflow(textPickerLayoutProperty->GetTextOverflow().value());
1043 } else {
1044 textLayoutProperty->UpdateTextOverflow(TextOverflow::CLIP);
1045 }
1046 }
1047
UpdateSelectedTextProperties(const RefPtr<PickerTheme> & pickerTheme,const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty)1048 void TextPickerColumnPattern::UpdateSelectedTextProperties(const RefPtr<PickerTheme>& pickerTheme,
1049 const RefPtr<TextLayoutProperty>& textLayoutProperty,
1050 const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty)
1051 {
1052 UpdateTextAreaPadding(pickerTheme, textLayoutProperty);
1053 auto selectedOptionSize = pickerTheme->GetOptionStyle(true, false).GetFontSize();
1054
1055 if (pickerTheme->IsCircleDial() && !isUserSetSelectColor_) {
1056 if (selectedMarkPaint_) {
1057 textLayoutProperty->UpdateTextColor(pickerTheme->GetOptionStyle(true, true).GetTextColor());
1058 } else {
1059 textLayoutProperty->UpdateTextColor(pickerTheme->GetOptionStyle(false, false).GetTextColor());
1060 }
1061 } else {
1062 textLayoutProperty->UpdateTextColor(textPickerLayoutProperty->GetSelectedColor().value_or(
1063 pickerTheme->GetOptionStyle(true, false).GetTextColor()));
1064 }
1065
1066 if (textPickerLayoutProperty->HasSelectedFontSize()) {
1067 textLayoutProperty->UpdateFontSize(textPickerLayoutProperty->GetSelectedFontSize().value());
1068 textLayoutProperty->UpdateAdaptMaxFontSize(Dimension());
1069 textLayoutProperty->UpdateAdaptMinFontSize(Dimension());
1070 } else {
1071 textLayoutProperty->UpdateAdaptMaxFontSize(selectedOptionSize);
1072 textLayoutProperty->UpdateAdaptMinFontSize(pickerTheme->GetOptionStyle(true, false).GetAdaptMinFontSize());
1073 }
1074 textLayoutProperty->UpdateFontWeight(textPickerLayoutProperty->GetSelectedWeight().value_or(
1075 pickerTheme->GetOptionStyle(true, false).GetFontWeight()));
1076 auto fontFamilyVector = textPickerLayoutProperty->GetSelectedFontFamily().value_or(
1077 pickerTheme->GetOptionStyle(true, false).GetFontFamilies());
1078 textLayoutProperty->UpdateFontFamily(fontFamilyVector.empty() ? FONT_FAMILY_DEFAULT : fontFamilyVector);
1079 textLayoutProperty->UpdateItalicFontStyle(textPickerLayoutProperty->GetSelectedFontStyle().value_or(
1080 pickerTheme->GetOptionStyle(true, false).GetFontStyle()));
1081
1082 if (textPickerLayoutProperty->GetSelectedMinFontSize().has_value()) {
1083 textLayoutProperty->UpdateAdaptMinFontSize(textPickerLayoutProperty->GetSelectedMinFontSize().value());
1084 }
1085 if (textPickerLayoutProperty->GetSelectedMaxFontSize().has_value()) {
1086 textLayoutProperty->UpdateAdaptMaxFontSize(textPickerLayoutProperty->GetSelectedMaxFontSize().value());
1087 }
1088 textLayoutProperty->UpdateHeightAdaptivePolicy(TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST);
1089 if (textPickerLayoutProperty->GetSelectedTextOverflow().has_value() &&
1090 textPickerLayoutProperty->GetSelectedTextOverflow().value() != TextOverflow::MARQUEE) {
1091 textLayoutProperty->UpdateTextOverflow(textPickerLayoutProperty->GetSelectedTextOverflow().value());
1092 } else {
1093 textLayoutProperty->UpdateTextOverflow(TextOverflow::CLIP);
1094 }
1095 }
1096
UpdateDefaultTextProperties(const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty,uint32_t currentIndex,uint32_t middleIndex)1097 void TextPickerColumnPattern::UpdateDefaultTextProperties(const RefPtr<TextLayoutProperty>& textLayoutProperty,
1098 const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty, uint32_t currentIndex, uint32_t middleIndex)
1099 {
1100 CHECK_NULL_VOID(textLayoutProperty);
1101 CHECK_NULL_VOID(textPickerLayoutProperty);
1102 auto host = GetHost();
1103 CHECK_NULL_VOID(host);
1104 auto context = host->GetContext();
1105 CHECK_NULL_VOID(context);
1106 auto theme = context->GetTheme<TextTheme>();
1107 CHECK_NULL_VOID(theme);
1108 auto textStyle = theme->GetTextStyle();
1109 textLayoutProperty->UpdateFontSize(
1110 textPickerLayoutProperty->GetDefaultFontSize().value_or(textStyle.GetFontSize()));
1111 textLayoutProperty->UpdateFontWeight(
1112 textPickerLayoutProperty->GetDefaultWeight().value_or(textStyle.GetFontWeight()));
1113 textLayoutProperty->UpdateTextColor(textPickerLayoutProperty->GetDefaultColor().value_or(textStyle.GetTextColor()));
1114 textLayoutProperty->UpdateFontFamily(
1115 textPickerLayoutProperty->GetDefaultFontFamily().value_or(textStyle.GetFontFamilies()));
1116 textLayoutProperty->UpdateItalicFontStyle(
1117 textPickerLayoutProperty->GetDefaultFontStyle().value_or(textStyle.GetFontStyle()));
1118 textLayoutProperty->UpdateAdaptMinFontSize(textPickerLayoutProperty->GetDefaultMinFontSize().value_or(Dimension()));
1119 textLayoutProperty->UpdateAdaptMaxFontSize(textPickerLayoutProperty->GetDefaultMaxFontSize().value_or(Dimension()));
1120 if (textPickerLayoutProperty->GetDefaultTextOverflow().has_value() &&
1121 textPickerLayoutProperty->GetDefaultTextOverflow().value() != TextOverflow::MARQUEE) {
1122 textLayoutProperty->UpdateTextOverflow(textPickerLayoutProperty->GetDefaultTextOverflow().value());
1123 } else {
1124 textLayoutProperty->UpdateTextOverflow(textStyle.GetTextOverflow());
1125 }
1126 textLayoutProperty->UpdateHeightAdaptivePolicy(TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST);
1127 textLayoutProperty->UpdateMaxLines(1);
1128 textLayoutProperty->UpdateAlignment(Alignment::CENTER);
1129
1130 CHECK_EQUAL_VOID(optionProperties_.empty(), true);
1131 InitTextHeightAndFontHeight(currentIndex, middleIndex, optionProperties_[currentIndex]);
1132
1133 bool isLandscape = static_cast<int32_t>(GetShowOptionCount()) == OPTION_COUNT_PHONE_LANDSCAPE + BUFFER_NODE_NUMBER;
1134 SetOptionShiftDistanceByIndex(currentIndex, isLandscape);
1135 }
1136
AddAnimationTextProperties(uint32_t currentIndex,const RefPtr<TextLayoutProperty> & textLayoutProperty)1137 void TextPickerColumnPattern::AddAnimationTextProperties(
1138 uint32_t currentIndex, const RefPtr<TextLayoutProperty>& textLayoutProperty)
1139 {
1140 TextProperties properties{};
1141 if (textLayoutProperty->HasFontSize()) {
1142 MeasureContext measureContext;
1143 measureContext.textContent = MEASURE_STRING;
1144 measureContext.fontSize = textLayoutProperty->GetFontSize().value();
1145 if (textLayoutProperty->HasFontFamily()) {
1146 auto fontFamilyVector = textLayoutProperty->GetFontFamily().value();
1147 if (fontFamilyVector.empty()) {
1148 measureContext.fontFamily = FONT_FAMILY_DEFAULT[0];
1149 } else {
1150 measureContext.fontFamily = fontFamilyVector[0];
1151 }
1152 } else {
1153 measureContext.fontFamily = FONT_FAMILY_DEFAULT[0];
1154 }
1155 auto size = MeasureUtil::MeasureTextSize(measureContext);
1156 if (!optionProperties_.empty()) {
1157 optionProperties_[currentIndex].fontheight = size.Height();
1158 if (optionProperties_[currentIndex].fontheight > optionProperties_[currentIndex].height) {
1159 optionProperties_[currentIndex].fontheight = optionProperties_[currentIndex].height;
1160 }
1161 }
1162 bool isLandscape = static_cast<int32_t>(GetShowOptionCount()) ==
1163 (OPTION_COUNT_PHONE_LANDSCAPE + BUFFER_NODE_NUMBER);
1164 SetOptionShiftDistanceByIndex(currentIndex, isLandscape);
1165 properties.fontSize = Dimension(textLayoutProperty->GetFontSize().value().ConvertToPx());
1166 }
1167 if (textLayoutProperty->HasTextColor()) {
1168 properties.currentColor = textLayoutProperty->GetTextColor().value();
1169 }
1170 if (textLayoutProperty->HasFontWeight()) {
1171 properties.fontWeight = textLayoutProperty->GetFontWeight().value();
1172 }
1173 if (currentIndex > 0) {
1174 properties.upFontSize = animationProperties_[currentIndex - 1].fontSize;
1175 animationProperties_[currentIndex - 1].downFontSize = properties.fontSize;
1176
1177 properties.upColor = animationProperties_[currentIndex - 1].currentColor;
1178 animationProperties_[currentIndex - 1].downColor = properties.currentColor;
1179
1180 properties.upFontWeight = animationProperties_[currentIndex - 1].fontWeight;
1181 animationProperties_[currentIndex - 1].downFontWeight = properties.fontWeight;
1182 }
1183 animationProperties_.emplace_back(properties);
1184 }
1185
UpdatePickerTextProperties(const RefPtr<TextLayoutProperty> & textLayoutProperty,const RefPtr<TextPickerLayoutProperty> & textPickerLayoutProperty,uint32_t currentIndex,uint32_t middleIndex,uint32_t showCount)1186 void TextPickerColumnPattern::UpdatePickerTextProperties(const RefPtr<TextLayoutProperty>& textLayoutProperty,
1187 const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty, uint32_t currentIndex, uint32_t middleIndex,
1188 uint32_t showCount)
1189 {
1190 if (textPickerLayoutProperty && textPickerLayoutProperty->GetDisableTextStyleAnimation().value_or(false)) {
1191 UpdateDefaultTextProperties(textLayoutProperty, textPickerLayoutProperty, currentIndex, middleIndex);
1192 return;
1193 }
1194 auto host = GetHost();
1195 CHECK_NULL_VOID(host);
1196 auto context = host->GetContext();
1197 CHECK_NULL_VOID(context);
1198 auto pickerTheme = context->GetTheme<PickerTheme>(GetThemeScopeId());
1199 CHECK_NULL_VOID(pickerTheme);
1200 if (currentIndex == middleIndex) {
1201 UpdateSelectedTextProperties(pickerTheme, textLayoutProperty, textPickerLayoutProperty);
1202 textLayoutProperty->UpdateAlignment(Alignment::CENTER);
1203 } else if ((currentIndex == middleIndex + 1) || (currentIndex == middleIndex - 1)) {
1204 UpdateCandidateTextProperties(pickerTheme, textLayoutProperty, textPickerLayoutProperty);
1205 } else {
1206 UpdateDisappearTextProperties(pickerTheme, textLayoutProperty, textPickerLayoutProperty);
1207 }
1208 if (currentIndex < middleIndex) {
1209 textLayoutProperty->UpdateAlignment(Alignment::TOP_CENTER);
1210 } else if (currentIndex > middleIndex) {
1211 textLayoutProperty->UpdateAlignment(Alignment::BOTTOM_CENTER);
1212 }
1213 textLayoutProperty->UpdateMaxLines(1);
1214 if (isTextFadeOut_) {
1215 textLayoutProperty->UpdateTextOverflow(TextOverflow::MARQUEE);
1216 }
1217 AddAnimationTextProperties(currentIndex, textLayoutProperty);
1218 }
1219
SetSelectColor(const RefPtr<TextLayoutProperty> & textLayoutProperty,const Color & startColor,const Color & endColor,const float & percent,bool isEqual)1220 void TextPickerColumnPattern::SetSelectColor(const RefPtr<TextLayoutProperty>& textLayoutProperty,
1221 const Color& startColor, const Color& endColor, const float& percent, bool isEqual)
1222 {
1223 auto colorEvaluator = AceType::MakeRefPtr<LinearEvaluator<Color>>();
1224 Color updateColor = colorEvaluator->Evaluate(startColor, endColor, percent);
1225 textLayoutProperty->UpdateTextColor(updateColor);
1226 }
1227
TextPropertiesLinearAnimation(const RefPtr<TextLayoutProperty> & textLayoutProperty,uint32_t idx,uint32_t showCount,bool isDown,double scaleSize)1228 void TextPickerColumnPattern::TextPropertiesLinearAnimation(const RefPtr<TextLayoutProperty>& textLayoutProperty,
1229 uint32_t idx, uint32_t showCount, bool isDown, double scaleSize)
1230 {
1231 uint32_t deltaIdx = static_cast<uint32_t>(GetOverScrollDeltaIndex());
1232 auto index = idx;
1233 bool isEqual = false;
1234 if (GreatNotEqual(scrollDelta_, 0.0f)) {
1235 index = index + deltaIdx;
1236 } else {
1237 if (index < deltaIdx) {
1238 return;
1239 }
1240 index = index - deltaIdx;
1241 }
1242 auto percent = distancePercent_ - deltaIdx;
1243 auto scale = scaleSize - deltaIdx;
1244
1245 if (index >= animationProperties_.size()) {
1246 return;
1247 }
1248 Dimension startFontSize = animationProperties_[index].fontSize;
1249 Color startColor = animationProperties_[index].currentColor;
1250 if ((!index && isDown) || ((index == (showCount - 1)) && !isDown)) {
1251 textLayoutProperty->UpdateFontSize(startFontSize);
1252 textLayoutProperty->UpdateTextColor(startColor);
1253 return;
1254 }
1255 Dimension endFontSize;
1256 Color endColor;
1257 if (GreatNotEqual(scrollDelta_, 0.0)) {
1258 endFontSize = animationProperties_[index].downFontSize;
1259 endColor = animationProperties_[index].downColor;
1260 if (GreatOrEqual(scale, FONTWEIGHT)) {
1261 textLayoutProperty->UpdateFontWeight(animationProperties_[index].downFontWeight);
1262 }
1263 } else {
1264 endFontSize = animationProperties_[index].upFontSize;
1265 endColor = animationProperties_[index].upColor;
1266 if (GreatOrEqual(scale, FONTWEIGHT)) {
1267 textLayoutProperty->UpdateFontWeight(animationProperties_[index].upFontWeight);
1268 }
1269 }
1270 Dimension updateSize = LinearFontSize(startFontSize, endFontSize, percent);
1271 textLayoutProperty->UpdateFontSize(updateSize);
1272 isEqual = (idx == (showCount / PICKER_SELECT_AVERAGE));
1273 SetSelectColor(textLayoutProperty, startColor, endColor, percent, isEqual);
1274 if (scale < FONTWEIGHT) {
1275 textLayoutProperty->UpdateFontWeight(animationProperties_[index].fontWeight);
1276 }
1277 }
1278
GetOverScrollDeltaIndex() const1279 int32_t TextPickerColumnPattern::GetOverScrollDeltaIndex() const
1280 {
1281 auto deltaIdx = 0;
1282 if (NotLoopOptions() && overscroller_.IsOverScroll()) {
1283 auto midIndex = GetShowOptionCount() / HALF_NUMBER;
1284 auto shiftDistance = optionProperties_[midIndex].nextDistance;
1285 for (auto idx = midIndex; idx < GetShowOptionCount(); idx++) {
1286 if (shiftDistance > std::abs(scrollDelta_)) {
1287 break;
1288 }
1289 shiftDistance += optionProperties_[idx].nextDistance;
1290 deltaIdx++;
1291 }
1292 }
1293 return deltaIdx;
1294 }
1295
UpdateTextPropertiesLinear(bool isDown,double scale)1296 void TextPickerColumnPattern::UpdateTextPropertiesLinear(bool isDown, double scale)
1297 {
1298 if (columnKind_ == ICON) {
1299 return;
1300 }
1301 auto host = GetHost();
1302 CHECK_NULL_VOID(host);
1303 uint32_t showCount = GetShowOptionCount();
1304 auto middleIndex = showCount / 2;
1305 auto child = host->GetChildren();
1306 auto iter = child.begin();
1307 if (child.size() != showCount) {
1308 return;
1309 }
1310 for (uint32_t index = 0; index < showCount; index++) {
1311 auto rangeNode = DynamicCast<FrameNode>(*iter);
1312 CHECK_NULL_VOID(rangeNode);
1313 RefPtr<TextLayoutProperty> textLayoutProperty;
1314 if (columnKind_ == TEXT) {
1315 auto textPattern = rangeNode->GetPattern<TextPattern>();
1316 CHECK_NULL_VOID(textPattern);
1317 textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
1318 CHECK_NULL_VOID(textLayoutProperty);
1319 UpdateTextOverflow(index == middleIndex, textLayoutProperty);
1320 TextPropertiesLinearAnimation(textLayoutProperty, index, showCount, isDown, scale);
1321 } else if (columnKind_ == MIXTURE) {
1322 auto children = rangeNode->GetChildren();
1323 if (children.size() != MIXTURE_CHILD_COUNT) {
1324 continue;
1325 }
1326 auto textNode = DynamicCast<FrameNode>(rangeNode->GetLastChild());
1327 auto textPattern = textNode->GetPattern<TextPattern>();
1328 textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
1329 CHECK_NULL_VOID(textLayoutProperty);
1330 UpdateTextOverflow(index == middleIndex, textLayoutProperty);
1331 TextPropertiesLinearAnimation(textLayoutProperty, index, showCount, isDown, scale);
1332 textNode->MarkModifyDone();
1333 textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1334 }
1335 rangeNode->MarkModifyDone();
1336 rangeNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1337 iter++;
1338 }
1339 }
1340
LinearFontSize(const Dimension & startFontSize,const Dimension & endFontSize,double percent)1341 Dimension TextPickerColumnPattern::LinearFontSize(
1342 const Dimension& startFontSize, const Dimension& endFontSize, double percent)
1343 {
1344 if (percent > FONT_SIZE_PERCENT) {
1345 return startFontSize + (endFontSize - startFontSize);
1346 } else {
1347 return startFontSize + (endFontSize - startFontSize) * std::abs(percent);
1348 }
1349 }
1350
InitPanEvent(const RefPtr<GestureEventHub> & gestureHub)1351 void TextPickerColumnPattern::InitPanEvent(const RefPtr<GestureEventHub>& gestureHub)
1352 {
1353 CHECK_NULL_VOID(!panEvent_);
1354 auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& event) {
1355 auto pattern = weak.Upgrade();
1356 CHECK_NULL_VOID(pattern);
1357 if (event.GetInputEventType() == InputEventType::AXIS && event.GetSourceTool() == SourceTool::MOUSE) {
1358 return;
1359 }
1360 pattern->HandleDragStart(event);
1361 };
1362 auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& event) {
1363 auto pattern = weak.Upgrade();
1364 CHECK_NULL_VOID(pattern);
1365 pattern->SetMainVelocity(event.GetMainVelocity());
1366 pattern->HandleDragMove(event);
1367 };
1368 auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1369 auto pattern = weak.Upgrade();
1370 CHECK_NULL_VOID(pattern);
1371 if (info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() == SourceTool::MOUSE) {
1372 return;
1373 }
1374 pattern->SetMainVelocity(info.GetMainVelocity());
1375 pattern->HandleDragEnd();
1376 };
1377 auto actionCancelTask = [weak = WeakClaim(this)]() {
1378 auto pattern = weak.Upgrade();
1379 CHECK_NULL_VOID(pattern);
1380 pattern->HandleDragEnd();
1381 };
1382 PanDirection panDirection;
1383 panDirection.type = PanDirection::VERTICAL;
1384 panEvent_ = MakeRefPtr<PanEvent>(
1385 std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
1386 PanDistanceMap distanceMap = { { SourceTool::UNKNOWN, DEFAULT_PAN_DISTANCE.ConvertToPx() },
1387 { SourceTool::PEN, DEFAULT_PEN_PAN_DISTANCE.ConvertToPx() } };
1388 gestureHub->AddPanEvent(panEvent_, panDirection, DEFAULT_PAN_FINGER, distanceMap);
1389 }
1390
GetParentLayout() const1391 RefPtr<TextPickerLayoutProperty> TextPickerColumnPattern::GetParentLayout() const
1392 {
1393 auto host = GetHost();
1394 CHECK_NULL_RETURN(host, nullptr);
1395 auto blendNode = DynamicCast<FrameNode>(host->GetParent());
1396 CHECK_NULL_RETURN(blendNode, nullptr);
1397 auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
1398 CHECK_NULL_RETURN(stackNode, nullptr);
1399 auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
1400 CHECK_NULL_RETURN(parentNode, nullptr);
1401
1402 auto property = parentNode->GetLayoutProperty<TextPickerLayoutProperty>();
1403 return property;
1404 }
1405
HandleDragStart(const GestureEvent & event)1406 void TextPickerColumnPattern::HandleDragStart(const GestureEvent& event)
1407 {
1408 SetSelectedMark();
1409 CHECK_NULL_VOID(GetToss());
1410 auto toss = GetToss();
1411 auto offsetY = event.GetGlobalPoint().GetY();
1412 toss->SetStart(offsetY);
1413 yLast_ = offsetY;
1414 overscroller_.SetStart(offsetY);
1415 pressed_ = true;
1416 auto frameNode = GetHost();
1417 CHECK_NULL_VOID(frameNode);
1418 frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, event.GetMainVelocity(), SceneStatus::START);
1419 // AccessibilityEventType::SCROLL_START
1420
1421 if (animation_) {
1422 AnimationUtils::StopAnimation(animation_);
1423 }
1424
1425 if (NotLoopOptions() && reboundAnimation_) {
1426 AnimationUtils::StopAnimation(reboundAnimation_);
1427 isReboundInProgress_ = false;
1428 overscroller_.ResetVelocity();
1429 overscroller_.SetOverScroll(scrollDelta_);
1430 }
1431 }
1432
HandleDragMove(const GestureEvent & event)1433 void TextPickerColumnPattern::HandleDragMove(const GestureEvent& event)
1434 {
1435 if (event.GetFingerList().size() > 1) {
1436 return;
1437 }
1438 if (event.GetInputEventType() == InputEventType::AXIS && event.GetSourceTool() == SourceTool::MOUSE) {
1439 if (InnerHandleScroll(LessNotEqual(event.GetDelta().GetY(), 0.0), true)) {
1440 HandleScrollStopEventCallback(true);
1441 }
1442 return;
1443 }
1444 animationBreak_ = false;
1445 CHECK_NULL_VOID(pressed_);
1446 CHECK_NULL_VOID(GetHost());
1447 CHECK_NULL_VOID(GetToss());
1448 auto toss = GetToss();
1449 auto offsetY =
1450 event.GetGlobalPoint().GetY() + (event.GetInputEventType() == InputEventType::AXIS ? event.GetOffsetY() : 0.0);
1451 if (NearEqual(offsetY, yLast_, MOVE_THRESHOLD)) { // if changing less than MOVE_THRESHOLD, no need to handle
1452 StopHapticController();
1453 return;
1454 }
1455 toss->SetEnd(offsetY);
1456 UpdateColumnChildPosition(offsetY);
1457 auto frameNode = GetHost();
1458 CHECK_NULL_VOID(frameNode);
1459 frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, event.GetMainVelocity(), SceneStatus::RUNNING);
1460 }
1461
HandleDragEnd()1462 void TextPickerColumnPattern::HandleDragEnd()
1463 {
1464 if (hapticController_) {
1465 hapticController_->Stop();
1466 isHapticPlayOnce_ = false;
1467 }
1468 pressed_ = false;
1469 CHECK_NULL_VOID(GetToss());
1470 auto toss = GetToss();
1471 auto frameNode = GetHost();
1472 CHECK_NULL_VOID(frameNode);
1473 if (NotLoopOptions()) {
1474 frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, mainVelocity_, SceneStatus::END);
1475 if (overscroller_.IsOverScroll()) { // Start rebound animation. Higher priority than fling
1476 CreateReboundAnimation(overscroller_.GetOverScroll(), 0.0);
1477 HandleScrollStopEventCallback(true);
1478 return;
1479 }
1480 }
1481 if (toss->Play()) { // Start fling animation
1482 frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, mainVelocity_, SceneStatus::END);
1483 // AccessibilityEventType::SCROLL_END
1484 return;
1485 }
1486 yOffset_ = 0.0;
1487 yLast_ = 0.0;
1488 if (!animationCreated_) {
1489 ScrollOption(0.0);
1490 return;
1491 }
1492 int32_t middleIndex = static_cast<int32_t>(GetShowOptionCount()) / HALF_NUMBER;
1493 ScrollDirection dir = GreatNotEqual(scrollDelta_, 0.0) ? ScrollDirection::DOWN : ScrollDirection::UP;
1494 auto shiftDistance = (dir == ScrollDirection::UP) ? optionProperties_[middleIndex].prevDistance
1495 : optionProperties_[middleIndex].nextDistance;
1496 auto shiftThreshold = shiftDistance / HALF_NUMBER;
1497 if (std::abs(scrollDelta_) >= std::abs(shiftThreshold)) {
1498 InnerHandleScroll(LessNotEqual(scrollDelta_, 0.0), true, false);
1499 scrollDelta_ = scrollDelta_ - std::abs(shiftDistance) * (dir == ScrollDirection::UP ? -1 : 1);
1500 if (NearZero(scrollDelta_)) {
1501 HandleScrollStopEventCallback(true);
1502 }
1503 }
1504 CreateAnimation(scrollDelta_, 0.0);
1505 frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, mainVelocity_, SceneStatus::END);
1506 if (!NearZero(scrollDelta_)) {
1507 HandleScrollStopEventCallback(true);
1508 }
1509 // AccessibilityEventType::SCROLL_END
1510 }
1511
CreateAnimation()1512 void TextPickerColumnPattern::CreateAnimation()
1513 {
1514 CHECK_NULL_VOID(!animationCreated_);
1515 auto host = GetHost();
1516 CHECK_NULL_VOID(host);
1517 auto renderContext = host->GetRenderContext();
1518 CHECK_NULL_VOID(renderContext);
1519 auto propertyCallback = [weak = AceType::WeakClaim(this)](float value) {
1520 auto column = weak.Upgrade();
1521 CHECK_NULL_VOID(column);
1522 column->ScrollOption(value);
1523 };
1524 scrollProperty_ = AceType::MakeRefPtr<NodeAnimatablePropertyFloat>(0.0, std::move(propertyCallback));
1525 renderContext->AttachNodeAnimatableProperty(scrollProperty_);
1526
1527 auto aroundClickCallback = [weak = AceType::WeakClaim(this)](float value) {
1528 auto column = weak.Upgrade();
1529 CHECK_NULL_VOID(column);
1530 column->UpdateColumnChildPosition(value);
1531 };
1532 aroundClickProperty_ = AceType::MakeRefPtr<NodeAnimatablePropertyFloat>(0.0, std::move(aroundClickCallback));
1533 renderContext->AttachNodeAnimatableProperty(aroundClickProperty_);
1534 animationCreated_ = true;
1535 }
1536
CreateAnimation(double from,double to)1537 void TextPickerColumnPattern::CreateAnimation(double from, double to)
1538 {
1539 AnimationOption option;
1540 option.SetCurve(Curves::FAST_OUT_SLOW_IN);
1541 option.SetDuration(CLICK_ANIMATION_DURATION);
1542 scrollProperty_->Set(from);
1543 auto host = GetHost();
1544 auto context = host? host->GetContextRefPtr(): nullptr;
1545 AnimationUtils::Animate(option, [weak = AceType::WeakClaim(this), to]() {
1546 auto column = weak.Upgrade();
1547 CHECK_NULL_VOID(column);
1548 column->scrollProperty_->Set(to);
1549 }, nullptr, nullptr, context);
1550 }
1551
CreateReboundAnimation(double from,double to)1552 void TextPickerColumnPattern::CreateReboundAnimation(double from, double to)
1553 {
1554 isReboundInProgress_ = true;
1555 AnimationOption option;
1556 option.SetCurve(overscroller_.GetReboundCurve());
1557 option.SetDuration(CLICK_ANIMATION_DURATION);
1558 scrollProperty_->Set(from);
1559 reboundAnimation_ = AnimationUtils::StartAnimation(option, [weak = AceType::WeakClaim(this), to]() {
1560 auto column = weak.Upgrade();
1561 CHECK_NULL_VOID(column);
1562 column->scrollProperty_->Set(to);
1563 }, [weak = AceType::WeakClaim(this)]() { // On Finish
1564 auto column = weak.Upgrade();
1565 CHECK_NULL_VOID(column);
1566 if (column->isReboundInProgress_) {
1567 column->isReboundInProgress_ = false;
1568 column->overscroller_.Reset();
1569 column->yLast_ = 0.0;
1570 column->yOffset_ = 0.0;
1571 }
1572 });
1573 }
1574
HandleEnterSelectedArea(double scrollDelta,float shiftDistance,ScrollDirection dir)1575 void TextPickerColumnPattern::HandleEnterSelectedArea(double scrollDelta, float shiftDistance, ScrollDirection dir)
1576 {
1577 auto shiftThreshold = shiftDistance / HALF_NUMBER;
1578 uint32_t totalOptionCount = GetOptionCount();
1579 uint32_t currentEnterIndex = GetCurrentIndex();
1580 auto isOverScroll = NotLoopOptions() && overscroller_.IsOverScroll();
1581 if (totalOptionCount == 0) {
1582 return;
1583 }
1584 if (dir == ScrollDirection::UP) {
1585 currentEnterIndex = (totalOptionCount + currentEnterIndex + 1) % totalOptionCount;
1586 } else {
1587 auto totalCountAndIndex = totalOptionCount + currentEnterIndex;
1588 currentEnterIndex = (totalCountAndIndex ? totalCountAndIndex - 1 : 0) % totalOptionCount;
1589 }
1590 bool isDragReverse = false;
1591 if (GreatNotEqual(std::abs(enterDelta_), std::abs(scrollDelta))) {
1592 isDragReverse = true;
1593 }
1594 enterDelta_ = (NearEqual(scrollDelta, shiftDistance)) ? 0.0 : scrollDelta;
1595 if (GreatOrEqual(std::abs(scrollDelta), std::abs(shiftThreshold)) && GetEnterIndex() != currentEnterIndex &&
1596 !isOverScroll) {
1597 SetEnterIndex(currentEnterIndex);
1598 HandleEnterSelectedAreaEventCallback(true);
1599 }
1600 if (isDragReverse && LessOrEqual(std::abs(scrollDelta), std::abs(shiftThreshold)) &&
1601 GetEnterIndex() != GetCurrentIndex() && !isOverScroll) {
1602 SetEnterIndex(GetCurrentIndex());
1603 HandleEnterSelectedAreaEventCallback(true);
1604 }
1605 }
1606
ScrollOption(double delta)1607 void TextPickerColumnPattern::ScrollOption(double delta)
1608 {
1609 scrollDelta_ = delta;
1610 auto midIndex = GetShowOptionCount() / HALF_NUMBER;
1611 ScrollDirection dir = GreatNotEqual(delta, 0.0) ? ScrollDirection::DOWN : ScrollDirection::UP;
1612 auto shiftDistance = (dir == ScrollDirection::UP) ? optionProperties_[midIndex].prevDistance
1613 : optionProperties_[midIndex].nextDistance;
1614 HandleEnterSelectedArea(scrollDelta_, shiftDistance, dir);
1615 distancePercent_ = delta / shiftDistance;
1616 auto textLinearPercent = 0.0;
1617 textLinearPercent = (std::abs(delta)) / (optionProperties_[midIndex].height);
1618 UpdateTextPropertiesLinear(LessNotEqual(delta, 0.0), textLinearPercent);
1619 CalcAlgorithmOffset(dir, distancePercent_);
1620 auto host = GetHost();
1621 CHECK_NULL_VOID(host);
1622 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
1623 }
1624
ResetAlgorithmOffset()1625 void TextPickerColumnPattern::ResetAlgorithmOffset()
1626 {
1627 algorithmOffset_.clear();
1628
1629 uint32_t counts = GetShowOptionCount();
1630 for (uint32_t i = 0; i < counts; i++) {
1631 algorithmOffset_.emplace_back(0.0);
1632 }
1633 }
1634
UpdateScrollDelta(double delta)1635 void TextPickerColumnPattern::UpdateScrollDelta(double delta)
1636 {
1637 SetCurrentOffset(delta);
1638 auto host = GetHost();
1639 CHECK_NULL_VOID(host);
1640 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1641 }
1642
CalcAlgorithmOffset(ScrollDirection dir,double distancePercent)1643 void TextPickerColumnPattern::CalcAlgorithmOffset(ScrollDirection dir, double distancePercent)
1644 {
1645 algorithmOffset_.clear();
1646
1647 uint32_t counts = GetShowOptionCount();
1648
1649 for (uint32_t i = 0; i < counts; i++) {
1650 auto distance = (dir == ScrollDirection::UP) ? optionProperties_[i].prevDistance
1651 : optionProperties_[i].nextDistance;
1652 auto val = std::trunc(distance * distancePercent);
1653 algorithmOffset_.emplace_back(static_cast<int32_t>(val));
1654 }
1655 }
1656
GetShiftDistance(int32_t index,ScrollDirection dir)1657 double TextPickerColumnPattern::GetShiftDistance(int32_t index, ScrollDirection dir)
1658 {
1659 if (optionProperties_.empty()) {
1660 return 0.0;
1661 }
1662 int32_t optionCounts = static_cast<int32_t>(GetShowOptionCount());
1663 if (optionCounts == 0) {
1664 return 0.0;
1665 }
1666 int32_t nextIndex = 0;
1667 auto isDown = dir == ScrollDirection::DOWN;
1668 nextIndex = isDown ? (optionCounts + index + 1) % optionCounts : (optionCounts + index - 1) % optionCounts;
1669 double distance = 0.0;
1670 switch (static_cast<OptionIndex>(index)) {
1671 case OptionIndex::COLUMN_INDEX_0: // first
1672 distance = (dir == ScrollDirection::DOWN) ? optionProperties_[index].height
1673 : (0.0 - optionProperties_[index].height);
1674 break;
1675 case OptionIndex::COLUMN_INDEX_1:
1676 distance = (dir == ScrollDirection::DOWN) ? optionProperties_[index].height
1677 : (0.0 - optionProperties_[nextIndex].height);
1678 break;
1679 case OptionIndex::COLUMN_INDEX_2:
1680 distance = GetUpCandidateDistance(index, nextIndex, dir);
1681 break;
1682
1683 case OptionIndex::COLUMN_INDEX_3:
1684 distance = GetSelectedDistance(index, nextIndex, dir);
1685 break;
1686
1687 case OptionIndex::COLUMN_INDEX_4:
1688 distance = GetDownCandidateDistance(index, nextIndex, dir);
1689 break;
1690 case OptionIndex::COLUMN_INDEX_5:
1691 distance = (dir == ScrollDirection::DOWN) ? optionProperties_[index].height
1692 : (0.0 - optionProperties_[nextIndex].height);
1693 break;
1694 case OptionIndex::COLUMN_INDEX_6: // last
1695 distance = (dir == ScrollDirection::DOWN) ? optionProperties_[index].height
1696 : (0.0 - optionProperties_[nextIndex].height);
1697 break;
1698 default:
1699 break;
1700 }
1701
1702 return distance;
1703 }
1704
IsDisableTextStyleAnimation() const1705 bool TextPickerColumnPattern::IsDisableTextStyleAnimation() const
1706 {
1707 RefPtr<TextPickerLayoutProperty> layout = GetParentLayout();
1708 CHECK_NULL_RETURN(layout, false);
1709 return layout->GetDisableTextStyleAnimation().value_or(false);
1710 }
1711
GetSelectedDistance(int32_t index,int32_t nextIndex,ScrollDirection dir)1712 double TextPickerColumnPattern::GetSelectedDistance(int32_t index, int32_t nextIndex, ScrollDirection dir)
1713 {
1714 double distance = 0.0;
1715 double val = 0.0;
1716 if (columnKind_ == TEXT && !IsDisableTextStyleAnimation()) {
1717 if (GreatOrEqual(optionProperties_[nextIndex].fontheight, optionProperties_[nextIndex].height)) {
1718 distance = (dir == ScrollDirection::UP) ?
1719 - optionProperties_[nextIndex].height : optionProperties_[index].height;
1720 } else {
1721 val = optionProperties_[index].height / HALF_NUMBER + optionProperties_[nextIndex].height -
1722 optionProperties_[nextIndex].fontheight / HALF_NUMBER;
1723 val = std::round(val);
1724 distance = (dir == ScrollDirection::DOWN) ? val : (0.0 - val);
1725 }
1726 } else {
1727 val = std::round((optionProperties_[index].height + optionProperties_[nextIndex].height) / HALF_NUMBER);
1728 distance = (dir == ScrollDirection::DOWN) ? val : (0.0 - val);
1729 }
1730 return distance;
1731 }
1732
GetUpCandidateDistance(int32_t index,int32_t nextIndex,ScrollDirection dir)1733 double TextPickerColumnPattern::GetUpCandidateDistance(int32_t index, int32_t nextIndex, ScrollDirection dir)
1734 {
1735 double distance = 0.0;
1736 double val = 0.0;
1737 // the index of last element in optionProperties_. return -1 while the arraySize equals 0.
1738 auto maxIndex = static_cast<int32_t>(optionProperties_.size()) - 1;
1739 auto minIndex = 0;
1740 if (index > maxIndex || index < minIndex || nextIndex > maxIndex || nextIndex < minIndex) {
1741 return distance;
1742 }
1743 if (columnKind_ == TEXT && !IsDisableTextStyleAnimation()) {
1744 if (dir == ScrollDirection::UP) {
1745 distance = -optionProperties_[nextIndex].height;
1746 } else {
1747 val = optionProperties_[index].height +
1748 (optionProperties_[nextIndex].height - optionProperties_[nextIndex].fontheight) / HALF_NUMBER;
1749 distance = std::round(val);
1750 }
1751 } else {
1752 val = std::round((optionProperties_[index].height + optionProperties_[nextIndex].height) / HALF_NUMBER);
1753 distance = (dir == ScrollDirection::DOWN) ? val : (0.0 - val);
1754 }
1755 return distance;
1756 }
1757
GetDownCandidateDistance(int32_t index,int32_t nextIndex,ScrollDirection dir)1758 double TextPickerColumnPattern::GetDownCandidateDistance(int32_t index, int32_t nextIndex, ScrollDirection dir)
1759 {
1760 double distance = 0.0;
1761 double val = 0.0;
1762 if (columnKind_ == TEXT && !IsDisableTextStyleAnimation()) {
1763 if (dir == ScrollDirection::DOWN) {
1764 distance = optionProperties_[index].height;
1765 } else {
1766 val = optionProperties_[index].height +
1767 (optionProperties_[nextIndex].height - optionProperties_[nextIndex].fontheight) / HALF_NUMBER;
1768 if (GreatNotEqual(optionProperties_[nextIndex].fontheight, optionProperties_[index].height)) {
1769 val = val + (optionProperties_[nextIndex].fontheight - optionProperties_[index].height);
1770 }
1771 distance = - std::round(val);
1772 }
1773 } else {
1774 val = std::round((optionProperties_[index].height + optionProperties_[nextIndex].height) / HALF_NUMBER);
1775 distance = (dir == ScrollDirection::DOWN) ? val : (0.0 - val);
1776 }
1777 return distance;
1778 }
1779
GetShiftDistanceForLandscape(int32_t index,ScrollDirection dir)1780 double TextPickerColumnPattern::GetShiftDistanceForLandscape(int32_t index, ScrollDirection dir)
1781 {
1782 int32_t optionCounts = static_cast<int32_t>(GetShowOptionCount());
1783 if (optionCounts == 0) {
1784 return 0.0;
1785 }
1786 int32_t nextIndex = 0;
1787 auto isDown = dir == ScrollDirection::DOWN;
1788 nextIndex = isDown ? (optionCounts + index + 1) % optionCounts : (optionCounts + index - 1) % optionCounts;
1789 double distance = 0.0;
1790 switch (static_cast<OptionIndex>(index)) {
1791 case OptionIndex::COLUMN_INDEX_0:
1792 distance = GetUpCandidateDistance(index, nextIndex, dir);
1793 break;
1794
1795 case OptionIndex::COLUMN_INDEX_1:
1796 distance = GetSelectedDistance(index, nextIndex, dir);
1797 break;
1798
1799 case OptionIndex::COLUMN_INDEX_2:
1800 distance = GetDownCandidateDistance(index, nextIndex, dir);
1801 break;
1802 default:
1803 break;
1804 }
1805
1806 return distance;
1807 }
1808
SetOptionShiftDistanceByIndex(int32_t index,const bool isLandscape)1809 void TextPickerColumnPattern::SetOptionShiftDistanceByIndex(int32_t index, const bool isLandscape)
1810 {
1811 CHECK_EQUAL_VOID(optionProperties_.empty(), true);
1812 TextPickerOptionProperty& prop = optionProperties_[index];
1813 if (isLandscape) {
1814 prop.prevDistance = GetShiftDistanceForLandscape(index, ScrollDirection::UP);
1815 prop.nextDistance = GetShiftDistanceForLandscape(index, ScrollDirection::DOWN);
1816 } else {
1817 prop.prevDistance = GetShiftDistance(index, ScrollDirection::UP);
1818 prop.nextDistance = GetShiftDistance(index, ScrollDirection::DOWN);
1819 }
1820 }
1821
SetOptionShiftDistance()1822 void TextPickerColumnPattern::SetOptionShiftDistance()
1823 {
1824 int32_t itemCounts = static_cast<int32_t>(GetShowOptionCount());
1825 bool isLandscape = itemCounts == OPTION_COUNT_PHONE_LANDSCAPE + BUFFER_NODE_NUMBER;
1826 for (int32_t i = 0; i < itemCounts; i++) {
1827 SetOptionShiftDistanceByIndex(i, isLandscape);
1828 }
1829 }
1830
UpdateToss(double offsetY)1831 void TextPickerColumnPattern::UpdateToss(double offsetY)
1832 {
1833 UpdateColumnChildPosition(offsetY);
1834 }
1835
TossStoped()1836 void TextPickerColumnPattern::TossStoped()
1837 {
1838 yOffset_ = 0.0;
1839 yLast_ = 0.0;
1840 ScrollOption(0.0);
1841 }
1842
TossAnimationStoped()1843 void TextPickerColumnPattern::TossAnimationStoped()
1844 {
1845 if (hapticController_) {
1846 hapticController_->Stop();
1847 }
1848 yLast_ = 0.0;
1849 ScrollOption(0.0);
1850 }
1851
GetSelectedObject(bool isColumnChange,int32_t status) const1852 std::string TextPickerColumnPattern::GetSelectedObject(bool isColumnChange, int32_t status) const
1853 {
1854 auto host = GetHost();
1855 CHECK_NULL_RETURN(host, "");
1856 auto value = GetOption(GetSelected());
1857 auto index = GetSelected();
1858 if (isColumnChange) {
1859 value = GetCurrentText();
1860 index = GetCurrentIndex();
1861 }
1862
1863 auto context = host->GetContext();
1864 CHECK_NULL_RETURN(context, "");
1865
1866 if (context->GetIsDeclarative()) {
1867 return std::string("{\"value\":") + "\"" + value + "\"" + ",\"index\":" + std::to_string(index) +
1868 ",\"status\":" + std::to_string(status) + "}";
1869 } else {
1870 return std::string("{\"newValue\":") + "\"" + value + "\"" + ",\"newSelected\":" + std::to_string(index) +
1871 ",\"status\":" + std::to_string(status) + "}";
1872 }
1873 }
1874
ResetTotalDelta()1875 void TextPickerColumnPattern::ResetTotalDelta()
1876 {
1877 totalDragDelta_ = 0.0;
1878 }
1879
SpringCurveTailMoveProcess(bool useRebound,double & dragDelta)1880 bool TextPickerColumnPattern::SpringCurveTailMoveProcess(bool useRebound, double& dragDelta)
1881 {
1882 if (useRebound) {
1883 return false;
1884 }
1885 auto toss = GetToss();
1886 if (toss && toss->GetTossPlaying()) {
1887 if (std::abs(dragDelta) < CURVE_MOVE_THRESHOLD) {
1888 dragDelta = dragDelta > 0 ? CURVE_MOVE_THRESHOLD : -CURVE_MOVE_THRESHOLD;
1889 }
1890 totalDragDelta_ += dragDelta;
1891 if (std::abs(totalDragDelta_) >= std::abs(toss->GetTossEndPosition())) {
1892 dragDelta -= (totalDragDelta_ - toss->GetTossEndPosition());
1893 ResetTotalDelta();
1894 return true;
1895 }
1896 }
1897 return false;
1898 }
1899
SpringCurveTailEndProcess(bool useRebound,bool stopMove)1900 void TextPickerColumnPattern::SpringCurveTailEndProcess(bool useRebound, bool stopMove)
1901 {
1902 if (useRebound || !stopMove) {
1903 return;
1904 }
1905 auto toss = GetToss();
1906 if (toss) {
1907 toss->SetTossPlaying(false);
1908 toss->StopTossAnimation();
1909 }
1910 }
1911
UpdateColumnChildPosition(double offsetY)1912 void TextPickerColumnPattern::UpdateColumnChildPosition(double offsetY)
1913 {
1914 double dragDelta = offsetY - yLast_;
1915 auto midIndex = GetShowOptionCount() / HALF_NUMBER;
1916 ScrollDirection dir = GreatNotEqual(dragDelta, 0.0) ? ScrollDirection::DOWN : ScrollDirection::UP;
1917 auto shiftDistance = (dir == ScrollDirection::UP) ? optionProperties_[midIndex].prevDistance
1918 : optionProperties_[midIndex].nextDistance;
1919 auto useRebound = NotLoopOptions();
1920 auto stopMove = SpringCurveTailMoveProcess(useRebound, dragDelta);
1921 offsetCurSet_ = 0.0;
1922
1923 if (hapticController_ && isShow_) {
1924 if (isEnableHaptic_ && !isHapticPlayOnce_ && !stopHaptic_) {
1925 hapticController_->HandleDelta(dragDelta);
1926 }
1927 }
1928 // the abs of drag delta is less than jump interval.
1929 dragDelta = GetDragDeltaLessThanJumpInterval(offsetY, dragDelta, useRebound, shiftDistance);
1930
1931 // Set options position
1932 ScrollOption(dragDelta);
1933 offsetCurSet_ = dragDelta;
1934 yOffset_ = dragDelta;
1935 yLast_ = offsetY;
1936
1937 if (useRebound && !pressed_ && isTossStatus_ && !isReboundInProgress_ && overscroller_.IsOverScroll()) {
1938 overscroller_.UpdateTossSpring(offsetY);
1939 if (overscroller_.ShouldStartRebound()) {
1940 auto toss = GetToss();
1941 CHECK_NULL_VOID(toss);
1942 toss->StopTossAnimation(); // Stop fling animation and start rebound animation implicitly
1943 StopHapticController();
1944 }
1945 }
1946 SpringCurveTailEndProcess(useRebound, stopMove);
1947 }
1948
GetDragDeltaLessThanJumpInterval(double offsetY,float originalDragDelta,bool useRebound,float shiftDistance)1949 double TextPickerColumnPattern::GetDragDeltaLessThanJumpInterval(
1950 double offsetY, float originalDragDelta, bool useRebound, float shiftDistance)
1951 {
1952 double dragDelta = originalDragDelta + yOffset_;
1953 auto isOverScroll = useRebound && overscroller_.IsOverScroll();
1954 if (NearEqual(std::abs(dragDelta), std::abs(shiftDistance)) && !NearZero(dragDelta)) {
1955 dragDelta = std::abs(dragDelta) / dragDelta * std::abs(shiftDistance);
1956 }
1957 if ((std::abs(dragDelta) >= std::abs(shiftDistance)) && !isOverScroll) {
1958 int32_t shiftDistanceCount = static_cast<int>(std::abs(dragDelta) / std::abs(shiftDistance));
1959 double additionalShift = dragDelta - shiftDistanceCount * shiftDistance;
1960 if (GreatNotEqual(std::abs(additionalShift), std::abs(dragDelta))) {
1961 additionalShift = dragDelta + shiftDistanceCount * shiftDistance;
1962 }
1963 for (int32_t i = 0; i < shiftDistanceCount; i++) {
1964 ScrollOption(shiftDistance);
1965 InnerHandleScroll(dragDelta < 0, true, false);
1966 }
1967 dragDelta = additionalShift;
1968 if (NearZero(dragDelta)) {
1969 HandleScrollStopEventCallback(true);
1970 }
1971 }
1972 if (useRebound && !isReboundInProgress_) {
1973 if (overscroller_.ApplyCurrentOffset(yLast_, offsetY, dragDelta)) {
1974 dragDelta =
1975 overscroller_.IsBackOverScroll() ? overscroller_.GetBackScroll() : overscroller_.GetOverScroll();
1976 }
1977 }
1978 return dragDelta;
1979 }
1980
CanMove(bool isDown) const1981 bool TextPickerColumnPattern::CanMove(bool isDown) const
1982 {
1983 if (!NotLoopOptions()) {
1984 return true;
1985 }
1986 auto host = GetHost();
1987 CHECK_NULL_RETURN(host, false);
1988 int totalOptionCount = static_cast<int>(GetOptionCount());
1989 int currentIndex = static_cast<int>(GetCurrentIndex());
1990 int nextVirtualIndex = isDown ? currentIndex + 1 : currentIndex - 1;
1991 return nextVirtualIndex >= 0 && nextVirtualIndex < totalOptionCount;
1992 }
1993
NotLoopOptions() const1994 bool TextPickerColumnPattern::NotLoopOptions() const
1995 {
1996 RefPtr<TextPickerLayoutProperty> layout = GetParentLayout();
1997 CHECK_NULL_RETURN(layout, false);
1998 bool canLoop = layout->GetCanLoop().value_or(true);
1999 return !canLoop;
2000 }
2001
HandleAccessibilityTextChange()2002 void TextPickerColumnPattern::HandleAccessibilityTextChange()
2003 {
2004 auto host = GetHost();
2005 CHECK_NULL_VOID(host);
2006 auto blendNode = DynamicCast<FrameNode>(host->GetParent());
2007 CHECK_NULL_VOID(blendNode);
2008 auto accessibilityProperty = blendNode->GetAccessibilityProperty<AccessibilityProperty>();
2009 CHECK_NULL_VOID(accessibilityProperty);
2010 accessibilityProperty->SetUserTextValue(GetOption(GetCurrentIndex()));
2011 accessibilityProperty->SetAccessibilityText(GetOption(GetCurrentIndex()));
2012 blendNode->OnAccessibilityEvent(AccessibilityEventType::TEXT_CHANGE);
2013 }
2014
InnerHandleScroll(bool isDown,bool isUpdatePropertiesOnly,bool isUpdateAnimationProperties)2015 bool TextPickerColumnPattern::InnerHandleScroll(
2016 bool isDown, bool isUpdatePropertiesOnly, bool isUpdateAnimationProperties)
2017 {
2018 auto host = GetHost();
2019 CHECK_NULL_RETURN(host, false);
2020 auto totalOptionCount = GetOptionCount();
2021 if (totalOptionCount == 0) {
2022 return false;
2023 }
2024
2025 if (NotLoopOptions() && ((isDown && currentIndex_ == totalOptionCount - 1) || (!isDown && currentIndex_ == 0))) {
2026 return false;
2027 }
2028
2029 uint32_t currentIndex = GetCurrentIndex();
2030 if (isDown) {
2031 currentIndex = (totalOptionCount + currentIndex + 1) % totalOptionCount; // index add one
2032 } else {
2033 auto totalCountAndIndex = totalOptionCount + currentIndex;
2034 currentIndex = (totalCountAndIndex ? totalCountAndIndex - 1 : 0) % totalOptionCount; // index reduce one
2035 }
2036 SetCurrentIndex(currentIndex);
2037 if (hapticController_ && isEnableHaptic_ && !stopHaptic_) {
2038 hapticController_->PlayOnce();
2039 }
2040 FlushCurrentOptions(isDown, isUpdatePropertiesOnly, isUpdateAnimationProperties);
2041 HandleChangeCallback(isDown, true);
2042 HandleEventCallback(true);
2043
2044 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
2045
2046 HandleAccessibilityTextChange();
2047 return true;
2048 }
2049
OnKeyEvent(const KeyEvent & event)2050 bool TextPickerColumnPattern::OnKeyEvent(const KeyEvent& event)
2051 {
2052 if (event.action != KeyAction::DOWN) {
2053 return false;
2054 }
2055 if (event.code == KeyCode::KEY_DPAD_UP || event.code == KeyCode::KEY_DPAD_DOWN ||
2056 event.code == KeyCode::KEY_DPAD_LEFT || event.code == KeyCode::KEY_DPAD_RIGHT) {
2057 HandleDirectionKey(event.code);
2058 return true;
2059 }
2060 return false;
2061 }
2062
HandleDirectionKey(KeyCode code)2063 bool TextPickerColumnPattern::HandleDirectionKey(KeyCode code)
2064 {
2065 auto host = GetHost();
2066 CHECK_NULL_RETURN(host, false);
2067 auto currentIndex = GetCurrentIndex();
2068 auto totalOptionCount = GetOptionCount();
2069 if (totalOptionCount == 0) {
2070 return false;
2071 }
2072 if (code == KeyCode::KEY_DPAD_UP) {
2073 auto totalCountAndIndex = totalOptionCount + currentIndex;
2074 SetCurrentIndex((totalCountAndIndex ? totalCountAndIndex - 1 : 0) % totalOptionCount);
2075 FlushCurrentOptions();
2076 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2077 return true;
2078 }
2079 if (code == KeyCode::KEY_DPAD_DOWN) {
2080 SetCurrentIndex((totalOptionCount + currentIndex + 1) % totalOptionCount);
2081 FlushCurrentOptions(true);
2082 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2083 return true;
2084 }
2085 return false;
2086 }
SetAccessibilityAction()2087 void TextPickerColumnPattern::SetAccessibilityAction()
2088 {
2089 auto host = GetHost();
2090 CHECK_NULL_VOID(host);
2091 auto blendNode = DynamicCast<FrameNode>(host->GetParent());
2092 CHECK_NULL_VOID(blendNode);
2093 auto accessibilityProperty = blendNode->GetAccessibilityProperty<AccessibilityProperty>();
2094 CHECK_NULL_VOID(accessibilityProperty);
2095 accessibilityProperty->SetAccessibilityGroup(true);
2096 accessibilityProperty->SetAccessibilityCustomRole("TextPicker");
2097 accessibilityProperty->SetUserTextValue(GetOption(GetCurrentIndex()));
2098 accessibilityProperty->SetAccessibilityText(GetOption(GetCurrentIndex()));
2099
2100 accessibilityProperty->SetSpecificSupportActionCallback(
2101 [weakPtr = WeakClaim(this), accessibilityPtr = WeakClaim(RawPtr(accessibilityProperty))]() {
2102 const auto& pattern = weakPtr.Upgrade();
2103 CHECK_NULL_VOID(pattern);
2104 const auto& accessibilityProperty = accessibilityPtr.Upgrade();
2105 CHECK_NULL_VOID(accessibilityProperty);
2106 if (pattern->CanMove(true)) {
2107 accessibilityProperty->AddSupportAction(AceAction::ACTION_SCROLL_FORWARD);
2108 }
2109 if (pattern->CanMove(false)) {
2110 accessibilityProperty->AddSupportAction(AceAction::ACTION_SCROLL_BACKWARD);
2111 }
2112 });
2113
2114 accessibilityProperty->SetActionScrollForward([weakPtr = WeakClaim(this)]() {
2115 const auto& pattern = weakPtr.Upgrade();
2116 CHECK_NULL_VOID(pattern);
2117 CHECK_NULL_VOID(pattern->animationCreated_);
2118 if (!pattern->CanMove(true)) {
2119 return;
2120 }
2121 pattern->InnerHandleScroll(true);
2122 pattern->CreateAnimation(0.0 - pattern->jumpInterval_, 0.0);
2123 pattern->HandleScrollStopEventCallback(true);
2124 // AccessibilityEventType::SCROLL_END
2125 });
2126
2127 accessibilityProperty->SetActionScrollBackward([weakPtr = WeakClaim(this)]() {
2128 const auto& pattern = weakPtr.Upgrade();
2129 CHECK_NULL_VOID(pattern);
2130 CHECK_NULL_VOID(pattern->animationCreated_);
2131 if (!pattern->CanMove(false)) {
2132 return;
2133 }
2134 pattern->InnerHandleScroll(false);
2135 pattern->CreateAnimation(pattern->jumpInterval_, 0.0);
2136 pattern->HandleScrollStopEventCallback(true);
2137 // AccessibilityEventType::SCROLL_END
2138 });
2139 }
2140
OnAroundButtonClick(RefPtr<EventParam> param)2141 void TextPickerColumnPattern::OnAroundButtonClick(RefPtr<EventParam> param)
2142 {
2143 if (clickBreak_) {
2144 return;
2145 }
2146 int32_t middleIndex = static_cast<int32_t>(GetShowOptionCount()) / HALF_NUMBER;
2147 int32_t step = param->itemIndex - middleIndex;
2148 if (step != 0) {
2149 if (animation_) {
2150 AnimationUtils::StopAnimation(animation_);
2151 yOffset_ = 0.0;
2152 }
2153
2154 StopHapticController();
2155 isHapticPlayOnce_ = true;
2156 int32_t index = static_cast<int32_t>(currentIndex_) + step;
2157 auto overFirst = index < 0 && step < 0;
2158 auto overLast =
2159 index > static_cast<int32_t>(GetOptionCount() ? GetOptionCount() - 1 : 0) && step > 0;
2160 if (NotLoopOptions() && (overscroller_.IsOverScroll() || overFirst || overLast)) {
2161 return;
2162 }
2163
2164 double distance =
2165 (step > 0 ? optionProperties_[middleIndex].prevDistance : optionProperties_[middleIndex].nextDistance) *
2166 std::abs(step);
2167 AnimationOption option;
2168 option.SetCurve(Curves::FAST_OUT_SLOW_IN);
2169 option.SetDuration(CLICK_ANIMATION_DURATION);
2170 yLast_ = 0.0;
2171 aroundClickProperty_->Set(0.0);
2172 animation_ = AnimationUtils::StartAnimation(option, [weak = AceType::WeakClaim(this), step, distance]() {
2173 auto column = weak.Upgrade();
2174 CHECK_NULL_VOID(column);
2175 column->aroundClickProperty_->Set(step > 0 ? 0.0 - std::abs(distance) : std::abs(distance));
2176 });
2177 auto host = GetHost();
2178 CHECK_NULL_VOID(host);
2179 auto pipeline = host->GetContext();
2180 CHECK_NULL_VOID(pipeline);
2181 pipeline->RequestFrame();
2182 }
2183 SetSelectedMark();
2184 }
2185
PlayResetAnimation()2186 void TextPickerColumnPattern::PlayResetAnimation()
2187 {
2188 int32_t middleIndex = static_cast<int32_t>(GetShowOptionCount()) / HALF_NUMBER;
2189 ScrollDirection dir = GreatNotEqual(scrollDelta_, 0.0) ? ScrollDirection::DOWN : ScrollDirection::UP;
2190 double shiftDistance = (dir == ScrollDirection::UP) ? optionProperties_[middleIndex].prevDistance
2191 : optionProperties_[middleIndex].nextDistance;
2192 double shiftThreshold = shiftDistance / HALF_NUMBER;
2193 if (std::abs(scrollDelta_) >= std::abs(shiftThreshold)) {
2194 InnerHandleScroll(LessNotEqual(scrollDelta_, 0.0), true, false);
2195 scrollDelta_ = scrollDelta_ - std::abs(shiftDistance) * (dir == ScrollDirection::UP ? -1 : 1);
2196 if (NearZero(scrollDelta_)) {
2197 HandleScrollStopEventCallback(true);
2198 }
2199 }
2200 CreateAnimation(scrollDelta_, 0.0);
2201 if (!NearZero(scrollDelta_)) {
2202 HandleScrollStopEventCallback(true);
2203 }
2204 }
2205
SetCanLoop(bool isLoop)2206 void TextPickerColumnPattern::SetCanLoop(bool isLoop)
2207 {
2208 if (isLoop_ == isLoop) {
2209 return;
2210 }
2211
2212 isLoop_ = isLoop;
2213 if (overscroller_.IsOverScroll()) {
2214 overscroller_.Reset();
2215 isReboundInProgress_ = false;
2216 yOffset_ = 0.0;
2217 ScrollOption(0.0);
2218 }
2219
2220 if (!isLoop && isTossStatus_) {
2221 auto toss = GetToss();
2222 CHECK_NULL_VOID(toss);
2223 overscroller_.SetLoopTossOffset(toss->GetTossOffset());
2224 }
2225 }
2226
SetSelectedMarkListener(std::function<void (int & selectedColumnId)> & listener)2227 void TextPickerColumnPattern::SetSelectedMarkListener(std::function<void(int& selectedColumnId)>& listener)
2228 {
2229 focusedListerner_ = listener;
2230 if (!circleUtils_) {
2231 circleUtils_ = new PickerColumnPatternCircleUtils<TextPickerColumnPattern>();
2232 }
2233 }
2234
SetSelectedMarkId(const int strColumnId)2235 void TextPickerColumnPattern::SetSelectedMarkId(const int strColumnId)
2236 {
2237 selectedColumnId_ = strColumnId;
2238 }
2239
SetSelectedMark(bool focus,bool notify,bool reRender)2240 void TextPickerColumnPattern::SetSelectedMark(bool focus, bool notify, bool reRender)
2241 {
2242 auto pipeline = GetContext();
2243 CHECK_NULL_VOID(pipeline);
2244 auto pickerTheme = pipeline->GetTheme<PickerTheme>();
2245 CHECK_NULL_VOID(pickerTheme);
2246 if (pickerTheme->IsCircleDial()) {
2247 CHECK_NULL_VOID(circleUtils_);
2248 circleUtils_->SetSelectedMark(this, pickerTheme, focus, notify, reRender);
2249 }
2250 }
2251
SetSelectedMarkPaint(bool paint)2252 void TextPickerColumnPattern::SetSelectedMarkPaint(bool paint)
2253 {
2254 selectedMarkPaint_ = paint;
2255 }
2256
UpdateSelectedTextColor(const RefPtr<PickerTheme> & pickerTheme)2257 void TextPickerColumnPattern::UpdateSelectedTextColor(const RefPtr<PickerTheme>& pickerTheme)
2258 {
2259 UpdateAnimationColor(pickerTheme);
2260
2261 auto host = GetHost();
2262 CHECK_NULL_VOID(host);
2263 auto blendNode = DynamicCast<FrameNode>(host->GetParent());
2264 CHECK_NULL_VOID(blendNode);
2265 auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
2266 CHECK_NULL_VOID(stackNode);
2267 auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
2268 CHECK_NULL_VOID(parentNode);
2269 auto layoutProperty = parentNode->GetLayoutProperty<TextPickerLayoutProperty>();
2270 CHECK_NULL_VOID(layoutProperty);
2271
2272 auto&& child = host->GetChildren();
2273 auto iter = child.begin();
2274 CHECK_NULL_VOID(iter != child.end());
2275 std::advance (iter, GetShowOptionCount() / PICKER_SELECT_AVERAGE);
2276 CHECK_NULL_VOID(iter != child.end());
2277 auto textNode = DynamicCast<FrameNode>(*iter);
2278 CHECK_NULL_VOID(textNode);
2279 auto textPattern = textNode->GetPattern<TextPattern>();
2280 CHECK_NULL_VOID(textPattern);
2281 auto textLayoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
2282 CHECK_NULL_VOID(textLayoutProperty);
2283
2284 UpdateSelectedTextProperties(pickerTheme, textLayoutProperty, layoutProperty);
2285
2286 textNode->MarkDirtyNode(PROPERTY_UPDATE_DIFF);
2287 host->MarkDirtyNode(PROPERTY_UPDATE_DIFF);
2288 }
2289
UpdateUserSetSelectColor()2290 void TextPickerColumnPattern::UpdateUserSetSelectColor()
2291 {
2292 isUserSetSelectColor_ = true;
2293 auto pipeline = GetContext();
2294 CHECK_NULL_VOID(pipeline);
2295 auto pickerTheme = pipeline->GetTheme<PickerTheme>();
2296 CHECK_NULL_VOID(pickerTheme);
2297 UpdateSelectedTextColor(pickerTheme);
2298 }
2299
UpdateAnimationColor(const RefPtr<PickerTheme> & pickerTheme)2300 void TextPickerColumnPattern::UpdateAnimationColor(const RefPtr<PickerTheme>& pickerTheme)
2301 {
2302 CHECK_NULL_VOID(pickerTheme);
2303 auto host = GetHost();
2304 CHECK_NULL_VOID(host);
2305 auto blendNode = DynamicCast<FrameNode>(host->GetParent());
2306 CHECK_NULL_VOID(blendNode);
2307 auto stackNode = DynamicCast<FrameNode>(blendNode->GetParent());
2308 CHECK_NULL_VOID(stackNode);
2309 auto parentNode = DynamicCast<FrameNode>(stackNode->GetParent());
2310 CHECK_NULL_VOID(parentNode);
2311 auto layoutProperty = parentNode->GetLayoutProperty<TextPickerLayoutProperty>();
2312 CHECK_NULL_VOID(layoutProperty);
2313 Color color;
2314
2315 if (pickerTheme->IsCircleDial() && !isUserSetSelectColor_) {
2316 if (selectedMarkPaint_) {
2317 color = pickerTheme->GetOptionStyle(true, true).GetTextColor();
2318 } else {
2319 color = pickerTheme->GetOptionStyle(false, false).GetTextColor();
2320 }
2321 } else {
2322 color = layoutProperty->GetSelectedColor().value_or(
2323 pickerTheme->GetOptionStyle(true, false).GetTextColor());
2324 }
2325
2326 uint32_t middleIndex = GetShowOptionCount() / PICKER_SELECT_AVERAGE;
2327 if (middleIndex - NEXT_COLOUM_DIFF >= 0 && animationProperties_.size() > middleIndex) {
2328 animationProperties_[middleIndex - NEXT_COLOUM_DIFF].downColor = color;
2329 animationProperties_[middleIndex + NEXT_COLOUM_DIFF].upColor = color;
2330 animationProperties_[middleIndex].currentColor = color;
2331 }
2332 }
2333
InitTextHeightAndFontHeight(uint32_t childIndex,uint32_t midIndex,TextPickerOptionProperty & prop)2334 void TextPickerColumnPattern::InitTextHeightAndFontHeight(uint32_t childIndex, uint32_t midIndex,
2335 TextPickerOptionProperty &prop)
2336 {
2337 auto host = GetHost();
2338 CHECK_NULL_VOID(host);
2339 auto pipeline = host->GetContext();
2340 CHECK_NULL_VOID(pipeline);
2341 auto theme = pipeline->GetTheme<PickerTheme>();
2342
2343 MeasureContext measureContext;
2344 measureContext.textContent = MEASURE_STRING;
2345 measureContext.fontFamily = FONT_FAMILY_DEFAULT[0];
2346
2347 if (childIndex == midIndex) {
2348 measureContext.fontSize = theme->GetOptionStyle(true, false).GetFontSize();
2349 } else if ((childIndex == (midIndex + 1)) || (childIndex == (midIndex - 1))) {
2350 measureContext.fontSize = theme->GetOptionStyle(false, false).GetFontSize() + FONT_SIZE;
2351 } else {
2352 measureContext.fontSize = theme->GetOptionStyle(false, false).GetFontSize();
2353 }
2354
2355 Size size = MeasureUtil::MeasureTextSize(measureContext);
2356 prop.fontheight = size.Height();
2357 prop.height = (childIndex == midIndex) ? dividerSpacing_ : gradientHeight_;
2358 }
2359
2360 #ifdef SUPPORT_DIGITAL_CROWN
GetSelectedColumnId()2361 int32_t& TextPickerColumnPattern::GetSelectedColumnId()
2362 {
2363 return selectedColumnId_;
2364 }
2365
IsCrownEventEnded()2366 bool TextPickerColumnPattern::IsCrownEventEnded()
2367 {
2368 return isCrownEventEnded_;
2369 }
2370
GetDigitalCrownSensitivity()2371 int32_t TextPickerColumnPattern::GetDigitalCrownSensitivity()
2372 {
2373 if (crownSensitivity_ == INVALID_CROWNSENSITIVITY) {
2374 auto pipeline = PipelineBase::GetCurrentContextSafelyWithCheck();
2375 CHECK_NULL_RETURN(pipeline, DEFAULT_CROWNSENSITIVITY);
2376 auto pickerTheme = pipeline->GetTheme<PickerTheme>();
2377 CHECK_NULL_RETURN(pickerTheme, DEFAULT_CROWNSENSITIVITY);
2378 crownSensitivity_ = pickerTheme->GetDigitalCrownSensitivity();
2379 }
2380
2381 return crownSensitivity_;
2382 }
2383
SetDigitalCrownSensitivity(int32_t crownSensitivity)2384 void TextPickerColumnPattern::SetDigitalCrownSensitivity(int32_t crownSensitivity)
2385 {
2386 crownSensitivity_ = crownSensitivity;
2387 }
2388
OnCrownEvent(const CrownEvent & event)2389 bool TextPickerColumnPattern::OnCrownEvent(const CrownEvent& event)
2390 {
2391 CHECK_NULL_RETURN(circleUtils_, false);
2392 return circleUtils_->OnCrownEvent(this, event);
2393 }
2394
HandleCrownBeginEvent(const CrownEvent & event)2395 void TextPickerColumnPattern::HandleCrownBeginEvent(const CrownEvent& event)
2396 {
2397 auto toss = GetToss();
2398 CHECK_NULL_VOID(toss);
2399 auto offsetY = 0.0;
2400 toss->SetStart(offsetY);
2401 yLast_ = offsetY;
2402 overscroller_.SetStart(offsetY);
2403 pressed_ = true;
2404 isCrownEventEnded_ = false;
2405 auto frameNode = GetHost();
2406 CHECK_NULL_VOID(frameNode);
2407 frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, yLast_, SceneStatus::START);
2408
2409 if (animation_) {
2410 AnimationUtils::StopAnimation(animation_);
2411 }
2412
2413 if (NotLoopOptions() && reboundAnimation_) {
2414 AnimationUtils::StopAnimation(reboundAnimation_);
2415 isReboundInProgress_ = false;
2416 overscroller_.ResetVelocity();
2417 overscroller_.SetOverScroll(scrollDelta_);
2418 }
2419 }
2420
HandleCrownMoveEvent(const CrownEvent & event)2421 void TextPickerColumnPattern::HandleCrownMoveEvent(const CrownEvent& event)
2422 {
2423 SetMainVelocity(event.angularVelocity);
2424 animationBreak_ = false;
2425 isCrownEventEnded_ = false;
2426 CHECK_NULL_VOID(pressed_);
2427 auto toss = GetToss();
2428 CHECK_NULL_VOID(toss);
2429 CHECK_NULL_VOID(circleUtils_);
2430 auto offsetY = circleUtils_->GetCrownRotatePx(event, GetDigitalCrownSensitivity());
2431 offsetY += yLast_;
2432 if (NearEqual(offsetY, yLast_, MOVE_THRESHOLD)) { // if changing less than MOVE_THRESHOLD, no need to handle
2433 return;
2434 }
2435 toss->SetEnd(offsetY);
2436 UpdateColumnChildPosition(offsetY);
2437 auto frameNode = GetHost();
2438 CHECK_NULL_VOID(frameNode);
2439 frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, mainVelocity_, SceneStatus::RUNNING);
2440 }
2441
HandleCrownEndEvent(const CrownEvent & event)2442 void TextPickerColumnPattern::HandleCrownEndEvent(const CrownEvent& event)
2443 {
2444 SetMainVelocity(event.angularVelocity);
2445 pressed_ = false;
2446 isCrownEventEnded_ = true;
2447 auto frameNode = GetHost();
2448 CHECK_NULL_VOID(frameNode);
2449 if (NotLoopOptions()) {
2450 frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, mainVelocity_, SceneStatus::END);
2451 if (overscroller_.IsOverScroll()) { // Start rebound animation. Higher priority than fling
2452 CreateReboundAnimation(overscroller_.GetOverScroll(), 0.0);
2453 StopHapticController();
2454 return;
2455 }
2456 }
2457
2458 yOffset_ = 0.0;
2459 yLast_ = 0.0;
2460 if (!animationCreated_) {
2461 ScrollOption(0.0);
2462 return;
2463 }
2464
2465 ScrollDirection dir = GreatNotEqual(scrollDelta_, 0.0f) ? ScrollDirection::DOWN : ScrollDirection::UP;
2466 auto middleIndex = static_cast<int32_t>(GetShowOptionCount()) / HALF_NUMBER;
2467 auto shiftDistance = (dir == ScrollDirection::DOWN) ? optionProperties_[middleIndex].nextDistance
2468 : optionProperties_[middleIndex].prevDistance;
2469 auto shiftThreshold = shiftDistance / HALF_NUMBER;
2470 if (std::abs(scrollDelta_) >= std::abs(shiftThreshold)) {
2471 InnerHandleScroll(LessNotEqual(scrollDelta_, 0.0), true, false);
2472 scrollDelta_ = scrollDelta_ - std::abs(shiftDistance) * (dir == ScrollDirection::UP ? -1 : 1);
2473 }
2474 CreateAnimation(scrollDelta_, 0.0);
2475 frameNode->AddFRCSceneInfo(PICKER_DRAG_SCENE, mainVelocity_, SceneStatus::END);
2476 StopHapticController();
2477 }
2478 #endif
2479
2480 } // namespace OHOS::Ace::NG
2481