1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components_ng/pattern/menu/sub_menu_layout_algorithm.h"
17
18 #include "core/components/container_modal/container_modal_constants.h"
19 #include "core/components_ng/pattern/menu/menu_item/menu_item_pattern.h"
20 namespace OHOS::Ace::NG {
21 constexpr double MOUNT_MENU_FINAL_SCALE = 0.95f;
Layout(LayoutWrapper * layoutWrapper)22 void SubMenuLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
23 {
24 CHECK_NULL_VOID(layoutWrapper);
25 auto size = layoutWrapper->GetGeometryNode()->GetFrameSize();
26 auto menuNode = layoutWrapper->GetHostNode();
27 CHECK_NULL_VOID(menuNode);
28 auto menuPattern = menuNode->GetPattern<MenuPattern>();
29 CHECK_NULL_VOID(menuPattern);
30 auto props = AceType::DynamicCast<MenuLayoutProperty>(layoutWrapper->GetLayoutProperty());
31 CHECK_NULL_VOID(props);
32 auto parentMenuItem = menuPattern->GetParentMenuItem();
33 CHECK_NULL_VOID(parentMenuItem);
34 InitCanExpandCurrentWindow(props->GetShowInSubWindowValue(false), layoutWrapper);
35 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
36 ModifySubMenuWrapper(layoutWrapper);
37 }
38 CheckMenuPadding(layoutWrapper);
39 const auto& geometryNode = layoutWrapper->GetGeometryNode();
40 CHECK_NULL_VOID(geometryNode);
41 auto parentItemPattern = parentMenuItem->GetPattern<MenuItemPattern>();
42 CHECK_NULL_VOID(parentItemPattern);
43 auto expandingMode = parentItemPattern->GetExpandingMode();
44 OffsetF position = GetSubMenuLayoutOffset(layoutWrapper, parentMenuItem, size, expandingMode);
45 geometryNode->SetMarginFrameOffset(position);
46 if (parentMenuItem) {
47 UpdateHoverRegion(parentMenuItem, position, size);
48 }
49 auto child = layoutWrapper->GetOrCreateChildByIndex(0);
50 CHECK_NULL_VOID(child);
51 child->Layout();
52 ClipMenuPath(layoutWrapper);
53 }
54
UpdateHoverRegion(RefPtr<FrameNode> & parentMenuItem,const OffsetF & position,const SizeF & size)55 void SubMenuLayoutAlgorithm::UpdateHoverRegion(
56 RefPtr<FrameNode>& parentMenuItem, const OffsetF& position, const SizeF& size)
57 {
58 auto parentPattern = parentMenuItem->GetPattern<MenuItemPattern>();
59 CHECK_NULL_VOID(parentPattern);
60 auto bottomRightPoint = position + OffsetF(size.Width(), size.Height());
61 auto pipelineContext = parentMenuItem->GetContextWithCheck();
62 CHECK_NULL_VOID(pipelineContext);
63 auto isContainerModal = pipelineContext->GetWindowModal() == WindowModal::CONTAINER_MODAL;
64 OffsetF wrapperOffset;
65 if ((!canExpandCurrentWindow_) && isContainerModal) {
66 auto newOffsetX = static_cast<float>(CONTAINER_BORDER_WIDTH.ConvertToPx());
67 auto newOffsetY = static_cast<float>(pipelineContext->GetCustomTitleHeight().ConvertToPx()) +
68 static_cast<float>(CONTAINER_BORDER_WIDTH.ConvertToPx());
69 wrapperOffset = OffsetF(newOffsetX, newOffsetY);
70 }
71 parentPattern->AddHoverRegions(position + wrapperOffset, bottomRightPoint + wrapperOffset);
72 }
73
GetSubMenuLayoutOffset(LayoutWrapper * layoutWrapper,const RefPtr<FrameNode> & parentMenuItem,const SizeF & size,SubMenuExpandingMode expandingMode)74 OffsetF SubMenuLayoutAlgorithm::GetSubMenuLayoutOffset(LayoutWrapper* layoutWrapper,
75 const RefPtr<FrameNode>& parentMenuItem, const SizeF& size, SubMenuExpandingMode expandingMode)
76 {
77 OffsetF position;
78 auto layoutDirection = layoutWrapper->GetLayoutProperty()->GetNonAutoLayoutDirection();
79 position = MenuLayoutAvoidAlgorithm(parentMenuItem, size, expandingMode, layoutWrapper);
80 if (layoutDirection == TextDirection::RTL) {
81 position.SetX(wrapperSize_.Width() - position.GetX() - size.Width());
82 }
83 return position;
84 }
85
MenuLayoutAvoidAlgorithm(const RefPtr<FrameNode> & parentMenuItem,const SizeF & size,SubMenuExpandingMode expandingMode,LayoutWrapper * layoutWrapper)86 OffsetF SubMenuLayoutAlgorithm::MenuLayoutAvoidAlgorithm(const RefPtr<FrameNode>& parentMenuItem, const SizeF& size,
87 SubMenuExpandingMode expandingMode, LayoutWrapper* layoutWrapper)
88 {
89 auto pipelineContext = PipelineContext::GetMainPipelineContext();
90 CHECK_NULL_RETURN(pipelineContext, NG::OffsetF(0.0f, 0.0f));
91 auto menuItemSize = parentMenuItem->GetGeometryNode()->GetFrameSize();
92 position_ = GetSubMenuPosition(parentMenuItem, expandingMode);
93 bool stacked = expandingMode == SubMenuExpandingMode::STACK;
94 if (layoutWrapper != nullptr) {
95 auto menuLayoutProperty = layoutWrapper->GetLayoutProperty();
96 CHECK_NULL_RETURN(menuLayoutProperty, NG::OffsetF(0.0f, 0.0f));
97 auto layoutDirection = menuLayoutProperty->GetNonAutoLayoutDirection();
98 if (layoutDirection == TextDirection::RTL) {
99 float leftSpace = position_.GetX() - menuItemSize.Width();
100 position_ = OffsetF(wrapperSize_.Width() - leftSpace, position_.GetY());
101 }
102 }
103 float x = HorizontalLayoutSubMenu(size, position_.GetX(), menuItemSize);
104 x = std::clamp(x, paddingStart_, wrapperSize_.Width() - size.Width() - paddingEnd_);
105 float y = 0.0f;
106 if (canExpandCurrentWindow_ || !Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
107 y = VerticalLayoutSubMenu(size, position_.GetY(), menuItemSize, parentMenuItem, stacked, layoutWrapper);
108 } else {
109 y = VerticalLayoutSubMenuHalfScreen(size, position_.GetY(), menuItemSize, parentMenuItem, stacked,
110 layoutWrapper);
111 }
112 float yMinAvoid = wrapperRect_.Top() + paddingTop_;
113 float yMaxAvoid = wrapperRect_.Bottom() - paddingBottom_ - size.Height();
114 if (stacked) {
115 yMinAvoid = wrapperRect_.Top() + param_.topSecurity;
116 yMaxAvoid = wrapperRect_.Bottom() - param_.bottomSecurity - size.Height();
117 }
118 y = std::clamp(y, yMinAvoid, yMaxAvoid);
119 return NG::OffsetF(x, y);
120 }
121
GetSubMenuPosition(const RefPtr<FrameNode> & parentMenuItem,SubMenuExpandingMode expandingMode)122 OffsetF SubMenuLayoutAlgorithm::GetSubMenuPosition(
123 const RefPtr<FrameNode>& parentMenuItem, SubMenuExpandingMode expandingMode)
124 {
125 auto parentItemFrameSize = parentMenuItem->GetGeometryNode()->GetMarginFrameSize();
126 OffsetF position;
127 if (expandingMode == SubMenuExpandingMode::STACK) {
128 auto parentItemPattern = parentMenuItem->GetPattern<MenuItemPattern>();
129 if (parentItemPattern != nullptr) {
130 auto parentMenu = parentItemPattern->GetMenu();
131 position = parentMenu == nullptr
132 ? parentMenuItem->GetPaintRectOffset(false, true) + OffsetF(parentItemFrameSize.Width(), 0.0)
133 : OffsetF(parentMenu->GetPaintRectOffset(false, true).GetX(),
134 parentMenuItem->GetPaintRectOffset(false, true).GetY() +
135 parentItemFrameSize.Height()); // * 0.95
136 }
137 } else if (expandingMode == SubMenuExpandingMode::SIDE) {
138 auto pipeline = parentMenuItem->GetContext();
139 auto selectTheme = pipeline ? pipeline->GetTheme<SelectTheme>() : nullptr;
140 float contentPadding = selectTheme ? -static_cast<float>(selectTheme->GetMenuPadding().ConvertToPx()) : 0.0f;
141 position =
142 parentMenuItem->GetPaintRectOffset(false, true) + OffsetF(parentItemFrameSize.Width(), contentPadding);
143 } else {
144 position = parentMenuItem->GetPaintRectOffset(false, true) + OffsetF(parentItemFrameSize.Width(), 0.0);
145 }
146
147 auto pipelineContext = parentMenuItem->GetContextWithCheck();
148 CHECK_NULL_RETURN(pipelineContext, OffsetF());
149 auto isContainerModal = pipelineContext->GetWindowModal() == WindowModal::CONTAINER_MODAL;
150 if ((!canExpandCurrentWindow_) && isContainerModal) {
151 auto newOffsetX = static_cast<float>(CONTAINER_BORDER_WIDTH.ConvertToPx());
152 auto newOffsetY = static_cast<float>(pipelineContext->GetCustomTitleHeight().ConvertToPx()) +
153 static_cast<float>(CONTAINER_BORDER_WIDTH.ConvertToPx());
154 position -= OffsetF(newOffsetX, newOffsetY);
155 }
156 auto parentMenu = AceType::DynamicCast<FrameNode>(parentMenuItem->GetParent());
157 CHECK_NULL_RETURN(parentMenu, position);
158 auto scroll = AceType::DynamicCast<FrameNode>(parentMenu->GetParent());
159 CHECK_NULL_RETURN(scroll, position);
160 while (scroll && (scroll->GetTag() != V2::SCROLL_ETS_TAG)) {
161 scroll = AceType::DynamicCast<FrameNode>(scroll->GetParent());
162 }
163 CHECK_NULL_RETURN(scroll, position);
164 auto scrollGeometryNode = scroll->GetGeometryNode();
165 CHECK_NULL_RETURN(scrollGeometryNode, position);
166 auto scrollTop = scroll->GetPaintRectOffset(false, true).GetY();
167 auto scrollHeight = scrollGeometryNode->GetFrameSize().Height();
168 auto bottomOffset = scrollTop + scrollHeight;
169 if (parentMenuItem->GetPaintRectOffset(false, true).GetY() > bottomOffset) {
170 return scroll->GetPaintRectOffset(false, true) + OffsetF(parentItemFrameSize.Width(), 0.0);
171 }
172 return position;
173 }
174
CalcStackSubMenuPositionYHalfScreenWithPreview(const SizeF & size,const RefPtr<FrameNode> & parentMenu,LayoutWrapper * layoutWrapper)175 float SubMenuLayoutAlgorithm::CalcStackSubMenuPositionYHalfScreenWithPreview(
176 const SizeF& size,
177 const RefPtr<FrameNode>& parentMenu,
178 LayoutWrapper* layoutWrapper
179 )
180 {
181 CHECK_NULL_RETURN(layoutWrapper, 0.0f);
182 CHECK_NULL_RETURN(parentMenu, 0.0f);
183 auto parentMenuPattern = parentMenu->GetPattern<MenuPattern>();
184 CHECK_NULL_RETURN(parentMenuPattern, 0.0f);
185 auto parentPlacement = parentMenuPattern->GetLastPlacement().value_or(Placement::NONE);
186 auto firstItemBottomPositionY = GetFirstItemBottomPositionY(parentMenu);
187 float parentMenuBottomY = GetMenuBottomPositionY(parentMenu);
188 auto lastItemPositionY = GetLastItemTopPositionY(parentMenu);
189 auto containerModalOffsetY = GetContainerModalOffsetY(parentMenu);
190 //correct position when window modal is containerModal
191 if (isContainerModal(parentMenu)) {
192 firstItemBottomPositionY -= containerModalOffsetY;
193 parentMenuBottomY -= containerModalOffsetY;
194 lastItemPositionY -= containerModalOffsetY;
195 }
196 if (parentPlacement == Placement::TOP_LEFT || parentPlacement == Placement::TOP ||
197 parentPlacement == Placement::TOP_RIGHT) {
198 auto bottomSpace = parentMenuBottomY - position_.GetY();
199 if (bottomSpace >= size.Height()) {
200 return position_.GetY();
201 }
202 bottomSpace = lastItemPositionY - wrapperRect_.Top() - param_.topSecurity;
203 if (size.Height() <= bottomSpace) {
204 return lastItemPositionY - size.Height();
205 }
206 auto subMenuNode = layoutWrapper->GetHostNode();
207 CHECK_NULL_RETURN(subMenuNode, 0.0f);
208 auto subMenuPattern = subMenuNode->GetPattern<MenuPattern>();
209 CHECK_NULL_RETURN(subMenuPattern, 0.0f);
210 auto diffY = bottomSpace - size.Height();
211 subMenuPattern->SetTranslateYForStack(diffY);
212 return wrapperRect_.Top() + param_.topSecurity;
213 } else {
214 auto bottomSpace = wrapperRect_.Bottom() - param_.bottomSecurity - position_.GetY();
215 if (bottomSpace >= size.Height()) {
216 return position_.GetY();
217 }
218 bottomSpace = wrapperRect_.Bottom() - param_.bottomSecurity - firstItemBottomPositionY;
219 if (size.Height() <= bottomSpace) {
220 return wrapperRect_.Bottom() - param_.bottomSecurity - size.Height();
221 }
222 auto subMenuNode = layoutWrapper->GetHostNode();
223 CHECK_NULL_RETURN(subMenuNode, 0.0f);
224 auto subMenuPattern = subMenuNode->GetPattern<MenuPattern>();
225 CHECK_NULL_RETURN(subMenuPattern, 0.0f);
226 auto diffY = size.Height() - bottomSpace;
227 subMenuPattern->SetTranslateYForStack(diffY);
228 return wrapperRect_.Bottom() - param_.bottomSecurity - size.Height();
229 }
230 }
231
NormalizePositionY(const RefPtr<FrameNode> & frameNode,float menuTopPositionY,float positionY)232 float SubMenuLayoutAlgorithm::NormalizePositionY(const RefPtr<FrameNode>& frameNode, float menuTopPositionY,
233 float positionY)
234 {
235 CHECK_NULL_RETURN(frameNode, positionY);
236 auto pipeline = frameNode->GetContext();
237 CHECK_NULL_RETURN(pipeline, positionY);
238 auto theme = pipeline->GetTheme<SelectTheme>();
239 CHECK_NULL_RETURN(theme, positionY);
240 // only 2in1 device need fix position
241 auto expandDisplay = theme->GetExpandDisplay();
242 CHECK_NULL_RETURN(expandDisplay, positionY);
243 return menuTopPositionY + (positionY - menuTopPositionY) * MOUNT_MENU_FINAL_SCALE;
244 }
245
CalcStackSubMenuPositionYHalfScreen(const SizeF & size,const RefPtr<FrameNode> & parentMenu,const RefPtr<FrameNode> & parentMenuItem)246 float SubMenuLayoutAlgorithm::CalcStackSubMenuPositionYHalfScreen(
247 const SizeF& size, const RefPtr<FrameNode>& parentMenu, const RefPtr<FrameNode>& parentMenuItem
248 )
249 {
250 auto parentMenuPattern = parentMenu->GetPattern<MenuPattern>();
251 auto parentPlacement = parentMenuPattern->GetLastPlacement().value_or(Placement::NONE);
252 auto firstItemBottomPositionY = GetFirstItemBottomPositionY(parentMenu);
253 float parentMenuBottomY = GetMenuBottomPositionY(parentMenu);
254 float lastMenuItemPositionY = GetLastItemTopPositionY(parentMenu);
255 auto containerModalOffsetY = GetContainerModalOffsetY(parentMenu);
256 auto parentMenuPositionY = parentMenu->GetPaintRectOffset(false, true).GetY();
257 firstItemBottomPositionY = NormalizePositionY(parentMenu, parentMenuPositionY, firstItemBottomPositionY);
258 parentMenuBottomY = NormalizePositionY(parentMenu, parentMenuPositionY, parentMenuBottomY);
259 lastMenuItemPositionY = NormalizePositionY(parentMenu, parentMenuPositionY, lastMenuItemPositionY);
260 //correct position when window modal is containerModal
261 if (isContainerModal(parentMenu)) {
262 firstItemBottomPositionY -= containerModalOffsetY;
263 parentMenuBottomY -= containerModalOffsetY;
264 lastMenuItemPositionY -= containerModalOffsetY;
265 parentMenuPositionY -= containerModalOffsetY;
266 }
267 float bottomSpace = 0.0f;
268 if (parentPlacement == Placement::TOP_LEFT || parentPlacement == Placement::TOP ||
269 parentPlacement == Placement::TOP_RIGHT) {
270 bottomSpace = parentMenuBottomY - position_.GetY();
271 if (bottomSpace >= size.Height()) {
272 return NormalizePositionY(parentMenu, parentMenuPositionY, position_.GetY());
273 }
274 bottomSpace = lastMenuItemPositionY - wrapperRect_.Top() - param_.topSecurity;
275 if (bottomSpace >= size.Height()) {
276 return lastMenuItemPositionY - size.Height();
277 }
278 return wrapperRect_.Top() + param_.topSecurity;
279 }
280 bottomSpace = wrapperRect_.Bottom() - param_.bottomSecurity - position_.GetY();
281 if (bottomSpace >= size.Height()) {
282 return NormalizePositionY(parentMenu, parentMenuPositionY, position_.GetY());
283 }
284 if (size.Height() < wrapperRect_.Height()) {
285 bottomSpace = wrapperRect_.Bottom() - param_.bottomSecurity - firstItemBottomPositionY;
286 if (size.Height() <= bottomSpace) {
287 return wrapperRect_.Bottom() - param_.bottomSecurity - size.Height();
288 }
289 if (bottomSpace < parentMenuItem->GetGeometryNode()->GetFrameSize().Height()) {
290 return parentMenuPositionY;
291 }
292 return firstItemBottomPositionY;
293 }
294 // can't fit in screen, line up with top of the screen
295 return 0.0f;
296 }
297
VerticalLayoutSubMenuHalfScreen(const SizeF & size,float position,const SizeF & menuItemSize,const RefPtr<FrameNode> & parentMenuItem,bool stacked,LayoutWrapper * layoutWrapper)298 float SubMenuLayoutAlgorithm::VerticalLayoutSubMenuHalfScreen(
299 const SizeF& size, float position, const SizeF& menuItemSize,
300 const RefPtr<FrameNode>& parentMenuItem, bool stacked, LayoutWrapper* layoutWrapper)
301 {
302 auto pipelineContext = PipelineContext::GetMainPipelineContext();
303 CHECK_NULL_RETURN(pipelineContext, 0.0f);
304 auto safeAreaManager = pipelineContext->GetSafeAreaManager();
305 CHECK_NULL_RETURN(safeAreaManager, 0.0f);
306 float wrapperHeight = wrapperSize_.Height();
307 float bottomSpace = 0.0f;
308 if (!stacked) {
309 bottomSpace = wrapperSize_.Height() - (position_.GetY() - param_.windowsOffsetY) - margin_ * 2.0f;
310 // line up top of subMenu with top of the menuItem
311 if (bottomSpace >= size.Height()) {
312 return position;
313 }
314 // line up bottom of menu with bottom of the screen
315 if (size.Height() < wrapperHeight) {
316 return wrapperHeight - size.Height();
317 }
318 // can't fit in screen, line up with top of the screen
319 return 0.0f;
320 }
321 CHECK_NULL_RETURN(parentMenuItem, bottomSpace);
322 auto parentItemPattern = parentMenuItem->GetPattern<MenuItemPattern>();
323 CHECK_NULL_RETURN(parentItemPattern, bottomSpace);
324 auto parentMenu = parentItemPattern->GetMenu(true);
325 CHECK_NULL_RETURN(parentMenu, bottomSpace);
326 auto parentMenuPattern = parentMenu->GetPattern<MenuPattern>();
327 CHECK_NULL_RETURN(parentMenuPattern, bottomSpace);
328 if (parentMenuPattern->GetPreviewMode() != MenuPreviewMode::NONE) {
329 CHECK_NULL_RETURN(layoutWrapper, bottomSpace);
330 return CalcStackSubMenuPositionYHalfScreenWithPreview(size, parentMenu, layoutWrapper);
331 } else {
332 return CalcStackSubMenuPositionYHalfScreen(size, parentMenu, parentMenuItem);
333 }
334 }
335
336 // return submenu vertical offset
VerticalLayoutSubMenu(const SizeF & size,float position,const SizeF & menuItemSize,const RefPtr<FrameNode> & parentMenuItem,bool stacked,LayoutWrapper * layoutWrapper)337 float SubMenuLayoutAlgorithm::VerticalLayoutSubMenu(const SizeF& size, float position, const SizeF& menuItemSize,
338 const RefPtr<FrameNode>& parentMenuItem, bool stacked, LayoutWrapper* layoutWrapper)
339 {
340 float bottomSpace = 0.0f;
341 if (!stacked) {
342 bottomSpace = wrapperRect_.Bottom() - position - paddingBottom_;
343 // line up top of subMenu with top of the menuItem
344 if (bottomSpace >= size.Height()) {
345 return position;
346 }
347 // line up bottom of menu with bottom of the screen
348 if (size.Height() < wrapperRect_.Height()) {
349 return wrapperRect_.Bottom() - size.Height() - paddingBottom_;
350 }
351 // can't fit in screen, line up with top of the screen
352 return wrapperRect_.Top() + paddingTop_;
353 }
354 CHECK_NULL_RETURN(parentMenuItem, bottomSpace);
355 auto parentItemPattern = parentMenuItem->GetPattern<MenuItemPattern>();
356 CHECK_NULL_RETURN(parentItemPattern, bottomSpace);
357 auto parentMenu = parentItemPattern->GetMenu(true);
358 CHECK_NULL_RETURN(parentMenu, bottomSpace);
359 auto parentMenuPattern = parentMenu->GetPattern<MenuPattern>();
360 CHECK_NULL_RETURN(parentMenuPattern, bottomSpace);
361 if (parentMenuPattern->GetPreviewMode() != MenuPreviewMode::NONE) {
362 CHECK_NULL_RETURN(layoutWrapper, bottomSpace);
363 return CalcStackSubMenuPositionYHalfScreenWithPreview(size, parentMenu, layoutWrapper);
364 } else {
365 return CalcStackSubMenuPositionYHalfScreen(size, parentMenu, parentMenuItem);
366 }
367 }
368
369 // returns submenu horizontal offset
HorizontalLayoutSubMenu(const SizeF & size,float position,const SizeF & menuItemSize,LayoutWrapper * layoutWrapper)370 float SubMenuLayoutAlgorithm::HorizontalLayoutSubMenu(
371 const SizeF& size, float position, const SizeF& menuItemSize, LayoutWrapper* layoutWrapper)
372 {
373 float wrapperWidth = wrapperSize_.Width();
374 float rightSpace = wrapperWidth - position - paddingEnd_;
375 float leftSpace = position - menuItemSize.Width();
376 if (layoutWrapper != nullptr) {
377 auto menuLayoutProperty = layoutWrapper->GetLayoutProperty();
378 CHECK_NULL_RETURN(menuLayoutProperty, 0.0f);
379 auto layoutDirection = menuLayoutProperty->GetNonAutoLayoutDirection();
380 if (layoutDirection == TextDirection::RTL) {
381 rightSpace = position - menuItemSize.Width();
382 leftSpace = wrapperWidth - position;
383 }
384 }
385 // can fit subMenu on the right side of menuItem
386 if (rightSpace >= size.Width()) {
387 return position;
388 }
389 // fit subMenu on the left side of menuItem
390 if (leftSpace >= size.Width()) {
391 return position - size.Width() - menuItemSize.Width();
392 }
393 // line up right side of menu with right boundary of the screen
394 if (size.Width() < wrapperWidth) {
395 return wrapperWidth - size.Width() - paddingEnd_;
396 }
397 // can't fit in screen, line up with left side of the screen
398 return 0.0f;
399 }
400
ModifySubMenuWrapper(LayoutWrapper * layoutWrapper)401 void SubMenuLayoutAlgorithm::ModifySubMenuWrapper(LayoutWrapper* layoutWrapper)
402 {
403 CHECK_NULL_VOID(layoutWrapper);
404 auto pipelineContext = PipelineContext::GetMainPipelineContext();
405 CHECK_NULL_VOID(pipelineContext);
406 auto safeAreaManager = pipelineContext->GetSafeAreaManager();
407 CHECK_NULL_VOID(safeAreaManager);
408 auto bottom = safeAreaManager->GetSystemSafeArea().bottom_.Length();
409 if (!canExpandCurrentWindow_) {
410 wrapperSize_ = SizeF(param_.menuWindowRect.Width(), param_.menuWindowRect.Height() - bottom);
411 } else {
412 wrapperSize_ = SizeF(wrapperSize_.Width(), wrapperSize_.Height());
413 }
414 }
415
InitializePadding(LayoutWrapper * layoutWrapper)416 void SubMenuLayoutAlgorithm::InitializePadding(LayoutWrapper* layoutWrapper)
417 {
418 auto menuPattern = layoutWrapper->GetHostNode()->GetPattern<MenuPattern>();
419 CHECK_NULL_VOID(menuPattern);
420 auto host = menuPattern->GetHost();
421 CHECK_NULL_VOID(host);
422 auto pipeline = host->GetContextWithCheck();
423 CHECK_NULL_VOID(pipeline);
424 auto theme = pipeline->GetTheme<SelectTheme>();
425 CHECK_NULL_VOID(theme);
426 if (!menuPattern->IsSelectOverlayExtensionMenu()) {
427 margin_ = static_cast<float>(theme->GetMenuPadding().ConvertToPx());
428 paddingStart_ = static_cast<float>(theme->GetDefaultPaddingStart().ConvertToPx());
429 paddingEnd_ = static_cast<float>(theme->GetDefaultPaddingEnd().ConvertToPx());
430 if (!AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
431 paddingTop_ = static_cast<float>(theme->GetDefaultPaddingTop().ConvertToPx());
432 paddingBottom_ = static_cast<float>(theme->GetDefaultPaddingBottomFixed().ConvertToPx());
433 }
434 }
435 }
436
InitializePaddingAPI12(LayoutWrapper * layoutWrapper)437 void SubMenuLayoutAlgorithm::InitializePaddingAPI12(LayoutWrapper* layoutWrapper)
438 {
439 auto menuNode = layoutWrapper->GetHostNode();
440 CHECK_NULL_VOID(menuNode);
441 auto menuPattern = menuNode->GetPattern<MenuPattern>();
442 CHECK_NULL_VOID(menuPattern);
443 auto pipeline = PipelineContext::GetMainPipelineContext();
444 CHECK_NULL_VOID(pipeline);
445 auto theme = pipeline->GetTheme<SelectTheme>();
446 CHECK_NULL_VOID(theme);
447 if (!menuPattern->IsSelectOverlayExtensionMenu()) {
448 margin_ = static_cast<float>(theme->GetMenuPadding().ConvertToPx());
449 if (!canExpandCurrentWindow_) {
450 paddingStart_ = static_cast<float>(theme->GetMenuLargeMargin().ConvertToPx());
451 paddingEnd_ = static_cast<float>(theme->GetMenuLargeMargin().ConvertToPx());
452 } else {
453 paddingStart_ = static_cast<float>(theme->GetMenuMediumMargin().ConvertToPx());
454 paddingEnd_ = static_cast<float>(theme->GetMenuMediumMargin().ConvertToPx());
455 }
456 }
457 }
458
CheckMenuPadding(LayoutWrapper * layoutWrapper)459 void SubMenuLayoutAlgorithm::CheckMenuPadding(LayoutWrapper* layoutWrapper)
460 {
461 CHECK_NULL_VOID(layoutWrapper);
462 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE)) {
463 InitializePaddingAPI12(layoutWrapper);
464 } else {
465 InitializePadding(layoutWrapper);
466 }
467 }
468
469 } // namespace OHOS::Ace::NG
470