• 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 "bridge/declarative_frontend/jsview/js_checkbox.h"
17 
18 #include <optional>
19 #include <string>
20 
21 #include "base/log/ace_scoring_log.h"
22 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
23 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
24 #include "bridge/declarative_frontend/jsview/models/checkbox_model_impl.h"
25 #include "bridge/declarative_frontend/view_stack_processor.h"
26 #include "core/components/checkable/checkable_component.h"
27 #include "core/components_ng/base/view_abstract.h"
28 #include "core/components_ng/base/view_stack_processor.h"
29 #include "core/components_ng/pattern/checkbox/checkbox_model_ng.h"
30 #include "core/components_v2/inspector/inspector_constants.h"
31 
32 namespace OHOS::Ace {
33 namespace {
34 constexpr float CHECK_BOX_MARK_SIZE_INVALID_VALUE = -1.0f;
35 }
36 std::unique_ptr<CheckBoxModel> CheckBoxModel::instance_ = nullptr;
37 std::mutex CheckBoxModel::mutex_;
38 
GetInstance()39 CheckBoxModel* CheckBoxModel::GetInstance()
40 {
41     if (!instance_) {
42         std::lock_guard<std::mutex> lock(mutex_);
43         if (!instance_) {
44 #ifdef NG_BUILD
45             instance_.reset(new NG::CheckBoxModelNG());
46 #else
47             if (Container::IsCurrentUseNewPipeline()) {
48                 instance_.reset(new NG::CheckBoxModelNG());
49             } else {
50                 instance_.reset(new Framework::CheckBoxModelImpl());
51             }
52 #endif
53         }
54     }
55     return instance_.get();
56 }
57 } // namespace OHOS::Ace
58 
59 namespace OHOS::Ace::Framework {
Create(const JSCallbackInfo & info)60 void JSCheckbox::Create(const JSCallbackInfo& info)
61 {
62     auto checkboxName = std::optional<std::string>("");
63     auto checkboxGroup = std::optional<std::string>("");
64     if ((info.Length() >= 1) && info[0]->IsObject()) {
65         auto paramObject = JSRef<JSObject>::Cast(info[0]);
66         auto name = paramObject->GetProperty("name");
67         auto group = paramObject->GetProperty("group");
68         if (name->IsString()) {
69             checkboxName = name->ToString();
70         }
71         if (group->IsString()) {
72             checkboxGroup = group->ToString();
73         }
74     }
75     CheckBoxModel::GetInstance()->Create(checkboxName, checkboxGroup, V2::CHECK_BOX_ETS_TAG);
76 }
77 
JSBind(BindingTarget globalObj)78 void JSCheckbox::JSBind(BindingTarget globalObj)
79 {
80     JSClass<JSCheckbox>::Declare("Checkbox");
81 
82     JSClass<JSCheckbox>::StaticMethod("create", &JSCheckbox::Create);
83     JSClass<JSCheckbox>::StaticMethod("select", &JSCheckbox::SetSelect);
84     JSClass<JSCheckbox>::StaticMethod("onChange", &JSCheckbox::SetOnChange);
85     JSClass<JSCheckbox>::StaticMethod("selectedColor", &JSCheckbox::SelectedColor);
86     JSClass<JSCheckbox>::StaticMethod("unselectedColor", &JSCheckbox::UnSelectedColor);
87     JSClass<JSCheckbox>::StaticMethod("mark", &JSCheckbox::Mark);
88     JSClass<JSCheckbox>::StaticMethod("responseRegion", &JSCheckbox::JsResponseRegion);
89     JSClass<JSCheckbox>::StaticMethod("width", &JSCheckbox::JsWidth);
90     JSClass<JSCheckbox>::StaticMethod("height", &JSCheckbox::JsHeight);
91     JSClass<JSCheckbox>::StaticMethod("size", &JSCheckbox::JsSize);
92     JSClass<JSCheckbox>::StaticMethod("padding", &JSCheckbox::JsPadding);
93     JSClass<JSCheckbox>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
94     JSClass<JSCheckbox>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
95     JSClass<JSCheckbox>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
96     JSClass<JSCheckbox>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
97     JSClass<JSCheckbox>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
98     JSClass<JSCheckbox>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
99     JSClass<JSCheckbox>::InheritAndBind<JSViewAbstract>(globalObj);
100 }
101 
ParseSelectObject(const JSCallbackInfo & info,const JSRef<JSVal> & changeEventVal)102 void ParseSelectObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
103 {
104     CHECK_NULL_VOID(changeEventVal->IsFunction());
105 
106     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
107     auto changeEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](bool param) {
108         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
109         ACE_SCORING_EVENT("CheckBox.ChangeEvent");
110         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(param));
111         func->ExecuteJS(1, &newJSVal);
112     };
113     CheckBoxModel::GetInstance()->SetChangeEvent(std::move(changeEvent));
114 }
115 
SetSelect(const JSCallbackInfo & info)116 void JSCheckbox::SetSelect(const JSCallbackInfo& info)
117 {
118     if (info.Length() < 1 || info.Length() > 2) {
119         LOGE("The arg is wrong, it is supposed to have 1 or 2 arguments");
120         return;
121     }
122     bool select = false;
123     if (info.Length() > 0 && info[0]->IsBoolean()) {
124         select = info[0]->ToBoolean();
125     }
126     CheckBoxModel::GetInstance()->SetSelect(select);
127     if (info.Length() > 1 && info[1]->IsFunction()) {
128         ParseSelectObject(info, info[1]);
129     }
130 }
131 
SetOnChange(const JSCallbackInfo & args)132 void JSCheckbox::SetOnChange(const JSCallbackInfo& args)
133 {
134     if (!args[0]->IsFunction()) {
135         return;
136     }
137     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(args[0]));
138     auto onChange = [execCtx = args.GetExecutionContext(), func = std::move(jsFunc)](bool select) {
139         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
140         ACE_SCORING_EVENT("CheckBox.onChange");
141         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(select));
142         func->ExecuteJS(1, &newJSVal);
143     };
144     CheckBoxModel::GetInstance()->SetOnChange(onChange);
145     args.ReturnSelf();
146 }
147 
JsResponseRegion(const JSCallbackInfo & info)148 void JSCheckbox::JsResponseRegion(const JSCallbackInfo& info)
149 {
150     if (!Container::IsCurrentUseNewPipeline()) {
151         JSViewAbstract::JsResponseRegion(info);
152         return;
153     }
154     if (info.Length() < 1) {
155         LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
156         return;
157     }
158     std::vector<DimensionRect> result;
159     if (!JSViewAbstract::ParseJsResponseRegionArray(info[0], result)) {
160         return;
161     }
162     CheckBoxModel::GetInstance()->SetResponseRegion(result);
163 }
164 
JsWidth(const JSCallbackInfo & info)165 void JSCheckbox::JsWidth(const JSCallbackInfo& info)
166 {
167     if (info.Length() < 1) {
168         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
169         return;
170     }
171 
172     JsWidth(info[0]);
173 }
174 
JsWidth(const JSRef<JSVal> & jsValue)175 void JSCheckbox::JsWidth(const JSRef<JSVal>& jsValue)
176 {
177     auto pipeline = PipelineBase::GetCurrentContext();
178     CHECK_NULL_VOID(pipeline);
179     auto checkBoxTheme = pipeline->GetTheme<CheckboxTheme>();
180     CHECK_NULL_VOID(checkBoxTheme);
181     auto defaultWidth = checkBoxTheme->GetDefaultWidth();
182     auto horizontalPadding = checkBoxTheme->GetHotZoneHorizontalPadding();
183     auto width = defaultWidth - horizontalPadding * 2;
184     CalcDimension value(width);
185     ParseJsDimensionVp(jsValue, value);
186     if (value.IsNegative()) {
187         value = width;
188     }
189     CheckBoxModel::GetInstance()->SetWidth(value);
190 }
191 
JsHeight(const JSCallbackInfo & info)192 void JSCheckbox::JsHeight(const JSCallbackInfo& info)
193 {
194     if (info.Length() < 1) {
195         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
196         return;
197     }
198 
199     JsHeight(info[0]);
200 }
201 
JsHeight(const JSRef<JSVal> & jsValue)202 void JSCheckbox::JsHeight(const JSRef<JSVal>& jsValue)
203 {
204     auto pipeline = PipelineBase::GetCurrentContext();
205     CHECK_NULL_VOID(pipeline);
206     auto checkBoxTheme = pipeline->GetTheme<CheckboxTheme>();
207     CHECK_NULL_VOID(checkBoxTheme);
208     auto defaultHeight = checkBoxTheme->GetDefaultHeight();
209     auto verticalPadding = checkBoxTheme->GetHotZoneVerticalPadding();
210     auto height = defaultHeight - verticalPadding * 2;
211     CalcDimension value(height);
212     ParseJsDimensionVp(jsValue, value);
213     if (value.IsNegative()) {
214         value = height;
215     }
216     CheckBoxModel::GetInstance()->SetHeight(value);
217 }
218 
JsSize(const JSCallbackInfo & info)219 void JSCheckbox::JsSize(const JSCallbackInfo& info)
220 {
221     if (info.Length() < 1) {
222         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
223         return;
224     }
225 
226     if (!info[0]->IsObject()) {
227         LOGE("arg is not Object or String.");
228         return;
229     }
230 
231     JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
232     JsWidth(sizeObj->GetProperty("width"));
233     JsHeight(sizeObj->GetProperty("height"));
234 }
235 
SelectedColor(const JSCallbackInfo & info)236 void JSCheckbox::SelectedColor(const JSCallbackInfo& info)
237 {
238     if (info.Length() < 1) {
239         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
240         return;
241     }
242     Color selectedColor;
243     auto theme = GetTheme<CheckboxTheme>();
244     if (!ParseJsColor(info[0], selectedColor)) {
245         selectedColor = theme->GetActiveColor();
246     }
247     CheckBoxModel::GetInstance()->SetSelectedColor(selectedColor);
248 }
249 
UnSelectedColor(const JSCallbackInfo & info)250 void JSCheckbox::UnSelectedColor(const JSCallbackInfo& info)
251 {
252     if (info.Length() < 1) {
253         LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
254         return;
255     }
256     Color unSelectedColor;
257     auto theme = GetTheme<CheckboxTheme>();
258     if (!ParseJsColor(info[0], unSelectedColor)) {
259         unSelectedColor = theme->GetInactiveColor();
260     }
261 
262     CheckBoxModel::GetInstance()->SetUnSelectedColor(unSelectedColor);
263 }
264 
Mark(const JSCallbackInfo & info)265 void JSCheckbox::Mark(const JSCallbackInfo& info)
266 {
267     if (info.Length() < 1) {
268         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
269         return;
270     }
271 
272     if (!info[0]->IsObject()) {
273         LOGE("arg is not Object.");
274         return;
275     }
276 
277     auto markObj = JSRef<JSObject>::Cast(info[0]);
278     auto strokeColorValue = markObj->GetProperty("strokeColor");
279     Color strokeColor;
280     auto theme = GetTheme<CheckboxTheme>();
281     if (!ParseJsColor(strokeColorValue, strokeColor)) {
282         strokeColor = theme->GetPointColor();
283     }
284     CheckBoxModel::GetInstance()->SetCheckMarkColor(strokeColor);
285 
286     auto sizeValue = markObj->GetProperty("size");
287     CalcDimension size;
288     if ((ParseJsDimensionVp(sizeValue, size)) && (size.Unit() != DimensionUnit::PERCENT) && (size.ConvertToVp() >= 0)) {
289         CheckBoxModel::GetInstance()->SetCheckMarkSize(size);
290     } else {
291         CheckBoxModel::GetInstance()->SetCheckMarkSize(Dimension(CHECK_BOX_MARK_SIZE_INVALID_VALUE));
292     }
293 
294     auto strokeWidthValue = markObj->GetProperty("strokeWidth");
295     CalcDimension strokeWidth;
296     if ((ParseJsDimensionVp(strokeWidthValue, strokeWidth)) && (strokeWidth.Unit() != DimensionUnit::PERCENT) &&
297         (strokeWidth.ConvertToVp() >= 0)) {
298         CheckBoxModel::GetInstance()->SetCheckMarkWidth(strokeWidth);
299     } else {
300         CheckBoxModel::GetInstance()->SetCheckMarkWidth(theme->GetCheckStroke());
301     }
302 }
303 
JsPadding(const JSCallbackInfo & info)304 void JSCheckbox::JsPadding(const JSCallbackInfo& info)
305 {
306     if (info.Length() < 1) {
307         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
308         return;
309     }
310     NG::PaddingPropertyF oldPadding({ 0.0f, 0.0f, 0.0f, 0.0f });
311     bool flag = GetOldPadding(info, oldPadding);
312     NG::PaddingProperty newPadding = GetNewPadding(info);
313     CheckBoxModel::GetInstance()->SetPadding(oldPadding, newPadding, flag);
314 }
315 
GetOldPadding(const JSCallbackInfo & info,NG::PaddingPropertyF & padding)316 bool JSCheckbox::GetOldPadding(const JSCallbackInfo& info, NG::PaddingPropertyF& padding)
317 {
318     if (info[0]->IsObject()) {
319         auto argsPtrItem = JsonUtil::ParseJsonString(info[0]->ToString());
320         if (!argsPtrItem || argsPtrItem->IsNull()) {
321             LOGE("Js Parse object failed. argsPtr is null. %s", info[0]->ToString().c_str());
322             return false;
323         }
324         if (argsPtrItem->Contains("top") || argsPtrItem->Contains("bottom") || argsPtrItem->Contains("left") ||
325             argsPtrItem->Contains("right")) {
326             CalcDimension topDimen = CalcDimension(0.0, DimensionUnit::VP);
327             CalcDimension leftDimen = CalcDimension(0.0, DimensionUnit::VP);
328             CalcDimension rightDimen = CalcDimension(0.0, DimensionUnit::VP);
329             CalcDimension bottomDimen = CalcDimension(0.0, DimensionUnit::VP);
330             ParseJsonDimensionVp(argsPtrItem->GetValue("top"), topDimen);
331             ParseJsonDimensionVp(argsPtrItem->GetValue("left"), leftDimen);
332             ParseJsonDimensionVp(argsPtrItem->GetValue("right"), rightDimen);
333             ParseJsonDimensionVp(argsPtrItem->GetValue("bottom"), bottomDimen);
334             if (leftDimen == 0.0_vp) {
335                 leftDimen = rightDimen;
336             }
337             if (topDimen == 0.0_vp) {
338                 topDimen = bottomDimen;
339             }
340             if (leftDimen == 0.0_vp) {
341                 leftDimen = topDimen;
342             }
343 
344             padding.left = leftDimen.ConvertToPx();
345             padding.right = rightDimen.ConvertToPx();
346             padding.top = topDimen.ConvertToPx();
347             padding.bottom = bottomDimen.ConvertToPx();
348             return true;
349         }
350     }
351 
352     CalcDimension length;
353     if (!ParseJsDimensionVp(info[0], length)) {
354         return false;
355     }
356 
357     padding.left = length.ConvertToPx();
358     padding.right = length.ConvertToPx();
359     padding.top = length.ConvertToPx();
360     padding.bottom = length.ConvertToPx();
361     return true;
362 }
363 
GetNewPadding(const JSCallbackInfo & info)364 NG::PaddingProperty JSCheckbox::GetNewPadding(const JSCallbackInfo& info)
365 {
366     NG::PaddingProperty padding(
367         { NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp) });
368     if (info[0]->IsObject()) {
369         std::optional<CalcDimension> left;
370         std::optional<CalcDimension> right;
371         std::optional<CalcDimension> top;
372         std::optional<CalcDimension> bottom;
373         JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(info[0]);
374 
375         CalcDimension leftDimen;
376         if (ParseJsDimensionVp(paddingObj->GetProperty("left"), leftDimen)) {
377             left = leftDimen;
378         }
379         CalcDimension rightDimen;
380         if (ParseJsDimensionVp(paddingObj->GetProperty("right"), rightDimen)) {
381             right = rightDimen;
382         }
383         CalcDimension topDimen;
384         if (ParseJsDimensionVp(paddingObj->GetProperty("top"), topDimen)) {
385             top = topDimen;
386         }
387         CalcDimension bottomDimen;
388         if (ParseJsDimensionVp(paddingObj->GetProperty("bottom"), bottomDimen)) {
389             bottom = bottomDimen;
390         }
391         if (left.has_value() || right.has_value() || top.has_value() || bottom.has_value()) {
392             padding = GetPadding(top, bottom, left, right);
393             return padding;
394         }
395     }
396     CalcDimension length;
397     if (!ParseJsDimensionVp(info[0], length)) {
398         length.Reset();
399     }
400 
401     padding.SetEdges(NG::CalcLength(length.IsNonNegative() ? length : CalcDimension()));
402     return padding;
403 }
404 
GetPadding(const std::optional<CalcDimension> & top,const std::optional<CalcDimension> & bottom,const std::optional<CalcDimension> & left,const std::optional<CalcDimension> & right)405 NG::PaddingProperty JSCheckbox::GetPadding(const std::optional<CalcDimension>& top,
406     const std::optional<CalcDimension>& bottom, const std::optional<CalcDimension>& left,
407     const std::optional<CalcDimension>& right)
408 {
409     NG::PaddingProperty padding(
410         { NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp) });
411     if (left.has_value()) {
412         if (left.value().Unit() == DimensionUnit::CALC) {
413             padding.left =
414                 NG::CalcLength(left.value().IsNonNegative() ? left.value().CalcValue() : CalcDimension().CalcValue());
415         } else {
416             padding.left = NG::CalcLength(left.value().IsNonNegative() ? left.value() : CalcDimension());
417         }
418     }
419     if (right.has_value()) {
420         if (right.value().Unit() == DimensionUnit::CALC) {
421             padding.right =
422                 NG::CalcLength(right.value().IsNonNegative() ? right.value().CalcValue() : CalcDimension().CalcValue());
423         } else {
424             padding.right = NG::CalcLength(right.value().IsNonNegative() ? right.value() : CalcDimension());
425         }
426     }
427     if (top.has_value()) {
428         if (top.value().Unit() == DimensionUnit::CALC) {
429             padding.top =
430                 NG::CalcLength(top.value().IsNonNegative() ? top.value().CalcValue() : CalcDimension().CalcValue());
431         } else {
432             padding.top = NG::CalcLength(top.value().IsNonNegative() ? top.value() : CalcDimension());
433         }
434     }
435     if (bottom.has_value()) {
436         if (bottom.value().Unit() == DimensionUnit::CALC) {
437             padding.bottom = NG::CalcLength(
438                 bottom.value().IsNonNegative() ? bottom.value().CalcValue() : CalcDimension().CalcValue());
439         } else {
440             padding.bottom = NG::CalcLength(bottom.value().IsNonNegative() ? bottom.value() : CalcDimension());
441         }
442     }
443     return padding;
444 }
445 } // namespace OHOS::Ace::Framework
446