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 #include "core/components_ng/event/scrollable_event.h"
17
18 #include "core/components_ng/event/target_component.h"
19 #include "core/components_ng/gestures/recognizers/parallel_recognizer.h"
20 #include "core/components_ng/pattern/list/list_pattern.h"
21 #include "core/components_ng/pattern/scroll/scroll_edge_effect.h"
22 #include "core/components_ng/pattern/scroll/scroll_pattern.h"
23 #include "core/components_ng/pattern/scrollable/scrollable.h"
24
25 namespace OHOS::Ace::NG {
26
ScrollableEvent(Axis axis)27 ScrollableEvent::ScrollableEvent(Axis axis) : axis_(axis) {};
28 ScrollableEvent::~ScrollableEvent() = default;
29
ScrollableActuator(const WeakPtr<GestureEventHub> & gestureEventHub)30 ScrollableActuator::ScrollableActuator(const WeakPtr<GestureEventHub>& gestureEventHub)
31 : gestureEventHub_(gestureEventHub)
32 {}
33
SetAxis(Axis axis)34 void ScrollableEvent::SetAxis(Axis axis)
35 {
36 axis_ = axis;
37 if (scrollable_) {
38 scrollable_->SetAxis(axis);
39 }
40 }
41
SetScrollable(const RefPtr<Scrollable> & scrollable)42 void ScrollableEvent::SetScrollable(const RefPtr<Scrollable>& scrollable)
43 {
44 scrollable_ = scrollable;
45 }
46
GetScrollable() const47 const RefPtr<Scrollable>& ScrollableEvent::GetScrollable() const
48 {
49 return scrollable_;
50 }
51
Idle() const52 bool ScrollableEvent::Idle() const
53 {
54 if (scrollable_) {
55 return scrollable_->Idle();
56 }
57 return true;
58 }
59
IsHitTestBlock(const PointF & localPoint,SourceType source) const60 bool ScrollableEvent::IsHitTestBlock(const PointF& localPoint, SourceType source) const
61 {
62 if (source == SourceType::MOUSE && InBarRectRegion(localPoint, source)) {
63 return false;
64 }
65 if (scrollable_ && !scrollable_->Idle() &&
66 std::abs(scrollable_->GetCurrentVelocity()) > PipelineBase::Vp2PxWithCurrentDensity(HTMBLOCK_VELOCITY)) {
67 return true;
68 }
69 if (getAnimateVelocityCallback_) {
70 return std::abs(getAnimateVelocityCallback_()) > PipelineBase::Vp2PxWithCurrentDensity(HTMBLOCK_VELOCITY);
71 }
72 return false;
73 }
74
AddPreviewMenuHandleDragEnd(GestureEventFunc && actionEnd)75 void ScrollableEvent::AddPreviewMenuHandleDragEnd(GestureEventFunc&& actionEnd)
76 {
77 if (scrollable_) {
78 scrollable_->AddPreviewMenuHandleDragEnd(std::move(actionEnd));
79 }
80 }
81
AddScrollEdgeEffect(const Axis & axis,RefPtr<ScrollEdgeEffect> & effect)82 void ScrollableActuator::AddScrollEdgeEffect(const Axis& axis, RefPtr<ScrollEdgeEffect>& effect)
83 {
84 CHECK_NULL_VOID(effect);
85 auto scrollable = scrollableEvents_[axis];
86 CHECK_NULL_VOID(scrollable);
87 effect->SetScrollable(scrollable->GetScrollable());
88 effect->InitialEdgeEffect();
89 scrollEffects_[axis] = effect;
90 }
91
RemoveScrollEdgeEffect(const RefPtr<ScrollEdgeEffect> & effect)92 bool ScrollableActuator::RemoveScrollEdgeEffect(const RefPtr<ScrollEdgeEffect>& effect)
93 {
94 CHECK_NULL_RETURN(effect, false);
95 for (auto iter = scrollEffects_.begin(); iter != scrollEffects_.end(); ++iter) {
96 if (effect == iter->second) {
97 scrollEffects_.erase(iter);
98 return true;
99 }
100 }
101 return false;
102 }
103
CollectTouchTarget(const OffsetF & coordinateOffset,const TouchRestrict & touchRestrict,const GetEventTargetImpl & getEventTargetImpl,TouchTestResult & result,const PointF & localPoint,const RefPtr<FrameNode> & frameNode,const RefPtr<TargetComponent> & targetComponent,ResponseLinkResult & responseLinkResult,int32_t touchId)104 void ScrollableActuator::CollectTouchTarget(const OffsetF& coordinateOffset, const TouchRestrict& touchRestrict,
105 const GetEventTargetImpl& getEventTargetImpl, TouchTestResult& result, const PointF& localPoint,
106 const RefPtr<FrameNode>& frameNode, const RefPtr<TargetComponent>& targetComponent,
107 ResponseLinkResult& responseLinkResult, int32_t touchId)
108 {
109 for (const auto& [axis, event] : scrollableEvents_) {
110 if (!event) {
111 continue;
112 }
113 if (event->GetEnabled()) {
114 if (event->InBarRegion(localPoint, touchRestrict.sourceType)) {
115 event->BarCollectTouchTarget(
116 coordinateOffset, getEventTargetImpl, result, frameNode, targetComponent, responseLinkResult);
117 } else if (event->InBarRectRegion(localPoint, touchRestrict.sourceType)) {
118 event->BarCollectLongPressTarget(
119 coordinateOffset, getEventTargetImpl, result, frameNode, targetComponent, responseLinkResult);
120 event->CollectScrollableTouchTarget(coordinateOffset, getEventTargetImpl, result, frameNode,
121 targetComponent, responseLinkResult, touchId);
122 event->BarRectCollectTouchTarget(
123 coordinateOffset, getEventTargetImpl, result, frameNode, targetComponent, responseLinkResult);
124 } else {
125 event->CollectScrollableTouchTarget(coordinateOffset, getEventTargetImpl, result, frameNode,
126 targetComponent, responseLinkResult, touchId);
127 }
128 }
129 bool clickJudge = event->ClickJudge(localPoint);
130 if (event->GetEnabled() || clickJudge) {
131 InitClickRecognizer(coordinateOffset, getEventTargetImpl, frameNode, targetComponent, event, clickJudge,
132 localPoint, touchRestrict.sourceType);
133 result.emplace_front(clickRecognizer_);
134 responseLinkResult.emplace_back(clickRecognizer_);
135 }
136 break;
137 }
138 }
139
InitClickRecognizer(const OffsetF & coordinateOffset,const GetEventTargetImpl & getEventTargetImpl,const RefPtr<FrameNode> & frameNode,const RefPtr<TargetComponent> & targetComponent,const RefPtr<ScrollableEvent> & event,bool clickJudge,const PointF & localPoint,SourceType source)140 void ScrollableActuator::InitClickRecognizer(const OffsetF& coordinateOffset,
141 const GetEventTargetImpl& getEventTargetImpl, const RefPtr<FrameNode>& frameNode,
142 const RefPtr<TargetComponent>& targetComponent, const RefPtr<ScrollableEvent>& event, bool clickJudge,
143 const PointF& localPoint, SourceType source)
144 {
145 if (!clickRecognizer_) {
146 clickRecognizer_ = MakeRefPtr<ClickRecognizer>();
147 }
148 bool isHitTestBlock = event->IsHitTestBlock(localPoint, source);
149 clickRecognizer_->SetCoordinateOffset(Offset(coordinateOffset.GetX(), coordinateOffset.GetY()));
150 clickRecognizer_->SetGetEventTargetImpl(getEventTargetImpl);
151 clickRecognizer_->SetNodeId(frameNode->GetId());
152 clickRecognizer_->AttachFrameNode(frameNode);
153 clickRecognizer_->SetTargetComponent(targetComponent);
154 clickRecognizer_->SetIsSystemGesture(true);
155 clickRecognizer_->SetRecognizerType(GestureTypeName::TAP_GESTURE);
156 clickRecognizer_->SetSysGestureJudge([isHitTestBlock, clickJudge](const RefPtr<GestureInfo>& gestureInfo,
157 const std::shared_ptr<BaseGestureEvent>&) -> GestureJudgeResult {
158 TAG_LOGI(
159 AceLogTag::ACE_SCROLLABLE, "Scrollable GestureJudge:%{public}d, %{public}d", isHitTestBlock, clickJudge);
160 return isHitTestBlock || clickJudge ? GestureJudgeResult::CONTINUE : GestureJudgeResult::REJECT;
161 });
162 clickRecognizer_->SetOnClick([weak = WeakClaim(RawPtr(frameNode))](const ClickInfo&) {
163 auto frameNode = weak.Upgrade();
164 CHECK_NULL_VOID(frameNode);
165 auto pattern = frameNode->GetPattern<ListPattern>();
166 CHECK_NULL_VOID(pattern);
167 auto item = pattern->GetSwiperItem().Upgrade();
168 CHECK_NULL_VOID(item);
169 item->ResetSwipeStatus();
170 });
171 }
172
173 namespace {
GetOverrideRecognizer(const RefPtr<FrameNode> & frameNode)174 RefPtr<NGGestureRecognizer> GetOverrideRecognizer(const RefPtr<FrameNode>& frameNode)
175 {
176 auto scroll = frameNode->GetPattern<ScrollPattern>();
177 CHECK_NULL_RETURN(scroll, nullptr);
178 return scroll->GetOverrideRecognizer();
179 }
180 } // namespace
181
CollectScrollableTouchTarget(const OffsetF & coordinateOffset,const GetEventTargetImpl & getEventTargetImpl,TouchTestResult & result,const RefPtr<FrameNode> & frameNode,const RefPtr<TargetComponent> & targetComponent,ResponseLinkResult & responseLinkResult,int32_t touchId)182 void ScrollableEvent::CollectScrollableTouchTarget(const OffsetF& coordinateOffset,
183 const GetEventTargetImpl& getEventTargetImpl, TouchTestResult& result, const RefPtr<FrameNode>& frameNode,
184 const RefPtr<TargetComponent>& targetComponent, ResponseLinkResult& responseLinkResult, int32_t touchId)
185 {
186 if (auto superRecognizer = GetOverrideRecognizer(frameNode)) {
187 result.emplace_back(superRecognizer);
188 auto recognizerGroup = AceType::DynamicCast<RecognizerGroup>(superRecognizer);
189 if (recognizerGroup) {
190 auto offset = Offset(coordinateOffset.GetX(), coordinateOffset.GetY());
191 recognizerGroup->SetRecognizerInfoRecursively(offset, frameNode, targetComponent, getEventTargetImpl);
192 recognizerGroup->CollectResponseLinkRecognizersRecursively(responseLinkResult);
193 recognizerGroup->BeginReferee(touchId, true);
194 } else {
195 responseLinkResult.emplace_back(superRecognizer);
196 }
197 superRecognizer->SetNodeId(frameNode->GetId());
198 superRecognizer->AttachFrameNode(frameNode);
199 superRecognizer->SetTargetComponent(targetComponent);
200 superRecognizer->SetIsSystemGesture(true);
201 superRecognizer->SetCoordinateOffset(Offset(coordinateOffset.GetX(), coordinateOffset.GetY()));
202 superRecognizer->SetGetEventTargetImpl(getEventTargetImpl);
203 return;
204 }
205 if (scrollable_) {
206 scrollable_->SetGetEventTargetImpl(getEventTargetImpl);
207 scrollable_->SetCoordinateOffset(Offset(coordinateOffset.GetX(), coordinateOffset.GetY()));
208 scrollable_->OnCollectTouchTarget(result, frameNode, targetComponent, responseLinkResult);
209 }
210 }
211 } // namespace OHOS::Ace::NG
212