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