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