• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_view.h"
16 
17 #include "base/geometry/dimension.h"
18 #include "base/geometry/ng/offset_t.h"
19 #include "base/memory/ace_type.h"
20 #include "base/memory/referenced.h"
21 #include "base/utils/utils.h"
22 #include "core/common/container.h"
23 #include "core/components/button/button_theme.h"
24 #include "core/components/common/layout/constants.h"
25 #include "core/components/common/layout/grid_system_manager.h"
26 #include "core/components/common/properties/alignment.h"
27 #include "core/components/common/properties/color.h"
28 #include "core/components/popup/popup_theme.h"
29 #include "core/components_ng/base/frame_node.h"
30 #include "core/components_ng/pattern/bubble/bubble_pattern.h"
31 #include "core/components_ng/pattern/button/button_event_hub.h"
32 #include "core/components_ng/pattern/button/button_layout_property.h"
33 #include "core/components_ng/pattern/button/button_pattern.h"
34 #include "core/components_ng/pattern/flex/flex_layout_pattern.h"
35 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
36 #include "core/components_ng/pattern/linear_layout/linear_layout_property.h"
37 #include "core/components_ng/pattern/scroll/scroll_pattern.h"
38 #include "core/components_ng/pattern/text/text_pattern.h"
39 #include "core/components_ng/property/calc_length.h"
40 #include "core/components_ng/render/paint_property.h"
41 #include "core/components_v2/inspector/inspector_constants.h"
42 #include "core/pipeline/base/element_register.h"
43 #include "core/pipeline/pipeline_base.h"
44 #include "core/pipeline_ng/pipeline_context.h"
45 
46 namespace OHOS::Ace::NG {
47 namespace {
48 constexpr double DOUBLENESS = 2.0;
49 constexpr Dimension OUT_RANGE_SPACE = 40.0_vp;
GetDisplayWindowRectOffset()50 OffsetF GetDisplayWindowRectOffset()
51 {
52     auto pipelineContext = PipelineContext::GetCurrentContext();
53     CHECK_NULL_RETURN(pipelineContext, OffsetF());
54     auto overlayManager = pipelineContext->GetOverlayManager();
55     CHECK_NULL_RETURN(overlayManager, OffsetF());
56     auto displayWindowOffset = OffsetF(pipelineContext->GetDisplayWindowRectInfo().GetOffset().GetX(),
57         pipelineContext->GetDisplayWindowRectInfo().GetOffset().GetY());
58     return displayWindowOffset;
59 }
60 
GetPopupTheme()61 RefPtr<PopupTheme> GetPopupTheme()
62 {
63     auto pipeline = PipelineBase::GetCurrentContext();
64     CHECK_NULL_RETURN(pipeline, nullptr);
65     auto popupTheme = pipeline->GetTheme<PopupTheme>();
66     CHECK_NULL_RETURN(popupTheme, nullptr);
67     return popupTheme;
68 }
69 
GetMaxWith()70 Dimension GetMaxWith()
71 {
72     auto gridColumnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::BUBBLE_TYPE);
73     auto parent = gridColumnInfo->GetParent();
74     if (parent) {
75         parent->BuildColumnWidth();
76     }
77     auto maxWidth = Dimension(gridColumnInfo->GetMaxWidth());
78     return maxWidth;
79 }
80 
UpdateTextProperties(const RefPtr<PopupParam> & param,const RefPtr<TextLayoutProperty> & textLayoutProps)81 void UpdateTextProperties(const RefPtr<PopupParam>& param, const RefPtr<TextLayoutProperty>& textLayoutProps)
82 {
83     auto textColor = param->GetTextColor();
84     if (textColor.has_value()) {
85         textLayoutProps->UpdateTextColor(textColor.value());
86     }
87     auto fontSize = param->GetFontSize();
88     if (fontSize.has_value()) {
89         textLayoutProps->UpdateFontSize(fontSize.value());
90     }
91     auto fontWeight = param->GetFontWeight();
92     if (fontWeight.has_value()) {
93         textLayoutProps->UpdateFontWeight(fontWeight.value());
94     }
95     auto fontStyle = param->GetFontStyle();
96     if (fontStyle.has_value()) {
97         textLayoutProps->UpdateItalicFontStyle(fontStyle.value());
98     }
99 }
100 } // namespace
101 
SetHitTestMode(RefPtr<FrameNode> & popupNode,bool isBlockEvent)102 void SetHitTestMode(RefPtr<FrameNode>& popupNode, bool isBlockEvent)
103 {
104     auto hub = popupNode->GetEventHub<BubbleEventHub>();
105     if (hub) {
106         auto ges = hub->GetOrCreateGestureEventHub();
107         if (!isBlockEvent) {
108             ges->SetHitTestMode(HitTestMode::HTMTRANSPARENT_SELF);
109         } else {
110             ges->SetHitTestMode(HitTestMode::HTMDEFAULT);
111         }
112     }
113 }
114 
CreateBubbleNode(const std::string & targetTag,int32_t targetId,const RefPtr<PopupParam> & param)115 RefPtr<FrameNode> BubbleView::CreateBubbleNode(
116     const std::string& targetTag, int32_t targetId, const RefPtr<PopupParam>& param)
117 {
118     auto popupId = ElementRegister::GetInstance()->MakeUniqueId();
119     ACE_LAYOUT_SCOPED_TRACE("Create[%s][self:%d]", V2::POPUP_ETS_TAG, popupId);
120     auto popupNode =
121         FrameNode::CreateFrameNode(V2::POPUP_ETS_TAG, popupId, AceType::MakeRefPtr<BubblePattern>(targetId, targetTag));
122     auto popupProp = AceType::DynamicCast<BubbleLayoutProperty>(popupNode->GetLayoutProperty());
123     auto popupPaintProp = popupNode->GetPaintProperty<BubbleRenderProperty>();
124     auto useCustom = param->IsUseCustom();
125 
126     // onstateChange.
127     auto bubbleHub = popupNode->GetEventHub<BubbleEventHub>();
128     if (bubbleHub) {
129         bubbleHub->SetOnStateChange(param->GetOnStateChange());
130     }
131 
132     auto message = param->GetMessage();
133     auto primaryButton = param->GetPrimaryButtonProperties();
134     auto secondaryButton = param->GetSecondaryButtonProperties();
135     // Update props
136     popupProp->UpdateUseCustom(useCustom);
137     popupProp->UpdateEnableArrow(param->EnableArrow());
138     popupProp->UpdatePlacement(param->GetPlacement());
139     popupProp->UpdateShowInSubWindow(param->IsShowInSubWindow());
140     popupProp->UpdatePositionOffset(OffsetF(param->GetTargetOffset().GetX(), param->GetTargetOffset().GetY()));
141     popupProp->UpdateBlockEvent(param->IsBlockEvent());
142     if (param->GetArrowHeight().has_value()) {
143         popupProp->UpdateArrowHeight(param->GetArrowHeight().value());
144     }
145     if (param->GetArrowWidth().has_value()) {
146         popupProp->UpdateArrowWidth(param->GetArrowWidth().value());
147     }
148     if (param->GetRadius().has_value()) {
149         popupProp->UpdateRadius(param->GetRadius().value());
150     }
151     SetHitTestMode(popupNode, param->IsBlockEvent());
152     if (param->GetTargetSpace().has_value()) {
153         popupProp->UpdateTargetSpace(param->GetTargetSpace().value());
154     }
155     auto displayWindowOffset = GetDisplayWindowRectOffset();
156     popupProp->UpdateDisplayWindowOffset(displayWindowOffset);
157     popupPaintProp->UpdateEnableArrow(param->EnableArrow());
158     if (param->GetArrowOffset().has_value()) {
159         popupPaintProp->UpdateArrowOffset(param->GetArrowOffset().value());
160     }
161     if (param->IsMaskColorSetted()) {
162         popupPaintProp->UpdateMaskColor(param->GetMaskColor());
163     }
164     if (param->IsBackgroundColorSetted()) {
165         popupPaintProp->UpdateBackgroundColor(param->GetBackgroundColor());
166     }
167     popupPaintProp->UpdateAutoCancel(!param->HasAction());
168     popupPaintProp->UpdatePlacement(param->GetPlacement());
169 
170     auto bubbleAccessibilityProperty = popupNode->GetAccessibilityProperty<AccessibilityProperty>();
171     CHECK_NULL_RETURN(bubbleAccessibilityProperty, nullptr);
172     bubbleAccessibilityProperty->SetText(message);
173     auto bobblePattern = popupNode->GetPattern<BubblePattern>();
174     // Create child
175     RefPtr<FrameNode> child;
176     if (primaryButton.showButton || secondaryButton.showButton) {
177         auto columnNode = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
178             AceType::MakeRefPtr<LinearLayoutPattern>(true));
179         auto columnLayoutProperty = columnNode->GetLayoutProperty<LinearLayoutProperty>();
180         columnLayoutProperty->UpdateMainAxisAlign(FlexAlign::CENTER); // mainAxisAlign
181         columnLayoutProperty->UpdateCrossAxisAlign(FlexAlign::CENTER);
182         auto combinedChild = CreateCombinedChild(param, popupId, targetId, popupNode);
183         popupPaintProp->UpdatePrimaryButtonShow(primaryButton.showButton);
184         popupPaintProp->UpdateSecondaryButtonShow(secondaryButton.showButton);
185         if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
186             popupPaintProp->UpdateAutoCancel(false);
187         }
188         combinedChild->MountToParent(columnNode);
189         child = columnNode;
190     } else {
191         auto columnNode = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
192             AceType::MakeRefPtr<LinearLayoutPattern>(true));
193         auto columnLayoutProperty = columnNode->GetLayoutProperty<LinearLayoutProperty>();
194         columnLayoutProperty->UpdateMainAxisAlign(FlexAlign::CENTER); // mainAxisAlign
195         columnLayoutProperty->UpdateCrossAxisAlign(FlexAlign::CENTER);
196         auto textNode = CreateMessage(message, useCustom);
197         bobblePattern->SetMessageNode(textNode);
198         auto popupTheme = GetPopupTheme();
199         auto padding = popupTheme->GetPadding();
200         auto layoutProps = textNode->GetLayoutProperty<TextLayoutProperty>();
201         PaddingProperty textPadding;
202         textPadding.left = CalcLength(padding.Left());
203         textPadding.right = CalcLength(padding.Right());
204         textPadding.top = CalcLength(padding.Top());
205         textPadding.bottom = CalcLength(padding.Bottom());
206         layoutProps->UpdatePadding(textPadding);
207         layoutProps->UpdateAlignment(Alignment::CENTER);
208         UpdateTextProperties(param, layoutProps);
209         auto buttonMiniMumHeight = popupTheme->GetBubbleMiniMumHeight().ConvertToPx();
210         layoutProps->UpdateCalcMinSize(CalcSize(std::nullopt, CalcLength(buttonMiniMumHeight)));
211         textNode->MarkModifyDone();
212         if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
213             textNode->MountToParent(columnNode);
214         } else {
215             auto scrollNode = FrameNode::CreateFrameNode(V2::SCROLL_ETS_TAG,
216                 ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ScrollPattern>());
217             CHECK_NULL_RETURN(scrollNode, nullptr);
218             auto scrollProps = scrollNode->GetLayoutProperty<ScrollLayoutProperty>();
219             scrollProps->UpdateAxis(Axis::VERTICAL);
220             scrollProps->UpdateAlignment(Alignment::CENTER_LEFT);
221             scrollNode->MarkModifyDone();
222             textNode->MountToParent(scrollNode);
223             scrollNode->MountToParent(columnNode);
224         }
225         child = columnNode;
226     }
227     // TODO: GridSystemManager is not completed, need to check later.
228     auto childLayoutProperty = child->GetLayoutProperty();
229     CHECK_NULL_RETURN(childLayoutProperty, nullptr);
230     float popupMaxWidth = 0.0f;
231     float popupMaxHeight = 0.0f;
232     GetPopupMaxWidthAndHeight(param, popupMaxWidth, popupMaxHeight);
233     childLayoutProperty->UpdateCalcMaxSize(
234         CalcSize(NG::CalcLength(Dimension(popupMaxWidth)), NG::CalcLength(Dimension(popupMaxHeight))));
235     if (param->GetChildWidth().has_value()) {
236         childLayoutProperty->UpdateUserDefinedIdealSize(
237             CalcSize(CalcLength(param->GetChildWidth().value()), std::nullopt));
238     }
239     auto renderContext = child->GetRenderContext();
240     if (renderContext) {
241         if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
242             renderContext->UpdateBackgroundColor(
243                 popupPaintProp->GetBackgroundColor().value_or(GetPopupTheme()->GetBackgroundColor()));
244         } else {
245             auto backgroundColor = popupPaintProp->GetBackgroundColor().value_or(Color::TRANSPARENT);
246             renderContext->UpdateBackgroundColor(backgroundColor);
247             BlurStyleOption styleOption;
248             styleOption.blurStyle = param->GetBlurStyle();
249             renderContext->UpdateBackBlurStyle(styleOption);
250         }
251         if (param->GetShadow().has_value()) {
252             renderContext->UpdateBackShadow(param->GetShadow().value());
253         }
254     }
255     child->MountToParent(popupNode);
256     return popupNode;
257 }
CreateCustomBubbleNode(const std::string & targetTag,int32_t targetId,const RefPtr<UINode> & customNode,const RefPtr<PopupParam> & param)258 RefPtr<FrameNode> BubbleView::CreateCustomBubbleNode(
259     const std::string& targetTag, int32_t targetId, const RefPtr<UINode>& customNode, const RefPtr<PopupParam>& param)
260 {
261     auto popupId = ElementRegister::GetInstance()->MakeUniqueId();
262     auto popupNode =
263         FrameNode::CreateFrameNode(V2::POPUP_ETS_TAG, popupId, AceType::MakeRefPtr<BubblePattern>(targetId, targetTag));
264     auto bubbleHub = popupNode->GetEventHub<BubbleEventHub>();
265     if (bubbleHub) {
266         bubbleHub->SetOnStateChange(param->GetOnStateChange());
267     }
268     auto popupPattern = popupNode->GetPattern<BubblePattern>();
269     popupPattern->SetCustomPopupTag(true);
270     // update bubble props
271     auto layoutProps = popupNode->GetLayoutProperty<BubbleLayoutProperty>();
272     layoutProps->UpdateUseCustom(param->IsUseCustom());
273     layoutProps->UpdateEnableArrow(param->EnableArrow());
274     layoutProps->UpdatePlacement(param->GetPlacement());
275     layoutProps->UpdateShowInSubWindow(param->IsShowInSubWindow());
276     layoutProps->UpdateBlockEvent(param->IsBlockEvent());
277     if (param->GetArrowHeight().has_value()) {
278         layoutProps->UpdateArrowHeight(param->GetArrowHeight().value());
279     }
280     if (param->GetArrowWidth().has_value()) {
281         layoutProps->UpdateArrowWidth(param->GetArrowWidth().value());
282     }
283     if (param->GetRadius().has_value()) {
284         layoutProps->UpdateRadius(param->GetRadius().value());
285     }
286     SetHitTestMode(popupNode, param->IsBlockEvent());
287     auto displayWindowOffset = GetDisplayWindowRectOffset();
288     layoutProps->UpdateDisplayWindowOffset(displayWindowOffset);
289     layoutProps->UpdatePositionOffset(OffsetF(param->GetTargetOffset().GetX(), param->GetTargetOffset().GetY()));
290     if (param->GetTargetSpace().has_value()) {
291         layoutProps->UpdateTargetSpace(param->GetTargetSpace().value());
292     }
293     auto popupPaintProps = popupNode->GetPaintProperty<BubbleRenderProperty>();
294     popupPaintProps->UpdateUseCustom(param->IsUseCustom());
295     popupPaintProps->UpdateEnableArrow(param->EnableArrow());
296     if (param->GetArrowOffset().has_value()) {
297         popupPaintProps->UpdateArrowOffset(param->GetArrowOffset().value());
298     }
299     if (param->IsMaskColorSetted()) {
300         popupPaintProps->UpdateMaskColor(param->GetMaskColor());
301     }
302     if (param->IsBackgroundColorSetted()) {
303         popupPaintProps->UpdateBackgroundColor(param->GetBackgroundColor());
304     }
305 
306     auto columnNode = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
307         AceType::MakeRefPtr<LinearLayoutPattern>(false));
308     auto columnNodeClip = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
309         AceType::MakeRefPtr<LinearLayoutPattern>(false));
310     auto clipContext = columnNodeClip->GetRenderContext();
311     clipContext->SetClipToBounds(true);
312     customNode->MountToParent(columnNodeClip);
313     columnNodeClip->MountToParent(columnNode);
314     auto columnRenderContext = columnNode->GetRenderContext();
315     auto columnLayoutProperty = columnNode->GetLayoutProperty<LinearLayoutProperty>();
316     CHECK_NULL_RETURN(columnLayoutProperty, nullptr);
317     columnLayoutProperty->UpdateMainAxisAlign(FlexAlign::CENTER); // mainAxisAlign
318     columnLayoutProperty->UpdateCrossAxisAlign(FlexAlign::CENTER);
319     auto customFrameNode = AceType::DynamicCast<FrameNode>(customNode);
320     float popupMaxWidth = 0.0f;
321     float popupMaxHeight = 0.0f;
322     GetPopupMaxWidthAndHeight(param, popupMaxWidth, popupMaxHeight);
323     columnLayoutProperty->UpdateCalcMaxSize(CalcSize(std::nullopt, NG::CalcLength(Dimension(popupMaxHeight))));
324     if (param->GetChildWidth().has_value()) {
325         columnLayoutProperty->UpdateUserDefinedIdealSize(
326             CalcSize(CalcLength(param->GetChildWidth().value()), std::nullopt));
327     }
328     if (columnRenderContext) {
329         if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
330             columnRenderContext->UpdateBackgroundColor(
331                 popupPaintProps->GetBackgroundColor().value_or(GetPopupTheme()->GetBackgroundColor()));
332         } else {
333             auto backgroundColor = popupPaintProps->GetBackgroundColor().value_or(Color::TRANSPARENT);
334             columnRenderContext->UpdateBackgroundColor(backgroundColor);
335             BlurStyleOption styleOption;
336             styleOption.blurStyle = param->GetBlurStyle();
337             columnRenderContext->UpdateBackBlurStyle(styleOption);
338         }
339         if (param->GetShadow().has_value()) {
340             columnRenderContext->UpdateBackShadow(param->GetShadow().value());
341         }
342     }
343     popupPaintProps->UpdateAutoCancel(!param->HasAction());
344     popupPaintProps->UpdatePlacement(param->GetPlacement());
345     columnNode->MountToParent(popupNode);
346     return popupNode;
347 }
348 
UpdateBubbleButtons(std::list<RefPtr<UINode>> & buttons,const RefPtr<PopupParam> & param)349 void BubbleView::UpdateBubbleButtons(std::list<RefPtr<UINode>>& buttons, const RefPtr<PopupParam>& param)
350 {
351     auto primaryButton = param->GetPrimaryButtonProperties();
352     auto secondaryButton = param->GetSecondaryButtonProperties();
353     if (primaryButton.showButton) {
354         auto button = AceType::DynamicCast<FrameNode>(buttons.front());
355         buttons.pop_front();
356         auto textNode = AceType::DynamicCast<FrameNode>(button->GetFirstChild());
357         auto layoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
358         layoutProperty->UpdateContent(primaryButton.value);
359         textNode->MarkModifyDone();
360         auto buttonEventHub = button->GetOrCreateGestureEventHub();
361         if (primaryButton.action) {
362             buttonEventHub->AddClickEvent(primaryButton.action);
363         }
364     }
365     if (secondaryButton.showButton) {
366         auto button = AceType::DynamicCast<FrameNode>(buttons.front());
367         buttons.pop_front();
368         auto textNode = AceType::DynamicCast<FrameNode>(button->GetFirstChild());
369         auto layoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
370         layoutProperty->UpdateContent(secondaryButton.value);
371         textNode->MarkModifyDone();
372         auto buttonEventHub = button->GetOrCreateGestureEventHub();
373         if (secondaryButton.action) {
374             buttonEventHub->AddClickEvent(secondaryButton.action);
375         }
376     }
377 }
378 
UpdateBubbleContent(int32_t popupId,const RefPtr<PopupParam> & param)379 void BubbleView::UpdateBubbleContent(int32_t popupId, const RefPtr<PopupParam>& param)
380 {
381     auto popupNode = FrameNode::GetFrameNode(V2::POPUP_ETS_TAG, popupId);
382     CHECK_NULL_VOID(popupNode);
383     auto message = param->GetMessage();
384     auto primaryButton = param->GetPrimaryButtonProperties();
385     auto secondaryButton = param->GetSecondaryButtonProperties();
386     auto columnNode = popupNode->GetFirstChild();
387     if (primaryButton.showButton || secondaryButton.showButton) {
388         CHECK_NULL_VOID(columnNode);
389         auto combinedChild = columnNode->GetFirstChild();
390         CHECK_NULL_VOID(combinedChild);
391         const auto& children = combinedChild->GetChildren();
392         for (const auto& child: children) {
393             if (child->GetTag() == V2::TEXT_ETS_TAG) {  // API10
394                 auto textNode = AceType::DynamicCast<FrameNode>(child);
395                 auto layoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
396                 layoutProperty->UpdateContent(message);
397                 UpdateTextProperties(param, layoutProperty);
398                 textNode->MarkModifyDone();
399             } else if (child->GetTag() == V2::SCROLL_ETS_TAG) {
400                 auto textNode = AceType::DynamicCast<FrameNode>(child->GetFirstChild());
401                 auto layoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
402                 layoutProperty->UpdateContent(message);
403                 UpdateTextProperties(param, layoutProperty);
404                 textNode->MarkModifyDone();
405             } else {
406                 auto buttons = child->GetChildren();
407                 UpdateBubbleButtons(buttons, param);
408             }
409         }
410     } else {
411         CHECK_NULL_VOID(columnNode);
412         auto childNode = columnNode->GetFirstChild();
413         if (!(Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
414             childNode = childNode->GetFirstChild();
415         }
416         auto textNode = AceType::DynamicCast<FrameNode>(childNode);
417         CHECK_NULL_VOID(textNode);
418         auto layoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
419         layoutProperty->UpdateContent(message);
420         UpdateTextProperties(param, layoutProperty);
421         textNode->MarkModifyDone();
422     }
423 }
424 
UpdatePopupParam(int32_t popupId,const RefPtr<PopupParam> & param,const RefPtr<FrameNode> & targetNode)425 void BubbleView::UpdatePopupParam(int32_t popupId, const RefPtr<PopupParam>& param, const RefPtr<FrameNode>& targetNode)
426 {
427     UpdateCommonParam(popupId, param, false);
428     UpdateBubbleContent(popupId, param);
429     auto popupNode = FrameNode::GetFrameNode(V2::POPUP_ETS_TAG, popupId);
430     CHECK_NULL_VOID(popupNode);
431     auto popupProp = AceType::DynamicCast<BubbleLayoutProperty>(popupNode->GetLayoutProperty());
432     auto popupPaintProp = popupNode->GetPaintProperty<BubbleRenderProperty>();
433     auto message = param->GetMessage();
434     auto primaryButton = param->GetPrimaryButtonProperties();
435     auto secondaryButton = param->GetSecondaryButtonProperties();
436     if (!(Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
437         if (primaryButton.showButton || secondaryButton.showButton) {
438             auto pipelineContext = PipelineBase::GetCurrentContext();
439             CHECK_NULL_VOID(pipelineContext);
440             float popupMaxWidth = 0.0f;
441             float popupMaxHeight = 0.0f;
442             GetPopupMaxWidthAndHeight(param, popupMaxWidth, popupMaxHeight);
443             auto buttonTheme = pipelineContext->GetTheme<ButtonTheme>();
444             CHECK_NULL_VOID(buttonTheme);
445             auto childNode = AceType::DynamicCast<FrameNode>(popupNode->GetFirstChild());
446             CHECK_NULL_VOID(childNode);
447             const auto& children = childNode->GetChildren();
448             for (const auto& uinode : children) {
449                 if (uinode->GetTag() == V2::SCROLL_ETS_TAG) {
450                     auto scrollNode = AceType::DynamicCast<FrameNode>(uinode);
451                     CHECK_NULL_VOID(scrollNode);
452                     auto scrollProps = scrollNode->GetLayoutProperty<ScrollLayoutProperty>();
453                     scrollProps->UpdateCalcMaxSize(CalcSize(
454                         std::nullopt, CalcLength(Dimension(popupMaxHeight) - buttonTheme->GetHeight() * DOUBLENESS)));
455                 }
456             }
457         }
458     }
459     // Update layout props
460     popupProp->UpdateUseCustom(param->IsUseCustom());
461     popupProp->UpdateEnableArrow(param->EnableArrow());
462     popupProp->UpdatePlacement(param->GetPlacement());
463     auto displayWindowOffset = GetDisplayWindowRectOffset();
464     popupProp->UpdateDisplayWindowOffset(displayWindowOffset);
465     // Update paint props
466     popupPaintProp->UpdatePlacement(param->GetPlacement());
467     popupPaintProp->UpdateUseCustom(param->IsUseCustom());
468     popupPaintProp->UpdateEnableArrow(param->EnableArrow());
469 }
470 
UpdateCustomPopupParam(int32_t popupId,const RefPtr<PopupParam> & param)471 void BubbleView::UpdateCustomPopupParam(int32_t popupId, const RefPtr<PopupParam>& param)
472 {
473     UpdateCommonParam(popupId, param);
474     auto popupNode = FrameNode::GetFrameNode(V2::POPUP_ETS_TAG, popupId);
475     CHECK_NULL_VOID(popupNode);
476     auto popupLayoutProp = popupNode->GetLayoutProperty<BubbleLayoutProperty>();
477     CHECK_NULL_VOID(popupLayoutProp);
478     auto popupPaintProp = popupNode->GetPaintProperty<BubbleRenderProperty>();
479     CHECK_NULL_VOID(popupPaintProp);
480     popupLayoutProp->UpdatePlacement(param->GetPlacement());
481     popupPaintProp->UpdatePlacement(param->GetPlacement());
482     popupLayoutProp->UpdateEnableArrow(param->EnableArrow());
483     popupPaintProp->UpdateAutoCancel(!param->HasAction());
484     popupPaintProp->UpdateEnableArrow(param->EnableArrow());
485 }
486 
GetPopupMaxWidthAndHeight(const RefPtr<PopupParam> & param,float & popupMaxWidth,float & popupMaxHeight)487 void BubbleView::GetPopupMaxWidthAndHeight(const RefPtr<PopupParam>& param, float& popupMaxWidth, float& popupMaxHeight)
488 {
489     auto pipelineContext = PipelineContext::GetMainPipelineContext();
490     CHECK_NULL_VOID(pipelineContext);
491     auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
492     auto safeAreaManager = pipelineContext->GetSafeAreaManager();
493     CHECK_NULL_VOID(safeAreaManager);
494     auto bottom = safeAreaManager->GetSystemSafeArea().bottom_.Length();
495     auto top = safeAreaManager->GetSystemSafeArea().top_.Length();
496     auto maxHeight = windowGlobalRect.Height();
497     if (param->IsShowInSubWindow()) {
498         maxHeight = SystemProperties::GetDeviceHeight();
499     }
500     popupMaxHeight = maxHeight - OUT_RANGE_SPACE.ConvertToPx() - OUT_RANGE_SPACE.ConvertToPx() - bottom - top;
501     popupMaxWidth = GetMaxWith().Value();
502 }
503 
UpdateCommonParam(int32_t popupId,const RefPtr<PopupParam> & param,bool custom)504 void BubbleView::UpdateCommonParam(int32_t popupId, const RefPtr<PopupParam>& param, bool custom)
505 {
506     auto popupNode = FrameNode::GetFrameNode(V2::POPUP_ETS_TAG, popupId);
507     CHECK_NULL_VOID(popupNode);
508     auto bubbleHub = popupNode->GetEventHub<BubbleEventHub>();
509     if (bubbleHub) {
510         bubbleHub->SetOnStateChange(param->GetOnStateChange());
511     }
512     auto popupLayoutProp = popupNode->GetLayoutProperty<BubbleLayoutProperty>();
513     CHECK_NULL_VOID(popupLayoutProp);
514     auto popupPaintProp = popupNode->GetPaintProperty<BubbleRenderProperty>();
515     CHECK_NULL_VOID(popupPaintProp);
516     if (param->GetArrowOffset().has_value()) {
517         popupPaintProp->UpdateArrowOffset(param->GetArrowOffset().value());
518     }
519     popupLayoutProp->UpdateShowInSubWindow(param->IsShowInSubWindow());
520     popupLayoutProp->UpdateBlockEvent(param->IsBlockEvent());
521     if (param->GetErrorArrowHeight()) {
522         popupLayoutProp->ResetArrowHeight();
523     }
524     if (param->GetErrorArrowWidth()) {
525         popupLayoutProp->ResetArrowWidth();
526     }
527     if (param->GetErrorRadius()) {
528         popupLayoutProp->ResetRadius();
529     }
530     if (param->GetArrowHeight().has_value()) {
531         popupLayoutProp->UpdateArrowHeight(param->GetArrowHeight().value());
532     }
533     if (param->GetArrowWidth().has_value()) {
534         popupLayoutProp->UpdateArrowWidth(param->GetArrowWidth().value());
535     }
536     if (param->GetRadius().has_value()) {
537         popupLayoutProp->UpdateRadius(param->GetRadius().value());
538     }
539     SetHitTestMode(popupNode, param->IsBlockEvent());
540     popupLayoutProp->UpdatePositionOffset(OffsetF(param->GetTargetOffset().GetX(), param->GetTargetOffset().GetY()));
541     if (param->IsMaskColorSetted()) {
542         popupPaintProp->UpdateMaskColor(param->GetMaskColor());
543     } else {
544         popupPaintProp->UpdateMaskColor(Color::TRANSPARENT);
545     }
546     if (param->GetTargetSpace().has_value()) {
547         popupLayoutProp->UpdateTargetSpace(param->GetTargetSpace().value());
548     }
549     if (param->IsBackgroundColorSetted()) {
550         popupPaintProp->UpdateBackgroundColor(param->GetBackgroundColor());
551     }
552     auto childNode = AceType::DynamicCast<FrameNode>(popupNode->GetFirstChild());
553     CHECK_NULL_VOID(childNode);
554     auto renderContext = childNode->GetRenderContext();
555     if (renderContext && param->GetShadow().has_value()) {
556         renderContext->UpdateBackShadow(param->GetShadow().value());
557     }
558     auto childLayoutProperty = childNode->GetLayoutProperty();
559     CHECK_NULL_VOID(childLayoutProperty);
560     float popupMaxWidth = 0.0f;
561     float popupMaxHeight = 0.0f;
562     GetPopupMaxWidthAndHeight(param, popupMaxWidth, popupMaxHeight);
563     if (custom) {
564         childLayoutProperty->UpdateCalcMaxSize(CalcSize(std::nullopt, NG::CalcLength(Dimension(popupMaxHeight))));
565     } else {
566         childLayoutProperty->UpdateCalcMaxSize(
567             CalcSize(NG::CalcLength(Dimension(popupMaxWidth)), NG::CalcLength(Dimension(popupMaxHeight))));
568     }
569     if (param->GetChildWidth().has_value()) {
570         childLayoutProperty->UpdateUserDefinedIdealSize(
571             CalcSize(CalcLength(param->GetChildWidth().value()), std::nullopt));
572     }
573     if (renderContext) {
574         if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
575             renderContext->UpdateBackgroundColor(
576                 popupPaintProp->GetBackgroundColor().value_or(GetPopupTheme()->GetBackgroundColor()));
577         } else {
578             auto backgroundColor = popupPaintProp->GetBackgroundColor().value_or(Color::TRANSPARENT);
579             renderContext->UpdateBackgroundColor(backgroundColor);
580             BlurStyleOption styleOption;
581             styleOption.blurStyle = param->GetBlurStyle();
582             renderContext->UpdateBackBlurStyle(styleOption);
583         }
584     }
585 }
586 
CreateMessage(const std::string & message,bool IsUseCustom)587 RefPtr<FrameNode> BubbleView::CreateMessage(const std::string& message, bool IsUseCustom)
588 {
589     auto textId = ElementRegister::GetInstance()->MakeUniqueId();
590     auto textNode = FrameNode::CreateFrameNode(V2::TEXT_ETS_TAG, textId, AceType::MakeRefPtr<TextPattern>());
591     // The buttons in popupNode can not get focus, if the textNode in the button is not focusable
592     textNode->GetOrCreateFocusHub()->SetFocusable(true);
593     auto layoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
594     layoutProperty->UpdateContent(message);
595     auto popupTheme = GetPopupTheme();
596     layoutProperty->UpdateFontSize(popupTheme->GetFontSize());
597     if (IsUseCustom) {
598         layoutProperty->UpdateTextColor(Color::BLACK);
599     } else {
600         if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
601             layoutProperty->UpdateTextColor(popupTheme->GetFontColor());
602         } else {
603             layoutProperty->UpdateTextColor(popupTheme->GetFontPrimaryColor());
604         }
605     }
606     textNode->MarkModifyDone();
607     return textNode;
608 }
609 
CreateCombinedChild(const RefPtr<PopupParam> & param,int32_t popupId,int32_t targetId,const RefPtr<FrameNode> & bobbleNode)610 RefPtr<FrameNode> BubbleView::CreateCombinedChild(
611     const RefPtr<PopupParam>& param, int32_t popupId, int32_t targetId, const RefPtr<FrameNode>& bobbleNode)
612 {
613     auto columnNode = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
614         AceType::MakeRefPtr<LinearLayoutPattern>(true));
615     auto layoutProps = columnNode->GetLayoutProperty<LinearLayoutProperty>();
616     layoutProps->UpdateMainAxisAlign(FlexAlign::FLEX_START); // mainAxisAlign
617     layoutProps->UpdateCrossAxisAlign(FlexAlign::FLEX_START);
618     auto message = BubbleView::CreateMessage(param->GetMessage(), param->IsUseCustom());
619     auto bubblePattern = bobbleNode->GetPattern<BubblePattern>();
620     CHECK_NULL_RETURN(bubblePattern, nullptr);
621     bubblePattern->SetMessageNode(message);
622     auto popupTheme = GetPopupTheme();
623     auto padding = popupTheme->GetPadding();
624     auto textLayoutProps = message->GetLayoutProperty<TextLayoutProperty>();
625     PaddingProperty textPadding;
626     textPadding.left = CalcLength(padding.Left());
627     textPadding.right = CalcLength(padding.Right());
628     textPadding.top = CalcLength(padding.Top());
629     textLayoutProps->UpdatePadding(textPadding);
630     textLayoutProps->UpdateAlignSelf(FlexAlign::FLEX_START);
631     UpdateTextProperties(param, textLayoutProps);
632     message->MarkModifyDone();
633     auto pipelineContext = PipelineBase::GetCurrentContext();
634     CHECK_NULL_RETURN(pipelineContext, nullptr);
635     float popupMaxWidth = 0.0f;
636     float popupMaxHeight = 0.0f;
637     if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
638         message->MountToParent(columnNode);
639     } else {
640         GetPopupMaxWidthAndHeight(param, popupMaxWidth, popupMaxHeight);
641         auto buttonTheme = pipelineContext->GetTheme<ButtonTheme>();
642         CHECK_NULL_RETURN(buttonTheme, nullptr);
643         auto scrollNode = FrameNode::CreateFrameNode(
644             V2::SCROLL_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ScrollPattern>());
645         CHECK_NULL_RETURN(scrollNode, nullptr);
646         auto scrollProps = scrollNode->GetLayoutProperty<ScrollLayoutProperty>();
647         scrollProps->UpdateAxis(Axis::VERTICAL);
648         scrollProps->UpdateAlignment(Alignment::CENTER_LEFT);
649         scrollProps->UpdateCalcMaxSize(
650             CalcSize(std::nullopt, CalcLength(Dimension(popupMaxHeight) - buttonTheme->GetHeight() * DOUBLENESS)));
651         scrollNode->MarkModifyDone();
652         message->MountToParent(scrollNode);
653         scrollNode->MountToParent(columnNode);
654     }
655     auto buttonLayout = BubbleView::CreateButtons(param, popupId, targetId);
656     if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
657         auto buttonRowLayoutProperty = buttonLayout->GetLayoutProperty<LinearLayoutProperty>();
658         buttonRowLayoutProperty->UpdateAlignSelf(FlexAlign::FLEX_END);
659     } else {
660         auto buttonFlexLayoutProperty = buttonLayout->GetLayoutProperty<FlexLayoutProperty>();
661         buttonFlexLayoutProperty->UpdateAlignSelf(FlexAlign::FLEX_END);
662     }
663     buttonLayout->MarkModifyDone();
664     auto childLayoutProperty = columnNode->GetLayoutProperty<LinearLayoutProperty>();
665     CHECK_NULL_RETURN(childLayoutProperty, nullptr);
666     if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
667         popupMaxWidth = GetMaxWith().Value();
668         childLayoutProperty->UpdateCalcMaxSize(CalcSize(NG::CalcLength(popupMaxWidth), std::nullopt));
669     } else {
670         childLayoutProperty->UpdateCalcMaxSize(
671             CalcSize(NG::CalcLength(Dimension(popupMaxWidth)), NG::CalcLength(Dimension(popupMaxHeight))));
672     }
673     buttonLayout->MountToParent(columnNode);
674     columnNode->MarkModifyDone();
675     return columnNode;
676 }
677 
CreateButtons(const RefPtr<PopupParam> & param,int32_t popupId,int32_t targetId)678 RefPtr<FrameNode> BubbleView::CreateButtons(const RefPtr<PopupParam>& param, int32_t popupId, int32_t targetId)
679 {
680     auto rowId = ElementRegister::GetInstance()->MakeUniqueId();
681     RefPtr<FrameNode> layoutNode;
682     if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
683         layoutNode =
684             FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, rowId, AceType::MakeRefPtr<LinearLayoutPattern>(false));
685     } else {
686         layoutNode = FrameNode::CreateFrameNode(V2::FLEX_ETS_TAG, rowId, AceType::MakeRefPtr<FlexLayoutPattern>(false));
687         layoutNode->GetPattern<FlexLayoutPattern>()->SetIsWrap(true);
688     }
689 
690     auto primaryButtonProp = param->GetPrimaryButtonProperties();
691     auto primaryButton = BubbleView::CreateButton(primaryButtonProp, popupId, targetId, param);
692     if (primaryButton) {
693         primaryButton->MountToParent(layoutNode);
694     }
695     auto secondaryButtonProp = param->GetSecondaryButtonProperties();
696     auto secondaryButton = BubbleView::CreateButton(secondaryButtonProp, popupId, targetId, param);
697     if (secondaryButton) {
698         secondaryButton->MountToParent(layoutNode);
699     }
700     auto popupTheme = GetPopupTheme();
701     auto littlePadding = popupTheme->GetLittlePadding();
702     PaddingProperty rowPadding;
703     rowPadding.right = CalcLength(littlePadding);
704     rowPadding.bottom = CalcLength(littlePadding);
705     if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
706         auto layoutProps = layoutNode->GetLayoutProperty<LinearLayoutProperty>();
707         layoutProps->UpdateSpace(GetPopupTheme()->GetButtonSpacing());
708         layoutProps->UpdatePadding(rowPadding);
709     } else {
710         auto layoutProps = layoutNode->GetLayoutProperty<FlexLayoutProperty>();
711         layoutProps->UpdatePadding(rowPadding);
712     }
713     layoutNode->MarkModifyDone();
714     return layoutNode;
715 }
716 
CreateButton(ButtonProperties & buttonParam,int32_t popupId,int32_t targetId,const RefPtr<PopupParam> & param)717 RefPtr<FrameNode> BubbleView::CreateButton(
718     ButtonProperties& buttonParam, int32_t popupId, int32_t targetId, const RefPtr<PopupParam>& param)
719 {
720     if (!buttonParam.showButton) {
721         return nullptr;
722     }
723     auto pipelineContext = PipelineBase::GetCurrentContext();
724     CHECK_NULL_RETURN(pipelineContext, nullptr);
725     auto buttonTheme = pipelineContext->GetTheme<ButtonTheme>();
726     CHECK_NULL_RETURN(buttonTheme, nullptr);
727     auto popupTheme = GetPopupTheme();
728     auto focusColor = popupTheme->GetFocusColor();
729     auto buttonId = ElementRegister::GetInstance()->MakeUniqueId();
730     auto buttonPattern = AceType::MakeRefPtr<NG::ButtonPattern>();
731     CHECK_NULL_RETURN(buttonPattern, nullptr);
732     // set button focus color
733     buttonPattern->setComponentButtonType(ComponentButtonType::POPUP);
734     buttonPattern->SetFocusBorderColor(focusColor);
735     auto buttonNode = FrameNode::CreateFrameNode(V2::BUTTON_ETS_TAG, buttonId, buttonPattern);
736     CHECK_NULL_RETURN(buttonPattern, nullptr);
737 
738     auto buttonProp = AceType::DynamicCast<ButtonLayoutProperty>(buttonNode->GetLayoutProperty());
739     auto isUseCustom = param->IsUseCustom();
740 
741     auto buttonTextNode = BubbleView::CreateMessage(buttonParam.value, isUseCustom);
742     auto textLayoutProperty = buttonTextNode->GetLayoutProperty<TextLayoutProperty>();
743     textLayoutProperty->UpdateFontSize(popupTheme->GetButtonFontSize());
744     if (!(Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
745         textLayoutProperty->UpdateTextColor(popupTheme->GetButtonFontColor());
746     }
747     auto buttonTextInsideMargin = popupTheme->GetButtonTextInsideMargin();
748     buttonTextNode->MountToParent(buttonNode);
749 
750     PaddingProperty buttonPadding;
751     auto padding = buttonTheme->GetPadding();
752     buttonPadding.left = CalcLength(buttonTextInsideMargin);
753     buttonPadding.right = CalcLength(buttonTextInsideMargin);
754     buttonProp->UpdatePadding(buttonPadding);
755     buttonProp->UpdateType(ButtonType::CAPSULE);
756     buttonProp->UpdateUserDefinedIdealSize(CalcSize(std::nullopt, CalcLength(buttonTheme->GetHeight())));
757     buttonProp->UpdateAlignment(Alignment::CENTER);
758     auto buttonMiniMumWidth = popupTheme->GetButtonMiniMumWidth().ConvertToPx();
759     buttonProp->UpdateCalcMinSize(CalcSize(CalcLength(buttonMiniMumWidth), std::nullopt));
760     auto renderContext = buttonNode->GetRenderContext();
761     if (renderContext) {
762         renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
763     }
764 
765     auto buttonEventHub = buttonNode->GetOrCreateGestureEventHub();
766     CHECK_NULL_RETURN(buttonEventHub, nullptr);
767     buttonEventHub->AddClickEvent(buttonParam.action);
768     auto popupNode = FrameNode::GetFrameNode(V2::POPUP_ETS_TAG, popupId);
769     auto closeCallback = [popupNode, targetId](GestureEvent& /* info */) {
770         auto container = Container::Current();
771         CHECK_NULL_VOID(container);
772         auto pipelineContext = container->GetPipelineContext();
773         CHECK_NULL_VOID(pipelineContext);
774         auto context = AceType::DynamicCast<NG::PipelineContext>(pipelineContext);
775         CHECK_NULL_VOID(context);
776         auto overlayManager = context->GetOverlayManager();
777         CHECK_NULL_VOID(overlayManager);
778         auto popupInfo = overlayManager->GetPopupInfo(targetId);
779         popupInfo.markNeedUpdate = true;
780         overlayManager->HidePopup(targetId, popupInfo);
781     };
782     if (buttonParam.action) {
783         buttonEventHub->AddClickEvent(buttonParam.action);
784     } else {
785         buttonEventHub->AddClickEvent(AceType::MakeRefPtr<ClickEvent>(closeCallback));
786     }
787 
788     return buttonNode;
789 }
790 } // namespace OHOS::Ace::NG
791