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/preview/menu_preview_layout_algorithm.h"
17
18 #include "core/components_ng/pattern/menu/menu_pattern.h"
19 #include "core/components_ng/pattern/menu/preview/menu_preview_pattern.h"
20
21 namespace OHOS::Ace::NG {
Measure(LayoutWrapper * layoutWrapper)22 void MenuPreviewLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
23 {
24 CHECK_NULL_VOID(layoutWrapper);
25 UpdateLayoutConstraintForPreview(layoutWrapper);
26 auto layoutProperty = layoutWrapper->GetLayoutProperty();
27 CHECK_NULL_VOID(layoutProperty);
28 auto layoutConstraint = layoutProperty->CreateChildConstraint();
29 for (const auto& child : layoutWrapper->GetAllChildrenWithBuild()) {
30 child->Measure(layoutConstraint);
31 }
32
33 LinearLayoutAlgorithm::Measure(layoutWrapper);
34 }
35
Layout(LayoutWrapper * layoutWrapper)36 void MenuPreviewLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
37 {
38 auto preview = layoutWrapper->GetHostNode();
39 CHECK_NULL_VOID(preview);
40 auto previewPattern = preview->GetPattern<MenuPreviewPattern>();
41 CHECK_NULL_VOID(previewPattern);
42 auto menuWrapper = previewPattern->GetMenuWrapper();
43 CHECK_NULL_VOID(menuWrapper);
44 auto menuWrapperPattern = menuWrapper->GetPattern<MenuWrapperPattern>();
45 CHECK_NULL_VOID(menuWrapperPattern);
46 auto menuNode = menuWrapperPattern->GetMenu();
47 CHECK_NULL_VOID(menuNode);
48 auto menuLayoutAlgorithmWrapper = menuNode->GetLayoutAlgorithm();
49 CHECK_NULL_VOID(menuLayoutAlgorithmWrapper);
50 auto menuLayoutAlgorithm = DynamicCast<MenuLayoutAlgorithm>(menuLayoutAlgorithmWrapper->GetLayoutAlgorithm());
51 CHECK_NULL_VOID(menuLayoutAlgorithm);
52 auto menuPattern = menuNode->GetPattern<MenuPattern>();
53 CHECK_NULL_VOID(menuPattern);
54 if (!menuPattern->HasLaid()) {
55 menuLayoutAlgorithm->Measure(AceType::RawPtr(menuNode));
56 menuLayoutAlgorithm->Layout(AceType::RawPtr(menuNode));
57 // This is a workaround, because sometimes the dirty will not be marked to the top menu node,
58 // the image size of the hoverScale may change. After the change, the image needs to call layout to send
59 // the measured paint to the rosen paint.
60 LayoutHoverScaleImage(menuWrapperPattern);
61 }
62 menuPattern->SetHasLaid(false);
63 for (const auto& child : layoutWrapper->GetAllChildrenWithBuild()) {
64 child->Layout();
65 }
66 LinearLayoutAlgorithm::Layout(layoutWrapper);
67 }
68
LayoutHoverScaleImage(const RefPtr<MenuWrapperPattern> & wrapperPattern)69 void MenuPreviewLayoutAlgorithm::LayoutHoverScaleImage(const RefPtr<MenuWrapperPattern>& wrapperPattern)
70 {
71 CHECK_NULL_VOID(wrapperPattern);
72 if (!wrapperPattern->GetIsShowHoverImage()) {
73 return;
74 }
75 auto hoverScaleImage = wrapperPattern->GetHoverImagePreview();
76 CHECK_NULL_VOID(hoverScaleImage);
77 hoverScaleImage->Layout();
78 }
79
UpdateLayoutConstraintForPreview(LayoutWrapper * layoutWrapper)80 void MenuPreviewLayoutAlgorithm::UpdateLayoutConstraintForPreview(LayoutWrapper* layoutWrapper)
81 {
82 CHECK_NULL_VOID(layoutWrapper);
83 auto preview = layoutWrapper->GetHostNode();
84 CHECK_NULL_VOID(preview);
85 auto previewPattern = preview->GetPattern<MenuPreviewPattern>();
86 CHECK_NULL_VOID(previewPattern);
87 auto menuWrapper = previewPattern->GetMenuWrapper();
88 CHECK_NULL_VOID(menuWrapper);
89 auto menuWrapperPattern = menuWrapper->GetPattern<MenuWrapperPattern>();
90 CHECK_NULL_VOID(menuWrapperPattern);
91 auto menuNode = menuWrapperPattern->GetMenu();
92 CHECK_NULL_VOID(menuNode);
93 auto menuPattern = menuNode->GetPattern<MenuPattern>();
94 CHECK_NULL_VOID(menuPattern);
95 auto menuParam = menuWrapperPattern->GetMenuParam();
96 if (menuParam.isPreviewContainScale) {
97 auto menuWindowRect = menuPattern->GetMenuWindowRect();
98 auto maxWidth = menuWindowRect.Width();
99 auto maxHeight = menuWindowRect.Height();
100 auto targetSize = menuPattern->GetTargetSize();
101 auto isOversize = GreatNotEqual(targetSize.Width(), maxWidth) || GreatNotEqual(targetSize.Height(), maxHeight);
102 if (!isOversize) {
103 return;
104 }
105 auto widthDelta = targetSize.Width() - maxWidth;
106 auto heightDelta = targetSize.Height() - maxHeight;
107 if (GreatOrEqual(widthDelta, heightDelta)) {
108 maxHeight = targetSize.Height() * (maxWidth / targetSize.Width());
109 } else {
110 maxWidth = targetSize.Width() * (maxHeight / targetSize.Height());
111 }
112 auto layoutProperty = layoutWrapper->GetLayoutProperty();
113 CHECK_NULL_VOID(layoutProperty);
114 auto layoutConstraint = layoutProperty->CreateChildConstraint();
115 layoutConstraint.maxSize.SetWidth(maxWidth);
116 layoutConstraint.maxSize.SetHeight(maxHeight);
117 layoutConstraint.selfIdealSize.SetWidth(maxWidth);
118 layoutConstraint.selfIdealSize.SetHeight(maxHeight);
119 layoutProperty->UpdateLayoutConstraint(layoutConstraint);
120 } else {
121 CheckLayoutConstraint(layoutWrapper, menuParam, menuPattern);
122 }
123 }
124
CheckLayoutConstraint(LayoutWrapper * layoutWrapper,const MenuParam & menuParam,const RefPtr<MenuPattern> & menuPattern)125 void MenuPreviewLayoutAlgorithm::CheckLayoutConstraint(
126 LayoutWrapper* layoutWrapper, const MenuParam& menuParam, const RefPtr<MenuPattern>& menuPattern)
127 {
128 CHECK_NULL_VOID(menuPattern);
129 CHECK_NULL_VOID(layoutWrapper);
130 auto layoutProperty = layoutWrapper->GetLayoutProperty();
131 CHECK_NULL_VOID(layoutProperty);
132 auto layoutConstraint = layoutProperty->CreateChildConstraint();
133
134 auto isUpdateContentConstraint = false;
135 // contentRect = windowSize - safeArea - margin
136 if (menuParam.availableLayoutAreaMode.has_value() &&
137 menuParam.availableLayoutAreaMode.value() == AvailableLayoutAreaMode::SAFE_AREA) {
138 auto layoutParam = menuPattern->GetMenuLayoutParam();
139 auto maxWidth = layoutParam.wrapperRect.Width() - layoutParam.leftSecurity - layoutParam.rightSecurity;
140 maxWidth = std::max(maxWidth, 0.0);
141 auto maxHeight = layoutParam.wrapperRect.Height() - layoutParam.topSecurity - layoutParam.bottomSecurity;
142 maxHeight = std::max(maxHeight, 0.0);
143 layoutConstraint.maxSize = { maxWidth, maxHeight };
144 layoutConstraint.percentReference = { maxWidth, maxHeight };
145 isUpdateContentConstraint = true;
146 }
147
148 if (menuParam.previewScaleMode.value_or(PreviewScaleMode::AUTO) == PreviewScaleMode::MAINTAIN) {
149 layoutConstraint.maxSize = { Infinity<float>(), Infinity<float>() };
150 isUpdateContentConstraint = true;
151 }
152
153 layoutProperty->UpdateLayoutConstraint(layoutConstraint);
154 if (isUpdateContentConstraint) {
155 layoutProperty->UpdateContentConstraint();
156 }
157 }
158 } // namespace OHOS::Ace::NG
159