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 
18 #include "base/utils/utils.h"
19 #include "core/common/recorder/node_data_cache.h"
20 #include "core/components/button/button_theme.h"
21 #include "core/components/common/layout/constants.h"
22 #include "core/components/common/properties/color.h"
23 #include "core/components_ng/pattern/button/button_event_hub.h"
24 #include "core/components_ng/pattern/button/toggle_button_pattern.h"
25 #include "core/components_ng/pattern/text/text_layout_property.h"
26 #include "core/components_ng/property/property.h"
27 #include "core/event/mouse_event.h"
28 #include "core/pipeline/pipeline_base.h"
29 
30 namespace OHOS::Ace::NG {
31 namespace {
32 constexpr int32_t TOUCH_DURATION = 100;
33 constexpr int32_t MOUSE_HOVER_DURATION = 250;
34 constexpr int32_t TYPE_TOUCH = 0;
35 constexpr int32_t TYPE_HOVER = 1;
36 constexpr int32_t TYPE_CANCEL = 2;
37 constexpr float NORMAL_SCALE = 1.0f;
38 } // namespace
39 
GetColorFromType(const RefPtr<ButtonTheme> & theme,const int32_t & type)40 Color ButtonPattern::GetColorFromType(const RefPtr<ButtonTheme>& theme, const int32_t& type)
41 {
42     if (type == TYPE_TOUCH) {
43         return blendClickColor_.value_or(theme->GetClickedColor());
44     } else if (type == TYPE_HOVER) {
45         return blendHoverColor_.value_or(theme->GetHoverColor());
46     } else {
47         return Color::TRANSPARENT;
48     }
49 }
50 
OnAttachToFrameNode()51 void ButtonPattern::OnAttachToFrameNode()
52 {
53     auto host = GetHost();
54     CHECK_NULL_VOID(host);
55     auto* pipeline = host->GetContextWithCheck();
56     CHECK_NULL_VOID(pipeline);
57     auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
58     CHECK_NULL_VOID(buttonTheme);
59     clickedColor_ = buttonTheme->GetClickedColor();
60     auto renderContext = host->GetRenderContext();
61     CHECK_NULL_VOID(renderContext);
62     renderContext->SetAlphaOffscreen(true);
63 }
64 
NeedAgingUpdateText(RefPtr<ButtonLayoutProperty> & layoutProperty)65 bool ButtonPattern::NeedAgingUpdateText(RefPtr<ButtonLayoutProperty>& layoutProperty)
66 {
67     CHECK_NULL_RETURN(layoutProperty, false);
68     auto pipeline = NG::PipelineContext::GetCurrentContextSafely();
69     CHECK_NULL_RETURN(pipeline, false);
70     auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
71     CHECK_NULL_RETURN(buttonTheme, false);
72     auto fontScale = pipeline->GetFontScale();
73 
74     if (layoutProperty->HasType() && layoutProperty->GetType() == ButtonType::CIRCLE) {
75         return false;
76     }
77 
78     if (layoutProperty->HasLabel() && layoutProperty->GetLabel()->empty()) {
79         return false;
80     }
81 
82     if (layoutProperty->HasFontSize() && layoutProperty->GetFontSize()->Unit() != DimensionUnit::FP) {
83         return false;
84     }
85     const auto& calcConstraint = layoutProperty->GetCalcLayoutConstraint();
86     if (calcConstraint && calcConstraint->selfIdealSize->Height().has_value() &&
87         calcConstraint->selfIdealSize->Width().has_value()) {
88         return false;
89     }
90     if (!(NearEqual(fontScale, buttonTheme->GetBigFontSizeScale()) ||
91             NearEqual(fontScale, buttonTheme->GetLargeFontSizeScale()) ||
92             NearEqual(fontScale, buttonTheme->GetMaxFontSizeScale()))) {
93         return false;
94     }
95     return true;
96 }
97 
UpdateTextLayoutProperty(RefPtr<ButtonLayoutProperty> & layoutProperty,RefPtr<TextLayoutProperty> & textLayoutProperty)98 void ButtonPattern::UpdateTextLayoutProperty(
99     RefPtr<ButtonLayoutProperty>& layoutProperty, RefPtr<TextLayoutProperty>& textLayoutProperty)
100 {
101     CHECK_NULL_VOID(layoutProperty);
102     CHECK_NULL_VOID(textLayoutProperty);
103     UpdateTextFontScale(layoutProperty, textLayoutProperty);
104     auto label = layoutProperty->GetLabelValue("");
105     textLayoutProperty->UpdateContent(label);
106     if (layoutProperty->GetFontSize().has_value()) {
107         textLayoutProperty->UpdateFontSize(layoutProperty->GetFontSize().value());
108     }
109     if (layoutProperty->GetFontWeight().has_value()) {
110         textLayoutProperty->UpdateFontWeight(layoutProperty->GetFontWeight().value());
111     }
112     if (layoutProperty->GetFontColor().has_value()) {
113         textLayoutProperty->UpdateTextColor(layoutProperty->GetFontColor().value());
114     }
115     if (layoutProperty->GetFontStyle().has_value()) {
116         textLayoutProperty->UpdateItalicFontStyle(layoutProperty->GetFontStyle().value());
117     }
118     if (layoutProperty->GetFontFamily().has_value()) {
119         textLayoutProperty->UpdateFontFamily(layoutProperty->GetFontFamily().value());
120     }
121 
122     auto pipeline = NG::PipelineContext::GetCurrentContextSafely();
123     CHECK_NULL_VOID(pipeline);
124     auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
125     CHECK_NULL_VOID(buttonTheme);
126     if (NeedAgingUpdateText(layoutProperty)) {
127         textLayoutProperty->UpdateMaxLines(buttonTheme->GetAgingTextMaxLines());
128     } else {
129         textLayoutProperty->UpdateMaxLines(buttonTheme->GetTextMaxLines());
130     }
131 
132     if (layoutProperty->GetTextOverflow().has_value()) {
133         textLayoutProperty->UpdateTextOverflow(layoutProperty->GetTextOverflow().value());
134     }
135     if (layoutProperty->GetMaxLines().has_value()) {
136         textLayoutProperty->UpdateMaxLines(layoutProperty->GetMaxLines().value());
137     }
138     if (layoutProperty->GetMinFontSize().has_value()) {
139         textLayoutProperty->UpdateAdaptMinFontSize(layoutProperty->GetMinFontSize().value());
140     }
141     if (layoutProperty->GetMaxFontSize().has_value()) {
142         textLayoutProperty->UpdateAdaptMaxFontSize(layoutProperty->GetMaxFontSize().value());
143     }
144     if (layoutProperty->GetHeightAdaptivePolicy().has_value()) {
145         textLayoutProperty->UpdateHeightAdaptivePolicy(layoutProperty->GetHeightAdaptivePolicy().value());
146     }
147     // update text style defined by buttonStyle and control size
148     UpdateTextStyle(layoutProperty, textLayoutProperty);
149 }
150 
UpdateTextStyle(RefPtr<ButtonLayoutProperty> & layoutProperty,RefPtr<TextLayoutProperty> & textLayoutProperty)151 void ButtonPattern::UpdateTextStyle(
152     RefPtr<ButtonLayoutProperty>& layoutProperty, RefPtr<TextLayoutProperty>& textLayoutProperty)
153 {
154     auto host = layoutProperty->GetHost();
155     CHECK_NULL_VOID(host);
156     auto* pipeline = host->GetContextWithCheck();
157     CHECK_NULL_VOID(pipeline);
158     auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
159     CHECK_NULL_VOID(buttonTheme);
160     if (!textLayoutProperty->HasTextColor()) {
161         ButtonStyleMode buttonStyle = layoutProperty->GetButtonStyle().value_or(ButtonStyleMode::EMPHASIZE);
162         ButtonRole buttonRole = layoutProperty->GetButtonRole().value_or(ButtonRole::NORMAL);
163         Color fontColor = buttonTheme->GetTextColor(buttonStyle, buttonRole);
164         textLayoutProperty->UpdateTextColor(fontColor);
165     }
166     if (!textLayoutProperty->HasFontSize()) {
167         ControlSize controlSize = layoutProperty->GetControlSize().value_or(ControlSize::NORMAL);
168         Dimension fontSize = buttonTheme->GetTextSize(controlSize);
169         textLayoutProperty->UpdateFontSize(fontSize);
170     }
171 }
172 
IsNeedToHandleHoverOpacity()173 bool ButtonPattern::IsNeedToHandleHoverOpacity()
174 {
175     auto host = GetHost();
176     CHECK_NULL_RETURN(host, false);
177     auto inputEventHub = host->GetOrCreateInputEventHub();
178     auto hoverEffect = inputEventHub->GetHoverEffect();
179     return isHover_ && hoverEffect != HoverEffectType::BOARD && hoverEffect != HoverEffectType::SCALE &&
180            hoverEffect != HoverEffectType::NONE;
181 }
182 
InitButtonLabel()183 void ButtonPattern::InitButtonLabel()
184 {
185     auto host = GetHost();
186     CHECK_NULL_VOID(host);
187     auto focusHub = host->GetFocusHub();
188     CHECK_NULL_VOID(focusHub);
189     auto layoutProperty = GetLayoutProperty<ButtonLayoutProperty>();
190     CHECK_NULL_VOID(layoutProperty);
191     if (!layoutProperty->GetLabel().has_value()) {
192         focusHub->SetFocusType(FocusType::SCOPE);
193         return;
194     }
195     focusHub->SetFocusType(FocusType::NODE);
196     auto textNode = DynamicCast<FrameNode>(host->GetFirstChild());
197     CHECK_NULL_VOID(textNode);
198     auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
199     CHECK_NULL_VOID(textLayoutProperty);
200     UpdateTextLayoutProperty(layoutProperty, textLayoutProperty);
201     auto buttonRenderContext = host->GetRenderContext();
202     CHECK_NULL_VOID(buttonRenderContext);
203     auto textRenderContext = textNode->GetRenderContext();
204     CHECK_NULL_VOID(textRenderContext);
205     textRenderContext->UpdateClipEdge(buttonRenderContext->GetClipEdgeValue(true));
206     textNode->MarkModifyDone();
207     textNode->MarkDirtyNode();
208 }
209 
OnModifyDone()210 void ButtonPattern::OnModifyDone()
211 {
212     Pattern::OnModifyDone();
213     FireBuilder();
214     InitButtonLabel();
215     HandleBackgroundColor();
216     HandleEnabled();
217     InitHoverEvent();
218     InitTouchEvent();
219 }
220 
InitTouchEvent()221 void ButtonPattern::InitTouchEvent()
222 {
223     if (touchListener_) {
224         return;
225     }
226     auto host = GetHost();
227     CHECK_NULL_VOID(host);
228     auto gesture = host->GetOrCreateGestureEventHub();
229     CHECK_NULL_VOID(gesture);
230     auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
231         auto buttonPattern = weak.Upgrade();
232         CHECK_NULL_VOID(buttonPattern);
233         if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
234             TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "button touch down");
235             buttonPattern->OnTouchDown();
236         }
237         if (info.GetTouches().front().GetTouchType() == TouchType::UP ||
238             info.GetTouches().front().GetTouchType() == TouchType::CANCEL) {
239             TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "button touch up");
240             buttonPattern->OnTouchUp();
241         }
242     };
243     touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
244     gesture->AddTouchEvent(touchListener_);
245 }
246 
OnAfterModifyDone()247 void ButtonPattern::OnAfterModifyDone()
248 {
249     auto host = GetHost();
250     CHECK_NULL_VOID(host);
251     auto inspectorId = host->GetInspectorId().value_or("");
252     if (!inspectorId.empty()) {
253         auto text = host->GetAccessibilityProperty<NG::AccessibilityProperty>()->GetText();
254         Recorder::NodeDataCache::Get().PutString(host, inspectorId, text);
255     }
256 }
257 
InitHoverEvent()258 void ButtonPattern::InitHoverEvent()
259 {
260     if (UseContentModifier()) {
261         return;
262     }
263     auto host = GetHost();
264     CHECK_NULL_VOID(host);
265     auto eventHub = host->GetEventHub<ButtonEventHub>();
266     auto inputHub = eventHub->GetOrCreateInputEventHub();
267     auto hoverEffect = inputHub->GetHoverEffect();
268     inputHub->SetHoverEffect(hoverEffect == HoverEffectType::BOARD ? HoverEffectType::AUTO : hoverEffect);
269     if (hoverListener_) {
270         return;
271     }
272     auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
273         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "button handle hover %{public}d", isHover);
274         auto pattern = weak.Upgrade();
275         if (pattern) {
276             pattern->HandleHoverEvent(isHover);
277         }
278     };
279 
280     hoverListener_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
281     inputHub->AddOnHoverEvent(hoverListener_);
282 }
283 
OnTouchDown()284 void ButtonPattern::OnTouchDown()
285 {
286     isPress_ = true;
287     FireBuilder();
288     if (UseContentModifier()) {
289         return;
290     }
291     auto host = GetHost();
292     CHECK_NULL_VOID(host);
293     auto buttonEventHub = GetEventHub<ButtonEventHub>();
294     CHECK_NULL_VOID(buttonEventHub);
295     if (buttonEventHub->GetStateEffect()) {
296         auto renderContext = host->GetRenderContext();
297         CHECK_NULL_VOID(renderContext);
298         backgroundColor_ = renderContext->GetBackgroundColor().value_or(Color::TRANSPARENT);
299         if (isSetClickedColor_) {
300             // for user self-defined
301             renderContext->UpdateBackgroundColor(clickedColor_);
302             return;
303         }
304         // for system default
305         auto isNeedToHandleHoverOpacity = IsNeedToHandleHoverOpacity();
306         AnimateTouchAndHover(renderContext, isNeedToHandleHoverOpacity ? TYPE_HOVER : TYPE_CANCEL, TYPE_TOUCH,
307             TOUCH_DURATION, isNeedToHandleHoverOpacity ? Curves::SHARP : Curves::FRICTION);
308     }
309 }
310 
OnTouchUp()311 void ButtonPattern::OnTouchUp()
312 {
313     isPress_ = false;
314     FireBuilder();
315     if (UseContentModifier()) {
316         return;
317     }
318     auto host = GetHost();
319     CHECK_NULL_VOID(host);
320     auto buttonEventHub = GetEventHub<ButtonEventHub>();
321     CHECK_NULL_VOID(buttonEventHub);
322     auto toggleButtonPattern = host->GetPattern<ToggleButtonPattern>();
323     if (toggleButtonPattern) {
324         toggleButtonPattern->OnClick();
325     }
326     if (buttonEventHub->GetStateEffect()) {
327         auto renderContext = host->GetRenderContext();
328         if (isSetClickedColor_) {
329             renderContext->UpdateBackgroundColor(backgroundColor_);
330             return;
331         }
332         if (buttonEventHub->IsEnabled()) {
333             auto isNeedToHandleHoverOpacity = IsNeedToHandleHoverOpacity();
334             AnimateTouchAndHover(renderContext, TYPE_TOUCH, isNeedToHandleHoverOpacity ? TYPE_HOVER : TYPE_CANCEL,
335                 TOUCH_DURATION, isNeedToHandleHoverOpacity ? Curves::SHARP : Curves::FRICTION);
336         } else {
337             AnimateTouchAndHover(renderContext, TYPE_TOUCH, TYPE_CANCEL, TOUCH_DURATION, Curves::FRICTION);
338         }
339     }
340 }
341 
HandleHoverEvent(bool isHover)342 void ButtonPattern::HandleHoverEvent(bool isHover)
343 {
344     isHover_ = isHover;
345     auto host = GetHost();
346     CHECK_NULL_VOID(host);
347     auto eventHub = host->GetEventHub<EventHub>();
348     CHECK_NULL_VOID(eventHub);
349     auto enabled = eventHub->IsEnabled();
350     auto inputEventHub = host->GetOrCreateInputEventHub();
351     auto hoverEffect = inputEventHub->GetHoverEffect();
352     if (hoverEffect == HoverEffectType::NONE || hoverEffect == HoverEffectType::SCALE) {
353         return;
354     }
355     if (!isPress_ && (enabled || !isHover)) {
356         auto renderContext = host->GetRenderContext();
357         CHECK_NULL_VOID(renderContext);
358         AnimateTouchAndHover(renderContext, isHover ? TYPE_CANCEL : TYPE_HOVER, isHover ? TYPE_HOVER : TYPE_CANCEL,
359             MOUSE_HOVER_DURATION, Curves::FRICTION);
360     }
361 }
362 
HandleBackgroundColor()363 void ButtonPattern::HandleBackgroundColor()
364 {
365     auto host = GetHost();
366     CHECK_NULL_VOID(host);
367     auto* pipeline = host->GetContextWithCheck();
368     CHECK_NULL_VOID(pipeline);
369     auto renderContext = host->GetRenderContext();
370     CHECK_NULL_VOID(renderContext);
371     auto layoutProperty = GetLayoutProperty<ButtonLayoutProperty>();
372     CHECK_NULL_VOID(layoutProperty);
373     auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
374     CHECK_NULL_VOID(buttonTheme);
375     ButtonStyleMode buttonStyle = layoutProperty->GetButtonStyle().value_or(ButtonStyleMode::EMPHASIZE);
376     ButtonRole buttonRole = layoutProperty->GetButtonRole().value_or(ButtonRole::NORMAL);
377     if (UseContentModifier()) {
378         renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
379         renderContext->ResetBackgroundColor();
380         return;
381     }
382 
383     if (!renderContext->HasBackgroundColor()) {
384         renderContext->UpdateBackgroundColor(buttonTheme->GetBgColor(buttonStyle, buttonRole));
385     }
386     themeBgColor_ = buttonTheme->GetBgColor(buttonStyle, buttonRole);
387     themeTextColor_ = buttonTheme->GetTextColor(buttonStyle, buttonRole);
388 }
389 
HandleEnabled()390 void ButtonPattern::HandleEnabled()
391 {
392     if (UseContentModifier()) {
393         return;
394     }
395     auto host = GetHost();
396     CHECK_NULL_VOID(host);
397     auto eventHub = host->GetEventHub<EventHub>();
398     CHECK_NULL_VOID(eventHub);
399     auto enabled = eventHub->IsEnabled();
400     auto renderContext = host->GetRenderContext();
401     CHECK_NULL_VOID(renderContext);
402     auto* pipeline = host->GetContextWithCheck();
403     CHECK_NULL_VOID(pipeline);
404     auto theme = pipeline->GetTheme<ButtonTheme>();
405     CHECK_NULL_VOID(theme);
406     auto alpha = theme->GetBgDisabledAlpha();
407     auto originalOpacity = renderContext->GetOpacityValue(1.0);
408     renderContext->OnOpacityUpdate(enabled ? originalOpacity : alpha * originalOpacity);
409 }
410 
AnimateTouchAndHover(RefPtr<RenderContext> & renderContext,int32_t typeFrom,int32_t typeTo,int32_t duration,const RefPtr<Curve> & curve)411 void ButtonPattern::AnimateTouchAndHover(RefPtr<RenderContext>& renderContext, int32_t typeFrom, int32_t typeTo,
412     int32_t duration, const RefPtr<Curve>& curve)
413 {
414     auto host = GetHost();
415     CHECK_NULL_VOID(host);
416     auto* pipeline = host->GetContextWithCheck();
417     CHECK_NULL_VOID(pipeline);
418     auto theme = pipeline->GetTheme<ButtonTheme>();
419     CHECK_NULL_VOID(theme);
420     TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "button animate touch from %{public}d to %{public}d", typeFrom, typeTo);
421     Color blendColorFrom = GetColorFromType(theme, typeFrom);
422     Color blendColorTo = GetColorFromType(theme, typeTo);
423     renderContext->BlendBgColor(blendColorFrom);
424     AnimationOption option = AnimationOption();
425     option.SetDuration(duration);
426     option.SetCurve(curve);
427     AnimationUtils::Animate(option, [renderContext, blendColorTo]() { renderContext->BlendBgColor(blendColorTo); });
428 }
429 
SetButtonPress(double xPos,double yPos)430 void ButtonPattern::SetButtonPress(double xPos, double yPos)
431 {
432     CHECK_NULL_VOID(contentModifierNode_);
433     auto host = GetHost();
434     CHECK_NULL_VOID(host);
435     auto eventHub = host->GetEventHub<EventHub>();
436     CHECK_NULL_VOID(eventHub);
437     auto enabled = eventHub->IsEnabled();
438     if (!enabled) {
439         return;
440     }
441     GestureEvent info;
442     std::chrono::microseconds microseconds(GetMicroTickCount());
443     TimeStamp time(microseconds);
444     info.SetTimeStamp(time);
445     auto x = Dimension(xPos, DimensionUnit::VP);
446     auto y = Dimension(yPos, DimensionUnit::VP);
447     info.SetLocalLocation(Offset(xPos, yPos));
448     auto currFrameRect = host->GetRectWithRender();
449     auto frameGlobalOffset = currFrameRect.GetOffset();
450     auto globalX = Dimension(x.ConvertToPx() + frameGlobalOffset.GetX());
451     auto globalY = Dimension(y.ConvertToPx() + frameGlobalOffset.GetY());
452     info.SetGlobalLocation(Offset(globalX.ConvertToVp(), globalY.ConvertToVp()));
453     auto pipeline = PipelineContext::GetCurrentContext();
454     CHECK_NULL_VOID(pipeline);
455     auto windowOffset = pipeline->GetCurrentWindowRect().GetOffset();
456     auto screenX = Dimension(windowOffset.GetX()) + globalX;
457     auto screenY = Dimension(windowOffset.GetY()) + globalY;
458     info.SetScreenLocation(Offset(screenX.ConvertToVp(), screenY.ConvertToVp()));
459     if (clickEventFunc_.has_value()) {
460         (clickEventFunc_.value())(info);
461     }
462 }
463 
FireBuilder()464 void ButtonPattern::FireBuilder()
465 {
466     auto host = GetHost();
467     CHECK_NULL_VOID(host);
468     auto gestureEventHub = host->GetOrCreateGestureEventHub();
469     CHECK_NULL_VOID(gestureEventHub);
470     if (!makeFunc_.has_value()) {
471         gestureEventHub->SetRedirectClick(false);
472         auto children = host->GetChildren();
473         for (const auto& child : children) {
474             if (nodeId_ == -1) {
475                 return;
476             }
477             if (child->GetId() == nodeId_) {
478                 host->RemoveChildAndReturnIndex(child);
479                 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
480                 break;
481             }
482         }
483         return;
484     } else {
485         gestureEventHub->SetRedirectClick(true);
486     }
487     auto builderNode = BuildContentModifierNode();
488     if (contentModifierNode_ == builderNode) {
489         return;
490     }
491     host->RemoveChildAndReturnIndex(contentModifierNode_);
492     contentModifierNode_ = builderNode;
493     CHECK_NULL_VOID(contentModifierNode_);
494     nodeId_ = contentModifierNode_->GetId();
495     host->AddChild(contentModifierNode_, 0);
496     host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
497     clickEventFunc_ = gestureEventHub->GetClickEvent();
498 }
499 
BuildContentModifierNode()500 RefPtr<FrameNode> ButtonPattern::BuildContentModifierNode()
501 {
502     auto host = GetHost();
503     CHECK_NULL_RETURN(host, nullptr);
504     auto layoutProperty = GetLayoutProperty<ButtonLayoutProperty>();
505     CHECK_NULL_RETURN(layoutProperty, nullptr);
506     auto label = layoutProperty->GetLabel().value_or("");
507     auto eventHub = host->GetEventHub<EventHub>();
508     CHECK_NULL_RETURN(eventHub, nullptr);
509     auto enabled = eventHub->IsEnabled();
510     ButtonConfiguration buttonConfiguration(label, isPress_, enabled);
511     return (makeFunc_.value())(buttonConfiguration);
512 }
513 
OnColorConfigurationUpdate()514 void ButtonPattern::OnColorConfigurationUpdate()
515 {
516     auto node = GetHost();
517     CHECK_NULL_VOID(node);
518     if (isColorUpdateFlag_) {
519         node->SetNeedCallChildrenUpdate(false);
520         return;
521     }
522     auto buttonLayoutProperty = node->GetLayoutProperty<ButtonLayoutProperty>();
523     CHECK_NULL_VOID(buttonLayoutProperty);
524     if (buttonLayoutProperty->GetCreateWithLabelValue(true)) {
525         node->SetNeedCallChildrenUpdate(false);
526     }
527     auto pipeline = node->GetContextWithCheck();
528     CHECK_NULL_VOID(pipeline);
529     auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
530     ButtonStyleMode buttonStyle = buttonLayoutProperty->GetButtonStyle().value_or(ButtonStyleMode::EMPHASIZE);
531     ButtonRole buttonRole = buttonLayoutProperty->GetButtonRole().value_or(ButtonRole::NORMAL);
532     auto renderContext = node->GetRenderContext();
533     CHECK_NULL_VOID(renderContext);
534     if (renderContext->GetBackgroundColor().value_or(themeBgColor_) == themeBgColor_) {
535         auto color = buttonTheme->GetBgColor(buttonStyle, buttonRole);
536         renderContext->UpdateBackgroundColor(color);
537     }
538     auto textNode = DynamicCast<FrameNode>(node->GetFirstChild());
539     CHECK_NULL_VOID(textNode);
540     auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
541     CHECK_NULL_VOID(textLayoutProperty);
542     if (textLayoutProperty->GetTextColor().value_or(themeTextColor_) == themeTextColor_) {
543         textLayoutProperty->UpdateTextColor(buttonTheme->GetTextColor(buttonStyle, buttonRole));
544         textNode->MarkDirtyNode();
545     }
546 }
547 
SetBuilderFunc(ButtonMakeCallback && makeFunc)548 void ButtonPattern::SetBuilderFunc(ButtonMakeCallback&& makeFunc)
549 {
550     if (makeFunc == nullptr) {
551         makeFunc_ = std::nullopt;
552         contentModifierNode_ = nullptr;
553         auto host = GetHost();
554         CHECK_NULL_VOID(host);
555         for (auto child : host->GetChildren()) {
556             auto childNode = DynamicCast<FrameNode>(child);
557             if (childNode) {
558                 childNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
559             }
560         }
561         OnModifyDone();
562         return;
563     }
564     makeFunc_ = std::move(makeFunc);
565 }
566 
UpdateTextFontScale(RefPtr<ButtonLayoutProperty> & layoutProperty,RefPtr<TextLayoutProperty> & textLayoutProperty)567 void ButtonPattern::UpdateTextFontScale(
568     RefPtr<ButtonLayoutProperty>& layoutProperty, RefPtr<TextLayoutProperty>& textLayoutProperty)
569 {
570     CHECK_NULL_VOID(layoutProperty);
571     CHECK_NULL_VOID(textLayoutProperty);
572     if (layoutProperty->HasType() && layoutProperty->GetType() == ButtonType::CIRCLE) {
573         textLayoutProperty->UpdateMaxFontScale(NORMAL_SCALE);
574     } else {
575         textLayoutProperty->ResetMaxFontScale();
576     }
577 }
578 } // namespace OHOS::Ace::NG
579