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