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