• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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