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