1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components_ng/pattern/container_modal/enhance/container_modal_view_enhance.h"
17
18 #include "base/geometry/dimension.h"
19 #include "base/geometry/ng/offset_t.h"
20 #include "base/i18n/localization.h"
21 #include "base/log/event_report.h"
22 #include "base/memory/ace_type.h"
23 #include "base/subwindow/subwindow_manager.h"
24 #include "base/utils/system_properties.h"
25 #include "base/utils/utils.h"
26 #include "core/common/container.h"
27 #include "core/components/common/layout/constants.h"
28 #include "core/components/common/properties/color.h"
29 #include "core/components/container_modal/container_modal_constants.h"
30 #include "core/components/theme/advanced_pattern_theme.h"
31 #include "core/components_ng/base/frame_node.h"
32 #include "core/components_ng/base/view_abstract.h"
33 #include "core/components_ng/gestures/pan_gesture.h"
34 #include "core/components_ng/gestures/tap_gesture.h"
35 #include "core/components_ng/pattern/button/button_layout_property.h"
36 #include "core/components_ng/pattern/button/button_pattern.h"
37 #include "core/components_ng/pattern/container_modal/container_modal_pattern.h"
38 #include "core/components_ng/pattern/container_modal/enhance/container_modal_pattern_enhance.h"
39 #include "core/components_ng/pattern/divider/divider_layout_property.h"
40 #include "core/components_ng/pattern/divider/divider_pattern.h"
41 #include "core/components_ng/pattern/image/image_layout_property.h"
42 #include "core/components_ng/pattern/image/image_pattern.h"
43 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
44 #include "core/components_ng/pattern/list/list_pattern.h"
45 #include "core/components_ng/pattern/menu/menu_pattern.h"
46 #include "core/components_ng/pattern/navigation/navigation_declaration.h"
47 #include "core/components_ng/pattern/patternlock/patternlock_paint_property.h"
48 #include "core/components_ng/pattern/stack/stack_pattern.h"
49 #include "core/components_ng/pattern/text/text_layout_property.h"
50 #include "core/components_ng/pattern/text/text_pattern.h"
51 #include "core/components_ng/property/calc_length.h"
52 #include "core/components_v2/inspector/inspector_constants.h"
53 #include "core/event/mouse_event.h"
54 #include "core/image/image_source_info.h"
55 #include "core/pipeline/base/element_register.h"
56
57 namespace OHOS::Ace::NG {
58 /**
59 * The structure of container_modal enhanced is designed as follows :
60 * |--container_modal(stack)
61 * |--column
62 * |--container_modal_custom_title(row)
63 * |--custom_node(js)
64 * |--stack
65 * |--container_modal_content(stage)
66 * |--page
67 * |--dialog(when show)
68 * |--gesture_row(row)
69 * |--container_modal_custom_floating_title(row)
70 * |--custom_node(js)
71 * |--container_modal_control_buttons(row)
72 * |--[maxRecover, minimize, close](button)
73 */
74 namespace {
75 const Dimension MENU_CONTAINER_WIDTH = 232.0_vp;
76 const Dimension MENU_CONTAINER_HEIGHT = 96.0_vp;
77 const Dimension MENU_ITEM_RADIUS = 12.0_vp;
78 const Dimension MENU_ITEM_WIDTH = 232.0_vp;
79 const Dimension MENU_ITEM_HEIGHT = 48.0_vp;
80 const Dimension MENU_ITEM_LEFT_PADDING = 12.0_vp;
81 const Dimension MENU_ITEM_TEXT_WIDTH = 144.0_vp;
82 const Dimension MENU_ITEM_TEXT_HEIGHT = 22.0_vp;
83 const Dimension MENU_ITEM_TEXT_PADDING = 8.0_vp;
84 const Dimension MENU_FLOAT_X = 220.0_vp;
85 const Dimension MENU_FLOAT_Y = 31.0_vp;
86 const Dimension MENU_SAFETY_X = 8.0_vp;
87 const Dimension MENU_SAFETY_Y = 96.0_vp;
88 const int32_t MENU_ITEM_MAXLINES = 1;
89 const int32_t MENU_TASK_DELAY_TIME = 600;
90 const Color MENU_ITEM_COLOR = Color(0xffffff);
91
92 const int32_t DOUBLE_CLICK_TO_MAXIMIZE = 1;
93 const int32_t DOUBLE_CLICK_TO_RECOVER = 2;
94
95 const int32_t MAX_BUTTON_CLICK_TO_MAXIMIZE = 1;
96 const int32_t MAX_BUTTON_CLICK_TO_RECOVER = 2;
97
98 const int32_t MAX_MENU_ITEM_LEFT_SPLIT = 1;
99 const int32_t MAX_MENU_ITEM_RIGHT_SPLIT = 2;
100 const int32_t MAX_MENU_ITEM_MAXIMIZE = 3;
101
102 const int32_t MAX_MENU_DEFAULT_NOT_CHANGE = 3;
103 } // namespace
104 bool ContainerModalViewEnhance::sIsForbidMenuEvent_ = false;
105 bool ContainerModalViewEnhance::sIsMenuPending_ = false;
106 bool ContainerModalViewEnhance::enableSplit_ = true;
107 OffsetF ContainerModalViewEnhance::menuOffset_ = {};
108 CancelableCallback<void()> ContainerModalViewEnhance::sContextTimer_;
109
Create(RefPtr<FrameNode> & content)110 RefPtr<FrameNode> ContainerModalViewEnhance::Create(RefPtr<FrameNode>& content)
111 {
112 auto containerModalNode = FrameNode::CreateFrameNode("ContainerModal",
113 ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ContainerModalPatternEnhance>());
114 auto stack = FrameNode::CreateFrameNode(
115 V2::STACK_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<StackPattern>());
116 auto column = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
117 AceType::MakeRefPtr<LinearLayoutPattern>(true));
118 auto controlButtonsRow = FrameNode::CreateFrameNode(
119 V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), MakeRefPtr<LinearLayoutPattern>(false));
120
121 column->AddChild(BuildTitle(containerModalNode));
122 stack->AddChild(content);
123 column->AddChild(stack);
124 column->AddChild(BuildGestureRow(containerModalNode));
125 auto containerPattern = containerModalNode->GetPattern<ContainerModalPatternEnhance>();
126 CHECK_NULL_RETURN(containerPattern, nullptr);
127 SetContainerModalPattern(containerPattern);
128 containerModalNode->AddChild(column);
129 containerModalNode->AddChild(BuildTitle(containerModalNode, true));
130 containerModalNode->AddChild(AddControlButtons(containerModalNode, controlButtonsRow));
131 containerPattern->Init();
132 return containerModalNode;
133 }
134
BuildTitle(RefPtr<FrameNode> & containerNode,bool isFloatingTitle)135 RefPtr<FrameNode> ContainerModalViewEnhance::BuildTitle(RefPtr<FrameNode>& containerNode, bool isFloatingTitle)
136 {
137 LOGI("ContainerModalViewEnhance BuildTitle called");
138 auto titleRow = BuildTitleContainer(containerNode, isFloatingTitle);
139 CHECK_NULL_RETURN(titleRow, nullptr);
140 SetTapGestureEvent(containerNode, titleRow);
141 return titleRow;
142 }
143
SetTapGestureEvent(RefPtr<FrameNode> & containerNode,RefPtr<FrameNode> & containerTitleRow)144 void ContainerModalViewEnhance::SetTapGestureEvent(
145 RefPtr<FrameNode>& containerNode, RefPtr<FrameNode>& containerTitleRow)
146 {
147 auto pipeline = PipelineContext::GetCurrentContext();
148 CHECK_NULL_VOID(pipeline);
149 auto windowManager = pipeline->GetWindowManager();
150 CHECK_NULL_VOID(windowManager);
151 auto eventHub = containerTitleRow->GetOrCreateGestureEventHub();
152 CHECK_NULL_VOID(eventHub);
153 auto tapGesture = AceType::MakeRefPtr<NG::TapGesture>(2, 1);
154 CHECK_NULL_VOID(tapGesture);
155 tapGesture->SetOnActionId([weakContainerNode = AceType::WeakClaim(AceType::RawPtr(containerNode)),
156 weakWindowManager = AceType::WeakClaim(AceType::RawPtr(windowManager))](
157 GestureEvent& info) {
158 LOGI("container window double click.");
159 auto windowManager = weakWindowManager.Upgrade();
160 CHECK_NULL_VOID(windowManager);
161 auto containerNode = weakContainerNode.Upgrade();
162 CHECK_NULL_VOID(containerNode);
163 bool isMoving = windowManager->WindowIsStartMoving();
164 if (isMoving) {
165 LOGI("window is moving, double-click is not supported.");
166 return;
167 }
168 auto windowMode = windowManager->GetWindowMode();
169 auto maximizeMode = windowManager->GetCurrentWindowMaximizeMode();
170 if (maximizeMode == MaximizeMode::MODE_AVOID_SYSTEM_BAR || windowMode == WindowMode::WINDOW_MODE_FULLSCREEN ||
171 windowMode == WindowMode::WINDOW_MODE_SPLIT_PRIMARY ||
172 windowMode == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) {
173 EventReport::ReportDoubleClickTitle(DOUBLE_CLICK_TO_RECOVER);
174 windowManager->WindowRecover();
175 } else if (windowMode == WindowMode::WINDOW_MODE_FLOATING) {
176 EventReport::ReportDoubleClickTitle(DOUBLE_CLICK_TO_MAXIMIZE);
177 windowManager->WindowMaximize(true);
178 }
179 containerNode->OnWindowFocused();
180 });
181 eventHub->AddGesture(tapGesture);
182 eventHub->OnModifyDone();
183 }
184
AddControlButtons(RefPtr<FrameNode> & containerNode,RefPtr<FrameNode> & containerTitleRow)185 RefPtr<FrameNode> ContainerModalViewEnhance::AddControlButtons(
186 RefPtr<FrameNode>& containerNode, RefPtr<FrameNode>& containerTitleRow)
187 {
188 auto pipeline = PipelineContext::GetCurrentContext();
189 CHECK_NULL_RETURN(pipeline, nullptr);
190 auto windowManager = pipeline->GetWindowManager();
191 CHECK_NULL_RETURN(windowManager, nullptr);
192
193 RefPtr<FrameNode> maximizeBtn = BuildControlButton(InternalResource::ResourceId::IC_WINDOW_MAX,
194 [weak = AceType::WeakClaim(AceType::RawPtr(containerNode)),
195 wk = AceType::WeakClaim(AceType::RawPtr(windowManager))](GestureEvent& info) {
196 auto containerNode = weak.Upgrade();
197 CHECK_NULL_VOID(containerNode);
198 auto windowManager = wk.Upgrade();
199 CHECK_NULL_VOID(windowManager);
200 ResetHoverTimer();
201 bool isMoving = windowManager->WindowIsStartMoving();
202 if (isMoving) {
203 LOGI("window is moving, maximization is not supported.");
204 return;
205 }
206 auto mode = windowManager->GetWindowMode();
207 auto currentMode = windowManager->GetCurrentWindowMaximizeMode();
208 if (mode == WindowMode::WINDOW_MODE_FULLSCREEN || currentMode == MaximizeMode::MODE_AVOID_SYSTEM_BAR ||
209 mode == WindowMode::WINDOW_MODE_SPLIT_PRIMARY || mode == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) {
210 EventReport::ReportClickTitleMaximizeMenu(MAX_MENU_ITEM_MAXIMIZE, MAX_BUTTON_CLICK_TO_RECOVER);
211 windowManager->WindowRecover();
212 } else {
213 EventReport::ReportClickTitleMaximizeMenu(MAX_MENU_ITEM_MAXIMIZE, MAX_BUTTON_CLICK_TO_MAXIMIZE);
214 windowManager->WindowMaximize(true);
215 }
216 containerNode->OnWindowFocused();
217 });
218 maximizeBtn->UpdateInspectorId("EnhanceMaximizeBtn");
219 BondingMaxBtnGestureEvent(maximizeBtn, containerNode);
220 BondingMaxBtnInputEvent(maximizeBtn, containerNode);
221 containerTitleRow->AddChild(maximizeBtn);
222
223 RefPtr<FrameNode> minimizeBtn = BuildControlButton(InternalResource::ResourceId::IC_WINDOW_MIN,
224 [weak = AceType::WeakClaim(AceType::RawPtr(windowManager))](GestureEvent& info) {
225 auto windowManager = weak.Upgrade();
226 if (!windowManager) {
227 LOGE("create minBtn callback func failed,windowManager is null!");
228 return;
229 }
230 bool isMoving = windowManager->WindowIsStartMoving();
231 if (isMoving) {
232 LOGI("window is moving, minimization is not supported.");
233 return;
234 }
235 LOGI("minimize button clicked");
236 windowManager->WindowMinimize();
237 });
238 // minimizeBtn add empty panEvent to over fater container event
239 minimizeBtn->UpdateInspectorId("EnhanceMinimizeBtn");
240 containerTitleRow->AddChild(minimizeBtn);
241
242 RefPtr<FrameNode> closeBtn = BuildControlButton(
243 InternalResource::ResourceId::IC_WINDOW_CLOSE,
244 [weak = AceType::WeakClaim(AceType::RawPtr(windowManager))](GestureEvent& info) {
245 auto windowManager = weak.Upgrade();
246 if (!windowManager) {
247 LOGE("create closeBtn callback func failed,windowManager is null!");
248 return;
249 }
250 bool isMoving = windowManager->WindowIsStartMoving();
251 if (isMoving) {
252 LOGI("window is moving, close is not supported.");
253 return;
254 }
255 LOGI("close button clicked");
256 windowManager->WindowClose();
257 },
258 true);
259 // closeBtn add empty panEvent to over fater container event
260 closeBtn->UpdateInspectorId("EnhanceCloseBtn");
261 containerTitleRow->AddChild(closeBtn);
262
263 return containerTitleRow;
264 }
265
BondingMaxBtnGestureEvent(RefPtr<FrameNode> & maximizeBtn,RefPtr<FrameNode> & containerNode)266 void ContainerModalViewEnhance::BondingMaxBtnGestureEvent(
267 RefPtr<FrameNode>& maximizeBtn, RefPtr<FrameNode>& containerNode)
268 {
269 auto pipeline = PipelineContext::GetCurrentContext();
270 auto windowManager = pipeline->GetWindowManager();
271 auto hub = maximizeBtn->GetOrCreateGestureEventHub();
272
273 // add long press event
274 auto longPressCallback = [weakMaximizeBtn = AceType::WeakClaim(AceType::RawPtr(maximizeBtn))](GestureEvent& info) {
275 auto maximizeBtn = weakMaximizeBtn.Upgrade();
276 CHECK_NULL_VOID(maximizeBtn);
277 auto menuPosX = info.GetScreenLocation().GetX() - info.GetLocalLocation().GetX() - MENU_FLOAT_X.ConvertToPx();
278 auto menuPosY = info.GetScreenLocation().GetY() - info.GetLocalLocation().GetY() + MENU_FLOAT_Y.ConvertToPx();
279 OffsetF menuPosition { menuPosX, menuPosY };
280 CalculateMenuOffset(menuPosition);
281 ShowMaxMenu(maximizeBtn, menuOffset_);
282 };
283 // diable mouse left!
284 auto longPressEvent = AceType::MakeRefPtr<LongPressEvent>(longPressCallback);
285 hub->SetLongPressEvent(longPressEvent, false, true);
286 }
287
BondingMaxBtnInputEvent(RefPtr<FrameNode> & maximizeBtn,RefPtr<FrameNode> & containerNode)288 void ContainerModalViewEnhance::BondingMaxBtnInputEvent(
289 RefPtr<FrameNode>& maximizeBtn, RefPtr<FrameNode>& containerNode)
290 {
291 auto pipeline = PipelineContext::GetCurrentContext();
292 auto windowManager = pipeline->GetWindowManager();
293 auto hub = maximizeBtn->GetOrCreateInputEventHub();
294 auto hoverMoveFuc = [](MouseInfo& info) {
295 sIsForbidMenuEvent_ = info.GetButton() == MouseButton::LEFT_BUTTON || info.GetScreenLocation().IsZero();
296 if (!sIsMenuPending_ && info.GetAction() == MouseAction::MOVE && !info.GetScreenLocation().IsZero()) {
297 auto menuPosX =
298 info.GetScreenLocation().GetX() - info.GetLocalLocation().GetX() - MENU_FLOAT_X.ConvertToPx();
299 auto menuPosY =
300 info.GetScreenLocation().GetY() - info.GetLocalLocation().GetY() + MENU_FLOAT_Y.ConvertToPx();
301 OffsetF menuPosition { menuPosX, menuPosY };
302 LOGI("ContainerModal menuPosition = %{public}s", menuPosition.ToString().c_str());
303 CalculateMenuOffset(menuPosition);
304 }
305 };
306 hub->AddOnMouseEvent(AceType::MakeRefPtr<InputEvent>(std::move(hoverMoveFuc)));
307
308 // add hover in out event
309 auto containerPattern = containerNode->GetPattern<ContainerModalPattern>();
310 auto hoverEventFuc = [weakMaximizeBtn = AceType::WeakClaim(AceType::RawPtr(maximizeBtn)),
311 weakContainerPattern = AceType::WeakClaim(AceType::RawPtr(containerPattern)),
312 weakPipeline = AceType::WeakClaim(AceType::RawPtr(pipeline))](bool hover) {
313 auto pattern = weakContainerPattern.Upgrade();
314 CHECK_NULL_VOID(pattern);
315 if (!hover) {
316 ResetHoverTimer();
317 return;
318 }
319 if (sIsMenuPending_ || sIsForbidMenuEvent_ || !pattern->GetIsFocus()) {
320 return;
321 }
322 auto maximizeBtn = weakMaximizeBtn.Upgrade();
323 CHECK_NULL_VOID(maximizeBtn);
324 auto pipeline = weakPipeline.Upgrade();
325 CHECK_NULL_VOID(pipeline);
326 auto&& callback = [weakMaximizeBtn = AceType::WeakClaim(AceType::RawPtr(maximizeBtn))]() {
327 auto maximizeBtn = weakMaximizeBtn.Upgrade();
328 ShowMaxMenu(maximizeBtn, menuOffset_);
329 };
330 sContextTimer_.Reset(callback);
331 ACE_SCOPED_TRACE("ContainerModalEnhance::PendingMaxMenu");
332 pipeline->GetTaskExecutor()->PostDelayedTask(sContextTimer_, TaskExecutor::TaskType::UI, MENU_TASK_DELAY_TIME,
333 "ArkUIContainerModalShowMaxMenu");
334 sIsMenuPending_ = true;
335 };
336 hub->AddOnHoverEvent(AceType::MakeRefPtr<InputEvent>(std::move(hoverEventFuc)));
337 }
338
ShowMaxMenu(const RefPtr<FrameNode> & targetNode,OffsetF menuPosition)339 RefPtr<FrameNode> ContainerModalViewEnhance::ShowMaxMenu(const RefPtr<FrameNode>& targetNode, OffsetF menuPosition)
340 {
341 LOGI("ContainerModal ShowMaxMenu called menuOffset_ = %{public}s", menuPosition.ToString().c_str());
342 if (!enableSplit_) {
343 LOGI("the app window is not support spilt menu");
344 return nullptr;
345 }
346 auto pipeline = PipelineContext::GetCurrentContext();
347 CHECK_NULL_RETURN(pipeline, nullptr);
348 auto windowManager = pipeline->GetWindowManager();
349 CHECK_NULL_RETURN(windowManager, nullptr);
350 // menu list
351 auto menuList = FrameNode::CreateFrameNode(
352 V2::LIST_COMPONENT_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ListPattern>());
353 auto listLayoutProperty = menuList->GetLayoutProperty<ListLayoutProperty>();
354 CHECK_NULL_RETURN(listLayoutProperty, nullptr);
355 listLayoutProperty->UpdateUserDefinedIdealSize(
356 CalcSize(CalcLength(MENU_CONTAINER_WIDTH), CalcLength(MENU_CONTAINER_HEIGHT)));
357 menuList->AddChild(BuildLeftSplitMenuItem());
358 menuList->AddChild(BuildRightSplitMenuItem());
359 auto subWindowManger = SubwindowManager::GetInstance();
360 CHECK_NULL_RETURN(subWindowManger, nullptr);
361 if ((!subWindowManger->GetSubwindow(Container::CurrentId()) ||
362 !subWindowManger->GetSubwindow(Container::CurrentId())->GetShown())) {
363 ACE_SCOPED_TRACE("ContainerModalViewEnhance::ShowMaxMenu");
364 MenuParam menuParam {};
365 menuParam.type = MenuType::CONTEXT_MENU;
366 SubwindowManager::GetInstance()->ShowMenuNG(menuList, menuParam, targetNode, menuPosition);
367 }
368 ResetHoverTimer();
369 return menuList;
370 }
371
BuildLeftSplitMenuItem()372 RefPtr<FrameNode> ContainerModalViewEnhance::BuildLeftSplitMenuItem()
373 {
374 auto pipeline = PipelineContext::GetCurrentContext();
375 CHECK_NULL_RETURN(pipeline, nullptr);
376 auto windowManager = pipeline->GetWindowManager();
377 CHECK_NULL_RETURN(windowManager, nullptr);
378 auto leftSplitClickFunc = [weak = AceType::WeakClaim(AceType::RawPtr(windowManager))](GestureEvent& info) {
379 auto windowManager = weak.Upgrade();
380 if (!windowManager) {
381 LOGE("create leftsplit callback func failed,windowMannager is null!");
382 return;
383 }
384 EventReport::ReportClickTitleMaximizeMenu(MAX_MENU_ITEM_LEFT_SPLIT, MAX_MENU_DEFAULT_NOT_CHANGE);
385 windowManager->FireWindowSplitCallBack();
386 };
387 auto leftSplitEvent = AceType::MakeRefPtr<ClickEvent>(std::move(leftSplitClickFunc));
388 auto screenLeftRow = BuildMenuItem(Localization::GetInstance()->GetEntryLetters("window.leftSide"),
389 InternalResource::ResourceId::IC_WINDOW_MENU_SCREEN_L, leftSplitEvent, false);
390 screenLeftRow->UpdateInspectorId("EnhanceMenuScreenLeftRow");
391 return screenLeftRow;
392 }
393
BuildRightSplitMenuItem()394 RefPtr<FrameNode> ContainerModalViewEnhance::BuildRightSplitMenuItem()
395 {
396 auto pipeline = PipelineContext::GetCurrentContext();
397 CHECK_NULL_RETURN(pipeline, nullptr);
398 auto windowManager = pipeline->GetWindowManager();
399 CHECK_NULL_RETURN(windowManager, nullptr);
400 auto rightSplitClickFunc = [weak = AceType::WeakClaim(AceType::RawPtr(windowManager))](GestureEvent& info) {
401 auto windowManager = weak.Upgrade();
402 if (!windowManager) {
403 LOGE("create rightSpiltBtn callback func failed, windowManager is null!");
404 return;
405 }
406 EventReport::ReportClickTitleMaximizeMenu(MAX_MENU_ITEM_RIGHT_SPLIT, MAX_MENU_DEFAULT_NOT_CHANGE);
407 windowManager->FireWindowSplitCallBack(false);
408 };
409 auto rightSplitEvent = AceType::MakeRefPtr<ClickEvent>(std::move(rightSplitClickFunc));
410 auto screenRightRow = BuildMenuItem(Localization::GetInstance()->GetEntryLetters("window.rightSide"),
411 InternalResource::ResourceId::IC_WINDOW_MENU_SCREEN_N, rightSplitEvent, false);
412 screenRightRow->UpdateInspectorId("EnhanceMenuScreenRightRow");
413 return screenRightRow;
414 }
415
BuildMenuItem(std::string title,InternalResource::ResourceId resourceId,RefPtr<ClickEvent> event,bool chooseCurrent)416 RefPtr<FrameNode> ContainerModalViewEnhance::BuildMenuItem(
417 std::string title, InternalResource::ResourceId resourceId, RefPtr<ClickEvent> event, bool chooseCurrent)
418 {
419 auto pipeline = PipelineContext::GetCurrentContext();
420 CHECK_NULL_RETURN(pipeline, nullptr);
421 auto windowManager = pipeline->GetWindowManager();
422 CHECK_NULL_RETURN(windowManager, nullptr);
423
424 // padding+pic+padding+text+padding+
425 auto containerTitleRow = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
426 AceType::MakeRefPtr<LinearLayoutPattern>(false));
427 // setRadius 8vp
428 auto render = containerTitleRow->GetRenderContext();
429 BorderRadiusProperty borderRadiusProperty;
430 borderRadiusProperty.SetRadius(MENU_ITEM_RADIUS);
431 render->UpdateBorderRadius(borderRadiusProperty);
432 // 232 48 leftPadding 4vp
433 auto layoutProperty = containerTitleRow->GetLayoutProperty<LinearLayoutProperty>();
434 layoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(MENU_ITEM_WIDTH), CalcLength(MENU_ITEM_HEIGHT)));
435 layoutProperty->UpdateMainAxisAlign(FlexAlign::FLEX_START);
436 layoutProperty->UpdateCrossAxisAlign(FlexAlign::CENTER);
437 PaddingProperty rowLeftPadding;
438 rowLeftPadding.left = CalcLength(MENU_ITEM_LEFT_PADDING);
439 layoutProperty->UpdatePadding(rowLeftPadding);
440
441 auto leftIcon = BuildMenuItemIcon(resourceId);
442 // text 144 22 padding 8vp
443 auto titleLabel = FrameNode::CreateFrameNode(
444 V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
445 auto textLayoutProperty = titleLabel->GetLayoutProperty<TextLayoutProperty>();
446 textLayoutProperty->UpdateContent(title);
447 textLayoutProperty->UpdateMaxLines(MENU_ITEM_MAXLINES);
448 textLayoutProperty->UpdateFontSize(TITLE_TEXT_FONT_SIZE);
449 textLayoutProperty->UpdateTextOverflow(TextOverflow::ELLIPSIS);
450 textLayoutProperty->UpdateAlignment(Alignment::CENTER_LEFT);
451 textLayoutProperty->UpdateUserDefinedIdealSize(
452 CalcSize(CalcLength(MENU_ITEM_TEXT_WIDTH), CalcLength(MENU_ITEM_TEXT_HEIGHT)));
453 PaddingProperty padding;
454 padding.left = CalcLength(MENU_ITEM_TEXT_PADDING);
455 auto text = BuildMenuItemPadding(padding, titleLabel);
456
457 // add icon and label
458 containerTitleRow->AddChild(leftIcon);
459 containerTitleRow->AddChild(text);
460 auto hub = containerTitleRow->GetOrCreateGestureEventHub();
461 CHECK_NULL_RETURN(hub, nullptr);
462 hub->AddClickEvent(event);
463 BondingMenuItemEvent(containerTitleRow);
464 return containerTitleRow;
465 }
466
BondingMenuItemEvent(RefPtr<FrameNode> item)467 void ContainerModalViewEnhance::BondingMenuItemEvent(RefPtr<FrameNode> item)
468 {
469 auto inputHub = item->GetOrCreateInputEventHub();
470 auto theme = PipelineContext::GetCurrentContext()->GetTheme<ListItemTheme>();
471 CHECK_NULL_VOID(theme);
472 auto hoverFunc = [item, weak = AceType::WeakClaim(AceType::RawPtr(theme))](bool isHover) {
473 auto theme = weak.Upgrade();
474 auto renderContext = item->GetRenderContext();
475 if (isHover && theme) {
476 renderContext->UpdateBackgroundColor(theme->GetItemHoverColor());
477 } else {
478 renderContext->UpdateBackgroundColor(MENU_ITEM_COLOR);
479 }
480 };
481 auto hoverEvent = AceType::MakeRefPtr<InputEvent>(std::move(hoverFunc));
482 inputHub->AddOnHoverEvent(hoverEvent);
483
484 auto clickFunc = [item, weak = AceType::WeakClaim(AceType::RawPtr(theme))](MouseInfo& info) -> void {
485 auto theme = weak.Upgrade();
486 if (MouseAction::PRESS == info.GetAction() && theme) {
487 auto renderContext = item->GetRenderContext();
488 renderContext->UpdateBackgroundColor(theme->GetClickColor());
489 }
490 };
491 auto clickEvent = AceType::MakeRefPtr<InputEvent>(std::move(clickFunc));
492 inputHub->AddOnMouseEvent(clickEvent);
493 }
494
BuildMenuItemIcon(InternalResource::ResourceId resourceId)495 RefPtr<FrameNode> ContainerModalViewEnhance::BuildMenuItemIcon(InternalResource::ResourceId resourceId)
496 {
497 auto icon = FrameNode::CreateFrameNode(
498 V2::IMAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ImagePattern>());
499 auto iconLayoutProperty = icon->GetLayoutProperty<ImageLayoutProperty>();
500 ImageSourceInfo sourceInfo;
501 sourceInfo.SetResourceId(resourceId);
502 auto theme = PipelineContext::GetCurrentContext()->GetTheme<AdvancedPatternTheme>();
503 if (theme) {
504 sourceInfo.SetFillColor(theme->GetPrimaryColor());
505 } else {
506 LOGI("BuildMenuItemIcon AdvancedPatternTheme is null");
507 }
508 iconLayoutProperty->UpdateImageSourceInfo(sourceInfo);
509 iconLayoutProperty->UpdateUserDefinedIdealSize(
510 CalcSize(CalcLength(TITLE_BUTTON_SIZE), CalcLength(TITLE_BUTTON_SIZE)));
511 icon->MarkModifyDone();
512 return icon;
513 }
514
BuildMenuItemPadding(PaddingProperty padding,RefPtr<FrameNode> node)515 RefPtr<FrameNode> ContainerModalViewEnhance::BuildMenuItemPadding(PaddingProperty padding, RefPtr<FrameNode> node)
516 {
517 auto row = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
518 AceType::MakeRefPtr<LinearLayoutPattern>(false));
519
520 auto rowLayoutProperty = row->GetLayoutProperty<LinearLayoutProperty>();
521 rowLayoutProperty->UpdatePadding(padding);
522 row->AddChild(node);
523
524 return row;
525 }
526
ResetHoverTimer()527 void ContainerModalViewEnhance::ResetHoverTimer()
528 {
529 sContextTimer_.Reset(nullptr);
530 sIsMenuPending_ = false;
531 }
532
CalculateMenuOffset(OffsetF currentOffset)533 void ContainerModalViewEnhance::CalculateMenuOffset(OffsetF currentOffset)
534 {
535 auto screenWidth = SystemProperties::GetDevicePhysicalWidth();
536 auto screenHeight = SystemProperties::GetDevicePhysicalHeight();
537 auto offsetX = currentOffset.GetX();
538 auto offsetY = currentOffset.GetY();
539 auto menuWidth = MENU_CONTAINER_WIDTH.ConvertToPx() + CONTENT_PADDING.ConvertToPx() * 2;
540 auto menuHeight = MENU_CONTAINER_HEIGHT.ConvertToPx() + CONTENT_PADDING.ConvertToPx() * 2;
541 auto buttonWidth = TITLE_ICON_SIZE.ConvertToPx() + CONTENT_PADDING.ConvertToPx() * 2;
542 auto pipeline = PipelineContext::GetCurrentContext();
543 CHECK_NULL_VOID(pipeline);
544 auto titleHeight = pipeline->GetCustomTitleHeight().ConvertToPx();
545 if (offsetX < MENU_SAFETY_X.ConvertToPx()) {
546 LOGI("ContainerModalViewEnhance::RecalculateMenuOffset OffsetX cover screen left");
547 offsetX = offsetX + menuWidth - buttonWidth;
548 }
549 if (offsetX > screenWidth - menuWidth - MENU_SAFETY_X.ConvertToPx()) {
550 LOGI("ContainerModalViewEnhance::RecalculateMenuOffset OffsetX cover screen right");
551 offsetX = screenWidth - menuWidth - MENU_SAFETY_X.ConvertToPx();
552 }
553 if (offsetY > screenHeight - menuHeight - MENU_SAFETY_Y.ConvertToPx()) {
554 LOGI("ContainerModalViewEnhance::RecalculateMenuOffset OffsetX cover screen bottom");
555 offsetY = offsetY - menuHeight - titleHeight;
556 }
557 menuOffset_ = { offsetX, offsetY };
558 LOGI("ContainerModal menuOffset_ = %{public}s", menuOffset_.ToString().c_str());
559 }
560
BuildGestureRow(RefPtr<FrameNode> & containerNode)561 RefPtr<FrameNode> ContainerModalViewEnhance::BuildGestureRow(RefPtr<FrameNode>& containerNode)
562 {
563 auto gestureRow = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
564 AceType::MakeRefPtr<LinearLayoutPattern>(false));
565 auto renderContext = gestureRow->GetRenderContext();
566 renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
567 renderContext->UpdatePosition(OffsetT<Dimension>());
568 SetTapGestureEvent(containerNode, gestureRow);
569 auto layoutProp = gestureRow->GetLayoutProperty();
570 layoutProp->UpdateUserDefinedIdealSize(
571 CalcSize(CalcLength(1.0, DimensionUnit::PERCENT), CalcLength(CONTAINER_TITLE_HEIGHT)));
572 return gestureRow;
573 }
574
575 } // namespace OHOS::Ace::NG
576