• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "bridge/declarative_frontend/jsview/js_scroll.h"
17 
18 #include "base/utils/utils.h"
19 #include "bridge/declarative_frontend/jsview/js_scroller.h"
20 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
21 #include "bridge/declarative_frontend/jsview/models/scroll_model_impl.h"
22 #include "core/components/common/layout/constants.h"
23 #include "core/components/scroll/scrollable.h"
24 #include "core/components_ng/pattern/scroll/inner/scroll_bar.h"
25 #include "core/components_ng/pattern/scroll/scroll_model.h"
26 #include "core/components_ng/pattern/scroll/scroll_model_ng.h"
27 
28 namespace OHOS::Ace {
29 
30 std::unique_ptr<ScrollModel> ScrollModel::instance_ = nullptr;
31 
GetInstance()32 ScrollModel* ScrollModel::GetInstance()
33 {
34     if (!instance_) {
35 #ifdef NG_BUILD
36         instance_.reset(new NG::ScrollModelNG());
37 #else
38         if (Container::IsCurrentUseNewPipeline()) {
39             instance_.reset(new NG::ScrollModelNG());
40         } else {
41             instance_.reset(new Framework::ScrollModelImpl());
42         }
43 #endif
44     }
45     return instance_.get();
46 }
47 
48 } // namespace OHOS::Ace
49 
50 namespace OHOS::Ace::Framework {
51 namespace {
52 const std::vector<Axis> AXIS = { Axis::VERTICAL, Axis::HORIZONTAL, Axis::FREE, Axis::NONE };
53 } // namespace
54 
Create(const JSCallbackInfo & info)55 void JSScroll::Create(const JSCallbackInfo& info)
56 {
57     ScrollModel::GetInstance()->Create();
58     if (info.Length() > 0 && info[0]->IsObject()) {
59         JSScroller* jsScroller = JSRef<JSObject>::Cast(info[0])->Unwrap<JSScroller>();
60         if (jsScroller) {
61             auto positionController = ScrollModel::GetInstance()->GetOrCreateController();
62             jsScroller->SetController(positionController);
63             // Init scroll bar proxy.
64             auto proxy = jsScroller->GetScrollBarProxy();
65             if (!proxy) {
66                 proxy = ScrollModel::GetInstance()->CreateScrollBarProxy();
67                 jsScroller->SetScrollBarProxy(proxy);
68             }
69             ScrollModel::GetInstance()->SetScrollBarProxy(proxy);
70         }
71     }
72     // init scroll bar
73     std::pair<bool, Color> barColor;
74     barColor.first = false;
75     std::pair<bool, Dimension> barWidth;
76     barWidth.first = false;
77     ScrollModel::GetInstance()->InitScrollBar(GetTheme<ScrollBarTheme>(), barColor, barWidth, EdgeEffect::NONE);
78 }
79 
SetScrollable(int32_t value)80 void JSScroll::SetScrollable(int32_t value)
81 {
82     if (value < 0 || value >= static_cast<int32_t>(AXIS.size())) {
83         LOGE("value is not valid: %{public}d", value);
84         return;
85     }
86     ScrollModel::GetInstance()->SetAxis(AXIS[value]);
87 }
88 
OnScrollBeginCallback(const JSCallbackInfo & args)89 void JSScroll::OnScrollBeginCallback(const JSCallbackInfo& args)
90 {
91     if (args[0]->IsFunction()) {
92         auto onScrollBegin = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
93                                  const Dimension& dx, const Dimension& dy) -> ScrollInfo {
94             ScrollInfo scrollInfo { .dx = dx, .dy = dy };
95             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollInfo);
96             auto params = ConvertToJSValues(dx, dy);
97             auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
98             if (result.IsEmpty()) {
99                 LOGE("Error calling onScrollBegin, result is empty.");
100                 return scrollInfo;
101             }
102 
103             if (!result->IsObject()) {
104                 LOGE("Error calling onScrollBegin, result is not object.");
105                 return scrollInfo;
106             }
107 
108             auto resObj = JSRef<JSObject>::Cast(result);
109             auto dxRemainValue = resObj->GetProperty("dxRemain");
110             if (dxRemainValue->IsNumber()) {
111                 scrollInfo.dx = Dimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
112             }
113             auto dyRemainValue = resObj->GetProperty("dyRemain");
114             if (dyRemainValue->IsNumber()) {
115                 scrollInfo.dy = Dimension(dyRemainValue->ToNumber<float>(), DimensionUnit::VP);
116             }
117             return scrollInfo;
118         };
119         ScrollModel::GetInstance()->SetOnScrollBegin(std::move(onScrollBegin));
120     }
121     args.SetReturnValue(args.This());
122 }
123 
OnScrollFrameBeginCallback(const JSCallbackInfo & args)124 void JSScroll::OnScrollFrameBeginCallback(const JSCallbackInfo& args)
125 {
126     if (args[0]->IsFunction()) {
127         auto onScrollFrameBegin = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
128                                       const Dimension& offset, ScrollState state) -> ScrollFrameResult {
129             OHOS::Ace::ScrollFrameResult scrollRes { .offset = offset };
130             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollRes);
131             auto params = ConvertToJSValues(offset, state);
132             auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
133             if (result.IsEmpty()) {
134                 LOGE("Error calling onScrollBegin, result is empty.");
135                 return scrollRes;
136             }
137 
138             if (!result->IsObject()) {
139                 LOGE("Error calling onScrollBegin, result is not object.");
140                 return scrollRes;
141             }
142 
143             auto resObj = JSRef<JSObject>::Cast(result);
144             auto dxRemainValue = resObj->GetProperty("offsetRemain");
145             if (dxRemainValue->IsNumber()) {
146                 scrollRes.offset = Dimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
147             }
148             return scrollRes;
149         };
150         ScrollModel::GetInstance()->SetOnScrollFrameBegin(std::move(onScrollFrameBegin));
151     }
152     args.SetReturnValue(args.This());
153 }
154 
OnScrollCallback(const JSCallbackInfo & args)155 void JSScroll::OnScrollCallback(const JSCallbackInfo& args)
156 {
157     if (args[0]->IsFunction()) {
158         auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
159                             const Dimension& xOffset, const Dimension& yOffset) {
160             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
161             auto params = ConvertToJSValues(xOffset, yOffset);
162             func->Call(JSRef<JSObject>(), params.size(), params.data());
163         };
164         ScrollModel::GetInstance()->SetOnScroll(std::move(onScroll));
165     }
166     args.SetReturnValue(args.This());
167 }
168 
OnScrollEdgeCallback(const JSCallbackInfo & args)169 void JSScroll::OnScrollEdgeCallback(const JSCallbackInfo& args)
170 {
171     if (args[0]->IsFunction()) {
172         auto scrollEdge = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
173                               const NG::ScrollEdge& side) {
174             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
175             auto params = ConvertToJSValues(side);
176             func->Call(JSRef<JSObject>(), 1, params.data());
177         };
178         ScrollModel::GetInstance()->SetOnScrollEdge(std::move(scrollEdge));
179     }
180     args.SetReturnValue(args.This());
181 }
182 
OnScrollEndCallback(const JSCallbackInfo & args)183 void JSScroll::OnScrollEndCallback(const JSCallbackInfo& args)
184 {
185     if (args[0]->IsFunction()) {
186         auto scrollEnd = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
187             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
188             func->Call(JSRef<JSObject>(), 0, nullptr);
189         };
190         ScrollModel::GetInstance()->SetOnScrollEnd(std::move(scrollEnd));
191     }
192     args.SetReturnValue(args.This());
193 }
194 
OnScrollStartCallback(const JSCallbackInfo & args)195 void JSScroll::OnScrollStartCallback(const JSCallbackInfo& args)
196 {
197     if (args[0]->IsFunction()) {
198         auto scrollStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
199             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
200             func->Call(JSRef<JSObject>(), 0, nullptr);
201         };
202         ScrollModel::GetInstance()->SetOnScrollStart(std::move(scrollStart));
203     }
204     args.SetReturnValue(args.This());
205 }
206 
OnScrollStopCallback(const JSCallbackInfo & args)207 void JSScroll::OnScrollStopCallback(const JSCallbackInfo& args)
208 {
209     if (args[0]->IsFunction()) {
210         auto scrollStop = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
211             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
212             func->Call(JSRef<JSObject>(), 0, nullptr);
213         };
214         ScrollModel::GetInstance()->SetOnScrollStop(std::move(scrollStop));
215     }
216     args.SetReturnValue(args.This());
217 }
218 
JSBind(BindingTarget globalObj)219 void JSScroll::JSBind(BindingTarget globalObj)
220 {
221     JSClass<JSScroll>::Declare("Scroll");
222     MethodOptions opt = MethodOptions::NONE;
223     JSClass<JSScroll>::StaticMethod("create", &JSScroll::Create, opt);
224     JSClass<JSScroll>::StaticMethod("scrollable", &JSScroll::SetScrollable, opt);
225     JSClass<JSScroll>::StaticMethod("onScrollBegin", &JSScroll::OnScrollBeginCallback, opt);
226     JSClass<JSScroll>::StaticMethod("onScrollFrameBegin", &JSScroll::OnScrollFrameBeginCallback, opt);
227     JSClass<JSScroll>::StaticMethod("onScroll", &JSScroll::OnScrollCallback, opt);
228     JSClass<JSScroll>::StaticMethod("onScrollEdge", &JSScroll::OnScrollEdgeCallback, opt);
229     JSClass<JSScroll>::StaticMethod("onScrollEnd", &JSScroll::OnScrollEndCallback, opt);
230     JSClass<JSScroll>::StaticMethod("onScrollStart", &JSScroll::OnScrollStartCallback, opt);
231     JSClass<JSScroll>::StaticMethod("onScrollStop", &JSScroll::OnScrollStopCallback, opt);
232     JSClass<JSScroll>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
233     JSClass<JSScroll>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
234     JSClass<JSScroll>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
235     JSClass<JSScroll>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
236     JSClass<JSScroll>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
237     JSClass<JSScroll>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
238     JSClass<JSScroll>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
239     JSClass<JSScroll>::StaticMethod("edgeEffect", &JSScroll::SetEdgeEffect, opt);
240     JSClass<JSScroll>::StaticMethod("scrollBar", &JSScroll::SetScrollBar, opt);
241     JSClass<JSScroll>::StaticMethod("scrollBarColor", &JSScroll::SetScrollBarColor, opt);
242     JSClass<JSScroll>::StaticMethod("scrollBarWidth", &JSScroll::SetScrollBarWidth, opt);
243     JSClass<JSScroll>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
244     JSClass<JSScroll>::StaticMethod("width", &JSScroll::JsWidth);
245     JSClass<JSScroll>::StaticMethod("height", &JSScroll::JsHeight);
246     JSClass<JSScroll>::Inherit<JSContainerBase>();
247     JSClass<JSScroll>::Inherit<JSViewAbstract>();
248     JSClass<JSScroll>::Bind<>(globalObj);
249 }
250 
SetScrollBar(const JSCallbackInfo & args)251 void JSScroll::SetScrollBar(const JSCallbackInfo& args)
252 {
253     if (args.Length() < 1) {
254         LOGE("args is invalid");
255         return;
256     }
257     int32_t displayMode;
258     if (args[0]->IsNull() || args[0]->IsUndefined() || !ParseJsInt32(args[0], displayMode)) {
259         displayMode = static_cast<int32_t>(NG::DisplayMode::AUTO);
260     }
261     ScrollModel::GetInstance()->SetDisplayMode(displayMode);
262 }
263 
SetScrollBarWidth(const JSCallbackInfo & args)264 void JSScroll::SetScrollBarWidth(const JSCallbackInfo& args)
265 {
266     auto pipelineContext = PipelineContext::GetCurrentContext();
267     CHECK_NULL_VOID_NOLOG(pipelineContext);
268     auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
269     CHECK_NULL_VOID_NOLOG(theme);
270     Dimension scrollBarWidth;
271     if (args.Length() < 1) {
272         LOGE("args is invalid");
273         return;
274     }
275     if (!ParseJsDimensionVp(args[0], scrollBarWidth) || args[0]->IsNull() || args[0]->IsUndefined() ||
276         (args[0]->IsString() && args[0]->ToString().empty()) || LessNotEqual(scrollBarWidth.Value(), 0.0)) {
277         scrollBarWidth = theme->GetNormalWidth();
278     }
279     ScrollModel::GetInstance()->SetScrollBarWidth(scrollBarWidth);
280 }
281 
SetScrollBarColor(const std::string & scrollBarColor)282 void JSScroll::SetScrollBarColor(const std::string& scrollBarColor)
283 {
284     if (scrollBarColor.empty()) {
285         return;
286     }
287     ScrollModel::GetInstance()->SetScrollBarColor(Color::FromString(scrollBarColor));
288 }
289 
SetEdgeEffect(int edgeEffect)290 void JSScroll::SetEdgeEffect(int edgeEffect)
291 {
292     ScrollModel::GetInstance()->SetEdgeEffect(static_cast<EdgeEffect>(edgeEffect));
293 }
294 
JsWidth(const JSCallbackInfo & info)295 void JSScroll::JsWidth(const JSCallbackInfo& info)
296 {
297     JSViewAbstract::JsWidth(info);
298     ScrollModel::GetInstance()->SetHasWidth(true);
299 }
300 
JsHeight(const JSCallbackInfo & info)301 void JSScroll::JsHeight(const JSCallbackInfo& info)
302 {
303     JSViewAbstract::JsHeight(info);
304     ScrollModel::GetInstance()->SetHasHeight(true);
305 }
306 
307 } // namespace OHOS::Ace::Framework
308