• 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 
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     CheckLocalizedBorderRadiuses();
214     FireBuilder();
215     InitButtonLabel();
216     HandleBackgroundColor();
217     HandleEnabled();
218     InitHoverEvent();
219     InitTouchEvent();
220 }
221 
CheckLocalizedBorderRadiuses()222 void ButtonPattern::CheckLocalizedBorderRadiuses()
223 {
224     auto host = GetHost();
225     CHECK_NULL_VOID(host);
226     const auto& property = host->GetLayoutProperty<ButtonLayoutProperty>();
227     CHECK_NULL_VOID(property);
228     auto direction = property->GetNonAutoLayoutDirection();
229     BorderRadiusProperty borderRadius;
230     BorderRadiusProperty borderRadiusProperty = property->GetBorderRadiusValue(BorderRadiusProperty {});
231     if (!borderRadiusProperty.radiusTopStart.has_value() && !borderRadiusProperty.radiusTopEnd.has_value() &&
232         !borderRadiusProperty.radiusBottomStart.has_value() && !borderRadiusProperty.radiusBottomEnd.has_value()) {
233         return;
234     }
235     if (borderRadiusProperty.radiusTopStart.has_value()) {
236         borderRadius.radiusTopStart = borderRadiusProperty.radiusTopStart;
237         if (direction == TextDirection::RTL) {
238             borderRadius.radiusTopRight = borderRadiusProperty.radiusTopStart;
239         } else {
240             borderRadius.radiusTopLeft = borderRadiusProperty.radiusTopStart;
241         }
242     }
243     if (borderRadiusProperty.radiusTopEnd.has_value()) {
244         borderRadius.radiusTopEnd = borderRadiusProperty.radiusTopEnd;
245         if (direction == TextDirection::RTL) {
246             borderRadius.radiusTopLeft = borderRadiusProperty.radiusTopEnd;
247         } else {
248             borderRadius.radiusTopRight = borderRadiusProperty.radiusTopEnd;
249         }
250     }
251     if (borderRadiusProperty.radiusBottomStart.has_value()) {
252         borderRadius.radiusBottomStart = borderRadiusProperty.radiusBottomStart;
253         if (direction == TextDirection::RTL) {
254             borderRadius.radiusBottomRight = borderRadiusProperty.radiusBottomStart;
255         } else {
256             borderRadius.radiusBottomLeft = borderRadiusProperty.radiusBottomStart;
257         }
258     }
259     if (borderRadiusProperty.radiusBottomEnd.has_value()) {
260         borderRadius.radiusBottomEnd = borderRadiusProperty.radiusBottomEnd;
261         if (direction == TextDirection::RTL) {
262             borderRadius.radiusBottomLeft = borderRadiusProperty.radiusBottomEnd;
263         } else {
264             borderRadius.radiusBottomRight = borderRadiusProperty.radiusBottomEnd;
265         }
266     }
267     property->UpdateBorderRadius(borderRadius);
268 }
269 
InitTouchEvent()270 void ButtonPattern::InitTouchEvent()
271 {
272     if (touchListener_) {
273         return;
274     }
275     auto host = GetHost();
276     CHECK_NULL_VOID(host);
277     auto gesture = host->GetOrCreateGestureEventHub();
278     CHECK_NULL_VOID(gesture);
279     auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
280         auto buttonPattern = weak.Upgrade();
281         CHECK_NULL_VOID(buttonPattern);
282         if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
283             TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "button touch down");
284             buttonPattern->OnTouchDown();
285         }
286         if (info.GetTouches().front().GetTouchType() == TouchType::UP ||
287             info.GetTouches().front().GetTouchType() == TouchType::CANCEL) {
288             TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "button touch up");
289             buttonPattern->OnTouchUp();
290         }
291     };
292     touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
293     gesture->AddTouchEvent(touchListener_);
294 }
295 
OnAfterModifyDone()296 void ButtonPattern::OnAfterModifyDone()
297 {
298     auto host = GetHost();
299     CHECK_NULL_VOID(host);
300     auto inspectorId = host->GetInspectorId().value_or("");
301     if (!inspectorId.empty()) {
302         auto text = host->GetAccessibilityProperty<NG::AccessibilityProperty>()->GetText();
303         Recorder::NodeDataCache::Get().PutString(host, inspectorId, text);
304     }
305 }
306 
InitHoverEvent()307 void ButtonPattern::InitHoverEvent()
308 {
309     if (UseContentModifier()) {
310         return;
311     }
312     auto host = GetHost();
313     CHECK_NULL_VOID(host);
314     auto eventHub = host->GetEventHub<ButtonEventHub>();
315     auto inputHub = eventHub->GetOrCreateInputEventHub();
316     auto hoverEffect = inputHub->GetHoverEffect();
317     inputHub->SetHoverEffect(hoverEffect == HoverEffectType::BOARD ? HoverEffectType::AUTO : hoverEffect);
318     if (hoverListener_) {
319         return;
320     }
321     auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
322         TAG_LOGI(AceLogTag::ACE_SELECT_COMPONENT, "button hover %{public}d", isHover);
323         auto pattern = weak.Upgrade();
324         if (pattern) {
325             pattern->HandleHoverEvent(isHover);
326         }
327     };
328 
329     hoverListener_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
330     inputHub->AddOnHoverEvent(hoverListener_);
331 }
332 
OnTouchDown()333 void ButtonPattern::OnTouchDown()
334 {
335     isPress_ = true;
336     FireBuilder();
337     if (UseContentModifier()) {
338         return;
339     }
340     auto host = GetHost();
341     CHECK_NULL_VOID(host);
342     auto buttonEventHub = GetEventHub<ButtonEventHub>();
343     CHECK_NULL_VOID(buttonEventHub);
344     if (buttonEventHub->GetStateEffect()) {
345         auto renderContext = host->GetRenderContext();
346         CHECK_NULL_VOID(renderContext);
347         backgroundColor_ = renderContext->GetBackgroundColor().value_or(Color::TRANSPARENT);
348         if (isSetClickedColor_) {
349             // for user self-defined
350             renderContext->UpdateBackgroundColor(clickedColor_);
351             return;
352         }
353         // for system default
354         auto isNeedToHandleHoverOpacity = IsNeedToHandleHoverOpacity();
355         AnimateTouchAndHover(renderContext, isNeedToHandleHoverOpacity ? TYPE_HOVER : TYPE_CANCEL, TYPE_TOUCH,
356             TOUCH_DURATION, isNeedToHandleHoverOpacity ? Curves::SHARP : Curves::FRICTION);
357     }
358 }
359 
OnTouchUp()360 void ButtonPattern::OnTouchUp()
361 {
362     isPress_ = false;
363     FireBuilder();
364     if (UseContentModifier()) {
365         return;
366     }
367     auto host = GetHost();
368     CHECK_NULL_VOID(host);
369     auto buttonEventHub = GetEventHub<ButtonEventHub>();
370     CHECK_NULL_VOID(buttonEventHub);
371     auto toggleButtonPattern = host->GetPattern<ToggleButtonPattern>();
372     if (toggleButtonPattern) {
373         toggleButtonPattern->OnClick();
374     }
375     if (buttonEventHub->GetStateEffect()) {
376         auto renderContext = host->GetRenderContext();
377         if (isSetClickedColor_) {
378             renderContext->UpdateBackgroundColor(backgroundColor_);
379             return;
380         }
381         if (buttonEventHub->IsEnabled()) {
382             auto isNeedToHandleHoverOpacity = IsNeedToHandleHoverOpacity();
383             AnimateTouchAndHover(renderContext, TYPE_TOUCH, isNeedToHandleHoverOpacity ? TYPE_HOVER : TYPE_CANCEL,
384                 TOUCH_DURATION, isNeedToHandleHoverOpacity ? Curves::SHARP : Curves::FRICTION);
385         } else {
386             AnimateTouchAndHover(renderContext, TYPE_TOUCH, TYPE_CANCEL, TOUCH_DURATION, Curves::FRICTION);
387         }
388     }
389 }
390 
HandleHoverEvent(bool isHover)391 void ButtonPattern::HandleHoverEvent(bool isHover)
392 {
393     isHover_ = isHover;
394     auto host = GetHost();
395     CHECK_NULL_VOID(host);
396     auto eventHub = host->GetEventHub<EventHub>();
397     CHECK_NULL_VOID(eventHub);
398     auto enabled = eventHub->IsEnabled();
399     auto inputEventHub = host->GetOrCreateInputEventHub();
400     auto hoverEffect = inputEventHub->GetHoverEffect();
401     if (hoverEffect == HoverEffectType::NONE || hoverEffect == HoverEffectType::SCALE) {
402         return;
403     }
404     if (!isPress_ && (enabled || !isHover)) {
405         auto renderContext = host->GetRenderContext();
406         CHECK_NULL_VOID(renderContext);
407         AnimateTouchAndHover(renderContext, isHover ? TYPE_CANCEL : TYPE_HOVER, isHover ? TYPE_HOVER : TYPE_CANCEL,
408             MOUSE_HOVER_DURATION, Curves::FRICTION);
409     }
410 }
411 
HandleBackgroundColor()412 void ButtonPattern::HandleBackgroundColor()
413 {
414     auto host = GetHost();
415     CHECK_NULL_VOID(host);
416     auto* pipeline = host->GetContextWithCheck();
417     CHECK_NULL_VOID(pipeline);
418     auto renderContext = host->GetRenderContext();
419     CHECK_NULL_VOID(renderContext);
420     auto layoutProperty = GetLayoutProperty<ButtonLayoutProperty>();
421     CHECK_NULL_VOID(layoutProperty);
422     auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
423     CHECK_NULL_VOID(buttonTheme);
424     ButtonStyleMode buttonStyle = layoutProperty->GetButtonStyle().value_or(ButtonStyleMode::EMPHASIZE);
425     ButtonRole buttonRole = layoutProperty->GetButtonRole().value_or(ButtonRole::NORMAL);
426     if (UseContentModifier()) {
427         renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
428         renderContext->ResetBackgroundColor();
429         return;
430     }
431     if (!renderContext->HasBackgroundColor()) {
432         renderContext->UpdateBackgroundColor(buttonTheme->GetBgColor(buttonStyle, buttonRole));
433     }
434     themeBgColor_ = buttonTheme->GetBgColor(buttonStyle, buttonRole);
435     themeTextColor_ = buttonTheme->GetTextColor(buttonStyle, buttonRole);
436 }
437 
HandleEnabled()438 void ButtonPattern::HandleEnabled()
439 {
440     if (UseContentModifier()) {
441         return;
442     }
443     auto host = GetHost();
444     CHECK_NULL_VOID(host);
445     auto eventHub = host->GetEventHub<EventHub>();
446     CHECK_NULL_VOID(eventHub);
447     auto enabled = eventHub->IsEnabled();
448     auto renderContext = host->GetRenderContext();
449     CHECK_NULL_VOID(renderContext);
450     auto* pipeline = host->GetContextWithCheck();
451     CHECK_NULL_VOID(pipeline);
452     auto theme = pipeline->GetTheme<ButtonTheme>();
453     CHECK_NULL_VOID(theme);
454     auto alpha = theme->GetBgDisabledAlpha();
455     auto originalOpacity = renderContext->GetOpacityValue(1.0);
456     renderContext->OnOpacityUpdate(enabled ? originalOpacity : alpha * originalOpacity);
457 }
458 
AnimateTouchAndHover(RefPtr<RenderContext> & renderContext,int32_t typeFrom,int32_t typeTo,int32_t duration,const RefPtr<Curve> & curve)459 void ButtonPattern::AnimateTouchAndHover(RefPtr<RenderContext>& renderContext, int32_t typeFrom, int32_t typeTo,
460     int32_t duration, const RefPtr<Curve>& curve)
461 {
462     auto host = GetHost();
463     CHECK_NULL_VOID(host);
464     auto* pipeline = host->GetContextWithCheck();
465     CHECK_NULL_VOID(pipeline);
466     auto theme = pipeline->GetTheme<ButtonTheme>();
467     CHECK_NULL_VOID(theme);
468     TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "button animate touch from %{public}d to %{public}d", typeFrom, typeTo);
469     Color blendColorFrom = GetColorFromType(theme, typeFrom);
470     Color blendColorTo = GetColorFromType(theme, typeTo);
471     renderContext->BlendBgColor(blendColorFrom);
472     AnimationOption option = AnimationOption();
473     option.SetDuration(duration);
474     option.SetCurve(curve);
475     AnimationUtils::Animate(option, [renderContext, blendColorTo]() { renderContext->BlendBgColor(blendColorTo); });
476 }
477 
SetButtonPress(double xPos,double yPos)478 void ButtonPattern::SetButtonPress(double xPos, double yPos)
479 {
480     CHECK_NULL_VOID(contentModifierNode_);
481     auto host = GetHost();
482     CHECK_NULL_VOID(host);
483     auto eventHub = host->GetEventHub<EventHub>();
484     CHECK_NULL_VOID(eventHub);
485     auto enabled = eventHub->IsEnabled();
486     if (!enabled) {
487         return;
488     }
489     GestureEvent info;
490     std::chrono::microseconds microseconds(GetMicroTickCount());
491     TimeStamp time(microseconds);
492     info.SetTimeStamp(time);
493     auto x = Dimension(xPos, DimensionUnit::VP);
494     auto y = Dimension(yPos, DimensionUnit::VP);
495     info.SetLocalLocation(Offset(xPos, yPos));
496     auto currFrameRect = host->GetRectWithRender();
497     auto frameGlobalOffset = currFrameRect.GetOffset();
498     auto globalX = Dimension(x.ConvertToPx() + frameGlobalOffset.GetX());
499     auto globalY = Dimension(y.ConvertToPx() + frameGlobalOffset.GetY());
500     info.SetGlobalLocation(Offset(globalX.ConvertToVp(), globalY.ConvertToVp()));
501     auto pipeline = PipelineContext::GetCurrentContext();
502     CHECK_NULL_VOID(pipeline);
503     auto windowOffset = pipeline->GetCurrentWindowRect().GetOffset();
504     auto screenX = Dimension(windowOffset.GetX()) + globalX;
505     auto screenY = Dimension(windowOffset.GetY()) + globalY;
506     info.SetScreenLocation(Offset(screenX.ConvertToVp(), screenY.ConvertToVp()));
507     if (clickEventFunc_.has_value()) {
508         (clickEventFunc_.value())(info);
509     }
510 }
511 
FireBuilder()512 void ButtonPattern::FireBuilder()
513 {
514     auto host = GetHost();
515     CHECK_NULL_VOID(host);
516     auto gestureEventHub = host->GetOrCreateGestureEventHub();
517     CHECK_NULL_VOID(gestureEventHub);
518     if (!makeFunc_.has_value()) {
519         gestureEventHub->SetRedirectClick(false);
520         auto children = host->GetChildren();
521         for (const auto& child : children) {
522             if (nodeId_ == -1) {
523                 return;
524             }
525             if (child->GetId() == nodeId_) {
526                 host->RemoveChildAndReturnIndex(child);
527                 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
528                 break;
529             }
530         }
531         return;
532     } else {
533         gestureEventHub->SetRedirectClick(true);
534     }
535     auto builderNode = BuildContentModifierNode();
536     if (contentModifierNode_ == builderNode) {
537         return;
538     }
539     host->RemoveChildAndReturnIndex(contentModifierNode_);
540     contentModifierNode_ = builderNode;
541     CHECK_NULL_VOID(contentModifierNode_);
542     nodeId_ = contentModifierNode_->GetId();
543     host->AddChild(contentModifierNode_, 0);
544     host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
545     clickEventFunc_ = gestureEventHub->GetClickEvent();
546 }
547 
BuildContentModifierNode()548 RefPtr<FrameNode> ButtonPattern::BuildContentModifierNode()
549 {
550     auto host = GetHost();
551     CHECK_NULL_RETURN(host, nullptr);
552     auto layoutProperty = GetLayoutProperty<ButtonLayoutProperty>();
553     CHECK_NULL_RETURN(layoutProperty, nullptr);
554     auto label = layoutProperty->GetLabel().value_or("");
555     auto eventHub = host->GetEventHub<EventHub>();
556     CHECK_NULL_RETURN(eventHub, nullptr);
557     auto enabled = eventHub->IsEnabled();
558     ButtonConfiguration buttonConfiguration(label, isPress_, enabled);
559     return (makeFunc_.value())(buttonConfiguration);
560 }
561 
OnColorConfigurationUpdate()562 void ButtonPattern::OnColorConfigurationUpdate()
563 {
564     auto node = GetHost();
565     CHECK_NULL_VOID(node);
566     if (isColorUpdateFlag_) {
567         node->SetNeedCallChildrenUpdate(false);
568         return;
569     }
570     auto buttonLayoutProperty = node->GetLayoutProperty<ButtonLayoutProperty>();
571     CHECK_NULL_VOID(buttonLayoutProperty);
572     if (buttonLayoutProperty->GetCreateWithLabelValue(true)) {
573         node->SetNeedCallChildrenUpdate(false);
574     }
575     auto pipeline = node->GetContextWithCheck();
576     CHECK_NULL_VOID(pipeline);
577     auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
578     ButtonStyleMode buttonStyle = buttonLayoutProperty->GetButtonStyle().value_or(ButtonStyleMode::EMPHASIZE);
579     ButtonRole buttonRole = buttonLayoutProperty->GetButtonRole().value_or(ButtonRole::NORMAL);
580     auto renderContext = node->GetRenderContext();
581     CHECK_NULL_VOID(renderContext);
582     if (renderContext->GetBackgroundColor().value_or(themeBgColor_) == themeBgColor_) {
583         auto color = buttonTheme->GetBgColor(buttonStyle, buttonRole);
584         renderContext->UpdateBackgroundColor(color);
585     }
586     auto textNode = DynamicCast<FrameNode>(node->GetFirstChild());
587     CHECK_NULL_VOID(textNode);
588     auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
589     CHECK_NULL_VOID(textLayoutProperty);
590     if (textLayoutProperty->GetTextColor().value_or(themeTextColor_) == themeTextColor_) {
591         textLayoutProperty->UpdateTextColor(buttonTheme->GetTextColor(buttonStyle, buttonRole));
592         textNode->MarkDirtyNode();
593     }
594 }
595 
SetBuilderFunc(ButtonMakeCallback && makeFunc)596 void ButtonPattern::SetBuilderFunc(ButtonMakeCallback&& makeFunc)
597 {
598     if (makeFunc == nullptr) {
599         makeFunc_ = std::nullopt;
600         contentModifierNode_ = nullptr;
601         auto host = GetHost();
602         CHECK_NULL_VOID(host);
603         for (auto child : host->GetChildren()) {
604             auto childNode = DynamicCast<FrameNode>(child);
605             if (childNode) {
606                 childNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
607             }
608         }
609         OnModifyDone();
610         return;
611     }
612     makeFunc_ = std::move(makeFunc);
613 }
614 
UpdateTextFontScale(RefPtr<ButtonLayoutProperty> & layoutProperty,RefPtr<TextLayoutProperty> & textLayoutProperty)615 void ButtonPattern::UpdateTextFontScale(
616     RefPtr<ButtonLayoutProperty>& layoutProperty, RefPtr<TextLayoutProperty>& textLayoutProperty)
617 {
618     CHECK_NULL_VOID(layoutProperty);
619     CHECK_NULL_VOID(textLayoutProperty);
620     if (layoutProperty->HasType() && layoutProperty->GetType() == ButtonType::CIRCLE) {
621         textLayoutProperty->UpdateMaxFontScale(NORMAL_SCALE);
622     } else {
623         textLayoutProperty->ResetMaxFontScale();
624     }
625 }
626 } // namespace OHOS::Ace::NG
627