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