• 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_radio.h"
17 
18 #include "base/log/ace_scoring_log.h"
19 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
20 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
21 #include "bridge/declarative_frontend/jsview/models/radio_model_impl.h"
22 #include "core/components/checkable/checkable_theme.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/radio/radio_model_ng.h"
26 
27 namespace OHOS::Ace {
28 
29 std::unique_ptr<RadioModel> RadioModel::instance_ = nullptr;
30 std::mutex RadioModel::mutex_;
31 
GetInstance()32 RadioModel* RadioModel::GetInstance()
33 {
34     if (!instance_) {
35         std::lock_guard<std::mutex> lock(mutex_);
36         if (!instance_) {
37 #ifdef NG_BUILD
38             instance_.reset(new NG::RadioModelNG());
39 #else
40             if (Container::IsCurrentUseNewPipeline()) {
41                 instance_.reset(new NG::RadioModelNG());
42             } else {
43                 instance_.reset(new Framework::RadioModelImpl());
44             }
45 #endif
46         }
47     }
48     return instance_.get();
49 }
50 
51 } // namespace OHOS::Ace
52 namespace OHOS::Ace::Framework {
Create(const JSCallbackInfo & info)53 void JSRadio::Create(const JSCallbackInfo& info)
54 {
55     if (info.Length() < 1) {
56         return;
57     }
58 
59     std::optional<std::string> value;
60     std::optional<std::string> group;
61     if ((info.Length() >= 1) && info[0]->IsObject()) {
62         auto paramObject = JSRef<JSObject>::Cast(info[0]);
63         auto valueTemp = paramObject->GetProperty("value");
64         auto groupTemp = paramObject->GetProperty("group");
65         if (valueTemp->IsString()) {
66             value = valueTemp->ToString();
67         } else {
68             value = "";
69         }
70         if (groupTemp->IsString()) {
71             group = groupTemp->ToString();
72         } else {
73             group = "";
74         }
75     }
76     RadioModel::GetInstance()->Create(value, group);
77 }
78 
JSBind(BindingTarget globalObj)79 void JSRadio::JSBind(BindingTarget globalObj)
80 {
81     JSClass<JSRadio>::Declare("Radio");
82 
83     JSClass<JSRadio>::StaticMethod("create", &JSRadio::Create);
84     JSClass<JSRadio>::StaticMethod("checked", &JSRadio::Checked);
85     JSClass<JSRadio>::StaticMethod("width", &JSRadio::JsWidth);
86     JSClass<JSRadio>::StaticMethod("height", &JSRadio::JsHeight);
87     JSClass<JSRadio>::StaticMethod("size", &JSRadio::JsSize);
88     JSClass<JSRadio>::StaticMethod("padding", &JSRadio::JsPadding);
89     JSClass<JSRadio>::StaticMethod("radioStyle", &JSRadio::JsRadioStyle);
90     JSClass<JSRadio>::StaticMethod("responseRegion", &JSRadio::JsResponseRegion);
91     JSClass<JSRadio>::StaticMethod("hoverEffect", &JSRadio::JsHoverEffect);
92     JSClass<JSRadio>::StaticMethod("onChange", &JSRadio::OnChange);
93     JSClass<JSRadio>::StaticMethod("onClick", &JSRadio::JsOnClick);
94     JSClass<JSRadio>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
95     JSClass<JSRadio>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
96     JSClass<JSRadio>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
97     JSClass<JSRadio>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
98     JSClass<JSRadio>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
99     JSClass<JSRadio>::InheritAndBind<JSViewAbstract>(globalObj);
100 }
101 
ParseCheckedObject(const JSCallbackInfo & args,const JSRef<JSVal> & changeEventVal)102 void ParseCheckedObject(const JSCallbackInfo& args, 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     WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
108     auto onChecked = [execCtx = args.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](bool check) {
109         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
110         ACE_SCORING_EVENT("Radio.onChangeEvent");
111         PipelineContext::SetCallBackNode(node);
112         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(check));
113         func->ExecuteJS(1, &newJSVal);
114     };
115     RadioModel::GetInstance()->SetOnChangeEvent(std::move(onChecked));
116 }
117 
Checked(const JSCallbackInfo & info)118 void JSRadio::Checked(const JSCallbackInfo& info)
119 {
120     if (info.Length() < 1 || info.Length() > 2) {
121         return;
122     }
123 
124     if (info.Length() > 0 && info[0]->IsBoolean()) {
125         RadioModel::GetInstance()->SetChecked(info[0]->ToBoolean());
126     } else {
127         RadioModel::GetInstance()->SetChecked(false);
128     }
129 
130     if (info.Length() > 1 && info[1]->IsFunction()) {
131         ParseCheckedObject(info, info[1]);
132     }
133 }
134 
JsWidth(const JSCallbackInfo & info)135 void JSRadio::JsWidth(const JSCallbackInfo& info)
136 {
137     if (info.Length() < 1) {
138         return;
139     }
140 
141     JsWidth(info[0]);
142 }
143 
JsWidth(const JSRef<JSVal> & jsValue)144 void JSRadio::JsWidth(const JSRef<JSVal>& jsValue)
145 {
146     auto pipeline = PipelineBase::GetCurrentContext();
147     CHECK_NULL_VOID(pipeline);
148     auto radioTheme = pipeline->GetTheme<RadioTheme>();
149     CHECK_NULL_VOID(radioTheme);
150     auto defaultWidth = radioTheme->GetDefaultWidth();
151     auto horizontalPadding = radioTheme->GetHotZoneHorizontalPadding();
152     auto width = defaultWidth - horizontalPadding * 2;
153     CalcDimension value(width);
154     ParseJsDimensionVp(jsValue, value);
155     if (value.IsNegative()) {
156         value = width;
157     }
158     RadioModel::GetInstance()->SetWidth(value);
159 }
160 
JsHeight(const JSCallbackInfo & info)161 void JSRadio::JsHeight(const JSCallbackInfo& info)
162 {
163     if (info.Length() < 1) {
164         return;
165     }
166 
167     JsHeight(info[0]);
168 }
169 
JsHeight(const JSRef<JSVal> & jsValue)170 void JSRadio::JsHeight(const JSRef<JSVal>& jsValue)
171 {
172     auto pipeline = PipelineBase::GetCurrentContext();
173     CHECK_NULL_VOID(pipeline);
174     auto radioTheme = pipeline->GetTheme<RadioTheme>();
175     CHECK_NULL_VOID(radioTheme);
176     auto defaultHeight = radioTheme->GetDefaultHeight();
177     auto verticalPadding = radioTheme->GetHotZoneVerticalPadding();
178     auto height = defaultHeight - verticalPadding * 2;
179     CalcDimension value(height);
180     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
181         if (!ParseJsDimensionVpNG(jsValue, value)) {
182             value = height;
183         }
184     } else {
185         ParseJsDimensionVp(jsValue, value);
186         if (value.IsNegative()) {
187             value = height;
188         }
189     }
190     RadioModel::GetInstance()->SetHeight(value);
191 }
192 
JsSize(const JSCallbackInfo & info)193 void JSRadio::JsSize(const JSCallbackInfo& info)
194 {
195     if (!info[0]->IsObject()) {
196         return;
197     }
198 
199     JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
200     JsWidth(sizeObj->GetProperty("width"));
201     JsHeight(sizeObj->GetProperty("height"));
202 }
203 
JsPadding(const JSCallbackInfo & info)204 void JSRadio::JsPadding(const JSCallbackInfo& info)
205 {
206     if (info.Length() < 1) {
207         return;
208     }
209     NG::PaddingPropertyF oldPadding = GetOldPadding(info);
210     NG::PaddingProperty newPadding = GetNewPadding(info);
211     RadioModel::GetInstance()->SetPadding(oldPadding, newPadding);
212 }
213 
GetOldPadding(const JSCallbackInfo & info)214 NG::PaddingPropertyF JSRadio::GetOldPadding(const JSCallbackInfo& info)
215 {
216     NG::PaddingPropertyF padding({ 0.0f, 0.0f, 0.0f, 0.0f });
217     if (info[0]->IsObject()) {
218         JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
219         if (jsObj->HasProperty("top") || jsObj->HasProperty("bottom")
220             || jsObj->HasProperty("left") || jsObj->HasProperty("right")) {
221             CalcDimension topDimen = CalcDimension(0.0, DimensionUnit::VP);
222             CalcDimension leftDimen = CalcDimension(0.0, DimensionUnit::VP);
223             CalcDimension rightDimen = CalcDimension(0.0, DimensionUnit::VP);
224             CalcDimension bottomDimen = CalcDimension(0.0, DimensionUnit::VP);
225             ParseJsDimensionVp(jsObj->GetProperty("top"), topDimen);
226             ParseJsDimensionVp(jsObj->GetProperty("left"), leftDimen);
227             ParseJsDimensionVp(jsObj->GetProperty("right"), rightDimen);
228             ParseJsDimensionVp(jsObj->GetProperty("bottom"), bottomDimen);
229             if (leftDimen == 0.0_vp) {
230                 leftDimen = rightDimen;
231             }
232             if (topDimen == 0.0_vp) {
233                 topDimen = bottomDimen;
234             }
235             if (leftDimen == 0.0_vp) {
236                 leftDimen = topDimen;
237             }
238 
239             padding.left = leftDimen.ConvertToPx();
240             padding.right = rightDimen.ConvertToPx();
241             padding.top = topDimen.ConvertToPx();
242             padding.bottom = bottomDimen.ConvertToPx();
243             return padding;
244         }
245     }
246 
247     CalcDimension length;
248     if (!ParseJsDimensionVp(info[0], length)) {
249         return padding;
250     }
251 
252     padding.left = length.ConvertToPx();
253     padding.right = length.ConvertToPx();
254     padding.top = length.ConvertToPx();
255     padding.bottom = length.ConvertToPx();
256     return padding;
257 }
258 
GetNewPadding(const JSCallbackInfo & info)259 NG::PaddingProperty JSRadio::GetNewPadding(const JSCallbackInfo& info)
260 {
261     NG::PaddingProperty padding(
262         { NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp) });
263     if (info[0]->IsObject()) {
264         std::optional<CalcDimension> left;
265         std::optional<CalcDimension> right;
266         std::optional<CalcDimension> top;
267         std::optional<CalcDimension> bottom;
268         JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(info[0]);
269 
270         CalcDimension leftDimen;
271         if (ParseJsDimensionVp(paddingObj->GetProperty("left"), leftDimen)) {
272             left = leftDimen;
273         }
274         CalcDimension rightDimen;
275         if (ParseJsDimensionVp(paddingObj->GetProperty("right"), rightDimen)) {
276             right = rightDimen;
277         }
278         CalcDimension topDimen;
279         if (ParseJsDimensionVp(paddingObj->GetProperty("top"), topDimen)) {
280             top = topDimen;
281         }
282         CalcDimension bottomDimen;
283         if (ParseJsDimensionVp(paddingObj->GetProperty("bottom"), bottomDimen)) {
284             bottom = bottomDimen;
285         }
286         if (left.has_value() || right.has_value() || top.has_value() || bottom.has_value()) {
287             padding = GetPadding(top, bottom, left, right);
288             return padding;
289         }
290     }
291     CalcDimension length;
292     if (!ParseJsDimensionVp(info[0], length)) {
293         length.Reset();
294     }
295 
296     padding.SetEdges(NG::CalcLength(length.IsNonNegative() ? length : CalcDimension()));
297     return padding;
298 }
299 
GetPadding(const std::optional<CalcDimension> & top,const std::optional<CalcDimension> & bottom,const std::optional<CalcDimension> & left,const std::optional<CalcDimension> & right)300 NG::PaddingProperty JSRadio::GetPadding(const std::optional<CalcDimension>& top,
301     const std::optional<CalcDimension>& bottom, const std::optional<CalcDimension>& left,
302     const std::optional<CalcDimension>& right)
303 {
304     NG::PaddingProperty padding(
305         { NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp) });
306     if (left.has_value() && left.value().IsNonNegative()) {
307         padding.left = NG::CalcLength(left.value());
308     }
309     if (right.has_value() && right.value().IsNonNegative()) {
310         padding.right = NG::CalcLength(right.value());
311     }
312     if (top.has_value() && top.value().IsNonNegative()) {
313         padding.top = NG::CalcLength(top.value());
314     }
315     if (bottom.has_value() && bottom.value().IsNonNegative()) {
316         padding.bottom = NG::CalcLength(bottom.value());
317     }
318     return padding;
319 }
320 
JsRadioStyle(const JSCallbackInfo & info)321 void JSRadio::JsRadioStyle(const JSCallbackInfo& info)
322 {
323     if (info[0]->IsObject()) {
324         JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
325         JSRef<JSVal> checkedBackgroundColor = obj->GetProperty("checkedBackgroundColor");
326         JSRef<JSVal> uncheckedBorderColor = obj->GetProperty("uncheckedBorderColor");
327         JSRef<JSVal> indicatorColor = obj->GetProperty("indicatorColor");
328         Color checkedBackgroundColorVal;
329         auto theme = GetTheme<RadioTheme>();
330         if (!ParseJsColor(checkedBackgroundColor, checkedBackgroundColorVal)) {
331             checkedBackgroundColorVal = theme->GetActiveColor();
332         }
333         RadioModel::GetInstance()->SetCheckedBackgroundColor(checkedBackgroundColorVal);
334         Color uncheckedBorderColorVal;
335         if (!ParseJsColor(uncheckedBorderColor, uncheckedBorderColorVal)) {
336             uncheckedBorderColorVal = theme->GetInactiveColor();
337         }
338         RadioModel::GetInstance()->SetUncheckedBorderColor(uncheckedBorderColorVal);
339         Color indicatorColorVal;
340         if (!ParseJsColor(indicatorColor, indicatorColorVal)) {
341             indicatorColorVal = theme->GetPointColor();
342         }
343         RadioModel::GetInstance()->SetIndicatorColor(indicatorColorVal);
344     }
345 }
346 
JsResponseRegion(const JSCallbackInfo & info)347 void JSRadio::JsResponseRegion(const JSCallbackInfo& info)
348 {
349     if (info.Length() < 1) {
350         return;
351     }
352 
353     std::vector<DimensionRect> result;
354     if (!JSViewAbstract::ParseJsResponseRegionArray(info[0], result)) {
355         return;
356     }
357 
358     RadioModel::GetInstance()->SetResponseRegion(result);
359 }
360 
OnChange(const JSCallbackInfo & args)361 void JSRadio::OnChange(const JSCallbackInfo& args)
362 {
363     if (!args[0]->IsFunction()) {
364         return;
365     }
366     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(args[0]));
367     WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
368     auto onChange = [execCtx = args.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](bool check) {
369         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
370         ACE_SCORING_EVENT("Radio.onChange");
371         PipelineContext::SetCallBackNode(node);
372         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(check));
373         func->ExecuteJS(1, &newJSVal);
374     };
375     RadioModel::GetInstance()->SetOnChange(std::move(onChange));
376     args.ReturnSelf();
377 }
378 
JsOnClick(const JSCallbackInfo & args)379 void JSRadio::JsOnClick(const JSCallbackInfo& args)
380 {
381     if (Container::IsCurrentUseNewPipeline()) {
382         JSViewAbstract::JsOnClick(args);
383         return;
384     }
385 
386     RadioModel::GetInstance()->SetOnClickEvent(
387         JsEventCallback<void()>(args.GetExecutionContext(), JSRef<JSFunc>::Cast(args[0])));
388 
389     args.ReturnSelf();
390 }
391 
JsHoverEffect(const JSCallbackInfo & info)392 void JSRadio::JsHoverEffect(const JSCallbackInfo& info)
393 {
394     if (info[0]->IsNumber()) {
395         RadioModel::GetInstance()->SetHoverEffect(static_cast<HoverEffectType>(info[0]->ToNumber<int32_t>()));
396     }
397 }
398 } // namespace OHOS::Ace::Framework
399