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