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