1 /*
2 * Copyright (c) 2022 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 "core/components_ng/pattern/button/button_pattern.h"
17 #include "core/components/text/text_theme.h"
18 #include "core/components_ng/pattern/button/toggle_button_pattern.h"
19 #include "core/components/theme/shadow_theme.h"
20
21 namespace OHOS::Ace::NG {
22 namespace {
23 constexpr int32_t TOUCH_DURATION = 100;
24 constexpr int32_t MOUSE_HOVER_DURATION = 250;
25 constexpr int32_t TYPE_TOUCH = 0;
26 constexpr int32_t TYPE_HOVER = 1;
27 constexpr int32_t TYPE_CANCEL = 2;
28 constexpr float NORMAL_SCALE = 1.0f;
29 } // namespace
30
GetFocusPattern() const31 FocusPattern ButtonPattern::GetFocusPattern() const
32 {
33 if (buttonType_ == ComponentButtonType::POPUP || buttonType_ == ComponentButtonType::STEPPER) {
34 FocusPaintParam focusPaintParam;
35 focusPaintParam.SetPaintColor(focusBorderColor_);
36 return { FocusType::NODE, true, FocusStyleType::INNER_BORDER, focusPaintParam };
37 }
38 if (buttonType_ == ComponentButtonType::NAVIGATION) {
39 FocusPaintParam focusPaintParam;
40 focusPaintParam.SetPaintColor(focusBorderColor_);
41 focusPaintParam.SetPaintWidth(focusBorderWidth_);
42 return { FocusType::NODE, true, FocusStyleType::INNER_BORDER, focusPaintParam };
43 }
44 return { FocusType::NODE, true, FocusStyleType::OUTER_BORDER };
45 }
46
IsNeedAdjustByAspectRatio()47 bool ButtonPattern::IsNeedAdjustByAspectRatio()
48 {
49 auto host = GetHost();
50 CHECK_NULL_RETURN(host, false);
51 auto layoutProperty = host->GetLayoutProperty<ButtonLayoutProperty>();
52 CHECK_NULL_RETURN(host, false);
53 auto isNeedAdjust = layoutProperty->HasAspectRatio() &&
54 layoutProperty->GetType().value_or(ButtonType::CAPSULE) != ButtonType::CIRCLE;
55
56 return isNeedAdjust;
57 }
58
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const59 void ButtonPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
60 {
61 Pattern::ToJsonValue(json, filter);
62 /* no fixed attr below, just return */
63 if (filter.IsFastFilter()) {
64 return;
65 }
66 auto host = GetHost();
67 CHECK_NULL_VOID(host);
68 auto layoutProperty = host->GetLayoutProperty<ButtonLayoutProperty>();
69 CHECK_NULL_VOID(layoutProperty);
70 auto context = PipelineBase::GetCurrentContext();
71 CHECK_NULL_VOID(context);
72 auto buttonTheme = context->GetTheme<ButtonTheme>();
73 CHECK_NULL_VOID(buttonTheme);
74 auto textStyle = buttonTheme->GetTextStyle();
75 auto buttonType = layoutProperty->GetType().value_or(ButtonType::CAPSULE);
76 json->PutExtAttr("type",
77 host->GetTag() == "Toggle" ? "ToggleType.Button" : ConvertButtonTypeToString(buttonType).c_str(), filter);
78 json->PutExtAttr("fontSize",
79 layoutProperty->GetFontSizeValue(layoutProperty->HasLabel() ? textStyle.GetFontSize() : Dimension(0))
80 .ToString()
81 .c_str(),
82 filter);
83 json->PutExtAttr("fontWeight",
84 V2::ConvertWrapFontWeightToStirng(layoutProperty->GetFontWeight().value_or(FontWeight::MEDIUM)).c_str(),
85 filter);
86 json->PutExtAttr("fontColor",
87 layoutProperty->GetFontColor()
88 .value_or(layoutProperty->HasLabel() ? textStyle.GetTextColor() : Color::BLACK)
89 .ColorToString()
90 .c_str(),
91 filter);
92 json->PutExtAttr("fontStyle",
93 layoutProperty->GetFontStyle().value_or(Ace::FontStyle::NORMAL) == Ace::FontStyle::NORMAL ? "FontStyle.Normal"
94 : "FontStyle.Italic",
95 filter);
96 json->PutExtAttr("label", layoutProperty->GetLabelValue("").c_str(), filter);
97 auto eventHub = host->GetEventHub<ButtonEventHub>();
98 CHECK_NULL_VOID(eventHub);
99 json->PutExtAttr("stateEffect", eventHub->GetStateEffect() ? "true" : "false", filter);
100
101 auto optionJson = JsonUtil::Create(true);
102 optionJson->Put("type", ConvertButtonTypeToString(layoutProperty->GetType().value_or(ButtonType::CAPSULE)).c_str());
103
104 optionJson->Put("stateEffect", eventHub->GetStateEffect() ? "true" : "false");
105 json->PutExtAttr("options", optionJson->ToString().c_str(), filter);
106 ToJsonValueAttribute(json, filter);
107 }
108
ToJsonValueAttribute(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const109 void ButtonPattern::ToJsonValueAttribute(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
110 {
111 auto host = GetHost();
112 CHECK_NULL_VOID(host);
113 auto layoutProperty = host->GetLayoutProperty<ButtonLayoutProperty>();
114 CHECK_NULL_VOID(layoutProperty);
115 auto fontFamilyVector = layoutProperty->GetFontFamily().value_or<std::vector<std::string>>({ "HarmonyOS Sans" });
116 std::string fontFamily;
117 if (!fontFamilyVector.empty()) {
118 fontFamily = fontFamilyVector.at(0);
119 for (uint32_t i = 1; i < fontFamilyVector.size(); ++i) {
120 fontFamily += ',' + fontFamilyVector.at(i);
121 }
122 }
123 json->PutExtAttr("fontFamily", fontFamily.c_str(), filter);
124 auto fontJsValue = JsonUtil::Create(true);
125 fontJsValue->Put("size", layoutProperty->GetFontSizeValue(Dimension(0)).ToString().c_str());
126 fontJsValue->Put("weight",
127 V2::ConvertWrapFontWeightToStirng(layoutProperty->GetFontWeight().value_or(FontWeight::MEDIUM)).c_str());
128 fontJsValue->Put("family", fontFamily.c_str());
129 fontJsValue->Put("style", layoutProperty->GetFontStyle().value_or(Ace::FontStyle::NORMAL) == Ace::FontStyle::NORMAL
130 ? "FontStyle.Normal"
131 : "FontStyle.Italic");
132 auto labelJsValue = JsonUtil::Create(true);
133 labelJsValue->Put("overflow",
134 V2::ConvertWrapTextOverflowToString(layoutProperty->GetTextOverflow().value_or(TextOverflow::CLIP)).c_str());
135 labelJsValue->Put("maxLines", std::to_string(layoutProperty->GetMaxLines().value_or(DEFAULT_MAXLINES)).c_str());
136 labelJsValue->Put("minFontSize", layoutProperty->GetMinFontSizeValue(Dimension(0)).ToString().c_str());
137 labelJsValue->Put("maxFontSize", layoutProperty->GetMaxFontSizeValue(Dimension(0)).ToString().c_str());
138 labelJsValue->Put("heightAdaptivePolicy",
139 V2::ConvertWrapTextHeightAdaptivePolicyToString(
140 layoutProperty->GetHeightAdaptivePolicy().value_or(TextHeightAdaptivePolicy::MAX_LINES_FIRST))
141 .c_str());
142 labelJsValue->Put("font", fontJsValue->ToString().c_str());
143 json->PutExtAttr("labelStyle", labelJsValue->ToString().c_str(), filter);
144
145 json->PutExtAttr("buttonStyle",
146 ConvertButtonStyleToString(layoutProperty->GetButtonStyle().value_or(ButtonStyleMode::EMPHASIZE)).c_str(),
147 filter);
148 json->PutExtAttr("controlSize",
149 ConvertControlSizeToString(layoutProperty->GetControlSize().value_or(ControlSize::NORMAL)).c_str(), filter);
150 json->PutExtAttr("role",
151 ConvertButtonRoleToString(layoutProperty->GetButtonRole().value_or(ButtonRole::NORMAL)).c_str(), filter);
152 }
153
ConvertButtonRoleToString(ButtonRole buttonRole)154 std::string ButtonPattern::ConvertButtonRoleToString(ButtonRole buttonRole)
155 {
156 std::string result;
157 switch (buttonRole) {
158 case ButtonRole::NORMAL:
159 result = "ButtonRole.NORMAL";
160 break;
161 case ButtonRole::ERROR:
162 result = "ButtonRole.ERROR";
163 break;
164 default:
165 break;
166 }
167 return result;
168 }
169
ConvertButtonTypeToString(ButtonType buttonType)170 std::string ButtonPattern::ConvertButtonTypeToString(ButtonType buttonType)
171 {
172 std::string result;
173 switch (buttonType) {
174 case ButtonType::NORMAL:
175 result = "ButtonType.Normal";
176 break;
177 case ButtonType::CAPSULE:
178 result = "ButtonType.Capsule";
179 break;
180 case ButtonType::CIRCLE:
181 result = "ButtonType.Circle";
182 break;
183 case ButtonType::ROUNDED_RECTANGLE:
184 result = "ButtonType.ROUNDED_RECTANGLE";
185 break;
186 default:
187 break;
188 }
189 return result;
190 }
191
ConvertButtonStyleToString(ButtonStyleMode buttonStyle)192 std::string ButtonPattern::ConvertButtonStyleToString(ButtonStyleMode buttonStyle)
193 {
194 std::string result;
195 switch (buttonStyle) {
196 case ButtonStyleMode::NORMAL:
197 result = "ButtonStyleMode.NORMAL";
198 break;
199 case ButtonStyleMode::EMPHASIZE:
200 result = "ButtonStyleMode.EMPHASIZED";
201 break;
202 case ButtonStyleMode::TEXT:
203 result = "ButtonStyleMode.TEXTUAL";
204 break;
205 default:
206 break;
207 }
208 return result;
209 }
210
ConvertControlSizeToString(ControlSize controlSize)211 std::string ButtonPattern::ConvertControlSizeToString(ControlSize controlSize)
212 {
213 std::string result;
214 switch (controlSize) {
215 case ControlSize::SMALL:
216 result = "ControlSize.SMALL";
217 break;
218 case ControlSize::NORMAL:
219 result = "ControlSize.NORMAL";
220 break;
221 default:
222 break;
223 }
224 return result;
225 }
226
GetColorFromType(const RefPtr<ButtonTheme> & theme,const int32_t & type)227 Color ButtonPattern::GetColorFromType(const RefPtr<ButtonTheme>& theme, const int32_t& type)
228 {
229 if (type == TYPE_TOUCH) {
230 return blendClickColor_.value_or(theme->GetClickedColor());
231 } else if (type == TYPE_HOVER) {
232 return blendHoverColor_.value_or(theme->GetHoverColor());
233 } else {
234 return Color::TRANSPARENT;
235 }
236 }
237
OnAttachToFrameNode()238 void ButtonPattern::OnAttachToFrameNode()
239 {
240 auto host = GetHost();
241 CHECK_NULL_VOID(host);
242 auto* pipeline = host->GetContextWithCheck();
243 CHECK_NULL_VOID(pipeline);
244 auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
245 CHECK_NULL_VOID(buttonTheme);
246 clickedColor_ = buttonTheme->GetClickedColor();
247 auto renderContext = host->GetRenderContext();
248 CHECK_NULL_VOID(renderContext);
249 renderContext->SetAlphaOffscreen(true);
250 }
251
NeedAgingUpdateText(RefPtr<ButtonLayoutProperty> & layoutProperty)252 bool ButtonPattern::NeedAgingUpdateText(RefPtr<ButtonLayoutProperty>& layoutProperty)
253 {
254 CHECK_NULL_RETURN(layoutProperty, false);
255 auto pipeline = NG::PipelineContext::GetCurrentContextSafely();
256 CHECK_NULL_RETURN(pipeline, false);
257 auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
258 CHECK_NULL_RETURN(buttonTheme, false);
259 auto fontScale = pipeline->GetFontScale();
260
261 if (layoutProperty->HasType() && layoutProperty->GetType() == ButtonType::CIRCLE) {
262 return false;
263 }
264
265 if (layoutProperty->HasLabel() && layoutProperty->GetLabel()->empty()) {
266 return false;
267 }
268
269 if (layoutProperty->HasFontSize() && layoutProperty->GetFontSize()->Unit() != DimensionUnit::FP) {
270 return false;
271 }
272 const auto& calcConstraint = layoutProperty->GetCalcLayoutConstraint();
273 if (calcConstraint && calcConstraint->selfIdealSize->Height().has_value() &&
274 calcConstraint->selfIdealSize->Width().has_value()) {
275 return false;
276 }
277 if (!(NearEqual(fontScale, buttonTheme->GetBigFontSizeScale()) ||
278 NearEqual(fontScale, buttonTheme->GetLargeFontSizeScale()) ||
279 NearEqual(fontScale, buttonTheme->GetMaxFontSizeScale()))) {
280 return false;
281 }
282 return true;
283 }
284
UpdateTextLayoutProperty(RefPtr<ButtonLayoutProperty> & layoutProperty,RefPtr<TextLayoutProperty> & textLayoutProperty)285 void ButtonPattern::UpdateTextLayoutProperty(
286 RefPtr<ButtonLayoutProperty>& layoutProperty, RefPtr<TextLayoutProperty>& textLayoutProperty)
287 {
288 CHECK_NULL_VOID(layoutProperty);
289 CHECK_NULL_VOID(textLayoutProperty);
290 UpdateTextFontScale(layoutProperty, textLayoutProperty);
291 auto label = layoutProperty->GetLabelValue("");
292 textLayoutProperty->UpdateContent(label);
293 if (layoutProperty->GetFontSize().has_value()) {
294 textLayoutProperty->UpdateFontSize(layoutProperty->GetFontSize().value());
295 }
296 if (layoutProperty->GetFontWeight().has_value()) {
297 textLayoutProperty->UpdateFontWeight(layoutProperty->GetFontWeight().value());
298 }
299 if (layoutProperty->GetFontColor().has_value()) {
300 textLayoutProperty->UpdateTextColor(layoutProperty->GetFontColor().value());
301 }
302 if (layoutProperty->GetFontStyle().has_value()) {
303 textLayoutProperty->UpdateItalicFontStyle(layoutProperty->GetFontStyle().value());
304 }
305 if (layoutProperty->GetFontFamily().has_value()) {
306 textLayoutProperty->UpdateFontFamily(layoutProperty->GetFontFamily().value());
307 }
308
309 auto pipeline = NG::PipelineContext::GetCurrentContextSafely();
310 CHECK_NULL_VOID(pipeline);
311 auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
312 CHECK_NULL_VOID(buttonTheme);
313 if (NeedAgingUpdateText(layoutProperty)) {
314 textLayoutProperty->UpdateMaxLines(buttonTheme->GetAgingTextMaxLines());
315 } else {
316 textLayoutProperty->UpdateMaxLines(buttonTheme->GetTextMaxLines());
317 }
318
319 if (layoutProperty->GetTextOverflow().has_value()) {
320 textLayoutProperty->UpdateTextOverflow(layoutProperty->GetTextOverflow().value());
321 }
322 if (layoutProperty->GetMaxLines().has_value()) {
323 textLayoutProperty->UpdateMaxLines(layoutProperty->GetMaxLines().value());
324 }
325 if (layoutProperty->GetMinFontSize().has_value()) {
326 textLayoutProperty->UpdateAdaptMinFontSize(layoutProperty->GetMinFontSize().value());
327 }
328 if (layoutProperty->GetMaxFontSize().has_value()) {
329 textLayoutProperty->UpdateAdaptMaxFontSize(layoutProperty->GetMaxFontSize().value());
330 }
331 if (layoutProperty->GetHeightAdaptivePolicy().has_value()) {
332 textLayoutProperty->UpdateHeightAdaptivePolicy(layoutProperty->GetHeightAdaptivePolicy().value());
333 }
334 // update text style defined by buttonStyle and control size
335 UpdateTextStyle(layoutProperty, textLayoutProperty);
336 }
337
UpdateTextStyle(RefPtr<ButtonLayoutProperty> & layoutProperty,RefPtr<TextLayoutProperty> & textLayoutProperty)338 void ButtonPattern::UpdateTextStyle(
339 RefPtr<ButtonLayoutProperty>& layoutProperty, RefPtr<TextLayoutProperty>& textLayoutProperty)
340 {
341 auto host = layoutProperty->GetHost();
342 CHECK_NULL_VOID(host);
343 auto* pipeline = host->GetContextWithCheck();
344 CHECK_NULL_VOID(pipeline);
345 auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
346 CHECK_NULL_VOID(buttonTheme);
347 if (!textLayoutProperty->HasTextColor()) {
348 ButtonStyleMode buttonStyle = layoutProperty->GetButtonStyle().value_or(ButtonStyleMode::EMPHASIZE);
349 ButtonRole buttonRole = layoutProperty->GetButtonRole().value_or(ButtonRole::NORMAL);
350 Color fontColor = buttonTheme->GetTextColor(buttonStyle, buttonRole);
351 textLayoutProperty->UpdateTextColor(fontColor);
352 }
353 if (!textLayoutProperty->HasFontSize()) {
354 ControlSize controlSize = layoutProperty->GetControlSize().value_or(ControlSize::NORMAL);
355 Dimension fontSize = buttonTheme->GetTextSize(controlSize);
356 textLayoutProperty->UpdateFontSize(fontSize);
357 }
358 }
359
IsNeedToHandleHoverOpacity()360 bool ButtonPattern::IsNeedToHandleHoverOpacity()
361 {
362 auto host = GetHost();
363 CHECK_NULL_RETURN(host, false);
364 auto inputEventHub = host->GetOrCreateInputEventHub();
365 auto hoverEffect = inputEventHub->GetHoverEffect();
366 return isHover_ && hoverEffect != HoverEffectType::BOARD && hoverEffect != HoverEffectType::SCALE &&
367 hoverEffect != HoverEffectType::NONE;
368 }
369
InitButtonLabel()370 void ButtonPattern::InitButtonLabel()
371 {
372 auto host = GetHost();
373 CHECK_NULL_VOID(host);
374 auto focusHub = host->GetFocusHub();
375 CHECK_NULL_VOID(focusHub);
376 auto layoutProperty = GetLayoutProperty<ButtonLayoutProperty>();
377 CHECK_NULL_VOID(layoutProperty);
378 if (!layoutProperty->GetLabel().has_value()) {
379 focusHub->SetFocusType(FocusType::SCOPE);
380 return;
381 }
382 focusHub->SetFocusType(FocusType::NODE);
383 auto textNode = DynamicCast<FrameNode>(host->GetFirstChild());
384 CHECK_NULL_VOID(textNode);
385 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
386 CHECK_NULL_VOID(textLayoutProperty);
387 UpdateTextLayoutProperty(layoutProperty, textLayoutProperty);
388 auto buttonRenderContext = host->GetRenderContext();
389 CHECK_NULL_VOID(buttonRenderContext);
390 auto textRenderContext = textNode->GetRenderContext();
391 CHECK_NULL_VOID(textRenderContext);
392 if (layoutProperty->HasType() && layoutProperty->GetType() == ButtonType::CIRCLE) {
393 textRenderContext->UpdateClipEdge(buttonRenderContext->GetClipEdgeValue(false));
394 } else {
395 textRenderContext->UpdateClipEdge(buttonRenderContext->GetClipEdgeValue(true));
396 }
397
398 auto pipeline = host->GetContextRefPtr();
399 CHECK_NULL_VOID(pipeline);
400 auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
401 CHECK_NULL_VOID(buttonTheme);
402 if (buttonTheme->GetIsApplyTextFontSize()) {
403 ControlSize controlSize = layoutProperty->GetControlSize().value_or(ControlSize::NORMAL);
404 if (textLayoutProperty->GetFontSize() == buttonTheme->GetTextSize(controlSize) ||
405 textLayoutProperty->GetFontSize() == buttonTheme->GetTextButtonFontSize()) {
406 ButtonStyleMode buttonStyle = layoutProperty->GetButtonStyle().value_or(ButtonStyleMode::EMPHASIZE);
407 Dimension fontSize = (buttonStyle == ButtonStyleMode::TEXT && controlSize == ControlSize::NORMAL) ?
408 buttonTheme->GetTextButtonFontSize() : buttonTheme->GetTextSize(controlSize);
409 textLayoutProperty->UpdateFontSize(fontSize);
410 }
411 }
412 textNode->MarkModifyDone();
413 textNode->MarkDirtyNode();
414 auto textTheme = pipeline->GetTheme<TextTheme>();
415 CHECK_NULL_VOID(textTheme);
416 isTextFadeOut_ = textTheme->GetIsTextFadeout();
417 UpdateTexOverflow(isHover_);
418 }
419
OnModifyDone()420 void ButtonPattern::OnModifyDone()
421 {
422 Pattern::OnModifyDone();
423 CheckLocalizedBorderRadiuses();
424 FireBuilder();
425 InitButtonLabel();
426 HandleBackgroundColor();
427 HandleEnabled();
428 InitHoverEvent();
429 InitTouchEvent();
430 HandleBorderAndShadow();
431 HandleFocusStatusStyle();
432 HandleFocusActiveStyle();
433 }
434
CheckLocalizedBorderRadiuses()435 void ButtonPattern::CheckLocalizedBorderRadiuses()
436 {
437 auto host = GetHost();
438 CHECK_NULL_VOID(host);
439 const auto& property = host->GetLayoutProperty<ButtonLayoutProperty>();
440 CHECK_NULL_VOID(property);
441 auto direction = property->GetNonAutoLayoutDirection();
442 BorderRadiusProperty borderRadius;
443 BorderRadiusProperty borderRadiusProperty = property->GetBorderRadiusValue(BorderRadiusProperty {});
444 if (!borderRadiusProperty.radiusTopStart.has_value() && !borderRadiusProperty.radiusTopEnd.has_value() &&
445 !borderRadiusProperty.radiusBottomStart.has_value() && !borderRadiusProperty.radiusBottomEnd.has_value()) {
446 return;
447 }
448 if (borderRadiusProperty.radiusTopStart.has_value()) {
449 borderRadius.radiusTopStart = borderRadiusProperty.radiusTopStart;
450 if (direction == TextDirection::RTL) {
451 borderRadius.radiusTopRight = borderRadiusProperty.radiusTopStart;
452 } else {
453 borderRadius.radiusTopLeft = borderRadiusProperty.radiusTopStart;
454 }
455 }
456 if (borderRadiusProperty.radiusTopEnd.has_value()) {
457 borderRadius.radiusTopEnd = borderRadiusProperty.radiusTopEnd;
458 if (direction == TextDirection::RTL) {
459 borderRadius.radiusTopLeft = borderRadiusProperty.radiusTopEnd;
460 } else {
461 borderRadius.radiusTopRight = borderRadiusProperty.radiusTopEnd;
462 }
463 }
464 if (borderRadiusProperty.radiusBottomStart.has_value()) {
465 borderRadius.radiusBottomStart = borderRadiusProperty.radiusBottomStart;
466 if (direction == TextDirection::RTL) {
467 borderRadius.radiusBottomRight = borderRadiusProperty.radiusBottomStart;
468 } else {
469 borderRadius.radiusBottomLeft = borderRadiusProperty.radiusBottomStart;
470 }
471 }
472 if (borderRadiusProperty.radiusBottomEnd.has_value()) {
473 borderRadius.radiusBottomEnd = borderRadiusProperty.radiusBottomEnd;
474 if (direction == TextDirection::RTL) {
475 borderRadius.radiusBottomLeft = borderRadiusProperty.radiusBottomEnd;
476 } else {
477 borderRadius.radiusBottomRight = borderRadiusProperty.radiusBottomEnd;
478 }
479 }
480 property->UpdateBorderRadius(borderRadius);
481 }
482
InitTouchEvent()483 void ButtonPattern::InitTouchEvent()
484 {
485 if (touchListener_) {
486 return;
487 }
488 auto host = GetHost();
489 CHECK_NULL_VOID(host);
490 auto gesture = host->GetOrCreateGestureEventHub();
491 CHECK_NULL_VOID(gesture);
492 auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
493 auto buttonPattern = weak.Upgrade();
494 CHECK_NULL_VOID(buttonPattern);
495 if (info.GetTouches().empty()) {
496 return;
497 }
498 if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
499 TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "button touch down");
500 buttonPattern->OnTouchDown();
501 buttonPattern->UpdateTexOverflow(!(buttonPattern->isPress_));
502 }
503 if (info.GetTouches().front().GetTouchType() == TouchType::UP ||
504 info.GetTouches().front().GetTouchType() == TouchType::CANCEL) {
505 TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "button touch up");
506 buttonPattern->OnTouchUp();
507 buttonPattern->UpdateTexOverflow(buttonPattern->isHover_ || buttonPattern->isFocus_);
508 }
509 };
510 touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
511 gesture->AddTouchEvent(touchListener_);
512 }
513
OnAfterModifyDone()514 void ButtonPattern::OnAfterModifyDone()
515 {
516 auto host = GetHost();
517 CHECK_NULL_VOID(host);
518 auto inspectorId = host->GetInspectorId().value_or("");
519 if (!inspectorId.empty()) {
520 auto text = host->GetAccessibilityProperty<NG::AccessibilityProperty>()->GetText();
521 Recorder::NodeDataCache::Get().PutString(host, inspectorId, text);
522 }
523 }
524
InitHoverEvent()525 void ButtonPattern::InitHoverEvent()
526 {
527 if (UseContentModifier()) {
528 return;
529 }
530 auto host = GetHost();
531 CHECK_NULL_VOID(host);
532 auto eventHub = host->GetEventHub<ButtonEventHub>();
533 auto inputHub = eventHub->GetOrCreateInputEventHub();
534 auto hoverEffect = inputHub->GetHoverEffect();
535 inputHub->SetHoverEffect(hoverEffect == HoverEffectType::BOARD ? HoverEffectType::AUTO : hoverEffect);
536 if (hoverListener_) {
537 return;
538 }
539 auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
540 TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "button hover %{public}d", isHover);
541 auto pattern = weak.Upgrade();
542 if (pattern) {
543 pattern->HandleHoverEvent(isHover);
544 }
545 };
546
547 hoverListener_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
548 inputHub->AddOnHoverEvent(hoverListener_);
549 }
550
OnTouchDown()551 void ButtonPattern::OnTouchDown()
552 {
553 isPress_ = true;
554 FireBuilder();
555 if (UseContentModifier()) {
556 return;
557 }
558 auto host = GetHost();
559 CHECK_NULL_VOID(host);
560 auto buttonEventHub = GetEventHub<ButtonEventHub>();
561 CHECK_NULL_VOID(buttonEventHub);
562 if (buttonEventHub->GetStateEffect()) {
563 auto renderContext = host->GetRenderContext();
564 CHECK_NULL_VOID(renderContext);
565 backgroundColor_ = renderContext->GetBackgroundColor().value_or(Color::TRANSPARENT);
566 if (isSetClickedColor_) {
567 // for user self-defined
568 renderContext->UpdateBackgroundColor(clickedColor_);
569 return;
570 }
571 // for system default
572 auto isNeedToHandleHoverOpacity = IsNeedToHandleHoverOpacity();
573 AnimateTouchAndHover(renderContext, isNeedToHandleHoverOpacity ? TYPE_HOVER : TYPE_CANCEL, TYPE_TOUCH,
574 TOUCH_DURATION, isNeedToHandleHoverOpacity ? Curves::SHARP : Curves::FRICTION);
575 }
576 }
577
OnTouchUp()578 void ButtonPattern::OnTouchUp()
579 {
580 isPress_ = false;
581 FireBuilder();
582 if (UseContentModifier()) {
583 return;
584 }
585 auto host = GetHost();
586 CHECK_NULL_VOID(host);
587 auto buttonEventHub = GetEventHub<ButtonEventHub>();
588 CHECK_NULL_VOID(buttonEventHub);
589 auto toggleButtonPattern = host->GetPattern<ToggleButtonPattern>();
590 if (toggleButtonPattern) {
591 toggleButtonPattern->OnClick();
592 }
593 if (buttonEventHub->GetStateEffect()) {
594 auto renderContext = host->GetRenderContext();
595 if (isSetClickedColor_) {
596 renderContext->UpdateBackgroundColor(backgroundColor_);
597 return;
598 }
599 if (buttonEventHub->IsEnabled()) {
600 auto isNeedToHandleHoverOpacity = IsNeedToHandleHoverOpacity();
601 AnimateTouchAndHover(renderContext, TYPE_TOUCH, isNeedToHandleHoverOpacity ? TYPE_HOVER : TYPE_CANCEL,
602 TOUCH_DURATION, isNeedToHandleHoverOpacity ? Curves::SHARP : Curves::FRICTION);
603 } else {
604 AnimateTouchAndHover(renderContext, TYPE_TOUCH, TYPE_CANCEL, TOUCH_DURATION, Curves::FRICTION);
605 }
606 }
607 }
608
HandleHoverEvent(bool isHover)609 void ButtonPattern::HandleHoverEvent(bool isHover)
610 {
611 isHover_ = isHover;
612 auto host = GetHost();
613 CHECK_NULL_VOID(host);
614 auto eventHub = host->GetEventHub<EventHub>();
615 CHECK_NULL_VOID(eventHub);
616 auto enabled = eventHub->IsEnabled();
617 auto inputEventHub = host->GetOrCreateInputEventHub();
618 auto hoverEffect = inputEventHub->GetHoverEffect();
619 if (hoverEffect == HoverEffectType::NONE || hoverEffect == HoverEffectType::SCALE) {
620 return;
621 }
622 if (!isPress_ && (enabled || !isHover)) {
623 auto renderContext = host->GetRenderContext();
624 CHECK_NULL_VOID(renderContext);
625 AnimateTouchAndHover(renderContext, isHover ? TYPE_CANCEL : TYPE_HOVER, isHover ? TYPE_HOVER : TYPE_CANCEL,
626 MOUSE_HOVER_DURATION, Curves::FRICTION);
627 if (isHover) {
628 auto pipeline = host->GetContextRefPtr();
629 CHECK_NULL_VOID(pipeline);
630 auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
631 SetButtonScale(renderContext, buttonTheme);
632 } else {
633 if (scaleModify_) {
634 scaleModify_ = false;
635 renderContext->SetScale(1.0f, 1.0f);
636 }
637 }
638 }
639 UpdateTexOverflow(isHover || isFocus_);
640 }
641
HandleBackgroundColor()642 void ButtonPattern::HandleBackgroundColor()
643 {
644 auto host = GetHost();
645 CHECK_NULL_VOID(host);
646 auto* pipeline = host->GetContextWithCheck();
647 CHECK_NULL_VOID(pipeline);
648 auto renderContext = host->GetRenderContext();
649 CHECK_NULL_VOID(renderContext);
650 auto layoutProperty = GetLayoutProperty<ButtonLayoutProperty>();
651 CHECK_NULL_VOID(layoutProperty);
652 auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
653 CHECK_NULL_VOID(buttonTheme);
654 ButtonStyleMode buttonStyle = layoutProperty->GetButtonStyle().value_or(ButtonStyleMode::EMPHASIZE);
655 ButtonRole buttonRole = layoutProperty->GetButtonRole().value_or(ButtonRole::NORMAL);
656 if (UseContentModifier()) {
657 renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
658 renderContext->ResetBackgroundColor();
659 return;
660 }
661
662 if (!renderContext->HasBackgroundColor()) {
663 renderContext->UpdateBackgroundColor(buttonTheme->GetBgColor(buttonStyle, buttonRole));
664 }
665 themeBgColor_ = buttonTheme->GetBgColor(buttonStyle, buttonRole);
666 themeTextColor_ = buttonTheme->GetTextColor(buttonStyle, buttonRole);
667 }
668
GetShadowFromTheme(ShadowStyle shadowStyle)669 Shadow ButtonPattern::GetShadowFromTheme(ShadowStyle shadowStyle)
670 {
671 auto host = GetHost();
672 CHECK_NULL_RETURN(host, Shadow::CreateShadow(shadowStyle));
673 auto pipeline = host->GetContextRefPtr();
674 CHECK_NULL_RETURN(pipeline, Shadow::CreateShadow(shadowStyle));
675 auto shadowTheme = pipeline->GetTheme<ShadowTheme>();
676 CHECK_NULL_RETURN(shadowTheme, Shadow::CreateShadow(shadowStyle));
677 auto colorMode = pipeline->GetColorMode();
678 return shadowTheme->GetShadow(shadowStyle, colorMode);
679 }
680
HandleShadowStyle(ButtonStyleMode buttonStyle,ShadowStyle shadowStyle,RefPtr<RenderContext> & renderContext,RefPtr<ButtonTheme> & buttonTheme)681 void ButtonPattern::HandleShadowStyle(ButtonStyleMode buttonStyle, ShadowStyle shadowStyle,
682 RefPtr<RenderContext>& renderContext, RefPtr<ButtonTheme>& buttonTheme)
683 {
684 if (shadowStyle != ShadowStyle::None && isApplyShadow_) {
685 auto&& graphics = renderContext->GetOrCreateGraphics();
686 CHECK_NULL_VOID(graphics);
687 auto normalShadow = GetShadowFromTheme(static_cast<ShadowStyle>(buttonTheme->GetShadowNormal()));
688 if (!graphics->HasBackShadow() || graphics->GetBackShadowValue() == normalShadow) {
689 auto shadow = GetShadowFromTheme(
690 buttonStyle == ButtonStyleMode::TEXT ? ShadowStyle::None : shadowStyle);
691 renderContext->UpdateBackShadow(shadow);
692 }
693 }
694 }
695
HandleBorderAndShadow()696 void ButtonPattern::HandleBorderAndShadow()
697 {
698 if (UseContentModifier()) {
699 return;
700 }
701 auto host = GetHost();
702 CHECK_NULL_VOID(host);
703 auto renderContext = host->GetRenderContext();
704 CHECK_NULL_VOID(renderContext);
705 auto layoutProperty = GetLayoutProperty<ButtonLayoutProperty>();
706 CHECK_NULL_VOID(layoutProperty);
707 auto pipeline = host->GetContextRefPtr();
708 CHECK_NULL_VOID(pipeline);
709 auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
710 CHECK_NULL_VOID(buttonTheme);
711
712 ButtonStyleMode buttonStyle = layoutProperty->GetButtonStyle().value_or(ButtonStyleMode::EMPHASIZE);
713 ShadowStyle shadowStyle = static_cast<ShadowStyle>(buttonTheme->GetShadowNormal());
714 HandleShadowStyle(buttonStyle, shadowStyle, renderContext, buttonTheme);
715
716 if (!layoutProperty->GetBorderWidthProperty() || isLayoutUpdate_) {
717 ControlSize controlSize = layoutProperty->GetControlSize().value_or(ControlSize::NORMAL);
718 Dimension borderWidth = controlSize == ControlSize::NORMAL ?
719 buttonTheme->GetBorderWidth() : buttonTheme->GetBorderWidthSmall();
720 if (borderWidth.ConvertToPx() <= 0) {
721 return;
722 }
723 BorderWidthProperty borderWidthProperty;
724 borderWidthProperty.SetBorderWidth(0.0_vp);
725 if (!renderContext->HasBorderWidth() ||
726 IsDynamicSwitchButtonStyle(renderContext->GetBorderWidthValue(borderWidthProperty), buttonTheme)) {
727 borderWidthProperty.SetBorderWidth(buttonStyle == ButtonStyleMode::NORMAL ? borderWidth : 0.0_vp);
728 layoutProperty->UpdateBorderWidth(borderWidthProperty);
729 renderContext->UpdateBorderWidth(borderWidthProperty);
730 isLayoutUpdate_ = true;
731 }
732
733 BorderColorProperty borderColorProperty;
734 borderColorProperty.SetColor(Color());
735 if (!renderContext->HasBorderColor() ||
736 IsDynamicSwitchButtonStyle(renderContext->GetBorderColorValue(borderColorProperty), buttonTheme)) {
737 Color borderColor = controlSize == ControlSize::NORMAL ?
738 buttonTheme->GetBorderColor() : buttonTheme->GetBorderColorSmall();
739 borderColorProperty.SetColor(borderColor);
740 renderContext->UpdateBorderColor(borderColorProperty);
741 }
742 return;
743 }
744 isLayoutUpdate_ = false;
745 }
746
IsDynamicSwitchButtonStyle(const BorderColorProperty & color,RefPtr<ButtonTheme> & buttonTheme)747 bool ButtonPattern::IsDynamicSwitchButtonStyle(const BorderColorProperty& color, RefPtr<ButtonTheme>& buttonTheme)
748 {
749 Color normalColor = buttonTheme->GetBorderColor();
750 Color smallColor = buttonTheme->GetBorderColorSmall();
751 BorderColorProperty borderColorProperty;
752 borderColorProperty.SetColor(Color());
753 BorderColorProperty normalColorProperty;
754 normalColorProperty.SetColor(normalColor);
755 BorderColorProperty smallColorProperty;
756 smallColorProperty.SetColor(smallColor);
757 if (color == normalColorProperty || color == smallColorProperty || color == borderColorProperty) {
758 return true;
759 }
760 return false;
761 }
762
IsDynamicSwitchButtonStyle(const BorderWidthProperty & width,RefPtr<ButtonTheme> & buttonTheme)763 bool ButtonPattern::IsDynamicSwitchButtonStyle(const BorderWidthProperty& width, RefPtr<ButtonTheme>& buttonTheme)
764 {
765 Dimension normalWidth = buttonTheme->GetBorderWidth();
766 Dimension smallWidth = buttonTheme->GetBorderWidthSmall();
767 BorderWidthProperty borderWidthProperty;
768 borderWidthProperty.SetBorderWidth(Dimension());
769 BorderWidthProperty normalWidthProperty;
770 normalWidthProperty.SetBorderWidth(normalWidth);
771 BorderWidthProperty smallWidthProperty;
772 smallWidthProperty.SetBorderWidth(smallWidth);
773 if (width == normalWidthProperty || width == smallWidthProperty || width == borderWidthProperty) {
774 return true;
775 }
776 return false;
777 }
778
UpdateTexOverflow(bool isMarqueeStart)779 void ButtonPattern::UpdateTexOverflow(bool isMarqueeStart)
780 {
781 if (isTextFadeOut_) {
782 auto host = GetHost();
783 CHECK_NULL_VOID(host);
784 auto textNode = DynamicCast<FrameNode>(host->GetFirstChild());
785 CHECK_NULL_VOID(textNode);
786 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
787 CHECK_NULL_VOID(textLayoutProperty);
788 textLayoutProperty->UpdateTextOverflow(TextOverflow::MARQUEE);
789 textLayoutProperty->UpdateTextMarqueeFadeout(true);
790 textLayoutProperty->UpdateTextMarqueeStart(isMarqueeStart);
791 textLayoutProperty->UpdateTextMarqueeStartPolicy(MarqueeStartPolicy::DEFAULT);
792 auto layoutProperty = GetLayoutProperty<ButtonLayoutProperty>();
793 CHECK_NULL_VOID(layoutProperty);
794 if (layoutProperty->GetTextOverflow().has_value()) {
795 textLayoutProperty->UpdateTextOverflow(layoutProperty->GetTextOverflow().value());
796 }
797 textNode->MarkDirtyNode();
798 }
799 }
800
HandleFocusActiveStyle()801 void ButtonPattern::HandleFocusActiveStyle()
802 {
803 if (UseContentModifier()) {
804 return;
805 }
806 auto host = GetHost();
807 CHECK_NULL_VOID(host);
808 auto pipeline = host->GetContextRefPtr();
809 CHECK_NULL_VOID(pipeline);
810 if (pipeline->GetIsFocusActive()) {
811 UpdateButtonStyle();
812 }
813 }
814
HandleEnabled()815 void ButtonPattern::HandleEnabled()
816 {
817 if (UseContentModifier()) {
818 return;
819 }
820 auto host = GetHost();
821 CHECK_NULL_VOID(host);
822 auto eventHub = host->GetEventHub<EventHub>();
823 CHECK_NULL_VOID(eventHub);
824 auto enabled = eventHub->IsEnabled();
825 auto renderContext = host->GetRenderContext();
826 CHECK_NULL_VOID(renderContext);
827 auto* pipeline = host->GetContextWithCheck();
828 CHECK_NULL_VOID(pipeline);
829 auto theme = pipeline->GetTheme<ButtonTheme>();
830 CHECK_NULL_VOID(theme);
831 auto alpha = theme->GetBgDisabledAlpha();
832 auto originalOpacity = renderContext->GetOpacityValue(1.0);
833 renderContext->OnOpacityUpdate(enabled ? originalOpacity : alpha * originalOpacity);
834 }
835
AnimateTouchAndHover(RefPtr<RenderContext> & renderContext,int32_t typeFrom,int32_t typeTo,int32_t duration,const RefPtr<Curve> & curve)836 void ButtonPattern::AnimateTouchAndHover(RefPtr<RenderContext>& renderContext, int32_t typeFrom, int32_t typeTo,
837 int32_t duration, const RefPtr<Curve>& curve)
838 {
839 auto host = GetHost();
840 CHECK_NULL_VOID(host);
841 auto* pipeline = host->GetContextWithCheck();
842 CHECK_NULL_VOID(pipeline);
843 auto theme = pipeline->GetTheme<ButtonTheme>();
844 CHECK_NULL_VOID(theme);
845 TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "button animate touch from %{public}d to %{public}d", typeFrom, typeTo);
846 Color blendColorFrom = GetColorFromType(theme, typeFrom);
847 Color blendColorTo = GetColorFromType(theme, typeTo);
848 renderContext->BlendBgColor(blendColorFrom);
849 AnimationOption option = AnimationOption();
850 option.SetDuration(duration);
851 option.SetCurve(curve);
852 AnimationUtils::Animate(option, [renderContext, blendColorTo]() { renderContext->BlendBgColor(blendColorTo); });
853 }
854
SetButtonPress(double xPos,double yPos)855 void ButtonPattern::SetButtonPress(double xPos, double yPos)
856 {
857 CHECK_NULL_VOID(contentModifierNode_);
858 auto host = GetHost();
859 CHECK_NULL_VOID(host);
860 auto eventHub = host->GetEventHub<EventHub>();
861 CHECK_NULL_VOID(eventHub);
862 auto enabled = eventHub->IsEnabled();
863 if (!enabled) {
864 return;
865 }
866 GestureEvent info;
867 std::chrono::microseconds microseconds(GetMicroTickCount());
868 TimeStamp time(microseconds);
869 info.SetTimeStamp(time);
870 auto x = Dimension(xPos, DimensionUnit::VP);
871 auto y = Dimension(yPos, DimensionUnit::VP);
872 info.SetLocalLocation(Offset(xPos, yPos));
873 auto currFrameRect = host->GetRectWithRender();
874 auto frameGlobalOffset = currFrameRect.GetOffset();
875 auto globalX = Dimension(x.ConvertToPx() + frameGlobalOffset.GetX());
876 auto globalY = Dimension(y.ConvertToPx() + frameGlobalOffset.GetY());
877 info.SetGlobalLocation(Offset(globalX.ConvertToVp(), globalY.ConvertToVp()));
878 auto pipeline = PipelineContext::GetCurrentContext();
879 CHECK_NULL_VOID(pipeline);
880 auto windowOffset = pipeline->GetCurrentWindowRect().GetOffset();
881 auto screenX = Dimension(windowOffset.GetX()) + globalX;
882 auto screenY = Dimension(windowOffset.GetY()) + globalY;
883 info.SetScreenLocation(Offset(screenX.ConvertToVp(), screenY.ConvertToVp()));
884 if (clickEventFunc_.has_value()) {
885 (clickEventFunc_.value())(info);
886 }
887 }
888
FireBuilder()889 void ButtonPattern::FireBuilder()
890 {
891 auto host = GetHost();
892 CHECK_NULL_VOID(host);
893 auto gestureEventHub = host->GetOrCreateGestureEventHub();
894 CHECK_NULL_VOID(gestureEventHub);
895 if (!makeFunc_.has_value()) {
896 gestureEventHub->SetRedirectClick(false);
897 if (nodeId_ == -1) {
898 return;
899 }
900 auto children = host->GetChildren();
901 for (const auto& child : children) {
902 if (child->GetId() == nodeId_) {
903 host->RemoveChildAndReturnIndex(child);
904 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
905 break;
906 }
907 }
908 return;
909 } else {
910 gestureEventHub->SetRedirectClick(true);
911 }
912 auto builderNode = BuildContentModifierNode();
913 if (contentModifierNode_ == builderNode) {
914 return;
915 }
916 host->RemoveChildAndReturnIndex(contentModifierNode_);
917 contentModifierNode_ = builderNode;
918 CHECK_NULL_VOID(contentModifierNode_);
919 nodeId_ = contentModifierNode_->GetId();
920 host->AddChild(contentModifierNode_, 0);
921 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
922 clickEventFunc_ = gestureEventHub->GetClickEvent();
923 }
924
BuildContentModifierNode()925 RefPtr<FrameNode> ButtonPattern::BuildContentModifierNode()
926 {
927 auto host = GetHost();
928 CHECK_NULL_RETURN(host, nullptr);
929 auto layoutProperty = GetLayoutProperty<ButtonLayoutProperty>();
930 CHECK_NULL_RETURN(layoutProperty, nullptr);
931 auto label = layoutProperty->GetLabel().value_or("");
932 auto eventHub = host->GetEventHub<EventHub>();
933 CHECK_NULL_RETURN(eventHub, nullptr);
934 auto enabled = eventHub->IsEnabled();
935 ButtonConfiguration buttonConfiguration(label, isPress_, enabled);
936 return (makeFunc_.value())(buttonConfiguration);
937 }
938
OnColorConfigurationUpdate()939 void ButtonPattern::OnColorConfigurationUpdate()
940 {
941 auto node = GetHost();
942 CHECK_NULL_VOID(node);
943 if (isColorUpdateFlag_) {
944 node->SetNeedCallChildrenUpdate(false);
945 return;
946 }
947 auto buttonLayoutProperty = node->GetLayoutProperty<ButtonLayoutProperty>();
948 CHECK_NULL_VOID(buttonLayoutProperty);
949 if (buttonLayoutProperty->GetCreateWithLabelValue(true)) {
950 node->SetNeedCallChildrenUpdate(false);
951 }
952 auto pipeline = node->GetContextWithCheck();
953 CHECK_NULL_VOID(pipeline);
954 auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
955 ButtonStyleMode buttonStyle = buttonLayoutProperty->GetButtonStyle().value_or(ButtonStyleMode::EMPHASIZE);
956 ButtonRole buttonRole = buttonLayoutProperty->GetButtonRole().value_or(ButtonRole::NORMAL);
957 auto renderContext = node->GetRenderContext();
958 CHECK_NULL_VOID(renderContext);
959 if (renderContext->GetBackgroundColor().value_or(themeBgColor_) == themeBgColor_) {
960 auto color = buttonTheme->GetBgColor(buttonStyle, buttonRole);
961 renderContext->UpdateBackgroundColor(color);
962 }
963 auto textNode = DynamicCast<FrameNode>(node->GetFirstChild());
964 CHECK_NULL_VOID(textNode);
965 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
966 CHECK_NULL_VOID(textLayoutProperty);
967 if (textLayoutProperty->GetTextColor().value_or(themeTextColor_) == themeTextColor_) {
968 textLayoutProperty->UpdateTextColor(buttonTheme->GetTextColor(buttonStyle, buttonRole));
969 textNode->MarkDirtyNode();
970 }
971 }
972
SetBuilderFunc(ButtonMakeCallback && makeFunc)973 void ButtonPattern::SetBuilderFunc(ButtonMakeCallback&& makeFunc)
974 {
975 if (makeFunc == nullptr) {
976 makeFunc_ = std::nullopt;
977 contentModifierNode_ = nullptr;
978 auto host = GetHost();
979 CHECK_NULL_VOID(host);
980 for (auto child : host->GetChildren()) {
981 auto childNode = DynamicCast<FrameNode>(child);
982 if (childNode) {
983 childNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
984 }
985 }
986 OnModifyDone();
987 return;
988 }
989 makeFunc_ = std::move(makeFunc);
990 }
991
UpdateTextFontScale(RefPtr<ButtonLayoutProperty> & layoutProperty,RefPtr<TextLayoutProperty> & textLayoutProperty)992 void ButtonPattern::UpdateTextFontScale(
993 RefPtr<ButtonLayoutProperty>& layoutProperty, RefPtr<TextLayoutProperty>& textLayoutProperty)
994 {
995 CHECK_NULL_VOID(layoutProperty);
996 CHECK_NULL_VOID(textLayoutProperty);
997 if (layoutProperty->GetMaxFontScale().has_value()) {
998 textLayoutProperty->UpdateMaxFontScale(layoutProperty->GetMaxFontScale().value());
999 } else {
1000 if (layoutProperty->HasType() && layoutProperty->GetType() == ButtonType::CIRCLE) {
1001 textLayoutProperty->UpdateMaxFontScale(NORMAL_SCALE);
1002 } else {
1003 textLayoutProperty->ResetMaxFontScale();
1004 }
1005 }
1006 if (layoutProperty->GetMinFontScale().has_value()) {
1007 textLayoutProperty->UpdateMinFontScale(layoutProperty->GetMinFontScale().value());
1008 } else {
1009 textLayoutProperty->ResetMinFontScale();
1010 }
1011 }
1012
OnFontScaleConfigurationUpdate()1013 void ButtonPattern::OnFontScaleConfigurationUpdate()
1014 {
1015 auto host = GetHost();
1016 CHECK_NULL_VOID(host);
1017 auto textNode = DynamicCast<FrameNode>(host->GetFirstChild());
1018 CHECK_NULL_VOID(textNode);
1019 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
1020 CHECK_NULL_VOID(textLayoutProperty);
1021 auto layoutProperty = GetLayoutProperty<ButtonLayoutProperty>();
1022 CHECK_NULL_VOID(layoutProperty);
1023 if (NeedAgingUpdateText(layoutProperty)) {
1024 if (!layoutProperty->GetMaxFontSize().has_value()) {
1025 textLayoutProperty->ResetAdaptMaxFontSize();
1026 } else {
1027 textLayoutProperty->UpdateAdaptMaxFontSize(layoutProperty->GetMaxFontSize().value());
1028 }
1029 if (!layoutProperty->GetMinFontSize().has_value()) {
1030 textLayoutProperty->ResetAdaptMinFontSize();
1031 } else {
1032 textLayoutProperty->UpdateAdaptMinFontSize(layoutProperty->GetMinFontSize().value());
1033 }
1034 } else {
1035 if (layoutProperty->GetMaxFontSize().has_value()) {
1036 textLayoutProperty->UpdateAdaptMaxFontSize(layoutProperty->GetMaxFontSize().value());
1037 }
1038 if (layoutProperty->GetMinFontSize().has_value()) {
1039 textLayoutProperty->UpdateAdaptMinFontSize(layoutProperty->GetMinFontSize().value());
1040 }
1041 }
1042 textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1043 }
1044
ToTreeJson(std::unique_ptr<JsonValue> & json,const InspectorConfig & config) const1045 void ButtonPattern::ToTreeJson(std::unique_ptr<JsonValue>& json, const InspectorConfig& config) const
1046 {
1047 Pattern::ToTreeJson(json, config);
1048 auto host = GetHost();
1049 CHECK_NULL_VOID(host);
1050 auto layoutProperty = host->GetLayoutProperty<ButtonLayoutProperty>();
1051 CHECK_NULL_VOID(layoutProperty);
1052 json->Put(TreeKey::CONTENT, layoutProperty->GetLabelValue("").c_str());
1053 }
1054
AddIsFocusActiveUpdateEvent()1055 void ButtonPattern::AddIsFocusActiveUpdateEvent()
1056 {
1057 if (!isFocusActiveUpdateEvent_) {
1058 isFocusActiveUpdateEvent_ = [weak = WeakClaim(this)](bool isFocusAcitve) {
1059 auto pattern = weak.Upgrade();
1060 CHECK_NULL_VOID(pattern);
1061 pattern->SetIsFocus(isFocusAcitve);
1062 pattern->UpdateButtonStyle();
1063 };
1064 }
1065 auto host = GetHost();
1066 CHECK_NULL_VOID(host);
1067 auto pipeline = host->GetContextRefPtr();
1068 CHECK_NULL_VOID(pipeline);
1069 pipeline->AddIsFocusActiveUpdateEvent(host, isFocusActiveUpdateEvent_);
1070 }
1071
RemoveIsFocusActiveUpdateEvent()1072 void ButtonPattern::RemoveIsFocusActiveUpdateEvent()
1073 {
1074 auto host = GetHost();
1075 CHECK_NULL_VOID(host);
1076 auto pipeline = host->GetContextRefPtr();
1077 CHECK_NULL_VOID(pipeline);
1078 pipeline->RemoveIsFocusActiveUpdateEvent(host);
1079 }
1080
HandleFocusStyleTask()1081 void ButtonPattern::HandleFocusStyleTask()
1082 {
1083 AddIsFocusActiveUpdateEvent();
1084 auto host = GetHost();
1085 CHECK_NULL_VOID(host);
1086 auto pipeline = host->GetContextRefPtr();
1087 CHECK_NULL_VOID(pipeline);
1088
1089 if (pipeline->GetIsFocusActive()) {
1090 SetIsFocus(true);
1091 UpdateButtonStyle();
1092 }
1093 }
1094
HandleBlurStyleTask()1095 void ButtonPattern::HandleBlurStyleTask()
1096 {
1097 SetIsFocus(false);
1098 RemoveIsFocusActiveUpdateEvent();
1099 UpdateButtonStyle();
1100 }
1101
SetBlurButtonStyle(RefPtr<RenderContext> & renderContext,RefPtr<ButtonTheme> & buttonTheme,RefPtr<ButtonLayoutProperty> & layoutProperty,RefPtr<FrameNode> & textNode)1102 void ButtonPattern::SetBlurButtonStyle(RefPtr<RenderContext>& renderContext, RefPtr<ButtonTheme>& buttonTheme,
1103 RefPtr<ButtonLayoutProperty>& layoutProperty, RefPtr<FrameNode>& textNode)
1104 {
1105 ButtonStyleMode buttonStyle = layoutProperty->GetButtonStyle().value_or(ButtonStyleMode::EMPHASIZE);
1106 ButtonRole buttonRole = layoutProperty->GetButtonRole().value_or(ButtonRole::NORMAL);
1107
1108 if (buttonStyle != ButtonStyleMode::TEXT && shadowModify_) {
1109 ShadowStyle shadowStyle = static_cast<ShadowStyle>(buttonTheme->GetShadowNormal());
1110 Shadow shadow = GetShadowFromTheme(shadowStyle);
1111 renderContext->UpdateBackShadow(shadow);
1112 shadowModify_ = false;
1113 }
1114 if (scaleModify_) {
1115 scaleModify_ = false;
1116 renderContext->SetScale(1.0f, 1.0f);
1117 }
1118 if (bgColorModify_) {
1119 bgColorModify_ = false;
1120 renderContext->UpdateBackgroundColor(buttonTheme->GetBgColor(buttonStyle, buttonRole));
1121 }
1122 if (focusTextColorModify_) {
1123 focusTextColorModify_ = false;
1124 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
1125 CHECK_NULL_VOID(textLayoutProperty);
1126 textLayoutProperty->UpdateTextColor(buttonTheme->GetTextColor(buttonStyle, buttonRole));
1127 auto textRenderContext = textNode->GetRenderContext();
1128 CHECK_NULL_VOID(textRenderContext);
1129 textRenderContext->UpdateForegroundColor(buttonTheme->GetTextColor(buttonStyle, buttonRole));
1130 textNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1131 }
1132 UpdateTexOverflow(isHover_);
1133 }
1134
SetFocusButtonStyle(RefPtr<RenderContext> & renderContext,RefPtr<ButtonTheme> & buttonTheme,RefPtr<ButtonLayoutProperty> & layoutProperty,RefPtr<FrameNode> & textNode)1135 void ButtonPattern::SetFocusButtonStyle(RefPtr<RenderContext>& renderContext, RefPtr<ButtonTheme>& buttonTheme,
1136 RefPtr<ButtonLayoutProperty>& layoutProperty, RefPtr<FrameNode>& textNode)
1137 {
1138 ButtonStyleMode buttonStyle = layoutProperty->GetButtonStyle().value_or(ButtonStyleMode::EMPHASIZE);
1139 ButtonRole buttonRole = layoutProperty->GetButtonRole().value_or(ButtonRole::NORMAL);
1140
1141 if (buttonStyle != ButtonStyleMode::TEXT) {
1142 ShadowStyle shadowStyle = static_cast<ShadowStyle>(buttonTheme->GetShadowFocus());
1143 HandleShadowStyle(buttonStyle, shadowStyle, renderContext, buttonTheme);
1144 shadowModify_ = true;
1145 }
1146 SetButtonScale(renderContext, buttonTheme);
1147 bgColorModify_ = renderContext->GetBackgroundColor() == buttonTheme->GetBgColor(buttonStyle, buttonRole);
1148 if (bgColorModify_) {
1149 if (buttonStyle == ButtonStyleMode::TEXT) {
1150 renderContext->UpdateBackgroundColor(buttonTheme->GetTextBackgroundFocus());
1151 } else if (buttonStyle == ButtonStyleMode::NORMAL) {
1152 renderContext->UpdateBackgroundColor(buttonTheme->GetNormalBackgroundFocus());
1153 } else if (buttonStyle == ButtonStyleMode::EMPHASIZE) {
1154 renderContext->UpdateBackgroundColor(buttonTheme->GetEmphasizeBackgroundFocus());
1155 }
1156 }
1157
1158 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
1159 CHECK_NULL_VOID(textLayoutProperty);
1160 focusTextColorModify_ =
1161 textLayoutProperty->GetTextColor() == buttonTheme->GetTextColor(buttonStyle, buttonRole);
1162 if (focusTextColorModify_ && buttonStyle != ButtonStyleMode::EMPHASIZE) {
1163 textLayoutProperty->UpdateTextColor(buttonTheme->GetFocusTextColor(buttonStyle, buttonRole));
1164 auto textRenderContext = textNode->GetRenderContext();
1165 CHECK_NULL_VOID(textRenderContext);
1166 textRenderContext->UpdateForegroundColor(buttonTheme->GetFocusTextColor(buttonStyle, buttonRole));
1167 textNode->MarkDirtyNode();
1168 }
1169 UpdateTexOverflow(true);
1170 }
1171
SetButtonScale(RefPtr<RenderContext> & renderContext,RefPtr<ButtonTheme> & buttonTheme)1172 void ButtonPattern::SetButtonScale(RefPtr<RenderContext>& renderContext, RefPtr<ButtonTheme>& buttonTheme)
1173 {
1174 if (renderContext->GetOrCreateTransform()) {
1175 float scaleHoverOrFocus = buttonTheme->GetScaleHoverOrFocus();
1176 VectorF scale(scaleHoverOrFocus, scaleHoverOrFocus);
1177 auto&& transform = renderContext->GetOrCreateTransform();
1178 if (scaleHoverOrFocus != 1.0 && (!transform->HasTransformScale() || transform->GetTransformScale() == scale)) {
1179 scaleModify_ = true;
1180 renderContext->SetScale(scaleHoverOrFocus, scaleHoverOrFocus);
1181 }
1182 }
1183 }
1184
UpdateButtonStyle()1185 void ButtonPattern::UpdateButtonStyle()
1186 {
1187 auto host = GetHost();
1188 CHECK_NULL_VOID(host);
1189 auto pipeline = host->GetContextRefPtr();
1190 CHECK_NULL_VOID(pipeline);
1191 auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
1192 CHECK_NULL_VOID(buttonTheme);
1193 auto textNode = DynamicCast<FrameNode>(host->GetFirstChild());
1194 CHECK_NULL_VOID(textNode);
1195 auto renderContext = host->GetRenderContext();
1196 CHECK_NULL_VOID(renderContext);
1197 auto layoutProperty = GetLayoutProperty<ButtonLayoutProperty>();
1198 CHECK_NULL_VOID(layoutProperty);
1199 if (isFocus_) {
1200 SetFocusButtonStyle(renderContext, buttonTheme, layoutProperty, textNode);
1201 } else {
1202 SetBlurButtonStyle(renderContext, buttonTheme, layoutProperty, textNode);
1203 }
1204 }
1205
HandleFocusStatusStyle()1206 void ButtonPattern::HandleFocusStatusStyle()
1207 {
1208 if (UseContentModifier()) {
1209 return;
1210 }
1211 auto host = GetHost();
1212 CHECK_NULL_VOID(host);
1213 auto focusHub = host->GetOrCreateFocusHub();
1214 CHECK_NULL_VOID(focusHub);
1215
1216 auto focusTask = [weak = WeakClaim(this)]() {
1217 TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "button handle focus event");
1218 auto pattern = weak.Upgrade();
1219 CHECK_NULL_VOID(pattern);
1220 pattern->HandleFocusStyleTask();
1221 };
1222 focusHub->SetOnFocusInternal(focusTask);
1223
1224 auto blurTask = [weak = WeakClaim(this)]() {
1225 TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "button handle blur event");
1226 auto pattern = weak.Upgrade();
1227 CHECK_NULL_VOID(pattern);
1228 pattern->HandleBlurStyleTask();
1229 };
1230 focusHub->SetOnBlurInternal(blurTask);
1231 }
1232 } // namespace OHOS::Ace::NG
1233