• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-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 
16 #include "core/components_ng/pattern/container_modal/enhance/container_modal_pattern_enhance.h"
17 
18 #include <atomic>
19 
20 #include "base/geometry/dimension.h"
21 #include "base/i18n/localization.h"
22 #include "base/log/event_report.h"
23 #include "base/subwindow/subwindow_manager.h"
24 #include "base/utils/device_config.h"
25 #include "base/utils/measure_util.h"
26 #include "base/utils/system_properties.h"
27 #include "base/utils/utils.h"
28 #include "core/components/common/layout/constants.h"
29 #include "core/components_ng/pattern/container_modal/container_modal_theme.h"
30 #include "core/components_ng/pattern/container_modal/enhance/container_modal_view_enhance.h"
31 #include "core/components_ng/pattern/list/list_pattern.h"
32 #include "core/components_ng/pattern/text/text_pattern.h"
33 #include "core/pipeline_ng/pipeline_context.h"
34 #include "core/common/resource/resource_manager.h"
35 namespace OHOS::Ace::NG {
36 namespace {
37 
38 const int32_t MENU_TASK_DELAY_TIME = 1000;
39 constexpr int32_t TITLE_POPUP_DURATION = 400;
40 const int32_t DOUBLE_CLICK_TO_MAXIMIZE = 1;
41 const int32_t DOUBLE_CLICK_TO_RECOVER = 2;
42 const int32_t MAX_BUTTON_CLICK_TO_MAXIMIZE = 1;
43 const int32_t MAX_BUTTON_CLICK_TO_RECOVER = 2;
44 const int32_t MAX_MENU_ITEM_LEFT_SPLIT = 1;
45 const int32_t MAX_MENU_ITEM_RIGHT_SPLIT = 2;
46 const int32_t MAX_MENU_ITEM_MAXIMIZE = 3;
47 const int32_t MAX_MENU_DEFAULT_NOT_CHANGE = 3;
48 
49 const Dimension MENU_ITEM_RADIUS = 4.0_vp;
50 const Dimension MENU_ITEM_PADDING_H = 12.0_vp;
51 const Dimension MENU_ITEM_PADDING_V = 8.0_vp;
52 const Dimension MENU_PADDING = 4.0_vp;
53 const Dimension MENU_GUTTER = 2.0_vp;
54 const Dimension MENU_SAFETY_X = 8.0_vp;
55 const Dimension MENU_SAFETY_Y = 96.0_vp;
56 const Dimension MENU_ITEM_TEXT_PADDING = 8.0_vp;
57 const Color MENU_ITEM_COLOR = Color(0xffffff);
58 
59 std::atomic<int32_t> g_nextListenerId = 1;
60 
GetNotMovingWindowManager(const RefPtr<FrameNode> & node)61 RefPtr<WindowManager> GetNotMovingWindowManager(const RefPtr<FrameNode>& node)
62 {
63     CHECK_NULL_RETURN(node, nullptr);
64     auto pipeline = node->GetContextRefPtr();
65     CHECK_NULL_RETURN(pipeline, nullptr);
66     const auto& windowManager = pipeline->GetWindowManager();
67     CHECK_NULL_RETURN(windowManager, nullptr);
68     bool isMoving = windowManager->WindowIsStartMoving();
69     if (isMoving) {
70         TAG_LOGI(AceLogTag::ACE_APPBAR, "window is moving, button click event is not supported");
71         return nullptr;
72     }
73     return windowManager;
74 }
75 
BondingMenuItemEvent(WeakPtr<ContainerModalPatternEnhance> & weakPtn,RefPtr<FrameNode> & item,bool isLeftSplit)76 void BondingMenuItemEvent(WeakPtr<ContainerModalPatternEnhance>& weakPtn, RefPtr<FrameNode>& item, bool isLeftSplit)
77 {
78     WeakPtr<FrameNode> weakItem = item;
79     auto hoverFunc = [weakItem](bool isHover) {
80         auto item = weakItem.Upgrade();
81         CHECK_NULL_VOID(item);
82         ContainerModalPatternEnhance::OnMenuItemHoverEvent(item, isHover);
83     };
84     auto clickFunc = [weakItem](MouseInfo& info) -> void {
85         auto item = weakItem.Upgrade();
86         CHECK_NULL_VOID(item);
87         ContainerModalPatternEnhance::OnMenuItemClickEvent(item, info);
88     };
89 
90     auto hoverEvent = AceType::MakeRefPtr<InputEvent>(std::move(hoverFunc));
91     auto clickEvent = AceType::MakeRefPtr<InputEvent>(std::move(clickFunc));
92 
93     auto inputHub = item->GetOrCreateInputEventHub();
94     inputHub->AddOnHoverEvent(hoverEvent);
95     inputHub->AddOnMouseEvent(clickEvent);
96 
97     auto gestureHub = item->GetOrCreateGestureEventHub();
98     CHECK_NULL_VOID(gestureHub);
99     auto splitClickFunc = [weakPtn, isLeftSplit](GestureEvent& info) {
100         auto pattern = weakPtn.Upgrade();
101         CHECK_NULL_VOID(pattern);
102         pattern->OnMenuItemClickGesture(isLeftSplit);
103     };
104     auto clickGesture = AceType::MakeRefPtr<ClickEvent>(std::move(splitClickFunc));
105     gestureHub->AddClickEvent(clickGesture);
106 }
107 
BuildMenuItem(WeakPtr<ContainerModalPatternEnhance> && weakPattern,bool isLeftSplit)108 RefPtr<FrameNode> BuildMenuItem(WeakPtr<ContainerModalPatternEnhance>&& weakPattern, bool isLeftSplit)
109 {
110     auto containerTitleRow = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
111         AceType::MakeRefPtr<LinearLayoutPattern>(false));
112 
113     using StrPair = std::tuple<std::string, std::string, InternalResource::ResourceId>;
114     const StrPair strs[] = {
115         { "window.leftSide", "EnhanceMenuScreenLeftRow", InternalResource::ResourceId::IC_WINDOW_MENU_SCREEN_L },
116         { "window.rightSide", "EnhanceMenuScreenRightRow", InternalResource::ResourceId::IC_WINDOW_MENU_SCREEN_N }};
117     const auto& sideSrc = isLeftSplit ? strs[0] : strs[1];
118     containerTitleRow->UpdateInspectorId(std::get<1>(sideSrc));
119 
120     // setRadius 8vp
121     auto render = containerTitleRow->GetRenderContext();
122     BorderRadiusProperty borderRadiusProperty;
123     borderRadiusProperty.SetRadius(MENU_ITEM_RADIUS);
124     render->UpdateBorderRadius(borderRadiusProperty);
125 
126     auto layoutProperty = containerTitleRow->GetLayoutProperty<LinearLayoutProperty>();
127     layoutProperty->UpdateMeasureType(MeasureType::MATCH_CONTENT);
128 
129     layoutProperty->UpdateMainAxisAlign(FlexAlign::FLEX_START);
130     layoutProperty->UpdateCrossAxisAlign(FlexAlign::CENTER);
131     PaddingProperty padding;
132     padding.SetEdges(CalcLength(MENU_ITEM_PADDING_H), CalcLength(MENU_ITEM_PADDING_H), CalcLength(MENU_ITEM_PADDING_V),
133         CalcLength(MENU_ITEM_PADDING_V));
134     layoutProperty->UpdatePadding(padding);
135 
136     auto icon = ContainerModalViewEnhance::BuildMenuItemIcon(std::get<2>(sideSrc));
137     auto textPattern = AceType::MakeRefPtr<TextPattern>();
138     auto titleLabel =
139         FrameNode::CreateFrameNode(V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), textPattern);
140     auto textLayoutProperty = titleLabel->GetLayoutProperty<TextLayoutProperty>();
141     textLayoutProperty->UpdateContent(Localization::GetInstance()->GetEntryLetters(std::get<0>(sideSrc)));
142     textLayoutProperty->UpdateMaxLines(1);
143     textLayoutProperty->UpdateFontSize(TITLE_TEXT_FONT_SIZE);
144     textLayoutProperty->UpdateAlignment(Alignment::CENTER_LEFT);
145     MarginProperty margin;
146     margin.left = CalcLength(MENU_ITEM_TEXT_PADDING);
147     margin.right = CalcLength(MENU_ITEM_TEXT_PADDING);
148     textLayoutProperty->UpdateMargin(margin);
149 
150     // add icon and label
151     containerTitleRow->AddChild(icon);
152     containerTitleRow->AddChild(titleLabel);
153     BondingMenuItemEvent(weakPattern, containerTitleRow, isLeftSplit);
154     return containerTitleRow;
155 }
156 
EventHubOnModifyDone(RefPtr<FrameNode> & node)157 void EventHubOnModifyDone(RefPtr<FrameNode>& node)
158 {
159     CHECK_NULL_VOID(node);
160     auto eventHub = node->GetOrCreateGestureEventHub();
161     CHECK_NULL_VOID(eventHub);
162     eventHub->OnModifyDone();
163 }
164 } // namespace
165 
ShowTitle(bool isShow,bool hasDeco,bool needUpdate)166 void ContainerModalPatternEnhance::ShowTitle(bool isShow, bool hasDeco, bool needUpdate)
167 {
168     auto containerNode = GetHost();
169     CHECK_NULL_VOID(containerNode);
170     auto customTitleRow = GetCustomTitleRow();
171     CHECK_NULL_VOID(customTitleRow);
172     auto floatingTitleRow = GetFloatingTitleRow();
173     CHECK_NULL_VOID(floatingTitleRow);
174     bool isFocus_ = GetIsFocus();
175     if (needUpdate) {
176         TAG_LOGI(AceLogTag::ACE_APPBAR, "title is need update, isFocus_: %{public}d", isFocus_);
177         ChangeCustomTitle(isFocus_);
178         ChangeControlButtons(isFocus_);
179         return;
180     }
181     auto pipelineContext = PipelineContext::GetCurrentContext();
182     CHECK_NULL_VOID(pipelineContext);
183     auto theme = pipelineContext->GetTheme<ContainerModalTheme>();
184     auto stackNode = GetStackNode();
185     CHECK_NULL_VOID(stackNode);
186     auto windowManager = pipelineContext->GetWindowManager();
187     CHECK_NULL_VOID(windowManager);
188     windowMode_ = windowManager->GetWindowMode();
189     isShow = isShow && hasDeco;
190     isTitleShow_ = isShow;
191     // update container modal padding and border
192     auto layoutProperty = containerNode->GetLayoutProperty();
193     CHECK_NULL_VOID(layoutProperty);
194     layoutProperty->UpdateAlignment(Alignment::TOP_LEFT);
195     bool isFloatingWindow = windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING;
196     BorderWidthProperty borderWidth;
197     layoutProperty->UpdateBorderWidth(borderWidth);
198     auto renderContext = containerNode->GetRenderContext();
199     CHECK_NULL_VOID(renderContext);
200     renderContext->SetClipToBounds(true);
201     renderContext->UpdateBackgroundColor(GetContainerColor(isFocus_));
202     // only floating window show border
203     BorderColorProperty borderColor;
204     borderColor.SetColor((isFloatingWindow && isShow) ? CONTAINER_BORDER_COLOR : Color::TRANSPARENT);
205     renderContext->UpdateBorderColor(borderColor);
206 
207     // update stack content border
208     auto stackLayoutProperty = stackNode->GetLayoutProperty();
209     CHECK_NULL_VOID(stackLayoutProperty);
210     stackLayoutProperty->UpdateLayoutWeight(1.0f);
211     auto stackRenderContext = stackNode->GetRenderContext();
212     CHECK_NULL_VOID(stackRenderContext);
213     stackRenderContext->SetClipToBounds(true);
214     auto customTitleLayoutProperty = customTitleRow->GetLayoutProperty();
215     CHECK_NULL_VOID(customTitleLayoutProperty);
216     customTitleLayoutProperty->UpdateVisibility(
217         (isShow && customTitleSettedShow_) ? VisibleType::VISIBLE : VisibleType::GONE);
218 
219     auto floatingLayoutProperty = floatingTitleRow->GetLayoutProperty();
220     CHECK_NULL_VOID(floatingLayoutProperty);
221     floatingLayoutProperty->UpdateVisibility(VisibleType::GONE);
222     auto controlButtonsNode = GetControlButtonRow();
223     CHECK_NULL_VOID(controlButtonsNode);
224     auto controlButtonsLayoutProperty = controlButtonsNode->GetLayoutProperty();
225     CHECK_NULL_VOID(controlButtonsLayoutProperty);
226     ChangeFloatingTitle(isFocus_);
227     ChangeControlButtons(isFocus_);
228     auto controlButtonsContext = controlButtonsNode->GetRenderContext();
229     CHECK_NULL_VOID(controlButtonsContext);
230     controlButtonsContext->OnTransformTranslateUpdate({ 0.0f, 0.0f, 0.0f });
231     controlButtonsLayoutProperty->UpdateVisibility(isShow ? VisibleType::VISIBLE : VisibleType::GONE);
232     controlButtonVisibleBeforeAnim_ = (isShow ? VisibleType::VISIBLE : VisibleType::GONE);
233     auto gestureRow = GetGestureRow();
234     CHECK_NULL_VOID(gestureRow);
235 
236     // add tap event and pan event
237     if (enableContainerModalGesture_) {
238         auto pattern = containerNode->GetPattern<ContainerModalPatternEnhance>();
239         pattern->SetTapGestureEvent(customTitleRow);
240         pattern->SetTapGestureEvent(gestureRow);
241         pattern->SetTapGestureEvent(floatingTitleRow);
242         AddPanEvent(customTitleRow);
243         AddPanEvent(gestureRow);
244         EventHubOnModifyDone(customTitleRow);
245         EventHubOnModifyDone(gestureRow);
246         EventHubOnModifyDone(floatingTitleRow);
247     }
248 
249     UpdateGestureRowVisible();
250     InitColumnTouchTestFunc();
251     controlButtonsNode->SetHitTestMode(HitTestMode::HTMTRANSPARENT_SELF);
252     auto stack = GetStackNode();
253     CHECK_NULL_VOID(stack);
254     stack->UpdateInspectorId(CONTAINER_MODAL_STACK_ID);
255 }
256 
GetTitleItemByIndex(const RefPtr<FrameNode> & controlButtonsNode,int32_t originIndex)257 RefPtr<UINode> ContainerModalPatternEnhance::GetTitleItemByIndex(
258     const RefPtr<FrameNode>& controlButtonsNode, int32_t originIndex)
259 {
260     return controlButtonsNode->GetChildAtIndex(originIndex);
261 }
262 
OnWindowForceUnfocused()263 void ContainerModalPatternEnhance::OnWindowForceUnfocused()
264 {
265     if (!GetIsFocus()) {
266         isHoveredMenu_ = false;
267         ContainerModalPattern::OnWindowUnfocused();
268     }
269 }
270 
ChangeCustomTitle(bool isFocus)271 void ContainerModalPatternEnhance::ChangeCustomTitle(bool isFocus)
272 {
273     // update custom title label
274     auto customTitleNode = GetCustomTitleNode();
275     CHECK_NULL_VOID(customTitleNode);
276     isFocus ? customTitleNode->FireOnWindowFocusedCallback() : customTitleNode->FireOnWindowUnfocusedCallback();
277 }
278 
ChangeControlButtons(bool isFocus)279 void ContainerModalPatternEnhance::ChangeControlButtons(bool isFocus)
280 {
281     auto controlButtonsNode = GetCustomButtonNode();
282     CHECK_NULL_VOID(controlButtonsNode);
283     isFocus ? controlButtonsNode->FireOnWindowFocusedCallback() : controlButtonsNode->FireOnWindowUnfocusedCallback();
284     SetMaximizeIconIsRecover();
285 }
286 
ChangeFloatingTitle(bool isFocus)287 void ContainerModalPatternEnhance::ChangeFloatingTitle(bool isFocus)
288 {
289     auto pipeline = PipelineContext::GetCurrentContext();
290     CHECK_NULL_VOID(pipeline);
291     auto windowManager = pipeline->GetWindowManager();
292     CHECK_NULL_VOID(windowManager);
293 
294     if (windowManager->GetWindowMode() != WindowMode::WINDOW_MODE_FLOATING &&
295         windowManager->GetWindowMode() != WindowMode::WINDOW_MODE_FULLSCREEN) {
296         windowManager->SetCurrentWindowMaximizeMode(MaximizeMode::MODE_RECOVER);
297     }
298 
299     auto floatingTitleRow = GetFloatingTitleRow();
300     CHECK_NULL_VOID(floatingTitleRow);
301     auto floatingContext = floatingTitleRow->GetRenderContext();
302     CHECK_NULL_VOID(floatingContext);
303     auto pipelineContext = PipelineContext::GetCurrentContext();
304     CHECK_NULL_VOID(pipelineContext);
305     auto theme = pipelineContext->GetTheme<ContainerModalTheme>();
306     floatingContext->UpdateBackgroundColor(GetContainerColor(isFocus));
307     // update floating custom title label
308     auto customFloatingTitleNode = GetFloatingTitleNode();
309     CHECK_NULL_VOID(customFloatingTitleNode);
310     isFocus ? customFloatingTitleNode->FireOnWindowFocusedCallback()
311             : customFloatingTitleNode->FireOnWindowUnfocusedCallback();
312 }
313 
SetContainerButtonHide(bool hideSplit,bool hideMaximize,bool hideMinimize,bool hideClose)314 void ContainerModalPatternEnhance::SetContainerButtonHide(
315     bool hideSplit, bool hideMaximize, bool hideMinimize, bool hideClose)
316 {
317     auto controlButtonsNode = GetCustomButtonNode();
318     CHECK_NULL_VOID(controlButtonsNode);
319     controlButtonsNode->FireCustomCallback(EVENT_NAME_HIDE_SPLIT, hideSplit);
320     controlButtonsNode->FireCustomCallback(EVENT_NAME_MAXIMIZE_VISIBILITY, hideMaximize);
321     controlButtonsNode->FireCustomCallback(EVENT_NAME_MINIMIZE_VISIBILITY, hideMinimize);
322     controlButtonsNode->FireCustomCallback(EVENT_NAME_CLOSE_VISIBILITY, hideClose);
323 }
324 
UpdateTitleInTargetPos(bool isShow,int32_t height)325 void ContainerModalPatternEnhance::UpdateTitleInTargetPos(bool isShow, int32_t height)
326 {
327     auto floatingTitleNode = GetFloatingTitleRow();
328     CHECK_NULL_VOID(floatingTitleNode);
329     auto floatingLayoutProperty = floatingTitleNode->GetLayoutProperty();
330     CHECK_NULL_VOID(floatingLayoutProperty);
331     auto floatingContext = floatingTitleNode->GetRenderContext();
332     CHECK_NULL_VOID(floatingContext);
333 
334     auto controlButtonsNode = GetControlButtonRow();
335     CHECK_NULL_VOID(controlButtonsNode);
336     auto controlButtonsLayoutProperty = controlButtonsNode->GetLayoutProperty();
337     CHECK_NULL_VOID(controlButtonsLayoutProperty);
338     auto buttonsContext = controlButtonsNode->GetRenderContext();
339     CHECK_NULL_VOID(buttonsContext);
340 
341     auto titlePopupDistance = titleHeight_.ConvertToPx();
342     auto cubicBezierCurve = AceType::MakeRefPtr<CubicCurve>(0.00, 0.00, 0.20, 1.00);
343     AnimationOption option;
344     option.SetDuration(TITLE_POPUP_DURATION);
345     option.SetCurve(cubicBezierCurve);
346 
347     if (isShow && CanShowFloatingTitle()) {
348         floatingContext->OnTransformTranslateUpdate({ 0.0f, height - static_cast<float>(titlePopupDistance), 0.0f });
349         floatingLayoutProperty->UpdateVisibility(floatingTitleSettedShow_ ? VisibleType::VISIBLE : VisibleType::GONE);
350         AnimationUtils::Animate(option, [floatingContext, height]() {
351             auto rect = floatingContext->GetPaintRectWithoutTransform();
352             floatingContext->OnTransformTranslateUpdate({ 0.0f, static_cast<float>(height - rect.GetY()), 0.0f });
353         });
354         buttonsContext->OnTransformTranslateUpdate({ 0.0f, height - static_cast<float>(titlePopupDistance), 0.0f });
355         controlButtonVisibleBeforeAnim_ = controlButtonsLayoutProperty->GetVisibilityValue();
356         controlButtonsLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
357         AnimationUtils::Animate(option, [buttonsContext, titlePopupDistance, height]() {
358             auto rect = buttonsContext->GetPaintRectWithoutTransform();
359             buttonsContext->OnTransformTranslateUpdate({ 0.0f,
360                 static_cast<float>(
361                     height - (titlePopupDistance - CONTAINER_TITLE_HEIGHT.ConvertToPx()) / 2 - rect.GetY()),
362                 0.0f });
363         });
364     }
365 
366     if (!isShow && CanHideFloatingTitle()) {
367         auto beforeVisible = controlButtonVisibleBeforeAnim_;
368         AnimationUtils::Animate(
369             option,
370             [floatingContext, buttonsContext, titlePopupDistance, beforeVisible]() {
371                 floatingContext->OnTransformTranslateUpdate({ 0.0f, static_cast<float>(-titlePopupDistance), 0.0f });
372                 buttonsContext->OnTransformTranslateUpdate({ 0.0f,
373                     beforeVisible == VisibleType::VISIBLE ? 0.0f : static_cast<float>(-titlePopupDistance), 0.0f });
374             },
375             [floatingLayoutProperty, controlButtonsLayoutProperty, weak = WeakClaim(this)]() {
376                 auto pattern = weak.Upgrade();
377                 CHECK_NULL_VOID(pattern);
378                 floatingLayoutProperty->UpdateVisibility(VisibleType::GONE);
379                 controlButtonsLayoutProperty->UpdateVisibility(pattern->controlButtonVisibleBeforeAnim_);
380             });
381     }
382 }
383 
AddPointLight()384 void ContainerModalPatternEnhance::AddPointLight() {}
385 
GetOrCreateMenuList(const RefPtr<FrameNode> & targetNode)386 RefPtr<FrameNode> ContainerModalPatternEnhance::GetOrCreateMenuList(const RefPtr<FrameNode>& targetNode)
387 {
388     MeasureContext textCtx;
389     textCtx.textContent = Localization::GetInstance()->GetEntryLetters("window.rightSide");
390     textCtx.fontSize = TITLE_TEXT_FONT_SIZE;
391     auto textSize = MeasureUtil::MeasureTextSize(textCtx);
392     textWidth_ = textSize.Width();
393 
394     if (!menuList_) {
395         BuildMenuList();
396     }
397     auto menuLayoutProperty = menuList_->GetLayoutProperty<ListLayoutProperty>();
398     menuLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(GetMenuWidth()), std::nullopt));
399     CalculateMenuOffset(targetNode);
400 
401     return menuList_;
402 }
403 
BuildMenuList()404 void ContainerModalPatternEnhance::BuildMenuList()
405 {
406     auto menuList = FrameNode::CreateFrameNode(
407         V2::LIST_COMPONENT_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ListPattern>());
408     auto listLayoutProperty = menuList->GetLayoutProperty<ListLayoutProperty>();
409     CHECK_NULL_VOID(listLayoutProperty);
410     listLayoutProperty->UpdateMeasureType(MeasureType::MATCH_CONTENT);
411     listLayoutProperty->UpdateLaneGutter(MENU_GUTTER);
412     menuList->AddChild(BuildMenuItem(WeakClaim(this), true));
413     menuList->AddChild(BuildMenuItem(WeakClaim(this), false));
414     menuList_ = menuList;
415 }
416 
GetMenuWidth()417 Dimension ContainerModalPatternEnhance::GetMenuWidth()
418 {
419     auto noneTextWidth = TITLE_ICON_SIZE + MENU_ITEM_PADDING_H * 2 + MENU_ITEM_TEXT_PADDING;
420     auto menuWidth = Dimension(textWidth_ + noneTextWidth.ConvertToPx());
421     return menuWidth;
422 }
423 
CalculateMenuOffset(const RefPtr<FrameNode> & targetNode)424 void ContainerModalPatternEnhance::CalculateMenuOffset(const RefPtr<FrameNode>& targetNode)
425 {
426     auto pipeline = targetNode->GetContextRefPtr();
427     CHECK_NULL_VOID(pipeline);
428     auto windowOffset = pipeline->GetCurrentWindowRect().GetOffset();
429     auto nodeOffset = targetNode->GetPositionToWindowWithTransform();
430     float menuWidth = GetMenuWidth().ConvertToPx() + MENU_PADDING.ConvertToPx() * 2;
431     float buttonSize = TITLE_ICON_SIZE.ConvertToPx();
432     float offsetX = nodeOffset.GetX() + windowOffset.GetX() - menuWidth + buttonSize;
433     float offsetY = nodeOffset.GetY() + windowOffset.GetY() + buttonSize;
434 
435     float screenWidth = SystemProperties::GetDevicePhysicalWidth();
436     float screenHeight = SystemProperties::GetDevicePhysicalHeight();
437     float titleHeight = GetCustomTitleHeight().ConvertToPx();
438     const Dimension MENU_CONTAINER_HEIGHT = 96.0_vp; // need to calculate from text, to be delete
439     float menuHeight = MENU_CONTAINER_HEIGHT.ConvertToPx() + 2 * CONTENT_PADDING.ConvertToPx();
440     if (offsetX < MENU_SAFETY_X.ConvertToPx()) {
441         TAG_LOGI(AceLogTag::ACE_APPBAR, "ContainerModalViewEnhance::RecalculateMenuOffset OffsetX cover screen left");
442         offsetX = offsetX + menuWidth - buttonSize;
443     }
444     if (offsetX > screenWidth - menuWidth - MENU_SAFETY_X.ConvertToPx()) {
445         TAG_LOGI(AceLogTag::ACE_APPBAR, "ContainerModalViewEnhance::RecalculateMenuOffset OffsetX cover screen right");
446         offsetX = nodeOffset.GetX() + windowOffset.GetX() + buttonSize;
447     }
448     if (offsetY > screenHeight - menuHeight - MENU_SAFETY_Y.ConvertToPx()) {
449         TAG_LOGI(AceLogTag::ACE_APPBAR, "ContainerModalViewEnhance::RecalculateMenuOffset OffsetX cover screen bottom");
450         offsetY = offsetY - menuHeight - titleHeight;
451     }
452     menuOffset_ = { offsetX, offsetY };
453     TAG_LOGI(AceLogTag::ACE_APPBAR, "ContainerModal ShowMaxMenu called menuOffset_ = %{public}s",
454         menuOffset_.ToString().c_str());
455 }
456 
SetTapGestureEvent(RefPtr<FrameNode> & containerTitleRow)457 void ContainerModalPatternEnhance::SetTapGestureEvent(RefPtr<FrameNode>& containerTitleRow)
458 {
459     auto eventHub = containerTitleRow->GetOrCreateGestureEventHub();
460     CHECK_NULL_VOID(eventHub);
461     auto tapGesture = AceType::MakeRefPtr<NG::TapGesture>(2, 1);
462     CHECK_NULL_VOID(tapGesture);
463     WeakPtr<FrameNode> weakNode = frameNode_;
464     tapGesture->SetOnActionId([weakNode](GestureEvent& info) mutable {
465         auto containerNode = weakNode.Upgrade();
466         CHECK_NULL_VOID(containerNode);
467         auto windowManager = GetNotMovingWindowManager(containerNode);
468         CHECK_NULL_VOID(windowManager);
469         auto windowMode = windowManager->GetWindowMode();
470         auto maximizeMode = windowManager->GetCurrentWindowMaximizeMode();
471         TAG_LOGI(AceLogTag::ACE_APPBAR, "container window double click. maximizeMode =  %{public}d", maximizeMode);
472         if (maximizeMode == MaximizeMode::MODE_AVOID_SYSTEM_BAR || windowMode == WindowMode::WINDOW_MODE_FULLSCREEN ||
473             windowMode == WindowMode::WINDOW_MODE_SPLIT_PRIMARY ||
474             windowMode == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) {
475             EventReport::ReportDoubleClickTitle(DOUBLE_CLICK_TO_RECOVER);
476             windowManager->WindowRecover();
477         } else if (windowMode == WindowMode::WINDOW_MODE_FLOATING) {
478             EventReport::ReportDoubleClickTitle(DOUBLE_CLICK_TO_MAXIMIZE);
479             windowManager->WindowMaximize(true);
480         }
481         containerNode->OnWindowActivated();
482     });
483     eventHub->AddGesture(tapGesture);
484 }
485 
ClearTapGestureEvent(RefPtr<FrameNode> & containerTitleRow)486 void ContainerModalPatternEnhance::ClearTapGestureEvent(RefPtr<FrameNode>& containerTitleRow)
487 {
488     auto eventHub = containerTitleRow->GetOrCreateGestureEventHub();
489     CHECK_NULL_VOID(eventHub);
490     eventHub->ClearGesture();
491     eventHub->OnModifyDone();
492 }
493 
OnMaxButtonClick(GestureEvent & info)494 void ContainerModalPatternEnhance::OnMaxButtonClick(GestureEvent& info)
495 {
496     auto windowManager = GetNotMovingWindowManager(frameNode_.Upgrade());
497     ResetHoverTimer();
498     if (!windowManager) {
499         return;
500     }
501     auto mode = windowManager->GetWindowMode();
502     TAG_LOGI(AceLogTag::ACE_APPBAR, "maxmize button click event triggerd, mode = %{public}d", mode);
503     auto currentMode = windowManager->GetCurrentWindowMaximizeMode();
504     if (mode == WindowMode::WINDOW_MODE_FULLSCREEN || currentMode == MaximizeMode::MODE_AVOID_SYSTEM_BAR ||
505         mode == WindowMode::WINDOW_MODE_SPLIT_PRIMARY || mode == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) {
506         EventReport::ReportClickTitleMaximizeMenu(MAX_MENU_ITEM_MAXIMIZE, MAX_BUTTON_CLICK_TO_RECOVER);
507         windowManager->WindowRecover();
508     } else {
509         EventReport::ReportClickTitleMaximizeMenu(MAX_MENU_ITEM_MAXIMIZE, MAX_BUTTON_CLICK_TO_MAXIMIZE);
510         windowManager->WindowMaximize(true);
511     }
512     GetHost()->OnWindowActivated();
513 }
514 
OnMinButtonClick(GestureEvent & info)515 void ContainerModalPatternEnhance::OnMinButtonClick(GestureEvent& info)
516 {
517     TAG_LOGI(AceLogTag::ACE_APPBAR, "minimize button clicked");
518     auto windowManager = GetNotMovingWindowManager(frameNode_.Upgrade());
519     CHECK_NULL_VOID(windowManager);
520     TAG_LOGI(AceLogTag::ACE_APPBAR, "minimize button click event triggerd");
521     windowManager->WindowMinimize();
522 }
523 
OnCloseButtonClick(GestureEvent & info)524 void ContainerModalPatternEnhance::OnCloseButtonClick(GestureEvent& info)
525 {
526     TAG_LOGI(AceLogTag::ACE_APPBAR, "close button clicked");
527     auto windowManager = GetNotMovingWindowManager(frameNode_.Upgrade());
528     CHECK_NULL_VOID(windowManager);
529     TAG_LOGI(AceLogTag::ACE_APPBAR, "close button click event triggerd");
530     windowManager->WindowClose();
531 }
532 
ShowMaxMenu(const RefPtr<FrameNode> & targetNode)533 RefPtr<FrameNode> ContainerModalPatternEnhance::ShowMaxMenu(const RefPtr<FrameNode>& targetNode)
534 {
535     CHECK_NULL_RETURN(targetNode, nullptr);
536     if (!enableSplit_) {
537         TAG_LOGI(AceLogTag::ACE_APPBAR, "the app window is not support spilt menu");
538         return nullptr;
539     }
540     auto pipeline = PipelineContext::GetCurrentContext();
541     CHECK_NULL_RETURN(pipeline, nullptr);
542     auto windowManager = pipeline->GetWindowManager();
543     CHECK_NULL_RETURN(windowManager, nullptr);
544     // menu list
545     auto menuList = GetOrCreateMenuList(targetNode);
546     CHECK_NULL_RETURN(menuList, nullptr);
547     auto subWindowManger = SubwindowManager::GetInstance();
548     CHECK_NULL_RETURN(subWindowManger, nullptr);
549     auto menuSubwindow = subWindowManger->GetSubwindowByType(Container::CurrentId(), SubwindowType::TYPE_MENU);
550     if ((!menuSubwindow || !menuSubwindow->GetShown())) {
551         ACE_SCOPED_TRACE("ContainerModalViewEnhance::ShowMaxMenu");
552         MenuParam menuParam {};
553         menuParam.type = MenuType::CONTEXT_MENU;
554         SubwindowManager::GetInstance()->ShowMenuNG(menuList, menuParam, targetNode, menuOffset_);
555     }
556     ResetHoverTimer();
557     return menuList;
558 }
559 
OnMaxBtnInputEvent(MouseInfo & info)560 void ContainerModalPatternEnhance::OnMaxBtnInputEvent(MouseInfo& info)
561 {
562     isForbidMenuEvent_ = (info.GetButton() == MouseButton::LEFT_BUTTON || info.GetScreenLocation().IsZero());
563 }
564 
OnMaxBtnHoverEvent(bool hover,WeakPtr<FrameNode> & weakBtn)565 void ContainerModalPatternEnhance::OnMaxBtnHoverEvent(bool hover, WeakPtr<FrameNode>& weakBtn)
566 {
567     if (!hover) {
568         ResetHoverTimer();
569         return;
570     }
571     if (isMenuPending_ || isForbidMenuEvent_ || !GetIsFocus()) { // whether can show menu
572         return;
573     }
574     auto&& callback = [weakPattern = WeakClaim(this), weakBtn]() {
575         auto maximizeBtn = weakBtn.Upgrade();
576         CHECK_NULL_VOID(maximizeBtn);
577         auto pattern = weakPattern.Upgrade();
578         CHECK_NULL_VOID(pattern);
579         pattern->ShowMaxMenu(maximizeBtn);
580     };
581     auto pipeline = GetHost()->GetContextRefPtr();
582     CHECK_NULL_VOID(pipeline);
583     contextTimer_.Reset(callback);
584     pipeline->GetTaskExecutor()->PostDelayedTask(
585         contextTimer_, TaskExecutor::TaskType::UI, MENU_TASK_DELAY_TIME, "ArkUIContainerModalShowMaxMenu");
586     isMenuPending_ = true;
587 }
588 
OnMenuItemHoverEvent(RefPtr<FrameNode> item,bool isHover)589 void ContainerModalPatternEnhance::OnMenuItemHoverEvent(RefPtr<FrameNode> item, bool isHover)
590 {
591     auto theme = item->GetContextRefPtr()->GetTheme<ListItemTheme>();
592     auto renderContext = item->GetRenderContext();
593     if (isHover && theme) {
594         renderContext->UpdateBackgroundColor(theme->GetItemHoverColor());
595     } else {
596         renderContext->UpdateBackgroundColor(MENU_ITEM_COLOR);
597     }
598 }
599 
OnMenuItemClickEvent(RefPtr<FrameNode> item,MouseInfo & info)600 void ContainerModalPatternEnhance::OnMenuItemClickEvent(RefPtr<FrameNode> item, MouseInfo& info)
601 {
602     auto theme = item->GetContextRefPtr()->GetTheme<ListItemTheme>();
603     if (MouseAction::PRESS == info.GetAction() && theme) {
604         auto renderContext = item->GetRenderContext();
605         renderContext->UpdateBackgroundColor(theme->GetClickColor());
606     }
607 }
608 
OnMenuItemClickGesture(bool isSplistLeft)609 void ContainerModalPatternEnhance::OnMenuItemClickGesture(bool isSplistLeft)
610 {
611     auto pipeline = GetContext();
612     CHECK_NULL_VOID(pipeline);
613     const auto& windowManager = pipeline->GetWindowManager();
614     CHECK_NULL_VOID(windowManager);
615     int32_t splitSide = isSplistLeft ? MAX_MENU_ITEM_LEFT_SPLIT : MAX_MENU_ITEM_RIGHT_SPLIT;
616     EventReport::ReportClickTitleMaximizeMenu(splitSide, MAX_MENU_DEFAULT_NOT_CHANGE);
617     windowManager->FireWindowSplitCallBack(isSplistLeft);
618 }
619 
ResetHoverTimer()620 void ContainerModalPatternEnhance::ResetHoverTimer()
621 {
622     contextTimer_.Reset(nullptr);
623     isMenuPending_ = false;
624 }
625 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)626 bool ContainerModalPatternEnhance::OnDirtyLayoutWrapperSwap(
627     const RefPtr<LayoutWrapper>& dirty,
628     const DirtySwapConfig& config)
629 {
630     CallButtonsRectChange();
631 
632     auto considerFloatingWindow = true;
633     CallSetContainerWindow(considerFloatingWindow);
634 
635     return false;
636 }
637 
EnablePanEventOnNode(RefPtr<FrameNode> & node,bool isEnable,const std::string & rowName)638 void ContainerModalPatternEnhance::EnablePanEventOnNode(
639     RefPtr<FrameNode>& node, bool isEnable, const std::string& rowName)
640 {
641     if (!node) {
642         TAG_LOGI(AceLogTag::ACE_APPBAR, "%{public}s is not exist when set pan event", rowName.c_str());
643         return;
644     }
645 
646     if (isEnable) {
647         AddPanEvent(node);
648     } else {
649         RemovePanEvent(node);
650     }
651 }
652 
EnableTapGestureOnNode(RefPtr<FrameNode> & node,bool isEnable,const std::string & rowName)653 void ContainerModalPatternEnhance::EnableTapGestureOnNode(
654     RefPtr<FrameNode>& node, bool isEnable, const std::string& rowName)
655 {
656     if (!node) {
657         TAG_LOGI(AceLogTag::ACE_APPBAR, "%{public}s is not exist when set tap gesture", rowName.c_str());
658         return;
659     }
660 
661     if (isEnable) {
662         SetTapGestureEvent(node);
663     } else {
664         ClearTapGestureEvent(node);
665     }
666 }
667 
HandleGestureRowHitTestMode(RefPtr<FrameNode> & gestureRow)668 void ContainerModalPatternEnhance::HandleGestureRowHitTestMode(RefPtr<FrameNode>& gestureRow)
669 {
670     if (!gestureRow) {
671         TAG_LOGI(AceLogTag::ACE_APPBAR, "gestureRow is not exist when HandleHitTestMode");
672         return;
673     }
674 
675     if (enableContainerModalGesture_) {
676         gestureRow->SetHitTestMode(HitTestMode::HTMDEFAULT);
677     } else {
678         gestureRow->SetHitTestMode(HitTestMode::HTMTRANSPARENT);
679     }
680 }
681 
EnableContainerModalGesture(bool isEnable)682 void ContainerModalPatternEnhance::EnableContainerModalGesture(bool isEnable)
683 {
684     TAG_LOGI(AceLogTag::ACE_APPBAR, "set event on container modal is %{public}d", isEnable);
685 
686     enableContainerModalGesture_ = isEnable;
687 
688     auto floatingTitleRow = GetFloatingTitleRow();
689     auto customTitleRow = GetCustomTitleRow();
690     auto gestureRow = GetGestureRow();
691     HandleGestureRowHitTestMode(gestureRow);
692     EnableTapGestureOnNode(floatingTitleRow, isEnable, "floating title row");
693     EnablePanEventOnNode(customTitleRow, isEnable, "custom title row");
694     EnableTapGestureOnNode(customTitleRow, isEnable, "custom title row");
695     EnablePanEventOnNode(gestureRow, isEnable, "gesture row");
696     EnableTapGestureOnNode(gestureRow, isEnable, "gesture row");
697     EventHubOnModifyDone(floatingTitleRow);
698     EventHubOnModifyDone(customTitleRow);
699     EventHubOnModifyDone(gestureRow);
700 }
701 
GetFloatingTitleVisible()702 bool ContainerModalPatternEnhance::GetFloatingTitleVisible()
703 {
704     auto floatingTitleRow = GetFloatingTitleRow();
705     CHECK_NULL_RETURN(floatingTitleRow, false);
706     auto floatingTitleRowProp = floatingTitleRow->GetLayoutProperty();
707     CHECK_NULL_RETURN(floatingTitleRowProp, false);
708     return (floatingTitleRowProp->GetVisibilityValue() == VisibleType::VISIBLE);
709 }
710 
GetCustomTitleVisible()711 bool ContainerModalPatternEnhance::GetCustomTitleVisible()
712 {
713     auto customTitleRow = GetCustomTitleRow();
714     CHECK_NULL_RETURN(customTitleRow, false);
715     auto customTitleRowProp = customTitleRow->GetLayoutProperty();
716     CHECK_NULL_RETURN(customTitleRowProp, false);
717     return (customTitleRowProp->GetVisibilityValue() == VisibleType::VISIBLE);
718 }
719 
GetControlButtonVisible()720 bool ContainerModalPatternEnhance::GetControlButtonVisible()
721 {
722     auto controlButtonRow = GetControlButtonRow();
723     CHECK_NULL_RETURN(controlButtonRow, false);
724     auto controlButtonRowProp = controlButtonRow->GetLayoutProperty();
725     CHECK_NULL_RETURN(controlButtonRowProp, false);
726     return (controlButtonRowProp->GetVisibilityValue() == VisibleType::VISIBLE);
727 }
728 
Init()729 void ContainerModalPatternEnhance::Init()
730 {
731     InitContainerColor();
732     InitContainerEvent();
733     InitTitle();
734     InitLayoutProperty();
735     SetColorConfigurationUpdate();
736 }
737 
SetColorConfigurationUpdate()738 void ContainerModalPatternEnhance::SetColorConfigurationUpdate()
739 {
740     TAG_LOGI(AceLogTag::ACE_APPBAR, "SetColorConfigurationUpdate");
741     auto customButtonNode = GetCustomButtonNode();
742     CHECK_NULL_VOID(customButtonNode);
743     auto context = GetContext();
744     CHECK_NULL_VOID(context);
745     auto isDark = context->GetColorMode() == ColorMode::DARK;
746     TAG_LOGI(AceLogTag::ACE_APPBAR, "SetColorConfigurationUpdate isDark = %{public}d", isDark);
747     customButtonNode->FireCustomCallback(EVENT_NAME_COLOR_CONFIGURATION, isDark);
748 }
749 
OnColorConfigurationUpdate()750 void ContainerModalPatternEnhance::OnColorConfigurationUpdate()
751 {
752     WindowFocus(isFocus_);
753     SetColorConfigurationUpdate();
754 }
755 
InitButtonsLayoutProperty()756 void ContainerModalPatternEnhance::InitButtonsLayoutProperty() {}
757 
OnMaxButtonClick()758 void ContainerModalPatternEnhance::OnMaxButtonClick()
759 {
760     TAG_LOGI(AceLogTag::ACE_APPBAR, "maxmize button clicked");
761     auto windowManager = GetNotMovingWindowManager(frameNode_.Upgrade());
762     if (!windowManager) {
763         return;
764     }
765     TAG_LOGI(AceLogTag::ACE_APPBAR, "maxmize button click event triggerd");
766     auto mode = windowManager->GetWindowMode();
767     auto currentMode = windowManager->GetCurrentWindowMaximizeMode();
768     if (mode == WindowMode::WINDOW_MODE_FULLSCREEN || currentMode == MaximizeMode::MODE_AVOID_SYSTEM_BAR ||
769         mode == WindowMode::WINDOW_MODE_SPLIT_PRIMARY || mode == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) {
770         EventReport::ReportClickTitleMaximizeMenu(MAX_MENU_ITEM_MAXIMIZE, MAX_BUTTON_CLICK_TO_RECOVER);
771         windowManager->WindowRecover();
772     } else {
773         EventReport::ReportClickTitleMaximizeMenu(MAX_MENU_ITEM_MAXIMIZE, MAX_BUTTON_CLICK_TO_MAXIMIZE);
774         windowManager->WindowMaximize(true);
775     }
776     GetHost()->OnWindowActivated();
777 }
778 
OnMinButtonClick()779 void ContainerModalPatternEnhance::OnMinButtonClick()
780 {
781     TAG_LOGI(AceLogTag::ACE_APPBAR, "minimize button clicked");
782     auto windowManager = GetNotMovingWindowManager(frameNode_.Upgrade());
783     CHECK_NULL_VOID(windowManager);
784     TAG_LOGI(AceLogTag::ACE_APPBAR, "minimize button click event triggerd");
785     windowManager->WindowMinimize();
786 }
787 
OnCloseButtonClick()788 void ContainerModalPatternEnhance::OnCloseButtonClick()
789 {
790     TAG_LOGI(AceLogTag::ACE_APPBAR, "close button clicked");
791     auto windowManager = GetNotMovingWindowManager(frameNode_.Upgrade());
792     CHECK_NULL_VOID(windowManager);
793     TAG_LOGI(AceLogTag::ACE_APPBAR, "close button click event triggerd");
794     windowManager->WindowClose();
795 }
796 
SetCloseButtonStatus(bool isEnabled)797 void ContainerModalPatternEnhance::SetCloseButtonStatus(bool isEnabled)
798 {
799     TAG_LOGI(AceLogTag::ACE_APPBAR, "SetCloseButtonStatus isEnabled: %{public}d", isEnabled);
800     auto customNode = GetCustomButtonNode();
801     CHECK_NULL_VOID(customNode);
802     customNode->FireCustomCallback(EVENT_NAME_CLOSE_STATUS, isEnabled);
803 }
804 
SetMaximizeIconIsRecover()805 void ContainerModalPatternEnhance::SetMaximizeIconIsRecover()
806 {
807     auto customNode = GetCustomButtonNode();
808     CHECK_NULL_VOID(customNode);
809 
810     auto pipeline = customNode->GetContextRefPtr();
811     CHECK_NULL_VOID(pipeline);
812     auto windowManager = pipeline->GetWindowManager();
813     CHECK_NULL_VOID(windowManager);
814     auto windowMode = windowManager->GetWindowMode();
815     MaximizeMode mode = windowManager->GetCurrentWindowMaximizeMode();
816     if (mode == MaximizeMode::MODE_AVOID_SYSTEM_BAR || windowMode == WindowMode::WINDOW_MODE_FULLSCREEN ||
817         windowMode == WindowMode::WINDOW_MODE_SPLIT_PRIMARY || windowMode == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) {
818         customNode->FireCustomCallback(EVENT_NAME_MAXIMIZE_IS_RECOVER, true);
819     } else {
820         customNode->FireCustomCallback(EVENT_NAME_MAXIMIZE_IS_RECOVER, false);
821     }
822 }
823 
CallContainerModalNative(const std::string & name,const std::string & value)824 void ContainerModalPatternEnhance::CallContainerModalNative(const std::string& name, const std::string& value)
825 {
826     TAG_LOGI(AceLogTag::ACE_APPBAR, "CallContainerModalNative name = %{public}s , value = %{public}s", name.c_str(),
827         value.c_str());
828     auto windowManager = GetNotMovingWindowManager(frameNode_.Upgrade());
829     CHECK_NULL_VOID(windowManager);
830     windowManager->FireWindowCallNativeCallback(name, value);
831 }
832 
OnContainerModalEvent(const std::string & name,const std::string & value)833 void ContainerModalPatternEnhance::OnContainerModalEvent(const std::string& name, const std::string& value)
834 {
835     auto controlButtonsNode = GetCustomButtonNode();
836     CHECK_NULL_VOID(controlButtonsNode);
837     controlButtonsNode->FireCustomCallback(name, value);
838     auto customTitleNode = GetCustomTitleNode();
839     CHECK_NULL_VOID(customTitleNode);
840     customTitleNode->FireCustomCallback(name, value);
841 }
842 
GetControlButtonRowWidth()843 CalcLength ContainerModalPatternEnhance::GetControlButtonRowWidth()
844 {
845     auto buttonRow = GetButtonRowByInspectorId();
846     CHECK_NULL_RETURN(buttonRow, CalcLength(Dimension(0, DimensionUnit::VP)));
847     auto width = buttonRow->GetGeometryNode()->GetFrameRect().Width();
848     if (NearZero(width)) {
849         // If the width is 0, initialize the width according to UX specifications.
850         int32_t buttonNum = 0;
851         const auto& children = buttonRow->GetChildren();
852         for (const auto& child : children) {
853             auto childButton = AceType::DynamicCast<FrameNode>(child);
854             if (childButton && childButton->IsVisible()) {
855                 buttonNum++;
856             }
857         }
858         return CalcLength(TITLE_ELEMENT_MARGIN_HORIZONTAL * (buttonNum - 1) + TITLE_BUTTON_SIZE * buttonNum +
859                           CONTROL_BUTTON_ROW_LEFT_PADDING + CONTROL_BUTTON_ROW_RIGHT_PADDING);
860     }
861     return CalcLength(Dimension(width, DimensionUnit::PX).ConvertToVp(), DimensionUnit::VP);
862 }
863 
GetContainerModalButtonsRect(RectF & containerModal,RectF & buttons)864 bool ContainerModalPatternEnhance::GetContainerModalButtonsRect(RectF& containerModal, RectF& buttons)
865 {
866     auto column = GetColumnNode();
867     CHECK_NULL_RETURN(column, false);
868     auto columnRect = column->GetGeometryNode()->GetFrameRect();
869     containerModal = columnRect;
870     if (columnRect.Width() == 0) {
871         TAG_LOGW(AceLogTag::ACE_APPBAR, "Get rect of buttons failed, the rect is measuring.");
872         return false;
873     }
874 
875     auto controlButtonsNode = GetControlButtonRow();
876     CHECK_NULL_RETURN(controlButtonsNode, false);
877     auto controlButtonsLayoutProperty = controlButtonsNode->GetLayoutProperty();
878     CHECK_NULL_RETURN(controlButtonsLayoutProperty, false);
879     if (controlButtonsLayoutProperty->GetVisibilityValue(VisibleType::VISIBLE) != VisibleType::VISIBLE) {
880         TAG_LOGW(AceLogTag::ACE_APPBAR, "Get rect of buttons failed, buttonRow are hidden");
881         return false;
882     }
883 
884     auto controlButtonsRow = GetButtonRowByInspectorId();
885     CHECK_NULL_RETURN(controlButtonsRow, false);
886     auto buttonRect = controlButtonsRow->GetGeometryNode()->GetFrameRect();
887     buttons = buttonRect;
888     if (buttons.Width() == 0) {
889         TAG_LOGW(AceLogTag::ACE_APPBAR, "Get rect of buttons failed, buttons are hidden");
890         return false;
891     }
892     return true;
893 }
894 
GetContainerModalComponentRect(RectF & containerModal,RectF & buttons)895 bool ContainerModalPatternEnhance::GetContainerModalComponentRect(RectF& containerModal, RectF& buttons)
896 {
897     auto column = GetColumnNode();
898     CHECK_NULL_RETURN(column, false);
899     auto columnRect = column->GetGeometryNode()->GetFrameRect();
900     containerModal = columnRect;
901     if (columnRect.Width() == 0) {
902         TAG_LOGW(AceLogTag::ACE_APPBAR, "Get rect of buttons failed, the rect is measuring.");
903         return false;
904     }
905 
906     if (customTitleSettedShow_) {
907         return false;
908     }
909     auto controlButtonsRow = GetButtonRowByInspectorId();
910     CHECK_NULL_RETURN(controlButtonsRow, false);
911     auto buttonRect = controlButtonsRow->GetGeometryNode()->GetFrameRect();
912     buttons = buttonRect;
913     if (buttons.Width() == 0) {
914         TAG_LOGW(AceLogTag::ACE_APPBAR, "Get rect of buttons failed, buttons are hidden");
915         return false;
916     }
917     return true;
918 }
919 
CallMenuWidthChange(int32_t resId)920 void ContainerModalPatternEnhance::CallMenuWidthChange(int32_t resId)
921 {
922     auto context = GetContext();
923     CHECK_NULL_VOID(context);
924     std::string text = "";
925     if (SystemProperties::GetResourceDecoupling()) {
926         auto resAdapter = ResourceManager::GetInstance().GetResourceAdapter(context->GetInstanceId());
927         text = resAdapter->GetString(resId);
928     }
929     if (text.empty()) {
930         TAG_LOGW(AceLogTag::ACE_APPBAR, "text is empty");
931         return;
932     }
933 
934     MeasureContext textCtx;
935     textCtx.textContent = text;
936     textCtx.fontSize = TITLE_TEXT_FONT_SIZE;
937     auto textSize = MeasureUtil::MeasureTextSize(textCtx);
938 
939     auto controlButtonsNode = GetCustomButtonNode();
940     CHECK_NULL_VOID(controlButtonsNode);
941     CalcDimension widthDimension(textSize.Width(), DimensionUnit::PX);
942     auto width = widthDimension.ConvertToVp();
943     TAG_LOGI(AceLogTag::ACE_APPBAR, "GetMenuWidth width = %{public}f", width);
944     controlButtonsNode->FireCustomCallback(EVENT_NAME_MENU_WIDTH_CHANGE, std::to_string(width));
945 }
946 
AddButtonsRectChangeListener(ButtonsRectChangeListener && listener)947 int32_t ContainerModalPatternEnhance::AddButtonsRectChangeListener(ButtonsRectChangeListener&& listener)
948 {
949     auto id = g_nextListenerId.fetch_add(1);
950     rectChangeListeners_.emplace(id, listener);
951     return id;
952 }
953 
RemoveButtonsRectChangeListener(int32_t id)954 void ContainerModalPatternEnhance::RemoveButtonsRectChangeListener(int32_t id)
955 {
956     auto it = rectChangeListeners_.find(id);
957     if (it != rectChangeListeners_.end()) {
958         rectChangeListeners_.erase(it);
959     }
960 }
961 
NotifyButtonsRectChange(const RectF & containerModal,const RectF & buttonsRect)962 void ContainerModalPatternEnhance::NotifyButtonsRectChange(const RectF& containerModal, const RectF& buttonsRect)
963 {
964     for (auto& pair : rectChangeListeners_) {
965         if (pair.second) {
966             pair.second(containerModal, buttonsRect);
967         }
968     }
969 }
970 } // namespace OHOS::Ace::NG
971