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