1 /*
2 * Copyright (c) 2022-2024 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 "base/log/dump_log.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 showArrow_ = bubbleLayoutAlgorithm->ShowArrow();
63 arrowPosition_ = bubbleLayoutAlgorithm->GetArrowPosition();
64 childOffset_ = bubbleLayoutAlgorithm->GetChildOffset();
65 childSize_ = bubbleLayoutAlgorithm->GetChildSize();
66 touchRegion_ = bubbleLayoutAlgorithm->GetTouchRegion();
67 hostWindowRect_ = bubbleLayoutAlgorithm->GetHostWindowRect();
68 targetOffset_ = bubbleLayoutAlgorithm->GetTargetOffset();
69 targetSize_ = bubbleLayoutAlgorithm->GetTargetSize();
70 arrowPlacement_ = bubbleLayoutAlgorithm->GetArrowPlacement();
71 clipPath_ = bubbleLayoutAlgorithm->GetClipPath();
72 clipFrameNode_ = bubbleLayoutAlgorithm->GetClipFrameNode();
73 arrowOffsetsFromClip_ = bubbleLayoutAlgorithm->GetArrowOffsetsFromClip();
74 arrowWidth_ = bubbleLayoutAlgorithm->GetArrowWidth();
75 arrowHeight_ = bubbleLayoutAlgorithm->GetArrowHeight();
76 border_ = bubbleLayoutAlgorithm->GetBorder();
77 dumpInfo_ = bubbleLayoutAlgorithm->GetDumpInfo();
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 if (SystemProperties::GetColorMode() != colorMode_ && !isCustomPopup_) {
91 colorMode_ = SystemProperties::GetColorMode();
92 UpdateBubbleText();
93 }
94 UpdateAgingTextSize();
95 Pattern::OnModifyDone();
96 InitTouchEvent();
97 RegisterButtonOnHover();
98 RegisterButtonOnTouch();
99 }
100
AddPipelineCallBack()101 void BubblePattern::AddPipelineCallBack()
102 {
103 auto host = GetHost();
104 CHECK_NULL_VOID(host);
105 auto pipelineContext = PipelineContext::GetCurrentContext();
106 CHECK_NULL_VOID(pipelineContext);
107 pipelineContext->AddWindowSizeChangeCallback(host->GetId());
108 pipelineContext->AddWindowStateChangedCallback(host->GetId());
109 }
110
OnAttachToFrameNode()111 void BubblePattern::OnAttachToFrameNode()
112 {
113 auto host = GetHost();
114 CHECK_NULL_VOID(host);
115 host->GetRenderContext()->SetClipToFrame(true);
116
117 auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
118 CHECK_NULL_VOID(targetNode);
119 auto pipelineContext = host->GetContextRefPtr();
120 CHECK_NULL_VOID(pipelineContext);
121 hasOnAreaChange_ = pipelineContext->HasOnAreaChangeNode(targetNode->GetId());
122 auto eventHub = targetNode->GetEventHub<EventHub>();
123 CHECK_NULL_VOID(eventHub);
124 OnAreaChangedFunc onAreaChangedFunc = [popupNodeWk = WeakPtr<FrameNode>(host)](const RectF& /* oldRect */,
125 const OffsetF& /* oldOrigin */, const RectF& /* rect */,
126 const OffsetF& /* origin */) {
127 auto popupNode = popupNodeWk.Upgrade();
128 CHECK_NULL_VOID(popupNode);
129 popupNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
130 };
131 eventHub->AddInnerOnAreaChangedCallback(host->GetId(), std::move(onAreaChangedFunc));
132 }
133
OnDetachFromFrameNode(FrameNode * frameNode)134 void BubblePattern::OnDetachFromFrameNode(FrameNode* frameNode)
135 {
136 auto pipeline = PipelineContext::GetCurrentContext();
137 CHECK_NULL_VOID(pipeline);
138 pipeline->RemoveWindowSizeChangeCallback(frameNode->GetId());
139 pipeline->RemoveWindowStateChangedCallback(frameNode->GetId());
140 auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
141 CHECK_NULL_VOID(targetNode);
142 if (!hasOnAreaChange_) {
143 pipeline->RemoveOnAreaChangeNode(targetNode->GetId());
144 }
145 }
146
InitTouchEvent()147 void BubblePattern::InitTouchEvent()
148 {
149 auto host = GetHost();
150 CHECK_NULL_VOID(host);
151 auto hub = host->GetEventHub<EventHub>();
152 CHECK_NULL_VOID(hub);
153 auto gestureHub = hub->GetOrCreateGestureEventHub();
154 CHECK_NULL_VOID(gestureHub);
155 if (touchEvent_) {
156 return;
157 }
158 auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
159 auto pattern = weak.Upgrade();
160 if (pattern) {
161 pattern->HandleTouchEvent(info);
162 }
163 };
164 touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
165 gestureHub->AddTouchEvent(touchEvent_);
166 }
167
HandleTouchEvent(const TouchEventInfo & info)168 void BubblePattern::HandleTouchEvent(const TouchEventInfo& info)
169 {
170 if (info.GetTouches().empty()) {
171 return;
172 }
173 auto touchType = info.GetTouches().front().GetTouchType();
174 auto clickPos = info.GetTouches().front().GetLocalLocation();
175 if (touchType == TouchType::DOWN) {
176 HandleTouchDown(clickPos);
177 }
178 }
179
HandleTouchDown(const Offset & clickPosition)180 void BubblePattern::HandleTouchDown(const Offset& clickPosition)
181 {
182 auto host = GetHost();
183 CHECK_NULL_VOID(host);
184 auto bubbleRenderProp = host->GetPaintProperty<BubbleRenderProperty>();
185 CHECK_NULL_VOID(bubbleRenderProp);
186 if (touchRegion_.IsInRegion(PointF(clickPosition.GetX(), clickPosition.GetY()))) {
187 return;
188 }
189 auto autoCancel = bubbleRenderProp->GetAutoCancel().value_or(true);
190 if (autoCancel) {
191 TAG_LOGD(AceLogTag::ACE_DIALOG, "handle popup touch down event");
192 if (!GetInteractiveDismiss()) {
193 return;
194 }
195 if (HasOnWillDismiss()) {
196 auto pipelineNg = PipelineContext::GetCurrentContext();
197 CHECK_NULL_VOID(pipelineNg);
198 auto overlayManager = pipelineNg->GetOverlayManager();
199 CHECK_NULL_VOID(overlayManager);
200 overlayManager->SetDismissPopupId(targetNodeId_);
201 CallOnWillDismiss(static_cast<int32_t>(DismissReason::TOUCH_OUTSIDE));
202 return;
203 }
204 PopBubble();
205 }
206 }
207
RegisterButtonOnHover()208 void BubblePattern::RegisterButtonOnHover()
209 {
210 if (mouseEventInitFlag_) {
211 return;
212 }
213 auto paintProps = GetPaintProperty<BubbleRenderProperty>();
214 CHECK_NULL_VOID(paintProps);
215 auto primaryButtonShow = paintProps->GetPrimaryButtonShow().value_or(false);
216 auto secondaryButtonShow = paintProps->GetSecondaryButtonShow().value_or(false);
217 auto custom = paintProps->GetUseCustom().value_or(false);
218 if (custom) {
219 return;
220 }
221 if (!primaryButtonShow && !secondaryButtonShow) {
222 return;
223 }
224 auto buttonRowNode = GetButtonRowNode();
225 for (const auto& child : buttonRowNode->GetChildren()) {
226 auto buttonNode = AceType::DynamicCast<FrameNode>(child);
227 CHECK_NULL_VOID(buttonNode);
228 if (buttonNode->GetTag() != V2::BUTTON_ETS_TAG) {
229 return;
230 }
231 auto inputHub = buttonNode->GetOrCreateInputEventHub();
232 CHECK_NULL_VOID(inputHub);
233 auto mouseTask = [weak = WeakClaim(this), buttonNodeWK = WeakPtr<FrameNode>(buttonNode)](bool isHover) {
234 auto pattern = weak.Upgrade();
235 CHECK_NULL_VOID(pattern);
236 auto buttonNode = buttonNodeWK.Upgrade();
237 CHECK_NULL_VOID(buttonNode);
238 pattern->ButtonOnHover(isHover, buttonNode);
239 };
240 auto mouseEvent = MakeRefPtr<InputEvent>(std::move(mouseTask));
241 inputHub->AddOnHoverEvent(mouseEvent);
242 }
243 mouseEventInitFlag_ = true;
244 }
245
ButtonOnHover(bool isHover,const RefPtr<NG::FrameNode> & buttonNode)246 void BubblePattern::ButtonOnHover(bool isHover, const RefPtr<NG::FrameNode>& buttonNode)
247 {
248 auto renderContext = buttonNode->GetRenderContext();
249 CHECK_NULL_VOID(renderContext);
250 auto pipeline = PipelineBase::GetCurrentContext();
251 CHECK_NULL_VOID(pipeline);
252 auto theme = pipeline->GetTheme<PopupTheme>();
253 isHover_ = isHover;
254 auto hoverColor = theme->GetButtonHoverColor();
255 auto backgroundColor = theme->GetButtonBackgroundColor();
256 if (isHover) {
257 // normal to hover
258 Animation(renderContext, hoverColor, theme->GetHoverAnimationDuration(), Curves::FRICTION);
259 } else {
260 // hover to normal
261 Animation(renderContext, backgroundColor, theme->GetHoverAnimationDuration(), Curves::FRICTION);
262 }
263 }
264
RegisterButtonOnTouch()265 void BubblePattern::RegisterButtonOnTouch()
266 {
267 if (touchEventInitFlag_) {
268 return;
269 }
270 auto paintProps = GetPaintProperty<BubbleRenderProperty>();
271 CHECK_NULL_VOID(paintProps);
272 auto primaryButtonShow = paintProps->GetPrimaryButtonShow().value_or(false);
273 auto secondaryButtonShow = paintProps->GetSecondaryButtonShow().value_or(false);
274 auto custom = paintProps->GetUseCustom().value_or(false);
275 if (custom) {
276 return;
277 }
278 if (!primaryButtonShow && !secondaryButtonShow) {
279 return;
280 }
281
282 auto buttonRowNode = GetButtonRowNode();
283 for (const auto& child : buttonRowNode->GetChildren()) {
284 auto buttonNode = AceType::DynamicCast<FrameNode>(child);
285 CHECK_NULL_VOID(buttonNode);
286 if (buttonNode->GetTag() != V2::BUTTON_ETS_TAG) {
287 return;
288 }
289 auto gestureHub = buttonNode->GetOrCreateGestureEventHub();
290 CHECK_NULL_VOID(gestureHub);
291 auto touchCallback = [weak = WeakClaim(this), buttonNodeWK = WeakPtr<FrameNode>(buttonNode)]
292 (const TouchEventInfo& info) {
293 auto pattern = weak.Upgrade();
294 CHECK_NULL_VOID(pattern);
295 auto buttonNode = buttonNodeWK.Upgrade();
296 CHECK_NULL_VOID(buttonNode);
297 pattern->ButtonOnPress(info, buttonNode);
298 };
299 auto touchEvent = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
300 gestureHub->AddTouchEvent(touchEvent);
301 }
302 touchEventInitFlag_ = true;
303 }
304
ButtonOnPress(const TouchEventInfo & info,const RefPtr<NG::FrameNode> & buttonNode)305 void BubblePattern::ButtonOnPress(const TouchEventInfo& info, const RefPtr<NG::FrameNode>& buttonNode)
306 {
307 auto touchType = info.GetTouches().front().GetTouchType();
308 auto renderContext = buttonNode->GetRenderContext();
309 CHECK_NULL_VOID(renderContext);
310 auto pipeline = PipelineBase::GetCurrentContext();
311 CHECK_NULL_VOID(pipeline);
312 auto theme = pipeline->GetTheme<PopupTheme>();
313 CHECK_NULL_VOID(theme);
314 auto pressColor = theme->GetButtonPressColor();
315 auto hoverColor = theme->GetButtonHoverColor();
316 auto backgroundColor = theme->GetButtonBackgroundColor();
317 if (touchType == TouchType::DOWN) {
318 if (isHover_) {
319 // hover to press
320 Animation(renderContext, pressColor, theme->GetHoverToPressAnimationDuration(), Curves::SHARP);
321 } else {
322 // normal to press
323 Animation(renderContext, pressColor, theme->GetHoverAnimationDuration(), Curves::SHARP);
324 }
325 } else if (touchType == TouchType::UP) {
326 if (isHover_) {
327 // press to hover
328 Animation(renderContext, hoverColor, theme->GetHoverToPressAnimationDuration(), Curves::SHARP);
329 } else {
330 // press to normal
331 Animation(renderContext, backgroundColor, theme->GetHoverAnimationDuration(), Curves::SHARP);
332 }
333 }
334 }
335
GetButtonRowNode()336 RefPtr<FrameNode> BubblePattern::GetButtonRowNode()
337 {
338 auto host = GetHost();
339 CHECK_NULL_RETURN(host, nullptr);
340 auto columnNode = AceType::DynamicCast<FrameNode>(host->GetLastChild());
341 CHECK_NULL_RETURN(columnNode, nullptr);
342 auto lastColumnNode = AceType::DynamicCast<FrameNode>(columnNode->GetLastChild());
343 CHECK_NULL_RETURN(lastColumnNode, nullptr);
344 auto buttonRowNode = AceType::DynamicCast<FrameNode>(lastColumnNode->GetLastChild());
345 CHECK_NULL_RETURN(buttonRowNode, nullptr);
346 if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
347 if (buttonRowNode->GetTag() != V2::ROW_ETS_TAG) {
348 return nullptr;
349 }
350 } else {
351 if (buttonRowNode->GetTag() != V2::FLEX_ETS_TAG) {
352 return nullptr;
353 }
354 }
355 if (buttonRowNode->GetChildren().empty()) {
356 return nullptr;
357 }
358 return buttonRowNode;
359 }
360
PopBubble()361 void BubblePattern::PopBubble()
362 {
363 auto pipelineNg = PipelineContext::GetCurrentContext();
364 CHECK_NULL_VOID(pipelineNg);
365 auto overlayManager = pipelineNg->GetOverlayManager();
366 CHECK_NULL_VOID(overlayManager);
367 auto popupInfo = overlayManager->GetPopupInfo(targetNodeId_);
368 if (!popupInfo.isCurrentOnShow) {
369 return;
370 }
371 popupInfo.markNeedUpdate = true;
372 auto host = GetHost();
373 CHECK_NULL_VOID(host);
374 auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
375 CHECK_NULL_VOID(layoutProp);
376 auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
377 if (showInSubWindow) {
378 SubwindowManager::GetInstance()->HidePopupNG(targetNodeId_);
379 } else {
380 overlayManager->HidePopup(targetNodeId_, popupInfo);
381 }
382 }
383
GetPopupTheme()384 RefPtr<PopupTheme> BubblePattern::GetPopupTheme()
385 {
386 auto pipelineContext = PipelineBase::GetCurrentContext();
387 CHECK_NULL_RETURN(pipelineContext, nullptr);
388 auto popupTheme = pipelineContext->GetTheme<PopupTheme>();
389 CHECK_NULL_RETURN(popupTheme, nullptr);
390 return popupTheme;
391 }
392
Animation(RefPtr<RenderContext> & renderContext,const Color & endColor,int32_t duration,const RefPtr<Curve> & curve)393 void BubblePattern::Animation(
394 RefPtr<RenderContext>& renderContext, const Color& endColor, int32_t duration, const RefPtr<Curve>& curve)
395 {
396 AnimationOption option = AnimationOption();
397 option.SetCurve(curve);
398 option.SetDuration(duration);
399 option.SetFillMode(FillMode::FORWARDS);
400 AnimationUtils::Animate(
401 option, [buttonContext = renderContext, color = endColor]() { buttonContext->UpdateBackgroundColor(color); });
402 }
403
PostTask(const TaskExecutor::Task & task,const std::string & name)404 bool BubblePattern::PostTask(const TaskExecutor::Task& task, const std::string& name)
405 {
406 auto pipeline = PipelineBase::GetCurrentContext();
407 CHECK_NULL_RETURN(pipeline, false);
408 auto taskExecutor = pipeline->GetTaskExecutor();
409 CHECK_NULL_RETURN(taskExecutor, false);
410 return taskExecutor->PostTask(task, TaskExecutor::TaskType::UI, name);
411 }
412
StartEnteringTransitionEffects(const RefPtr<FrameNode> & popupNode,const std::function<void ()> & finish)413 void BubblePattern::StartEnteringTransitionEffects(
414 const RefPtr<FrameNode>& popupNode, const std::function<void()>& finish)
415 {
416 auto popupId = popupNode->GetId();
417 auto pattern = popupNode->GetPattern<BubblePattern>();
418 pattern->transitionStatus_ = TransitionStatus::ENTERING;
419 auto layoutProp = popupNode->GetLayoutProperty<BubbleLayoutProperty>();
420 CHECK_NULL_VOID(layoutProp);
421 layoutProp->UpdateVisibility(VisibleType::VISIBLE, false);
422 auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
423 auto isBlock = layoutProp->GetBlockEventValue(true);
424 auto& renderContext = popupNode->GetRenderContext();
425 renderContext->SetTransitionInCallback(
426 [weak = WeakClaim(this), finish, showInSubWindow, popupId, isBlock]() {
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 (showInSubWindow) {
434 std::vector<Rect> rects;
435 if (!isBlock) {
436 auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
437 pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
438 rects.emplace_back(rect);
439 } else {
440 auto parentWindowRect = pattern->GetHostWindowRect();
441 auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
442 pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
443 rects.emplace_back(parentWindowRect);
444 rects.emplace_back(rect);
445 }
446 auto subWindowMgr = SubwindowManager::GetInstance();
447 subWindowMgr->SetHotAreas(rects, popupId, pattern->GetContainerId());
448 }
449 if (finish) {
450 finish();
451 }
452 });
453 }
454
StartExitingTransitionEffects(const RefPtr<FrameNode> & popupNode,const std::function<void ()> & finish)455 void BubblePattern::StartExitingTransitionEffects(
456 const RefPtr<FrameNode>& popupNode, const std::function<void()>& finish)
457 {
458 auto pattern = popupNode->GetPattern<BubblePattern>();
459 pattern->transitionStatus_ = TransitionStatus::EXITING;
460 auto layoutProperty = popupNode->GetLayoutProperty();
461 layoutProperty->UpdateVisibility(VisibleType::INVISIBLE, true);
462 auto renderContext = popupNode->GetRenderContext();
463 renderContext->SetTransitionOutCallback(
464 [weak = WeakClaim(this), finish]() {
465 auto pattern = weak.Upgrade();
466 CHECK_NULL_VOID(pattern);
467 if (pattern->transitionStatus_ != TransitionStatus::EXITING) {
468 return;
469 }
470 pattern->transitionStatus_ = TransitionStatus::INVISIABLE;
471 if (finish) {
472 finish();
473 }
474 });
475 }
476
StartEnteringAnimation(std::function<void ()> finish)477 void BubblePattern::StartEnteringAnimation(std::function<void()> finish)
478 {
479 if (!arrowPlacement_.has_value()) {
480 delayShow_ = true;
481 finish_ = finish;
482 return;
483 }
484 if (IsOnShow()) {
485 return;
486 }
487
488 if (transitionStatus_ == TransitionStatus::INVISIABLE) {
489 ResetToInvisible();
490 }
491
492 StartOffsetEnteringAnimation();
493 if (finish) {
494 StartAlphaEnteringAnimation(finish);
495 } else {
496 StartAlphaEnteringAnimation(finish_);
497 }
498 }
499
StartOffsetEnteringAnimation()500 void BubblePattern::StartOffsetEnteringAnimation()
501 {
502 AnimationOption optionPosition;
503 optionPosition.SetDuration(ENTRY_ANIMATION_DURATION);
504 optionPosition.SetCurve(Curves::FRICTION);
505 AnimationUtils::Animate(
506 optionPosition,
507 [weak = WeakClaim(this)]() {
508 auto pattern = weak.Upgrade();
509 CHECK_NULL_VOID(pattern);
510 auto renderContext = pattern->GetRenderContext();
511 CHECK_NULL_VOID(renderContext);
512 renderContext->UpdateOffset(OffsetT<Dimension>());
513 renderContext->SyncGeometryProperties(nullptr);
514 },
515 nullptr);
516 }
517
StartAlphaEnteringAnimation(std::function<void ()> finish)518 void BubblePattern::StartAlphaEnteringAnimation(std::function<void()> finish)
519 {
520 AnimationOption optionAlpha;
521 optionAlpha.SetDuration(ENTRY_ANIMATION_DURATION);
522 optionAlpha.SetCurve(Curves::SHARP);
523 auto host = GetHost();
524 auto popupId = host->GetId();
525 CHECK_NULL_VOID(host);
526 auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
527 CHECK_NULL_VOID(layoutProp);
528 auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
529 auto isBlock = layoutProp->GetBlockEventValue(true);
530 AnimationUtils::Animate(
531 optionAlpha,
532 [weak = WeakClaim(this)]() {
533 auto pattern = weak.Upgrade();
534 CHECK_NULL_VOID(pattern);
535 pattern->transitionStatus_ = TransitionStatus::ENTERING;
536 auto renderContext = pattern->GetRenderContext();
537 CHECK_NULL_VOID(renderContext);
538 renderContext->UpdateOpacity(VISIABLE_ALPHA);
539 },
540 [weak = WeakClaim(this), finish, showInSubWindow, popupId, isBlock]() {
541 auto pattern = weak.Upgrade();
542 CHECK_NULL_VOID(pattern);
543 if (pattern->transitionStatus_ != TransitionStatus::ENTERING) {
544 return;
545 }
546 pattern->transitionStatus_ = TransitionStatus::NORMAL;
547 if (showInSubWindow) {
548 std::vector<Rect> rects;
549 if (!isBlock) {
550 auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
551 pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
552 rects.emplace_back(rect);
553 } else {
554 auto parentWindowRect = pattern->GetHostWindowRect();
555 auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
556 pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
557 rects.emplace_back(parentWindowRect);
558 rects.emplace_back(rect);
559 }
560 auto subWindowMgr = SubwindowManager::GetInstance();
561 subWindowMgr->SetHotAreas(rects, popupId, pattern->GetContainerId());
562 }
563 if (finish) {
564 finish();
565 }
566 });
567 }
568
StartExitingAnimation(std::function<void ()> finish)569 void BubblePattern::StartExitingAnimation(std::function<void()> finish)
570 {
571 StartOffsetExitingAnimation();
572 StartAlphaExitingAnimation(finish);
573 }
574
StartOffsetExitingAnimation()575 void BubblePattern::StartOffsetExitingAnimation()
576 {
577 AnimationOption optionPosition;
578 optionPosition.SetDuration(EXIT_ANIMATION_DURATION);
579 optionPosition.SetCurve(Curves::FRICTION);
580 AnimationUtils::Animate(
581 optionPosition,
582 [weak = WeakClaim(this)]() {
583 auto pattern = weak.Upgrade();
584 CHECK_NULL_VOID(pattern);
585 auto renderContext = pattern->GetRenderContext();
586 CHECK_NULL_VOID(renderContext);
587 renderContext->UpdateOffset(pattern->GetInvisibleOffset());
588 renderContext->SyncGeometryProperties(nullptr);
589 },
590 nullptr);
591 }
592
StartAlphaExitingAnimation(std::function<void ()> finish)593 void BubblePattern::StartAlphaExitingAnimation(std::function<void()> finish)
594 {
595 AnimationOption optionAlpha;
596 optionAlpha.SetDuration(EXIT_ANIMATION_DURATION);
597 optionAlpha.SetCurve(Curves::SHARP);
598 AnimationUtils::Animate(
599 optionAlpha,
600 [weak = WeakClaim(this)]() {
601 auto pattern = weak.Upgrade();
602 CHECK_NULL_VOID(pattern);
603 pattern->transitionStatus_ = TransitionStatus::EXITING;
604 auto renderContext = pattern->GetRenderContext();
605 CHECK_NULL_VOID(renderContext);
606 renderContext->UpdateOpacity(INVISIABLE_ALPHA);
607 },
608 [weak = WeakClaim(this), finish]() {
609 auto pattern = weak.Upgrade();
610 CHECK_NULL_VOID(pattern);
611 if (pattern->transitionStatus_ != TransitionStatus::EXITING) {
612 return;
613 }
614 pattern->transitionStatus_ = TransitionStatus::INVISIABLE;
615 if (finish) {
616 finish();
617 }
618 });
619 }
620
IsOnShow()621 bool BubblePattern::IsOnShow()
622 {
623 return (transitionStatus_ == TransitionStatus::ENTERING) || (transitionStatus_ == TransitionStatus::NORMAL);
624 }
625
IsExiting()626 bool BubblePattern::IsExiting()
627 {
628 return transitionStatus_ == TransitionStatus::EXITING;
629 }
630
GetInvisibleOffset()631 OffsetT<Dimension> BubblePattern::GetInvisibleOffset()
632 {
633 if (!arrowPlacement_.has_value()) {
634 return OffsetT<Dimension>();
635 }
636
637 OffsetT<Dimension> offset;
638 switch (arrowPlacement_.value()) {
639 case Placement::LEFT:
640 case Placement::LEFT_TOP:
641 case Placement::LEFT_BOTTOM:
642 offset.AddX(INVISIABLE_OFFSET);
643 break;
644 case Placement::RIGHT:
645 case Placement::RIGHT_TOP:
646 case Placement::RIGHT_BOTTOM:
647 offset.AddX(INVISIABLE_OFFSET * -1);
648 break;
649 case Placement::TOP:
650 case Placement::TOP_LEFT:
651 case Placement::TOP_RIGHT:
652 offset.AddY(INVISIABLE_OFFSET);
653 break;
654 case Placement::BOTTOM:
655 case Placement::BOTTOM_LEFT:
656 case Placement::BOTTOM_RIGHT:
657 offset.AddY(INVISIABLE_OFFSET * -1);
658 break;
659 default:
660 break;
661 }
662 return offset;
663 }
664
GetRenderContext()665 RefPtr<RenderContext> BubblePattern::GetRenderContext()
666 {
667 auto frameNode = GetHost();
668 CHECK_NULL_RETURN(frameNode, nullptr);
669 return frameNode->GetRenderContext();
670 }
671
ResetToInvisible()672 void BubblePattern::ResetToInvisible()
673 {
674 auto renderContext = GetRenderContext();
675 CHECK_NULL_VOID(renderContext);
676
677 renderContext->UpdateOpacity(INVISIABLE_ALPHA);
678 renderContext->UpdateOffset(GetInvisibleOffset());
679 renderContext->SyncGeometryProperties(nullptr);
680 }
681
OnWindowSizeChanged(int32_t width,int32_t height,WindowSizeChangeReason type)682 void BubblePattern::OnWindowSizeChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
683 {
684 switch (type) {
685 case WindowSizeChangeReason::UNDEFINED:
686 case WindowSizeChangeReason::MOVE:
687 case WindowSizeChangeReason::RESIZE:
688 case WindowSizeChangeReason::DRAG_START:
689 case WindowSizeChangeReason::DRAG:
690 case WindowSizeChangeReason::DRAG_END: {
691 break;
692 }
693 default: {
694 auto pipelineNg = PipelineContext::GetCurrentContext();
695 CHECK_NULL_VOID(pipelineNg);
696 auto overlayManager = pipelineNg->GetOverlayManager();
697 CHECK_NULL_VOID(overlayManager);
698 overlayManager->HideAllPopups();
699 auto host = GetHost();
700 CHECK_NULL_VOID(host);
701 auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
702 CHECK_NULL_VOID(layoutProp);
703 auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
704 if (showInSubWindow) {
705 auto subwindow = SubwindowManager::GetInstance()->GetSubwindow(Container::CurrentId());
706 CHECK_NULL_VOID(subwindow);
707 subwindow->HidePopupNG(targetNodeId_);
708 }
709 }
710 }
711 }
712
OnWindowHide()713 void BubblePattern::OnWindowHide()
714 {
715 auto pipelineNg = PipelineContext::GetCurrentContext();
716 CHECK_NULL_VOID(pipelineNg);
717 auto overlayManager = pipelineNg->GetOverlayManager();
718 CHECK_NULL_VOID(overlayManager);
719 overlayManager->HideAllPopups();
720 auto host = GetHost();
721 CHECK_NULL_VOID(host);
722 auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
723 CHECK_NULL_VOID(layoutProp);
724 auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
725 if (showInSubWindow) {
726 auto subwindow = SubwindowManager::GetInstance()->GetSubwindow(Container::CurrentId());
727 CHECK_NULL_VOID(subwindow);
728 subwindow->HidePopupNG(targetNodeId_);
729 }
730 }
731
732
UpdateText(const RefPtr<UINode> & node,const RefPtr<PopupTheme> & popupTheme)733 void BubblePattern::UpdateText(const RefPtr<UINode>& node, const RefPtr<PopupTheme>& popupTheme)
734 {
735 if (node->GetTag() == V2::TEXT_ETS_TAG) {
736 auto textNode = DynamicCast<FrameNode>(node);
737 CHECK_NULL_VOID(textNode);
738 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
739 CHECK_NULL_VOID(textLayoutProperty);
740 auto parentNode = node->GetParent();
741 if (parentNode && parentNode->GetTag() == V2::BUTTON_ETS_TAG &&
742 !(Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
743 textLayoutProperty->UpdateTextColor(popupTheme->GetButtonFontColor());
744 } else if (!isSetMessageColor_) {
745 if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
746 textLayoutProperty->UpdateTextColor(popupTheme->GetFontColor());
747 } else {
748 textLayoutProperty->UpdateTextColor(popupTheme->GetFontPrimaryColor());
749 }
750 }
751 textNode->MarkModifyDone();
752 } else {
753 for (const auto& childNode : node->GetChildren()) {
754 UpdateText(childNode, popupTheme);
755 }
756 }
757 }
758
DumpInfo()759 void BubblePattern::DumpInfo()
760 {
761 DumpLog::GetInstance().AddDesc("enableArrow: " + std::to_string(dumpInfo_.enableArrow));
762 DumpLog::GetInstance().AddDesc("mask: " + std::to_string(dumpInfo_.mask));
763 DumpLog::GetInstance().AddDesc("targetTag: " + dumpInfo_.targetNode + ", targetID: "
764 + std::to_string(dumpInfo_.targetID));
765 DumpLog::GetInstance().AddDesc("targetOffset: " + dumpInfo_.targetOffset.ToString());
766 DumpLog::GetInstance().AddDesc("targetSize: " + dumpInfo_.targetOffset.ToString());
767 DumpLog::GetInstance().AddDesc("touchRegion: " + dumpInfo_.touchRegion.ToString());
768 DumpLog::GetInstance().AddDesc("avoid top: " + std::to_string(dumpInfo_.top)
769 + ", bottom: " + std::to_string(dumpInfo_.bottom));
770 DumpLog::GetInstance().AddDesc("userOffset: " + dumpInfo_.userOffset.ToString());
771 DumpLog::GetInstance().AddDesc("targetSpace: " + dumpInfo_.targetSpace.ToString());
772 DumpLog::GetInstance().AddDesc("originPlacement: " + dumpInfo_.originPlacement);
773 DumpLog::GetInstance().AddDesc("finalPlacement: " + dumpInfo_.finalPlacement);
774 }
775
UpdateBubbleText()776 void BubblePattern::UpdateBubbleText()
777 {
778 auto host = GetHost();
779 CHECK_NULL_VOID(host);
780 host->SetNeedCallChildrenUpdate(false);
781 auto context = host->GetContext();
782 CHECK_NULL_VOID(context);
783 auto popupTheme = context->GetTheme<PopupTheme>();
784 CHECK_NULL_VOID(popupTheme);
785 UpdateText(host, popupTheme);
786 host->MarkDirtyNode();
787 }
788
OnColorConfigurationUpdate()789 void BubblePattern::OnColorConfigurationUpdate()
790 {
791 if (isCustomPopup_) {
792 return;
793 }
794 colorMode_ = SystemProperties::GetColorMode();
795 UpdateBubbleText();
796 }
797
UpdateAgingTextSize()798 void BubblePattern::UpdateAgingTextSize()
799 {
800 if (isCustomPopup_) {
801 return;
802 }
803 CHECK_NULL_VOID(messageNode_);
804 messageNode_->MarkDirtyNode();
805 }
806 } // namespace OHOS::Ace::NG
807