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