1 /*
2  * Copyright (c) 2023-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_SCROLL_SCROLLABLE_NG_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_SCROLL_SCROLLABLE_NG_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/components_ng/render/animation_utils.h"
29 #include "core/event/axis_event.h"
30 #include "core/event/touch_event.h"
31 #include "core/gestures/raw_recognizer.h"
32 #include "core/gestures/timeout_recognizer.h"
33 
34 namespace OHOS::Ace::NG {
35 enum class NestedState {
36     GESTURE = 0,
37     CHILD_SCROLL,
38     CHILD_OVER_SCROLL,
39 };
40 
41 struct OverScrollOffset {
42     double start;
43     double end;
44 };
45 
46 struct ScrollResult {
47     double remain;
48     bool reachEdge;
49 };
50 
51 using ScrollEventCallback = std::function<void()>;
52 using OutBoundaryCallback = std::function<bool()>;
53 using ScrollOverCallback = std::function<void(double velocity)>;
54 using WatchFixCallback = std::function<double(double final, double current)>;
55 using ScrollBeginCallback = std::function<ScrollInfo(Dimension, Dimension)>;
56 using ScrollFrameBeginCallback = std::function<ScrollFrameResult(Dimension, ScrollState)>;
57 using DragEndForRefreshCallback = std::function<void()>;
58 using DragCancelRefreshCallback = std::function<void()>;
59 using MouseLeftButtonScroll = std::function<bool()>;
60 using ScrollSnapCallback = std::function<bool(double targetOffset, double velocity)>;
61 using ContinuousSlidingCallback = std::function<double()>;
62 using CalePredictSnapOffsetCallback =
63     std::function<std::optional<float>(float delta, float dragDistance, float velocity)>;
64 using NeedScrollSnapToSideCallback = std::function<bool(float delta)>;
65 using NestableScrollCallback = std::function<ScrollResult(float, int32_t, NestedState)>;
66 using DragFRCSceneCallback = std::function<void(double velocity, NG::SceneStatus sceneStatus)>;
67 using IsReverseCallback = std::function<bool()>;
68 using RemainVelocityCallback = std::function<bool(float)>;
69 
70 class FrameNode;
71 class PipelineContext;
72 
73 class Scrollable : public TouchEventTarget {
74     DECLARE_ACE_TYPE(Scrollable, TouchEventTarget);
75 
76 public:
77     Scrollable();
78     Scrollable(ScrollPositionCallback&& callback, Axis axis);
79     Scrollable(const ScrollPositionCallback& callback, Axis axis);
80     ~Scrollable() override;
81 
82     static void SetVelocityScale(double sVelocityScale);
83     static double GetVelocityScale();
84     static void SetFriction(double sFriction);
85 
86     void Initialize(const WeakPtr<PipelineBase>& context);
87 
88     void Initialize(PipelineContext* context);
89 
IsMotionStop()90     bool IsMotionStop() const
91     {
92         return isSpringAnimationStop_ && isFrictionAnimationStop_ && !moved_;
93     }
94 
IsSpringMotionRunning()95     bool IsSpringMotionRunning() const
96     {
97         return !isSpringAnimationStop_;
98     }
99 
IsDragging()100     bool IsDragging() const
101     {
102         return isTouching_ && !isFrictionAnimationStop_;
103     }
104 
105     void SetAxis(Axis axis);
106 
GetMainOffset(const Offset & offset)107     double GetMainOffset(const Offset& offset) const
108     {
109         return axis_ == Axis::HORIZONTAL ? offset.GetX() : offset.GetY();
110     }
111 
GetMainSize(const Size & size)112     double GetMainSize(const Size& size) const
113     {
114         return axis_ == Axis::HORIZONTAL ? size.Width() : size.Height();
115     }
116 
SetCallback(const ScrollPositionCallback & callback)117     void SetCallback(const ScrollPositionCallback& callback)
118     {
119         callback_ = callback;
120     }
121 
SetCoordinateOffset(const Offset & offset)122     void SetCoordinateOffset(const Offset& offset) const
123     {
124         if (panRecognizerNG_) {
125             panRecognizerNG_->SetCoordinateOffset(offset);
126         }
127     }
128 
129     void OnCollectTouchTarget(TouchTestResult& result, const RefPtr<FrameNode>& frameNode,
130         const RefPtr<TargetComponent>& targetComponent, ResponseLinkResult& responseLinkResult);
131 
SetDragTouchRestrict(const TouchRestrict & touchRestrict)132     void SetDragTouchRestrict(const TouchRestrict& touchRestrict)
133     {
134         if (panRecognizerNG_) {
135             panRecognizerNG_->SetTouchRestrict(touchRestrict);
136         }
137     }
138 
SetScrollEndCallback(const ScrollEventCallback & scrollEndCallback)139     void SetScrollEndCallback(const ScrollEventCallback& scrollEndCallback)
140     {
141         scrollEndCallback_ = scrollEndCallback;
142     }
143 
SetScrollTouchUpCallback(const ScrollEventCallback & scrollTouchUpCallback)144     void SetScrollTouchUpCallback(const ScrollEventCallback& scrollTouchUpCallback)
145     {
146         scrollTouchUpCallback_ = scrollTouchUpCallback;
147     }
148 
SetUnstaticFriction(double friction)149     void SetUnstaticFriction(double friction)
150     {
151         friction_ = friction;
152     }
153 
154     void HandleTouchDown();
155     void HandleTouchUp();
156     void HandleTouchCancel();
157     void HandleDragStart(const GestureEvent& info);
158     void HandleDragUpdate(const GestureEvent& info);
159     void HandleDragEnd(const GestureEvent& info);
160     void HandleScrollEnd(const std::optional<float>& velocity);
161     bool HandleOverScroll(double velocity);
162     ScrollResult HandleScroll(double offset, int32_t source, NestedState state);
163     void LayoutDirectionEst(double& correctVelocity);
164 
SetMoved(bool value)165     void SetMoved(bool value)
166     {
167         moved_ = value;
168     }
SetCanOverScroll(bool value)169     void SetCanOverScroll(bool value)
170     {
171         canOverScroll_ = value;
172     }
CanOverScroll()173     bool CanOverScroll() const
174     {
175         return canOverScroll_;
176     }
177 
178     void ProcessScrollMotionStop(bool StopFriction);
179 
DispatchEvent(const TouchEvent & point)180     bool DispatchEvent(const TouchEvent& point) override
181     {
182         return true;
183     }
HandleEvent(const TouchEvent & event)184     bool HandleEvent(const TouchEvent& event) override
185     {
186         if (!available_) {
187             return true;
188         }
189         return true;
190     }
HandleEvent(const AxisEvent & event)191     bool HandleEvent(const AxisEvent& event) override
192     {
193         return false;
194     }
195 
SetScrollEnd(const ScrollEventCallback & scrollEnd)196     void SetScrollEnd(const ScrollEventCallback& scrollEnd)
197     {
198         scrollEnd_ = scrollEnd;
199     }
200 
SetRemainVelocityCallback(const RemainVelocityCallback & remainVelocityCallback)201     void SetRemainVelocityCallback(const RemainVelocityCallback& remainVelocityCallback)
202     {
203         remainVelocityCallback_ = remainVelocityCallback;
204     }
205 
SetScrollOverCallBack(const ScrollOverCallback & scrollOverCallback)206     void SetScrollOverCallBack(const ScrollOverCallback& scrollOverCallback)
207     {
208         scrollOverCallback_ = scrollOverCallback;
209     }
210 
SetNotifyScrollOverCallBack(const ScrollOverCallback & scrollOverCallback)211     void SetNotifyScrollOverCallBack(const ScrollOverCallback& scrollOverCallback)
212     {
213         notifyScrollOverCallback_ = scrollOverCallback;
214     }
215 
SetCurrentPositionCallback(const std::function<double ()> & currentPositionCallback)216     void SetCurrentPositionCallback(const std::function<double()>& currentPositionCallback)
217     {
218         currentPositionCallback_ = currentPositionCallback;
219     }
220 
SetOutBoundaryCallback(const OutBoundaryCallback & outBoundaryCallback)221     void SetOutBoundaryCallback(const OutBoundaryCallback& outBoundaryCallback)
222     {
223         outBoundaryCallback_ = outBoundaryCallback;
224     }
225 
SetDragEndCallback(const DragEndForRefreshCallback & dragEndCallback)226     void SetDragEndCallback(const DragEndForRefreshCallback& dragEndCallback)
227     {
228         dragEndCallback_ = dragEndCallback;
229     }
230 
SetDragCancelCallback(const DragCancelRefreshCallback & dragCancelCallback)231     void SetDragCancelCallback(const DragCancelRefreshCallback& dragCancelCallback)
232     {
233         dragCancelCallback_ = dragCancelCallback;
234     }
235 
GetDragEndCallback()236     const DragEndForRefreshCallback& GetDragEndCallback() const
237     {
238         return dragEndCallback_;
239     }
240 
GetDragCancelCallback()241     const DragCancelRefreshCallback& GetDragCancelCallback() const
242     {
243         return dragCancelCallback_;
244     }
245 
SetWatchFixCallback(const WatchFixCallback & watchFixCallback)246     void SetWatchFixCallback(const WatchFixCallback& watchFixCallback)
247     {
248         watchFixCallback_ = watchFixCallback;
249     }
250 
MarkNeedCenterFix(bool needFix)251     void MarkNeedCenterFix(bool needFix)
252     {
253         needCenterFix_ = needFix;
254     }
255 
GetCurrentVelocity()256     double GetCurrentVelocity() const
257     {
258         return currentVelocity_;
259     };
260 
SetIsReverseCallback(const IsReverseCallback & isReverseCallback)261     void SetIsReverseCallback(const IsReverseCallback& isReverseCallback)
262     {
263         isReverseCallback_ = isReverseCallback;
264     }
265 
266     void OnAnimateStop();
267     void ProcessScrollSnapStop();
268     void StartSpringMotion(
269         double mainPosition, double mainVelocity, const ExtentPair& extent, const ExtentPair& initExtent);
270     void UpdateSpringMotion(double mainPosition, const ExtentPair& extent, const ExtentPair& initExtent);
271 
272     void UpdateScrollSnapStartOffset(double offset);
273     void StartScrollSnapMotion(float predictSnapOffset, float scrollSnapVelocity);
274     void UpdateScrollSnapEndWithOffset(double offset);
275 
276     bool IsAnimationNotRunning() const;
277 
278     bool Idle() const;
279 
280     bool IsStopped() const;
281 
282     bool IsSpringStopped() const;
283 
284     bool IsSnapStopped() const;
285 
286     void StopScrollable();
287 
Available()288     bool Available() const
289     {
290         return available_;
291     }
292 
MarkAvailable(bool available)293     void MarkAvailable(bool available)
294     {
295         available_ = available;
296     }
297 
GetContext()298     WeakPtr<PipelineBase> GetContext() const
299     {
300         return context_;
301     }
302 
SetNodeId(int32_t nodeId)303     void SetNodeId(int32_t nodeId)
304     {
305         nodeId_ = nodeId;
306     }
307 
SetNodeTag(const std::string & nodeTag)308     void SetNodeTag(const std::string& nodeTag)
309     {
310         nodeTag_ = nodeTag;
311     }
312 
313     void ProcessScrollOverCallback(double velocity);
314 
315     void SetSlipFactor(double SlipFactor);
316 
ChangeMoveStatus(bool flag)317     void ChangeMoveStatus(bool flag)
318     {
319         moved_ = flag;
320     }
321 
SetOnScrollBegin(const ScrollBeginCallback & scrollBeginCallback)322     void SetOnScrollBegin(const ScrollBeginCallback& scrollBeginCallback)
323     {
324         scrollBeginCallback_ = scrollBeginCallback;
325     }
326 
SetOnContinuousSliding(const ContinuousSlidingCallback & continuousSlidingCallback)327     void SetOnContinuousSliding(const ContinuousSlidingCallback& continuousSlidingCallback)
328     {
329         continuousSlidingCallback_ = continuousSlidingCallback;
330     }
331 
SetHandleScrollCallback(NestableScrollCallback && func)332     void SetHandleScrollCallback(NestableScrollCallback&& func)
333     {
334         handleScrollCallback_ = std::move(func);
335     }
SetOverScrollCallback(std::function<bool (float)> && func)336     void SetOverScrollCallback(std::function<bool(float)>&& func)
337     {
338         overScrollCallback_ = std::move(func);
339     }
340     void StartScrollAnimation(float mainPosition, float velocity);
SetOnScrollStartRec(std::function<void (float)> && func)341     void SetOnScrollStartRec(std::function<void(float)>&& func)
342     {
343         onScrollStartRec_ = std::move(func);
344     }
SetOnScrollEndRec(std::function<void (const std::optional<float> &)> && func)345     void SetOnScrollEndRec(std::function<void(const std::optional<float>&)>&& func)
346     {
347         onScrollEndRec_ = std::move(func);
348     }
349 
SetEdgeEffect(EdgeEffect effect)350     void SetEdgeEffect(EdgeEffect effect)
351     {
352         edgeEffect_ = effect;
353     }
354 
SetOnScrollSnapCallback(const ScrollSnapCallback & scrollSnapCallback)355     void SetOnScrollSnapCallback(const ScrollSnapCallback& scrollSnapCallback)
356     {
357         scrollSnapCallback_ = scrollSnapCallback;
358     }
SetContinuousDragStatus(bool status)359     void SetContinuousDragStatus(bool status)
360     {
361         continuousDragStatus_ = status;
362     }
IncreaseContinueDragCount()363     void IncreaseContinueDragCount()
364     {
365         dragCount_++;
366     }
ResetContinueDragCount()367     void ResetContinueDragCount()
368     {
369         dragCount_ = 1;
370     }
SetDragStartPosition(double position)371     void SetDragStartPosition(double position)
372     {
373         dragStartPosition_ = position;
374     }
SetDragEndPosition(double position)375     void SetDragEndPosition(double position)
376     {
377         dragEndPosition_ = position;
378     }
GetDragOffset()379     double GetDragOffset()
380     {
381         return dragEndPosition_ - dragStartPosition_;
382     }
383 
SetCalePredictSnapOffsetCallback(CalePredictSnapOffsetCallback && calePredictSnapOffsetCallback)384     void SetCalePredictSnapOffsetCallback(CalePredictSnapOffsetCallback&& calePredictSnapOffsetCallback)
385     {
386         calePredictSnapOffsetCallback_ = std::move(calePredictSnapOffsetCallback);
387     }
388 
SetNeedScrollSnapToSideCallback(NeedScrollSnapToSideCallback && needScrollSnapToSideCallback)389     void SetNeedScrollSnapToSideCallback(NeedScrollSnapToSideCallback&& needScrollSnapToSideCallback)
390     {
391         needScrollSnapToSideCallback_ = std::move(needScrollSnapToSideCallback);
392     }
393 
394     void ProcessScrollSnapSpringMotion(float scrollSnapDelta, float scrollSnapVelocity);
395 
StopSnapController()396     void StopSnapController()
397     {
398         if (!isSnapAnimationStop_) {
399             StopSnapAnimation();
400         }
401     }
402 
GetCurrentPos()403     double GetCurrentPos() const
404     {
405         return currentPos_;
406     }
407 
GetNeedScrollSnapChange()408     bool GetNeedScrollSnapChange() const
409     {
410         return needScrollSnapChange_;
411     }
412 
AddPreviewMenuHandleDragEnd(GestureEventFunc && actionEnd)413     void AddPreviewMenuHandleDragEnd(GestureEventFunc&& actionEnd)
414     {
415         AddPanActionEndEvent(std::move(actionEnd));
416     }
417 
GetIsDragging()418     bool GetIsDragging() const
419     {
420         return isDragging_;
421     }
422 
SetDragFRCSceneCallback(DragFRCSceneCallback && dragFRCSceneCallback)423     void SetDragFRCSceneCallback(DragFRCSceneCallback&& dragFRCSceneCallback)
424     {
425         dragFRCSceneCallback_ = std::move(dragFRCSceneCallback);
426     }
427 
GetFinalPosition()428     float GetFinalPosition()
429     {
430         return finalPosition_;
431     }
432 
GetSnapFinalPosition()433     float GetSnapFinalPosition()
434     {
435         return endPos_;
436     }
437 
SetMaxFlingVelocity(double max)438     void SetMaxFlingVelocity(double max)
439     {
440         double density = PipelineBase::GetCurrentDensity();
441         maxFlingVelocity_ = max * density;
442     }
443 
GetMaxFlingVelocity()444     double GetMaxFlingVelocity() const
445     {
446         return maxFlingVelocity_;
447     }
448 
449     void StopFrictionAnimation();
450     void StopSpringAnimation(bool reachFinalPosition = false);
451     void StopSnapAnimation();
452 
453     RefPtr<NodeAnimatablePropertyFloat> GetFrictionProperty();
454     RefPtr<NodeAnimatablePropertyFloat> GetSpringProperty();
455     RefPtr<NodeAnimatablePropertyFloat> GetSnapProperty();
456 
GetPanDirection()457     Axis GetPanDirection() const
458     {
459         CHECK_NULL_RETURN(panRecognizerNG_, Axis::NONE);
460         return panRecognizerNG_->GetAxisDirection();
461     }
462 
SetNestedScrolling(bool nestedScrolling)463     void SetNestedScrolling(bool nestedScrolling)
464     {
465         nestedScrolling_ = nestedScrolling;
466     }
467 
GetNestedScrolling()468     bool GetNestedScrolling() const
469     {
470         return nestedScrolling_;
471     }
472 
AddPanActionEndEvent(GestureEventFunc && event)473     void AddPanActionEndEvent(GestureEventFunc&& event)
474     {
475         panActionEndEvents_.emplace_back(event);
476     }
477 
478 private:
479     bool UpdateScrollPosition(double offset, int32_t source) const;
480     void ProcessSpringMotion(double position);
481     void ProcessScrollMotion(double position);
482     void ProcessScrollSnapMotion(double position);
483     void FixScrollMotion(float position, float initVelocity);
484     void ExecuteScrollBegin(double& mainDelta);
485     double ComputeCap(int dragCount);
486     double GetGain(double delta);
487     void SetDelayedTask();
488     void MarkNeedFlushAnimationStartTime();
489     float GetFrictionVelocityByFinalPosition(
490         float final, float position, float signum, float friction, float threshold = DEFAULT_MULTIPLIER);
491 
492     /**
493      * @brief Checks if the scroll event is caused by a mouse wheel.
494      *
495      * @param info The GestureEvent containing the scroll event information.
496      * @return true if the scroll event is caused by a mouse wheel, false otherwise.
497      */
498     static inline bool IsMouseWheelScroll(const GestureEvent& info);
499 
500     ScrollPositionCallback callback_;
501     ScrollEventCallback scrollEnd_;
502     ScrollEventCallback scrollEndCallback_;
503     ScrollEventCallback scrollTouchUpCallback_;
504     ScrollOverCallback scrollOverCallback_;       // scroll motion controller when edge set to spring
505     ScrollOverCallback notifyScrollOverCallback_; // scroll motion controller when edge set to spring
506     OutBoundaryCallback outBoundaryCallback_;     // whether out of boundary check when edge set to spring
507     std::function<double()> currentPositionCallback_;
508     IsReverseCallback isReverseCallback_;
509 
510     WatchFixCallback watchFixCallback_;
511     ScrollBeginCallback scrollBeginCallback_;
512     ScrollSnapCallback scrollSnapCallback_;
513     DragEndForRefreshCallback dragEndCallback_;
514     DragCancelRefreshCallback dragCancelCallback_;
515     ContinuousSlidingCallback continuousSlidingCallback_;
516     Axis axis_ = Axis::VERTICAL;
517     // used for ng structure.
518     RefPtr<NG::PanRecognizer> panRecognizerNG_;
519 
520     WeakPtr<PipelineBase> context_;
521     double currentPos_ = 0.0;
522     double currentVelocity_ = 0.0;
523     double maxFlingVelocity_ = 0.0;
524     bool scrollPause_ = false;
525     bool touchUp_ = false;
526     bool moved_ = false;
527     bool isTouching_ = false;
528     bool isDragging_ = false;
529     bool available_ = true;
530     bool needCenterFix_ = false;
531     bool isDragUpdateStop_ = false;
532     bool isFadingAway_ = false;
533     // The accessibilityId of UINode
534     int32_t nodeId_ = 0;
535     // The tag of UINode
536     std::string nodeTag_ = "Scrollable";
537     double slipFactor_ = 0.0;
538     static std::optional<double> sFriction_;
539     static std::optional<double> sVelocityScale_;
540     bool continuousDragStatus_ = false;
541     CancelableCallback<void()> task_;
542     int32_t dragCount_ = 0;
543     double lastPos_ = 0.0;
544     double dragStartPosition_ = 0.0;
545     double dragEndPosition_ = 0.0;
546     double lastVelocity_ = 0.0;
547     double friction_ = -1.0;
548     double velocityScale_ = 0.0;
549     double preGain_ = 1.0;
550 #ifdef OHOS_PLATFORM
551     int64_t startIncreaseTime_ = 0;
552 #endif
553 
554     // ScrollablePattern::HandleScroll
555     NestableScrollCallback handleScrollCallback_;
556     // ScrollablePattern::HandleOverScroll
557     std::function<bool(float)> overScrollCallback_;
558     // ScrollablePattern::onScrollStartRecursiveInner
559     std::function<void(float)> onScrollStartRec_;
560     // ScrollablePattern::onScrollEndRecursiveInner
561     std::function<void(const std::optional<float>&)> onScrollEndRec_;
562     // ScrollablePattern::RemainVelocityToChild
563     RemainVelocityCallback remainVelocityCallback_;
564 
565     EdgeEffect edgeEffect_ = EdgeEffect::NONE;
566     bool canOverScroll_ = true;
567 
568     // scrollSnap
569     bool needScrollSnapChange_ = false;
570     CalePredictSnapOffsetCallback calePredictSnapOffsetCallback_;
571     NeedScrollSnapToSideCallback needScrollSnapToSideCallback_;
572     std::list<GestureEventFunc> panActionEndEvents_;
573 
574     DragFRCSceneCallback dragFRCSceneCallback_;
575 
576     uint64_t lastVsyncTime_ = 0;
577     RefPtr<NodeAnimatablePropertyFloat> frictionOffsetProperty_;
578     float finalPosition_ = 0.0f;
579     float lastPosition_ = 0.0f;
580     float initVelocity_ = 0.0f;
581     float frictionVelocity_ = 0.0f;
582     bool isFrictionAnimationStop_ = true;
583 
584     RefPtr<NodeAnimatablePropertyFloat> springOffsetProperty_;
585     bool isSpringAnimationStop_ = true;
586     bool skipRestartSpring_ = false; // set to true when need to skip repeated spring animation
587     uint32_t updateSnapAnimationCount_ = 0;
588     uint32_t springAnimationCount_ = 0;
589 
590     RefPtr<NodeAnimatablePropertyFloat> snapOffsetProperty_;
591     bool isSnapAnimationStop_ = true;
592     bool isSnapScrollAnimationStop_ = true;
593     float snapVelocity_ = 0.0f;
594     float endPos_ = 0.0;
595     bool isSnapAnimation_ = false;
596     bool nestedScrolling_ = false;
597 };
598 
599 } // namespace OHOS::Ace::NG
600 
601 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_SCROLL_SCROLLABLE_NG_H
602