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