1 /*
2  * Copyright (c) 2021-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_SCROLL_SCROLLABLE_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_SCROLL_SCROLLABLE_H
18 
19 #include <functional>
20 
21 #include "base/geometry/dimension.h"
22 #include "core/animation/animator.h"
23 #include "core/animation/friction_motion.h"
24 #include "core/animation/scroll_motion.h"
25 #include "core/components_ng/base/frame_scene_status.h"
26 #include "core/components_ng/gestures/recognizers/pan_recognizer.h"
27 #include "core/components_ng/pattern/scrollable/scrollable_properties.h"
28 #include "core/event/axis_event.h"
29 #include "core/event/touch_event.h"
30 #include "core/gestures/pan_recognizer.h"
31 #include "core/gestures/raw_recognizer.h"
32 #include "core/gestures/timeout_recognizer.h"
33 #include "core/pipeline/base/related_node.h"
34 #include "core/pipeline/base/render_node.h"
35 
36 namespace OHOS::Ace {
37 enum class NestedState {
38     GESTURE = 0,
39     CHILD_SCROLL,
40     CHILD_OVER_SCROLL,
41 };
42 
43 struct OverScrollOffset {
44     double start;
45     double end;
46 };
47 
48 struct ScrollResult {
49     double remain;
50     bool reachEdge;
51 };
52 
53 using ScrollEventCallback = std::function<void()>;
54 using OutBoundaryCallback = std::function<bool()>;
55 using ScrollOverCallback = std::function<void(double velocity)>;
56 using WatchFixCallback = std::function<double(double final, double current)>;
57 using ScrollBeginCallback = std::function<ScrollInfo(Dimension, Dimension)>;
58 using ScrollFrameBeginCallback = std::function<ScrollFrameResult(Dimension, ScrollState)>;
59 using DragEndForRefreshCallback = std::function<void()>;
60 using DragCancelRefreshCallback = std::function<void()>;
61 using MouseLeftButtonScroll = std::function<bool()>;
62 using ScrollSnapCallback = std::function<bool(double targetOffset, double velocity)>;
63 using ContinuousSlidingCallback = std::function<double()>;
64 using CalePredictSnapOffsetCallback =
65                 std::function<std::optional<float>(float delta, float dragDistance, float velocity)>;
66 using NeedScrollSnapToSideCallback = std::function<bool(float delta)>;
67 using NestableScrollCallback = std::function<ScrollResult(float, int32_t, NestedState)>;
68 using DragFRCSceneCallback = std::function<void(double velocity, NG::SceneStatus sceneStatus)>;
69 using ScrollMotionFRCSceneCallback = std::function<void(double velocity, NG::SceneStatus sceneStatus)>;
70 
71 class Scrollable : public TouchEventTarget, public RelatedChild {
72     DECLARE_ACE_TYPE(Scrollable, TouchEventTarget);
73 
74 public:
75     Scrollable() = default;
Scrollable(ScrollPositionCallback && callback,Axis axis)76     Scrollable(ScrollPositionCallback&& callback, Axis axis) : callback_(std::move(callback)), axis_(axis) {}
Scrollable(const ScrollPositionCallback & callback,Axis axis)77     Scrollable(const ScrollPositionCallback& callback, Axis axis) : callback_(callback), axis_(axis) {}
78     ~Scrollable() override;
79 
80     static void SetVelocityScale(double sVelocityScale);
81     static void SetFriction(double sFriction);
82 
83     void Initialize(const WeakPtr<PipelineBase>& context);
84 
IsMotionStop()85     bool IsMotionStop() const
86     {
87         return (springController_ ? (!springController_->IsRunning()) : true) &&
88                (controller_ ? (!controller_->IsRunning()) : true) && !moved_;
89     }
90 
IsSpringMotionRunning()91     bool IsSpringMotionRunning() const
92     {
93         return springController_ ? springController_->IsRunning() : false;
94     }
95 
IsDragging()96     bool IsDragging() const
97     {
98         return isTouching_ && controller_->IsRunning();
99     }
100 
101     void SetAxis(Axis axis);
102 
SetScrollableNode(const WeakPtr<RenderNode> & node)103     void SetScrollableNode(const WeakPtr<RenderNode>& node)
104     {
105         scrollableNode_ = node;
106     }
107 
GetMainOffset(const Offset & offset)108     double GetMainOffset(const Offset& offset) const
109     {
110         return axis_ == Axis::HORIZONTAL ? offset.GetX() : offset.GetY();
111     }
112 
GetMainSize(const Size & size)113     double GetMainSize(const Size& size) const
114     {
115         return axis_ == Axis::HORIZONTAL ? size.Width() : size.Height();
116     }
117 
SetCallback(const ScrollPositionCallback & callback)118     void SetCallback(const ScrollPositionCallback& callback)
119     {
120         callback_ = callback;
121     }
122 
SetCoordinateOffset(const Offset & offset)123     void SetCoordinateOffset(const Offset& offset) const
124     {
125         if (panRecognizer_) {
126             panRecognizer_->SetCoordinateOffset(offset);
127         }
128 
129         if (panRecognizerNG_) {
130             panRecognizerNG_->SetCoordinateOffset(offset);
131         }
132 
133         if (rawRecognizer_) {
134             rawRecognizer_->SetCoordinateOffset(offset);
135         }
136     }
137 
OnCollectTouchTarget(TouchTestResult & result)138     void OnCollectTouchTarget(TouchTestResult& result)
139     {
140         if (panRecognizerNG_) {
141             result.emplace_back(panRecognizerNG_);
142         }
143 
144         if (rawRecognizer_) {
145             result.emplace_back(rawRecognizer_);
146         }
147     }
148 
SetDragTouchRestrict(const TouchRestrict & touchRestrict)149     void SetDragTouchRestrict(const TouchRestrict& touchRestrict)
150     {
151         if (panRecognizer_) {
152             panRecognizer_->SetTouchRestrict(touchRestrict);
153         }
154         if (panRecognizerNG_) {
155             panRecognizerNG_->SetTouchRestrict(touchRestrict);
156         }
157     }
158 
SetScrollEndCallback(const ScrollEventCallback & scrollEndCallback)159     void SetScrollEndCallback(const ScrollEventCallback& scrollEndCallback)
160     {
161         scrollEndCallback_ = scrollEndCallback;
162     }
163 
SetScrollTouchUpCallback(const ScrollEventCallback & scrollTouchUpCallback)164     void SetScrollTouchUpCallback(const ScrollEventCallback& scrollTouchUpCallback)
165     {
166         scrollTouchUpCallback_ = scrollTouchUpCallback;
167     }
168 
SetUnstaticFriction(double friction)169     void SetUnstaticFriction(double friction)
170     {
171         friction_ = friction;
172     }
173 
174     void HandleTouchDown();
175     void HandleTouchUp();
176     void HandleTouchCancel();
177     void HandleDragStart(const GestureEvent& info);
178     void HandleDragUpdate(const GestureEvent& info);
179     void HandleDragEnd(const GestureEvent& info);
180     void HandleScrollEnd();
181     bool HandleOverScroll(double velocity);
182     ScrollResult HandleScroll(double offset, int32_t source, NestedState state);
183     [[deprecated]] ScrollResult HandleScrollParentFirst(double& offset, int32_t source, NestedState state);
184     [[deprecated]] ScrollResult HandleScrollSelfFirst(double& offset, int32_t source, NestedState state);
185     [[deprecated]] ScrollResult HandleScrollSelfOnly(double& offset, int32_t source, NestedState state);
186     [[deprecated]] ScrollResult HandleScrollParallel(double& offset, int32_t source, NestedState state);
187 
SetMoved(bool value)188     void SetMoved(bool value)
189     {
190         moved_ = value;
191     }
SetCanOverScroll(bool value)192     void SetCanOverScroll(bool value)
193     {
194         canOverScroll_ = value;
195     }
CanOverScroll()196     bool CanOverScroll() const
197     {
198         return canOverScroll_;
199     }
200 
201     void ProcessScrollMotionStop();
202 
DispatchEvent(const TouchEvent & point)203     bool DispatchEvent(const TouchEvent& point) override
204     {
205         return true;
206     }
HandleEvent(const TouchEvent & event)207     bool HandleEvent(const TouchEvent& event) override
208     {
209         if (!available_) {
210             return true;
211         }
212         if (panRecognizer_) {
213             panRecognizer_->HandleEvent(event);
214         }
215         if (rawRecognizer_) {
216             return rawRecognizer_->HandleEvent(event);
217         }
218         return true;
219     }
HandleEvent(const AxisEvent & event)220     bool HandleEvent(const AxisEvent& event) override
221     {
222         if (panRecognizer_) {
223             return panRecognizer_->HandleEvent(event);
224         }
225         return false;
226     }
227 
SetScrollEnd(const ScrollEventCallback & scrollEnd)228     void SetScrollEnd(const ScrollEventCallback& scrollEnd)
229     {
230         scrollEnd_ = scrollEnd;
231     }
232 
SetScrollOverCallBack(const ScrollOverCallback & scrollOverCallback)233     void SetScrollOverCallBack(const ScrollOverCallback& scrollOverCallback)
234     {
235         scrollOverCallback_ = scrollOverCallback;
236     }
237 
SetNotifyScrollOverCallBack(const ScrollOverCallback & scrollOverCallback)238     void SetNotifyScrollOverCallBack(const ScrollOverCallback& scrollOverCallback)
239     {
240         notifyScrollOverCallback_ = scrollOverCallback;
241     }
242 
SetOutBoundaryCallback(const OutBoundaryCallback & outBoundaryCallback)243     void SetOutBoundaryCallback(const OutBoundaryCallback& outBoundaryCallback)
244     {
245         outBoundaryCallback_ = outBoundaryCallback;
246     }
247 
SetDragEndCallback(const DragEndForRefreshCallback & dragEndCallback)248     void SetDragEndCallback(const DragEndForRefreshCallback& dragEndCallback)
249     {
250         dragEndCallback_ = dragEndCallback;
251     }
252 
SetDragCancelCallback(const DragCancelRefreshCallback & dragCancelCallback)253     void SetDragCancelCallback(const DragCancelRefreshCallback& dragCancelCallback)
254     {
255         dragCancelCallback_ = dragCancelCallback;
256     }
257 
GetDragEndCallback()258     const DragEndForRefreshCallback& GetDragEndCallback() const
259     {
260         return dragEndCallback_;
261     }
262 
GetDragCancelCallback()263     const DragCancelRefreshCallback& GetDragCancelCallback() const
264     {
265         return dragCancelCallback_;
266     }
267 
SetWatchFixCallback(const WatchFixCallback & watchFixCallback)268     void SetWatchFixCallback(const WatchFixCallback& watchFixCallback)
269     {
270         watchFixCallback_ = watchFixCallback;
271     }
272 
MarkNeedCenterFix(bool needFix)273     void MarkNeedCenterFix(bool needFix)
274     {
275         needCenterFix_ = needFix;
276     }
277 
GetCurrentVelocity()278     double GetCurrentVelocity() const
279     {
280         return currentVelocity_;
281     };
282 
283     void OnAnimateStop();
284     void ProcessScrollSnapStop();
285     void StartSpringMotion(
286         double mainPosition, double mainVelocity, const ExtentPair& extent, const ExtentPair& initExtent);
287 
288     void UpdateScrollSnapStartOffset(double offset);
289     void StartScrollSnapMotion(float predictSnapOffset, float scrollSnapVelocity);
290     void UpdateScrollSnapEndWithOffset(double offset);
291 
292     bool IsAnimationNotRunning() const;
293 
294     bool Idle() const;
295 
296     bool IsStopped() const;
297 
298     bool IsSpringStopped() const;
299 
300     bool IsSnapStopped() const;
301 
302     void StopScrollable();
303 
Available()304     bool Available() const
305     {
306         return available_;
307     }
308 
MarkAvailable(bool available)309     void MarkAvailable(bool available)
310     {
311         available_ = available;
312     }
313 
GetContext()314     WeakPtr<PipelineBase> GetContext() const
315     {
316         return context_;
317     }
318 
SetNodeId(int64_t nodeId)319     void SetNodeId(int64_t nodeId)
320     {
321         nodeId_ = nodeId;
322     }
323 
324     void ProcessScrollOverCallback(double velocity);
325 
326     void SetSlipFactor(double SlipFactor);
327 
SetOverSpringProperty(const RefPtr<SpringProperty> & property)328     void SetOverSpringProperty(const RefPtr<SpringProperty>& property)
329     {
330         if (property && property->IsValid()) {
331             spring_ = property;
332         }
333     }
334 
ChangeMoveStatus(bool flag)335     void ChangeMoveStatus(bool flag)
336     {
337         moved_ = flag;
338     }
339 
340     static const RefPtr<SpringProperty>& GetDefaultOverSpringProperty();
341 
GetPanRecognizer()342     RefPtr<PanRecognizer> GetPanRecognizer() const
343     {
344         return panRecognizer_;
345     }
346 
SetOnScrollBegin(const ScrollBeginCallback & scrollBeginCallback)347     void SetOnScrollBegin(const ScrollBeginCallback& scrollBeginCallback)
348     {
349         scrollBeginCallback_ = scrollBeginCallback;
350     }
351 
SetOnScrollFrameBegin(const ScrollFrameBeginCallback & scrollFrameBeginCallback)352     [[deprecated]] void SetOnScrollFrameBegin(const ScrollFrameBeginCallback& scrollFrameBeginCallback)
353     {
354         scrollFrameBeginCallback_ = scrollFrameBeginCallback;
355     }
356 
SetOnContinuousSliding(const ContinuousSlidingCallback & continuousSlidingCallback)357     void SetOnContinuousSliding(const ContinuousSlidingCallback& continuousSlidingCallback)
358     {
359         continuousSlidingCallback_ = continuousSlidingCallback;
360     }
361 
362     void OnFlushTouchEventsBegin() override;
363     void OnFlushTouchEventsEnd() override;
364 
SetNestedScrollOptions(NestedScrollOptions opt)365     [[deprecated]] void SetNestedScrollOptions(NestedScrollOptions opt)
366     {
367         nestedOpt_ = opt;
368     }
SetOverScrollOffsetCallback(std::function<OverScrollOffset (double)> && overScroll)369     [[deprecated]] void SetOverScrollOffsetCallback(std::function<OverScrollOffset(double)>&& overScroll)
370     {
371         overScrollOffsetCallback_ = std::move(overScroll);
372     }
SetHandleScrollCallback(NestableScrollCallback && func)373     void SetHandleScrollCallback(NestableScrollCallback&& func)
374     {
375         handleScrollCallback_ = std::move(func);
376     }
SetOverScrollCallback(std::function<bool (float)> && func)377     void SetOverScrollCallback(std::function<bool(float)>&& func)
378     {
379         overScrollCallback_ = std::move(func);
380     }
381     void StartScrollAnimation(float mainPosition, float velocity);
SetOnScrollStartRec(std::function<void (float)> && func)382     void SetOnScrollStartRec(std::function<void(float)>&& func)
383     {
384         onScrollStartRec_ = std::move(func);
385     }
SetOnScrollEndRec(std::function<void ()> && func)386     void SetOnScrollEndRec(std::function<void()>&& func)
387     {
388         onScrollEndRec_ = std::move(func);
389     }
SetParent(RefPtr<Scrollable> parent)390     [[deprecated]] void SetParent(RefPtr<Scrollable> parent)
391     {
392         parent_ = AceType::WeakClaim(AceType::RawPtr(parent));
393     }
SetEdgeEffect(EdgeEffect effect)394     void SetEdgeEffect(EdgeEffect effect)
395     {
396         edgeEffect_ = effect;
397     }
398 
SetOnScrollSnapCallback(const ScrollSnapCallback & scrollSnapCallback)399     void SetOnScrollSnapCallback(const ScrollSnapCallback& scrollSnapCallback)
400     {
401         scrollSnapCallback_ = scrollSnapCallback;
402     }
SetContinuousDragStatus(bool status)403     void SetContinuousDragStatus(bool status)
404     {
405         continuousDragStatus_ = status;
406     }
IncreaseContinueDragCount()407     void IncreaseContinueDragCount()
408     {
409         dragCount_++;
410     }
ResetContinueDragCount()411     void ResetContinueDragCount()
412     {
413         dragCount_ = 1;
414     }
SetDragStartPosition(double position)415     void SetDragStartPosition(double position)
416     {
417         dragStartPosition_ = position;
418     }
SetDragEndPosition(double position)419     void SetDragEndPosition(double position)
420     {
421         dragEndPosition_ = position;
422     }
GetDragOffset()423     double GetDragOffset()
424     {
425         return dragEndPosition_ - dragStartPosition_;
426     }
427 
SetCalePredictSnapOffsetCallback(CalePredictSnapOffsetCallback && calePredictSnapOffsetCallback)428     void SetCalePredictSnapOffsetCallback(CalePredictSnapOffsetCallback&& calePredictSnapOffsetCallback)
429     {
430         calePredictSnapOffsetCallback_ = std::move(calePredictSnapOffsetCallback);
431     }
432 
SetNeedScrollSnapToSideCallback(NeedScrollSnapToSideCallback && needScrollSnapToSideCallback)433     void SetNeedScrollSnapToSideCallback(NeedScrollSnapToSideCallback&& needScrollSnapToSideCallback)
434     {
435         needScrollSnapToSideCallback_ = std::move(needScrollSnapToSideCallback);
436     }
437 
438     void ProcessScrollSnapSpringMotion(float scrollSnapDelta, float scrollSnapVelocity);
439 
StopSnapController()440     void StopSnapController()
441     {
442         if (snapController_ && !snapController_->IsStopped()) {
443             snapController_->Stop();
444         }
445     }
446 
GetCurrentPos()447     double GetCurrentPos() const
448     {
449         return currentPos_;
450     }
451 
GetNeedScrollSnapChange()452     bool GetNeedScrollSnapChange() const
453     {
454         return needScrollSnapChange_;
455     }
456 
AddPreviewMenuHandleDragEnd(GestureEventFunc && actionEnd)457     void AddPreviewMenuHandleDragEnd(GestureEventFunc&& actionEnd)
458     {
459         actionEnd_ = std::move(actionEnd);
460     }
461 
GetIsDragging()462     bool GetIsDragging() const
463     {
464         return isDragging_;
465     }
466 
SetDragFRCSceneCallback(DragFRCSceneCallback && dragFRCSceneCallback)467     void SetDragFRCSceneCallback(DragFRCSceneCallback&& dragFRCSceneCallback)
468     {
469         dragFRCSceneCallback_ = std::move(dragFRCSceneCallback);
470     }
471 
SetScrollMotionFRCSceneCallback(ScrollMotionFRCSceneCallback && scrollMotionFRCSceneCallback)472     void SetScrollMotionFRCSceneCallback(ScrollMotionFRCSceneCallback&& scrollMotionFRCSceneCallback)
473     {
474         scrollMotionFRCSceneCallback_ = std::move(scrollMotionFRCSceneCallback);
475     }
476 
SetMaxFlingVelocity(double max)477     void SetMaxFlingVelocity(double max)
478     {
479         maxFlingVelocity_ = max;
480     }
481 
482 private:
483     bool UpdateScrollPosition(double offset, int32_t source) const;
484     void ProcessSpringMotion(double position);
485     void ProcessScrollMotion(double position);
486     void ProcessScrollSnapMotion(double position);
487     void FixScrollMotion(double position);
488     void ExecuteScrollBegin(double& mainDelta);
489     [[deprecated]] void ExecuteScrollFrameBegin(double& mainDelta, ScrollState state);
490     double ComputeCap(int dragCount);
491     double GetGain(double delta);
492     void SetDelayedTask();
493 
494     ScrollPositionCallback callback_;
495     ScrollEventCallback scrollEnd_;
496     ScrollEventCallback scrollEndCallback_;
497     ScrollEventCallback scrollTouchUpCallback_;
498     ScrollOverCallback scrollOverCallback_;       // scroll motion controller when edge set to spring
499     ScrollOverCallback notifyScrollOverCallback_; // scroll motion controller when edge set to spring
500     OutBoundaryCallback outBoundaryCallback_;     // whether out of boundary check when edge set to spring
501 
502     WatchFixCallback watchFixCallback_;
503     ScrollBeginCallback scrollBeginCallback_;
504     [[deprecated]] ScrollFrameBeginCallback scrollFrameBeginCallback_;
505     ScrollSnapCallback scrollSnapCallback_;
506     DragEndForRefreshCallback dragEndCallback_;
507     DragCancelRefreshCallback dragCancelCallback_;
508     ContinuousSlidingCallback continuousSlidingCallback_;
509     Axis axis_;
510     RefPtr<PanRecognizer> panRecognizer_;
511 
512     // used for ng structure.
513     RefPtr<NG::PanRecognizer> panRecognizerNG_;
514 
515     RefPtr<RawRecognizer> rawRecognizer_;
516     RefPtr<Animator> controller_;
517     RefPtr<Animator> springController_;
518     RefPtr<Animator> scrollSnapController_;
519     RefPtr<Animator> snapController_;
520     RefPtr<FrictionMotion> motion_;
521     RefPtr<ScrollMotion> scrollMotion_;
522     RefPtr<SpringMotion> scrollSnapMotion_;
523     RefPtr<SpringMotion> snapMotion_;
524     RefPtr<SpringProperty> spring_;
525     WeakPtr<PipelineBase> context_;
526     WeakPtr<RenderNode> scrollableNode_;
527     double currentPos_ = 0.0;
528     double currentVelocity_ = 0.0;
529     double maxFlingVelocity_ = 0.0;
530     bool scrollPause_ = false;
531     bool touchUp_ = false;
532     bool moved_ = false;
533     bool isTouching_ = false;
534     bool isDragging_ = false;
535     bool available_ = true;
536     bool needCenterFix_ = false;
537     bool isDragUpdateStop_ = false;
538     int64_t nodeId_ = 0;
539     double slipFactor_ = 0.0;
540     static double sFriction_;
541     static double sVelocityScale_;
542     bool continuousDragStatus_ = false;
543     CancelableCallback<void()> task_;
544     int32_t dragCount_ = 0;
545     double lastPos_ = 0.0;
546     double dragStartPosition_ = 0.0;
547     double dragEndPosition_ = 0.0;
548     double lastVelocity_ = 0.0;
549     double friction_ = -1.0;
550 #ifdef OHOS_PLATFORM
551     int64_t startIncreaseTime_ = 0;
552 #endif
553 
554     // nested scroll
555     [[deprecated]] WeakPtr<Scrollable> parent_;
556     [[deprecated]] NestedScrollOptions nestedOpt_ = { NestedScrollMode::SELF_ONLY, NestedScrollMode::SELF_ONLY };
557     [[deprecated]] std::function<OverScrollOffset(double)> overScrollOffsetCallback_;
558     // ScrollablePattern::HandleScroll
559     NestableScrollCallback handleScrollCallback_;
560     // ScrollablePattern::HandleOverScroll
561     std::function<bool(float)> overScrollCallback_;
562     // ScrollablePattern::onScrollStartRecursive
563     std::function<void(float)> onScrollStartRec_;
564     // ScrollablePattern::onScrollEndRecursive
565     std::function<void()> onScrollEndRec_;
566 
567     EdgeEffect edgeEffect_ = EdgeEffect::NONE;
568     bool canOverScroll_ = true;
569 
570     // scrollSnap
571     bool needScrollSnapChange_ = false;
572     CalePredictSnapOffsetCallback calePredictSnapOffsetCallback_;
573     NeedScrollSnapToSideCallback needScrollSnapToSideCallback_;
574     GestureEventFunc actionEnd_;
575 
576     DragFRCSceneCallback dragFRCSceneCallback_;
577     ScrollMotionFRCSceneCallback scrollMotionFRCSceneCallback_;
578 };
579 
580 } // namespace OHOS::Ace
581 
582 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_SCROLL_SCROLLABLE_H
583