• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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