1 /*
2 * Copyright (c) 2022-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/menu/menu_layout_algorithm.h"
17
18 #include <optional>
19 #include <vector>
20
21 #include "base/geometry/dimension.h"
22 #include "base/geometry/ng/offset_t.h"
23 #include "base/geometry/ng/size_t.h"
24 #include "base/geometry/size.h"
25 #include "base/memory/ace_type.h"
26 #include "base/memory/referenced.h"
27 #include "base/subwindow/subwindow_manager.h"
28 #include "base/utils/utils.h"
29 #include "core/common/ace_engine.h"
30 #include "core/components/common/layout/grid_system_manager.h"
31 #include "core/components/common/properties/placement.h"
32 #include "core/components/container_modal/container_modal_constants.h"
33 #include "core/components_ng/pattern/linear_layout/linear_layout_property.h"
34 #include "core/components_ng/pattern/menu/menu_layout_property.h"
35 #include "core/components_ng/pattern/menu/menu_pattern.h"
36 #include "core/components_ng/pattern/menu/menu_theme.h"
37 #include "core/components_ng/pattern/menu/preview/menu_preview_pattern.h"
38 #include "core/components_ng/pattern/menu/wrapper/menu_wrapper_pattern.h"
39 #include "core/components_ng/pattern/scroll/scroll_layout_property.h"
40 #include "core/components_ng/property/layout_constraint.h"
41 #include "core/components_ng/property/measure_property.h"
42 #include "core/pipeline/pipeline_base.h"
43 #include "core/pipeline_ng/pipeline_context.h"
44 namespace OHOS::Ace::NG {
45
46 namespace {
47 constexpr uint32_t MIN_GRID_COUNTS = 2;
48 constexpr uint32_t GRID_COUNTS_4 = 4;
49 constexpr uint32_t GRID_COUNTS_6 = 6;
50 constexpr uint32_t GRID_COUNTS_8 = 8;
51 constexpr uint32_t GRID_COUNTS_12 = 12;
52 constexpr size_t ALIGNMENT_STEP_OFFSET = 2;
53 constexpr float HEIGHT_CONSTRAINT_FACTOR = 0.8;
54
55 const std::map<Placement, std::vector<Placement>> PLACEMENT_STATES = {
56 { Placement::BOTTOM_LEFT,
57 {
58 Placement::BOTTOM_LEFT,
59 Placement::BOTTOM_RIGHT,
60 Placement::TOP_LEFT,
61 Placement::TOP_RIGHT,
62 Placement::RIGHT_TOP,
63 Placement::RIGHT_BOTTOM,
64 Placement::LEFT_TOP,
65 Placement::LEFT_BOTTOM,
66 Placement::NONE,
67 } },
68 { Placement::BOTTOM,
69 {
70 Placement::BOTTOM,
71 Placement::BOTTOM_LEFT,
72 Placement::BOTTOM_RIGHT,
73 Placement::TOP,
74 Placement::TOP_LEFT,
75 Placement::TOP_RIGHT,
76 Placement::RIGHT,
77 Placement::RIGHT_TOP,
78 Placement::RIGHT_BOTTOM,
79 Placement::LEFT,
80 Placement::LEFT_TOP,
81 Placement::LEFT_BOTTOM,
82 Placement::NONE,
83 } },
84 { Placement::BOTTOM_RIGHT,
85 {
86 Placement::BOTTOM_RIGHT,
87 Placement::BOTTOM_LEFT,
88 Placement::TOP_RIGHT,
89 Placement::TOP_LEFT,
90 Placement::RIGHT_BOTTOM,
91 Placement::RIGHT_TOP,
92 Placement::LEFT_BOTTOM,
93 Placement::LEFT_TOP,
94 Placement::NONE,
95 } },
96 { Placement::TOP_LEFT,
97 {
98 Placement::TOP_LEFT,
99 Placement::TOP_RIGHT,
100 Placement::BOTTOM_LEFT,
101 Placement::BOTTOM_RIGHT,
102 Placement::RIGHT_TOP,
103 Placement::RIGHT_BOTTOM,
104 Placement::LEFT_TOP,
105 Placement::LEFT_BOTTOM,
106 Placement::NONE,
107 } },
108 { Placement::TOP,
109 {
110 Placement::TOP,
111 Placement::TOP_LEFT,
112 Placement::TOP_RIGHT,
113 Placement::BOTTOM,
114 Placement::BOTTOM_LEFT,
115 Placement::BOTTOM_RIGHT,
116 Placement::RIGHT,
117 Placement::RIGHT_TOP,
118 Placement::RIGHT_BOTTOM,
119 Placement::LEFT,
120 Placement::LEFT_TOP,
121 Placement::LEFT_BOTTOM,
122 Placement::NONE,
123 } },
124 { Placement::TOP_RIGHT,
125 {
126 Placement::TOP_RIGHT,
127 Placement::TOP_LEFT,
128 Placement::BOTTOM_RIGHT,
129 Placement::BOTTOM_LEFT,
130 Placement::RIGHT_BOTTOM,
131 Placement::RIGHT_TOP,
132 Placement::LEFT_BOTTOM,
133 Placement::LEFT_TOP,
134 Placement::NONE,
135 } },
136 { Placement::LEFT_TOP,
137 {
138 Placement::LEFT_TOP,
139 Placement::LEFT_BOTTOM,
140 Placement::RIGHT_TOP,
141 Placement::RIGHT_BOTTOM,
142 Placement::BOTTOM_LEFT,
143 Placement::BOTTOM_RIGHT,
144 Placement::TOP_LEFT,
145 Placement::TOP_RIGHT,
146 Placement::NONE,
147 } },
148 { Placement::LEFT,
149 {
150 Placement::LEFT,
151 Placement::LEFT_TOP,
152 Placement::LEFT_BOTTOM,
153 Placement::RIGHT,
154 Placement::RIGHT_TOP,
155 Placement::RIGHT_BOTTOM,
156 Placement::BOTTOM,
157 Placement::BOTTOM_LEFT,
158 Placement::BOTTOM_RIGHT,
159 Placement::TOP,
160 Placement::TOP_LEFT,
161 Placement::TOP_RIGHT,
162 Placement::NONE,
163 } },
164 { Placement::LEFT_BOTTOM,
165 {
166 Placement::LEFT_BOTTOM,
167 Placement::LEFT_TOP,
168 Placement::RIGHT_BOTTOM,
169 Placement::RIGHT_TOP,
170 Placement::BOTTOM_RIGHT,
171 Placement::BOTTOM_LEFT,
172 Placement::TOP_RIGHT,
173 Placement::TOP_LEFT,
174 Placement::NONE,
175 } },
176 { Placement::RIGHT_TOP,
177 {
178 Placement::RIGHT_TOP,
179 Placement::RIGHT_BOTTOM,
180 Placement::LEFT_TOP,
181 Placement::LEFT_BOTTOM,
182 Placement::BOTTOM_LEFT,
183 Placement::BOTTOM_RIGHT,
184 Placement::TOP_LEFT,
185 Placement::TOP_RIGHT,
186 Placement::NONE,
187 } },
188 { Placement::RIGHT,
189 {
190 Placement::RIGHT,
191 Placement::RIGHT_TOP,
192 Placement::RIGHT_BOTTOM,
193 Placement::LEFT,
194 Placement::LEFT_TOP,
195 Placement::LEFT_BOTTOM,
196 Placement::BOTTOM,
197 Placement::BOTTOM_LEFT,
198 Placement::BOTTOM_RIGHT,
199 Placement::TOP,
200 Placement::TOP_LEFT,
201 Placement::TOP_RIGHT,
202 Placement::NONE,
203 } },
204 { Placement::RIGHT_BOTTOM,
205 {
206 Placement::RIGHT_BOTTOM,
207 Placement::RIGHT_TOP,
208 Placement::LEFT_BOTTOM,
209 Placement::LEFT_TOP,
210 Placement::BOTTOM_RIGHT,
211 Placement::BOTTOM_LEFT,
212 Placement::TOP_RIGHT,
213 Placement::TOP_LEFT,
214 Placement::NONE,
215 } },
216 };
217
GetMaxGridCounts(const RefPtr<GridColumnInfo> & columnInfo)218 uint32_t GetMaxGridCounts(const RefPtr<GridColumnInfo>& columnInfo)
219 {
220 CHECK_NULL_RETURN(columnInfo, GRID_COUNTS_8);
221 auto currentColumns = columnInfo->GetParent()->GetColumns();
222 auto maxGridCounts = GRID_COUNTS_8;
223 switch (currentColumns) {
224 case GRID_COUNTS_4:
225 maxGridCounts = GRID_COUNTS_4;
226 break;
227 case GRID_COUNTS_8:
228 maxGridCounts = GRID_COUNTS_6;
229 break;
230 case GRID_COUNTS_12:
231 maxGridCounts = GRID_COUNTS_8;
232 break;
233 case MIN_GRID_COUNTS:
234 maxGridCounts = MIN_GRID_COUNTS;
235 break;
236 default:
237 break;
238 }
239 return maxGridCounts;
240 }
241 } // namespace
242
MenuLayoutAlgorithm(int32_t id,const std::string & tag)243 MenuLayoutAlgorithm::MenuLayoutAlgorithm(int32_t id, const std::string& tag) : targetNodeId_(id), targetTag_(tag)
244 {
245 placementFuncMap_[Placement::TOP] = &MenuLayoutAlgorithm::GetPositionWithPlacementTop;
246 placementFuncMap_[Placement::TOP_LEFT] = &MenuLayoutAlgorithm::GetPositionWithPlacementTopLeft;
247 placementFuncMap_[Placement::TOP_RIGHT] = &MenuLayoutAlgorithm::GetPositionWithPlacementTopRight;
248 placementFuncMap_[Placement::BOTTOM] = &MenuLayoutAlgorithm::GetPositionWithPlacementBottom;
249 placementFuncMap_[Placement::BOTTOM_LEFT] = &MenuLayoutAlgorithm::GetPositionWithPlacementBottomLeft;
250 placementFuncMap_[Placement::BOTTOM_RIGHT] = &MenuLayoutAlgorithm::GetPositionWithPlacementBottomRight;
251 placementFuncMap_[Placement::LEFT] = &MenuLayoutAlgorithm::GetPositionWithPlacementLeft;
252 placementFuncMap_[Placement::LEFT_TOP] = &MenuLayoutAlgorithm::GetPositionWithPlacementLeftTop;
253 placementFuncMap_[Placement::LEFT_BOTTOM] = &MenuLayoutAlgorithm::GetPositionWithPlacementLeftBottom;
254 placementFuncMap_[Placement::RIGHT] = &MenuLayoutAlgorithm::GetPositionWithPlacementRight;
255 placementFuncMap_[Placement::RIGHT_TOP] = &MenuLayoutAlgorithm::GetPositionWithPlacementRightTop;
256 placementFuncMap_[Placement::RIGHT_BOTTOM] = &MenuLayoutAlgorithm::GetPositionWithPlacementRightBottom;
257
258 setHorizontal_ = { Placement::LEFT, Placement::LEFT_BOTTOM, Placement::LEFT_TOP,
259 Placement::RIGHT, Placement::RIGHT_BOTTOM, Placement::RIGHT_TOP };
260 setVertical_ = { Placement::TOP, Placement::TOP_LEFT, Placement::TOP_RIGHT,
261 Placement::BOTTOM, Placement::BOTTOM_LEFT, Placement::BOTTOM_RIGHT };
262
263 auto pipeline = PipelineBase::GetCurrentContext();
264 CHECK_NULL_VOID(pipeline);
265 auto menuTheme = pipeline->GetTheme<NG::MenuTheme>();
266 CHECK_NULL_VOID(menuTheme);
267 previewScale_ = menuTheme->GetPreviewAfterAnimationScale();
268 if (LessOrEqual(previewScale_, 0.0f)) {
269 previewScale_ = 1.0f;
270 }
271 }
272
~MenuLayoutAlgorithm()273 MenuLayoutAlgorithm::~MenuLayoutAlgorithm()
274 {
275 placementFuncMap_.clear();
276 setHorizontal_.clear();
277 setVertical_.clear();
278 }
279
ModifyNormalPreviewMenuPortraitPlacement(LayoutWrapper * layoutWrapper)280 void MenuLayoutAlgorithm::ModifyNormalPreviewMenuPortraitPlacement(LayoutWrapper* layoutWrapper)
281 {
282 CHECK_NULL_VOID(layoutWrapper);
283 auto props = AceType::DynamicCast<MenuLayoutProperty>(layoutWrapper->GetLayoutProperty());
284 CHECK_NULL_VOID(props);
285
286 auto hasPlacement = props->GetMenuPlacement().has_value();
287 if (placement_ == Placement::TOP_LEFT || placement_ == Placement::TOP || placement_ == Placement::TOP_RIGHT) {
288 if (!hasPlacement) {
289 placement_ = Placement::TOP_LEFT;
290 props->UpdateMenuPlacement(placement_);
291 }
292 } else if (!hasPlacement) {
293 placement_ = Placement::BOTTOM_LEFT;
294 props->UpdateMenuPlacement(placement_);
295 }
296 }
297
ModifyNormalPreviewMenuPlacement(LayoutWrapper * layoutWrapper)298 void MenuLayoutAlgorithm::ModifyNormalPreviewMenuPlacement(LayoutWrapper* layoutWrapper)
299 {
300 CHECK_NULL_VOID(layoutWrapper);
301 auto props = AceType::DynamicCast<MenuLayoutProperty>(layoutWrapper->GetLayoutProperty());
302 CHECK_NULL_VOID(props);
303
304 auto hasPlacement = props->GetMenuPlacement().has_value();
305 if (SystemProperties::GetDeviceOrientation() == DeviceOrientation::PORTRAIT) {
306 ModifyNormalPreviewMenuPortraitPlacement(layoutWrapper);
307 } else if (!hasPlacement) {
308 placement_ = Placement::RIGHT_TOP;
309 props->UpdateMenuPlacement(placement_);
310 }
311 }
312
ModifyPreviewMenuPlacement(LayoutWrapper * layoutWrapper)313 void MenuLayoutAlgorithm::ModifyPreviewMenuPlacement(LayoutWrapper* layoutWrapper)
314 {
315 CHECK_NULL_VOID(layoutWrapper);
316 auto props = AceType::DynamicCast<MenuLayoutProperty>(layoutWrapper->GetLayoutProperty());
317 CHECK_NULL_VOID(props);
318
319 auto hasPlacement = props->GetMenuPlacement().has_value();
320 if (SystemProperties::GetDeviceType() == DeviceType::PHONE) {
321 ModifyNormalPreviewMenuPlacement(layoutWrapper);
322 } else {
323 if (!hasPlacement) {
324 placement_ = Placement::RIGHT_TOP;
325 props->UpdateMenuPlacement(placement_);
326 }
327 }
328 }
329
Initialize(LayoutWrapper * layoutWrapper)330 void MenuLayoutAlgorithm::Initialize(LayoutWrapper* layoutWrapper)
331 {
332 CHECK_NULL_VOID(layoutWrapper);
333 // currently using click point as menu position
334 auto props = AceType::DynamicCast<MenuLayoutProperty>(layoutWrapper->GetLayoutProperty());
335 CHECK_NULL_VOID(props);
336 auto menuNode = layoutWrapper->GetHostNode();
337 CHECK_NULL_VOID(menuNode);
338 auto menuPattern = menuNode->GetPattern<MenuPattern>();
339 CHECK_NULL_VOID(menuPattern);
340 float scale = menuPattern->GetPreviewAfterAnimationScale();
341 previewScale_ = LessOrEqual(scale, 0.0f) ? previewScale_ : scale;
342 position_ = props->GetMenuOffset().value_or(OffsetF());
343 positionOffset_ = props->GetPositionOffset().value_or(OffsetF());
344 InitializePadding(layoutWrapper);
345 InitWrapperRect(props, menuPattern);
346 placement_ = props->GetMenuPlacement().value_or(Placement::BOTTOM_LEFT);
347 ModifyPositionToWrapper(layoutWrapper, position_);
348 if (!menuPattern->IsSelectOverlayExtensionMenu() && menuPattern->GetPreviewMode() != MenuPreviewMode::NONE) {
349 ModifyPreviewMenuPlacement(layoutWrapper);
350 }
351 InitSpace(props, menuPattern);
352 }
353
InitWrapperRect(const RefPtr<MenuLayoutProperty> & props,const RefPtr<MenuPattern> & menuPattern)354 void MenuLayoutAlgorithm::InitWrapperRect(
355 const RefPtr<MenuLayoutProperty>& props, const RefPtr<MenuPattern>& menuPattern)
356 {
357 auto constraint = props->GetLayoutConstraint();
358 // has minus navgation bar height(AvoidAreaType.TYPE_NAVIGATION_INDICATOR)
359 auto wrapperIdealSize =
360 CreateIdealSize(constraint.value(), Axis::FREE, props->GetMeasureType(MeasureType::MATCH_PARENT), true);
361 auto pipelineContext = GetCurrentPipelineContext();
362 CHECK_NULL_VOID(pipelineContext);
363 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
364 wrapperRect_.SetRect(0, 0, wrapperIdealSize.Width(), wrapperIdealSize.Height());
365 auto safeAreaManager = pipelineContext->GetSafeAreaManager();
366 // system safeArea(AvoidAreaType.TYPE_SYSTEM) only include status bar,now the bottom is 0
367 auto bottom = safeAreaManager->GetSystemSafeArea().bottom_.Length();
368 auto top = safeAreaManager->GetSystemSafeArea().top_.Length();
369 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
370 if (hierarchicalParameters_) {
371 // wrapperRect_= windowGlobalRect- dock -statusbar
372 wrapperRect_ = pipelineContext->GetDisplayAvailableRect();
373 } else {
374 // wrapperIdealSize.Height = windowGlobalRect.Height()-navigation_indicator.height,no AR to avoid navigation
375 auto windowManager = pipelineContext->GetWindowManager();
376 auto isContainerModal = pipelineContext->GetWindowModal() == WindowModal::CONTAINER_MODAL && windowManager &&
377 windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING;
378 double width = windowGlobalRect.Width();
379 double height = windowGlobalRect.Height();
380 if (isContainerModal) {
381 LimitContainerModalMenuRect(width, height);
382 }
383 wrapperRect_.SetRect(0, top, width, height - top - bottom);
384
385 }
386 }
387
388 if (!menuPattern->IsSelectOverlayExtensionMenu() && menuPattern->GetPreviewMode() != MenuPreviewMode::NONE) {
389 // come from ModifyPreviewMenuPlacement
390 if (NearEqual(wrapperIdealSize.Height(), windowGlobalRect.Height())) {
391 wrapperRect_.SetRect(0, top, windowGlobalRect.Width(), windowGlobalRect.Height() - bottom);
392 }
393 }
394 wrapperSize_ = SizeF(wrapperRect_.Width(), wrapperRect_.Height());
395 }
396
InitSpace(const RefPtr<MenuLayoutProperty> & props,const RefPtr<MenuPattern> & menuPattern)397 void MenuLayoutAlgorithm::InitSpace(const RefPtr<MenuLayoutProperty>& props, const RefPtr<MenuPattern>& menuPattern)
398 {
399 auto constraint = props->GetLayoutConstraint();
400 auto targetSize = props->GetTargetSizeValue(SizeF());
401 if (menuPattern->IsSelectOverlayExtensionMenu()) {
402 topSpace_ = 0.0f;
403 bottomSpace_ = constraint->maxSize.Height() - position_.GetY();
404 leftSpace_ = Infinity<float>();
405 } else {
406 if (props->GetMenuPlacement().has_value()) {
407 auto targetSecurity = targetSecurity_;
408 topSpace_ = std::max(0.0, targetOffset_.GetY() - targetSecurity - paddingTop_ - wrapperRect_.Top());
409 bottomSpace_ = std::max(0.0,
410 wrapperRect_.Bottom() - targetOffset_.GetY() - targetSize_.Height() - targetSecurity - paddingBottom_);
411 if (NearZero(topSpace_) && NearZero(bottomSpace_)) {
412 bottomSpace_ = wrapperRect_.Bottom() - position_.GetY() - paddingTop_;
413 }
414 leftSpace_ = std::max(0.0, wrapperRect_.Left() + targetOffset_.GetX() - paddingStart_ - targetSecurity);
415 rightSpace_ = std::max(
416 0.0, wrapperRect_.Right() - targetSize_.Width() - targetSecurity - paddingStart_ - paddingEnd_);
417 if (NearZero(leftSpace_) && NearZero(rightSpace_)) {
418 leftSpace_ = position_.GetX();
419 rightSpace_ = wrapperRect_.Right() - leftSpace_;
420 }
421 } else {
422 if (hierarchicalParameters_ || !Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
423 topSpace_ = position_.GetY() - targetSize.Height() - paddingTop_ - wrapperRect_.Top();
424 bottomSpace_ = wrapperRect_.Bottom() - position_.GetY() - paddingBottom_;
425 } else {
426 topSpace_ = position_.GetY() - wrapperRect_.Top() - paddingTop_;
427 bottomSpace_ = wrapperRect_.Bottom() - position_.GetY() - paddingTop_;
428 }
429 leftSpace_ = position_.GetX() - paddingStart_;
430 rightSpace_ = wrapperRect_.Right() - leftSpace_ - paddingEnd_;
431 }
432 }
433 }
434
InitializePadding(LayoutWrapper * layoutWrapper)435 void MenuLayoutAlgorithm::InitializePadding(LayoutWrapper* layoutWrapper)
436 {
437 auto menuNode = layoutWrapper->GetHostNode();
438 CHECK_NULL_VOID(menuNode);
439 auto menuPattern = menuNode->GetPattern<MenuPattern>();
440 CHECK_NULL_VOID(menuPattern);
441 auto pipeline = PipelineBase::GetCurrentContext();
442 CHECK_NULL_VOID(pipeline);
443 auto theme = pipeline->GetTheme<SelectTheme>();
444 CHECK_NULL_VOID(theme);
445 if (!menuPattern->IsSelectOverlayExtensionMenu()) {
446 margin_ = static_cast<float>(theme->GetOutPadding().ConvertToPx());
447 optionPadding_ = margin_;
448 paddingStart_ = static_cast<float>(theme->GetDefaultPaddingStart().ConvertToPx());
449 paddingEnd_ = static_cast<float>(theme->GetDefaultPaddingEnd().ConvertToPx());
450 paddingTop_ = static_cast<float>(theme->GetDefaultPaddingTop().ConvertToPx());
451 paddingBottom_ = static_cast<float>(theme->GetDefaultPaddingBottomFixed().ConvertToPx());
452 } else {
453 optionPadding_ = static_cast<float>(theme->GetOutPadding().ConvertToPx());
454 }
455 }
456
InitializePaddingAPI11(LayoutWrapper * layoutWrapper)457 void MenuLayoutAlgorithm::InitializePaddingAPI11(LayoutWrapper* layoutWrapper)
458 {
459 auto menuNode = layoutWrapper->GetHostNode();
460 CHECK_NULL_VOID(menuNode);
461 auto menuPattern = menuNode->GetPattern<MenuPattern>();
462 CHECK_NULL_VOID(menuPattern);
463 auto pipeline = PipelineBase::GetCurrentContext();
464 CHECK_NULL_VOID(pipeline);
465 auto theme = pipeline->GetTheme<SelectTheme>();
466 CHECK_NULL_VOID(theme);
467
468 if (!menuPattern->IsSelectOverlayExtensionMenu() && !hierarchicalParameters_) {
469 margin_ = static_cast<float>(theme->GetOutPadding().ConvertToPx());
470 optionPadding_ = margin_;
471 paddingStart_ = static_cast<float>(theme->GetMaxPaddingStart().ConvertToPx());
472 paddingEnd_ = static_cast<float>(theme->GetMaxPaddingEnd().ConvertToPx());
473 paddingTop_ = static_cast<float>(theme->GetDefaultPaddingTop().ConvertToPx());
474 paddingBottom_ = static_cast<float>(theme->GetDefaultPaddingBottomFixed().ConvertToPx());
475 } else {
476 margin_ = static_cast<float>(theme->GetOutPadding().ConvertToPx());
477 paddingStart_ = margin_;
478 paddingEnd_ = margin_;
479 paddingTop_ = margin_;
480 paddingBottom_ = margin_;
481 optionPadding_ = static_cast<float>(theme->GetOutPadding().ConvertToPx());
482 }
483 }
484
ModifyPositionToWrapper(LayoutWrapper * layoutWrapper,OffsetF & position)485 void MenuLayoutAlgorithm::ModifyPositionToWrapper(LayoutWrapper* layoutWrapper, OffsetF& position)
486 {
487 auto menu = layoutWrapper->GetHostNode();
488 CHECK_NULL_VOID(menu);
489 auto wrapper = AceType::DynamicCast<FrameNode>(menu->GetParent());
490 CHECK_NULL_VOID(wrapper);
491
492 OffsetF wrapperOffset;
493 // minus wrapper offset in LayoutFullScreen
494 auto wrapperLayoutProps = wrapper->GetLayoutProperty();
495 CHECK_NULL_VOID(wrapperLayoutProps);
496 auto&& safeAreaInsets = wrapperLayoutProps->GetSafeAreaInsets();
497 if (safeAreaInsets) {
498 wrapperOffset +=
499 OffsetF(static_cast<float>(safeAreaInsets->left_.end), static_cast<float>(safeAreaInsets->top_.end));
500 position -= wrapperOffset;
501 }
502
503 auto menuPattern = menu->GetPattern<MenuPattern>();
504 CHECK_NULL_VOID(menuPattern);
505 bool isSubMenu = menuPattern->IsSubMenu() || menuPattern->IsSelectOverlaySubMenu();
506 if ((menuPattern->IsContextMenu() || (isSubMenu && Container::CurrentId() >= MIN_SUBCONTAINER_ID) ||
507 hierarchicalParameters_) &&
508 (targetTag_ != V2::SELECT_ETS_TAG)) {
509 // no need to modify for context menu, because context menu wrapper is full screen.
510 return;
511 }
512 // minus wrapper offset in floating window
513 auto pipelineContext = GetCurrentPipelineContext();
514 CHECK_NULL_VOID(pipelineContext);
515 auto windowManager = pipelineContext->GetWindowManager();
516 auto isContainerModal = pipelineContext->GetWindowModal() == WindowModal::CONTAINER_MODAL && windowManager &&
517 windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING;
518 if (isContainerModal) {
519 wrapperOffset = OffsetF(static_cast<float>((CONTAINER_BORDER_WIDTH + CONTENT_PADDING).ConvertToPx()),
520 static_cast<float>((CONTAINER_TITLE_HEIGHT + CONTAINER_BORDER_WIDTH).ConvertToPx()));
521 position -= wrapperOffset;
522 }
523 }
524
525 // Called to perform layout render node and child.
Measure(LayoutWrapper * layoutWrapper)526 void MenuLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
527 {
528 // initialize screen size and menu position
529 CHECK_NULL_VOID(layoutWrapper);
530 auto menuNode = layoutWrapper->GetHostNode();
531 CHECK_NULL_VOID(menuNode);
532 auto menuPattern = menuNode->GetPattern<MenuPattern>();
533 CHECK_NULL_VOID(menuPattern);
534 auto menuLayoutProperty = AceType::DynamicCast<MenuLayoutProperty>(layoutWrapper->GetLayoutProperty());
535 CHECK_NULL_VOID(menuLayoutProperty);
536 auto isShowInSubWindow = menuLayoutProperty->GetShowInSubWindowValue(true);
537 InitHierarchicalParameters(isShowInSubWindow);
538 if (!targetTag_.empty()) {
539 InitTargetSizeAndPosition(layoutWrapper, menuPattern->IsContextMenu(), menuPattern);
540 }
541 Initialize(layoutWrapper);
542
543 const auto& constraint = menuLayoutProperty->GetLayoutConstraint();
544 if (!constraint) {
545 return;
546 }
547 auto idealSize = CreateIdealSize(
548 constraint.value(), Axis::VERTICAL, menuLayoutProperty->GetMeasureType(MeasureType::MATCH_CONTENT), true);
549 const auto& padding = menuLayoutProperty->CreatePaddingAndBorder();
550 MinusPaddingToSize(padding, idealSize);
551
552 // calculate menu main size
553 auto childConstraint = CreateChildConstraint(layoutWrapper);
554 auto container = Container::Current();
555 CHECK_NULL_VOID(container);
556 if (container->IsSubContainer()) {
557 auto parentId = SubwindowManager::GetInstance()->GetParentContainerId(Container::CurrentId());
558 auto parentContainer = AceEngine::Get().GetContainer(parentId);
559 CHECK_NULL_VOID(parentContainer);
560 auto pipeline = AceType::DynamicCast<NG::PipelineContext>(parentContainer->GetPipelineContext());
561 CHECK_NULL_VOID(pipeline);
562 auto childInsets = pipeline->GetSafeArea();
563 childInsets.top_.start = 0;
564 childInsets.top_.end = 0;
565 LayoutWrapper::ApplySafeArea(childInsets, childConstraint);
566 }
567 if (menuPattern->IsSelectMenu() && menuPattern->GetHasOptionWidth()) {
568 auto selectMenuWidth = menuPattern->GetSelectMenuWidth();
569 childConstraint.maxSize.SetWidth(selectMenuWidth);
570 childConstraint.parentIdealSize.SetWidth(selectMenuWidth);
571 childConstraint.selfIdealSize.SetWidth(selectMenuWidth);
572 }
573 float idealHeight = 0.0f;
574 float idealWidth = 0.0f;
575 for (const auto& child : layoutWrapper->GetAllChildrenWithBuild()) {
576 child->Measure(childConstraint);
577 auto childSize = child->GetGeometryNode()->GetMarginFrameSize();
578 idealHeight += childSize.Height();
579 idealWidth = std::max(idealWidth, childSize.Width());
580 }
581 idealSize.SetHeight(idealHeight);
582 idealSize.SetWidth(idealWidth);
583 AddPaddingToSize(padding, idealSize);
584
585 auto geometryNode = layoutWrapper->GetGeometryNode();
586 CHECK_NULL_VOID(geometryNode);
587 geometryNode->SetFrameSize(idealSize);
588 }
589
GetPreviewNodeAndMenuNodeTotalSize(const RefPtr<FrameNode> & frameNode,RefPtr<LayoutWrapper> & previewLayoutWrapper,RefPtr<LayoutWrapper> & menuLayoutWrapper)590 SizeF MenuLayoutAlgorithm::GetPreviewNodeAndMenuNodeTotalSize(const RefPtr<FrameNode>& frameNode,
591 RefPtr<LayoutWrapper>& previewLayoutWrapper, RefPtr<LayoutWrapper>& menuLayoutWrapper)
592 {
593 SizeF size;
594 CHECK_NULL_RETURN(frameNode, size);
595 auto pipelineContext = GetCurrentPipelineContext();
596 CHECK_NULL_RETURN(pipelineContext, size);
597 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
598 for (auto& child : frameNode->GetAllChildrenWithBuild()) {
599 auto hostNode = child->GetHostNode();
600 auto geometryNode = child->GetGeometryNode();
601 if (!hostNode || !geometryNode) {
602 continue;
603 }
604 if (hostNode->GetTag() == V2::MENU_PREVIEW_ETS_TAG || hostNode->GetTag() == V2::IMAGE_ETS_TAG) {
605 RefPtr<GridColumnInfo> columnInfo =
606 GridSystemManager::GetInstance().GetInfoByType(GridColumnType::MENU);
607 CHECK_NULL_RETURN(columnInfo, size);
608 auto parent = columnInfo->GetParent();
609 CHECK_NULL_RETURN(parent, size);
610 parent->BuildColumnWidth(std::min(windowGlobalRect.Width(), windowGlobalRect.Height()));
611 auto maxWidth = static_cast<float>(columnInfo->GetWidth(GRID_COUNTS_4)) / previewScale_;
612 auto frameSize = geometryNode->GetMarginFrameSize();
613 static SizeF previewSize;
614 static int32_t hostId = -1;
615 if (hostNode->GetTag() == V2::MENU_PREVIEW_ETS_TAG) {
616 if (previewSize == SizeF(0.0f, 0.0f) || hostId != hostNode->GetId()) {
617 previewSize = frameSize;
618 hostId = hostNode->GetId();
619 } else {
620 frameSize = previewSize;
621 }
622 if (LessOrEqual(frameSize.Width(), maxWidth)) {
623 geometryNode->SetFrameSize(SizeF(frameSize.Width(), frameSize.Height()));
624 } else {
625 geometryNode->SetFrameSize(SizeF(maxWidth, frameSize.Height()));
626 }
627 } else {
628 geometryNode->SetFrameSize(frameSize);
629 }
630 frameSize = geometryNode->GetMarginFrameSize() * previewScale_;
631 auto widthLeftSpace = windowGlobalRect.Width() - paddingStart_ - paddingEnd_;
632 if (GreatNotEqual(frameSize.Width(), widthLeftSpace)) {
633 auto unitSpace = widthLeftSpace / frameSize.Width() / previewScale_;
634 geometryNode->SetFrameSize(SizeF(widthLeftSpace / previewScale_, unitSpace * frameSize.Height()));
635 }
636 previewLayoutWrapper = child;
637 size += geometryNode->GetMarginFrameSize() * previewScale_;
638 }
639 auto menuPattern = hostNode->GetPattern<MenuPattern>();
640 if (hostNode->GetTag() == V2::MENU_ETS_TAG && menuPattern && !menuPattern->IsSubMenu()) {
641 menuLayoutWrapper = child;
642 size += geometryNode->GetMarginFrameSize();
643 }
644 }
645 return size;
646 }
647
LayoutNormalTopPreviewBottomMenuLessThan(const RefPtr<GeometryNode> & previewGeometryNode,const RefPtr<GeometryNode> & menuGeometryNode,const PreviewMenuParam & param,SizeF & totalSize)648 void MenuLayoutAlgorithm::LayoutNormalTopPreviewBottomMenuLessThan(const RefPtr<GeometryNode>& previewGeometryNode,
649 const RefPtr<GeometryNode>& menuGeometryNode, const PreviewMenuParam& param, SizeF& totalSize)
650 {
651 CHECK_NULL_VOID(previewGeometryNode);
652 CHECK_NULL_VOID(menuGeometryNode);
653
654 OffsetF center(targetOffset_.GetX() + targetSize_.Width() / 2, targetOffset_.GetY() + targetSize_.Height() / 2);
655 targetCenterOffset_ = center;
656 auto previewSize = previewGeometryNode->GetMarginFrameSize() * previewScale_;
657 OffsetF offset(center.GetX() - previewSize.Width() / 2,
658 std::min<float>(center.GetY() - previewSize.Height() / 2, param.windowGlobalSizeF.Height() -
659 param.bottomSecurity - param.bottom - totalSize.Height() - param.previewMenuGap));
660 auto x = std::clamp(offset.GetX(), param.windowsOffsetX + paddingStart_,
661 param.windowsOffsetX + param.windowGlobalSizeF.Width() - previewSize.Width() - paddingEnd_);
662 auto y = std::clamp(offset.GetY(), param.windowsOffsetY + param.top + param.topSecurity,
663 param.windowsOffsetY + param.windowGlobalSizeF.Height() - param.bottomSecurity - param.bottom -
664 previewSize.Height());
665 x = x + (previewSize.Width() - previewSize.Width() / previewScale_) / 2;
666 y = y + (previewSize.Height() - previewSize.Height() / previewScale_) / 2;
667 previewGeometryNode->SetMarginFrameOffset(OffsetF(x, y));
668 }
669
LayoutNormalTopPreviewBottomMenuGreateThan(const RefPtr<GeometryNode> & previewGeometryNode,const RefPtr<GeometryNode> & menuGeometryNode,const PreviewMenuParam & param,SizeF & totalSize)670 void MenuLayoutAlgorithm::LayoutNormalTopPreviewBottomMenuGreateThan(const RefPtr<GeometryNode>& previewGeometryNode,
671 const RefPtr<GeometryNode>& menuGeometryNode, const PreviewMenuParam& param, SizeF& totalSize)
672 {
673 CHECK_NULL_VOID(previewGeometryNode);
674 CHECK_NULL_VOID(menuGeometryNode);
675
676 OffsetF center(targetOffset_.GetX() + targetSize_.Width() / 2, targetOffset_.GetY() + targetSize_.Height() / 2);
677 targetCenterOffset_ = center;
678 auto previewSize = previewGeometryNode->GetMarginFrameSize() * previewScale_;
679 auto menuHeight = totalSize.Height() - previewSize.Height();
680 auto previewHalfHeight = previewSize.Height() / 2;
681 if (LessNotEqual(menuHeight, previewHalfHeight)) {
682 auto menuSize = menuGeometryNode->GetMarginFrameSize();
683 if (GreatNotEqual(param.menuItemTotalHeight, previewHalfHeight)) {
684 menuGeometryNode->SetFrameSize(SizeF(menuSize.Width(), previewHalfHeight));
685 totalSize = SizeF(totalSize.Width(), previewHalfHeight + previewSize.Height());
686 } else {
687 menuGeometryNode->SetFrameSize(SizeF(menuSize.Width(), param.menuItemTotalHeight));
688 totalSize = SizeF(totalSize.Width(), param.menuItemTotalHeight + previewSize.Height());
689 }
690 }
691
692 auto heightLeftSpace = param.windowGlobalSizeF.Height() - param.top - param.bottom - param.topSecurity -
693 param.bottomSecurity - param.previewMenuGap;
694 auto delta = totalSize.Height() - heightLeftSpace;
695 if (GreatNotEqual(delta, 0.0f)) {
696 menuHeight = totalSize.Height() - previewSize.Height();
697 float unitSpace = 0.0f;
698 if (LessNotEqual(menuHeight, previewHalfHeight)) {
699 unitSpace = delta / previewSize.Height();
700 } else {
701 unitSpace = delta / totalSize.Height();
702 auto menuSize = menuGeometryNode->GetMarginFrameSize();
703 menuGeometryNode->SetFrameSize(SizeF(menuSize.Width(), (1 - unitSpace) * menuSize.Height()));
704 }
705 previewGeometryNode->SetFrameSize(SizeF((1 - unitSpace) * previewSize.Width() / previewScale_,
706 (1 - unitSpace) * previewSize.Height() / previewScale_));
707 totalSize = totalSize - SizeF(0.0f, delta);
708 }
709 previewSize = previewGeometryNode->GetMarginFrameSize() * previewScale_;
710 OffsetF offset(center.GetX() - previewSize.Width() / 2, 0.0f);
711 auto x = std::clamp(offset.GetX(), param.windowsOffsetX + paddingStart_,
712 param.windowsOffsetX + param.windowGlobalSizeF.Width() - previewSize.Width() - paddingEnd_);
713 auto y = std::clamp(offset.GetY(), param.windowsOffsetY + param.top + param.topSecurity, param.windowsOffsetY +
714 param.windowGlobalSizeF.Height() - param.bottomSecurity - param.bottom - previewSize.Height());
715 x = x + (previewSize.Width() - previewSize.Width() / previewScale_) / 2;
716 y = y + (previewSize.Height() - previewSize.Height() / previewScale_) / 2;
717 previewGeometryNode->SetMarginFrameOffset(OffsetF(x, y));
718 }
719
LayoutNormalTopPreviewBottomMenu(const RefPtr<GeometryNode> & previewGeometryNode,const RefPtr<GeometryNode> & menuGeometryNode,SizeF & totalSize,float menuItemTotalHeight)720 void MenuLayoutAlgorithm::LayoutNormalTopPreviewBottomMenu(const RefPtr<GeometryNode>& previewGeometryNode,
721 const RefPtr<GeometryNode>& menuGeometryNode, SizeF& totalSize, float menuItemTotalHeight)
722 {
723 CHECK_NULL_VOID(previewGeometryNode);
724 CHECK_NULL_VOID(menuGeometryNode);
725
726 auto pipelineContext = GetCurrentPipelineContext();
727 CHECK_NULL_VOID(pipelineContext);
728 auto safeAreaManager = pipelineContext->GetSafeAreaManager();
729 CHECK_NULL_VOID(safeAreaManager);
730 auto top = safeAreaManager->GetSystemSafeArea().top_.Length();
731 auto bottom = safeAreaManager->GetSystemSafeArea().bottom_.Length();
732 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
733 float windowsOffsetX = static_cast<float>(windowGlobalRect.GetOffset().GetX());
734 float windowsOffsetY = static_cast<float>(windowGlobalRect.GetOffset().GetY());
735 float screenHeight = wrapperSize_.Height();
736 if (!NearEqual(wrapperSize_.Height(), windowGlobalRect.Height())) {
737 screenHeight += bottom;
738 }
739 SizeF windowGlobalSizeF(windowGlobalRect.Width(), screenHeight - windowsOffsetY);
740
741 float topSecurity = static_cast<float>(PORTRAIT_TOP_SECURITY.ConvertToPx());
742 float bottomSecurity = static_cast<float>(PORTRAIT_BOTTOM_SECURITY.ConvertToPx());
743
744 PreviewMenuParam param;
745 param.windowGlobalSizeF = windowGlobalSizeF;
746 param.windowsOffsetX = windowsOffsetX;
747 param.windowsOffsetY = windowsOffsetY;
748 param.top = top;
749 param.bottom = bottom;
750 param.topSecurity = topSecurity;
751 param.bottomSecurity = bottomSecurity;
752 param.previewMenuGap = targetSecurity_;
753 param.menuItemTotalHeight = menuItemTotalHeight;
754 if (LessNotEqual(totalSize.Height() + targetSecurity_,
755 windowGlobalSizeF.Height() - topSecurity - bottomSecurity - top - bottom)) {
756 LayoutNormalTopPreviewBottomMenuLessThan(previewGeometryNode, menuGeometryNode, param, totalSize);
757 } else {
758 LayoutNormalTopPreviewBottomMenuGreateThan(previewGeometryNode, menuGeometryNode, param, totalSize);
759 }
760 auto previewSize = previewGeometryNode->GetMarginFrameSize();
761 auto securityHeight = windowGlobalRect.Height() - topSecurity - top - bottomSecurity - bottom;
762 if (GreatNotEqual(windowGlobalSizeF.Height(), windowGlobalRect.Height()) &&
763 GreatNotEqual(previewSize.Height(), securityHeight)) {
764 previewGeometryNode->SetFrameSize(SizeF(previewSize.Width(), securityHeight));
765 }
766 }
767
LayoutNormalBottomPreviewTopMenuLessThan(const RefPtr<GeometryNode> & previewGeometryNode,const RefPtr<GeometryNode> & menuGeometryNode,const PreviewMenuParam & param,SizeF & totalSize)768 void MenuLayoutAlgorithm::LayoutNormalBottomPreviewTopMenuLessThan(const RefPtr<GeometryNode>& previewGeometryNode,
769 const RefPtr<GeometryNode>& menuGeometryNode, const PreviewMenuParam& param, SizeF& totalSize)
770 {
771 CHECK_NULL_VOID(previewGeometryNode);
772 CHECK_NULL_VOID(menuGeometryNode);
773
774 OffsetF center(targetOffset_.GetX() + targetSize_.Width() / 2, targetOffset_.GetY() + targetSize_.Height() / 2);
775 targetCenterOffset_ = center;
776 auto previewSize = previewGeometryNode->GetMarginFrameSize() * previewScale_;
777 OffsetF offset(center.GetX() - previewSize.Width() / 2,
778 std::max<float>(center.GetY() - previewSize.Height() / 2,
779 param.top + param.topSecurity + totalSize.Height() - previewSize.Height() + param.previewMenuGap));
780 auto x = std::clamp(offset.GetX(), param.windowsOffsetX + paddingStart_,
781 param.windowsOffsetX + param.windowGlobalSizeF.Width() - previewSize.Width() - paddingEnd_);
782 auto y = std::clamp(offset.GetY(), param.windowsOffsetY + param.top + param.topSecurity,
783 param.windowsOffsetY + param.windowGlobalSizeF.Height() - param.bottomSecurity - param.bottom -
784 previewSize.Height());
785 x = x + (previewSize.Width() - previewSize.Width() / previewScale_) / 2;
786 y = y + (previewSize.Height() - previewSize.Height() / previewScale_) / 2;
787 previewGeometryNode->SetMarginFrameOffset(OffsetF(x, y));
788 }
789
LayoutNormalBottomPreviewTopMenuGreateThan(const RefPtr<GeometryNode> & previewGeometryNode,const RefPtr<GeometryNode> & menuGeometryNode,const PreviewMenuParam & param,SizeF & totalSize)790 void MenuLayoutAlgorithm::LayoutNormalBottomPreviewTopMenuGreateThan(const RefPtr<GeometryNode>& previewGeometryNode,
791 const RefPtr<GeometryNode>& menuGeometryNode, const PreviewMenuParam& param, SizeF& totalSize)
792 {
793 CHECK_NULL_VOID(previewGeometryNode);
794 CHECK_NULL_VOID(menuGeometryNode);
795
796 OffsetF center(targetOffset_.GetX() + targetSize_.Width() / 2, targetOffset_.GetY() + targetSize_.Height() / 2);
797 targetCenterOffset_ = center;
798 auto previewSize = previewGeometryNode->GetMarginFrameSize() * previewScale_;
799 auto menuHeight = totalSize.Height() - previewSize.Height();
800 auto previewHalfHeight = previewSize.Height() / 2;
801 if (LessNotEqual(menuHeight, previewHalfHeight)) {
802 auto menuSize = menuGeometryNode->GetMarginFrameSize();
803 if (GreatNotEqual(param.menuItemTotalHeight, previewHalfHeight)) {
804 menuGeometryNode->SetFrameSize(SizeF(menuSize.Width(), previewHalfHeight));
805 totalSize = SizeF(totalSize.Width(), previewHalfHeight + previewSize.Height());
806 } else {
807 menuGeometryNode->SetFrameSize(SizeF(menuSize.Width(), param.menuItemTotalHeight));
808 totalSize = SizeF(totalSize.Width(), param.menuItemTotalHeight + previewSize.Height());
809 }
810 }
811
812 auto heightLeftSpace = param.windowGlobalSizeF.Height() - param.top - param.topSecurity - param.bottom -
813 param.bottomSecurity - param.previewMenuGap;
814 auto delta = totalSize.Height() - heightLeftSpace;
815 if (GreatNotEqual(delta, 0.0f)) {
816 menuHeight = totalSize.Height() - previewSize.Height();
817 float unitSpace = 0.0f;
818 if (LessNotEqual(menuHeight, previewHalfHeight)) {
819 unitSpace = delta / previewSize.Height();
820 } else {
821 unitSpace = delta / totalSize.Height();
822 auto menuSize = menuGeometryNode->GetMarginFrameSize();
823 menuGeometryNode->SetFrameSize(SizeF(menuSize.Width(), (1 - unitSpace) * menuSize.Height()));
824 }
825 previewGeometryNode->SetFrameSize(SizeF((1 - unitSpace) * previewSize.Width() / previewScale_,
826 (1 - unitSpace) * previewSize.Height() / previewScale_));
827 totalSize = totalSize - SizeF(0.0f, delta);
828 }
829 previewSize = previewGeometryNode->GetMarginFrameSize() * previewScale_;
830 OffsetF offset(center.GetX() - previewSize.Width() / 2,
831 param.windowGlobalSizeF.Height() - param.bottomSecurity - param.bottom - previewSize.Height());
832
833 auto x = std::clamp(offset.GetX(), param.windowsOffsetX + paddingStart_,
834 param.windowsOffsetX + param.windowGlobalSizeF.Width() - previewSize.Width() - paddingEnd_);
835 auto y = std::clamp(offset.GetY(), param.windowsOffsetY + param.top + param.topSecurity, param.windowsOffsetY +
836 param.windowGlobalSizeF.Height() - param.bottomSecurity - param.bottom - previewSize.Height());
837 x = x + (previewSize.Width() - previewSize.Width() / previewScale_) / 2;
838 y = y + (previewSize.Height() - previewSize.Height() / previewScale_) / 2;
839 previewGeometryNode->SetMarginFrameOffset(OffsetF(x, y));
840 }
841
LayoutNormalBottomPreviewTopMenu(const RefPtr<GeometryNode> & previewGeometryNode,const RefPtr<GeometryNode> & menuGeometryNode,SizeF & totalSize,float menuItemTotalHeight)842 void MenuLayoutAlgorithm::LayoutNormalBottomPreviewTopMenu(const RefPtr<GeometryNode>& previewGeometryNode,
843 const RefPtr<GeometryNode>& menuGeometryNode, SizeF& totalSize, float menuItemTotalHeight)
844 {
845 CHECK_NULL_VOID(previewGeometryNode);
846 CHECK_NULL_VOID(menuGeometryNode);
847
848 auto pipelineContext = GetCurrentPipelineContext();
849 CHECK_NULL_VOID(pipelineContext);
850 auto safeAreaManager = pipelineContext->GetSafeAreaManager();
851 CHECK_NULL_VOID(safeAreaManager);
852 auto top = safeAreaManager->GetSystemSafeArea().top_.Length();
853 auto bottom = safeAreaManager->GetSystemSafeArea().bottom_.Length();
854 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
855 float windowsOffsetX = static_cast<float>(windowGlobalRect.GetOffset().GetX());
856 float windowsOffsetY = static_cast<float>(windowGlobalRect.GetOffset().GetY());
857 float screenHeight = wrapperSize_.Height();
858 if (!NearEqual(wrapperSize_.Height(), windowGlobalRect.Height())) {
859 screenHeight += bottom;
860 }
861 SizeF windowGlobalSizeF(windowGlobalRect.Width(), screenHeight - windowsOffsetY);
862
863 float topSecurity = static_cast<float>(PORTRAIT_TOP_SECURITY.ConvertToPx());
864 float bottomSecurity = static_cast<float>(PORTRAIT_BOTTOM_SECURITY.ConvertToPx());
865
866 PreviewMenuParam param;
867 param.windowGlobalSizeF = windowGlobalSizeF;
868 param.windowsOffsetX = windowsOffsetX;
869 param.windowsOffsetY = windowsOffsetY;
870 param.top = top;
871 param.bottom = bottom;
872 param.topSecurity = topSecurity;
873 param.bottomSecurity = bottomSecurity;
874 param.previewMenuGap = targetSecurity_;
875 param.menuItemTotalHeight = menuItemTotalHeight;
876 if (LessNotEqual(totalSize.Height() + targetSecurity_,
877 windowGlobalSizeF.Height() - topSecurity - bottomSecurity - top - bottom)) {
878 LayoutNormalBottomPreviewTopMenuLessThan(previewGeometryNode, menuGeometryNode, param, totalSize);
879 } else {
880 LayoutNormalBottomPreviewTopMenuGreateThan(previewGeometryNode, menuGeometryNode, param, totalSize);
881 }
882 auto previewSize = previewGeometryNode->GetMarginFrameSize();
883 auto securityHeight = windowGlobalRect.Height() - topSecurity - top - bottomSecurity - bottom;
884 if (GreatNotEqual(windowGlobalSizeF.Height(), windowGlobalRect.Height()) &&
885 GreatNotEqual(previewSize.Height(), securityHeight)) {
886 previewGeometryNode->SetFrameSize(SizeF(previewSize.Width(), securityHeight));
887 }
888 }
889
UpdateScrollAndColumnLayoutConstraint(const RefPtr<LayoutWrapper> & previewLayoutWrapper,const RefPtr<LayoutWrapper> & menuLayoutWrapper)890 void MenuLayoutAlgorithm::UpdateScrollAndColumnLayoutConstraint(
891 const RefPtr<LayoutWrapper>& previewLayoutWrapper, const RefPtr<LayoutWrapper>& menuLayoutWrapper)
892 {
893 CHECK_NULL_VOID(menuLayoutWrapper);
894 CHECK_NULL_VOID(previewLayoutWrapper);
895 RefPtr<GeometryNode> menuGeometryNode = menuLayoutWrapper->GetGeometryNode();
896 RefPtr<GeometryNode> previewGeometryNode = previewLayoutWrapper->GetGeometryNode();
897 CHECK_NULL_VOID(menuGeometryNode);
898 CHECK_NULL_VOID(previewGeometryNode);
899
900 for (auto& child : menuLayoutWrapper->GetAllChildrenWithBuild()) {
901 auto geometryNode = child->GetGeometryNode();
902 if (!geometryNode) {
903 continue;
904 }
905 auto frameSize = menuGeometryNode->GetMarginFrameSize();
906 geometryNode->SetFrameSize(SizeF(frameSize.Width(), frameSize.Height()));
907 auto layoutProperty = child->GetLayoutProperty();
908 CHECK_NULL_VOID(layoutProperty);
909 auto constraint = layoutProperty->GetLayoutConstraint();
910 if (constraint.has_value()) {
911 constraint.value().maxSize.SetWidth(frameSize.Width());
912 constraint.value().maxSize.SetHeight(frameSize.Height());
913 constraint.value().selfIdealSize.UpdateSizeWithCheck(SizeF(frameSize.Width(), frameSize.Height()));
914 layoutProperty->UpdateLayoutConstraint(constraint.value());
915 child->Measure(constraint);
916 }
917 }
918
919 for (auto& child : previewLayoutWrapper->GetAllChildrenWithBuild()) {
920 auto hostNode = child->GetHostNode();
921 auto geometryNode = child->GetGeometryNode();
922 if (!hostNode || !geometryNode) {
923 continue;
924 }
925 auto frameSize = previewGeometryNode->GetMarginFrameSize();
926 geometryNode->SetFrameSize(SizeF(frameSize.Width(), frameSize.Height()));
927 auto layoutProperty = child->GetLayoutProperty();
928 CHECK_NULL_VOID(layoutProperty);
929 auto constraint = layoutProperty->GetLayoutConstraint();
930 if (constraint.has_value()) {
931 constraint.value().maxSize.SetWidth(frameSize.Width());
932 constraint.value().maxSize.SetHeight(frameSize.Height());
933 constraint.value().selfIdealSize.UpdateSizeWithCheck(SizeF(frameSize.Width(), frameSize.Height()));
934 layoutProperty->UpdateLayoutConstraint(constraint.value());
935 hostNode->GetRenderContext()->SetClipToBounds(true);
936 child->Measure(constraint);
937 }
938 }
939 }
940
GetMenuItemTotalHeight(const RefPtr<LayoutWrapper> & menuLayoutWrapper)941 float MenuLayoutAlgorithm::GetMenuItemTotalHeight(const RefPtr<LayoutWrapper>& menuLayoutWrapper)
942 {
943 CHECK_NULL_RETURN(menuLayoutWrapper, 0.0f);
944 RefPtr<GeometryNode> menuGeometryNode = menuLayoutWrapper->GetGeometryNode();
945 CHECK_NULL_RETURN(menuGeometryNode, 0.0f);
946 float height = 0.0f;
947
948 for (auto& child : menuLayoutWrapper->GetAllChildrenWithBuild()) {
949 auto geometryNode = child->GetGeometryNode();
950 if (!geometryNode) {
951 continue;
952 }
953 for (auto& menuItem : child->GetAllChildrenWithBuild()) {
954 auto itemHostnode = menuItem->GetHostNode();
955 auto itemGeometryNode = menuItem->GetGeometryNode();
956 if (!itemHostnode || !itemGeometryNode) {
957 continue;
958 }
959 height += itemGeometryNode->GetMarginFrameSize().Height();
960 }
961 }
962 auto menuHeight = menuGeometryNode->GetMarginFrameSize().Height();
963 if (LessNotEqual(height, menuHeight)) {
964 height = menuHeight;
965 }
966 return height;
967 }
968
LayoutNormalPreviewMenu(LayoutWrapper * layoutWrapper)969 void MenuLayoutAlgorithm::LayoutNormalPreviewMenu(LayoutWrapper* layoutWrapper)
970 {
971 CHECK_NULL_VOID(layoutWrapper);
972 auto menuNode = layoutWrapper->GetHostNode();
973 CHECK_NULL_VOID(menuNode);
974 auto parentNode = AceType::DynamicCast<FrameNode>(menuNode->GetParent());
975 CHECK_NULL_VOID(parentNode);
976 auto menuProp = DynamicCast<MenuLayoutProperty>(layoutWrapper->GetLayoutProperty());
977 CHECK_NULL_VOID(menuProp);
978
979 RefPtr<LayoutWrapper> menuLayoutWrapper;
980 RefPtr<LayoutWrapper> previewLayoutWrapper;
981 SizeF totalSize = GetPreviewNodeAndMenuNodeTotalSize(parentNode, previewLayoutWrapper, menuLayoutWrapper);
982 CHECK_NULL_VOID(menuLayoutWrapper);
983 CHECK_NULL_VOID(previewLayoutWrapper);
984 RefPtr<GeometryNode> menuGeometryNode = menuLayoutWrapper->GetGeometryNode();
985 RefPtr<GeometryNode> previewGeometryNode = previewLayoutWrapper->GetGeometryNode();
986 auto menuItemTotalHeight = GetMenuItemTotalHeight(menuLayoutWrapper);
987
988 if (SystemProperties::GetDeviceOrientation() == DeviceOrientation::PORTRAIT) {
989 if (placement_ == Placement::TOP_LEFT || placement_ == Placement::TOP || placement_ == Placement::TOP_RIGHT) {
990 LayoutNormalBottomPreviewTopMenu(previewGeometryNode, menuGeometryNode, totalSize, menuItemTotalHeight);
991 } else {
992 LayoutNormalTopPreviewBottomMenu(previewGeometryNode, menuGeometryNode, totalSize, menuItemTotalHeight);
993 }
994 } else {
995 LayoutOtherDeviceLeftPreviewRightMenu(previewGeometryNode, menuGeometryNode, totalSize, menuItemTotalHeight);
996 }
997 UpdateScrollAndColumnLayoutConstraint(previewLayoutWrapper, menuLayoutWrapper);
998 auto previewSize = previewGeometryNode->GetMarginFrameSize();
999 previewOffset_ = previewGeometryNode->GetFrameOffset();
1000 auto previewOffsetX = previewOffset_.GetX();
1001 auto previewOffsetY = previewOffset_.GetY();
1002 targetSize_ = previewSize * previewScale_;
1003 targetOffset_ = OffsetF(previewOffsetX + (previewSize.Width() - targetSize_.Width()) / 2,
1004 previewOffsetY + (previewSize.Height() - targetSize_.Height()) / 2);
1005 auto previewHostNode = previewLayoutWrapper->GetHostNode();
1006 CHECK_NULL_VOID(previewHostNode);
1007 auto renderContext = previewHostNode->GetRenderContext();
1008 CHECK_NULL_VOID(renderContext);
1009 renderContext->UpdatePosition(OffsetT<Dimension>(Dimension(previewOffsetX), Dimension(previewOffsetY)));
1010
1011 auto menuHostNode = menuLayoutWrapper->GetHostNode();
1012 CHECK_NULL_VOID(menuHostNode);
1013 previewOriginOffset_ = targetCenterOffset_ - OffsetF(previewSize.Width() / 2, previewSize.Height() / 2);
1014 previewSize_ = previewSize;
1015 auto menuPattern = menuHostNode->GetPattern<MenuPattern>();
1016 CHECK_NULL_VOID(menuPattern);
1017 menuPattern->SetPreviewOriginOffset(previewOriginOffset_);
1018 }
1019
LayoutOtherDeviceLeftPreviewRightMenuLessThan(const RefPtr<GeometryNode> & previewGeometryNode,const RefPtr<GeometryNode> & menuGeometryNode,const PreviewMenuParam & param,SizeF & totalSize)1020 void MenuLayoutAlgorithm::LayoutOtherDeviceLeftPreviewRightMenuLessThan(const RefPtr<GeometryNode>& previewGeometryNode,
1021 const RefPtr<GeometryNode>& menuGeometryNode, const PreviewMenuParam& param, SizeF& totalSize)
1022 {
1023 CHECK_NULL_VOID(previewGeometryNode);
1024 CHECK_NULL_VOID(menuGeometryNode);
1025
1026 OffsetF targetCenterOffset(
1027 targetOffset_.GetX() + targetSize_.Width() / 2, targetOffset_.GetY() + targetSize_.Height() / 2);
1028 targetCenterOffset_ = targetCenterOffset;
1029 auto previewSize = previewGeometryNode->GetMarginFrameSize() * previewScale_;
1030 auto heightLeftSpace =
1031 param.windowGlobalSizeF.Height() - param.top - param.topSecurity - param.bottomSecurity - param.bottom;
1032 auto delta = previewSize.Height() - heightLeftSpace;
1033 if (GreatNotEqual(delta, 0.0f)) {
1034 auto unitSpace = delta / previewSize.Height();
1035 previewGeometryNode->SetFrameSize(SizeF((1 - unitSpace) * previewSize.Width() / previewScale_,
1036 (1 - unitSpace) * previewSize.Height() / previewScale_));
1037 totalSize = totalSize - SizeF(unitSpace * previewSize.Width(), unitSpace * previewSize.Height());
1038 }
1039 previewSize = previewGeometryNode->GetMarginFrameSize() * previewScale_;
1040 auto menuSize = menuGeometryNode->GetMarginFrameSize();
1041 menuGeometryNode->SetFrameSize(
1042 SizeF(menuSize.Width(), std::min<float>(param.menuItemTotalHeight, heightLeftSpace)));
1043 menuSize = menuGeometryNode->GetMarginFrameSize();
1044 auto offsetX = targetCenterOffset.GetX() - previewSize.Width() / 2;
1045 auto offsetY = std::min<float>(targetCenterOffset.GetY() - previewSize.Height() / 2,
1046 param.windowGlobalSizeF.Height() - param.bottomSecurity - param.bottom - menuSize.Height());
1047 auto x = std::clamp(offsetX, param.windowsOffsetX + paddingStart_,
1048 param.windowsOffsetX + param.windowGlobalSizeF.Width() - previewSize.Width() - paddingEnd_);
1049 auto y = std::clamp(offsetY, param.windowsOffsetY + param.top + param.topSecurity,
1050 param.windowsOffsetY + param.windowGlobalSizeF.Height() - param.bottomSecurity - param.bottom -
1051 previewSize.Height());
1052 x = x + (previewSize.Width() - previewSize.Width() / previewScale_) / 2;
1053 y = y + (previewSize.Height() - previewSize.Height() / previewScale_) / 2;
1054 previewGeometryNode->SetMarginFrameOffset(OffsetF(x, y));
1055 }
1056
LayoutOtherDeviceLeftPreviewRightMenuGreateThan(const RefPtr<GeometryNode> & previewGeometryNode,const RefPtr<GeometryNode> & menuGeometryNode,const PreviewMenuParam & param,SizeF & totalSize)1057 void MenuLayoutAlgorithm::LayoutOtherDeviceLeftPreviewRightMenuGreateThan(
1058 const RefPtr<GeometryNode>& previewGeometryNode, const RefPtr<GeometryNode>& menuGeometryNode,
1059 const PreviewMenuParam& param, SizeF& totalSize)
1060 {
1061 CHECK_NULL_VOID(previewGeometryNode);
1062 CHECK_NULL_VOID(menuGeometryNode);
1063
1064 OffsetF targetCenterOffset(
1065 targetOffset_.GetX() + targetSize_.Width() / 2, targetOffset_.GetY() + targetSize_.Height() / 2);
1066 targetCenterOffset_ = targetCenterOffset;
1067 auto previewSize = previewGeometryNode->GetMarginFrameSize() * previewScale_;
1068 auto widthLeftSpace = param.windowGlobalSizeF.Width() - paddingStart_ - paddingEnd_ - param.previewMenuGap;
1069 auto delta = totalSize.Width() - widthLeftSpace;
1070 if (GreatNotEqual(delta, 0.0f)) {
1071 auto unitSpace = delta / previewSize.Width();
1072 previewGeometryNode->SetFrameSize(SizeF((1 - unitSpace) * previewSize.Width() / previewScale_,
1073 (1 - unitSpace) * previewSize.Height() / previewScale_));
1074 totalSize = totalSize - SizeF(unitSpace * previewSize.Width(), unitSpace * previewSize.Height());
1075 }
1076 previewSize = previewGeometryNode->GetMarginFrameSize() * previewScale_;
1077 auto heightLeftSpace =
1078 param.windowGlobalSizeF.Height() - param.topSecurity - param.top - param.bottomSecurity - param.bottom;
1079 delta = previewSize.Height() - heightLeftSpace;
1080 if (GreatNotEqual(delta, 0.0f)) {
1081 auto unitSpace = delta / previewSize.Height();
1082 previewGeometryNode->SetFrameSize(SizeF((1 - unitSpace) * previewSize.Width() / previewScale_,
1083 (1 - unitSpace) * previewSize.Height() / previewScale_));
1084 totalSize = totalSize - SizeF(unitSpace * previewSize.Width(), unitSpace * previewSize.Height());
1085 }
1086 previewSize = previewGeometryNode->GetMarginFrameSize() * previewScale_;
1087 auto menuSize = menuGeometryNode->GetMarginFrameSize();
1088 menuGeometryNode->SetFrameSize(
1089 SizeF(menuSize.Width(), std::min<float>(param.menuItemTotalHeight, heightLeftSpace)));
1090 menuSize = menuGeometryNode->GetMarginFrameSize();
1091 auto offsetX = 0.0f;
1092 auto offsetY = std::min<float>(targetCenterOffset.GetY() - previewSize.Height() / 2,
1093 param.windowGlobalSizeF.Height() - param.bottomSecurity - param.bottom - menuSize.Height());
1094 auto x = std::clamp(offsetX, param.windowsOffsetX + paddingStart_,
1095 param.windowsOffsetX + param.windowGlobalSizeF.Width() - previewSize.Width() - paddingEnd_);
1096 auto y = std::clamp(offsetY, param.windowsOffsetY + param.top + param.topSecurity,
1097 param.windowsOffsetY + param.windowGlobalSizeF.Height() - param.bottomSecurity - param.bottom -
1098 previewSize.Height());
1099 x = x + (previewSize.Width() - previewSize.Width() / previewScale_) / 2;
1100 y = y + (previewSize.Height() - previewSize.Height() / previewScale_) / 2;
1101 previewGeometryNode->SetMarginFrameOffset(OffsetF(x, y));
1102 }
1103
LayoutOtherDeviceLeftPreviewRightMenu(const RefPtr<GeometryNode> & previewGeometryNode,const RefPtr<GeometryNode> & menuGeometryNode,SizeF & totalSize,float menuItemTotalHeight)1104 void MenuLayoutAlgorithm::LayoutOtherDeviceLeftPreviewRightMenu(const RefPtr<GeometryNode>& previewGeometryNode,
1105 const RefPtr<GeometryNode>& menuGeometryNode, SizeF& totalSize, float menuItemTotalHeight)
1106 {
1107 CHECK_NULL_VOID(previewGeometryNode);
1108 CHECK_NULL_VOID(menuGeometryNode);
1109
1110 auto pipelineContext = GetCurrentPipelineContext();
1111 CHECK_NULL_VOID(pipelineContext);
1112 auto safeAreaManager = pipelineContext->GetSafeAreaManager();
1113 CHECK_NULL_VOID(safeAreaManager);
1114 auto top = safeAreaManager->GetSystemSafeArea().top_.Length();
1115 auto bottom = safeAreaManager->GetSystemSafeArea().bottom_.Length();
1116 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
1117 float windowsOffsetX = static_cast<float>(windowGlobalRect.GetOffset().GetX());
1118 float windowsOffsetY = static_cast<float>(windowGlobalRect.GetOffset().GetY());
1119 float screenHeight = wrapperSize_.Height();
1120 if (!NearEqual(wrapperSize_.Height(), windowGlobalRect.Height())) {
1121 screenHeight += bottom;
1122 }
1123 SizeF windowGlobalSizeF(windowGlobalRect.Width(), screenHeight - windowsOffsetY);
1124 float topSecurity = 0.0f;
1125 float bottomSecurity = 0.0f;
1126 if (SystemProperties::GetDeviceOrientation() == DeviceOrientation::PORTRAIT) {
1127 topSecurity = static_cast<float>(PORTRAIT_TOP_SECURITY.ConvertToPx());
1128 bottomSecurity = static_cast<float>(PORTRAIT_BOTTOM_SECURITY.ConvertToPx());
1129 } else {
1130 topSecurity = static_cast<float>(LANDSCAPE_TOP_SECURITY.ConvertToPx());
1131 bottomSecurity = static_cast<float>(LANDSCAPE_BOTTOM_SECURITY.ConvertToPx());
1132 }
1133 PreviewMenuParam param;
1134 param.windowGlobalSizeF = windowGlobalSizeF;
1135 param.windowsOffsetX = windowsOffsetX;
1136 param.windowsOffsetY = windowsOffsetY;
1137 param.top = top;
1138 param.bottom = bottom;
1139 param.topSecurity = topSecurity;
1140 param.bottomSecurity = bottomSecurity;
1141 param.previewMenuGap = targetSecurity_;
1142 param.menuItemTotalHeight = menuItemTotalHeight;
1143 if (LessNotEqual(totalSize.Width() + targetSecurity_, windowGlobalSizeF.Width() - paddingStart_ - paddingEnd_)) {
1144 LayoutOtherDeviceLeftPreviewRightMenuLessThan(previewGeometryNode, menuGeometryNode, param, totalSize);
1145 } else {
1146 LayoutOtherDeviceLeftPreviewRightMenuGreateThan(previewGeometryNode, menuGeometryNode, param, totalSize);
1147 }
1148 auto previewSize = previewGeometryNode->GetMarginFrameSize();
1149 auto securityHeight = windowGlobalRect.Height() - topSecurity - top - bottomSecurity - bottom;
1150 if (GreatNotEqual(windowGlobalSizeF.Height(), windowGlobalRect.Height()) &&
1151 GreatNotEqual(previewSize.Height(), securityHeight)) {
1152 previewGeometryNode->SetFrameSize(SizeF(previewSize.Width(), securityHeight));
1153 }
1154 }
1155
LayoutOtherDevicePreviewMenu(LayoutWrapper * layoutWrapper)1156 void MenuLayoutAlgorithm::LayoutOtherDevicePreviewMenu(LayoutWrapper* layoutWrapper)
1157 {
1158 CHECK_NULL_VOID(layoutWrapper);
1159 auto menuNode = layoutWrapper->GetHostNode();
1160 CHECK_NULL_VOID(menuNode);
1161 auto parentNode = AceType::DynamicCast<FrameNode>(menuNode->GetParent());
1162 CHECK_NULL_VOID(parentNode);
1163 auto menuProp = DynamicCast<MenuLayoutProperty>(layoutWrapper->GetLayoutProperty());
1164 CHECK_NULL_VOID(menuProp);
1165
1166 RefPtr<LayoutWrapper> menuLayoutWrapper;
1167 RefPtr<LayoutWrapper> previewLayoutWrapper;
1168 SizeF totalSize = GetPreviewNodeAndMenuNodeTotalSize(parentNode, previewLayoutWrapper, menuLayoutWrapper);
1169 CHECK_NULL_VOID(menuLayoutWrapper);
1170 CHECK_NULL_VOID(previewLayoutWrapper);
1171 RefPtr<GeometryNode> menuGeometryNode = menuLayoutWrapper->GetGeometryNode();
1172 RefPtr<GeometryNode> previewGeometryNode = previewLayoutWrapper->GetGeometryNode();
1173 CHECK_NULL_VOID(menuGeometryNode);
1174 CHECK_NULL_VOID(previewGeometryNode);
1175 auto menuItemTotalHeight = GetMenuItemTotalHeight(menuLayoutWrapper);
1176 LayoutOtherDeviceLeftPreviewRightMenu(previewGeometryNode, menuGeometryNode, totalSize, menuItemTotalHeight);
1177 UpdateScrollAndColumnLayoutConstraint(previewLayoutWrapper, menuLayoutWrapper);
1178 auto previewSize = previewGeometryNode->GetMarginFrameSize();
1179 previewOffset_ = previewGeometryNode->GetFrameOffset();
1180 auto previewOffsetX = previewGeometryNode->GetFrameOffset().GetX();
1181 auto previewOffsetY = previewGeometryNode->GetFrameOffset().GetY();
1182 targetSize_ = previewSize * previewScale_;
1183 targetOffset_ = OffsetF(previewOffsetX + (previewSize.Width() - targetSize_.Width()) / 2,
1184 previewOffsetY + (previewSize.Height() - targetSize_.Height()) / 2);
1185 auto previewHostNode = previewLayoutWrapper->GetHostNode();
1186 CHECK_NULL_VOID(previewHostNode);
1187 auto renderContext = previewHostNode->GetRenderContext();
1188 CHECK_NULL_VOID(renderContext);
1189 renderContext->UpdatePosition(OffsetT<Dimension>(Dimension(previewOffsetX), Dimension(previewOffsetY)));
1190
1191 auto menuHostNode = menuLayoutWrapper->GetHostNode();
1192 CHECK_NULL_VOID(menuHostNode);
1193 previewOriginOffset_ = targetCenterOffset_ - OffsetF(previewSize.Width() / 2, previewSize.Height() / 2);
1194 previewSize_ = previewSize;
1195 auto menuPattern = menuHostNode->GetPattern<MenuPattern>();
1196 CHECK_NULL_VOID(menuPattern);
1197 menuPattern->SetPreviewOriginOffset(previewOriginOffset_);
1198 }
1199
LayoutPreviewMenu(LayoutWrapper * layoutWrapper)1200 void MenuLayoutAlgorithm::LayoutPreviewMenu(LayoutWrapper* layoutWrapper)
1201 {
1202 auto paintProperty = GetPaintProperty(layoutWrapper);
1203 CHECK_NULL_VOID(paintProperty);
1204 paintProperty->UpdateEnableArrow(false);
1205 if (SystemProperties::GetDeviceType() == DeviceType::PHONE) {
1206 LayoutNormalPreviewMenu(layoutWrapper);
1207 } else {
1208 LayoutOtherDevicePreviewMenu(layoutWrapper);
1209 }
1210 }
1211
FixMenuOriginOffset(float beforeAnimationScale,float afterAnimationScale)1212 OffsetF MenuLayoutAlgorithm::FixMenuOriginOffset(float beforeAnimationScale, float afterAnimationScale)
1213 {
1214 auto beforeScalePreviewOffset = OffsetF((previewSize_ * ((1.0f - beforeAnimationScale) / 2)).Width(),
1215 (previewSize_ * ((1.0f - beforeAnimationScale) / 2)).Height());
1216 auto afterScalePreviewOffset = OffsetF((previewSize_ * ((afterAnimationScale - 1.0f) / 2)).Width(),
1217 (previewSize_ * ((afterAnimationScale - 1.0f) / 2)).Height());
1218 auto scaleOffset = afterScalePreviewOffset + beforeScalePreviewOffset;
1219 float x = 0.0f;
1220 float y = 0.0f;
1221 switch (placement_) {
1222 case Placement::BOTTOM_LEFT:
1223 case Placement::LEFT_BOTTOM:
1224 x += scaleOffset.GetX();
1225 y -= scaleOffset.GetY();
1226 break;
1227 case Placement::TOP_RIGHT:
1228 case Placement::RIGHT_TOP:
1229 x -= scaleOffset.GetX();
1230 y += scaleOffset.GetY();
1231 break;
1232 case Placement::TOP_LEFT:
1233 case Placement::LEFT_TOP:
1234 x += scaleOffset.GetX();
1235 y += scaleOffset.GetY();
1236 break;
1237 case Placement::BOTTOM_RIGHT:
1238 case Placement::RIGHT_BOTTOM:
1239 x -= scaleOffset.GetX();
1240 y -= scaleOffset.GetY();
1241 break;
1242 case Placement::BOTTOM:
1243 y -= scaleOffset.GetY();
1244 break;
1245 case Placement::TOP:
1246 y += scaleOffset.GetY();
1247 break;
1248 case Placement::LEFT:
1249 x += scaleOffset.GetX();
1250 break;
1251 case Placement::RIGHT:
1252 x -= scaleOffset.GetX();
1253 break;
1254 default:
1255 x += scaleOffset.GetX();
1256 y -= scaleOffset.GetY();
1257 break;
1258 }
1259 return OffsetF(x, y);
1260 }
1261
Layout(LayoutWrapper * layoutWrapper)1262 void MenuLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
1263 {
1264 CHECK_NULL_VOID(layoutWrapper);
1265 auto menuProp = DynamicCast<MenuLayoutProperty>(layoutWrapper->GetLayoutProperty());
1266 CHECK_NULL_VOID(menuProp);
1267 auto menuNode = layoutWrapper->GetHostNode();
1268 CHECK_NULL_VOID(menuNode);
1269 auto menuPattern = menuNode->GetPattern<MenuPattern>();
1270 CHECK_NULL_VOID(menuPattern);
1271
1272 if (menuPattern->GetPreviewMode() != MenuPreviewMode::NONE) {
1273 LayoutPreviewMenu(layoutWrapper);
1274 }
1275 if (!menuPattern->IsSelectOverlayExtensionMenu() && !menuPattern->IsSelectOverlayCustomMenu()) {
1276 auto geometryNode = layoutWrapper->GetGeometryNode();
1277 CHECK_NULL_VOID(geometryNode);
1278 auto size = geometryNode->GetMarginFrameSize();
1279 bool didNeedArrow = GetIfNeedArrow(layoutWrapper, size);
1280 if (menuPattern->IsSelectMenu()) {
1281 ComputeMenuPositionByAlignType(menuProp, size);
1282 auto offset = ComputeMenuPositionByOffset(menuProp, geometryNode);
1283 position_ += offset;
1284 }
1285 auto menuPosition = MenuLayoutAvoidAlgorithm(menuProp, menuPattern, size, didNeedArrow);
1286 if (menuPattern->IsSelectOverlayRightClickMenu()) {
1287 AdjustSelectOverlayMenuPosition(menuPosition, geometryNode);
1288 }
1289 SetMenuPlacementForAnimation(layoutWrapper);
1290 arrowPosition_ = GetArrowPositionWithPlacement(size);
1291 if (didNeedArrow && arrowPlacement_ != Placement::NONE) {
1292 LayoutArrow(layoutWrapper);
1293 }
1294 geometryNode->SetFrameOffset(menuPosition);
1295 auto pipeline = PipelineBase::GetCurrentContext();
1296 CHECK_NULL_VOID(pipeline);
1297 auto menuTheme = pipeline->GetTheme<NG::MenuTheme>();
1298 CHECK_NULL_VOID(menuTheme);
1299 auto beforeAnimationScale = menuTheme->GetPreviewBeforeAnimationScale();
1300 auto afterAnimationScale = menuTheme->GetPreviewAfterAnimationScale();
1301 auto menuOriginOffset = menuPosition - (previewOffset_ - previewOriginOffset_) +
1302 FixMenuOriginOffset(beforeAnimationScale, afterAnimationScale);
1303 menuPattern->SetOriginOffset(menuOriginOffset);
1304 auto previewScale = 1.0f;
1305 if (menuPattern->GetPreviewMode() == MenuPreviewMode::IMAGE &&
1306 !NearEqual(menuPattern->GetTargetSize().Width(), previewSize_.Width())) {
1307 previewScale = menuPattern->GetTargetSize().Width() / previewSize_.Width();
1308 }
1309 auto menuEndOffset = menuPosition -
1310 (previewOffset_ - previewOriginOffset_) + FixMenuOriginOffset(previewScale, afterAnimationScale);
1311 menuPattern->SetEndOffset(menuEndOffset);
1312 menuPattern->SetHasLaid(true);
1313 }
1314
1315 // translate each option by the height of previous options
1316 OffsetF translate;
1317 for (const auto& child : layoutWrapper->GetAllChildrenWithBuild()) {
1318 child->GetGeometryNode()->SetMarginFrameOffset(translate);
1319 child->Layout();
1320 translate += OffsetF(0, child->GetGeometryNode()->GetFrameSize().Height());
1321 }
1322 }
1323
AdjustSelectOverlayMenuPosition(OffsetF & menuPosition,const RefPtr<GeometryNode> & geometryNode)1324 void MenuLayoutAlgorithm::AdjustSelectOverlayMenuPosition(
1325 OffsetF& menuPosition, const RefPtr<GeometryNode>& geometryNode)
1326 {
1327 auto pipelineContext = GetCurrentPipelineContext();
1328 CHECK_NULL_VOID(pipelineContext);
1329 auto safeAreaManager = pipelineContext->GetSafeAreaManager();
1330 auto keyboardInsert = safeAreaManager->GetKeyboardInset();
1331 auto size = geometryNode->GetFrameSize();
1332 auto start = static_cast<float>(keyboardInsert.start);
1333 if (GreatNotEqual(menuPosition.GetY() + size.Height(), start) && GreatOrEqual(start, size.Height())) {
1334 menuPosition.SetY(menuPosition.GetY() - margin_ - size.Height());
1335 } else if (GreatNotEqual(menuPosition.GetY() + size.Height(), start) && LessNotEqual(start, size.Height()) &&
1336 GreatNotEqual(start, 0)) {
1337 menuPosition.SetY(menuPosition.GetY() - margin_ - size.Height() / 2);
1338 }
1339 }
1340
SetMenuPlacementForAnimation(LayoutWrapper * layoutWrapper)1341 void MenuLayoutAlgorithm::SetMenuPlacementForAnimation(LayoutWrapper* layoutWrapper)
1342 {
1343 auto menu = layoutWrapper->GetHostNode();
1344 CHECK_NULL_VOID(menu);
1345 auto menuPattern = menu->GetPattern<MenuPattern>();
1346 CHECK_NULL_VOID(menuPattern);
1347 auto menuWrapper = menuPattern->GetMenuWrapper();
1348 CHECK_NULL_VOID(menuWrapper);
1349 auto wrapperPattern = menuWrapper->GetPattern<MenuWrapperPattern>();
1350 CHECK_NULL_VOID(wrapperPattern);
1351 wrapperPattern->SetMenuPlacementAfterLayout(placement_);
1352 }
1353
LayoutArrow(const LayoutWrapper * layoutWrapper)1354 void MenuLayoutAlgorithm::LayoutArrow(const LayoutWrapper* layoutWrapper)
1355 {
1356 auto paintProperty = GetPaintProperty(layoutWrapper);
1357 CHECK_NULL_VOID(paintProperty);
1358 paintProperty->UpdateArrowPosition(arrowPosition_);
1359 paintProperty->UpdateArrowPlacement(arrowPlacement_);
1360 }
1361
GetPaintProperty(const LayoutWrapper * layoutWrapper)1362 RefPtr<MenuPaintProperty> MenuLayoutAlgorithm::GetPaintProperty(const LayoutWrapper* layoutWrapper)
1363 {
1364 auto menuNode = layoutWrapper->GetHostNode();
1365 CHECK_NULL_RETURN(menuNode, nullptr);
1366 auto paintProperty = menuNode->GetPaintProperty<MenuPaintProperty>();
1367 CHECK_NULL_RETURN(paintProperty, nullptr);
1368 return paintProperty;
1369 }
1370
GetIfNeedArrow(const LayoutWrapper * layoutWrapper,const SizeF & menuSize)1371 bool MenuLayoutAlgorithm::GetIfNeedArrow(const LayoutWrapper* layoutWrapper, const SizeF& menuSize)
1372 {
1373 CHECK_NULL_RETURN(layoutWrapper, false);
1374 auto menuNode = layoutWrapper->GetHostNode();
1375 CHECK_NULL_RETURN(menuNode, false);
1376 auto menuPattern = menuNode->GetPattern<MenuPattern>();
1377 CHECK_NULL_RETURN(menuPattern, false);
1378 auto menuProp = DynamicCast<MenuLayoutProperty>(layoutWrapper->GetLayoutProperty());
1379 CHECK_NULL_RETURN(menuProp, false);
1380 auto paintProperty = GetPaintProperty(layoutWrapper);
1381 CHECK_NULL_RETURN(paintProperty, false);
1382 propNeedArrow_ = paintProperty->GetEnableArrow().value_or(false);
1383
1384 auto pipeline = PipelineBase::GetCurrentContext();
1385 CHECK_NULL_RETURN(pipeline, false);
1386 auto selectThemePtr = pipeline->GetTheme<SelectTheme>();
1387 CHECK_NULL_RETURN(selectThemePtr, false);
1388 if (!propNeedArrow_ || !menuProp->GetMenuPlacement().has_value()) {
1389 return false;
1390 }
1391
1392 propArrowOffset_ = paintProperty->GetArrowOffset().value_or(Dimension(0));
1393 menuRadius_ = selectThemePtr->GetMenuBorderRadius().ConvertToPx();
1394 arrowMinLimit_ = menuRadius_ + ARROW_WIDTH.ConvertToPx() / 2.0;
1395 arrowWidth_ = ARROW_WIDTH.ConvertToPx();
1396 auto targetSpaceReal = TARGET_SPACE.ConvertToPx();
1397
1398 if (setHorizontal_.find(placement_) != setHorizontal_.end()) {
1399 if (menuSize.Height() >= menuRadius_ * 2 + arrowWidth_) {
1400 arrowInMenu_ = true;
1401 targetSpace_ = targetSpaceReal;
1402 }
1403 }
1404
1405 if (setVertical_.find(placement_) != setVertical_.end()) {
1406 if (menuSize.Width() >= menuRadius_ * 2 + arrowWidth_) {
1407 arrowInMenu_ = true;
1408 targetSpace_ = targetSpaceReal;
1409 }
1410 }
1411
1412 return menuPattern->IsContextMenu() && !targetTag_.empty() && arrowInMenu_;
1413 }
1414
UpdatePropArrowOffset()1415 void MenuLayoutAlgorithm::UpdatePropArrowOffset()
1416 {
1417 if (propArrowOffset_.IsValid()) {
1418 if (propArrowOffset_.Unit() == DimensionUnit::PERCENT) {
1419 propArrowOffset_.SetValue(std::clamp(propArrowOffset_.Value(), 0.0, 1.0));
1420 }
1421 return;
1422 }
1423 switch (arrowPlacement_) {
1424 case Placement::LEFT:
1425 case Placement::RIGHT:
1426 case Placement::TOP:
1427 case Placement::BOTTOM:
1428 propArrowOffset_ = ARROW_HALF_PERCENT_VALUE;
1429 break;
1430 case Placement::TOP_LEFT:
1431 case Placement::BOTTOM_LEFT:
1432 case Placement::LEFT_TOP:
1433 case Placement::RIGHT_TOP:
1434 propArrowOffset_ = ARROW_ZERO_PERCENT_VALUE;
1435 break;
1436 case Placement::TOP_RIGHT:
1437 case Placement::BOTTOM_RIGHT:
1438 case Placement::LEFT_BOTTOM:
1439 case Placement::RIGHT_BOTTOM:
1440 propArrowOffset_ = ARROW_ONE_HUNDRED_PERCENT_VALUE;
1441 break;
1442 default:
1443 break;
1444 }
1445 }
1446
UpdateArrowOffsetWithMenuLimit(const SizeF & menuSize)1447 void MenuLayoutAlgorithm::UpdateArrowOffsetWithMenuLimit(const SizeF& menuSize)
1448 {
1449 UpdatePropArrowOffset();
1450
1451 if (setHorizontal_.find(arrowPlacement_) != setHorizontal_.end()) {
1452 if (menuSize.Height() >= menuRadius_ * 2 + arrowWidth_) {
1453 float range = menuSize.Height() - menuRadius_ * 2 - arrowWidth_;
1454 float tempOffset = propArrowOffset_.Unit() == DimensionUnit::PERCENT ? propArrowOffset_.Value() * range :
1455 propArrowOffset_.ConvertToPx();
1456 arrowOffset_ = std::clamp(tempOffset, 0.0f, range);
1457 }
1458 }
1459
1460 if (setVertical_.find(arrowPlacement_) != setVertical_.end()) {
1461 if (menuSize.Width() >= menuRadius_ * 2 + arrowWidth_) {
1462 arrowInMenu_ = true;
1463 float range = menuSize.Width() - menuRadius_ * 2 - arrowWidth_;
1464 float tempOffset = propArrowOffset_.Unit() == DimensionUnit::PERCENT ? propArrowOffset_.Value() * range :
1465 propArrowOffset_.ConvertToPx();
1466 arrowOffset_ = std::clamp(tempOffset, 0.0f, range);
1467 }
1468 }
1469 }
1470
ComputeMenuPositionByAlignType(const RefPtr<MenuLayoutProperty> & menuProp,const SizeF & menuSize)1471 void MenuLayoutAlgorithm::ComputeMenuPositionByAlignType(
1472 const RefPtr<MenuLayoutProperty>& menuProp, const SizeF& menuSize)
1473 {
1474 auto alignType = menuProp->GetAlignType().value_or(MenuAlignType::START);
1475 auto targetSize = menuProp->GetTargetSizeValue(SizeF());
1476 switch (alignType) {
1477 case MenuAlignType::CENTER: {
1478 position_.AddX(targetSize.Width() / 2.0f - menuSize.Width() / 2.0f);
1479 break;
1480 }
1481 case MenuAlignType::END: {
1482 position_.AddX(targetSize.Width() - menuSize.Width());
1483 break;
1484 }
1485 default:
1486 break;
1487 }
1488 }
1489
ComputeMenuPositionByOffset(const RefPtr<MenuLayoutProperty> & menuProp,const RefPtr<GeometryNode> & geometryNode)1490 OffsetF MenuLayoutAlgorithm::ComputeMenuPositionByOffset(
1491 const RefPtr<MenuLayoutProperty>& menuProp, const RefPtr<GeometryNode>& geometryNode)
1492 {
1493 CHECK_NULL_RETURN(menuProp, OffsetF(0, 0));
1494 CHECK_NULL_RETURN(geometryNode, OffsetF(0, 0));
1495
1496 const auto& layoutConstraint = menuProp->GetLayoutConstraint();
1497 CHECK_NULL_RETURN(layoutConstraint, OffsetF(0, 0));
1498 auto menuAlignOffset = menuProp->GetOffset().value_or(
1499 DimensionOffset(Dimension(0, DimensionUnit::VP), Dimension(0, DimensionUnit::VP)));
1500
1501 auto menuSize = geometryNode->GetFrameSize();
1502 auto menuTrimOffsetX =
1503 ConvertToPx(CalcLength(menuAlignOffset.GetX()), layoutConstraint->scaleProperty, menuSize.Width());
1504 auto menuTrimOffsetY =
1505 ConvertToPx(CalcLength(menuAlignOffset.GetY()), layoutConstraint->scaleProperty, menuSize.Height());
1506 OffsetF menuTrimOffset = OffsetF(menuTrimOffsetX.value_or(0.0), menuTrimOffsetY.value_or(0.0));
1507 return menuTrimOffset;
1508 }
1509
GetCurrentPipelineContext()1510 RefPtr<PipelineContext> MenuLayoutAlgorithm::GetCurrentPipelineContext()
1511 {
1512 auto containerId = Container::CurrentId();
1513 RefPtr<PipelineContext> context;
1514 if (containerId >= MIN_SUBCONTAINER_ID) {
1515 auto parentContainerId = SubwindowManager::GetInstance()->GetParentContainerId(containerId);
1516 auto parentContainer = AceEngine::Get().GetContainer(parentContainerId);
1517 CHECK_NULL_RETURN(parentContainer, nullptr);
1518 context = DynamicCast<PipelineContext>(parentContainer->GetPipelineContext());
1519 } else {
1520 context = PipelineContext::GetCurrentContext();
1521 }
1522 return context;
1523 }
1524
MenuLayoutAvoidAlgorithm(const RefPtr<MenuLayoutProperty> & menuProp,const RefPtr<MenuPattern> & menuPattern,const SizeF & size,bool didNeedArrow)1525 OffsetF MenuLayoutAlgorithm::MenuLayoutAvoidAlgorithm(const RefPtr<MenuLayoutProperty>& menuProp,
1526 const RefPtr<MenuPattern>& menuPattern, const SizeF& size, bool didNeedArrow)
1527 {
1528 auto pipelineContext = GetCurrentPipelineContext();
1529 CHECK_NULL_RETURN(pipelineContext, OffsetF(0, 0));
1530 CHECK_NULL_RETURN(menuProp, OffsetF(0, 0));
1531 CHECK_NULL_RETURN(menuPattern, OffsetF(0, 0));
1532 float x = 0.0f;
1533 float y = 0.0f;
1534 if (menuProp->GetMenuPlacement().has_value() && (targetSize_.Width() > 0.0 || targetSize_.Height() > 0.0)) {
1535 placement_ = menuProp->GetMenuPlacement().value();
1536 auto childOffset = GetChildPosition(size, didNeedArrow);
1537 x = childOffset.GetX();
1538 y = childOffset.GetY();
1539 } else {
1540 x = HorizontalLayout(size, position_.GetX(), menuPattern->IsSelectMenu()) + positionOffset_.GetX();
1541 y = VerticalLayout(size, position_.GetY(), menuPattern->IsContextMenu()) + positionOffset_.GetY();
1542 }
1543 x = std::clamp(static_cast<double>(x), static_cast<double>(paddingStart_),
1544 static_cast<double>(wrapperRect_.Right() - size.Width() - paddingEnd_));
1545 float yMinAvoid = wrapperRect_.Top() + paddingTop_;
1546 float yMaxAvoid = wrapperRect_.Bottom() - paddingBottom_ - size.Height();
1547 y = std::clamp(y, yMinAvoid, yMaxAvoid);
1548 return { x, y };
1549 }
1550
LimitContainerModalMenuRect(double & rectWidth,double & rectHeight)1551 void MenuLayoutAlgorithm::LimitContainerModalMenuRect(double& rectWidth, double& rectHeight)
1552 {
1553 auto containerOffsetX = static_cast<float>(CONTAINER_BORDER_WIDTH.ConvertToPx()) +
1554 static_cast<float>(CONTAINER_BORDER_WIDTH.ConvertToPx()) +
1555 static_cast<float>(CONTENT_PADDING.ConvertToPx());
1556 auto containerOffsetY = static_cast<float>(CONTAINER_TITLE_HEIGHT.ConvertToPx()) +
1557 static_cast<float>(CONTAINER_BORDER_WIDTH.ConvertToPx()) +
1558 static_cast<float>(CONTAINER_BORDER_WIDTH.ConvertToPx());
1559 rectWidth -= containerOffsetX;
1560 rectHeight -= containerOffsetY;
1561 }
1562
UpdateConstraintWidth(LayoutWrapper * layoutWrapper,LayoutConstraintF & constraint)1563 void MenuLayoutAlgorithm::UpdateConstraintWidth(LayoutWrapper* layoutWrapper, LayoutConstraintF& constraint)
1564 {
1565 RefPtr<GridColumnInfo> columnInfo;
1566 columnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::MENU);
1567 auto menuNode = layoutWrapper->GetHostNode();
1568 CHECK_NULL_VOID(menuNode);
1569 auto menuPattern = menuNode->GetPattern<MenuPattern>();
1570 CHECK_NULL_VOID(menuPattern);
1571 if (menuPattern && menuPattern->IsSelectOverlayExtensionMenu()) {
1572 columnInfo->GetParent()->BuildColumnWidth();
1573 } else {
1574 columnInfo->GetParent()->BuildColumnWidth(wrapperSize_.Width());
1575 }
1576 auto menuLayoutProperty = AceType::DynamicCast<MenuLayoutProperty>(layoutWrapper->GetLayoutProperty());
1577 CHECK_NULL_VOID(menuLayoutProperty);
1578 // set max width
1579 const auto& padding = menuLayoutProperty->CreatePaddingAndBorder();
1580 auto maxHorizontalSpace = std::max(leftSpace_, rightSpace_) - 2.0f * padding.Width();
1581 auto maxWidth = static_cast<float>(columnInfo->GetWidth(GetMaxGridCounts(columnInfo)));
1582 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
1583 maxWidth = std::min(maxHorizontalSpace, maxWidth);
1584 }
1585 maxWidth = std::min(constraint.maxSize.Width(), maxWidth);
1586 constraint.maxSize.SetWidth(maxWidth);
1587 }
1588
UpdateConstraintHeight(LayoutWrapper * layoutWrapper,LayoutConstraintF & constraint)1589 void MenuLayoutAlgorithm::UpdateConstraintHeight(LayoutWrapper* layoutWrapper, LayoutConstraintF& constraint)
1590 {
1591 auto pipelineContext = GetCurrentPipelineContext();
1592 CHECK_NULL_VOID(pipelineContext);
1593 auto menuPattern = layoutWrapper->GetHostNode()->GetPattern<MenuPattern>();
1594 CHECK_NULL_VOID(menuPattern);
1595
1596 float maxAvailableHeight = wrapperRect_.Height();
1597 float maxSpaceHeight = maxAvailableHeight * HEIGHT_CONSTRAINT_FACTOR;
1598 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
1599 if (menuPattern->IsHeightModifiedBySelect()) {
1600 auto menuLayoutProps = AceType::DynamicCast<MenuLayoutProperty>(layoutWrapper->GetLayoutProperty());
1601 auto selectModifiedHeight = menuLayoutProps->GetSelectModifiedHeight().value();
1602 if (selectModifiedHeight < maxSpaceHeight) {
1603 maxSpaceHeight = selectModifiedHeight;
1604 }
1605 }
1606 }
1607 constraint.maxSize.SetHeight(maxSpaceHeight);
1608 }
1609
CreateChildConstraint(LayoutWrapper * layoutWrapper)1610 LayoutConstraintF MenuLayoutAlgorithm::CreateChildConstraint(LayoutWrapper* layoutWrapper)
1611 {
1612 auto menuLayoutProperty = AceType::DynamicCast<MenuLayoutProperty>(layoutWrapper->GetLayoutProperty());
1613 CHECK_NULL_RETURN(menuLayoutProperty, LayoutConstraintF());
1614
1615 auto childConstraint = menuLayoutProperty->CreateChildConstraint();
1616 UpdateConstraintWidth(layoutWrapper, childConstraint);
1617 UpdateConstraintHeight(layoutWrapper, childConstraint);
1618 UpdateConstraintBaseOnOptions(layoutWrapper, childConstraint);
1619 return childConstraint;
1620 }
1621
UpdateConstraintBaseOnOptions(LayoutWrapper * layoutWrapper,LayoutConstraintF & constraint)1622 void MenuLayoutAlgorithm::UpdateConstraintBaseOnOptions(LayoutWrapper* layoutWrapper, LayoutConstraintF& constraint)
1623 {
1624 auto menuNode = layoutWrapper->GetHostNode();
1625 CHECK_NULL_VOID(menuNode);
1626 auto menuPattern = menuNode->GetPattern<MenuPattern>();
1627 CHECK_NULL_VOID(menuPattern);
1628 auto options = menuPattern->GetOptions();
1629 if (options.empty()) {
1630 return;
1631 }
1632 auto optionConstraint = constraint;
1633 RefPtr<GridColumnInfo> columnInfo;
1634 columnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::MENU);
1635 columnInfo->GetParent()->BuildColumnWidth(wrapperSize_.Width());
1636 auto minWidth = static_cast<float>(columnInfo->GetWidth(MIN_GRID_COUNTS));
1637 optionConstraint.maxSize.MinusWidth(optionPadding_ * 2.0f);
1638 optionConstraint.minSize.SetWidth(minWidth - optionPadding_ * 2.0f);
1639 auto maxChildrenWidth = optionConstraint.minSize.Width();
1640 auto optionsLayoutWrapper = GetOptionsLayoutWrappper(layoutWrapper);
1641 for (const auto& optionWrapper : optionsLayoutWrapper) {
1642 optionWrapper->GetLayoutProperty()->ResetCalcMinSize();
1643 optionWrapper->Measure(optionConstraint);
1644 auto childSize = optionWrapper->GetGeometryNode()->GetMarginFrameSize();
1645 maxChildrenWidth = std::max(maxChildrenWidth, childSize.Width());
1646 }
1647 if (menuPattern->IsSelectOverlayExtensionMenu()) {
1648 maxChildrenWidth = std::min(maxChildrenWidth, optionConstraint.maxSize.Width());
1649 UpdateOptionConstraint(optionsLayoutWrapper, maxChildrenWidth);
1650 constraint.minSize.SetWidth(maxChildrenWidth);
1651 return;
1652 }
1653 UpdateOptionConstraint(optionsLayoutWrapper, maxChildrenWidth);
1654 constraint.minSize.SetWidth(maxChildrenWidth + optionPadding_ * 2.0f);
1655 }
1656
GetOptionsLayoutWrappper(LayoutWrapper * layoutWrapper)1657 std::list<RefPtr<LayoutWrapper>> MenuLayoutAlgorithm::GetOptionsLayoutWrappper(LayoutWrapper* layoutWrapper)
1658 {
1659 std::list<RefPtr<LayoutWrapper>> optionsWrapper;
1660 auto scrollWrapper = layoutWrapper->GetOrCreateChildByIndex(0);
1661 CHECK_NULL_RETURN(scrollWrapper, optionsWrapper);
1662 auto columnWrapper = scrollWrapper->GetOrCreateChildByIndex(0);
1663 CHECK_NULL_RETURN(columnWrapper, optionsWrapper);
1664 optionsWrapper = columnWrapper->GetAllChildrenWithBuild();
1665 return optionsWrapper;
1666 }
1667
UpdateOptionConstraint(std::list<RefPtr<LayoutWrapper>> & options,float width)1668 void MenuLayoutAlgorithm::UpdateOptionConstraint(std::list<RefPtr<LayoutWrapper>>& options, float width)
1669 {
1670 for (const auto& option : options) {
1671 auto optionLayoutProps = option->GetLayoutProperty();
1672 CHECK_NULL_VOID(optionLayoutProps);
1673 optionLayoutProps->UpdateCalcMinSize(CalcSize(CalcLength(width), std::nullopt));
1674 }
1675 }
1676
1677 // return vertical offset
VerticalLayout(const SizeF & size,float position,bool isContextMenu)1678 float MenuLayoutAlgorithm::VerticalLayout(const SizeF &size, float position, bool isContextMenu)
1679 {
1680 placement_ = Placement::BOTTOM;
1681 // can put menu below click point
1682 if (GreatOrEqual(bottomSpace_, size.Height())) {
1683 return position + margin_;
1684 }
1685 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) && isContextMenu) {
1686 if (LessNotEqual(bottomSpace_, size.Height()) && LessNotEqual(size.Height(), wrapperRect_.Height())) {
1687 return wrapperRect_.Bottom() - size.Height() - paddingBottom_;
1688 }
1689 // can't fit in screen, line up with top of the screen
1690 return wrapperRect_.Top() + paddingTop_;
1691 } else {
1692 float wrapperHeight = wrapperSize_.Height();
1693 // put menu above click point
1694 if (GreatOrEqual(topSpace_, size.Height())) {
1695 // menu show on top
1696 placement_ = Placement::TOP;
1697 return topSpace_ - size.Height() + margin_;
1698 }
1699 // line up bottom of menu with bottom of the screen
1700 if (LessNotEqual(size.Height(), wrapperHeight)) {
1701 return wrapperHeight - size.Height();
1702 }
1703 // can't fit in screen, line up with top of the screen
1704 return 0.0f;
1705 }
1706 }
1707
1708 // returns horizontal offset
HorizontalLayout(const SizeF & size,float position,bool isSelectMenu)1709 float MenuLayoutAlgorithm::HorizontalLayout(const SizeF& size, float position, bool isSelectMenu)
1710 {
1711 float wrapperWidth = wrapperSize_.Width();
1712 // can fit menu on the right side of position
1713 if (rightSpace_ >= size.Width()) {
1714 return position + margin_;
1715 }
1716
1717 // fit menu on the left side
1718 if (!isSelectMenu && leftSpace_ >= size.Width()) {
1719 return position - size.Width();
1720 }
1721
1722 // line up right side of menu with right boundary of the screen
1723 if (size.Width() < wrapperWidth) {
1724 if (isSelectMenu) {
1725 return position;
1726 }
1727 return wrapperWidth - size.Width();
1728 }
1729
1730 // can't fit in screen, line up with left side of the screen
1731 return 0.0f;
1732 }
1733
GetPositionWithPlacement(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition)1734 OffsetF MenuLayoutAlgorithm::GetPositionWithPlacement(
1735 const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition)
1736 {
1737 OffsetF childPosition;
1738
1739 auto func = placementFuncMap_.find(placement_);
1740 if (func != placementFuncMap_.end()) {
1741 auto placementFunc = func->second;
1742 if (placementFunc != nullptr) {
1743 childPosition = (this->*placementFunc)(childSize, topPosition, bottomPosition);
1744 }
1745 }
1746 return childPosition;
1747 }
1748
GetArrowPositionWithPlacement(const SizeF & menuSize)1749 OffsetF MenuLayoutAlgorithm::GetArrowPositionWithPlacement(const SizeF& menuSize)
1750 {
1751 UpdateArrowOffsetWithMenuLimit(menuSize);
1752 auto addArrowOffsetToArrowMin = arrowOffset_ + arrowMinLimit_;
1753 auto space_ = ARROW_HIGHT.ConvertToPx();
1754 OffsetF childPosition;
1755 switch (arrowPlacement_) {
1756 case Placement::TOP:
1757 case Placement::TOP_LEFT:
1758 case Placement::TOP_RIGHT:
1759 childPosition = OffsetF(addArrowOffsetToArrowMin, menuSize.Height() + space_);
1760 break;
1761 case Placement::BOTTOM:
1762 case Placement::BOTTOM_LEFT:
1763 case Placement::BOTTOM_RIGHT:
1764 childPosition = OffsetF(addArrowOffsetToArrowMin, -space_);
1765 break;
1766 case Placement::LEFT:
1767 case Placement::LEFT_TOP:
1768 case Placement::LEFT_BOTTOM:
1769 childPosition = OffsetF(menuSize.Width() + space_, addArrowOffsetToArrowMin);
1770 break;
1771 case Placement::RIGHT:
1772 case Placement::RIGHT_TOP:
1773 case Placement::RIGHT_BOTTOM:
1774 childPosition = OffsetF(-space_, addArrowOffsetToArrowMin);
1775 break;
1776 default:
1777 break;
1778 }
1779 return childPosition;
1780 }
1781
GetMenuWrapperOffset(const LayoutWrapper * layoutWrapper)1782 OffsetF MenuLayoutAlgorithm::GetMenuWrapperOffset(const LayoutWrapper* layoutWrapper)
1783 {
1784 CHECK_NULL_RETURN(layoutWrapper, OffsetF());
1785 auto menuNode = layoutWrapper->GetHostNode();
1786 CHECK_NULL_RETURN(menuNode, OffsetF());
1787 return menuNode->GetParentGlobalOffsetDuringLayout();
1788 }
1789
InitTargetSizeAndPosition(const LayoutWrapper * layoutWrapper,bool isContextMenu,const RefPtr<MenuPattern> & menuPattern)1790 void MenuLayoutAlgorithm::InitTargetSizeAndPosition(
1791 const LayoutWrapper* layoutWrapper, bool isContextMenu, const RefPtr<MenuPattern>& menuPattern)
1792 {
1793 CHECK_NULL_VOID(layoutWrapper);
1794 CHECK_NULL_VOID(menuPattern);
1795 auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
1796 CHECK_NULL_VOID(targetNode);
1797 auto geometryNode = targetNode->GetGeometryNode();
1798 CHECK_NULL_VOID(geometryNode);
1799 auto props = AceType::DynamicCast<MenuLayoutProperty>(layoutWrapper->GetLayoutProperty());
1800 CHECK_NULL_VOID(props);
1801 bool expandDisplay = menuPattern->GetMenuExpandDisplay();
1802 if (props->GetIsRectInTargetValue(false)) {
1803 targetSize_ = props->GetTargetSizeValue(SizeF());
1804 targetOffset_ = props->GetMenuOffsetValue(OffsetF());
1805 } else {
1806 targetSize_ = geometryNode->GetFrameSize();
1807 targetOffset_ = targetNode->GetPaintRectOffset();
1808 }
1809 menuPattern->SetTargetSize(targetSize_);
1810 auto pipelineContext = GetCurrentPipelineContext();
1811 CHECK_NULL_VOID(pipelineContext);
1812 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
1813 expandDisplay = true;
1814 }
1815 if (((isContextMenu && expandDisplay) || hierarchicalParameters_) && (targetTag_ != V2::SELECT_ETS_TAG)) {
1816 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
1817 float windowsOffsetX = static_cast<float>(windowGlobalRect.GetOffset().GetX());
1818 float windowsOffsetY = static_cast<float>(windowGlobalRect.GetOffset().GetY());
1819 targetOffset_ += OffsetF(windowsOffsetX, windowsOffsetY);
1820 OffsetF offset = GetMenuWrapperOffset(layoutWrapper);
1821 targetOffset_ -= offset;
1822 return;
1823 }
1824
1825 auto windowManager = pipelineContext->GetWindowManager();
1826 auto isContainerModal = pipelineContext->GetWindowModal() == WindowModal::CONTAINER_MODAL && windowManager &&
1827 windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING;
1828 if (isContainerModal) {
1829 auto newOffsetX = static_cast<float>(CONTAINER_BORDER_WIDTH.ConvertToPx()) +
1830 static_cast<float>(CONTENT_PADDING.ConvertToPx());
1831 auto newOffsetY = static_cast<float>(CONTAINER_TITLE_HEIGHT.ConvertToPx()) +
1832 static_cast<float>(CONTAINER_BORDER_WIDTH.ConvertToPx());
1833 targetOffset_ -= OffsetF(newOffsetX, newOffsetY);
1834 } else {
1835 OffsetF offset = GetMenuWrapperOffset(layoutWrapper);
1836 targetOffset_ -= offset;
1837 }
1838 }
1839
FitToScreen(const OffsetF & position,const SizeF & childSize,bool didNeedArrow)1840 OffsetF MenuLayoutAlgorithm::FitToScreen(const OffsetF& position, const SizeF& childSize, bool didNeedArrow)
1841 {
1842 OffsetF afterOffsetPosition;
1843 auto originPosition = position;
1844
1845 if (NearEqual(positionOffset_, OffsetF(0.0f, 0.0f)) && (!didNeedArrow || arrowPlacement_ == Placement::NONE)) {
1846 afterOffsetPosition = AddTargetSpace(originPosition);
1847 } else {
1848 afterOffsetPosition = AddOffset(originPosition);
1849 }
1850
1851 if (!CheckPosition(afterOffsetPosition, childSize)) {
1852 return OffsetF(0.0f, 0.0f);
1853 }
1854
1855 return afterOffsetPosition;
1856 }
1857
GetChildPosition(const SizeF & childSize,bool didNeedArrow)1858 OffsetF MenuLayoutAlgorithm::GetChildPosition(const SizeF& childSize, bool didNeedArrow)
1859 {
1860 OffsetF bottomPosition = OffsetF(targetOffset_.GetX() + (targetSize_.Width() - childSize.Width()) / 2.0,
1861 targetOffset_.GetY() + targetSize_.Height() + targetSpace_);
1862 OffsetF topPosition = OffsetF(targetOffset_.GetX() + (targetSize_.Width() - childSize.Width()) / 2.0,
1863 targetOffset_.GetY() - childSize.Height() - targetSpace_);
1864 OffsetF defaultPosition = OffsetF(targetOffset_.GetX() + (targetSize_.Width() - childSize.Width()) / 2.0,
1865 targetOffset_.GetY() + (targetSize_.Height() - childSize.Height()) / 2.0);
1866
1867 OffsetF childPosition;
1868 OffsetF position = defaultPosition;
1869 auto positionOffset = positionOffset_;
1870 std::vector<Placement> currentPlacementStates = PLACEMENT_STATES.find(Placement::BOTTOM_LEFT)->second;
1871 if (PLACEMENT_STATES.find(placement_) != PLACEMENT_STATES.end()) {
1872 currentPlacementStates = PLACEMENT_STATES.find(placement_)->second;
1873 }
1874 size_t step = ALIGNMENT_STEP_OFFSET;
1875 if (placement_ <= Placement::BOTTOM) {
1876 step += 1;
1877 }
1878 for (size_t i = 0, len = currentPlacementStates.size(); i < len; i++) {
1879 placement_ = currentPlacementStates[i];
1880 if (placement_ == Placement::NONE) {
1881 break;
1882 }
1883 if (i >= step) {
1884 positionOffset_ = OffsetF(0.0f, 0.0f);
1885 }
1886 childPosition = GetPositionWithPlacement(childSize, topPosition, bottomPosition);
1887 position = FitToScreen(childPosition, childSize, didNeedArrow);
1888 if (NearEqual(position, OffsetF(0.0f, 0.0f))) {
1889 continue;
1890 }
1891 break;
1892 }
1893 if (placement_ == Placement::NONE) {
1894 position = GetAdjustPosition(currentPlacementStates, step, childSize, topPosition, bottomPosition);
1895 if (NearEqual(position, OffsetF(0.0f, 0.0f))) {
1896 position = defaultPosition;
1897 }
1898 }
1899 positionOffset_ = positionOffset;
1900 arrowPlacement_ = placement_;
1901
1902 return position;
1903 }
1904
GetAdjustPosition(std::vector<Placement> & currentPlacementStates,size_t step,const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition)1905 OffsetF MenuLayoutAlgorithm::GetAdjustPosition(std::vector<Placement>& currentPlacementStates, size_t step,
1906 const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition)
1907 {
1908 OffsetF childPosition;
1909 OffsetF position;
1910 for (size_t i = 0, len = currentPlacementStates.size(); i < len;) {
1911 placement_ = currentPlacementStates[i];
1912 if (placement_ == Placement::NONE) {
1913 break;
1914 }
1915 childPosition = GetPositionWithPlacement(childSize, topPosition, bottomPosition);
1916 position = AdjustPosition(childPosition, childSize.Width(), childSize.Height(), targetSecurity_);
1917 if (NearEqual(position, OffsetF(0.0f, 0.0f))) {
1918 i += step;
1919 continue;
1920 }
1921 break;
1922 }
1923 return position;
1924 }
1925
AdjustPosition(const OffsetF & position,float width,float height,float space)1926 OffsetF MenuLayoutAlgorithm::AdjustPosition(const OffsetF& position, float width, float height, float space)
1927 {
1928 float xMax = 0.0f;
1929 float yMax = 0.0f;
1930 float xMin = paddingStart_;
1931 float yMin = std::max(1.0f, static_cast<float>(wrapperRect_.Top()) + paddingTop_);
1932 float wrapperBottom = wrapperRect_.Bottom();
1933 switch (placement_) {
1934 case Placement::LEFT_TOP:
1935 case Placement::LEFT_BOTTOM:
1936 case Placement::LEFT: {
1937 xMax = std::min(targetOffset_.GetX() - width - space, wrapperSize_.Width() - paddingEnd_ - width);
1938 yMax = wrapperBottom - height - paddingBottom_;
1939 break;
1940 }
1941 case Placement::RIGHT_TOP:
1942 case Placement::RIGHT_BOTTOM:
1943 case Placement::RIGHT: {
1944 xMin = std::max(targetOffset_.GetX() + targetSize_.Width() + space, paddingStart_);
1945 xMax = wrapperSize_.Width() - width - paddingEnd_;
1946 yMax = wrapperBottom - height - paddingBottom_;
1947 break;
1948 }
1949 case Placement::TOP_LEFT:
1950 case Placement::TOP_RIGHT:
1951 case Placement::TOP: {
1952 xMax = wrapperSize_.Width() - width - paddingEnd_;
1953 yMax = std::min(targetOffset_.GetY() - height - space, wrapperBottom - paddingBottom_ - height);
1954 break;
1955 }
1956 case Placement::BOTTOM_LEFT:
1957 case Placement::BOTTOM_RIGHT:
1958 case Placement::BOTTOM: {
1959 xMax = wrapperSize_.Width() - width - paddingEnd_;
1960 yMin = std::max(targetOffset_.GetY() + targetSize_.Height() + space, yMin);
1961 yMax = wrapperBottom - height - paddingBottom_;
1962 break;
1963 }
1964 default:
1965 break;
1966 }
1967 if (xMax < xMin || yMax < yMin) {
1968 return OffsetF(0.0f, 0.0f);
1969 }
1970 auto x = std::clamp(position.GetX(), xMin, xMax);
1971 auto y = std::clamp(position.GetY(), yMin, yMax);
1972 return OffsetF(x, y);
1973 }
1974
AddTargetSpace(const OffsetF & position)1975 OffsetF MenuLayoutAlgorithm::AddTargetSpace(const OffsetF& position)
1976 {
1977 auto x = position.GetX();
1978 auto y = position.GetY();
1979 switch (placement_) {
1980 case Placement::BOTTOM_LEFT:
1981 case Placement::BOTTOM_RIGHT:
1982 case Placement::BOTTOM: {
1983 y += targetSecurity_;
1984 break;
1985 }
1986 case Placement::TOP_LEFT:
1987 case Placement::TOP_RIGHT:
1988 case Placement::TOP: {
1989 y -= targetSecurity_;
1990 break;
1991 }
1992 case Placement::RIGHT_TOP:
1993 case Placement::RIGHT_BOTTOM:
1994 case Placement::RIGHT: {
1995 x += targetSecurity_;
1996 break;
1997 }
1998 case Placement::LEFT_TOP:
1999 case Placement::LEFT_BOTTOM:
2000 case Placement::LEFT: {
2001 x -= targetSecurity_;
2002 break;
2003 }
2004 default: {
2005 y += targetSecurity_;
2006 break;
2007 }
2008 }
2009 return OffsetF(x, y);
2010 }
2011
AddOffset(const OffsetF & position)2012 OffsetF MenuLayoutAlgorithm::AddOffset(const OffsetF& position)
2013 {
2014 auto x = position.GetX();
2015 auto y = position.GetY();
2016 switch (placement_) {
2017 case Placement::BOTTOM_LEFT:
2018 case Placement::BOTTOM_RIGHT:
2019 case Placement::BOTTOM: {
2020 x += positionOffset_.GetX();
2021 y += positionOffset_.GetY();
2022 break;
2023 }
2024 case Placement::TOP_LEFT:
2025 case Placement::TOP_RIGHT:
2026 case Placement::TOP: {
2027 x += positionOffset_.GetX();
2028 y -= positionOffset_.GetY();
2029 break;
2030 }
2031 case Placement::RIGHT_TOP:
2032 case Placement::RIGHT_BOTTOM:
2033 case Placement::RIGHT: {
2034 x += positionOffset_.GetX();
2035 y += positionOffset_.GetY();
2036 break;
2037 }
2038 case Placement::LEFT_TOP:
2039 case Placement::LEFT_BOTTOM:
2040 case Placement::LEFT: {
2041 x -= positionOffset_.GetX();
2042 y += positionOffset_.GetY();
2043 break;
2044 }
2045 default: {
2046 x += positionOffset_.GetX();
2047 y += positionOffset_.GetY();
2048 break;
2049 }
2050 }
2051 return OffsetF(x, y);
2052 }
2053
CheckPositionInPlacementRect(const Rect & rect,const OffsetF & position,const SizeF & childSize)2054 bool MenuLayoutAlgorithm::CheckPositionInPlacementRect(
2055 const Rect& rect, const OffsetF& position, const SizeF& childSize)
2056 {
2057 auto x = position.GetX();
2058 auto y = position.GetY();
2059 if (x < rect.Left() || (x + childSize.Width()) > rect.Right() || y < rect.Top() ||
2060 (y + childSize.Height()) > rect.Bottom()) {
2061 return false;
2062 }
2063 return true;
2064 }
2065
CheckPosition(const OffsetF & position,const SizeF & childSize)2066 bool MenuLayoutAlgorithm::CheckPosition(const OffsetF& position, const SizeF& childSize)
2067 {
2068 float targetOffsetX = targetOffset_.GetX();
2069 float targetOffsetY = targetOffset_.GetY();
2070 float yAvoid = wrapperRect_.Top() + paddingTop_;
2071 Rect rect;
2072 switch (placement_) {
2073 case Placement::BOTTOM_LEFT:
2074 case Placement::BOTTOM_RIGHT:
2075 case Placement::BOTTOM: {
2076 auto y = std::max(targetOffsetY + targetSize_.Height(), yAvoid);
2077 auto height = std::min(
2078 static_cast<float>(wrapperRect_.Bottom()) - paddingBottom_ - targetOffsetY - targetSize_.Height(),
2079 wrapperSize_.Height() - paddingBottom_ - paddingTop_);
2080 rect.SetRect(
2081 paddingStart_, y, wrapperSize_.Width() - paddingEnd_ - paddingStart_, height);
2082 break;
2083 }
2084 case Placement::TOP_LEFT:
2085 case Placement::TOP_RIGHT:
2086 case Placement::TOP: {
2087 auto height = std::min(targetOffsetY - yAvoid, wrapperSize_.Height() - paddingTop_ - paddingBottom_);
2088 rect.SetRect(paddingStart_, yAvoid, wrapperSize_.Width() - paddingEnd_ - paddingStart_, height);
2089 break;
2090 }
2091 case Placement::RIGHT_TOP:
2092 case Placement::RIGHT_BOTTOM:
2093 case Placement::RIGHT: {
2094 auto x = std::max(targetOffsetX + targetSize_.Width(), paddingStart_);
2095 auto width = std::min(wrapperSize_.Width() - targetOffsetX - targetSize_.Width() - paddingEnd_,
2096 wrapperSize_.Width() - paddingStart_ - paddingEnd_);
2097 rect.SetRect(x, yAvoid, width, wrapperSize_.Height() - paddingBottom_ - paddingTop_);
2098 break;
2099 }
2100 case Placement::LEFT_TOP:
2101 case Placement::LEFT_BOTTOM:
2102 case Placement::LEFT: {
2103 auto width = std::min(
2104 targetOffsetX - paddingStart_, wrapperSize_.Width() - paddingEnd_ - paddingStart_);
2105 rect.SetRect(paddingStart_, yAvoid, width, wrapperSize_.Height() - paddingBottom_ - paddingTop_);
2106 break;
2107 }
2108 default:
2109 return false;
2110 }
2111 return CheckPositionInPlacementRect(rect, position, childSize);
2112 }
2113
GetPositionWithPlacementTop(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition)2114 OffsetF MenuLayoutAlgorithm::GetPositionWithPlacementTop(
2115 const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition)
2116 {
2117 return topPosition;
2118 }
2119
GetPositionWithPlacementTopLeft(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition)2120 OffsetF MenuLayoutAlgorithm::GetPositionWithPlacementTopLeft(
2121 const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition)
2122 {
2123 OffsetF childPosition;
2124 float marginRight = 0.0f;
2125 float marginBottom = 0.0f;
2126 childPosition = OffsetF(targetOffset_.GetX() - marginRight,
2127 targetOffset_.GetY() - childSize.Height() - marginBottom - targetSpace_);
2128 return childPosition;
2129 }
2130
GetPositionWithPlacementTopRight(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition)2131 OffsetF MenuLayoutAlgorithm::GetPositionWithPlacementTopRight(
2132 const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition)
2133 {
2134 OffsetF childPosition;
2135 float marginBottom = 0.0f;
2136 float marginLeft = 0.0f;
2137 childPosition = OffsetF(targetOffset_.GetX() + targetSize_.Width() - childSize.Width() + marginLeft,
2138 targetOffset_.GetY() - childSize.Height() - targetSpace_ - marginBottom);
2139 return childPosition;
2140 }
2141
GetPositionWithPlacementBottom(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition)2142 OffsetF MenuLayoutAlgorithm::GetPositionWithPlacementBottom(
2143 const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition)
2144 {
2145 return bottomPosition;
2146 }
2147
GetPositionWithPlacementBottomLeft(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition)2148 OffsetF MenuLayoutAlgorithm::GetPositionWithPlacementBottomLeft(
2149 const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition)
2150 {
2151 OffsetF childPosition;
2152 float marginRight = 0.0f;
2153 float marginTop = 0.0f;
2154 childPosition = OffsetF(targetOffset_.GetX() - marginRight,
2155 targetOffset_.GetY() + targetSize_.Height() + targetSpace_ + marginTop);
2156 return childPosition;
2157 }
2158
GetPositionWithPlacementBottomRight(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition)2159 OffsetF MenuLayoutAlgorithm::GetPositionWithPlacementBottomRight(
2160 const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition)
2161 {
2162 OffsetF childPosition;
2163 float marginTop = 0.0f;
2164 float marginLeft = 0.0f;
2165 childPosition = OffsetF(targetOffset_.GetX() + targetSize_.Width() - childSize.Width() + marginLeft,
2166 targetOffset_.GetY() + targetSize_.Height() + targetSpace_ + marginTop);
2167 return childPosition;
2168 }
2169
GetPositionWithPlacementLeft(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition)2170 OffsetF MenuLayoutAlgorithm::GetPositionWithPlacementLeft(
2171 const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition)
2172 {
2173 OffsetF childPosition;
2174 float marginRight = 0.0f;
2175 childPosition =
2176 OffsetF(targetOffset_.GetX() - targetSpace_ - childSize.Width() - marginRight,
2177 targetOffset_.GetY() + targetSize_.Height() / 2.0 - childSize.Height() / 2.0);
2178 return childPosition;
2179 }
2180
GetPositionWithPlacementLeftTop(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition)2181 OffsetF MenuLayoutAlgorithm::GetPositionWithPlacementLeftTop(
2182 const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition)
2183 {
2184 OffsetF childPosition;
2185 float marginRight = 0.0f;
2186 float marginBottom = 0.0f;
2187 childPosition =
2188 OffsetF(targetOffset_.GetX() - targetSpace_ - childSize.Width() - marginRight,
2189 targetOffset_.GetY() - marginBottom);
2190 return childPosition;
2191 }
2192
GetPositionWithPlacementLeftBottom(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition)2193 OffsetF MenuLayoutAlgorithm::GetPositionWithPlacementLeftBottom(
2194 const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition)
2195 {
2196 OffsetF childPosition;
2197 float marginRight = 0.0f;
2198 float marginTop = 0.0f;
2199 childPosition =
2200 OffsetF(targetOffset_.GetX() - targetSpace_ - childSize.Width() - marginRight,
2201 targetOffset_.GetY() + targetSize_.Height() - childSize.Height() - marginTop);
2202 return childPosition;
2203 }
2204
GetPositionWithPlacementRight(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition)2205 OffsetF MenuLayoutAlgorithm::GetPositionWithPlacementRight(
2206 const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition)
2207 {
2208 OffsetF childPosition;
2209 float marginLeft = 0.0f;
2210 childPosition =
2211 OffsetF(targetOffset_.GetX() + targetSize_.Width() + targetSpace_ + marginLeft,
2212 targetOffset_.GetY() + targetSize_.Height() / 2.0 - childSize.Height() / 2.0);
2213 return childPosition;
2214 }
2215
GetPositionWithPlacementRightTop(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition)2216 OffsetF MenuLayoutAlgorithm::GetPositionWithPlacementRightTop(
2217 const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition)
2218 {
2219 OffsetF childPosition;
2220 float marginBottom = 0.0f;
2221 float marginLeft = 0.0f;
2222 childPosition =
2223 OffsetF(targetOffset_.GetX() + targetSize_.Width() + targetSpace_ + marginLeft,
2224 targetOffset_.GetY() - marginBottom);
2225 return childPosition;
2226 }
2227
GetPositionWithPlacementRightBottom(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition)2228 OffsetF MenuLayoutAlgorithm::GetPositionWithPlacementRightBottom(
2229 const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition)
2230 {
2231 OffsetF childPosition;
2232 float marginTop = 0.0f;
2233 float marginLeft = 0.0f;
2234 childPosition =
2235 OffsetF(targetOffset_.GetX() + targetSize_.Width() + targetSpace_ + marginLeft,
2236 targetOffset_.GetY() + targetSize_.Height() - childSize.Height() - marginTop);
2237 return childPosition;
2238 }
2239
InitHierarchicalParameters(bool isShowInSubWindow)2240 void MenuLayoutAlgorithm::InitHierarchicalParameters(bool isShowInSubWindow)
2241 {
2242 auto pipeline = PipelineBase::GetCurrentContext();
2243 CHECK_NULL_VOID(pipeline);
2244 auto theme = pipeline->GetTheme<SelectTheme>();
2245 CHECK_NULL_VOID(theme);
2246 auto expandDisplay = theme->GetExpandDisplay();
2247 if (expandDisplay && !isShowInSubWindow) {
2248 hierarchicalParameters_ = false;
2249 return;
2250 }
2251 hierarchicalParameters_ = expandDisplay;
2252 }
2253
2254 } // namespace OHOS::Ace::NG
2255