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