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