• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 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 #include "core/components_ng/pattern/bubble/bubble_pattern.h"
16 
17 #include "base/geometry/ng/offset_t.h"
18 #include "base/memory/ace_type.h"
19 #include "base/subwindow/subwindow.h"
20 #include "base/subwindow/subwindow_manager.h"
21 #include "base/utils/utils.h"
22 #include "core/common/container.h"
23 #include "core/common/container_scope.h"
24 #include "core/common/window_animation_config.h"
25 #include "core/components/common/properties/shadow_config.h"
26 #include "core/components/container_modal/container_modal_constants.h"
27 #include "core/components_ng/base/frame_node.h"
28 #include "core/components_ng/base/ui_node.h"
29 #include "core/components_ng/pattern/bubble/bubble_layout_property.h"
30 #include "core/components_ng/pattern/bubble/bubble_render_property.h"
31 #include "core/components_ng/pattern/text/text_layout_property.h"
32 #include "core/components_ng/property/property.h"
33 #include "core/components_v2/inspector/inspector_constants.h"
34 #include "core/event/touch_event.h"
35 #include "core/pipeline/pipeline_base.h"
36 #include "core/pipeline/pipeline_context.h"
37 #include "core/pipeline_ng/pipeline_context.h"
38 
39 namespace OHOS::Ace::NG {
40 namespace {
41 constexpr float VISIABLE_ALPHA = 1.0f;
42 constexpr float INVISIABLE_ALPHA = 0.0f;
43 constexpr int32_t ENTRY_ANIMATION_DURATION = 250;
44 constexpr int32_t EXIT_ANIMATION_DURATION = 100;
45 const Dimension INVISIABLE_OFFSET = 8.0_px;
46 } // namespace
47 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,bool skipMeasure,bool skipLayout)48 bool BubblePattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, bool skipMeasure, bool skipLayout)
49 {
50     if (skipMeasure && skipLayout) {
51         return false;
52     }
53     auto host = GetHost();
54     CHECK_NULL_RETURN(host, false);
55     auto paintProperty = host->GetPaintProperty<BubbleRenderProperty>();
56     CHECK_NULL_RETURN(paintProperty, false);
57     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
58     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
59     auto bubbleLayoutAlgorithm = DynamicCast<BubbleLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
60     CHECK_NULL_RETURN(bubbleLayoutAlgorithm, false);
61 
62     // Calculating bubble offset and set.
63     auto childRenderOffset = bubbleLayoutAlgorithm->GetChildOffsetAfterLayout(dirty);
64     auto childNode = DynamicCast<FrameNode>(host->GetFirstChild());
65     CHECK_NULL_RETURN(childNode, false);
66     auto childContext = childNode->GetRenderContext();
67     CHECK_NULL_RETURN(childContext, false);
68     childContext->UpdateOffset(childRenderOffset);
69 
70     showArrow_ = bubbleLayoutAlgorithm->ShowArrow();
71     arrowPosition_ = bubbleLayoutAlgorithm->GetArrowPosition();
72     childOffset_ = bubbleLayoutAlgorithm->GetChildOffset();
73     childSize_ = bubbleLayoutAlgorithm->GetChildSize();
74     touchRegion_ = bubbleLayoutAlgorithm->GetTouchRegion();
75     targetOffset_ = bubbleLayoutAlgorithm->GetTargetOffset();
76     targetSize_ = bubbleLayoutAlgorithm->GetTargetSize();
77     arrowPlacement_ = bubbleLayoutAlgorithm->GetArrowPlacement();
78     paintProperty->UpdatePlacement(bubbleLayoutAlgorithm->GetArrowPlacement());
79     if (delayShow_) {
80         delayShow_ = false;
81         if (transitionStatus_ == TransitionStatus::INVISIABLE) {
82             StartEnteringAnimation(nullptr);
83         }
84     }
85     return true;
86 }
87 
OnModifyDone()88 void BubblePattern::OnModifyDone()
89 {
90     Pattern::OnModifyDone();
91     InitTouchEvent();
92     RegisterButtonOnHover();
93     RegisterButtonOnTouch();
94 }
95 
OnAttachToFrameNode()96 void BubblePattern::OnAttachToFrameNode()
97 {
98     auto host = GetHost();
99     CHECK_NULL_VOID(host);
100     auto pipelineContext = PipelineContext::GetCurrentContext();
101     CHECK_NULL_VOID(pipelineContext);
102     pipelineContext->AddWindowSizeChangeCallback(host->GetId());
103     pipelineContext->AddWindowStateChangedCallback(host->GetId());
104     host->GetRenderContext()->SetClipToFrame(true);
105 
106     auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
107     CHECK_NULL_VOID(targetNode);
108     pipelineContext->AddOnAreaChangeNode(targetNode->GetId());
109     OnAreaChangedFunc onAreaChangedFunc = [popupNodeWk = WeakPtr<FrameNode>(host)](const RectF& /* oldRect */,
110                                               const OffsetF& /* oldOrigin */, const RectF& /* rect */,
111                                               const OffsetF& /* origin */) {
112         auto popupNode = popupNodeWk.Upgrade();
113         CHECK_NULL_VOID(popupNode);
114         popupNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
115     };
116     targetNode->SetOnAreaChangeCallback(std::move(onAreaChangedFunc));
117 }
118 
OnDetachFromFrameNode(FrameNode * frameNode)119 void BubblePattern::OnDetachFromFrameNode(FrameNode* frameNode)
120 {
121     auto pipeline = PipelineContext::GetCurrentContext();
122     CHECK_NULL_VOID(pipeline);
123     pipeline->RemoveWindowSizeChangeCallback(frameNode->GetId());
124     pipeline->RemoveWindowStateChangedCallback(frameNode->GetId());
125     auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
126     CHECK_NULL_VOID(targetNode);
127     pipeline->RemoveOnAreaChangeNode(targetNode->GetId());
128 }
129 
InitTouchEvent()130 void BubblePattern::InitTouchEvent()
131 {
132     auto host = GetHost();
133     CHECK_NULL_VOID(host);
134     auto hub = host->GetEventHub<EventHub>();
135     CHECK_NULL_VOID(hub);
136     auto gestureHub = hub->GetOrCreateGestureEventHub();
137     CHECK_NULL_VOID(gestureHub);
138     if (touchEvent_) {
139         return;
140     }
141     auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
142         auto pattern = weak.Upgrade();
143         if (pattern) {
144             pattern->HandleTouchEvent(info);
145         }
146     };
147     touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
148     gestureHub->AddTouchEvent(touchEvent_);
149 }
150 
HandleTouchEvent(const TouchEventInfo & info)151 void BubblePattern::HandleTouchEvent(const TouchEventInfo& info)
152 {
153     if (info.GetTouches().empty()) {
154         return;
155     }
156     auto touchType = info.GetTouches().front().GetTouchType();
157     auto clickPos = info.GetTouches().front().GetLocalLocation();
158     if (touchType == TouchType::DOWN) {
159         HandleTouchDown(clickPos);
160     }
161 }
162 
HandleTouchDown(const Offset & clickPosition)163 void BubblePattern::HandleTouchDown(const Offset& clickPosition)
164 {
165     // TODO: need to check click position
166     auto host = GetHost();
167     CHECK_NULL_VOID(host);
168     auto bubbleRenderProp = host->GetPaintProperty<BubbleRenderProperty>();
169     CHECK_NULL_VOID(bubbleRenderProp);
170     if (touchRegion_.IsInRegion(PointF(clickPosition.GetX(), clickPosition.GetY()))) {
171         LOGI("Contains the touch region.");
172         return;
173     }
174     auto autoCancel = bubbleRenderProp->GetAutoCancel().value_or(true);
175     if (autoCancel) {
176         PopBubble();
177     }
178 }
179 
RegisterButtonOnHover()180 void BubblePattern::RegisterButtonOnHover()
181 {
182     if (mouseEventInitFlag_) {
183         return;
184     }
185     auto paintProps = GetPaintProperty<BubbleRenderProperty>();
186     CHECK_NULL_VOID(paintProps);
187     auto primaryButtonShow = paintProps->GetPrimaryButtonShow().value_or(false);
188     auto secondaryButtonShow = paintProps->GetSecondaryButtonShow().value_or(false);
189     auto custom = paintProps->GetUseCustom().value_or(false);
190     if (custom) {
191         return;
192     }
193     if (!primaryButtonShow && !secondaryButtonShow) {
194         return;
195     }
196     auto buttonRowNode = GetButtonRowNode();
197     for (const auto& child : buttonRowNode->GetChildren()) {
198         auto buttonNode = AceType::DynamicCast<FrameNode>(child);
199         CHECK_NULL_VOID(buttonNode);
200         if (buttonNode->GetTag() != V2::BUTTON_ETS_TAG) {
201             return;
202         }
203         auto inputHub = buttonNode->GetOrCreateInputEventHub();
204         CHECK_NULL_VOID(inputHub);
205         auto mouseTask = [weak = WeakClaim(this), buttonNode](bool isHover) {
206             auto pattern = weak.Upgrade();
207             CHECK_NULL_VOID(pattern);
208             pattern->ButtonOnHover(isHover, buttonNode);
209         };
210         auto mouseEvent = MakeRefPtr<InputEvent>(std::move(mouseTask));
211         inputHub->AddOnHoverEvent(mouseEvent);
212     }
213     mouseEventInitFlag_ = true;
214 }
215 
ButtonOnHover(bool isHover,const RefPtr<NG::FrameNode> & buttonNode)216 void BubblePattern::ButtonOnHover(bool isHover, const RefPtr<NG::FrameNode>& buttonNode)
217 {
218     auto renderContext = buttonNode->GetRenderContext();
219     CHECK_NULL_VOID(renderContext);
220     auto pipeline = PipelineBase::GetCurrentContext();
221     CHECK_NULL_VOID(pipeline);
222     auto theme = pipeline->GetTheme<PopupTheme>();
223     isHover_ = isHover;
224     auto hoverColor = theme->GetButtonHoverColor();
225     auto backgroundColor = theme->GetButtonBackgroundColor();
226     if (isHover) {
227         // normal to hover
228         Animation(renderContext, hoverColor, theme->GetHoverAnimationDuration(), Curves::FRICTION);
229     } else {
230         // hover to normal
231         Animation(renderContext, backgroundColor, theme->GetHoverAnimationDuration(), Curves::FRICTION);
232     }
233 }
234 
RegisterButtonOnTouch()235 void BubblePattern::RegisterButtonOnTouch()
236 {
237     if (touchEventInitFlag_) {
238         return;
239     }
240     auto paintProps = GetPaintProperty<BubbleRenderProperty>();
241     CHECK_NULL_VOID(paintProps);
242     auto primaryButtonShow = paintProps->GetPrimaryButtonShow().value_or(false);
243     auto secondaryButtonShow = paintProps->GetSecondaryButtonShow().value_or(false);
244     auto custom = paintProps->GetUseCustom().value_or(false);
245     if (custom) {
246         return;
247     }
248     if (!primaryButtonShow && !secondaryButtonShow) {
249         return;
250     }
251 
252     auto buttonRowNode = GetButtonRowNode();
253     for (const auto& child : buttonRowNode->GetChildren()) {
254         auto buttonNode = AceType::DynamicCast<FrameNode>(child);
255         CHECK_NULL_VOID(buttonNode);
256         if (buttonNode->GetTag() != V2::BUTTON_ETS_TAG) {
257             return;
258         }
259         auto gestureHub = buttonNode->GetOrCreateGestureEventHub();
260         CHECK_NULL_VOID(gestureHub);
261         auto touchCallback = [weak = WeakClaim(this), buttonNode](const TouchEventInfo& info) {
262             auto pattern = weak.Upgrade();
263             CHECK_NULL_VOID(pattern);
264             pattern->ButtonOnPress(info, buttonNode);
265         };
266         auto touchEvent = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
267         gestureHub->AddTouchEvent(touchEvent);
268     }
269     touchEventInitFlag_ = true;
270 }
271 
ButtonOnPress(const TouchEventInfo & info,const RefPtr<NG::FrameNode> & buttonNode)272 void BubblePattern::ButtonOnPress(const TouchEventInfo& info, const RefPtr<NG::FrameNode>& buttonNode)
273 {
274     auto touchType = info.GetTouches().front().GetTouchType();
275     auto renderContext = buttonNode->GetRenderContext();
276     CHECK_NULL_VOID(renderContext);
277     auto pipeline = PipelineBase::GetCurrentContext();
278     CHECK_NULL_VOID(pipeline);
279     auto theme = pipeline->GetTheme<PopupTheme>();
280     CHECK_NULL_VOID(theme);
281     auto pressColor = theme->GetButtonPressColor();
282     auto hoverColor = theme->GetButtonHoverColor();
283     auto backgroundColor = theme->GetButtonBackgroundColor();
284     if (touchType == TouchType::DOWN) {
285         if (isHover_) {
286             // hover to press
287             Animation(renderContext, pressColor, theme->GetHoverToPressAnimationDuration(), Curves::SHARP);
288         } else {
289             // normal to press
290             Animation(renderContext, pressColor, theme->GetHoverAnimationDuration(), Curves::SHARP);
291         }
292     } else if (touchType == TouchType::UP) {
293         if (isHover_) {
294             // press to hover
295             Animation(renderContext, hoverColor, theme->GetHoverToPressAnimationDuration(), Curves::SHARP);
296         } else {
297             // press to normal
298             Animation(renderContext, backgroundColor, theme->GetHoverAnimationDuration(), Curves::SHARP);
299         }
300     }
301 }
302 
GetButtonRowNode()303 RefPtr<FrameNode> BubblePattern::GetButtonRowNode()
304 {
305     auto host = GetHost();
306     CHECK_NULL_RETURN(host, nullptr);
307     auto columnNode = AceType::DynamicCast<FrameNode>(host->GetLastChild());
308     CHECK_NULL_RETURN(columnNode, nullptr);
309     auto buttonRowNode = AceType::DynamicCast<FrameNode>(columnNode->GetLastChild());
310     CHECK_NULL_RETURN(buttonRowNode, nullptr);
311     if (buttonRowNode->GetTag() != V2::ROW_ETS_TAG) {
312         return nullptr;
313     }
314     if (buttonRowNode->GetChildren().empty()) {
315         return nullptr;
316     }
317     return buttonRowNode;
318 }
319 
PopBubble()320 void BubblePattern::PopBubble()
321 {
322     LOGI("BubblePattern::PopBubble from click");
323     auto pipelineNg = PipelineContext::GetCurrentContext();
324     CHECK_NULL_VOID(pipelineNg);
325     auto overlayManager = pipelineNg->GetOverlayManager();
326     CHECK_NULL_VOID(overlayManager);
327     auto popupInfo = overlayManager->GetPopupInfo(targetNodeId_);
328     if (!popupInfo.isCurrentOnShow) {
329         return;
330     }
331     popupInfo.markNeedUpdate = true;
332     popupInfo.popupId = -1;
333     auto host = GetHost();
334     CHECK_NULL_VOID(host);
335     auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
336     CHECK_NULL_VOID(layoutProp);
337     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
338     if (showInSubWindow) {
339         SubwindowManager::GetInstance()->HidePopupNG(targetNodeId_);
340     } else {
341         overlayManager->HidePopup(targetNodeId_, popupInfo);
342     }
343 }
344 
GetPopupTheme()345 RefPtr<PopupTheme> BubblePattern::GetPopupTheme()
346 {
347     auto pipelineContext = PipelineBase::GetCurrentContext();
348     CHECK_NULL_RETURN(pipelineContext, nullptr);
349     auto popupTheme = pipelineContext->GetTheme<PopupTheme>();
350     CHECK_NULL_RETURN(popupTheme, nullptr);
351     return popupTheme;
352 }
353 
Animation(RefPtr<RenderContext> & renderContext,const Color & endColor,int32_t duration,const RefPtr<Curve> & curve)354 void BubblePattern::Animation(
355     RefPtr<RenderContext>& renderContext, const Color& endColor, int32_t duration, const RefPtr<Curve>& curve)
356 {
357     AnimationOption option = AnimationOption();
358     option.SetCurve(curve);
359     option.SetDuration(duration);
360     option.SetFillMode(FillMode::FORWARDS);
361     AnimationUtils::Animate(
362         option, [buttonContext = renderContext, color = endColor]() { buttonContext->UpdateBackgroundColor(color); });
363 }
364 
PostTask(const TaskExecutor::Task & task)365 bool BubblePattern::PostTask(const TaskExecutor::Task& task)
366 {
367     auto pipeline = PipelineBase::GetCurrentContext();
368     CHECK_NULL_RETURN(pipeline, false);
369     auto taskExecutor = pipeline->GetTaskExecutor();
370     CHECK_NULL_RETURN(taskExecutor, false);
371     return taskExecutor->PostTask(task, TaskExecutor::TaskType::UI);
372 }
373 
StartEnteringAnimation(std::function<void ()> finish)374 void BubblePattern::StartEnteringAnimation(std::function<void()> finish)
375 {
376     if (!arrowPlacement_.has_value()) {
377         delayShow_ = true;
378         return;
379     }
380     if (IsOnShow()) {
381         return;
382     }
383 
384     if (transitionStatus_ == TransitionStatus::INVISIABLE) {
385         ResetToInvisible();
386     }
387 
388     StartOffsetEnteringAnimation();
389     StartAlphaEnteringAnimation(finish);
390 }
391 
StartOffsetEnteringAnimation()392 void BubblePattern::StartOffsetEnteringAnimation()
393 {
394     AnimationOption optionPosition;
395     optionPosition.SetDuration(ENTRY_ANIMATION_DURATION);
396     optionPosition.SetCurve(Curves::FRICTION);
397     AnimationUtils::Animate(
398         optionPosition,
399         [weak = WeakClaim(this)]() {
400             auto pattern = weak.Upgrade();
401             CHECK_NULL_VOID(pattern);
402             auto renderContext = pattern->GetRenderContext();
403             CHECK_NULL_VOID(renderContext);
404             renderContext->UpdateOffset(OffsetT<Dimension>());
405             renderContext->SyncGeometryProperties(nullptr);
406         },
407         nullptr);
408 }
409 
StartAlphaEnteringAnimation(std::function<void ()> finish)410 void BubblePattern::StartAlphaEnteringAnimation(std::function<void()> finish)
411 {
412     AnimationOption optionAlpha;
413     optionAlpha.SetDuration(ENTRY_ANIMATION_DURATION);
414     optionAlpha.SetCurve(Curves::SHARP);
415     AnimationUtils::Animate(
416         optionAlpha,
417         [weak = WeakClaim(this)]() {
418             auto pattern = weak.Upgrade();
419             CHECK_NULL_VOID(pattern);
420             pattern->transitionStatus_ = TransitionStatus::ENTERING;
421             auto renderContext = pattern->GetRenderContext();
422             CHECK_NULL_VOID(renderContext);
423             renderContext->UpdateOpacity(VISIABLE_ALPHA);
424         },
425         [weak = WeakClaim(this), finish, id = Container::CurrentId()]() {
426             ContainerScope scope(id);
427             auto pattern = weak.Upgrade();
428             CHECK_NULL_VOID(pattern);
429             if (pattern->transitionStatus_ != TransitionStatus::ENTERING) {
430                 return;
431             }
432             pattern->transitionStatus_ = TransitionStatus::NORMAL;
433             if (finish) {
434                 pattern->PostTask([finish, id = Container::CurrentId()]() {
435                     ContainerScope scope(id);
436                     finish();
437                 });
438             }
439         });
440 }
441 
StartExitingAnimation(std::function<void ()> finish)442 void BubblePattern::StartExitingAnimation(std::function<void()> finish)
443 {
444     StartOffsetExitingAnimation();
445     StartAlphaExitingAnimation(finish);
446 }
447 
StartOffsetExitingAnimation()448 void BubblePattern::StartOffsetExitingAnimation()
449 {
450     AnimationOption optionPosition;
451     optionPosition.SetDuration(EXIT_ANIMATION_DURATION);
452     optionPosition.SetCurve(Curves::FRICTION);
453     AnimationUtils::Animate(
454         optionPosition,
455         [weak = WeakClaim(this)]() {
456             auto pattern = weak.Upgrade();
457             CHECK_NULL_VOID(pattern);
458             auto renderContext = pattern->GetRenderContext();
459             CHECK_NULL_VOID(renderContext);
460             renderContext->UpdateOffset(pattern->GetInvisibleOffset());
461             renderContext->SyncGeometryProperties(nullptr);
462         },
463         nullptr);
464 }
465 
StartAlphaExitingAnimation(std::function<void ()> finish)466 void BubblePattern::StartAlphaExitingAnimation(std::function<void()> finish)
467 {
468     AnimationOption optionAlpha;
469     optionAlpha.SetDuration(EXIT_ANIMATION_DURATION);
470     optionAlpha.SetCurve(Curves::SHARP);
471     AnimationUtils::Animate(
472         optionAlpha,
473         [weak = WeakClaim(this)]() {
474             auto pattern = weak.Upgrade();
475             CHECK_NULL_VOID(pattern);
476             pattern->transitionStatus_ = TransitionStatus::EXITING;
477             auto renderContext = pattern->GetRenderContext();
478             CHECK_NULL_VOID(renderContext);
479             renderContext->UpdateOpacity(INVISIABLE_ALPHA);
480         },
481         [weak = WeakClaim(this), finish, id = Container::CurrentId()]() {
482             ContainerScope scope(id);
483             auto pattern = weak.Upgrade();
484             CHECK_NULL_VOID(pattern);
485             if (pattern->transitionStatus_ != TransitionStatus::EXITING) {
486                 return;
487             }
488             pattern->transitionStatus_ = TransitionStatus::INVISIABLE;
489             if (finish) {
490                 pattern->PostTask([finish, id = Container::CurrentId()]() {
491                     ContainerScope scope(id);
492                     finish();
493                 });
494             }
495         });
496 }
497 
IsOnShow()498 bool BubblePattern::IsOnShow()
499 {
500     return (transitionStatus_ == TransitionStatus::ENTERING) || (transitionStatus_ == TransitionStatus::NORMAL);
501 }
502 
IsExiting()503 bool BubblePattern::IsExiting()
504 {
505     return transitionStatus_ == TransitionStatus::EXITING;
506 }
507 
GetInvisibleOffset()508 OffsetT<Dimension> BubblePattern::GetInvisibleOffset()
509 {
510     if (!arrowPlacement_.has_value()) {
511         return OffsetT<Dimension>();
512     }
513 
514     OffsetT<Dimension> offset;
515     switch (arrowPlacement_.value()) {
516         case Placement::LEFT:
517         case Placement::LEFT_TOP:
518         case Placement::LEFT_BOTTOM:
519             offset.AddX(INVISIABLE_OFFSET);
520             break;
521         case Placement::RIGHT:
522         case Placement::RIGHT_TOP:
523         case Placement::RIGHT_BOTTOM:
524             offset.AddX(INVISIABLE_OFFSET * -1);
525             break;
526         case Placement::TOP:
527         case Placement::TOP_LEFT:
528         case Placement::TOP_RIGHT:
529             offset.AddY(INVISIABLE_OFFSET);
530             break;
531         case Placement::BOTTOM:
532         case Placement::BOTTOM_LEFT:
533         case Placement::BOTTOM_RIGHT:
534             offset.AddY(INVISIABLE_OFFSET * -1);
535             break;
536         default:
537             break;
538     }
539     return offset;
540 }
541 
GetRenderContext()542 RefPtr<RenderContext> BubblePattern::GetRenderContext()
543 {
544     auto frameNode = GetHost();
545     CHECK_NULL_RETURN(frameNode, nullptr);
546     return frameNode->GetRenderContext();
547 }
548 
ResetToInvisible()549 void BubblePattern::ResetToInvisible()
550 {
551     auto renderContext = GetRenderContext();
552     CHECK_NULL_VOID(renderContext);
553 
554     renderContext->UpdateOpacity(INVISIABLE_ALPHA);
555     renderContext->UpdateOffset(GetInvisibleOffset());
556     renderContext->SyncGeometryProperties(nullptr);
557 }
558 
OnWindowSizeChanged(int32_t width,int32_t height,WindowSizeChangeReason type)559 void BubblePattern::OnWindowSizeChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
560 {
561     switch (type) {
562         case WindowSizeChangeReason::UNDEFINED:
563         case WindowSizeChangeReason::MOVE:
564         case WindowSizeChangeReason::RESIZE:
565         case WindowSizeChangeReason::DRAG_START:
566         case WindowSizeChangeReason::DRAG:
567         case WindowSizeChangeReason::DRAG_END: {
568             break;
569         }
570         default: {
571             auto pipelineNg = PipelineContext::GetCurrentContext();
572             CHECK_NULL_VOID(pipelineNg);
573             auto overlayManager = pipelineNg->GetOverlayManager();
574             CHECK_NULL_VOID(overlayManager);
575             overlayManager->HideAllPopups();
576             auto host = GetHost();
577             CHECK_NULL_VOID(host);
578             auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
579             CHECK_NULL_VOID(layoutProp);
580             auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
581             if (showInSubWindow) {
582                 auto subwindow = SubwindowManager::GetInstance()->GetSubwindow(Container::CurrentId());
583                 CHECK_NULL_VOID(subwindow);
584                 subwindow->HidePopupNG(targetNodeId_);
585             }
586         }
587     }
588 }
589 
OnWindowHide()590 void BubblePattern::OnWindowHide()
591 {
592     auto pipelineNg = PipelineContext::GetCurrentContext();
593     CHECK_NULL_VOID(pipelineNg);
594     auto overlayManager = pipelineNg->GetOverlayManager();
595     CHECK_NULL_VOID(overlayManager);
596     overlayManager->HideAllPopups();
597     auto host = GetHost();
598     CHECK_NULL_VOID(host);
599     auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
600     CHECK_NULL_VOID(layoutProp);
601     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
602     if (showInSubWindow) {
603         auto subwindow = SubwindowManager::GetInstance()->GetSubwindow(Container::CurrentId());
604         CHECK_NULL_VOID(subwindow);
605         subwindow->HidePopupNG(targetNodeId_);
606     }
607 }
608 
OnColorConfigurationUpdate()609 void BubblePattern::OnColorConfigurationUpdate()
610 {
611     if (isCustomPopup_) {
612         return;
613     }
614     auto host = GetHost();
615     CHECK_NULL_VOID(host);
616     host->SetNeedCallChildrenUpdate(false);
617     auto context = host->GetContext();
618     CHECK_NULL_VOID(context);
619     auto popupTheme = context->GetTheme<PopupTheme>();
620     CHECK_NULL_VOID(popupTheme);
621     auto buttonRowNode = GetButtonRowNode();
622     CHECK_NULL_VOID(buttonRowNode);
623     for (const auto& child : buttonRowNode->GetChildren()) {
624         auto buttonNode = AceType::DynamicCast<FrameNode>(child);
625         CHECK_NULL_VOID(buttonNode);
626         if (buttonNode->GetTag() != V2::BUTTON_ETS_TAG) {
627             return;
628         }
629         auto renderContext = buttonNode->GetRenderContext();
630         CHECK_NULL_VOID(renderContext);
631         auto childText = buttonNode->GetFirstChild();
632         CHECK_NULL_VOID(childText);
633         auto textNode = DynamicCast<FrameNode>(childText);
634         CHECK_NULL_VOID(textNode);
635         auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
636         CHECK_NULL_VOID(textLayoutProperty);
637         textLayoutProperty->UpdateTextColor(popupTheme->GetFontColor());
638         textNode->MarkDirtyNode();
639     }
640     host->MarkDirtyNode();
641 }
642 
643 } // namespace OHOS::Ace::NG