1 /*
2  * Copyright (c) 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 #include "bridge/cj_frontend/interfaces/cj_ffi/cj_scroll_ffi.h"
17 
18 #include "cj_lambda.h"
19 #include "bridge/cj_frontend/interfaces/cj_ffi/utils.h"
20 #include "bridge/common/utils/utils.h"
21 #include "core/common/container.h"
22 #include "core/components/scroll/scroll_component.h"
23 #include "core/components/scroll/scroll_controller_base.h"
24 #include "core/components_ng/pattern/scroll/scroll_model_ng.h"
25 
26 using namespace OHOS::Ace;
27 using namespace OHOS::FFI;
28 using namespace OHOS::Ace::Framework;
29 
30 namespace {
31 const std::vector<Axis> AXIS = { Axis::VERTICAL, Axis::HORIZONTAL, Axis::FREE, Axis::NONE };
32 const std::vector<DisplayMode> DISPLAY_MODE = { DisplayMode::OFF, DisplayMode::AUTO, DisplayMode::ON };
33 const std::vector<ScrollEdgeType> SCROLL_EDGE_TYPES = { ScrollEdgeType::SCROLL_TOP, ScrollEdgeType::SCROLL_NONE,
34     ScrollEdgeType::SCROLL_BOTTOM, ScrollEdgeType::SCROLL_NONE, ScrollEdgeType::SCROLL_TOP, ScrollEdgeType::SCROLL_NONE,
35     ScrollEdgeType::SCROLL_BOTTOM };
36 const std::vector<ScrollAlign> SCROLL_ALIGN_LIST = { ScrollAlign::START, ScrollAlign::CENTER, ScrollAlign::END,
37     ScrollAlign::AUTO, ScrollAlign::NONE };
38 } // namespace
39 
40 namespace OHOS::Ace::Framework {
41 
NativeNGScroller()42 NativeNGScroller::NativeNGScroller() : FFIData()
43 {
44     LOGI("Scroller constructed: %{public}" PRId64, GetID());
45 }
46 
ScrollTo(const Dimension & xOffset,const Dimension & yOffset,double duration,const RefPtr<Curve> & curve)47 void NativeNGScroller::ScrollTo(
48     const Dimension& xOffset, const Dimension& yOffset, double duration, const RefPtr<Curve>& curve)
49 {
50     if (!controller_) {
51         LOGE("controller_ is nullptr");
52         return;
53     }
54     auto direction = controller_->GetScrollDirection();
55     auto position = direction == Axis::VERTICAL ? yOffset : xOffset;
56     bool smooth = false;
57     controller_->AnimateTo(position, duration, curve, smooth);
58 }
59 
ScrollBy(const Dimension & xOffset,const Dimension & yOffset)60 void NativeNGScroller::ScrollBy(const Dimension& xOffset, const Dimension& yOffset)
61 {
62     if (!controller_) {
63         LOGE("Scroll controller is null: invalid scrollerID");
64         return;
65     }
66 
67     auto deltaX = xOffset.Value();
68     auto deltaY = yOffset.Value();
69     auto container = Container::Current();
70     if (container) {
71         auto context = container->GetPipelineContext();
72         if (context) {
73             if (xOffset.Unit() == DimensionUnit::PERCENT) {
74                 deltaX = 0.0;
75             } else {
76                 deltaX = context->NormalizeToPx(xOffset);
77             }
78             if (yOffset.Unit() == DimensionUnit::PERCENT) {
79                 deltaY = 0.0;
80             } else {
81                 deltaY = context->NormalizeToPx(yOffset);
82             }
83         }
84     }
85     controller_->ScrollBy(deltaX, deltaY, false);
86 }
87 
ScrollEdge(ScrollEdgeType edge)88 void NativeNGScroller::ScrollEdge(ScrollEdgeType edge)
89 {
90     if (!controller_) {
91         LOGE("controller_ is nullptr");
92         return;
93     }
94     controller_->ScrollToEdge(edge, true);
95 }
96 
ScrollPage(bool next)97 void NativeNGScroller::ScrollPage(bool next)
98 {
99     if (!controller_) {
100         LOGE("controller_ is nullptr");
101         return;
102     }
103     controller_->ScrollPage(!next, true);
104 }
105 
ScrollToIndex(int32_t index,bool smooth,int32_t align)106 void NativeNGScroller::ScrollToIndex(int32_t index, bool smooth, int32_t align)
107 {
108     if (!controller_) {
109         LOGE("controller_ is nullptr");
110         return;
111     }
112     controller_->ScrollToIndex(index, smooth, SCROLL_ALIGN_LIST[align]);
113 }
114 
CurrentOffset()115 Offset NativeNGScroller::CurrentOffset()
116 {
117     if (!controller_) {
118         LOGE("controller_ is nullptr");
119         return Offset(0.0, 0.0);
120     }
121     return controller_->GetCurrentOffset();
122 }
123 
124 } // namespace OHOS::Ace::Framework
125 
126 extern "C" {
FfiOHOSAceFrameworkScrollCreate(int64_t scrollerID)127 void FfiOHOSAceFrameworkScrollCreate(int64_t scrollerID)
128 {
129     if (scrollerID == -1) {
130         ScrollModel::GetInstance()->Create();
131         std::pair<bool, Color> barColor;
132         barColor.first = false;
133         std::pair<bool, Dimension> barWidth;
134         barWidth.first = false;
135         auto pipelineContext = PipelineContext::GetCurrentContext();
136         auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
137         ScrollModel::GetInstance()->InitScrollBar(theme, barColor, barWidth, EdgeEffect::NONE);
138         return;
139     }
140 
141     auto scroller = FFIData::GetData<NativeNGScroller>(scrollerID);
142     if (scroller == nullptr) {
143         LOGE("invalid scrollerID");
144         return;
145     }
146     ScrollModel::GetInstance()->Create();
147     auto positionController = ScrollModel::GetInstance()->GetOrCreateController();
148     scroller->SetController(positionController);
149     auto proxy = scroller->GetScrollBarProxy();
150     if (!proxy) {
151         proxy = ScrollModel::GetInstance()->CreateScrollBarProxy();
152         scroller->SetScrollBarProxy(proxy);
153     }
154     ScrollModel::GetInstance()->SetScrollBarProxy(proxy);
155     std::pair<bool, Color> barColor;
156     barColor.first = false;
157     std::pair<bool, Dimension> barWidth;
158     barWidth.first = false;
159     auto pipelineContext = PipelineContext::GetCurrentContext();
160     auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
161     ScrollModel::GetInstance()->InitScrollBar(theme, barColor, barWidth, EdgeEffect::NONE);
162 }
163 
FfiOHOSAceFrameworkScrollScrollable(int32_t scrollDirection)164 void FfiOHOSAceFrameworkScrollScrollable(int32_t scrollDirection)
165 {
166     if (!Utils::CheckParamsValid(scrollDirection, AXIS.size())) {
167         LOGE("invalid value for scrollDirection");
168         return;
169     }
170 
171     ScrollModel::GetInstance()->SetAxis(AXIS[scrollDirection]);
172 }
173 
FfiOHOSAceFrameworkScrollScrollBar(int32_t barState)174 void FfiOHOSAceFrameworkScrollScrollBar(int32_t barState)
175 {
176     if (!Utils::CheckParamsValid(barState, DISPLAY_MODE.size())) {
177         LOGE("invalid value for DisplayMode");
178         return;
179     }
180     ScrollModel::GetInstance()->SetDisplayMode(barState);
181 }
182 
FfiOHOSAceFrameworkScrollScrollBarColor(uint32_t color)183 void FfiOHOSAceFrameworkScrollScrollBarColor(uint32_t color)
184 {
185     ScrollModel::GetInstance()->SetScrollBarColor(Color(color));
186 }
187 
188 
FfiOHOSAceFrameworkScrollSetOnScrollFrameBegin(double (* callback)(double offset,int32_t state))189 void FfiOHOSAceFrameworkScrollSetOnScrollFrameBegin(double (*callback)(double offset, int32_t state))
190 {
191     auto lambda = [callback = CJLambda::Create(callback)](const Dimension& offset, const ScrollState& state)
192      -> ScrollFrameResult {
193         auto res = callback(offset.Value(), static_cast<int32_t>(state));
194         ScrollFrameResult scrollRes { .offset = Dimension { res, DimensionUnit::VP } };
195         return scrollRes;
196     };
197     ScrollModel::GetInstance()->SetOnScrollFrameBegin(lambda);
198 }
199 
FfiOHOSAceFrameworkScrollScrollBarWidth(double width,int32_t unit)200 void FfiOHOSAceFrameworkScrollScrollBarWidth(double width, int32_t unit)
201 {
202     Dimension value(width, static_cast<DimensionUnit>(unit));
203     ScrollModel::GetInstance()->SetScrollBarWidth(value);
204 }
205 
FfiOHOSAceFrameworkScrollNestedScroll(int32_t scrollForward,int32_t scrollBackward)206 void FfiOHOSAceFrameworkScrollNestedScroll(int32_t scrollForward, int32_t scrollBackward)
207 {
208     NestedScrollOptions localNestedScrollOptions = {.forward = NestedScrollMode(scrollForward),
209         .backward = NestedScrollMode(scrollBackward)};
210     ScrollModel::GetInstance()->SetNestedScroll(localNestedScrollOptions);
211 }
212 
FfiOHOSAceFrameworkScrollOnScroll(void (* callback)(CJOffset scrollInfo))213 void FfiOHOSAceFrameworkScrollOnScroll(void (*callback)(CJOffset scrollInfo))
214 {
215     ScrollModel::GetInstance()->SetOnScroll(
216         [ffiOnScroll = CJLambda::Create(callback)](const Dimension& xOffset, const Dimension& yOffset) {
217             CJOffset ffiScrollInfo;
218             ffiScrollInfo.xOffset = xOffset.Value();
219             ffiScrollInfo.yOffset = yOffset.Value();
220             ffiOnScroll(ffiScrollInfo);
221         });
222 }
223 
FfiOHOSAceFrameworkScrollOnScrollEdge(void (* callback)(int32_t edge))224 void FfiOHOSAceFrameworkScrollOnScrollEdge(void (*callback)(int32_t edge))
225 {
226     ScrollModel::GetInstance()->SetOnScrollEdge(
227         [ffiOnScrollEdge = CJLambda::Create(callback)](
228             const NG::ScrollEdge& side) { ffiOnScrollEdge(static_cast<int32_t>(side)); });
229 }
230 
FfiOHOSAceFrameworkScrollOnScrollEnd(void (* callback)())231 void FfiOHOSAceFrameworkScrollOnScrollEnd(void (*callback)())
232 {
233     ScrollModel::GetInstance()->SetOnScrollEnd(CJLambda::Create(callback));
234 }
235 
FfiOHOSAceFrameworkScrollerCtor()236 int64_t FfiOHOSAceFrameworkScrollerCtor()
237 {
238     auto nativeScroller = FFIData::Create<NativeNGScroller>();
239     if (nativeScroller == nullptr) {
240         return FFI_ERROR_CODE;
241     }
242     return nativeScroller->GetID();
243 }
244 
FfiOHOSAceFrameworkScrollerScrollTo(int64_t selfID,double xOffset,int32_t xUnit,double yOffset,int32_t yUnit)245 void FfiOHOSAceFrameworkScrollerScrollTo(int64_t selfID, double xOffset, int32_t xUnit, double yOffset, int32_t yUnit)
246 {
247     Dimension xValue(xOffset, static_cast<DimensionUnit>(xUnit));
248     Dimension yValue(yOffset, static_cast<DimensionUnit>(yUnit));
249     auto self_ = FFIData::GetData<NativeNGScroller>(selfID);
250     if (self_ != nullptr) {
251         self_->ScrollTo(xValue, yValue, 0.0, Curves::EASE);
252     } else {
253         LOGE("invalid scrollerID");
254     }
255 }
256 
FfiOHOSAceFrameworkScrollerScrollToByCurve(int64_t selfID,double xOffset,int32_t xUnit,double yOffset,int32_t yUnit,double duration,const char * curve)257 void FfiOHOSAceFrameworkScrollerScrollToByCurve(
258     int64_t selfID, double xOffset, int32_t xUnit, double yOffset, int32_t yUnit, double duration, const char* curve)
259 {
260     Dimension xValue(xOffset, static_cast<DimensionUnit>(xUnit));
261     Dimension yValue(yOffset, static_cast<DimensionUnit>(yUnit));
262     auto self_ = FFIData::GetData<NativeNGScroller>(selfID);
263     if (self_ != nullptr) {
264         self_->ScrollTo(xValue, yValue, duration, CreateCurve(curve, false));
265     } else {
266         LOGE("invalid scrollerID");
267     }
268 }
269 
FfiOHOSAceFrameworkScrollerScrollBy(int64_t selfID,double xOffset,int32_t xUnit,double yOffset,int32_t yUnit)270 void FfiOHOSAceFrameworkScrollerScrollBy(
271     int64_t selfID, double xOffset, int32_t xUnit, double yOffset, int32_t yUnit)
272 {
273     Dimension xValue(xOffset, static_cast<DimensionUnit>(xUnit));
274     Dimension yValue(yOffset, static_cast<DimensionUnit>(yUnit));
275     auto self_ = FFIData::GetData<NativeNGScroller>(selfID);
276     if (self_ != nullptr) {
277         self_->ScrollBy(xValue, yValue);
278     } else {
279         LOGE("Scroll controller is null: invalid scrollerID");
280     }
281 }
FfiOHOSAceFrameworkScrollerScrollToIndex(int64_t selfID,int32_t index,bool smooth,int32_t align)282 void FfiOHOSAceFrameworkScrollerScrollToIndex(int64_t selfID, int32_t index, bool smooth, int32_t align)
283 {
284     auto self_ = FFIData::GetData<NativeNGScroller>(selfID);
285     if (self_ != nullptr) {
286         self_->ScrollToIndex(index, smooth, align);
287     } else {
288         LOGE("invalid scrollerID");
289     }
290 }
291 
FfiOHOSAceFrameworkScrollerScrollEdge(int64_t selfID,int32_t edge)292 void FfiOHOSAceFrameworkScrollerScrollEdge(int64_t selfID, int32_t edge)
293 {
294     if (!Utils::CheckParamsValid(edge, SCROLL_EDGE_TYPES.size())) {
295         LOGE("invalid value for DisplayMode");
296         return;
297     }
298     auto self_ = FFIData::GetData<NativeNGScroller>(selfID);
299     if (self_ != nullptr) {
300         self_->ScrollEdge(SCROLL_EDGE_TYPES[edge]);
301     } else {
302         LOGE("invalid scrollerID");
303     }
304 }
305 
FfiOHOSAceFrameworkScrollerScrollPage(int64_t selfID,bool next)306 void FfiOHOSAceFrameworkScrollerScrollPage(int64_t selfID, bool next)
307 {
308     auto self_ = FFIData::GetData<NativeNGScroller>(selfID);
309     if (self_ != nullptr) {
310         self_->ScrollPage(next);
311     } else {
312         LOGE("invalid scrollerID");
313     }
314 }
315 
FfiOHOSAceFrameworkScrollerCurrentOffset(int64_t selfID)316 CJOffset FfiOHOSAceFrameworkScrollerCurrentOffset(int64_t selfID)
317 {
318     CJOffset cjOffset = { 0.0, 0.0 };
319     auto self_ = FFIData::GetData<NativeNGScroller>(selfID);
320     if (self_ != nullptr) {
321         auto offset = self_->CurrentOffset();
322         cjOffset.xOffset = offset.GetX();
323         cjOffset.yOffset = offset.GetY();
324     } else {
325         LOGE("invalid scrollerID");
326     }
327     return cjOffset;
328 }
329 }
330