1 /*
2  * Copyright (c) 2021-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_SCROLL_POSITION_CONTROLLER_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_SCROLL_SCROLL_POSITION_CONTROLLER_H
18 
19 #include <functional>
20 
21 #include "core/animation/curve.h"
22 #include "core/components/scroll/scroll_controller.h"
23 #include "core/components/scroll/scrollable.h"
24 #include "core/pipeline/base/render_node.h"
25 
26 namespace OHOS::Ace {
27 
28 using OnScrollFunc = std::function<void(const std::string&)>;
29 
30 class ScrollEventInfo : public BaseEventInfo, public EventToJSONStringAdapter {
31     DECLARE_RELATIONSHIP_OF_CLASSES(ScrollEventInfo, BaseEventInfo, EventToJSONStringAdapter);
32 public:
33     ScrollEventInfo(ScrollEvent type, double scrollX, double scrollY, int32_t scrollState);
34 
35     ~ScrollEventInfo() = default;
36 
37     std::string ToJSONString() const override;
38 
GetType()39     ScrollEvent GetType() const
40     {
41         return type_;
42     }
43 
GetScrollX()44     double GetScrollX() const
45     {
46         return scrollX_;
47     }
48 
GetScrollY()49     double GetScrollY() const
50     {
51         return scrollY_;
52     }
53 
GetScrollState()54     int32_t GetScrollState() const
55     {
56         return scrollState_;
57     }
58 
SetScrollType(ScrollEvent type)59     void SetScrollType(ScrollEvent type)
60     {
61         type_ = type;
62     }
63 
64 private:
65     ScrollEvent type_ = ScrollEvent::SCROLL_TOP;
66     double scrollX_ = 0.0;
67     double scrollY_ = 0.0;
68     int32_t scrollState_ = -1;
69 };
70 
71 using ScrollEventFunc = std::function<void(std::shared_ptr<ScrollEventInfo>&)>;
72 class ACE_EXPORT ScrollPositionController : public ScrollController {
73     DECLARE_ACE_TYPE(ScrollPositionController, ScrollController);
74 
75 public:
76     ScrollPositionController() = default;
77     ~ScrollPositionController() override = default;
78 
SetInitialIndex(int32_t index)79     void SetInitialIndex(int32_t index)
80     {
81         if (index == 0) {
82             flags_ = POSITION_TOP;
83         } else {
84             flags_ = POSITION_MIDDLE;
85         }
86         initialIndex_ = index;
87     }
88 
GetInitialIndex()89     int32_t GetInitialIndex() const
90     {
91         return initialIndex_;
92     }
93 
SetInitialOffset(double initialOffset)94     void SetInitialOffset(double initialOffset)
95     {
96         if (NearZero(initialOffset)) {
97             flags_ = POSITION_TOP;
98         } else {
99             flags_ = POSITION_MIDDLE;
100         }
101         initialOffset_ = initialOffset;
102     }
103 
GetInitialOffset()104     double GetInitialOffset() const
105     {
106         return initialOffset_;
107     }
108 
109     double GetCurrentPosition() const;
110     Axis GetScrollDirection() const override;
111 
112     void ScrollToIndex(int32_t index, bool smooth, ScrollAlign align, std::optional<float> extraOffset) override;
113     void JumpTo(double position);
114     bool AnimateTo(const Dimension& position, float duration, const RefPtr<Curve>& curve, bool smooth,
115         bool canOverScroll = false) override;
116     bool AnimateTo(double position, float duration, const RefPtr<Curve>& curve, bool limitDuration = true,
117         const std::function<void()>& onFinish = nullptr);
118     bool AnimateToTarget(const ComposeId& targetId, float duration, const RefPtr<Curve>& curve,
119         bool limitDuration = true, const std::function<void()>& onFinish = nullptr);
120     void ScrollBy(double pixelX, double pixelY, bool smooth) override;
121     void ScrollArrow(double scrollDistance, bool reverse, bool smooth);
122     void ScrollToEdge(ScrollEdgeType scrollEdgeType, bool smooth) override;
123     void ScrollPage(bool reverse, bool smooth) override;
124     Offset GetCurrentOffset() const override;
125 
126 
SetScrollEvent(ScrollEvent event,const ScrollEventFunc & scrollEvent)127     void SetScrollEvent(
128         ScrollEvent event, const ScrollEventFunc& scrollEvent)
129     {
130         switch (event) {
131             case ScrollEvent::SCROLL_TOP:
132                 scrollTop_ = scrollEvent;
133                 break;
134             case ScrollEvent::SCROLL_BOTTOM:
135                 scrollBottom_ = scrollEvent;
136                 break;
137             case ScrollEvent::SCROLL_END:
138                 scrollEnd_ = scrollEvent;
139                 break;
140             case ScrollEvent::SCROLL_TOUCHUP:
141                 scrollTouchUp_ = scrollEvent;
142                 break;
143             case ScrollEvent::SCROLL_POSITION:
144                 scrollPosition_ = scrollEvent;
145                 break;
146             case ScrollEvent::SCROLL_EDGE:
147                 scrollEdge_ = scrollEvent;
148                 break;
149             default:
150                 LOGW("unknown scroll event");
151                 break;
152         }
153     }
154 
HandleScrollEvent(std::shared_ptr<ScrollEventInfo> info)155     void HandleScrollEvent(std::shared_ptr<ScrollEventInfo> info) const
156     {
157         if (!info) {
158             LOGE("scroll event info is null");
159             return;
160         }
161         auto eventType = info->GetType();
162         switch (eventType) {
163             case ScrollEvent::SCROLL_TOP:
164                 if (scrollTop_) {
165                     scrollTop_(info);
166                 }
167                 if (scrollEdge_) {
168                     scrollEdge_(info);
169                 }
170                 break;
171             case ScrollEvent::SCROLL_BOTTOM:
172                 if (scrollBottom_) {
173                     scrollBottom_(info);
174                 }
175                 if (scrollEdge_) {
176                     scrollEdge_(info);
177                 }
178                 break;
179             case ScrollEvent::SCROLL_END:
180                 if (scrollEnd_) {
181                     scrollEnd_(info);
182                 }
183                 break;
184             case ScrollEvent::SCROLL_TOUCHUP:
185                 if (scrollTouchUp_) {
186                     scrollTouchUp_(info);
187                 }
188                 break;
189             case ScrollEvent::SCROLL_POSITION:
190                 if (scrollPosition_) {
191                     scrollPosition_(info);
192                 }
193                 break;
194             default:
195                 LOGW("handle unknown scroll event");
196                 break;
197         }
198     }
199 
SetTop()200     void SetTop()
201     {
202         flags_ |= POSITION_TOP;
203     }
204 
SetBottom()205     void SetBottom()
206     {
207         flags_ |= POSITION_BOTTOM;
208     }
209 
SetMiddle()210     void SetMiddle()
211     {
212         flags_ = POSITION_MIDDLE;
213     }
214 
IsTop()215     bool IsTop() const
216     {
217         return (flags_ & POSITION_TOP);
218     }
219 
IsBottom()220     bool IsBottom() const
221     {
222         return (flags_ & POSITION_BOTTOM);
223     }
224 
SetNonScrollable()225     void SetNonScrollable()
226     {
227         flags_ = (POSITION_TOP | POSITION_BOTTOM);
228     }
229 
230     using OnFirstChanged = std::function<void(int32_t)>;
AddFirstChangedCallback(const OnFirstChanged & callback)231     void AddFirstChangedCallback(const OnFirstChanged& callback)
232     {
233         onChanged_ = callback;
234     }
235 
236     using IndexerRotation = std::function<bool()>;
AddIndexerStateQueryCallback(const IndexerRotation & callback)237     void AddIndexerStateQueryCallback(const IndexerRotation& callback)
238     {
239         indexerRotationCallback_ = callback;
240     }
241 
IsScrollNeedRotation()242     bool IsScrollNeedRotation()
243     {
244         return  !(indexerRotationCallback_ && indexerRotationCallback_());
245     }
246 
SetFirstItemIndex(int32_t firstIndex)247     void SetFirstItemIndex(int32_t firstIndex)
248     {
249         firstIndex_ = firstIndex;
250         if (onChanged_) {
251             onChanged_(firstIndex_);
252         }
253     }
254 
GetFirstItemIndex()255     int32_t GetFirstItemIndex() const
256     {
257         return firstIndex_;
258     }
259 
260 private:
261     int32_t initialIndex_ = 0;
262     double initialOffset_ = 0.0;
263     OnFirstChanged onChanged_;
264     IndexerRotation indexerRotationCallback_;
265     int32_t firstIndex_ = 0;
266 
267     ScrollEventFunc scrollTop_;
268     ScrollEventFunc scrollBottom_;
269     ScrollEventFunc scrollTouchUp_;
270     ScrollEventFunc scrollEnd_;
271     ScrollEventFunc scrollPosition_;
272     ScrollEventFunc scrollEdge_;
273     uint32_t flags_ = POSITION_TOP;
274 };
275 
276 } // namespace OHOS::Ace
277 
278 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_SCROLL_SCROLL_POSITION_CONTROLLER_H
279