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