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