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