• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         LOGE("slider create error, info is non-valid");
124         SliderModel::GetInstance()->Create(
125             static_cast<float>(value), static_cast<float>(step), static_cast<float>(min), static_cast<float>(max));
126         return;
127     }
128 
129     auto paramObject = JSRef<JSObject>::Cast(info[0]);
130     auto getValue = paramObject->GetProperty("value");
131     auto getMin = paramObject->GetProperty("min");
132     auto getMax = paramObject->GetProperty("max");
133     auto getStep = paramObject->GetProperty("step");
134     auto getStyle = paramObject->GetProperty("style");
135     auto direction = paramObject->GetProperty("direction");
136     auto isReverse = paramObject->GetProperty("reverse");
137     JSRef<JSVal> changeEventVal;
138 
139     if (!getValue->IsNull() && getValue->IsNumber()) {
140         value = getValue->ToNumber<double>();
141     } else if (!getValue->IsNull() && getValue->IsObject()) {
142         JSRef<JSObject> valueObj = JSRef<JSObject>::Cast(getValue);
143         changeEventVal = valueObj->GetProperty("changeEvent");
144         auto valueProperty = valueObj->GetProperty("value");
145         value = valueProperty->ToNumber<double>();
146     }
147 
148     if (!getMin->IsNull() && getMin->IsNumber()) {
149         min = getMin->ToNumber<double>();
150     }
151 
152     if (!getMax->IsNull() && getMax->IsNumber()) {
153         max = getMax->ToNumber<double>();
154     }
155 
156     if (!getStep->IsNull() && getStep->IsNumber()) {
157         step = getStep->ToNumber<double>();
158     }
159 
160     if (!isReverse->IsNull() && isReverse->IsBoolean()) {
161         reverse = isReverse->ToBoolean();
162     }
163 
164     if (GreatOrEqual(min, max)) {
165         min = 0;
166         max = 100;
167     }
168 
169     step = GetStep(step, max, min);
170 
171     if (!Container::IsCurrentUseNewPipeline()) {
172         value = GetValue(value, max, min);
173     }
174 
175     auto sliderStyle = SliderStyle::OUTSET;
176     auto sliderMode = SliderModel::SliderMode::OUTSET;
177     if (!getStyle->IsNull() && getStyle->IsNumber()) {
178         sliderStyle = static_cast<SliderStyle>(getStyle->ToNumber<int32_t>());
179     }
180     if (sliderStyle == SliderStyle::INSET) {
181         sliderMode = SliderModel::SliderMode::INSET;
182     } else if (sliderStyle == SliderStyle::CAPSULE) {
183         sliderMode = SliderModel::SliderMode::CAPSULE;
184     } else {
185         sliderMode = SliderModel::SliderMode::OUTSET;
186     }
187 
188     auto sliderDirection = Axis::HORIZONTAL;
189     if (!direction->IsNull() && direction->IsNumber()) {
190         sliderDirection = static_cast<Axis>(direction->ToNumber<int32_t>());
191     }
192     if (sliderDirection != Axis::VERTICAL) {
193         sliderDirection = Axis::HORIZONTAL;
194     }
195 
196     SliderModel::GetInstance()->Create(
197         static_cast<float>(value), static_cast<float>(step), static_cast<float>(min), static_cast<float>(max));
198     SliderModel::GetInstance()->SetSliderMode(sliderMode);
199     SliderModel::GetInstance()->SetDirection(sliderDirection);
200     SliderModel::GetInstance()->SetReverse(reverse);
201     if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) {
202         ParseSliderValueObject(info, changeEventVal);
203     }
204 }
205 
SetThickness(const JSCallbackInfo & info)206 void JSSlider::SetThickness(const JSCallbackInfo& info)
207 {
208     if (info.Length() < 1) {
209         LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
210         return;
211     }
212     CalcDimension value;
213     if (!ParseJsDimensionVp(info[0], value)) {
214         value = CalcDimension(0.0);
215     }
216     SliderModel::GetInstance()->SetThickness(value);
217 }
218 
SetBlockColor(const JSCallbackInfo & info)219 void JSSlider::SetBlockColor(const JSCallbackInfo& info)
220 {
221     if (info.Length() < 1) {
222         LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
223         return;
224     }
225     Color colorVal;
226     if (!ParseJsColor(info[0], colorVal)) {
227         auto theme = GetTheme<SliderTheme>();
228         CHECK_NULL_VOID(theme);
229         colorVal = theme->GetBlockColor();
230     }
231     SliderModel::GetInstance()->SetBlockColor(colorVal);
232 }
233 
SetTrackColor(const JSCallbackInfo & info)234 void JSSlider::SetTrackColor(const JSCallbackInfo& info)
235 {
236     if (info.Length() < 1) {
237         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
238         return;
239     }
240     Color colorVal;
241     if (!ParseJsColor(info[0], colorVal)) {
242         auto theme = GetTheme<SliderTheme>();
243         CHECK_NULL_VOID(theme);
244         colorVal = theme->GetTrackBgColor();
245     }
246     SliderModel::GetInstance()->SetTrackBackgroundColor(colorVal);
247 }
248 
SetSelectedColor(const JSCallbackInfo & info)249 void JSSlider::SetSelectedColor(const JSCallbackInfo& info)
250 {
251     if (info.Length() < 1) {
252         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
253         return;
254     }
255     Color colorVal;
256     if (!ParseJsColor(info[0], colorVal)) {
257         auto theme = GetTheme<SliderTheme>();
258         CHECK_NULL_VOID(theme);
259         colorVal = theme->GetTrackSelectedColor();
260     }
261     SliderModel::GetInstance()->SetSelectColor(colorVal);
262 }
263 
SetMinLabel(const JSCallbackInfo & info)264 void JSSlider::SetMinLabel(const JSCallbackInfo& info)
265 {
266     if (info.Length() < 1) {
267         LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
268         return;
269     }
270 
271     if (!info[0]->IsString()) {
272         LOGE("arg is not string.");
273         return;
274     }
275     SliderModel::GetInstance()->SetMinLabel(info[0]->ToNumber<float>());
276 }
277 
SetMaxLabel(const JSCallbackInfo & info)278 void JSSlider::SetMaxLabel(const JSCallbackInfo& info)
279 {
280     if (info.Length() < 1) {
281         LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
282         return;
283     }
284 
285     if (!info[0]->IsString()) {
286         LOGE("arg is not string.");
287         return;
288     }
289     SliderModel::GetInstance()->SetMaxLabel(info[0]->ToNumber<float>());
290 }
291 
SetShowSteps(const JSCallbackInfo & info)292 void JSSlider::SetShowSteps(const JSCallbackInfo& info)
293 {
294     if (info.Length() < 1) {
295         LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
296         return;
297     }
298     bool showSteps = false;
299     if (info[0]->IsBoolean()) {
300         showSteps = info[0]->ToBoolean();
301     }
302     SliderModel::GetInstance()->SetShowSteps(showSteps);
303 }
304 
SetShowTips(const JSCallbackInfo & info)305 void JSSlider::SetShowTips(const JSCallbackInfo& info)
306 {
307     if (info.Length() < 1) {
308         LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
309         return;
310     }
311     bool showTips = false;
312     if (info[0]->IsBoolean()) {
313         showTips = info[0]->ToBoolean();
314     }
315 
316     std::optional<std::string> content;
317     if (info.Length() == SLIDER_SHOW_TIPS_MAX_PARAMS) {
318         std::string str;
319         if (ParseJsString(info[1], str)) {
320             content = str;
321         }
322     }
323 
324     SliderModel::GetInstance()->SetShowTips(showTips, content);
325 }
326 
SetBlockBorderColor(const JSCallbackInfo & info)327 void JSSlider::SetBlockBorderColor(const JSCallbackInfo& info)
328 {
329     if (info.Length() < 1) {
330         LOGW("The arg is wrong, it is supposed to have at least 1 arguments");
331         return;
332     }
333 
334     Color colorVal;
335     if (!ParseJsColor(info[0], colorVal)) {
336         SliderModel::GetInstance()->ResetBlockBorderColor();
337         return;
338     }
339     SliderModel::GetInstance()->SetBlockBorderColor(colorVal);
340 }
341 
SetBlockBorderWidth(const JSCallbackInfo & info)342 void JSSlider::SetBlockBorderWidth(const JSCallbackInfo& info)
343 {
344     if (info.Length() < 1) {
345         LOGW("The arg is wrong, it is supposed to have at least 1 arguments");
346         return;
347     }
348 
349     CalcDimension blockBorderWidth;
350     if (!ParseJsDimensionVp(info[0], blockBorderWidth)) {
351         SliderModel::GetInstance()->ResetBlockBorderWidth();
352         return;
353     }
354     if (LessNotEqual(blockBorderWidth.Value(), 0.0)) {
355         SliderModel::GetInstance()->ResetBlockBorderWidth();
356         return;
357     }
358     SliderModel::GetInstance()->SetBlockBorderWidth(blockBorderWidth);
359 }
360 
SetStepColor(const JSCallbackInfo & info)361 void JSSlider::SetStepColor(const JSCallbackInfo& info)
362 {
363     if (info.Length() < 1) {
364         LOGW("The arg is wrong, it is supposed to have at least 1 arguments");
365         return;
366     }
367 
368     Color colorVal;
369     if (!ParseJsColor(info[0], colorVal)) {
370         SliderModel::GetInstance()->ResetStepColor();
371         return;
372     }
373     SliderModel::GetInstance()->SetStepColor(colorVal);
374 }
375 
SetTrackBorderRadius(const JSCallbackInfo & info)376 void JSSlider::SetTrackBorderRadius(const JSCallbackInfo& info)
377 {
378     if (info.Length() < 1) {
379         LOGW("The arg is wrong, it is supposed to have at least 1 arguments");
380         return;
381     }
382 
383     CalcDimension trackBorderRadius;
384     if (!ParseJsDimensionVpNG(info[0], trackBorderRadius, true)) {
385         SliderModel::GetInstance()->ResetTrackBorderRadius();
386         return;
387     }
388     if (LessNotEqual(trackBorderRadius.Value(), 0.0)) {
389         SliderModel::GetInstance()->ResetTrackBorderRadius();
390         return;
391     }
392     SliderModel::GetInstance()->SetTrackBorderRadius(trackBorderRadius);
393 }
394 
SetBlockSize(const JSCallbackInfo & info)395 void JSSlider::SetBlockSize(const JSCallbackInfo& info)
396 {
397     if (info.Length() < 1) {
398         LOGW("The arg is wrong, it is supposed to have at least 1 arguments");
399         return;
400     }
401     if (!info[0]->IsObject()) {
402         SliderModel::GetInstance()->ResetBlockSize();
403         return;
404     }
405     JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
406 
407     CalcDimension width;
408     JSRef<JSVal> jsWidth = sizeObj->GetProperty("width");
409     if (!ParseJsDimensionVp(jsWidth, width)) {
410         width.SetValue(0.0);
411     }
412     if (LessNotEqual(width.Value(), 0.0)) {
413         width.SetValue(0.0);
414     }
415 
416     CalcDimension height;
417     JSRef<JSVal> jsHeight = sizeObj->GetProperty("height");
418     if (!ParseJsDimensionVp(jsHeight, height)) {
419         height.SetValue(0.0);
420     }
421     if (LessNotEqual(height.Value(), 0.0)) {
422         height.SetValue(0.0);
423     }
424 
425     SliderModel::GetInstance()->SetBlockSize(width, height);
426 }
427 
SetBlockStyle(const JSCallbackInfo & info)428 void JSSlider::SetBlockStyle(const JSCallbackInfo& info)
429 {
430     if (info.Length() < 1) {
431         LOGW("The arg is wrong, it is supposed to have at least 1 arguments");
432         return;
433     }
434 
435     if (!info[0]->IsObject()) {
436         LOGW("arg is not object.");
437         ResetBlockStyle();
438         return;
439     }
440     auto jsObj = JSRef<JSObject>::Cast(info[0]);
441     auto getType = jsObj->GetProperty("type");
442     if (getType->IsNull() || !getType->IsNumber()) {
443         LOGW("block type is not number.");
444         ResetBlockStyle();
445         return;
446     }
447     auto type = static_cast<SliderModel::BlockStyleType>(getType->ToNumber<int32_t>());
448     if (type == SliderModel::BlockStyleType::IMAGE) {
449         std::string src;
450         if (!ParseJsMedia(jsObj->GetProperty("image"), src)) {
451             ResetBlockStyle();
452             return;
453         }
454         SliderModel::GetInstance()->SetBlockImage(src);
455     } else if (type == SliderModel::BlockStyleType::SHAPE) {
456         auto shape = jsObj->GetProperty("shape");
457         if (!shape->IsObject()) {
458             LOGW("shape param is not an object.");
459             ResetBlockStyle();
460             return;
461         }
462         JSShapeAbstract* shapeAbstract = JSRef<JSObject>::Cast(shape)->Unwrap<JSShapeAbstract>();
463         if (shapeAbstract == nullptr) {
464             LOGW("clipShape is null");
465             ResetBlockStyle();
466             return;
467         }
468         SliderModel::GetInstance()->SetBlockShape(shapeAbstract->GetBasicShape());
469     }
470     SliderModel::GetInstance()->SetBlockType(type);
471 }
472 
SetStepSize(const JSCallbackInfo & info)473 void JSSlider::SetStepSize(const JSCallbackInfo& info)
474 {
475     if (info.Length() < 1) {
476         LOGW("The arg is wrong, it is supposed to have at least 1 arguments");
477         return;
478     }
479 
480     CalcDimension stepSize;
481     if (!ParseJsDimensionVp(info[0], stepSize)) {
482         SliderModel::GetInstance()->ResetStepSize();
483         return;
484     }
485     if (LessNotEqual(stepSize.Value(), 0.0)) {
486         auto theme = GetTheme<SliderTheme>();
487         CHECK_NULL_VOID(theme);
488         stepSize = theme->GetMarkerSize();
489     }
490     SliderModel::GetInstance()->SetStepSize(stepSize);
491 }
492 
OnChange(const JSCallbackInfo & info)493 void JSSlider::OnChange(const JSCallbackInfo& info)
494 {
495     if (info.Length() < 1) {
496         LOGW("Must contain at least 1 argument");
497         return;
498     }
499     if (!info[0]->IsFunction()) {
500         LOGW("Argument is not a function object");
501         return;
502     }
503     SliderModel::GetInstance()->SetOnChange(
504         JsEventCallback<void(float, int32_t)>(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0])));
505     info.ReturnSelf();
506 }
507 
ResetBlockStyle()508 void JSSlider::ResetBlockStyle()
509 {
510     SliderModel::GetInstance()->ResetBlockType();
511     SliderModel::GetInstance()->ResetBlockImage();
512     SliderModel::GetInstance()->ResetBlockShape();
513 }
514 } // namespace OHOS::Ace::Framework
515