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_button.h"
17
18 #include "base/geometry/dimension.h"
19 #include "base/log/ace_scoring_log.h"
20 #include "base/log/ace_trace.h"
21 #include "base/log/log_wrapper.h"
22 #include "base/utils/utils.h"
23 #include "core/components/button/button_component.h"
24 #include "core/components/button/button_theme.h"
25 #include "core/components_ng/pattern/button/button_model_ng.h"
26 #include "frameworks/bridge/declarative_frontend/engine/functions/js_click_function.h"
27 #include "frameworks/bridge/declarative_frontend/jsview/js_utils.h"
28 #include "frameworks/bridge/declarative_frontend/jsview/models/button_model_impl.h"
29 #include "frameworks/bridge/declarative_frontend/view_stack_processor.h"
30
31 namespace OHOS::Ace {
32 std::unique_ptr<ButtonModel> ButtonModel::instance_ = nullptr;
33 std::mutex ButtonModel::mutex_;
34
GetInstance()35 ButtonModel* ButtonModel::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::ButtonModelNG());
42 #else
43 if (Container::IsCurrentUseNewPipeline()) {
44 instance_.reset(new NG::ButtonModelNG());
45 } else {
46 instance_.reset(new Framework::ButtonModelImpl());
47 }
48 #endif
49 }
50 }
51 return instance_.get();
52 }
53 } // namespace OHOS::Ace
54
55 namespace OHOS::Ace::Framework {
56 const std::vector<TextOverflow> TEXT_OVERFLOWS = { TextOverflow::NONE, TextOverflow::CLIP, TextOverflow::ELLIPSIS,
57 TextOverflow::MARQUEE };
58 const std::vector<FontStyle> FONT_STYLES = { FontStyle::NORMAL, FontStyle::ITALIC };
59 const std::vector<TextHeightAdaptivePolicy> HEIGHT_ADAPTIVE_POLICY = { TextHeightAdaptivePolicy::MAX_LINES_FIRST,
60 TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST, TextHeightAdaptivePolicy::LAYOUT_CONSTRAINT_FIRST };
61
62 bool JSButton::isLabelButton_ = false;
63
SetFontSize(const JSCallbackInfo & info)64 void JSButton::SetFontSize(const JSCallbackInfo& info)
65 {
66 if (info.Length() < 1) {
67 LOGE("The argv is wrong, it is supposed to have at least 1 argument");
68 return;
69 }
70 auto buttonTheme = GetTheme<ButtonTheme>();
71 CHECK_NULL_VOID(buttonTheme);
72 CalcDimension fontSize = buttonTheme->GetTextStyle().GetFontSize();
73 if (ParseJsDimensionVpNG(info[0], fontSize) && fontSize.Unit() != DimensionUnit::PERCENT &&
74 GreatOrEqual(fontSize.Value(), 0.0)) {
75 ParseJsDimensionFp(info[0], fontSize);
76 } else {
77 fontSize = buttonTheme->GetTextStyle().GetFontSize();
78 }
79 ButtonModel::GetInstance()->SetFontSize(fontSize);
80 }
81
SetFontWeight(const std::string & value)82 void JSButton::SetFontWeight(const std::string& value)
83 {
84 ButtonModel::GetInstance()->SetFontWeight(ConvertStrToFontWeight(value));
85 }
86
SetFontStyle(int32_t value)87 void JSButton::SetFontStyle(int32_t value)
88 {
89 const std::vector<FontStyle> fontStyles = { FontStyle::NORMAL, FontStyle::ITALIC };
90 if (value < 0 || value >= static_cast<int32_t>(fontStyles.size())) {
91 LOGE("Text fontStyle(%d) is invalid value", value);
92 return;
93 }
94
95 ButtonModel::GetInstance()->SetFontStyle(fontStyles[value]);
96 }
97
SetFontFamily(const JSCallbackInfo & info)98 void JSButton::SetFontFamily(const JSCallbackInfo& info)
99 {
100 if (info.Length() < 1) {
101 LOGE("The argv is wrong, it is supposed to have at least 1 argument");
102 return;
103 }
104 std::vector<std::string> fontFamilies;
105 if (!ParseJsFontFamilies(info[0], fontFamilies)) {
106 LOGE("Parse FontFamilies failed");
107 return;
108 }
109
110 ButtonModel::GetInstance()->SetFontFamily(fontFamilies);
111 }
112
SetTextColor(const JSCallbackInfo & info)113 void JSButton::SetTextColor(const JSCallbackInfo& info)
114 {
115 if (info.Length() < 1) {
116 LOGE("The argv is wrong, it is supposed to have at least 1 argument");
117 return;
118 }
119 Color textColor;
120 if (!ParseJsColor(info[0], textColor)) {
121 LOGI("Set text color is invalid, use default text color.");
122 auto buttonTheme = PipelineBase::GetCurrentContext()->GetTheme<ButtonTheme>();
123 textColor = buttonTheme->GetTextStyle().GetTextColor();
124 }
125
126 ButtonModel::GetInstance()->SetFontColor(textColor);
127 }
128
SetType(const JSCallbackInfo & info)129 void JSButton::SetType(const JSCallbackInfo& info)
130 {
131 if (info.Length() < 1) {
132 return;
133 }
134 int32_t value = 1;
135 if (info[0]->IsNumber()) {
136 value = info[0]->ToNumber<int32_t>();
137 }
138 if ((ButtonType)value == ButtonType::CAPSULE || (ButtonType)value == ButtonType::CIRCLE ||
139 (ButtonType)value == ButtonType::ARC || (ButtonType)value == ButtonType::NORMAL) {
140 ButtonModel::GetInstance()->SetType(value);
141 } else {
142 LOGE("Setting button to non valid ButtonType %d", value);
143 }
144 }
145
SetStateEffect(bool stateEffect)146 void JSButton::SetStateEffect(bool stateEffect)
147 {
148 ButtonModel::GetInstance()->SetStateEffect(stateEffect);
149 }
150
HandleDifferentRadius(const JSRef<JSVal> & args)151 void JSButton::HandleDifferentRadius(const JSRef<JSVal>& args)
152 {
153 std::optional<CalcDimension> radiusTopLeft;
154 std::optional<CalcDimension> radiusTopRight;
155 std::optional<CalcDimension> radiusBottomLeft;
156 std::optional<CalcDimension> radiusBottomRight;
157 if (args->IsObject()) {
158 JSRef<JSObject> object = JSRef<JSObject>::Cast(args);
159 CalcDimension topLeft;
160 if (ParseJsDimensionVp(object->GetProperty("topLeft"), topLeft)) {
161 radiusTopLeft = topLeft;
162 }
163 CalcDimension topRight;
164 if (ParseJsDimensionVp(object->GetProperty("topRight"), topRight)) {
165 radiusTopRight = topRight;
166 }
167 CalcDimension bottomLeft;
168 if (ParseJsDimensionVp(object->GetProperty("bottomLeft"), bottomLeft)) {
169 radiusBottomLeft = bottomLeft;
170 }
171 CalcDimension bottomRight;
172 if (ParseJsDimensionVp(object->GetProperty("bottomRight"), bottomRight)) {
173 radiusBottomRight = bottomRight;
174 }
175 if (!radiusTopLeft.has_value() && !radiusTopRight.has_value() && !radiusBottomLeft.has_value() &&
176 !radiusBottomRight.has_value()) {
177 return;
178 }
179 ButtonModel::GetInstance()->SetBorderRadius(radiusTopLeft, radiusTopRight, radiusBottomLeft, radiusBottomRight);
180 }
181 }
182
GetFontContent(JSRef<JSVal> & font,ButtonParameters & buttonParameters)183 void JSButton::GetFontContent(JSRef<JSVal>& font, ButtonParameters& buttonParameters)
184 {
185 JSRef<JSObject> obj = JSRef<JSObject>::Cast(font);
186 JSRef<JSVal> size = obj->GetProperty("size");
187 CalcDimension fontSize;
188 if (ParseJsDimensionFp(size, fontSize)) {
189 buttonParameters.fontSize = fontSize;
190 }
191
192 JSRef<JSVal> weight = obj->GetProperty("weight");
193 if (weight->IsString()) {
194 buttonParameters.fontWeight = ConvertStrToFontWeight(weight->ToString());
195 }
196
197 JSRef<JSVal> family = obj->GetProperty("family");
198 std::vector<std::string> fontFamilies;
199 if (ParseJsFontFamilies(family, fontFamilies)) {
200 buttonParameters.fontFamily = fontFamilies;
201 }
202
203 JSRef<JSVal> style = obj->GetProperty("style");
204 if (style->IsNumber()) {
205 auto value = style->ToNumber<int32_t>();
206 if (value >= 0 && value < static_cast<int32_t>(FONT_STYLES.size())) {
207 buttonParameters.fontStyle = FONT_STYLES[value];
208 }
209 }
210 }
211
CompleteParameters(ButtonParameters & buttonParameters)212 void JSButton::CompleteParameters(ButtonParameters& buttonParameters)
213 {
214 auto buttonTheme = GetTheme<ButtonTheme>();
215 if (!buttonTheme) {
216 return;
217 }
218 auto textStyle = buttonTheme->GetTextStyle();
219 if (!buttonParameters.maxLines.has_value()) {
220 buttonParameters.maxLines = buttonTheme->GetTextMaxLines();
221 }
222 if (!buttonParameters.minFontSize.has_value()) {
223 buttonParameters.minFontSize = buttonTheme->GetMinFontSize();
224 }
225 if (!buttonParameters.maxFontSize.has_value()) {
226 buttonParameters.maxFontSize = buttonTheme->GetMaxFontSize();
227 }
228 if (!buttonParameters.fontSize.has_value()) {
229 buttonParameters.fontSize = textStyle.GetFontSize();
230 }
231 if (!buttonParameters.fontWeight.has_value()) {
232 buttonParameters.fontWeight = textStyle.GetFontWeight();
233 }
234 if (!buttonParameters.fontStyle.has_value()) {
235 buttonParameters.fontStyle = textStyle.GetFontStyle();
236 }
237 if (!buttonParameters.heightAdaptivePolicy.has_value()) {
238 buttonParameters.heightAdaptivePolicy = TextHeightAdaptivePolicy::MAX_LINES_FIRST;
239 }
240 if (!buttonParameters.textOverflow.has_value()) {
241 buttonParameters.textOverflow = TextOverflow::CLIP;
242 }
243 }
244
SetLableStyle(const JSCallbackInfo & info)245 void JSButton::SetLableStyle(const JSCallbackInfo& info)
246 {
247 if (!info[0]->IsObject()) {
248 LOGE("info[0] not is Object");
249 return;
250 }
251
252 ButtonParameters buttonParameters;
253 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
254 JSRef<JSVal> overflowValue = obj->GetProperty("overflow");
255 buttonParameters.textOverflow = TextOverflow::ELLIPSIS;
256 if (!overflowValue->IsNull() && overflowValue->IsNumber()) {
257 auto overflow = overflowValue->ToNumber<int32_t>();
258 if (overflow >= 0 && overflow < static_cast<int32_t>(TEXT_OVERFLOWS.size()) &&
259 TEXT_OVERFLOWS[overflow] != TextOverflow::MARQUEE) {
260 buttonParameters.textOverflow = TEXT_OVERFLOWS[overflow];
261 }
262 }
263
264 JSRef<JSVal> maxLines = obj->GetProperty("maxLines");
265 if (!maxLines->IsNull() && maxLines->IsNumber()) {
266 buttonParameters.maxLines = Positive(maxLines->ToNumber<int32_t>()) ? maxLines->ToNumber<int32_t>() : 1;
267 }
268
269 JSRef<JSVal> minFontSizeValue = obj->GetProperty("minFontSize");
270 CalcDimension minFontSize;
271 if (ParseJsDimensionFp(minFontSizeValue, minFontSize)) {
272 buttonParameters.minFontSize = minFontSize;
273 }
274
275 JSRef<JSVal> maxFontSizeValue = obj->GetProperty("maxFontSize");
276 CalcDimension maxFontSize;
277 if (ParseJsDimensionFp(maxFontSizeValue, maxFontSize)) {
278 buttonParameters.maxFontSize = maxFontSize;
279 }
280
281 JSRef<JSVal> adaptHeightValue = obj->GetProperty("heightAdaptivePolicy");
282 if (!adaptHeightValue->IsNull() && adaptHeightValue->IsNumber()) {
283 auto adaptHeight = adaptHeightValue->ToNumber<int32_t>();
284 if (adaptHeight >= 0 && adaptHeight < static_cast<int32_t>(HEIGHT_ADAPTIVE_POLICY.size())) {
285 buttonParameters.heightAdaptivePolicy = HEIGHT_ADAPTIVE_POLICY[adaptHeight];
286 }
287 }
288
289 JSRef<JSVal> font = obj->GetProperty("font");
290 if (!font->IsNull() && font->IsObject()) {
291 GetFontContent(font, buttonParameters);
292 }
293
294 CompleteParameters(buttonParameters);
295 ButtonModel::GetInstance()->SetLableStyle(buttonParameters);
296 }
297
JsRemoteMessage(const JSCallbackInfo & info)298 void JSButton::JsRemoteMessage(const JSCallbackInfo& info)
299 {
300 RemoteCallback remoteCallback;
301 JSInteractableView::JsRemoteMessage(info, remoteCallback);
302 ButtonModel::GetInstance()->SetRemoteMessage(std::move(remoteCallback));
303 }
304
JSBind(BindingTarget globalObj)305 void JSButton::JSBind(BindingTarget globalObj)
306 {
307 JSClass<JSButton>::Declare("Button");
308 JSClass<JSButton>::StaticMethod("fontColor", &JSButton::SetTextColor, MethodOptions::NONE);
309 JSClass<JSButton>::StaticMethod("fontSize", &JSButton::SetFontSize, MethodOptions::NONE);
310 JSClass<JSButton>::StaticMethod("fontWeight", &JSButton::SetFontWeight, MethodOptions::NONE);
311 JSClass<JSButton>::StaticMethod("fontStyle", &JSButton::SetFontStyle, MethodOptions::NONE);
312 JSClass<JSButton>::StaticMethod("fontFamily", &JSButton::SetFontFamily, MethodOptions::NONE);
313 JSClass<JSButton>::StaticMethod("type", &JSButton::SetType, MethodOptions::NONE);
314 JSClass<JSButton>::StaticMethod("stateEffect", &JSButton::SetStateEffect, MethodOptions::NONE);
315 JSClass<JSButton>::StaticMethod("labelStyle", &JSButton::SetLableStyle, MethodOptions::NONE);
316 JSClass<JSButton>::StaticMethod("onClick", &JSButton::JsOnClick);
317 JSClass<JSButton>::StaticMethod("remoteMessage", &JSButton::JsRemoteMessage);
318 JSClass<JSButton>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
319 JSClass<JSButton>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
320 JSClass<JSButton>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
321 JSClass<JSButton>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
322 JSClass<JSButton>::StaticMethod("backgroundColor", &JSButton::JsBackgroundColor);
323 JSClass<JSButton>::StaticMethod("width", &JSButton::JsWidth);
324 JSClass<JSButton>::StaticMethod("height", &JSButton::JsHeight);
325 JSClass<JSButton>::StaticMethod("aspectRatio", &JSButton::JsAspectRatio);
326 JSClass<JSButton>::StaticMethod("borderRadius", &JSButton::JsRadius);
327 JSClass<JSButton>::StaticMethod("border", &JSButton::JsBorder);
328 JSClass<JSButton>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
329 JSClass<JSButton>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
330 JSClass<JSButton>::StaticMethod("size", &JSButton::JsSize);
331 JSClass<JSButton>::StaticMethod("padding", &JSButton::JsPadding);
332 JSClass<JSButton>::StaticMethod("hoverEffect", &JSButton::JsHoverEffect);
333
334 JSClass<JSButton>::StaticMethod("createWithLabel", &JSButton::CreateWithLabel, MethodOptions::NONE);
335 JSClass<JSButton>::StaticMethod("createWithChild", &JSButton::CreateWithChild, MethodOptions::NONE);
336 JSClass<JSButton>::InheritAndBind<JSContainerBase>(globalObj);
337 }
338
CreateWithLabel(const JSCallbackInfo & info)339 void JSButton::CreateWithLabel(const JSCallbackInfo& info)
340 {
341 std::list<RefPtr<Component>> buttonChildren;
342 std::string label;
343 bool labelSet = false;
344 CreateWithPara para;
345 para.parseSuccess = ParseJsString(info[0], label);
346 para.label = label;
347 if (info[0]->IsObject() && JSRef<JSObject>::Cast(info[0])->GetProperty("type")->IsNumber()) {
348 para.typeFirst =
349 static_cast<ButtonType>(JSRef<JSObject>::Cast(info[0])->GetProperty("type")->ToNumber<int32_t>());
350 }
351 if (info[1]->IsObject() && JSRef<JSObject>::Cast(info[1])->GetProperty("type")->IsNumber()) {
352 para.typeSecond =
353 static_cast<ButtonType>(JSRef<JSObject>::Cast(info[1])->GetProperty("type")->ToNumber<int32_t>());
354 }
355 if (info[0]->IsObject() && JSRef<JSObject>::Cast(info[0])->GetProperty("stateEffect")->IsBoolean()) {
356 para.stateEffectFirst = JSRef<JSObject>::Cast(info[0])->GetProperty("stateEffect")->ToBoolean();
357 }
358 if (info[1]->IsObject() && JSRef<JSObject>::Cast(info[1])->GetProperty("stateEffect")->IsBoolean()) {
359 para.stateEffectSecond = JSRef<JSObject>::Cast(info[1])->GetProperty("stateEffect")->ToBoolean();
360 }
361 if (para.parseSuccess.value()) {
362 labelSet = true;
363 }
364
365 para.labelSetInfoFirst = !labelSet && info[0]->IsObject();
366 para.labelSetInfoSecond = (info.Length() > 1) && info[1]->IsObject();
367 ButtonModel::GetInstance()->CreateWithLabel(para, buttonChildren);
368 ButtonModel::GetInstance()->Create(para, buttonChildren);
369 isLabelButton_ = true;
370 }
371
CreateWithChild(const JSCallbackInfo & info)372 void JSButton::CreateWithChild(const JSCallbackInfo& info)
373 {
374 CreateWithPara para;
375 para.labelSetInfoFirst = info[0]->IsObject();
376 para.labelSetInfoSecond = (info.Length() > 1) && info[1]->IsObject();
377 if (info[0]->IsObject() && JSRef<JSObject>::Cast(info[0])->GetProperty("type")->IsNumber()) {
378 para.typeFirst =
379 static_cast<ButtonType>(JSRef<JSObject>::Cast(info[0])->GetProperty("type")->ToNumber<int32_t>());
380 }
381
382 if (info[1]->IsObject() && JSRef<JSObject>::Cast(info[1])->GetProperty("type")->IsNumber()) {
383 para.typeSecond =
384 static_cast<ButtonType>(JSRef<JSObject>::Cast(info[1])->GetProperty("type")->ToNumber<int32_t>());
385 }
386
387 if (info[0]->IsObject() && JSRef<JSObject>::Cast(info[0])->GetProperty("stateEffect")->IsBoolean()) {
388 para.stateEffectFirst = JSRef<JSObject>::Cast(info[0])->GetProperty("stateEffect")->ToBoolean();
389 }
390
391 if (info[1]->IsObject() && JSRef<JSObject>::Cast(info[1])->GetProperty("stateEffect")->IsBoolean()) {
392 para.stateEffectSecond = JSRef<JSObject>::Cast(info[1])->GetProperty("stateEffect")->ToBoolean();
393 }
394 ButtonModel::GetInstance()->CreateWithChild(para);
395 isLabelButton_ = false;
396 }
397
JsPadding(const JSCallbackInfo & info)398 void JSButton::JsPadding(const JSCallbackInfo& info)
399 {
400 NG::PaddingProperty paddingNew = GetNewPadding(info);
401 Edge paddingOld = Edge(GetOldPadding(info));
402 ButtonModel::GetInstance()->Padding(paddingNew, paddingOld);
403 }
404
GetOldPadding(const JSCallbackInfo & info)405 Edge JSButton::GetOldPadding(const JSCallbackInfo& info)
406 {
407 Edge padding;
408 if (!info[0]->IsString() && !info[0]->IsNumber() && !info[0]->IsObject()) {
409 LOGE("arg is not a string, number or object.");
410 return padding;
411 }
412
413 if (info[0]->IsNumber()) {
414 CalcDimension edgeValue;
415 if (ParseJsDimensionVp(info[0], edgeValue)) {
416 padding = Edge(edgeValue);
417 }
418 } else if (info[0]->IsObject()) {
419 auto object = JsonUtil::ParseJsonString(info[0]->ToString());
420 if (!object) {
421 LOGE("Js Parse object failed. argsPtr is null.");
422 return padding;
423 }
424 CalcDimension left = CalcDimension(0.0, DimensionUnit::VP);
425 CalcDimension top = CalcDimension(0.0, DimensionUnit::VP);
426 CalcDimension right = CalcDimension(0.0, DimensionUnit::VP);
427 CalcDimension bottom = CalcDimension(0.0, DimensionUnit::VP);
428 if (object->Contains("top") || object->Contains("bottom") || object->Contains("left") ||
429 object->Contains("right")) {
430 ParseJsonDimensionVp(object->GetValue("left"), left);
431 ParseJsonDimensionVp(object->GetValue("top"), top);
432 ParseJsonDimensionVp(object->GetValue("right"), right);
433 ParseJsonDimensionVp(object->GetValue("bottom"), bottom);
434 }
435 padding = Edge(left, top, right, bottom);
436 }
437
438 return padding;
439 }
440
GetNewPadding(const JSCallbackInfo & info)441 NG::PaddingProperty JSButton::GetNewPadding(const JSCallbackInfo& info)
442 {
443 NG::PaddingProperty padding = { NG::CalcLength(0.0), NG::CalcLength(0.0), NG::CalcLength(0.0),
444 NG::CalcLength(0.0) };
445 if (isLabelButton_) {
446 auto buttonTheme = GetTheme<ButtonTheme>();
447 auto defaultPadding = buttonTheme->GetPadding();
448 padding = { NG::CalcLength(defaultPadding.Left()), NG::CalcLength(defaultPadding.Right()),
449 NG::CalcLength(defaultPadding.Top()), NG::CalcLength(defaultPadding.Bottom()) };
450 }
451 if (info[0]->IsObject()) {
452 std::optional<CalcDimension> left;
453 std::optional<CalcDimension> right;
454 std::optional<CalcDimension> top;
455 std::optional<CalcDimension> bottom;
456 JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(info[0]);
457
458 CalcDimension leftDimen;
459 if (ParseJsDimensionVp(paddingObj->GetProperty("left"), leftDimen)) {
460 left = leftDimen;
461 }
462 CalcDimension rightDimen;
463 if (ParseJsDimensionVp(paddingObj->GetProperty("right"), rightDimen)) {
464 right = rightDimen;
465 }
466 CalcDimension topDimen;
467 if (ParseJsDimensionVp(paddingObj->GetProperty("top"), topDimen)) {
468 top = topDimen;
469 }
470 CalcDimension bottomDimen;
471 if (ParseJsDimensionVp(paddingObj->GetProperty("bottom"), bottomDimen)) {
472 bottom = bottomDimen;
473 }
474 if (left.has_value() || right.has_value() || top.has_value() || bottom.has_value()) {
475 padding = SetPaddings(top, bottom, left, right);
476 return padding;
477 }
478 }
479
480 CalcDimension length(-1);
481 ParseJsDimensionVp(info[0], length);
482 if (length.IsNonNegative()) {
483 padding.SetEdges(NG::CalcLength(length));
484 }
485 return padding;
486 }
487
SetPaddings(const std::optional<CalcDimension> & top,const std::optional<CalcDimension> & bottom,const std::optional<CalcDimension> & left,const std::optional<CalcDimension> & right)488 NG::PaddingProperty JSButton::SetPaddings(const std::optional<CalcDimension>& top,
489 const std::optional<CalcDimension>& bottom, const std::optional<CalcDimension>& left,
490 const std::optional<CalcDimension>& right)
491 {
492 NG::PaddingProperty paddings;
493 if (top.has_value()) {
494 if (top.value().Unit() == DimensionUnit::CALC) {
495 paddings.top =
496 NG::CalcLength(top.value().IsNonNegative() ? top.value().CalcValue() : CalcDimension().CalcValue());
497 } else {
498 paddings.top = NG::CalcLength(top.value().IsNonNegative() ? top.value() : CalcDimension());
499 }
500 }
501 if (bottom.has_value()) {
502 if (bottom.value().Unit() == DimensionUnit::CALC) {
503 paddings.bottom = NG::CalcLength(
504 bottom.value().IsNonNegative() ? bottom.value().CalcValue() : CalcDimension().CalcValue());
505 } else {
506 paddings.bottom = NG::CalcLength(bottom.value().IsNonNegative() ? bottom.value() : CalcDimension());
507 }
508 }
509 if (left.has_value()) {
510 if (left.value().Unit() == DimensionUnit::CALC) {
511 paddings.left =
512 NG::CalcLength(left.value().IsNonNegative() ? left.value().CalcValue() : CalcDimension().CalcValue());
513 } else {
514 paddings.left = NG::CalcLength(left.value().IsNonNegative() ? left.value() : CalcDimension());
515 }
516 }
517 if (right.has_value()) {
518 if (right.value().Unit() == DimensionUnit::CALC) {
519 paddings.right =
520 NG::CalcLength(right.value().IsNonNegative() ? right.value().CalcValue() : CalcDimension().CalcValue());
521 } else {
522 paddings.right = NG::CalcLength(right.value().IsNonNegative() ? right.value() : CalcDimension());
523 }
524 }
525
526 return paddings;
527 }
528
JsOnClick(const JSCallbackInfo & info)529 void JSButton::JsOnClick(const JSCallbackInfo& info)
530 {
531 LOGD("JSButton JsOnClick");
532 if (info[0]->IsUndefined() && IsDisableEventVersion()) {
533 LOGD("JsOnClick callback is undefined");
534 ViewAbstractModel::GetInstance()->DisableOnClick();
535 return;
536 }
537 if (!info[0]->IsFunction()) {
538 LOGE("OnClick parameter need a function.");
539 return;
540 }
541
542 auto jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(info[0]));
543 auto onTap = [execCtx = info.GetExecutionContext(), func = jsOnClickFunc](GestureEvent& info) {
544 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
545 ACE_SCORING_EVENT("onClick");
546 func->Execute(info);
547 };
548
549 auto onClick = [execCtx = info.GetExecutionContext(), func = jsOnClickFunc](const ClickInfo* info) {
550 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
551 ACE_SCORING_EVENT("onClick");
552 func->Execute(*info);
553 };
554
555 ButtonModel::GetInstance()->OnClick(std::move(onTap), std::move(onClick));
556 }
557
JsBackgroundColor(const JSCallbackInfo & info)558 void JSButton::JsBackgroundColor(const JSCallbackInfo& info)
559 {
560 if (info.Length() < 1) {
561 LOGE("The argv is wrong, it is supposed to have at least 1 argument");
562 return;
563 }
564 Color backgroundColor;
565 bool colorFlag = ParseJsColor(info[0], backgroundColor);
566 if (!colorFlag) {
567 auto buttonTheme = GetTheme<ButtonTheme>();
568 if (buttonTheme) {
569 backgroundColor = buttonTheme->GetBgColor();
570 }
571 }
572
573 ButtonModel::GetInstance()->BackgroundColor(backgroundColor, colorFlag);
574 info.ReturnSelf();
575 }
576
JsWidth(const JSCallbackInfo & info)577 void JSButton::JsWidth(const JSCallbackInfo& info)
578 {
579 JSViewAbstract::JsWidth(info);
580 CalcDimension value = GetSizeValue(info);
581 if (LessNotEqual(value.Value(), 0.0)) {
582 return;
583 }
584
585 ButtonModel::GetInstance()->SetWidth(value);
586 }
587
JsHeight(const JSCallbackInfo & info)588 void JSButton::JsHeight(const JSCallbackInfo& info)
589 {
590 JSViewAbstract::JsHeight(info);
591 CalcDimension value = GetSizeValue(info);
592 if (LessNotEqual(value.Value(), 0.0)) {
593 return;
594 }
595
596 ButtonModel::GetInstance()->SetHeight(value);
597 }
598
JsAspectRatio(const JSCallbackInfo & info)599 void JSButton::JsAspectRatio(const JSCallbackInfo& info)
600 {
601 JSViewAbstract::JsAspectRatio(info);
602 if (info.Length() < 1) {
603 LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
604 return;
605 }
606 double value = 0.0;
607 if (!ParseJsDouble(info[0], value)) {
608 return;
609 }
610
611 ButtonModel::GetInstance()->SetAspectRatio(value);
612 }
613
JsSize(const JSCallbackInfo & info)614 void JSButton::JsSize(const JSCallbackInfo& info)
615 {
616 if (info.Length() < 0) {
617 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
618 return;
619 }
620
621 if (!info[0]->IsObject()) {
622 LOGE("arg is not Object or String.");
623 return;
624 }
625
626 std::optional<CalcDimension> widthInfo;
627 std::optional<CalcDimension> heightInfo;
628 JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
629 CalcDimension width;
630 if (ParseJsDimensionVp(sizeObj->GetProperty("width"), width)) {
631 widthInfo = width;
632 }
633 CalcDimension height;
634 if (ParseJsDimensionVp(sizeObj->GetProperty("height"), height)) {
635 heightInfo = height;
636 }
637
638 ButtonModel::GetInstance()->SetSize(widthInfo, heightInfo);
639 }
640
JsRadius(const JSCallbackInfo & info)641 void JSButton::JsRadius(const JSCallbackInfo& info)
642 {
643 if (info.Length() < 1) {
644 LOGE("The argv is wrong, it is supposed to have at least 1 argument");
645 return;
646 }
647 CalcDimension radius;
648 ParseJsDimensionVp(info[0], radius);
649 ButtonModel::GetInstance()->SetBorderRadius(radius);
650 HandleDifferentRadius(info[0]);
651 }
652
JsBorder(const JSCallbackInfo & info)653 void JSButton::JsBorder(const JSCallbackInfo& info)
654 {
655 JSViewAbstract::JsBorder(info);
656 if (!info[0]->IsObject()) {
657 LOGE("args is not a object. %s", info[0]->ToString().c_str());
658 return;
659 }
660 JSRef<JSObject> object = JSRef<JSObject>::Cast(info[0]);
661 CalcDimension borderRadius;
662 auto valueRadius = object->GetProperty("radius");
663 ParseJsDimensionVp(valueRadius, borderRadius);
664 ButtonModel::GetInstance()->SetBorderRadius(borderRadius);
665 HandleDifferentRadius(valueRadius);
666 }
667
GetSizeValue(const JSCallbackInfo & info)668 CalcDimension JSButton::GetSizeValue(const JSCallbackInfo& info)
669 {
670 if (info.Length() < 1) {
671 LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
672 return { -1.0 };
673 }
674 CalcDimension value;
675 if (!ParseJsDimensionVp(info[0], value)) {
676 return { -1.0 };
677 }
678 return value;
679 }
680
JsHoverEffect(const JSCallbackInfo & info)681 void JSButton::JsHoverEffect(const JSCallbackInfo& info)
682 {
683 if (!info[0]->IsNumber()) {
684 LOGE("The arg is not a number");
685 return;
686 }
687
688 auto hoverEffectNum = info[0]->ToNumber<int32_t>();
689 ButtonModel::GetInstance()->SetHoverEffect(hoverEffectNum);
690 }
691 } // namespace OHOS::Ace::Framework
692