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