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