• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SCROLL_INNER_SCROLL_BAR_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SCROLL_INNER_SCROLL_BAR_H
18 
19 #include <cmath>
20 
21 #include "base/geometry/dimension.h"
22 #include "base/geometry/offset.h"
23 #include "base/geometry/rect.h"
24 #include "base/utils/utils.h"
25 #include "core/animation/friction_motion.h"
26 #include "core/components/common/properties/color.h"
27 #include "core/components/common/properties/edge.h"
28 #include "core/components/scroll/scroll_bar_theme.h"
29 #include "core/components_ng/event/input_event.h"
30 #include "core/components_ng/event/touch_event.h"
31 #include "core/components_ng/property/border_property.h"
32 #include "core/components_ng/gestures/recognizers/pan_recognizer.h"
33 #include "core/components_ng/pattern/scrollable/scrollable_properties.h"
34 #include "core/components_ng/pattern/scroll/inner/scroll_bar_overlay_modifier.h"
35 
36 namespace OHOS::Ace::NG {
37 
38 constexpr double FACTOR_HALF = 0.5;
39 constexpr double DEFAULT_TOPANGLE = 60.0;
40 constexpr double DEFAULT_BOTTOMANGLE = 120.0;
41 constexpr double DEFAULT_MINANGLE = 10.0;
42 constexpr double STRAIGHT_ANGLE = 180.0;
43 constexpr double BAR_FRICTION = 0.9;
44 constexpr Color PRESSED_BLEND_COLOR = Color(0x19000000);
45 
46 enum class ShapeMode {
47     /*
48      * unspecified, follow theme.
49      */
50     DEFAULT = 0,
51     /*
52      * rect scrollbar.
53      */
54     RECT,
55     /*
56      * round scrollbar.
57      */
58     ROUND,
59 };
60 
61 enum class DisplayMode {
62     /*
63      * do not display scrollbar.
64      */
65     OFF = 0,
66     /*
67      * display scrollbar on demand.
68      */
69     AUTO,
70     /*
71      * always display scrollbar.
72      */
73     ON,
74 };
75 
76 enum class PositionMode {
77     /*
78      * display scrollbar on right.
79      */
80     RIGHT = 0,
81     /*
82      * display scrollbar on left.
83      */
84     LEFT,
85     /*
86      * display scrollbar on bottom.
87      */
88     BOTTOM,
89 };
90 
91 class ScrollBar final : public AceType {
92     DECLARE_ACE_TYPE(ScrollBar, AceType);
93 
94 public:
95     ScrollBar();
96     ScrollBar(DisplayMode displayMode, ShapeMode shapeMode = ShapeMode::RECT,
97         PositionMode positionMode = PositionMode::RIGHT);
98     ~ScrollBar() override = default;
99 
100     bool InBarTouchRegion(const Point& point) const;
101     bool InBarHoverRegion(const Point& point) const;
102     bool NeedScrollBar() const;
103     bool NeedPaint() const;
104     void UpdateScrollBarRegion(
105         const Offset& offset, const Size& size, const Offset& lastOffset, double estimatedHeight);
106     double GetNormalWidthToPx() const;
107     float CalcPatternOffset(float scrollBarOffset) const;
108 
GetShapeMode()109     ShapeMode GetShapeMode() const
110     {
111         return shapeMode_;
112     }
113 
GetDisplayMode()114     DisplayMode GetDisplayMode() const
115     {
116         return displayMode_;
117     }
118 
GetPositionMode()119     PositionMode GetPositionMode() const
120     {
121         return positionMode_;
122     }
123 
SetPadding(const Edge & padding)124     void SetPadding(const Edge& padding)
125     {
126         padding_ = padding;
127     }
128 
GetPadding()129     const Edge& GetPadding() const
130     {
131         return padding_;
132     }
133 
SetBackgroundColor(const Color & backgroundColor)134     void SetBackgroundColor(const Color& backgroundColor)
135     {
136         backgroundColor_ = backgroundColor;
137     }
138 
GetBackgroundColor()139     const Color& GetBackgroundColor() const
140     {
141         return backgroundColor_;
142     }
143 
SetForegroundColor(const Color & foregroundColor)144     void SetForegroundColor(const Color& foregroundColor)
145     {
146         foregroundColor_ = foregroundColor;
147     }
148 
GetForegroundColor()149     Color GetForegroundColor() const
150     {
151         return IsPressed() ? foregroundColor_.BlendColor(PRESSED_BLEND_COLOR) : foregroundColor_;
152     }
153 
GetTopAngle()154     double GetTopAngle() const
155     {
156         return topAngle_;
157     }
158 
GetBottomAngle()159     double GetBottomAngle() const
160     {
161         return bottomAngle_;
162     }
163 
GetTrickStartAngle()164     double GetTrickStartAngle() const
165     {
166         return trickStartAngle_;
167     }
168 
GetTrickSweepAngle()169     double GetTrickSweepAngle() const
170     {
171         return trickSweepAngle_;
172     }
173 
SetMinHeight(const Dimension & minHeight)174     void SetMinHeight(const Dimension& minHeight)
175     {
176         minHeight_ = minHeight;
177     }
178 
GetMinHeight()179     const Dimension& GetMinHeight() const
180     {
181         return minHeight_;
182     }
183 
SetMinDynamicHeight(const Dimension & minDynamicHeight)184     void SetMinDynamicHeight(const Dimension& minDynamicHeight)
185     {
186         minDynamicHeight_ = minDynamicHeight;
187     }
188 
GetMinDynamicHeight()189     const Dimension& GetMinDynamicHeight() const
190     {
191         return minDynamicHeight_;
192     }
193 
SetInactiveWidth(const Dimension & inactiveWidth)194     void SetInactiveWidth(const Dimension& inactiveWidth)
195     {
196         inactiveWidth_ = inactiveWidth;
197     }
198 
SetActiveWidth(const Dimension & activeWidth)199     void SetActiveWidth(const Dimension& activeWidth)
200     {
201         activeWidth_ = activeWidth;
202     }
203 
SetHoverWidth(const RefPtr<ScrollBarTheme> & theme)204     void SetHoverWidth(const RefPtr<ScrollBarTheme>& theme)
205     {
206         hoverWidth_ = theme->GetActiveWidth() + theme->GetScrollBarMargin() * 2;
207     }
208 
GetActiveWidth()209     const Dimension& GetActiveWidth() const
210     {
211         return activeWidth_;
212     }
213 
SetNormalWidth(const Dimension & normalWidth)214     void SetNormalWidth(const Dimension& normalWidth)
215     {
216         if (normalWidth_ != normalWidth) {
217             normalWidthUpdate_ = true;
218             normalWidth_ = normalWidth;
219             CalcReservedHeight();
220             MarkNeedRender();
221         }
222     }
223 
GetActiveRect()224     const Rect& GetActiveRect() const
225     {
226         return activeRect_;
227     }
228 
SetTouchWidth(const Dimension & touchWidth)229     void SetTouchWidth(const Dimension& touchWidth)
230     {
231         touchWidth_ = touchWidth;
232     }
233 
GetTouchWidth()234     const Dimension& GetTouchWidth() const
235     {
236         return touchWidth_;
237     }
238 
GetBarRect()239     const Rect& GetBarRect() const
240     {
241         return barRect_;
242     }
243 
SetScrollable(bool isScrollable)244     void SetScrollable(bool isScrollable)
245     {
246         CHECK_NULL_VOID_NOLOG(isScrollable_ != isScrollable);
247         isScrollable_ = isScrollable;
248     }
249 
IsScrollable()250     bool IsScrollable() const
251     {
252         return isScrollable_;
253     }
254 
SetPositionMode(PositionMode positionMode)255     void SetPositionMode(PositionMode positionMode)
256     {
257         if (positionMode_ != positionMode) {
258             positionModeUpdate_ = true;
259             positionMode_ = positionMode;
260             if (panRecognizer_) {
261                 PanDirection panDirection;
262                 panDirection.type =
263                     positionMode_ == PositionMode::BOTTOM ? PanDirection::HORIZONTAL : PanDirection::VERTICAL;
264                 panRecognizer_->SetDirection(panDirection);
265             }
266         }
267     }
268 
SetShapeMode(ShapeMode shapeMode)269     void SetShapeMode(ShapeMode shapeMode)
270     {
271         shapeMode_ = shapeMode;
272     }
273 
SetDisplayMode(DisplayMode displayMode)274     void SetDisplayMode(DisplayMode displayMode)
275     {
276         CHECK_NULL_VOID_NOLOG(displayMode_ != displayMode);
277         displayMode_ = displayMode;
278     }
279 
SetOutBoundary(double outBoundary)280     void SetOutBoundary(double outBoundary)
281     {
282         inSpring_ = !NearEqual(outBoundary_, outBoundary, 0.000001f);
283         if (inSpring_ && adaptAnimator_ && adaptAnimator_->IsRunning()) {
284             adaptAnimator_->Stop();
285         }
286         outBoundary_ = outBoundary;
287     }
288 
SetPosition(const Dimension & position)289     void SetPosition(const Dimension& position)
290     {
291         position_ = position;
292     }
293 
GetPosition()294     const Dimension& GetPosition() const
295     {
296         return position_;
297     }
298 
SetPressed(bool press)299     void SetPressed(bool press)
300     {
301         isPressed_ = press;
302     }
303 
IsPressed()304     bool IsPressed() const
305     {
306         return isPressed_;
307     }
308 
SetHover(bool hover)309     void SetHover(bool hover)
310     {
311         isHover_ = hover;
312     }
313 
IsHover()314     bool IsHover() const
315     {
316         return isHover_;
317     }
318 
GetOpacity()319     uint8_t GetOpacity() const
320     {
321         return opacity_;
322     }
323 
PlayScrollBarEndAnimation()324     void PlayScrollBarEndAnimation()
325     {
326         if (displayMode_ == DisplayMode::AUTO && isScrollable_ && !isHover_ && !isPressed_) {
327             opacityAnimationType_ = OpacityAnimationType::DISAPPEAR;
328             MarkNeedRender();
329         }
330     }
331 
PlayScrollBarStartAnimation()332     void PlayScrollBarStartAnimation()
333     {
334         if (displayMode_ == DisplayMode::AUTO && isScrollable_) {
335             disapplearDelayTask_.Cancel();
336             opacityAnimationType_ = OpacityAnimationType::APPEAR;
337             MarkNeedRender();
338         }
339     }
340 
GetOpacityAnimationType()341     OpacityAnimationType GetOpacityAnimationType() const
342     {
343         return opacityAnimationType_;
344     }
345 
SetOpacityAnimationType(OpacityAnimationType opacityAnimationType)346     void SetOpacityAnimationType(OpacityAnimationType opacityAnimationType)
347     {
348         opacityAnimationType_ = opacityAnimationType;
349     }
350 
GetHoverAnimationType()351     HoverAnimationType GetHoverAnimationType() const
352     {
353         return hoverAnimationType_;
354     }
355 
SetHoverAnimationType(HoverAnimationType hoverAnimationType)356     void SetHoverAnimationType(HoverAnimationType hoverAnimationType)
357     {
358         hoverAnimationType_ = hoverAnimationType;
359     }
360 
361 
PlayScrollBarGrowAnimation()362     void PlayScrollBarGrowAnimation()
363     {
364         PlayScrollBarStartAnimation();
365         normalWidth_ = activeWidth_;
366         FlushBarWidth();
367         hoverAnimationType_ = HoverAnimationType::GROW;
368         MarkNeedRender();
369     }
370 
PlayScrollBarShrinkAnimation()371     void PlayScrollBarShrinkAnimation()
372     {
373         normalWidth_ = inactiveWidth_;
374         FlushBarWidth();
375         hoverAnimationType_ = HoverAnimationType::SHRINK;
376         MarkNeedRender();
377     }
378 
MarkNeedRender()379     void MarkNeedRender()
380     {
381         if (markNeedRenderFunc_) {
382             markNeedRenderFunc_();
383         }
384     }
385 
SetMarkNeedRenderFunc(std::function<void ()> && func)386     void SetMarkNeedRenderFunc(std::function<void()>&& func)
387     {
388         markNeedRenderFunc_ = func;
389     }
390 
GetTouchEvent()391     RefPtr<TouchEventImpl> GetTouchEvent()
392     {
393         return touchEvent_;
394     }
395 
GetMouseEvent()396     RefPtr<InputEvent> GetMouseEvent()
397     {
398         return mouseEvent_;
399     }
400 
GetHoverEvent()401     RefPtr<InputEvent> GetHoverEvent() const
402     {
403         return hoverEvent_;
404     }
405 
SetIsUserNormalWidth(bool isUserNormalWidth)406     void SetIsUserNormalWidth(bool isUserNormalWidth)
407     {
408         isUserNormalWidth_ = isUserNormalWidth;
409     }
410 
GetIsUserNormalWidth()411     bool GetIsUserNormalWidth() const
412     {
413         return isUserNormalWidth_;
414     }
415 
SetStartReservedHeight(const Dimension & startReservedHeight)416     void SetStartReservedHeight(const Dimension& startReservedHeight)
417     {
418         startReservedHeight_ = startReservedHeight;
419     }
420 
GetStartReservedHeight()421     const Dimension& GetStartReservedHeight() const
422     {
423         return startReservedHeight_;
424     }
425 
SetEndReservedHeight(const Dimension & endReservedHeight)426     void SetEndReservedHeight(const Dimension& endReservedHeight)
427     {
428         endReservedHeight_ = endReservedHeight;
429     }
430 
GetEndReservedHeight()431     const Dimension& GetEndReservedHeight() const
432     {
433         return endReservedHeight_;
434     }
435 
SetHostBorderRadius(const BorderRadiusProperty & hostBorderRadius)436     void SetHostBorderRadius(const BorderRadiusProperty& hostBorderRadius)
437     {
438         hostBorderRadius_ = hostBorderRadius;
439     }
440 
GetHostBorderRadius()441     const BorderRadiusProperty& GetHostBorderRadius() const
442     {
443         return hostBorderRadius_;
444     }
445 
SetScrollPositionCallback(ScrollPositionCallback && callback)446     void SetScrollPositionCallback(ScrollPositionCallback&& callback)
447     {
448         scrollPositionCallback_ = std::move(callback);
449     }
450 
GetScrollPositionCallback()451     const ScrollPositionCallback& GetScrollPositionCallback() const
452     {
453         return scrollPositionCallback_;
454     }
455 
SetScrollEndCallback(ScrollEndCallback && scrollEndCallback)456     void SetScrollEndCallback(ScrollEndCallback&& scrollEndCallback)
457     {
458         scrollEndCallback_ = std::move(scrollEndCallback);
459     }
460 
GetScrollEndCallback()461     const ScrollEndCallback& GetScrollEndCallback() const
462     {
463         return scrollEndCallback_;
464     }
465 
SetCalePredictSnapOffsetCallback(CalePredictSnapOffsetCallback && calePredictSnapOffsetCallback)466     void SetCalePredictSnapOffsetCallback(CalePredictSnapOffsetCallback&& calePredictSnapOffsetCallback)
467     {
468         calePredictSnapOffsetCallback_ = std::move(calePredictSnapOffsetCallback);
469     }
470 
GetCalePredictSnapOffsetCallback()471     const CalePredictSnapOffsetCallback& GetCalePredictSnapOffsetCallback() const
472     {
473         return calePredictSnapOffsetCallback_;
474     }
475 
SetStartScrollSnapMotionCallback(StartScrollSnapMotionCallback && startScrollSnapMotionCallback)476     void SetStartScrollSnapMotionCallback(StartScrollSnapMotionCallback&& startScrollSnapMotionCallback)
477     {
478         startScrollSnapMotionCallback_ = std::move(startScrollSnapMotionCallback);
479     }
480 
GetStartScrollSnapMotionCallback()481     const StartScrollSnapMotionCallback& GetStartScrollSnapMotionCallback() const
482     {
483         return startScrollSnapMotionCallback_;
484     }
485 
486     void SetGestureEvent();
487     void SetMouseEvent();
488     void SetHoverEvent();
489     void FlushBarWidth();
490     void PlayAdaptAnimation(double activeSize, double activeMainOffset, double inactiveSize, double inactiveMainOffset);
491     void CalcReservedHeight();
492     void OnCollectTouchTarget(const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
493         TouchTestResult& result);
494     void ScheduleDisapplearDelayTask();
495 
496 protected:
497     void InitTheme();
498 
499 private:
500     void SetBarRegion(const Offset& offset, const Size& size);
501     void SetRectTrickRegion(const Offset& offset, const Size& size, const Offset& lastOffset, double mainScrollExtent);
502     void SetRoundTrickRegion(const Offset& offset, const Size& size, const Offset& lastOffset, double mainScrollExtent);
503     void UpdateActiveRectSize(double activeSize);
504     void UpdateActiveRectOffset(double activeMainOffset);
505     double NormalizeToPx(const Dimension& dimension) const;
506     void InitPanRecognizer();
507     void HandleDragStart(const GestureEvent& info);
508     void HandleDragUpdate(const GestureEvent& info);
509     void HandleDragEnd(const GestureEvent& info);
510     void ProcessFrictionMotion(double value);
511     void ProcessFrictionMotionStop();
512 
513     DisplayMode displayMode_ = DisplayMode::AUTO;
514     ShapeMode shapeMode_ = ShapeMode::RECT;
515     PositionMode positionMode_ = PositionMode::RIGHT;
516     BorderRadiusProperty hostBorderRadius_;
517     Edge padding_;
518     Color backgroundColor_;
519     Color foregroundColor_;
520     Rect touchRegion_;
521     Rect hoverRegion_;
522     Rect barRect_;
523     Rect activeRect_;
524     Dimension minHeight_;           // this is min static height
525     Dimension minDynamicHeight_;    // this is min dynamic height when on the top or bottom
526     Dimension startReservedHeight_; // this is reservedHeight on the start
527     Dimension endReservedHeight_;   // this is reservedHeight on the end
528     Dimension inactiveWidth_;
529     Dimension activeWidth_;
530     Dimension normalWidth_;
531     Dimension touchWidth_;
532     Dimension hoverWidth_;
533 
534     Dimension position_;
535 
536     double trickStartAngle_ = 0.0;
537     double trickSweepAngle_ = 0.0;
538     double topAngle_ = DEFAULT_TOPANGLE;
539     double bottomAngle_ = DEFAULT_BOTTOMANGLE;
540     double minAngle_ = DEFAULT_MINANGLE;
541     double outBoundary_ = 0.0;
542     double offsetScale_ = 1.0f;
543     double scrollableOffset_ = 0.0;
544     double barRegionSize_ = 0.0;
545     double friction_ = BAR_FRICTION;
546     double frictionPosition_ = 0.0;
547 
548     bool isScrollable_ = false;
549 
550     bool isPressed_ = false;
551     bool isDriving_ = false; // false: scroll driving; true: bar driving
552     bool isHover_ = false;
553     bool inSpring_ = false; // whether bar in the spring state
554     bool positionModeUpdate_ = false;
555     bool normalWidthUpdate_ = false;
556     bool isUserNormalWidth_ = false;
557 
558     Offset paintOffset_;
559     Size viewPortSize_;
560     Offset lastOffset_;
561     double estimatedHeight_ = 0.0;
562     uint8_t opacity_ = UINT8_MAX;
563     RefPtr<TouchEventImpl> touchEvent_;
564     RefPtr<InputEvent> mouseEvent_;
565     RefPtr<InputEvent> hoverEvent_;
566     RefPtr<PanRecognizer> panRecognizer_;
567     RefPtr<Animator> adaptAnimator_;
568     RefPtr<Animator> frictionController_;
569     RefPtr<FrictionMotion> frictionMotion_;
570     std::function<void()> markNeedRenderFunc_;
571     ScrollPositionCallback scrollPositionCallback_;
572     ScrollEndCallback scrollEndCallback_;
573     CalePredictSnapOffsetCallback calePredictSnapOffsetCallback_;
574     StartScrollSnapMotionCallback startScrollSnapMotionCallback_;
575     OpacityAnimationType opacityAnimationType_ = OpacityAnimationType::NONE;
576     HoverAnimationType hoverAnimationType_ = HoverAnimationType::NONE;
577     CancelableCallback<void()> disapplearDelayTask_;
578 };
579 
580 } // namespace OHOS::Ace::NG
581 
582 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SCROLL_INNER_SCROLL_BAR_H
583