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