• 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_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