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