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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SCROLL_BAR_SCROLL_BAR_PATTERN_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SCROLL_BAR_SCROLL_BAR_PATTERN_H
18 
19 #include "base/geometry/axis.h"
20 #include "base/utils/utils.h"
21 #include "core/common/container.h"
22 #include "core/components/common/layout/constants.h"
23 #include "core/components_ng/pattern/pattern.h"
24 #include "core/components_ng/pattern/scroll/inner/scroll_bar.h"
25 #include "core/components_ng/pattern/scroll/scroll_event_hub.h"
26 #include "core/components_ng/pattern/scroll_bar/proxy/scroll_bar_proxy.h"
27 #include "core/components_ng/pattern/scroll_bar/scroll_bar_accessibility_property.h"
28 #include "core/components_ng/pattern/scroll_bar/scroll_bar_layout_algorithm.h"
29 #include "core/components_ng/pattern/scroll_bar/scroll_bar_layout_property.h"
30 #include "core/components_ng/pattern/scroll_bar/scroll_bar_paint_method.h"
31 #include "core/components_ng/pattern/scrollable/scrollable_pattern.h"
32 #include "core/components_ng/render/animation_utils.h"
33 
34 namespace OHOS::Ace::NG {
35 
36 class ScrollBarPattern : public Pattern {
37     DECLARE_ACE_TYPE(ScrollBarPattern, Pattern);
38 
39 public:
40     ScrollBarPattern() = default;
~ScrollBarPattern()41     ~ScrollBarPattern() override
42     {
43         if (scrollBarProxy_) {
44             scrollBarProxy_->UnRegisterScrollBar(AceType::WeakClaim(this));
45         }
46         scrollBarProxy_ = nullptr;
47         scrollableEvent_ = nullptr;
48         disappearAnimation_ = nullptr;
49     }
50 
IsAtomicNode()51     bool IsAtomicNode() const override
52     {
53         return false;
54     }
55 
CreateLayoutProperty()56     RefPtr<LayoutProperty> CreateLayoutProperty() override
57     {
58         return MakeRefPtr<ScrollBarLayoutProperty>();
59     }
60 
CreateAccessibilityProperty()61     RefPtr<AccessibilityProperty> CreateAccessibilityProperty() override
62     {
63         return MakeRefPtr<ScrollBarAccessibilityProperty>();
64     }
65 
CreateLayoutAlgorithm()66     RefPtr<LayoutAlgorithm> CreateLayoutAlgorithm() override
67     {
68         auto layoutAlgorithm = MakeRefPtr<ScrollBarLayoutAlgorithm>(currentOffset_);
69         return layoutAlgorithm;
70     }
71 
CreateEventHub()72     RefPtr<EventHub> CreateEventHub() override
73     {
74         return MakeRefPtr<ScrollEventHub>();
75     }
76 
GetCurrentPosition()77     float GetCurrentPosition() const
78     {
79         return currentOffset_;
80     }
81 
SetCurrentPosition(float currentOffset)82     void SetCurrentPosition(float currentOffset)
83     {
84         currentOffset_ = currentOffset;
85     }
86 
GetAxis()87     Axis GetAxis() const
88     {
89         return axis_;
90     }
91 
GetScrollableDistance()92     float GetScrollableDistance() const
93     {
94         return scrollableDistance_;
95     }
96 
SetScrollBarProxy(const RefPtr<ScrollBarProxy> & scrollBarProxy)97     void SetScrollBarProxy(const RefPtr<ScrollBarProxy>& scrollBarProxy)
98     {
99         scrollBarProxy_ = scrollBarProxy;
100     }
101 
GetDisplayMode()102     const DisplayMode& GetDisplayMode() const
103     {
104         return displayMode_;
105     }
106 
GetControlDistance()107     float GetControlDistance() const
108     {
109         return controlDistance_;
110     }
111 
SetControlDistance(float controlDistance)112     void SetControlDistance(float controlDistance)
113     {
114         if (Positive(controlDistance_) ? !Positive(controlDistance) : Positive(controlDistance)) {
115             controlDistanceChanged_ = true;
116         }
117         controlDistance_ = controlDistance;
118     }
119 
GetScrollableNodeOffset()120     float GetScrollableNodeOffset() const
121     {
122         return scrollableNodeOffset_;
123     }
124 
SetScrollableNodeOffset(float scrollableNodeOffset)125     void SetScrollableNodeOffset(float scrollableNodeOffset)
126     {
127         scrollableNodeOffset_ = scrollableNodeOffset;
128     }
129 
130     bool IsAtTop() const;
131     bool IsAtBottom() const;
132     bool UpdateCurrentOffset(float offset, int32_t source);
133 
134     /**
135      * @brief Stops the motion animator of the scroll bar.
136      */
StopMotion()137     inline void StopMotion()
138     {
139         if (frictionController_ && frictionController_->IsRunning()) {
140             frictionController_->Stop();
141         }
142     }
143     // disappear Animator
144     void StartDisappearAnimator();
145     void StopDisappearAnimator();
146     void SetOpacity(uint8_t value);
147     void SendAccessibilityEvent(AccessibilityEventType eventType);
148 
SetChildOffset(float childOffset)149     void SetChildOffset(float childOffset)
150     {
151         childOffset_ = childOffset;
152     };
153 
GetChildOffset()154     float GetChildOffset() const
155     {
156         return childOffset_;
157     };
158 
SetChildRect(const RectF & rect)159     void SetChildRect(const RectF& rect)
160     {
161         childRect_ = rect;
162     }
163 
SetDisappearAnimation(const std::shared_ptr<AnimationUtils::Animation> & disappearAnimation)164     void SetDisappearAnimation(const std::shared_ptr<AnimationUtils::Animation>& disappearAnimation)
165     {
166         disappearAnimation_ = disappearAnimation;
167     }
168 
169     void OnCollectTouchTarget(const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
170         TouchTestResult& result, const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
171         ResponseLinkResult& responseLinkResult);
172 
GetMainOffset(const Offset & offset)173     float GetMainOffset(const Offset& offset) const
174     {
175         return axis_ == Axis::HORIZONTAL ? offset.GetX() : offset.GetY();
176     }
177 
SetDragStartPosition(float position)178     void SetDragStartPosition(float position)
179     {
180         dragStartPosition_ = position;
181     }
182 
SetDragEndPosition(float position)183     void SetDragEndPosition(float position)
184     {
185         dragEndPosition_ = position;
186     }
187 
GetDragOffset()188     float GetDragOffset()
189     {
190         return dragEndPosition_ - dragStartPosition_;
191     }
192 
193     void SetScrollBar(DisplayMode displayMode);
194     void UpdateScrollBarOffset();
195     void HandleScrollBarOutBoundary(float scrollBarOutBoundaryExtent);
196     void UpdateScrollBarRegion(float offset, float estimatedHeight, Size viewPort, Offset viewOffset);
197     void RegisterScrollBarEventTask();
198     bool UpdateScrollBarDisplay();
199     bool IsReverse() const;
200     void SetReverse(bool reverse);
201 
GetGestureHub()202     RefPtr<GestureEventHub> GetGestureHub()
203     {
204         auto host = GetHost();
205         CHECK_NULL_RETURN(host, nullptr);
206         auto hub = host->GetEventHub<EventHub>();
207         CHECK_NULL_RETURN(hub, nullptr);
208         return hub->GetOrCreateGestureEventHub();
209     }
210 
GetInputHub()211     RefPtr<InputEventHub> GetInputHub()
212     {
213         auto host = GetHost();
214         CHECK_NULL_RETURN(host, nullptr);
215         auto hub = host->GetEventHub<EventHub>();
216         CHECK_NULL_RETURN(hub, nullptr);
217         return hub->GetOrCreateInputEventHub();
218     }
219 
CreateScrollBarOverlayModifier()220     void CreateScrollBarOverlayModifier()
221     {
222         CHECK_NULL_VOID(scrollBar_ && scrollBar_->NeedPaint());
223         CHECK_NULL_VOID(!scrollBarOverlayModifier_);
224         scrollBarOverlayModifier_ = AceType::MakeRefPtr<ScrollBarOverlayModifier>();
225         scrollBarOverlayModifier_->SetRect(scrollBar_->GetActiveRect());
226         scrollBarOverlayModifier_->SetPositionMode(scrollBar_->GetPositionMode());
227     }
228 
CreateNodePaintMethod()229     RefPtr<NodePaintMethod> CreateNodePaintMethod() override
230     {
231         if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
232             auto paint = MakeRefPtr<ScrollBarPaintMethod>(hasChild_);
233             paint->SetScrollBar(scrollBar_);
234             if (!HasChild()) {
235                 auto activeRect = scrollBar_->GetActiveRect();
236                 auto offset = activeRect.GetOffset();
237                 auto offsetF = OffsetF(offset.GetX(), offset.GetY());
238                 auto size = activeRect.GetSize();
239                 auto sizeF = SizeF(size.Width(), size.Height());
240                 childRect_ = RectF(offsetF, sizeF);
241             }
242             CreateScrollBarOverlayModifier();
243             paint->SetScrollBarOverlayModifier(scrollBarOverlayModifier_);
244             return paint;
245         } else {
246             return Pattern::CreateNodePaintMethod();
247         }
248     }
249 
SetChild(bool hasChild)250     void SetChild(bool hasChild)
251     {
252         hasChild_ = hasChild;
253     }
254 
SetPreFrameChildState(bool preFrameChildState)255     void SetPreFrameChildState(bool preFrameChildState)
256     {
257         preFrameChildState_ = preFrameChildState;
258     }
259 
GetPreFrameChildState()260     bool GetPreFrameChildState()
261     {
262         return preFrameChildState_;
263     }
264 
HasChild()265     bool HasChild()
266     {
267         return hasChild_;
268     }
269 
CheckChildState()270     bool CheckChildState()
271     {
272         auto currentChildState = HasChild();
273         auto preChildState = GetPreFrameChildState();
274         if (preChildState != currentChildState) {
275             SetPreFrameChildState(currentChildState);
276             return true;
277         }
278         return false;
279     }
280     void InitClickEvent();
281     void HandleClickEvent();
282     void InitLongPressEvent();
283     void HandleLongPress(bool smooth);
284     void InitMouseEvent();
285     bool IsInScrollBar();
286     void ScheduleCaretLongPress();
287     void StartLongPressEventTimer();
288     void OnCollectClickTarget(const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
289         TouchTestResult& result, const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
290         ResponseLinkResult& responseLinkResult);
291     void OnCollectLongPressTarget(const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
292         TouchTestResult& result, const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
293         ResponseLinkResult& responseLinkResult);
294     void AddScrollBarLayoutInfo();
295 
296     void GetAxisDumpInfo();
297 
298     void GetDisplayModeDumpInfo();
299 
300     void GetPanDirectionDumpInfo();
301 
302     void DumpAdvanceInfo() override;
303 
SetScrollEnabled(bool enabled)304     void SetScrollEnabled(bool enabled)
305     {
306         CHECK_NULL_VOID(scrollableEvent_);
307         scrollableEvent_->SetEnabled(enabled);
308         if (!enabled) {
309             scrollableEvent_->SetAxis(Axis::NONE);
310         } else {
311             scrollableEvent_->SetAxis(axis_);
312         }
313     }
314 
315     void OnColorConfigurationUpdate() override;
316 
GetScrollBarProxy()317     RefPtr<ScrollBarProxy> GetScrollBarProxy()
318     {
319         return scrollBarProxy_;
320     }
321 
SetEnableNestedSorll(bool enableNestedSorll)322     void SetEnableNestedSorll(bool enableNestedSorll)
323     {
324         enableNestedSorll_ = enableNestedSorll;
325     }
326 
GetEnableNestedSorll()327     bool GetEnableNestedSorll() const
328     {
329         return enableNestedSorll_;
330     }
331 
332     void ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const override;
333 private:
334     void OnModifyDone() override;
335     void SetBarCollectClickAndLongPressTargetCallback();
336     void SetInBarRectRegionCallback();
337     void OnAttachToFrameNode() override;
338     bool OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config) override;
339     void ValidateOffset();
340     void SetAccessibilityAction();
341     void InitPanRecognizer();
342     void HandleDragStart(const GestureEvent& info);
343     void HandleDragUpdate(const GestureEvent& info);
344     void HandleDragEnd(const GestureEvent& info);
345     void ProcessFrictionMotion(double value);
346     void ProcessFrictionMotionStop();
347 
348     RefPtr<ScrollBarProxy> scrollBarProxy_;
349     RefPtr<ScrollableEvent> scrollableEvent_;
350     Axis axis_ = Axis::VERTICAL;
351     DisplayMode displayMode_ { DisplayMode::AUTO };
352     float currentOffset_ = 0.0f;
353     float lastOffset_ = 0.0f;
354     float scrollableDistance_ = 0.0f;
355     float controlDistance_ = 0.0f;
356     bool  controlDistanceChanged_ = false;
357     float scrollableNodeOffset_ = 0.0f;
358     bool hasChild_ = false;
359     bool preFrameChildState_ = false;
360     float friction_ = BAR_FRICTION;
361     float frictionPosition_ = 0.0;
362     float dragStartPosition_ = 0.0f;
363     float dragEndPosition_ = 0.0f;
364 
365     float childOffset_ = 0.0f;  // main size of child
366     RefPtr<ScrollBarOverlayModifier> scrollBarOverlayModifier_;
367     RefPtr<ScrollBar> scrollBar_;
368     RefPtr<PanRecognizer> panRecognizer_;
369     RefPtr<FrictionMotion> frictionMotion_;
370     RefPtr<Animator> frictionController_;
371     ScrollPositionCallback scrollPositionCallback_;
372     ScrollEndCallback scrollEndCallback_;
373     RectF childRect_;
374     uint8_t opacity_ = UINT8_MAX;
375     CancelableCallback<void()> disapplearDelayTask_;
376     std::shared_ptr<AnimationUtils::Animation> disappearAnimation_;
377     bool isReverse_ = false;
378 
379     // dump info
380     std::list<OuterScrollBarLayoutInfo> outerScrollBarLayoutInfos_;
381     bool enableNestedSorll_ = false;
382     bool isMousePressed_ = false;
383     RefPtr<ClickEvent> clickListener_;
384     RefPtr<ClickRecognizer> clickRecognizer_;
385     RefPtr<LongPressRecognizer> longPressRecognizer_;
386     RefPtr<InputEvent> mouseEvent_;
387     Offset locationInfo_;
388     //Determine whether the current scroll direction is scrolling upwards or downwards
389     bool scrollingUp_ = false;
390     bool scrollingDown_ = false;
391 };
392 
393 } // namespace OHOS::Ace::NG
394 
395 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SCROLL_BAR_SCROLL_BAR_PATTERN_H
396