• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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/scroll/inner/scroll_bar.h"
17 
18 #include "base/log/dump_log.h"
19 #include "core/common/vibrator/vibrator_utils.h"
20 
21 namespace OHOS::Ace::NG {
22 namespace {
23 constexpr int32_t BAR_DISAPPRAE_DELAY_DURATION = 2000; // 2000ms
24 constexpr double BAR_ADAPT_EPSLION = 1.0;
25 constexpr int32_t SCROLL_BAR_LAYOUT_INFO_COUNT = 30;
26 constexpr int32_t LONG_PRESS_PAGE_INTERVAL_MS = 100;
27 constexpr int32_t LONG_PRESS_TIME_THRESHOLD_MS = 500;
28 constexpr int32_t OGN_FIGNERID = -1;
29 #ifdef ARKUI_WEARABLE
30 constexpr char SCROLL_BAR_VIBRATOR_WEAK[] = "watchhaptic.feedback.crown.strength3";
31 #endif
32 } // namespace
33 
ScrollBar()34 ScrollBar::ScrollBar()
35 {
36     InitTheme();
37 }
38 
ScrollBar(DisplayMode displayMode,ShapeMode shapeMode,PositionMode positionMode)39 ScrollBar::ScrollBar(DisplayMode displayMode, ShapeMode shapeMode, PositionMode positionMode) : ScrollBar()
40 {
41     displayMode_ = displayMode;
42     shapeMode_ = shapeMode;
43     positionMode_ = positionMode;
44 }
45 
InitTheme()46 void ScrollBar::InitTheme()
47 {
48     auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
49     CHECK_NULL_VOID(pipelineContext);
50     auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
51     CHECK_NULL_VOID(theme);
52     themeNormalWidth_ = theme->GetNormalWidth();
53     SetInactiveWidth(themeNormalWidth_);
54     SetNormalWidth(themeNormalWidth_, pipelineContext);
55     SetActiveWidth(theme->GetActiveWidth());
56     SetTouchWidth(theme->GetTouchWidth());
57     SetMinHeight(theme->GetMinHeight());
58     SetMinDynamicHeight(theme->GetMinDynamicHeight());
59     SetBackgroundColor(theme->GetBackgroundColor());
60     SetForegroundColor(theme->GetForegroundColor());
61     SetForegroundHoverBlendColor(theme->GetForegroundHoverBlendColor());
62     SetForegroundPressedBlendColor(theme->GetForegroundPressedBlendColor());
63     SetPadding(theme->GetPadding());
64     SetHoverWidth(theme);
65     SetArcNormalBackgroundWidth(theme->GetArcNormalBackgroundWidth());
66     SetArcActiveBackgroundWidth(theme->GetArcActiveBackgroundWidth());
67     SetArcNormalStartAngle(theme->GetArcNormalStartAngle());
68     SetArcActiveStartAngle(theme->GetArcActiveStartAngle());
69     SetArcNormalMaxOffsetAngle(theme->GetArcNormalMaxOffsetAngle());
70     SetArcActiveMaxOffsetAngle(theme->GetArcActiveMaxOffsetAngle());
71     SetArcNormalScrollBarWidth(theme->GetArcNormalScrollBarWidth());
72     SetArcActiveScrollBarWidth(theme->GetArcActiveScrollBarWidth());
73     SetArcForegroundColor(theme->GetArcForegroundColor());
74     SetArcBackgroundColor(theme->GetArcBackgroundColor());
75 }
76 
InBarTouchRegion(const Point & point) const77 bool ScrollBar::InBarTouchRegion(const Point& point) const
78 {
79     if (NeedPaint() && shapeMode_ == ShapeMode::RECT) {
80         return touchRegion_.IsInRegion(point);
81     }
82     return false;
83 }
84 
InBarHoverRegion(const Point & point) const85 bool ScrollBar::InBarHoverRegion(const Point& point) const
86 {
87     if (NeedPaint() && shapeMode_ == ShapeMode::RECT) {
88         return hoverRegion_.IsInRegion(point);
89     }
90     return false;
91 }
92 
InBarRectRegion(const Point & point) const93 bool ScrollBar::InBarRectRegion(const Point& point) const
94 {
95     if (NeedPaint() && shapeMode_ == ShapeMode::RECT) {
96         return barRect_.IsInRegion(point);
97     }
98     return false;
99 }
100 
CheckBarDirection(const Point & point)101 BarDirection ScrollBar::CheckBarDirection(const Point& point)
102 {
103     if (!InBarRectRegion(point)) {
104         return BarDirection::BAR_NONE;
105     }
106     auto touchRegion = GetTouchRegion();
107     auto pointOffset = OffsetF(point.GetX(), point.GetY());
108     auto scrollBarTopOffset = OffsetF(touchRegion.Left(), touchRegion.Top());
109     auto scrollBarBottomOffset = OffsetF(touchRegion.Right(), touchRegion.Bottom());
110     auto axis = positionMode_ == PositionMode::BOTTOM ? Axis::HORIZONTAL : Axis::VERTICAL;
111     if (pointOffset.GetMainOffset(axis) < scrollBarTopOffset.GetMainOffset(axis)) {
112         return BarDirection::PAGE_UP;
113     } else if (pointOffset.GetMainOffset(axis) > scrollBarBottomOffset.GetMainOffset(axis)) {
114         return BarDirection::PAGE_DOWN;
115     } else {
116         return BarDirection::BAR_NONE;
117     }
118 }
119 
FlushBarWidth(const RefPtr<PipelineContext> & context)120 void ScrollBar::FlushBarWidth(const RefPtr<PipelineContext>& context)
121 {
122     if (shapeMode_ == ShapeMode::RECT) {
123         SetRectTrickRegion(paintOffset_, viewPortSize_, lastOffset_, estimatedHeight_, SCROLL_FROM_NONE, context);
124     } else {
125         SetRoundTrickRegion(paintOffset_, viewPortSize_, lastOffset_, estimatedHeight_);
126     }
127     SetBarRegion(paintOffset_, viewPortSize_, context);
128 }
129 
UpdateScrollBarRegion(const Offset & offset,const Size & size,const Offset & lastOffset,double estimatedHeight,int32_t scrollSource)130 void ScrollBar::UpdateScrollBarRegion(
131     const Offset& offset, const Size& size, const Offset& lastOffset, double estimatedHeight, int32_t scrollSource)
132 {
133     // return if nothing changes to avoid changing opacity
134     if (!positionModeUpdate_ && !normalWidthUpdate_ && paintOffset_ == offset && viewPortSize_ == size &&
135         lastOffset_ == lastOffset && NearEqual(estimatedHeight_, estimatedHeight, 0.000001f) && !isReverseUpdate_ &&
136         !isScrollBarMarginUpdate_) {
137         return;
138     }
139     // When the scroll jumps without animation and is at the top or bottom before and after the jump,
140     // the scrollbar is not displayed.
141     auto checkAtEdge = (scrollSource == SCROLL_FROM_JUMP || scrollSource == SCROLL_FROM_FOCUS_JUMP) &&
142         displayMode_ == DisplayMode::AUTO && isScrollable_;
143     if (checkAtEdge) {
144         auto atTop = NearZero(GetMainOffset(lastOffset_)) && NearZero(GetMainOffset(lastOffset));
145         auto atBottom = NearEqual(GetMainOffset(lastOffset_), estimatedHeight_ - GetMainSize(viewPortSize_)) &&
146                         NearEqual(GetMainOffset(lastOffset), estimatedHeight - GetMainSize(size));
147         if (!atTop && !atBottom) {
148             opacityAnimationType_  = OpacityAnimationType::APPEAR_WITHOUT_ANIMATION;
149             ScheduleDisappearDelayTask();
150         }
151     }
152     if (!NearEqual(estimatedHeight_, estimatedHeight, 0.000001f) || viewPortSize_ != size) {
153         needAddLayoutInfo = true;
154     }
155     if (!NearZero(estimatedHeight)) {
156         paintOffset_ = offset;
157         viewPortSize_ = size;
158         lastOffset_ = lastOffset;
159         estimatedHeight_ = estimatedHeight;
160         if (shapeMode_ == ShapeMode::RECT) {
161             SetRectTrickRegion(offset, size, lastOffset, estimatedHeight, scrollSource);
162         } else {
163             SetRoundTrickRegion(offset, size, lastOffset, estimatedHeight);
164         }
165         SetBarRegion(offset, size);
166         positionModeUpdate_ = false;
167         normalWidthUpdate_ = false;
168         isReverseUpdate_ = false;
169         isScrollBarMarginUpdate_ = false;
170     }
171     needAddLayoutInfo =false;
172 }
173 
UpdateActiveRectSize(double activeSize)174 void ScrollBar::UpdateActiveRectSize(double activeSize)
175 {
176     if (positionMode_ == PositionMode::LEFT || positionMode_ == PositionMode::RIGHT) {
177         activeRect_.SetHeight(activeSize);
178         touchRegion_.SetHeight(activeSize);
179         hoverRegion_.SetHeight(activeSize);
180     } else if (positionMode_ == PositionMode::BOTTOM) {
181         activeRect_.SetWidth(activeSize);
182         touchRegion_.SetWidth(activeSize);
183         hoverRegion_.SetWidth(activeSize);
184     }
185 }
186 
UpdateActiveRectOffset(double activeMainOffset)187 void ScrollBar::UpdateActiveRectOffset(double activeMainOffset)
188 {
189     if (positionMode_ == PositionMode::LEFT || positionMode_ == PositionMode::RIGHT) {
190         activeMainOffset = std::min(activeMainOffset, barRegionSize_ - activeRect_.Height());
191         activeRect_.SetTop(activeMainOffset);
192         touchRegion_.SetTop(activeMainOffset);
193         hoverRegion_.SetTop(activeMainOffset);
194     } else if (positionMode_ == PositionMode::BOTTOM) {
195         activeMainOffset = std::min(activeMainOffset, barRegionSize_ - activeRect_.Width());
196         activeRect_.SetLeft(activeMainOffset);
197         touchRegion_.SetLeft(activeMainOffset);
198         hoverRegion_.SetLeft(activeMainOffset);
199     }
200 }
201 
SetBarRegion(const Offset & offset,const Size & size,const RefPtr<PipelineContext> & context)202 void ScrollBar::SetBarRegion(const Offset& offset, const Size& size, const RefPtr<PipelineContext>& context)
203 {
204     if (shapeMode_ == ShapeMode::RECT) {
205         double mainSize = (positionMode_ == PositionMode::BOTTOM ? size.Width() : size.Height());
206         auto scrollBarMarginStart =
207             scrollBarMargin_.has_value() ? scrollBarMargin_.value().start_.ConvertToPxWithSize(mainSize) : 0.0;
208         auto scrollBarMarginEnd =
209             scrollBarMargin_.has_value() ? scrollBarMargin_.value().end_.ConvertToPxWithSize(mainSize) : 0.0;
210         double reserved = NormalizeToPx(startReservedHeight_, context) + NormalizeToPx(endReservedHeight_, context) +
211             scrollBarMarginStart + scrollBarMarginEnd;
212         double height = std::max(size.Height() - reserved, 0.0);
213         auto hoverWidth = isUserNormalWidth_ ? barWidth_ : NormalizeToPx(hoverWidth_, context);
214         if (positionMode_ == PositionMode::LEFT) {
215             auto padding = isUserNormalWidth_ ? NormalizeToPx(padding_.Left(), context) : 0.0;
216             barRect_ = Rect(padding, 0.0, hoverWidth, height) + offset;
217         } else if (positionMode_ == PositionMode::RIGHT) {
218             auto padding = isUserNormalWidth_ ? NormalizeToPx(padding_.Right(), context) : 0.0;
219             barRect_ = Rect(size.Width() - hoverWidth - padding, 0.0, hoverWidth, height) + offset;
220         } else if (positionMode_ == PositionMode::BOTTOM) {
221             auto trackWidth = std::max(size.Width() - reserved, 0.0);
222             auto padding = isUserNormalWidth_ ? NormalizeToPx(padding_.Bottom(), context) : 0.0;
223             barRect_ = Rect(0.0, size.Height() - hoverWidth - padding, trackWidth, hoverWidth) + offset;
224         }
225     }
226 }
227 
SetRectTrickRegion(const Offset & offset,const Size & size,const Offset & lastOffset,double estimatedHeight,int32_t scrollSource,const RefPtr<PipelineContext> & context)228 void ScrollBar::SetRectTrickRegion(const Offset& offset, const Size& size, const Offset& lastOffset,
229     double estimatedHeight, int32_t scrollSource, const RefPtr<PipelineContext>& context)
230 {
231     double mainSize = (positionMode_ == PositionMode::BOTTOM ? size.Width() : size.Height());
232     auto scrollBarMarginStart =
233         scrollBarMargin_.has_value() ? scrollBarMargin_.value().start_.ConvertToPxWithSize(mainSize) : 0.0;
234     auto scrollBarMarginEnd =
235         scrollBarMargin_.has_value() ? scrollBarMargin_.value().end_.ConvertToPxWithSize(mainSize) : 0.0;
236     barRegionSize_ = std::max(mainSize - NormalizeToPx(endReservedHeight_, context) -
237         NormalizeToPx(startReservedHeight_, context) - scrollBarMarginStart - scrollBarMarginEnd, 0.0);
238     if (LessOrEqual(estimatedHeight, 0.0)) {
239         return;
240     }
241     double activeBarSize = barRegionSize_ * mainSize / estimatedHeight;
242     double activeSize = activeBarSize - outBoundary_;
243     bool hideBarForSmallRegionWithMargin =
244         LessNotEqual(barRegionSize_, NormalizeToPx(minHeight_, context)) && scrollBarMargin_.has_value();
245     if (hideBarForSmallRegionWithMargin) {
246         activeSize = 0.0;
247     } else {
248         if (!NearZero(outBoundary_)) {
249             activeSize = std::max(std::max(activeSize, NormalizeToPx(minHeight_, context) - outBoundary_),
250                 NormalizeToPx(minDynamicHeight_, context));
251         } else {
252             activeSize = std::max(activeSize, NormalizeToPx(minHeight_, context));
253         }
254         barWidth_ = NormalizeToPx(normalWidth_, context);
255         if (LessOrEqual(activeSize, barWidth_)) {
256             if (GreatNotEqual(barWidth_, mainSize)) {
257                 barWidth_ = NormalizeToPx(themeNormalWidth_, context);
258             } else {
259                 activeSize = barWidth_;
260             }
261         }
262     }
263 
264     double lastMainOffset =
265         std::max(positionMode_ == PositionMode::BOTTOM ? lastOffset.GetX() : lastOffset.GetY(), 0.0);
266     if (NearEqual(mainSize, estimatedHeight)) {
267         offsetScale_ = 0.0;
268     } else {
269         offsetScale_ = (barRegionSize_ - activeSize) / (estimatedHeight - mainSize);
270     }
271     // Calculate relative offset first
272     double relativeOffset = std::min(offsetScale_ * lastMainOffset, barRegionSize_ - activeSize);
273     if (isReverse_) {
274         relativeOffset = barRegionSize_ - activeSize - relativeOffset;
275     }
276     // Convert to absolute position
277     double activeMainOffset = relativeOffset + NormalizeToPx(startReservedHeight_) + scrollBarMarginStart;
278     bool canUseAnimation = NearZero(outBoundary_) && !positionModeUpdate_ && scrollSource != SCROLL_FROM_JUMP;
279     double inactiveSize = 0.0;
280     double inactiveMainOffset = 0.0;
281     scrollableOffset_ = activeMainOffset;
282     CalcScrollBarRegion(activeMainOffset, activeSize, offset, size, inactiveMainOffset, inactiveSize);
283     AddScrollBarLayoutInfo();
284     // If the scrollBar length changes, start the adaptation animation
285     if (!NearZero(inactiveSize) && !NearEqual(activeSize, inactiveSize, BAR_ADAPT_EPSLION) && canUseAnimation &&
286         !Negative(inactiveMainOffset) && !normalWidthUpdate_ && !hideBarForSmallRegionWithMargin) {
287         PlayScrollBarAdaptAnimation();
288     } else {
289         needAdaptAnimation_ = false;
290     }
291 }
292 
CalcScrollBarRegion(double activeMainOffset,double activeSize,const Offset & offset,const Size & size,double & inactiveMainOffset,double & inactiveSize)293 void ScrollBar::CalcScrollBarRegion(double activeMainOffset, double activeSize, const Offset& offset, const Size& size,
294     double& inactiveMainOffset, double& inactiveSize)
295 {
296     if (positionMode_ == PositionMode::LEFT) {
297         inactiveSize = activeRect_.Height();
298         inactiveMainOffset = activeRect_.Top();
299         activeRect_ = Rect(-NormalizeToPx(position_) + NormalizeToPx(padding_.Left()),
300             activeMainOffset, barWidth_, activeSize) + offset;
301         if (isUserNormalWidth_) {
302             touchRegion_ = activeRect_;
303             hoverRegion_ = activeRect_;
304         } else {
305             touchRegion_ = activeRect_ + Size(NormalizeToPx(touchWidth_), 0);
306             hoverRegion_ = activeRect_ + Size(NormalizeToPx(hoverWidth_), 0);
307         }
308     } else if (positionMode_ == PositionMode::RIGHT) {
309         inactiveSize = activeRect_.Height();
310         inactiveMainOffset = activeRect_.Top();
311         double x = size.Width() - barWidth_ - NormalizeToPx(padding_.Right()) + NormalizeToPx(position_);
312         activeRect_ = Rect(x, activeMainOffset, barWidth_, activeSize) + offset;
313         // Update the hot region
314         if (isUserNormalWidth_) {
315             touchRegion_ = activeRect_;
316             hoverRegion_ = activeRect_;
317         } else {
318             touchRegion_ =
319                 activeRect_ - Offset(NormalizeToPx(touchWidth_) - barWidth_ - NormalizeToPx(padding_.Right()), 0.0) +
320                 Size(NormalizeToPx(touchWidth_) - barWidth_, 0);
321             hoverRegion_ =
322                 activeRect_ - Offset(NormalizeToPx(hoverWidth_) - barWidth_ - NormalizeToPx(padding_.Right()), 0.0) +
323                 Size(NormalizeToPx(hoverWidth_) - barWidth_, 0);
324         }
325     } else if (positionMode_ == PositionMode::BOTTOM) {
326         inactiveSize = activeRect_.Width();
327         inactiveMainOffset = activeRect_.Left();
328         auto positionY = size.Height() - barWidth_ - NormalizeToPx(padding_.Bottom()) + NormalizeToPx(position_);
329         activeRect_ = Rect(activeMainOffset, positionY, activeSize, barWidth_) + offset;
330         if (isUserNormalWidth_) {
331             touchRegion_ = activeRect_;
332             hoverRegion_ = activeRect_;
333         } else {
334             auto hotRegionOffset = Offset(
335                 0.0, NormalizeToPx(touchWidth_) - barWidth_ - NormalizeToPx(padding_.Bottom()));
336             auto hotRegionSize = Size(0, NormalizeToPx(touchWidth_) - barWidth_);
337             touchRegion_ = activeRect_ - hotRegionOffset + hotRegionSize;
338 
339             auto hoverRegionOffset = Offset(
340                 0.0, NormalizeToPx(hoverWidth_) - barWidth_ - NormalizeToPx(padding_.Bottom()));
341             auto hoverRegionSize = Size(0, NormalizeToPx(hoverWidth_) - barWidth_);
342             hoverRegion_ = activeRect_ - hoverRegionOffset + hoverRegionSize;
343         }
344     }
345 }
346 
SetRoundTrickRegion(const Offset & offset,const Size & size,const Offset & lastOffset,double estimatedHeight)347 void ScrollBar::SetRoundTrickRegion(
348     const Offset& offset, const Size& size, const Offset& lastOffset, double estimatedHeight)
349 {
350     double diameter = std::min(size.Width(), size.Height());
351     if (!NearEqual(estimatedHeight, diameter)) {
352         double maxAngle = bottomAngle_ - topAngle_;
353         trickSweepAngle_ = std::max(diameter * maxAngle / estimatedHeight, minAngle_);
354         double lastOffsetY = std::max(lastOffset.GetY(), 0.0);
355         double trickStartAngle = (maxAngle - trickSweepAngle_) * lastOffsetY / (estimatedHeight - diameter);
356         trickStartAngle = std::clamp(0.0, trickStartAngle, maxAngle) - maxAngle * FACTOR_HALF;
357         if (positionMode_ == PositionMode::LEFT) {
358             if (trickStartAngle > 0.0) {
359                 trickStartAngle_ = STRAIGHT_ANGLE - trickStartAngle;
360             } else {
361                 trickStartAngle_ = -(trickStartAngle + STRAIGHT_ANGLE);
362             }
363             trickSweepAngle_ = -trickSweepAngle_;
364         } else {
365             trickStartAngle_ = trickStartAngle;
366         }
367     }
368 }
369 
NeedScrollBar() const370 bool ScrollBar::NeedScrollBar() const
371 {
372     return displayMode_ == DisplayMode::AUTO || displayMode_ == DisplayMode::ON;
373 }
374 
NeedPaint() const375 bool ScrollBar::NeedPaint() const
376 {
377     return NeedScrollBar() && isScrollable_;
378 }
379 
GetNormalWidthToPx() const380 double ScrollBar::GetNormalWidthToPx() const
381 {
382     return NormalizeToPx(normalWidth_);
383 }
384 
CalcPatternOffset(float scrollBarOffset) const385 float ScrollBar::CalcPatternOffset(float scrollBarOffset) const
386 {
387     auto activeRectLength = positionMode_ == PositionMode::BOTTOM ? activeRect_.Width() : activeRect_.Height();
388     if (!isDriving_ || NearZero(barRegionSize_ - activeRectLength)) {
389         return scrollBarOffset;
390     }
391     auto mainSize = (positionMode_ == PositionMode::BOTTOM ? viewPortSize_.Width() : viewPortSize_.Height());
392     return -scrollBarOffset * (estimatedHeight_ - mainSize) / (barRegionSize_ - activeRectLength);
393 }
394 
NormalizeToPx(const Dimension & dimension,const RefPtr<PipelineContext> & context) const395 double ScrollBar::NormalizeToPx(const Dimension& dimension, const RefPtr<PipelineContext>& context) const
396 {
397     auto pipelineContext = context ? context : PipelineContext::GetCurrentContextSafelyWithCheck();
398     CHECK_NULL_RETURN(pipelineContext, 0.0);
399     return pipelineContext->NormalizeToPx(dimension);
400 }
401 
SetGestureEvent()402 void ScrollBar::SetGestureEvent()
403 {
404     if (!touchEvent_) {
405         touchEvent_ = MakeRefPtr<TouchEventImpl>([weak = WeakClaim(this)](const TouchEventInfo& info) {
406             auto scrollBar = weak.Upgrade();
407             CHECK_NULL_VOID(scrollBar && scrollBar->IsScrollable());
408             if (info.GetTouches().empty()) {
409                 return;
410             }
411             auto touch = info.GetTouches().front();
412             if (touch.GetTouchType() == TouchType::DOWN) {
413                 TAG_LOGI(AceLogTag::ACE_SCROLL_BAR, "inner scrollBar touch down, panDirection: %{public}u",
414                     scrollBar->GetPanDirection());
415                 Point point(touch.GetLocalLocation().GetX(), touch.GetLocalLocation().GetY());
416                 bool inRegion = false;
417                 if (info.GetSourceDevice() == SourceType::TOUCH) {
418                     inRegion = scrollBar->InBarTouchRegion(point);
419                 } else if (info.GetSourceDevice() == SourceType::MOUSE) {
420                     inRegion = scrollBar->InBarHoverRegion(point);
421                     scrollBar->MarkNeedRender();
422                 }
423                 if (inRegion) {
424                     scrollBar->fingerId_ = touch.GetFingerId();
425                 }
426                 if (!scrollBar->IsPressed()) {
427                     scrollBar->SetPressed(inRegion);
428                 }
429                 if (inRegion && !scrollBar->IsHover()) {
430                     scrollBar->PlayScrollBarGrowAnimation();
431                 }
432             }
433             if ((info.GetTouches().front().GetTouchType() == TouchType::UP ||
434                     info.GetTouches().front().GetTouchType() == TouchType::CANCEL) &&
435                     (scrollBar->fingerId_ == info.GetTouches().front().GetFingerId())) {
436                 if (scrollBar->IsPressed() && !scrollBar->IsHover()) {
437                     scrollBar->PlayScrollBarShrinkAnimation();
438                     scrollBar->ScheduleDisappearDelayTask();
439                 }
440                 scrollBar->SetPressed(false);
441                 scrollBar->fingerId_ = OGN_FIGNERID;
442                 scrollBar->MarkNeedRender();
443             }
444         });
445     }
446     if (!panRecognizer_) {
447         InitPanRecognizer();
448     }
449 }
450 
SetMouseEvent()451 void ScrollBar::SetMouseEvent()
452 {
453     if (mouseEvent_) {
454         return;
455     }
456     mouseEvent_ = MakeRefPtr<InputEvent>([weak = WeakClaim(this)](MouseInfo& info) {
457         auto scrollBar = weak.Upgrade();
458         CHECK_NULL_VOID(scrollBar && scrollBar->IsScrollable());
459         Point point(info.GetLocalLocation().GetX(), info.GetLocalLocation().GetY());
460         bool inBarRegion = scrollBar->InBarRectRegion(point);
461         bool inHoverRegion = scrollBar->InBarHoverRegion(point);
462         if (inBarRegion) {
463             scrollBar->PlayScrollBarAppearAnimation();
464             if (info.GetButton() == MouseButton::LEFT_BUTTON && info.GetAction() == MouseAction::PRESS) {
465                 scrollBar->isMousePressed_ = true;
466             } else {
467                 scrollBar->isMousePressed_ = false;
468             }
469             scrollBar->isShowScrollBar_ = true;
470         }
471         if (inBarRegion && !scrollBar->IsHover()) {
472             if (!scrollBar->IsPressed()) {
473                 scrollBar->PlayScrollBarGrowAnimation();
474             }
475             scrollBar->SetHover(true);
476         }
477         if (scrollBar->IsHover() && !inBarRegion) {
478             scrollBar->SetHover(false);
479             if (!scrollBar->IsPressed()) {
480                 scrollBar->PlayScrollBarShrinkAnimation();
481             }
482         }
483         scrollBar->SetHoverSlider(inHoverRegion);
484         if (!inBarRegion && !inHoverRegion && !scrollBar->IsPressed() && scrollBar->isShowScrollBar_) {
485             scrollBar->ScheduleDisappearDelayTask();
486             scrollBar->isShowScrollBar_ = false;
487         }
488         scrollBar->locationInfo_ = info.GetLocalLocation();
489     });
490     if (!longPressRecognizer_) {
491         InitLongPressEvent();
492     }
493 }
494 
SetHoverEvent()495 void ScrollBar::SetHoverEvent()
496 {
497     CHECK_NULL_VOID(!hoverEvent_);
498     hoverEvent_ = MakeRefPtr<InputEvent>([weak = WeakClaim(this)](bool isHover) {
499         auto scrollBar = weak.Upgrade();
500         CHECK_NULL_VOID(scrollBar && scrollBar->IsScrollable());
501         if (scrollBar->IsHover() && !isHover) {
502             scrollBar->SetHover(false);
503             scrollBar->SetHoverSlider(false);
504             if (!scrollBar->IsPressed()) {
505                 scrollBar->PlayScrollBarShrinkAnimation();
506                 scrollBar->ScheduleDisappearDelayTask();
507             }
508         }
509     });
510 }
511 
OnCollectLongPressTarget(const OffsetF & coordinateOffset,const GetEventTargetImpl & getEventTargetImpl,TouchTestResult & result,const RefPtr<FrameNode> & frameNode,const RefPtr<TargetComponent> & targetComponent,ResponseLinkResult & responseLinkResult)512 void ScrollBar::OnCollectLongPressTarget(const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
513     TouchTestResult& result, const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
514     ResponseLinkResult& responseLinkResult)
515 {
516     if (longPressRecognizer_ && isScrollable_) {
517         longPressRecognizer_->SetCoordinateOffset(Offset(coordinateOffset.GetX(), coordinateOffset.GetY()));
518         longPressRecognizer_->SetGetEventTargetImpl(getEventTargetImpl);
519         longPressRecognizer_->SetNodeId(frameNode->GetId());
520         longPressRecognizer_->AttachFrameNode(frameNode);
521         longPressRecognizer_->SetTargetComponent(targetComponent);
522         longPressRecognizer_->SetIsSystemGesture(true);
523         longPressRecognizer_->SetRecognizerType(GestureTypeName::LONG_PRESS_GESTURE);
524         longPressRecognizer_->SetSysGestureJudge([](const RefPtr<GestureInfo>& gestureInfo,
525                                                  const std::shared_ptr<BaseGestureEvent>&) -> GestureJudgeResult {
526             const auto &inputEventType = gestureInfo->GetInputEventType();
527             TAG_LOGI(AceLogTag::ACE_SCROLL_BAR, "input event type:%{public}d", inputEventType);
528             if (inputEventType == InputEventType::MOUSE_BUTTON) {
529                 return GestureJudgeResult::CONTINUE;
530             }
531             return GestureJudgeResult::REJECT;
532         });
533         result.emplace_front(longPressRecognizer_);
534         responseLinkResult.emplace_back(longPressRecognizer_);
535     }
536 }
537 
InitLongPressEvent()538 void ScrollBar::InitLongPressEvent()
539 {
540     longPressRecognizer_ = AceType::MakeRefPtr<LongPressRecognizer>(LONG_PRESS_TIME_THRESHOLD_MS, 1, false, false);
541     longPressRecognizer_->SetOnAction([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
542         auto scrollBar = weakBar.Upgrade();
543         if (scrollBar) {
544             scrollBar->HandleLongPress(true);
545         }
546     });
547 }
548 
HandleLongPress(bool smooth)549 void ScrollBar::HandleLongPress(bool smooth)
550 {
551     Point point(locationInfo_.GetX(), locationInfo_.GetY());
552     bool reverse = false;
553     if (AnalysisUpOrDown(point, reverse) && isMousePressed_) {
554         scrollPageCallback_(reverse, smooth);
555         ScheduleCaretLongPress();
556     }
557 }
558 
AnalysisUpOrDown(Point point,bool & reverse)559 bool ScrollBar::AnalysisUpOrDown(Point point, bool& reverse)
560 {
561     switch (CheckBarDirection(point)) {
562         case BarDirection::BAR_NONE:
563             return false;
564         case BarDirection::PAGE_UP:
565             reverse = true;
566             return true;
567         case BarDirection::PAGE_DOWN:
568             reverse = false;
569             return true;
570     }
571 }
572 
ScheduleCaretLongPress()573 void ScrollBar::ScheduleCaretLongPress()
574 {
575     auto context = PipelineContext::GetCurrentContextSafelyWithCheck();
576     CHECK_NULL_VOID(context);
577     if (!context->GetTaskExecutor()) {
578         return;
579     }
580     auto taskExecutor = context->GetTaskExecutor();
581     CHECK_NULL_VOID(taskExecutor);
582     taskExecutor->PostDelayedTask(
583         [weak = WeakClaim(this)]() {
584             auto pattern = weak.Upgrade();
585             CHECK_NULL_VOID(pattern);
586             pattern->HandleLongPress(true);
587         },
588         TaskExecutor::TaskType::UI, LONG_PRESS_PAGE_INTERVAL_MS, "ArkUIScrollBarInnerHandleLongPress");
589 }
590 
CalcReservedHeight(const RefPtr<PipelineContext> & context)591 void ScrollBar::CalcReservedHeight(const RefPtr<PipelineContext>& context)
592 {
593     auto pipelineContext = context ? context : PipelineContext::GetCurrentContextSafelyWithCheck();
594     CHECK_NULL_VOID(pipelineContext);
595     if (pipelineContext->GetMinPlatformVersion() < static_cast<int32_t>(PlatformVersion::VERSION_TEN)) {
596         auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
597         CHECK_NULL_VOID(theme);
598         startReservedHeight_ = Dimension(0.0, DimensionUnit::PX);
599         endReservedHeight_ = theme->GetReservedHeight();
600         FlushBarWidth();
601         return;
602     }
603     float startRadius = 0.f;
604     float endRadius = 0.f;
605     float barMargin = 0.f;
606     float padding = 0.f;
607     float startRadiusHeight = 0.f;
608     float endRadiusHeight = 0.f;
609     GetRadiusAndPadding(startRadius, endRadius, padding, pipelineContext);
610     if (std::isnan(startRadius)) {
611         startRadius = 0.f;
612     }
613     if (std::isnan(endRadius)) {
614         endRadius = 0.f;
615     }
616     // 2 means start margin and end margin
617     barMargin = padding + NormalizeToPx(normalWidth_, pipelineContext) / 2;
618     if (LessOrEqual(startRadius, barMargin)) {
619         startReservedHeight_ = Dimension(0.0, DimensionUnit::PX);
620     } else {
621         startRadiusHeight = startRadius - std::sqrt(2 * padding * startRadius - padding * padding);
622         startReservedHeight_ = Dimension(startRadiusHeight + (startRadius / barMargin), DimensionUnit::PX);
623     }
624 
625     if (LessOrEqual(endRadius, barMargin)) {
626         endReservedHeight_ = Dimension(0.0, DimensionUnit::PX);
627     } else {
628         endRadiusHeight = endRadius - std::sqrt(2 * padding * endRadius - padding * padding);
629         endReservedHeight_ = Dimension(endRadiusHeight + (endRadius / barMargin), DimensionUnit::PX);
630     }
631     FlushBarWidth(pipelineContext);
632 }
633 
GetRadiusAndPadding(float & startRadius,float & endRadius,float & padding,const RefPtr<PipelineContext> & context)634 void ScrollBar::GetRadiusAndPadding(
635     float& startRadius, float& endRadius, float& padding, const RefPtr<PipelineContext>& context)
636 {
637     switch (positionMode_) {
638         case PositionMode::LEFT:
639             startRadius = hostBorderRadius_.radiusTopLeft.value_or(Dimension()).ConvertToPx();
640             endRadius = hostBorderRadius_.radiusBottomLeft.value_or(Dimension()).ConvertToPx();
641             padding = NormalizeToPx(padding_.Left(), context);
642             break;
643         case PositionMode::RIGHT:
644             startRadius = hostBorderRadius_.radiusTopRight.value_or(Dimension()).ConvertToPx();
645             endRadius = hostBorderRadius_.radiusBottomRight.value_or(Dimension()).ConvertToPx();
646             padding = NormalizeToPx(padding_.Right(), context);
647             break;
648         case PositionMode::BOTTOM:
649             startRadius = hostBorderRadius_.radiusBottomLeft.value_or(Dimension()).ConvertToPx();
650             endRadius = hostBorderRadius_.radiusBottomRight.value_or(Dimension()).ConvertToPx();
651             padding = NormalizeToPx(padding_.Bottom(), context);
652             break;
653         default:
654             break;
655     }
656 }
657 
InitPanRecognizer()658 void ScrollBar::InitPanRecognizer()
659 {
660     PanDirection panDirection;
661     panDirection.type = positionMode_ == PositionMode::BOTTOM ? PanDirection::HORIZONTAL : PanDirection::VERTICAL;
662     auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
663     double dipScale = pipelineContext ? pipelineContext->GetDipScale() : 0.0;
664     PanDistanceMap distanceMap = { { SourceTool::UNKNOWN, DEFAULT_PAN_DISTANCE.Value() * dipScale },
665         { SourceTool::PEN, DEFAULT_PEN_PAN_DISTANCE.Value() * dipScale } };
666     panRecognizer_ = MakeRefPtr<PanRecognizer>(1, panDirection, distanceMap);
667     panRecognizer_->SetMouseDistance(DRAG_PAN_DISTANCE_MOUSE.Value() * dipScale);
668     panRecognizer_->SetOnActionUpdate([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
669         auto scrollBar = weakBar.Upgrade();
670         if (scrollBar) {
671             scrollBar->HandleDragUpdate(info);
672         }
673     });
674     panRecognizer_->SetOnActionEnd([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
675         auto scrollBar = weakBar.Upgrade();
676         if (scrollBar) {
677             scrollBar->HandleDragEnd(info);
678         }
679     });
680     panRecognizer_->SetOnActionStart([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
681         auto scrollBar = weakBar.Upgrade();
682         if (scrollBar) {
683             scrollBar->HandleDragStart(info);
684         }
685     });
686     panRecognizer_->SetOnActionCancel([weakBar = AceType::WeakClaim(this)](const GestureEvent& info) {
687         auto scrollBar = weakBar.Upgrade();
688         if (scrollBar) {
689             GestureEvent info;
690             scrollBar->HandleDragEnd(info);
691         }
692     });
693 }
694 
StopFlingAnimation()695 void ScrollBar::StopFlingAnimation()
696 {
697     if (frictionController_ && frictionController_->IsRunning()) {
698         frictionController_->Stop();
699     }
700 }
701 
HandleDragStart(const GestureEvent & info)702 void ScrollBar::HandleDragStart(const GestureEvent& info)
703 {
704     StopFlingAnimation();
705     TAG_LOGI(AceLogTag::ACE_SCROLL_BAR, "inner scrollBar drag start");
706     ACE_SCOPED_TRACE("inner scrollBar HandleDragStart");
707     if (scrollPositionCallback_) {
708         scrollPositionCallback_(0, SCROLL_FROM_START, false);
709         if (dragFRCSceneCallback_) {
710             dragFRCSceneCallback_(0, NG::SceneStatus::START);
711         }
712     }
713     SetDragStartPosition(GetMainOffset(Offset(info.GetGlobalPoint().GetX(), info.GetGlobalPoint().GetY())));
714     isDriving_ = true;
715 }
716 
HandleDragUpdate(const GestureEvent & info)717 void ScrollBar::HandleDragUpdate(const GestureEvent& info)
718 {
719     // if historical touch point slope is zero but delta is not zero, no need to update.
720     auto mainDelta = info.GetMainDelta();
721     if (info.IsInterpolated()) {
722         if (GetPanDirection() == Axis::VERTICAL && NearZero(info.GetInputYDeltaSlope()) && !NearZero(mainDelta)) {
723             return;
724         } else if (GetPanDirection() == Axis::HORIZONTAL && NearZero(info.GetInputXDeltaSlope()) &&
725                    !NearZero(mainDelta)) {
726             return;
727         }
728     }
729     if (scrollPositionCallback_) {
730         // The offset of the mouse wheel and gesture is opposite.
731         auto offset = info.GetInputEventType() == InputEventType::AXIS ?
732                       info.GetMainDelta() : CalcPatternOffset(info.GetMainDelta());
733         if (IsReverse()) {
734             offset = -offset;
735         }
736         ACE_SCOPED_TRACE("inner scrollBar HandleDragUpdate offset:%f", offset);
737         auto isMouseWheelScroll =
738             info.GetInputEventType() == InputEventType::AXIS && info.GetSourceTool() != SourceTool::TOUCHPAD;
739         scrollPositionCallback_(offset, SCROLL_FROM_BAR, isMouseWheelScroll);
740         if (dragFRCSceneCallback_) {
741             dragFRCSceneCallback_(NearZero(info.GetMainDelta()) ? info.GetMainVelocity()
742                                                                 : info.GetMainVelocity() / info.GetMainDelta() * offset,
743                 NG::SceneStatus::RUNNING);
744         }
745     }
746 }
747 
HandleDragEnd(const GestureEvent & info)748 void ScrollBar::HandleDragEnd(const GestureEvent& info)
749 {
750     if (dragFRCSceneCallback_) {
751         dragFRCSceneCallback_(0, NG::SceneStatus::END);
752     }
753     auto velocity = IsReverse() ? -info.GetMainVelocity() : info.GetMainVelocity();
754     TAG_LOGI(AceLogTag::ACE_SCROLL_BAR, "inner scrollBar drag end, velocity is %{public}f", velocity);
755     ACE_SCOPED_TRACE("inner scrollBar HandleDragEnd velocity:%f", velocity);
756     if (NearZero(velocity) || info.GetInputEventType() == InputEventType::AXIS) {
757         if (scrollEndCallback_) {
758             scrollEndCallback_();
759         }
760         isDriving_ = false;
761         return;
762     }
763     SetDragEndPosition(GetMainOffset(Offset(info.GetGlobalPoint().GetX(), info.GetGlobalPoint().GetY())));
764     frictionPosition_ = 0.0;
765     if (frictionMotion_) {
766         frictionMotion_->Reset(friction_, 0, velocity);
767     } else {
768         frictionMotion_ = AceType::MakeRefPtr<FrictionMotion>(friction_, 0, velocity);
769         frictionMotion_->AddListener([weakBar = AceType::WeakClaim(this)](double value) {
770             auto scrollBar = weakBar.Upgrade();
771             CHECK_NULL_VOID(scrollBar);
772             scrollBar->ProcessFrictionMotion(value);
773         });
774     }
775     SnapAnimationOptions snapAnimationOptions = {
776         .snapDelta = CalcPatternOffset(frictionMotion_->GetFinalPosition()),
777         .animationVelocity = -velocity,
778         .dragDistance = CalcPatternOffset(GetDragOffset()),
779         .fromScrollBar = true,
780     };
781     if (startSnapAnimationCallback_ && startSnapAnimationCallback_(snapAnimationOptions)) {
782         isDriving_ = false;
783         return;
784     }
785 
786     if (!frictionController_) {
787         auto context = PipelineContext::GetCurrentContextSafelyWithCheck();
788         CHECK_NULL_VOID(context);
789         frictionController_ = CREATE_ANIMATOR(context);
790         frictionController_->AddStopListener([weakBar = AceType::WeakClaim(this)]() {
791             auto scrollBar = weakBar.Upgrade();
792             CHECK_NULL_VOID(scrollBar);
793             scrollBar->ProcessFrictionMotionStop();
794         });
795     }
796     frictionController_->PlayMotion(frictionMotion_);
797 }
798 
ProcessFrictionMotion(double value)799 void ScrollBar::ProcessFrictionMotion(double value)
800 {
801     if (scrollPositionCallback_) {
802         auto offset = CalcPatternOffset(value - frictionPosition_);
803         if (!scrollPositionCallback_(offset, SCROLL_FROM_BAR_FLING, false)) {
804             if (frictionController_ && frictionController_->IsRunning()) {
805                 frictionController_->Stop();
806             }
807         }
808     }
809     frictionPosition_ = value;
810 }
811 
ProcessFrictionMotionStop()812 void ScrollBar::ProcessFrictionMotionStop()
813 {
814     if (scrollEndCallback_) {
815         scrollEndCallback_();
816     }
817     isDriving_ = false;
818 }
819 
OnCollectTouchTarget(const OffsetF & coordinateOffset,const GetEventTargetImpl & getEventTargetImpl,TouchTestResult & result,const RefPtr<FrameNode> & frameNode,const RefPtr<TargetComponent> & targetComponent,ResponseLinkResult & responseLinkResult,bool inBarRect)820 void ScrollBar::OnCollectTouchTarget(const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
821     TouchTestResult& result, const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
822     ResponseLinkResult& responseLinkResult, bool inBarRect)
823 {
824     if (panRecognizer_ && isScrollable_) {
825         panRecognizer_->SetCoordinateOffset(Offset(coordinateOffset.GetX(), coordinateOffset.GetY()));
826         panRecognizer_->SetGetEventTargetImpl(getEventTargetImpl);
827         panRecognizer_->SetNodeId(frameNode->GetId());
828         panRecognizer_->AttachFrameNode(frameNode);
829         panRecognizer_->SetTargetComponent(targetComponent);
830         panRecognizer_->SetIsSystemGesture(true);
831         panRecognizer_->SetRecognizerType(GestureTypeName::PAN_GESTURE);
832         GestureJudgeFunc sysJudge = nullptr;
833         if (inBarRect) {
834             sysJudge = [](const RefPtr<GestureInfo>& gestureInfo,
835                           const std::shared_ptr<BaseGestureEvent>&) -> GestureJudgeResult {
836                 auto inputEventType = gestureInfo->GetInputEventType();
837                 return inputEventType == InputEventType::AXIS ? GestureJudgeResult::CONTINUE
838                                                               : GestureJudgeResult::REJECT;
839             };
840         }
841         panRecognizer_->SetSysGestureJudge(sysJudge);
842         result.emplace_front(panRecognizer_);
843         responseLinkResult.emplace_back(panRecognizer_);
844     }
845 }
846 
ScheduleDisappearDelayTask()847 void ScrollBar::ScheduleDisappearDelayTask()
848 {
849     if (displayMode_ == DisplayMode::AUTO && isScrollable_ && !isHover_) {
850         disappearDelayTask_.Cancel();
851         auto context = PipelineContext::GetCurrentContextSafelyWithCheck();
852         CHECK_NULL_VOID(context);
853         auto taskExecutor = context->GetTaskExecutor();
854         CHECK_NULL_VOID(taskExecutor);
855         disappearDelayTask_.Reset([weak = WeakClaim(this)] {
856             auto scrollBar = weak.Upgrade();
857             CHECK_NULL_VOID(scrollBar);
858             scrollBar->PlayScrollBarDisappearAnimation();
859         });
860         taskExecutor->PostDelayedTask(disappearDelayTask_, TaskExecutor::TaskType::UI, BAR_DISAPPRAE_DELAY_DURATION,
861             "ArkUIScrollBarInnerDisappearAnimation");
862     }
863 }
864 
AddScrollBarLayoutInfo()865 void ScrollBar::AddScrollBarLayoutInfo()
866 {
867     CHECK_NULL_VOID(needAddLayoutInfo);
868     if (innerScrollBarLayoutInfos_.size() >= SCROLL_BAR_LAYOUT_INFO_COUNT) {
869         innerScrollBarLayoutInfos_.pop_front();
870     }
871     innerScrollBarLayoutInfos_.push_back(InnerScrollBarLayoutInfo({
872         .layoutTime_ = GetSysTimestamp(),
873         .viewPortSize_ = viewPortSize_,
874         .lastOffset_ = lastOffset_,
875         .estimatedHeight_ = estimatedHeight_,
876         .outBoundary_ = outBoundary_,
877         .activeRect_ = activeRect_,
878     }));
879 }
880 
GetShapeModeDumpInfo()881 void ScrollBar::GetShapeModeDumpInfo()
882 {
883     switch (shapeMode_) {
884         case ShapeMode::RECT: {
885             DumpLog::GetInstance().AddDesc("shapeMode: RECT");
886             break;
887         }
888         case ShapeMode::ROUND: {
889             DumpLog::GetInstance().AddDesc("shapeMode: ROUND");
890             break;
891         }
892         case ShapeMode::DEFAULT: {
893             DumpLog::GetInstance().AddDesc("shapeMode: DEFAULT");
894             break;
895         }
896         default: {
897             break;
898         }
899     }
900 }
901 
GetPositionModeDumpInfo()902 void ScrollBar::GetPositionModeDumpInfo()
903 {
904     switch (positionMode_) {
905         case PositionMode::RIGHT: {
906             DumpLog::GetInstance().AddDesc("positionMode: RIGHT");
907             DumpLog::GetInstance().AddDesc(std::string("padding.right: ").append(padding_.Right().ToString()));
908             break;
909         }
910         case PositionMode::LEFT: {
911             DumpLog::GetInstance().AddDesc("positionMode: LEFT");
912             DumpLog::GetInstance().AddDesc(std::string("padding.left: ").append(padding_.Left().ToString()));
913             break;
914         }
915         case PositionMode::BOTTOM: {
916             DumpLog::GetInstance().AddDesc("positionMode: BOTTOM");
917             DumpLog::GetInstance().AddDesc(std::string("padding.bottom: ").append(padding_.Bottom().ToString()));
918             break;
919         }
920         default: {
921             break;
922         }
923     }
924 }
925 
GetAxisDumpInfo()926 void ScrollBar::GetAxisDumpInfo()
927 {
928     switch (axis_) {
929         case Axis::NONE: {
930             DumpLog::GetInstance().AddDesc("axis: NONE");
931             break;
932         }
933         case Axis::VERTICAL: {
934             DumpLog::GetInstance().AddDesc("axis: VERTICAL");
935             break;
936         }
937         case Axis::HORIZONTAL: {
938             DumpLog::GetInstance().AddDesc("axis: HORIZONTAL");
939             break;
940         }
941         case Axis::FREE: {
942             DumpLog::GetInstance().AddDesc("axis: FREE");
943             break;
944         }
945         default: {
946             break;
947         }
948     }
949 }
950 
GetPanDirectionDumpInfo()951 void ScrollBar::GetPanDirectionDumpInfo()
952 {
953     if (panRecognizer_) {
954         switch (panRecognizer_->GetAxisDirection()) {
955             case Axis::NONE: {
956                 DumpLog::GetInstance().AddDesc("panDirection: NONE");
957                 break;
958             }
959             case Axis::VERTICAL: {
960                 DumpLog::GetInstance().AddDesc("panDirection: VERTICAL");
961                 break;
962             }
963             case Axis::HORIZONTAL: {
964                 DumpLog::GetInstance().AddDesc("panDirection: HORIZONTAL");
965                 break;
966             }
967             case Axis::FREE: {
968                 DumpLog::GetInstance().AddDesc("panDirection: FREE");
969                 break;
970             }
971             default: {
972                 break;
973             }
974         }
975     } else {
976         DumpLog::GetInstance().AddDesc("panDirection is null");
977     }
978 }
979 
DumpAdvanceInfo()980 void ScrollBar::DumpAdvanceInfo()
981 {
982     DumpLog::GetInstance().AddDesc(std::string("activeRect: ").append(activeRect_.ToString()));
983     DumpLog::GetInstance().AddDesc(std::string("touchRegion: ").append(touchRegion_.ToString()));
984     DumpLog::GetInstance().AddDesc(std::string("hoverRegion: ").append(hoverRegion_.ToString()));
985     DumpLog::GetInstance().AddDesc(std::string("normalWidth: ").append(normalWidth_.ToString()));
986     DumpLog::GetInstance().AddDesc(std::string("activeWidth: ").append(activeWidth_.ToString()));
987     DumpLog::GetInstance().AddDesc(std::string("touchWidth: ").append(touchWidth_.ToString()));
988     DumpLog::GetInstance().AddDesc(std::string("hoverWidth: ").append(hoverWidth_.ToString()));
989     GetShapeModeDumpInfo();
990     GetPositionModeDumpInfo();
991     GetAxisDumpInfo();
992     GetPanDirectionDumpInfo();
993     DumpLog::GetInstance().AddDesc(std::string("hostBorderRadius: ").append(hostBorderRadius_.ToString()));
994     DumpLog::GetInstance().AddDesc(std::string("startReservedHeight: ").append(startReservedHeight_.ToString()));
995     DumpLog::GetInstance().AddDesc(std::string("endReservedHeight: ").append(endReservedHeight_.ToString()));
996     DumpLog::GetInstance().AddDesc(
997         std::string("scrollBarMargin").append(scrollBarMargin_.value_or(ScrollBarMargin()).ToString()));
998     DumpLog::GetInstance().AddDesc(std::string("isScrollable: ").append(std::to_string(isScrollable_)));
999     DumpLog::GetInstance().AddDesc(std::string("isReverse: ").append(std::to_string(isReverse_)));
1000     DumpLog::GetInstance().AddDesc("==========================innerScrollBarLayoutInfos==========================");
1001     for (const auto& info : innerScrollBarLayoutInfos_) {
1002         DumpLog::GetInstance().AddDesc(info.ToString());
1003     }
1004     DumpLog::GetInstance().AddDesc("==========================innerScrollBarLayoutInfos==========================");
1005 }
1006 
GetForegroundColor() const1007 Color ScrollBar::GetForegroundColor() const
1008 {
1009     if (IsPressed()) {
1010         return foregroundColor_.BlendColor(foregroundPressedBlendColor_);
1011     }
1012     if (IsHoverSlider()) {
1013         return foregroundColor_.BlendColor(foregroundHoverBlendColor_);
1014     }
1015     return foregroundColor_;
1016 }
1017 
SetHoverWidth(const RefPtr<ScrollBarTheme> & theme)1018 void ScrollBar::SetHoverWidth(const RefPtr<ScrollBarTheme>& theme)
1019 {
1020     hoverWidth_ = theme->GetActiveWidth() + theme->GetScrollBarMargin() * 2;
1021 }
1022 
SetNormalWidth(const Dimension & normalWidth,const RefPtr<PipelineContext> & context)1023 void ScrollBar::SetNormalWidth(const Dimension& normalWidth, const RefPtr<PipelineContext>& context)
1024 {
1025     if (normalWidth_ != normalWidth) {
1026         normalWidthUpdate_ = true;
1027         normalWidth_ = normalWidth;
1028         CalcReservedHeight(context);
1029         MarkNeedRender();
1030     }
1031 }
1032 
SetScrollable(bool isScrollable)1033 void ScrollBar::SetScrollable(bool isScrollable)
1034 {
1035     CHECK_NULL_VOID(isScrollable_ != isScrollable);
1036     isScrollable_ = isScrollable;
1037 }
1038 
SetPositionMode(PositionMode positionMode)1039 void ScrollBar::SetPositionMode(PositionMode positionMode)
1040 {
1041     if (positionMode_ != positionMode) {
1042         positionModeUpdate_ = true;
1043         positionMode_ = positionMode;
1044         if (panRecognizer_) {
1045             PanDirection panDirection;
1046             panDirection.type =
1047                 positionMode_ == PositionMode::BOTTOM ? PanDirection::HORIZONTAL : PanDirection::VERTICAL;
1048             panRecognizer_->SetDirection(panDirection);
1049         }
1050     }
1051 }
1052 
SetDisplayMode(DisplayMode displayMode)1053 void ScrollBar::SetDisplayMode(DisplayMode displayMode)
1054 {
1055     CHECK_NULL_VOID(displayMode_ != displayMode);
1056     displayMode_ = displayMode;
1057 }
1058 
PlayScrollBarDisappearAnimation()1059 void ScrollBar::PlayScrollBarDisappearAnimation()
1060 {
1061     if (displayMode_ == DisplayMode::AUTO && isScrollable_ && !isHover_ && !isPressed_) {
1062         opacityAnimationType_ = OpacityAnimationType::DISAPPEAR;
1063         MarkNeedRender();
1064     }
1065 }
1066 
PlayScrollBarAppearAnimation()1067 void ScrollBar::PlayScrollBarAppearAnimation()
1068 {
1069     if (displayMode_ == DisplayMode::AUTO && isScrollable_) {
1070         disappearDelayTask_.Cancel();
1071         opacityAnimationType_ = OpacityAnimationType::APPEAR;
1072         MarkNeedRender();
1073     }
1074 }
1075 
PlayScrollBarGrowAnimation()1076 void ScrollBar::PlayScrollBarGrowAnimation()
1077 {
1078 #ifdef ARKUI_WEARABLE
1079     VibratorUtils::StartVibraFeedback(SCROLL_BAR_VIBRATOR_WEAK);
1080 #endif
1081     PlayScrollBarAppearAnimation();
1082     normalWidth_ = activeWidth_;
1083     FlushBarWidth();
1084     hoverAnimationType_ = HoverAnimationType::GROW;
1085     MarkNeedRender();
1086 }
1087 
PlayScrollBarShrinkAnimation()1088 void ScrollBar::PlayScrollBarShrinkAnimation()
1089 {
1090 #ifdef ARKUI_WEARABLE
1091     VibratorUtils::StartVibraFeedback(SCROLL_BAR_VIBRATOR_WEAK);
1092 #endif
1093     normalWidth_ = inactiveWidth_;
1094     FlushBarWidth();
1095     hoverAnimationType_ = HoverAnimationType::SHRINK;
1096     MarkNeedRender();
1097 }
1098 
PlayScrollBarAdaptAnimation()1099 void ScrollBar::PlayScrollBarAdaptAnimation()
1100 {
1101     needAdaptAnimation_ = true;
1102     MarkNeedRender();
1103 }
1104 
MarkNeedRender()1105 void ScrollBar::MarkNeedRender()
1106 {
1107     if (markNeedRenderFunc_) {
1108         markNeedRenderFunc_();
1109     }
1110 }
1111 
GetMainOffset(const Offset & offset) const1112 float ScrollBar::GetMainOffset(const Offset& offset) const
1113 {
1114     return positionMode_ == PositionMode::BOTTOM ? offset.GetX() : offset.GetY();
1115 }
1116 
GetMainSize(const Size & size) const1117 float ScrollBar::GetMainSize(const Size& size) const
1118 {
1119     return positionMode_ == PositionMode::BOTTOM ? size.Width() : size.Height();
1120 }
1121 
SetReverse(bool reverse)1122 void ScrollBar::SetReverse(bool reverse)
1123 {
1124     if (isReverse_ != reverse) {
1125         isReverse_ = reverse;
1126         isReverseUpdate_ = true;
1127     }
1128 }
1129 
GetPanDirection() const1130 Axis ScrollBar::GetPanDirection() const
1131 {
1132     CHECK_NULL_RETURN(panRecognizer_, Axis::NONE);
1133     return panRecognizer_->GetAxisDirection();
1134 }
1135 
GetShapeModeDumpInfo(std::unique_ptr<JsonValue> & json)1136 void ScrollBar::GetShapeModeDumpInfo(std::unique_ptr<JsonValue>& json)
1137 {
1138     switch (shapeMode_) {
1139         case ShapeMode::RECT: {
1140             json->Put("shapeMode", "RECT");
1141             break;
1142         }
1143         case ShapeMode::ROUND: {
1144             json->Put("shapeMode", "ROUND");
1145             break;
1146         }
1147         case ShapeMode::DEFAULT: {
1148             json->Put("shapeMode", "DEFAULT");
1149             break;
1150         }
1151         default: {
1152             break;
1153         }
1154     }
1155 }
1156 
GetPositionModeDumpInfo(std::unique_ptr<JsonValue> & json)1157 void ScrollBar::GetPositionModeDumpInfo(std::unique_ptr<JsonValue>& json)
1158 {
1159     switch (positionMode_) {
1160         case PositionMode::RIGHT: {
1161             json->Put("padding.right", padding_.Right().ToString().c_str());
1162             break;
1163         }
1164         case PositionMode::LEFT: {
1165             json->Put("padding.left", padding_.Left().ToString().c_str());
1166             break;
1167         }
1168         case PositionMode::BOTTOM: {
1169             json->Put("padding.bottom", padding_.Bottom().ToString().c_str());
1170             break;
1171         }
1172         default: {
1173             break;
1174         }
1175     }
1176 }
1177 
GetAxisDumpInfo(std::unique_ptr<JsonValue> & json)1178 void ScrollBar::GetAxisDumpInfo(std::unique_ptr<JsonValue>& json)
1179 {
1180     switch (axis_) {
1181         case Axis::NONE: {
1182             json->Put("axis", "NONE");
1183             break;
1184         }
1185         case Axis::VERTICAL: {
1186             json->Put("axis", "VERTICAL");
1187             break;
1188         }
1189         case Axis::HORIZONTAL: {
1190             json->Put("axis", "HORIZONTAL");
1191             break;
1192         }
1193         case Axis::FREE: {
1194             json->Put("axis", "FREE");
1195             break;
1196         }
1197         default: {
1198             break;
1199         }
1200     }
1201 }
1202 
GetPanDirectionDumpInfo(std::unique_ptr<JsonValue> & json)1203 void ScrollBar::GetPanDirectionDumpInfo(std::unique_ptr<JsonValue>& json)
1204 {
1205     if (panRecognizer_) {
1206         switch (panRecognizer_->GetAxisDirection()) {
1207             case Axis::NONE: {
1208                 json->Put("panDirection", "NONE");
1209                 break;
1210             }
1211             case Axis::VERTICAL: {
1212                 json->Put("panDirection", "VERTICAL");
1213                 break;
1214             }
1215             case Axis::HORIZONTAL: {
1216                 json->Put("panDirection", "HORIZONTAL");
1217                 break;
1218             }
1219             case Axis::FREE: {
1220                 json->Put("panDirection", "FREE");
1221                 break;
1222             }
1223             default: {
1224                 break;
1225             }
1226         }
1227     }
1228 }
1229 
DumpAdvanceInfo(std::unique_ptr<JsonValue> & json)1230 void ScrollBar::DumpAdvanceInfo(std::unique_ptr<JsonValue>& json)
1231 {
1232     json->Put("activeRect", activeRect_.ToString().c_str());
1233     json->Put("touchRegion", touchRegion_.ToString().c_str());
1234     json->Put("hoverRegion", hoverRegion_.ToString().c_str());
1235     json->Put("normalWidth", normalWidth_.ToString().c_str());
1236     json->Put("activeWidth", activeWidth_.ToString().c_str());
1237     json->Put("touchWidth", touchWidth_.ToString().c_str());
1238     json->Put("hoverWidth", hoverWidth_.ToString().c_str());
1239     GetShapeModeDumpInfo(json);
1240     GetPositionModeDumpInfo(json);
1241     GetAxisDumpInfo(json);
1242     GetPanDirectionDumpInfo(json);
1243     json->Put("hostBorderRadius", hostBorderRadius_.ToString().c_str());
1244     json->Put("startReservedHeight", startReservedHeight_.ToString().c_str());
1245     json->Put("endReservedHeight", endReservedHeight_.ToString().c_str());
1246     json->Put("scrollBarMargin", scrollBarMargin_.value_or(ScrollBarMargin()).ToString().c_str());
1247     json->Put("isScrollable", std::to_string(isScrollable_).c_str());
1248     json->Put("isReverse", std::to_string(isReverse_).c_str());
1249 
1250     std::unique_ptr<JsonValue> children = JsonUtil::CreateArray(true);
1251     for (const auto& info : innerScrollBarLayoutInfos_) {
1252         std::unique_ptr<JsonValue> child = JsonUtil::Create(true);
1253         info.ToJson(child);
1254         children->Put(child);
1255     }
1256     json->Put("innerScrollBarLayoutInfos", children);
1257 }
1258 } // namespace OHOS::Ace::NG
1259