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_EVENT_SCROLLABLE_EVENT_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_EVENT_SCROLLABLE_EVENT_H
18 
19 #include <list>
20 #include <unordered_map>
21 
22 #include "base/geometry/axis.h"
23 #include "base/memory/referenced.h"
24 #include "core/components_ng/event/target_component.h"
25 #include "core/components_ng/pattern/scrollable/scrollable.h"
26 #include "core/components_ng/event/gesture_event_actuator.h"
27 #include "core/components_ng/pattern/scroll/scroll_edge_effect.h"
28 
29 namespace OHOS::Ace::NG {
30 namespace {
31 constexpr float HTMBLOCK_VELOCITY = 200;
32 }
33 
34 class GestureEventHub;
35 
36 using BarCollectTouchTargetCallback = std::function<void(const OffsetF&, const GetEventTargetImpl&, TouchTestResult&,
37     const RefPtr<FrameNode>&, const RefPtr<TargetComponent>&, ResponseLinkResult& responseLinkResult)>;
38 using InBarRegionCallback = std::function<bool(const PointF&, SourceType source)>;
39 using GetAnimateVelocityCallback = std::function<double()>;
40 using ClickJudgeCallback = std::function<bool(const PointF&)>;
41 
42 class ScrollableEvent : public AceType {
DECLARE_ACE_TYPE(ScrollableEvent,AceType)43     DECLARE_ACE_TYPE(ScrollableEvent, AceType)
44 public:
45     explicit ScrollableEvent(Axis axis) : axis_(axis) {};
46     ~ScrollableEvent() override = default;
47 
GetAxis()48     Axis GetAxis() const
49     {
50         return axis_;
51     }
52 
SetAxis(Axis axis)53     void SetAxis(Axis axis)
54     {
55         axis_ = axis;
56         if (scrollable_) {
57             scrollable_->SetAxis(axis);
58         }
59     }
60 
SetScrollable(const RefPtr<Scrollable> & scrollable)61     void SetScrollable(const RefPtr<Scrollable>& scrollable)
62     {
63         scrollable_ = scrollable;
64     }
65 
GetScrollable()66     const RefPtr<Scrollable>& GetScrollable() const
67     {
68         return scrollable_;
69     }
70 
SetEnabled(bool enabled)71     void SetEnabled(bool enabled)
72     {
73         enabled_ = enabled;
74     }
75 
GetEnabled()76     bool GetEnabled() const
77     {
78         return enabled_;
79     }
80 
Idle()81     bool Idle() const
82     {
83         if (scrollable_) {
84             return scrollable_->Idle();
85         }
86         return true;
87     }
88 
IsHitTestBlock(const PointF & localPoint,SourceType source)89     bool IsHitTestBlock(const PointF& localPoint, SourceType source) const
90     {
91         if (source == SourceType::MOUSE && InBarRectRegion(localPoint, source)) {
92             return false;
93         }
94         if (scrollable_ && !scrollable_->Idle() &&
95             std::abs(scrollable_->GetCurrentVelocity()) > PipelineBase::Vp2PxWithCurrentDensity(HTMBLOCK_VELOCITY)) {
96             return true;
97         }
98         if (getAnimateVelocityCallback_) {
99             return std::abs(getAnimateVelocityCallback_()) > PipelineBase::Vp2PxWithCurrentDensity(HTMBLOCK_VELOCITY);
100         }
101         return false;
102     }
103 
SetBarCollectTouchTargetCallback(const BarCollectTouchTargetCallback && barCollectTouchTarget)104     void SetBarCollectTouchTargetCallback(const BarCollectTouchTargetCallback&& barCollectTouchTarget)
105     {
106         barCollectTouchTarget_ = std::move(barCollectTouchTarget);
107     }
108 
SetInBarRegionCallback(const InBarRegionCallback && inBarRegionCallback)109     void SetInBarRegionCallback(const InBarRegionCallback&& inBarRegionCallback)
110     {
111         inBarRegionCallback_ = std::move(inBarRegionCallback);
112     }
113 
InBarRegion(const PointF & localPoint,SourceType source)114     bool InBarRegion(const PointF& localPoint, SourceType source) const
115     {
116         return inBarRegionCallback_ && barCollectTouchTarget_ && inBarRegionCallback_(localPoint, source);
117     }
118 
BarCollectTouchTarget(const OffsetF & coordinateOffset,const GetEventTargetImpl & getEventTargetImpl,TouchTestResult & result,const RefPtr<FrameNode> & frameNode,const RefPtr<TargetComponent> & targetComponent,ResponseLinkResult & responseLinkResult)119     void BarCollectTouchTarget(const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
120         TouchTestResult& result, const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
121         ResponseLinkResult& responseLinkResult)
122     {
123         if (barCollectTouchTarget_) {
124             barCollectTouchTarget_(
125                 coordinateOffset, getEventTargetImpl, result, frameNode, targetComponent, responseLinkResult);
126         }
127     }
128 
SetAnimateVelocityCallback(const GetAnimateVelocityCallback && getAnimateVelocityCallback)129     void SetAnimateVelocityCallback(const GetAnimateVelocityCallback&& getAnimateVelocityCallback)
130     {
131         getAnimateVelocityCallback_ = std::move(getAnimateVelocityCallback);
132     }
133 
AddPreviewMenuHandleDragEnd(GestureEventFunc && actionEnd)134     void AddPreviewMenuHandleDragEnd(GestureEventFunc&& actionEnd)
135     {
136         if (scrollable_) {
137             scrollable_->AddPreviewMenuHandleDragEnd(std::move(actionEnd));
138         }
139     }
140 
SetBarCollectClickAndLongPressTargetCallback(const BarCollectTouchTargetCallback && barCollectLongPressTarget)141     void SetBarCollectClickAndLongPressTargetCallback(const BarCollectTouchTargetCallback&& barCollectLongPressTarget)
142     {
143         barCollectLongPressTarget_ = std::move(barCollectLongPressTarget);
144     }
145 
SetInBarRectRegionCallback(const InBarRegionCallback && inBarRectRegionCallback)146     void SetInBarRectRegionCallback(const InBarRegionCallback&& inBarRectRegionCallback)
147     {
148         inBarRectRegionCallback_ = std::move(inBarRectRegionCallback);
149     }
150 
InBarRectRegion(const PointF & localPoint,SourceType source)151     bool InBarRectRegion(const PointF& localPoint, SourceType source) const
152     {
153         CHECK_NULL_RETURN(inBarRectRegionCallback_, false);
154         return inBarRectRegionCallback_ && barCollectLongPressTarget_ && inBarRectRegionCallback_(localPoint, source);
155     }
156 
BarCollectLongPressTarget(const OffsetF & coordinateOffset,const GetEventTargetImpl & getEventTargetImpl,TouchTestResult & result,const RefPtr<FrameNode> & frameNode,const RefPtr<TargetComponent> & targetComponent,ResponseLinkResult & responseLinkResult)157     void BarCollectLongPressTarget(const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
158         TouchTestResult& result, const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
159         ResponseLinkResult& responseLinkResult)
160     {
161         if (barCollectLongPressTarget_) {
162             barCollectLongPressTarget_(
163                 coordinateOffset, getEventTargetImpl, result, frameNode, targetComponent, responseLinkResult);
164         }
165     }
166 
ClickJudge(const PointF & localPoint)167     bool ClickJudge(const PointF& localPoint) const
168     {
169         return clickJudgeCallback_ && clickJudgeCallback_(localPoint);
170     }
171 
SetClickJudgeCallback(const ClickJudgeCallback && clickJudgeCallback)172     void SetClickJudgeCallback(const ClickJudgeCallback&& clickJudgeCallback)
173     {
174         clickJudgeCallback_ = std::move(clickJudgeCallback);
175     }
176 
177     void CollectScrollableTouchTarget(const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
178         TouchTestResult& result, const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
179         ResponseLinkResult& responseLinkResult);
180 
181 private:
182     Axis axis_ = Axis::VERTICAL;
183     bool enabled_ = true;
184     RefPtr<Scrollable> scrollable_;
185     BarCollectTouchTargetCallback barCollectTouchTarget_;
186     BarCollectTouchTargetCallback barCollectLongPressTarget_;
187     InBarRegionCallback inBarRegionCallback_;
188     InBarRegionCallback inBarRectRegionCallback_;
189     GetAnimateVelocityCallback getAnimateVelocityCallback_;
190     ClickJudgeCallback clickJudgeCallback_;
191 };
192 
193 class ScrollableActuator : public GestureEventActuator {
194     DECLARE_ACE_TYPE(ScrollableActuator, GestureEventActuator)
195 public:
196     explicit ScrollableActuator(const WeakPtr<GestureEventHub>& gestureEventHub);
197     ~ScrollableActuator() override = default;
198 
AddScrollableEvent(const RefPtr<ScrollableEvent> & scrollableEvent)199     void AddScrollableEvent(const RefPtr<ScrollableEvent>& scrollableEvent)
200     {
201         scrollableEvents_[scrollableEvent->GetAxis()] = scrollableEvent;
202     }
203 
RemoveScrollableEvent(const RefPtr<ScrollableEvent> & scrollableEvent)204     void RemoveScrollableEvent(const RefPtr<ScrollableEvent>& scrollableEvent)
205     {
206         scrollableEvents_.erase(scrollableEvent->GetAxis());
207     }
208 
AddPreviewMenuHandleDragEnd(GestureEventFunc && actionEnd)209     void AddPreviewMenuHandleDragEnd(GestureEventFunc&& actionEnd)
210     {
211         for (auto it = scrollableEvents_.begin(); it != scrollableEvents_.end(); ++it) {
212             auto scrollableEvent = it->second;
213             if (!scrollableEvent) {
214                 continue;
215             }
216             scrollableEvent->AddPreviewMenuHandleDragEnd(std::move(actionEnd));
217             break;
218         }
219     }
220 
221     void AddScrollEdgeEffect(const Axis& axis, RefPtr<ScrollEdgeEffect>& effect);
222     bool RemoveScrollEdgeEffect(const RefPtr<ScrollEdgeEffect>& effect);
223 
224     void CollectTouchTarget(const OffsetF& coordinateOffset, const TouchRestrict& touchRestrict,
225         const GetEventTargetImpl& getEventTargetImpl, TouchTestResult& result, const PointF& localPoint,
226         const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
227         ResponseLinkResult& responseLinkResult);
228 
229     void InitClickRecognizer(const OffsetF& coordinateOffset, const GetEventTargetImpl& getEventTargetImpl,
230         const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
231         const RefPtr<ScrollableEvent>& event, bool clickJudge,
232         const PointF& localPoint, SourceType source);
233 
234 private:
235     void InitializeScrollable(RefPtr<ScrollableEvent> event);
236 
237     std::unordered_map<Axis, RefPtr<ScrollableEvent>> scrollableEvents_;
238     std::unordered_map<Axis, RefPtr<ScrollEdgeEffect>> scrollEffects_;
239     WeakPtr<GestureEventHub> gestureEventHub_;
240     RefPtr<ClickRecognizer> clickRecognizer_;
241 };
242 
243 } // namespace OHOS::Ace::NG
244 
245 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_EVENT_SCROLLABLE_EVENT_HUB_H
246