1 /*
2 * Copyright (c) 2021-2023 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 "frameworks/bridge/declarative_frontend/jsview/js_slider.h"
17
18 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
19 #include "bridge/declarative_frontend/jsview/models/slider_model_impl.h"
20 #include "core/components/slider/render_slider.h"
21 #include "core/components/slider/slider_element.h"
22 #include "core/components_ng/pattern/slider/slider_model_ng.h"
23 #include "frameworks/bridge/declarative_frontend/engine/functions/js_function.h"
24 #include "frameworks/bridge/declarative_frontend/jsview/js_shape_abstract.h"
25
26 namespace OHOS::Ace {
27 namespace {
28 constexpr int SLIDER_SHOW_TIPS_MAX_PARAMS = 2;
29 } // namespace
30
31 std::unique_ptr<SliderModel> SliderModel::instance_ = nullptr;
32 std::mutex SliderModel::mutex_;
33
GetInstance()34 SliderModel* SliderModel::GetInstance()
35 {
36 if (!instance_) {
37 std::lock_guard<std::mutex> lock(mutex_);
38 if (!instance_) {
39 #ifdef NG_BUILD
40 instance_.reset(new NG::SliderModelNG());
41 #else
42 if (Container::IsCurrentUseNewPipeline()) {
43 instance_.reset(new NG::SliderModelNG());
44 } else {
45 instance_.reset(new Framework::SliderModelImpl());
46 }
47 #endif
48 }
49 }
50 return instance_.get();
51 }
52
53 } // namespace OHOS::Ace
54
55 namespace OHOS::Ace::Framework {
56
JSBind(BindingTarget globalObj)57 void JSSlider::JSBind(BindingTarget globalObj)
58 {
59 JSClass<JSSlider>::Declare("Slider");
60 MethodOptions opt = MethodOptions::NONE;
61 JSClass<JSSlider>::StaticMethod("create", &JSSlider::Create, opt);
62 JSClass<JSSlider>::StaticMethod("blockColor", &JSSlider::SetBlockColor);
63 JSClass<JSSlider>::StaticMethod("trackColor", &JSSlider::SetTrackColor);
64 JSClass<JSSlider>::StaticMethod("trackThickness", &JSSlider::SetThickness);
65 JSClass<JSSlider>::StaticMethod("selectedColor", &JSSlider::SetSelectedColor);
66 JSClass<JSSlider>::StaticMethod("minLabel", &JSSlider::SetMinLabel);
67 JSClass<JSSlider>::StaticMethod("maxLabel", &JSSlider::SetMaxLabel);
68 JSClass<JSSlider>::StaticMethod("showSteps", &JSSlider::SetShowSteps);
69 JSClass<JSSlider>::StaticMethod("showTips", &JSSlider::SetShowTips);
70 JSClass<JSSlider>::StaticMethod("blockBorderColor", &JSSlider::SetBlockBorderColor);
71 JSClass<JSSlider>::StaticMethod("blockBorderWidth", &JSSlider::SetBlockBorderWidth);
72 JSClass<JSSlider>::StaticMethod("stepColor", &JSSlider::SetStepColor);
73 JSClass<JSSlider>::StaticMethod("trackBorderRadius", &JSSlider::SetTrackBorderRadius);
74 JSClass<JSSlider>::StaticMethod("blockSize", &JSSlider::SetBlockSize);
75 JSClass<JSSlider>::StaticMethod("blockStyle", &JSSlider::SetBlockStyle);
76 JSClass<JSSlider>::StaticMethod("stepSize", &JSSlider::SetStepSize);
77 JSClass<JSSlider>::StaticMethod("onChange", &JSSlider::OnChange);
78 JSClass<JSSlider>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
79 JSClass<JSSlider>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
80 JSClass<JSSlider>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
81 JSClass<JSSlider>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
82 JSClass<JSSlider>::InheritAndBind<JSViewAbstract>(globalObj);
83 }
84
GetStep(double step,double max,double min)85 double GetStep(double step, double max, double min)
86 {
87 if (LessOrEqual(step, 0.0) || step > max - min) {
88 step = 1;
89 }
90 return step;
91 }
92
GetValue(double value,double max,double min)93 double GetValue(double value, double max, double min)
94 {
95 if (value < min) {
96 value = min;
97 }
98
99 if (value > max) {
100 value = max;
101 }
102 return value;
103 }
104
ParseSliderValueObject(const JSCallbackInfo & info,const JSRef<JSVal> & changeEventVal)105 void ParseSliderValueObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
106 {
107 CHECK_NULL_VOID(changeEventVal->IsFunction());
108
109 JsEventCallback<void(float)> onChangeEvent(info.GetExecutionContext(), JSRef<JSFunc>::Cast(changeEventVal));
110 SliderModel::GetInstance()->SetOnChangeEvent(std::move(onChangeEvent));
111 }
112
Create(const JSCallbackInfo & info)113 void JSSlider::Create(const JSCallbackInfo& info)
114 {
115 static const double valueMin = -1000000.0f;
116 double value = valueMin; // value:Current progress value. The default value is min.
117 double min = 0; // min:Set the minimum value. The default value is 0.
118 double max = 100; // max:Set the maximum value. The default value is 100.
119 double step = 1; // step:Sets the sliding jump value of the slider. The default value is 1.
120 bool reverse = false;
121
122 if (!info[0]->IsObject()) {
123 SliderModel::GetInstance()->Create(
124 static_cast<float>(value), static_cast<float>(step), static_cast<float>(min), static_cast<float>(max));
125 return;
126 }
127
128 auto paramObject = JSRef<JSObject>::Cast(info[0]);
129 auto getValue = paramObject->GetProperty("value");
130 auto getMin = paramObject->GetProperty("min");
131 auto getMax = paramObject->GetProperty("max");
132 auto getStep = paramObject->GetProperty("step");
133 auto getStyle = paramObject->GetProperty("style");
134 auto direction = paramObject->GetProperty("direction");
135 auto isReverse = paramObject->GetProperty("reverse");
136 JSRef<JSVal> changeEventVal;
137
138 if (!getValue->IsNull() && getValue->IsNumber()) {
139 value = getValue->ToNumber<double>();
140 } else if (!getValue->IsNull() && getValue->IsObject()) {
141 JSRef<JSObject> valueObj = JSRef<JSObject>::Cast(getValue);
142 changeEventVal = valueObj->GetProperty("changeEvent");
143 auto valueProperty = valueObj->GetProperty("value");
144 value = valueProperty->ToNumber<double>();
145 }
146
147 if (!getMin->IsNull() && getMin->IsNumber()) {
148 min = getMin->ToNumber<double>();
149 }
150
151 if (!getMax->IsNull() && getMax->IsNumber()) {
152 max = getMax->ToNumber<double>();
153 }
154
155 if (!getStep->IsNull() && getStep->IsNumber()) {
156 step = getStep->ToNumber<double>();
157 }
158
159 if (!isReverse->IsNull() && isReverse->IsBoolean()) {
160 reverse = isReverse->ToBoolean();
161 }
162
163 if (GreatOrEqual(min, max)) {
164 min = 0;
165 max = 100;
166 }
167
168 step = GetStep(step, max, min);
169
170 if (!Container::IsCurrentUseNewPipeline()) {
171 value = GetValue(value, max, min);
172 }
173
174 auto sliderStyle = SliderStyle::OUTSET;
175 auto sliderMode = SliderModel::SliderMode::OUTSET;
176 if (!getStyle->IsNull() && getStyle->IsNumber()) {
177 sliderStyle = static_cast<SliderStyle>(getStyle->ToNumber<int32_t>());
178 }
179 if (sliderStyle == SliderStyle::INSET) {
180 sliderMode = SliderModel::SliderMode::INSET;
181 } else if (sliderStyle == SliderStyle::CAPSULE) {
182 sliderMode = SliderModel::SliderMode::CAPSULE;
183 } else {
184 sliderMode = SliderModel::SliderMode::OUTSET;
185 }
186
187 auto sliderDirection = Axis::HORIZONTAL;
188 if (!direction->IsNull() && direction->IsNumber()) {
189 sliderDirection = static_cast<Axis>(direction->ToNumber<int32_t>());
190 }
191 if (sliderDirection != Axis::VERTICAL) {
192 sliderDirection = Axis::HORIZONTAL;
193 }
194
195 SliderModel::GetInstance()->Create(
196 static_cast<float>(value), static_cast<float>(step), static_cast<float>(min), static_cast<float>(max));
197 SliderModel::GetInstance()->SetSliderMode(sliderMode);
198 SliderModel::GetInstance()->SetDirection(sliderDirection);
199 SliderModel::GetInstance()->SetReverse(reverse);
200 if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) {
201 ParseSliderValueObject(info, changeEventVal);
202 }
203 }
204
SetThickness(const JSCallbackInfo & info)205 void JSSlider::SetThickness(const JSCallbackInfo& info)
206 {
207 if (info.Length() < 1) {
208 return;
209 }
210 CalcDimension value;
211 if (!ParseJsDimensionVp(info[0], value)) {
212 value = CalcDimension(0.0);
213 }
214 SliderModel::GetInstance()->SetThickness(value);
215 }
216
SetBlockColor(const JSCallbackInfo & info)217 void JSSlider::SetBlockColor(const JSCallbackInfo& info)
218 {
219 if (info.Length() < 1) {
220 return;
221 }
222 Color colorVal;
223 if (!ParseJsColor(info[0], colorVal)) {
224 auto theme = GetTheme<SliderTheme>();
225 CHECK_NULL_VOID(theme);
226 colorVal = theme->GetBlockColor();
227 }
228 SliderModel::GetInstance()->SetBlockColor(colorVal);
229 }
230
SetTrackColor(const JSCallbackInfo & info)231 void JSSlider::SetTrackColor(const JSCallbackInfo& info)
232 {
233 if (info.Length() < 1) {
234 return;
235 }
236 Color colorVal;
237 if (!ParseJsColor(info[0], colorVal)) {
238 auto theme = GetTheme<SliderTheme>();
239 CHECK_NULL_VOID(theme);
240 colorVal = theme->GetTrackBgColor();
241 }
242 SliderModel::GetInstance()->SetTrackBackgroundColor(colorVal);
243 }
244
SetSelectedColor(const JSCallbackInfo & info)245 void JSSlider::SetSelectedColor(const JSCallbackInfo& info)
246 {
247 if (info.Length() < 1) {
248 return;
249 }
250 Color colorVal;
251 if (!ParseJsColor(info[0], colorVal)) {
252 auto theme = GetTheme<SliderTheme>();
253 CHECK_NULL_VOID(theme);
254 colorVal = theme->GetTrackSelectedColor();
255 }
256 SliderModel::GetInstance()->SetSelectColor(colorVal);
257 }
258
SetMinLabel(const JSCallbackInfo & info)259 void JSSlider::SetMinLabel(const JSCallbackInfo& info)
260 {
261 if (!info[0]->IsString()) {
262 return;
263 }
264 SliderModel::GetInstance()->SetMinLabel(info[0]->ToNumber<float>());
265 }
266
SetMaxLabel(const JSCallbackInfo & info)267 void JSSlider::SetMaxLabel(const JSCallbackInfo& info)
268 {
269 if (!info[0]->IsString()) {
270 return;
271 }
272 SliderModel::GetInstance()->SetMaxLabel(info[0]->ToNumber<float>());
273 }
274
SetShowSteps(const JSCallbackInfo & info)275 void JSSlider::SetShowSteps(const JSCallbackInfo& info)
276 {
277 if (info.Length() < 1) {
278 return;
279 }
280 bool showSteps = false;
281 if (info[0]->IsBoolean()) {
282 showSteps = info[0]->ToBoolean();
283 }
284 SliderModel::GetInstance()->SetShowSteps(showSteps);
285 }
286
SetShowTips(const JSCallbackInfo & info)287 void JSSlider::SetShowTips(const JSCallbackInfo& info)
288 {
289 if (info.Length() < 1) {
290 return;
291 }
292 bool showTips = false;
293 if (info[0]->IsBoolean()) {
294 showTips = info[0]->ToBoolean();
295 }
296
297 std::optional<std::string> content;
298 if (info.Length() == SLIDER_SHOW_TIPS_MAX_PARAMS) {
299 std::string str;
300 if (ParseJsString(info[1], str)) {
301 content = str;
302 }
303 }
304
305 SliderModel::GetInstance()->SetShowTips(showTips, content);
306 }
307
SetBlockBorderColor(const JSCallbackInfo & info)308 void JSSlider::SetBlockBorderColor(const JSCallbackInfo& info)
309 {
310 if (info.Length() < 1) {
311 return;
312 }
313
314 Color colorVal;
315 if (!ParseJsColor(info[0], colorVal)) {
316 SliderModel::GetInstance()->ResetBlockBorderColor();
317 return;
318 }
319 SliderModel::GetInstance()->SetBlockBorderColor(colorVal);
320 }
321
SetBlockBorderWidth(const JSCallbackInfo & info)322 void JSSlider::SetBlockBorderWidth(const JSCallbackInfo& info)
323 {
324 if (info.Length() < 1) {
325 return;
326 }
327
328 CalcDimension blockBorderWidth;
329 if (!ParseJsDimensionVp(info[0], blockBorderWidth)) {
330 SliderModel::GetInstance()->ResetBlockBorderWidth();
331 return;
332 }
333 if (LessNotEqual(blockBorderWidth.Value(), 0.0)) {
334 SliderModel::GetInstance()->ResetBlockBorderWidth();
335 return;
336 }
337 SliderModel::GetInstance()->SetBlockBorderWidth(blockBorderWidth);
338 }
339
SetStepColor(const JSCallbackInfo & info)340 void JSSlider::SetStepColor(const JSCallbackInfo& info)
341 {
342 if (info.Length() < 1) {
343 return;
344 }
345
346 Color colorVal;
347 if (!ParseJsColor(info[0], colorVal)) {
348 SliderModel::GetInstance()->ResetStepColor();
349 return;
350 }
351 SliderModel::GetInstance()->SetStepColor(colorVal);
352 }
353
SetTrackBorderRadius(const JSCallbackInfo & info)354 void JSSlider::SetTrackBorderRadius(const JSCallbackInfo& info)
355 {
356 if (info.Length() < 1) {
357 return;
358 }
359
360 CalcDimension trackBorderRadius;
361 if (!ParseJsDimensionVpNG(info[0], trackBorderRadius, true)) {
362 SliderModel::GetInstance()->ResetTrackBorderRadius();
363 return;
364 }
365 if (LessNotEqual(trackBorderRadius.Value(), 0.0)) {
366 SliderModel::GetInstance()->ResetTrackBorderRadius();
367 return;
368 }
369 SliderModel::GetInstance()->SetTrackBorderRadius(trackBorderRadius);
370 }
371
SetBlockSize(const JSCallbackInfo & info)372 void JSSlider::SetBlockSize(const JSCallbackInfo& info)
373 {
374 if (info.Length() < 1) {
375 return;
376 }
377 if (!info[0]->IsObject()) {
378 SliderModel::GetInstance()->ResetBlockSize();
379 return;
380 }
381 JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
382
383 CalcDimension width;
384 JSRef<JSVal> jsWidth = sizeObj->GetProperty("width");
385 if (!ParseJsDimensionVp(jsWidth, width)) {
386 width.SetValue(0.0);
387 }
388 if (LessNotEqual(width.Value(), 0.0)) {
389 width.SetValue(0.0);
390 }
391
392 CalcDimension height;
393 JSRef<JSVal> jsHeight = sizeObj->GetProperty("height");
394 if (!ParseJsDimensionVp(jsHeight, height)) {
395 height.SetValue(0.0);
396 }
397 if (LessNotEqual(height.Value(), 0.0)) {
398 height.SetValue(0.0);
399 }
400
401 SliderModel::GetInstance()->SetBlockSize(width, height);
402 }
403
SetBlockStyle(const JSCallbackInfo & info)404 void JSSlider::SetBlockStyle(const JSCallbackInfo& info)
405 {
406 if (!info[0]->IsObject()) {
407 ResetBlockStyle();
408 return;
409 }
410 auto jsObj = JSRef<JSObject>::Cast(info[0]);
411 auto getType = jsObj->GetProperty("type");
412 if (getType->IsNull() || !getType->IsNumber()) {
413 ResetBlockStyle();
414 return;
415 }
416 auto type = static_cast<SliderModel::BlockStyleType>(getType->ToNumber<int32_t>());
417 if (type == SliderModel::BlockStyleType::IMAGE) {
418 std::string src;
419 auto image = jsObj->GetProperty("image");
420 if (!ParseJsMedia(image, src)) {
421 ResetBlockStyle();
422 return;
423 }
424 std::string bundleName;
425 std::string moduleName;
426 GetJsMediaBundleInfo(image, bundleName, moduleName);
427 SliderModel::GetInstance()->SetBlockImage(src, bundleName, moduleName);
428 } else if (type == SliderModel::BlockStyleType::SHAPE) {
429 auto shape = jsObj->GetProperty("shape");
430 if (!shape->IsObject()) {
431 ResetBlockStyle();
432 return;
433 }
434 JSShapeAbstract* shapeAbstract = JSRef<JSObject>::Cast(shape)->Unwrap<JSShapeAbstract>();
435 if (shapeAbstract == nullptr) {
436 ResetBlockStyle();
437 return;
438 }
439 SliderModel::GetInstance()->SetBlockShape(shapeAbstract->GetBasicShape());
440 }
441 SliderModel::GetInstance()->SetBlockType(type);
442 }
443
SetStepSize(const JSCallbackInfo & info)444 void JSSlider::SetStepSize(const JSCallbackInfo& info)
445 {
446 if (info.Length() < 1) {
447 return;
448 }
449
450 CalcDimension stepSize;
451 if (!ParseJsDimensionVp(info[0], stepSize)) {
452 SliderModel::GetInstance()->ResetStepSize();
453 return;
454 }
455 if (LessNotEqual(stepSize.Value(), 0.0)) {
456 auto theme = GetTheme<SliderTheme>();
457 CHECK_NULL_VOID(theme);
458 stepSize = theme->GetMarkerSize();
459 }
460 SliderModel::GetInstance()->SetStepSize(stepSize);
461 }
462
OnChange(const JSCallbackInfo & info)463 void JSSlider::OnChange(const JSCallbackInfo& info)
464 {
465 if (!info[0]->IsFunction()) {
466 return;
467 }
468 SliderModel::GetInstance()->SetOnChange(
469 JsEventCallback<void(float, int32_t)>(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0])));
470 info.ReturnSelf();
471 }
472
ResetBlockStyle()473 void JSSlider::ResetBlockStyle()
474 {
475 SliderModel::GetInstance()->ResetBlockType();
476 SliderModel::GetInstance()->ResetBlockImage();
477 SliderModel::GetInstance()->ResetBlockShape();
478 }
479 } // namespace OHOS::Ace::Framework
480