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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_MENU_MENU_LAYOUT_ALGORITHM_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_MENU_MENU_LAYOUT_ALGORITHM_H
18 
19 #include <list>
20 
21 #include "base/geometry/ng/offset_t.h"
22 #include "base/geometry/ng/size_t.h"
23 #include "base/memory/referenced.h"
24 #include "core/components/common/properties/placement.h"
25 #include "core/components_ng/layout/box_layout_algorithm.h"
26 #include "core/components_ng/layout/layout_wrapper.h"
27 #include "core/components_ng/pattern/menu/menu_layout_property.h"
28 #include "core/components_ng/pattern/menu/menu_paint_property.h"
29 #include "core/components_ng/property/border_property.h"
30 
31 namespace OHOS::Ace::NG {
32 
33 struct MenuDumpInfo {
34     uint32_t menuPreviewMode = 0;
35     uint32_t menuType = 0;
36     bool enableArrow = false;
37     OffsetF offset;
38     std::string targetNode;
39     OffsetF targetOffset;
40     SizeF targetSize;
41     Rect menuWindowRect;
42     Rect wrapperRect;
43     float previewBeginScale = 0.0f;
44     float previewEndScale = 0.0f;
45     float top = 0.0f;
46     float bottom = 0.0f;
47     OffsetF globalLocation;
48     std::string originPlacement;
49     std::string defaultPlacement;
50     OffsetF finalPosition;
51     std::string finalPlacement = "NONE";
52 };
53 class MenuLayoutProperty;
54 class MenuPattern;
55 class MenuLayoutAlgorithm : public BoxLayoutAlgorithm {
56     DECLARE_ACE_TYPE(MenuLayoutAlgorithm, BoxLayoutAlgorithm)
57 public:
58     MenuLayoutAlgorithm(int32_t id, const std::string& tag,
59         const std::optional<OffsetF>& lastPosition = std::nullopt);
60     MenuLayoutAlgorithm() = default;
61     ~MenuLayoutAlgorithm() override;
62 
63     // override measureSelf and measureChildren.
64     void Measure(LayoutWrapper* layoutWrapper) override;
65 
66     void Layout(LayoutWrapper* layoutWrapper) override;
67 
GetPlacement()68     Placement GetPlacement() const
69     {
70         return placement_;
71     }
72 
73     bool canExpandCurrentWindow_ = false;
74     void InitCanExpandCurrentWindow(bool isShowInSubWindow);
75     bool CheckIsEmbeddedMode(LayoutWrapper* layoutWrapper);
76     Rect GetMenuWindowRectInfo(const RefPtr<MenuPattern>& menuPattern);
77 
78 protected:
79     float VerticalLayout(const SizeF& size, float clickPosition, bool IsContextMenu = false);
80     float HorizontalLayout(const SizeF& size, float clickPosition, bool IsSelectMenu = false);
81 
82     RefPtr<MenuPaintProperty> GetPaintProperty(const LayoutWrapper* layoutWrapper);
83     OffsetF GetMenuWrapperOffset(const LayoutWrapper* layoutWrapper);
84 
85     // position input is relative to main window left top point,
86     // menu show position is relative to menuWrapper.
87     OffsetF position_;
88     OffsetF positionOffset_;
89     SizeF wrapperSize_;
90     // rect is relative to menuWrapper
91     Rect wrapperRect_;
92     struct PreviewMenuParam {
93         SizeF windowGlobalSizeF;
94         Rect menuWindowRect;
95         float windowsOffsetX = 0.0f;
96         float windowsOffsetY = 0.0f;
97         float top = 0.0f;
98         float bottom = 0.0f;
99         float left = 0.0f;
100         float right = 0.0f;
101         float topSecurity = 0.0f;
102         float bottomSecurity = 0.0f;
103         float previewMenuGap = 0.0f;
104         float menuItemTotalHeight = 0.0f;
105     };
106     PreviewMenuParam param_;
107 
108 private:
109     enum class ErrorPositionType {
110         NORMAL = 0,
111         TOP_LEFT_ERROR,
112         BOTTOM_RIGHT_ERROR,
113     };
114     enum class DirectionState {
115         Bottom_Direction = 1,
116         Top_Direction,
117         Right_Direction,
118         Left_Direction,
119         None_Direction,
120     };
121 
122     void Initialize(LayoutWrapper* layoutWrapper);
123     void InitializePadding(LayoutWrapper* layoutWrapper);
124     void InitializePaddingAPI12(LayoutWrapper* layoutWrapper);
125     void InitializePaddingAPI11(LayoutWrapper* layoutWrapper);
126     void InitializeParam(const RefPtr<MenuPattern>& menuPattern);
127     void InitializeLayoutRegionMargin(const RefPtr<MenuPattern>& menuPattern);
128     void InitWrapperRect(const RefPtr<MenuLayoutProperty>& props, const RefPtr<MenuPattern>& menuPattern);
129     uint32_t GetBottomBySafeAreaManager(const RefPtr<SafeAreaManager>& safeAreaManager,
130         const RefPtr<MenuLayoutProperty>& props, const RefPtr<MenuPattern>& menuPattern);
131     void InitSpace(const RefPtr<MenuLayoutProperty>& props, const RefPtr<MenuPattern>& menuPattern);
132     void ModifyPositionToWrapper(LayoutWrapper* layoutWrapper, OffsetF& position);
133     LayoutConstraintF CreateChildConstraint(LayoutWrapper* layoutWrapper);
134     void UpdateConstraintWidth(LayoutWrapper* layoutWrapper, LayoutConstraintF& constraint);
135     void UpdateConstraintHeight(LayoutWrapper* layoutWrapper, LayoutConstraintF& constraint);
136     void UpdateConstraintBaseOnOptions(LayoutWrapper* layoutWrapper, LayoutConstraintF& constraint);
137     void UpdateOptionConstraint(std::list<RefPtr<LayoutWrapper>>& options, float width);
138 
139     void ComputeMenuPositionByAlignType(const RefPtr<MenuLayoutProperty>& menuProp, const SizeF& menuSize);
140     OffsetF ComputeMenuPositionByOffset(
141         const RefPtr<MenuLayoutProperty>& menuProp, const RefPtr<GeometryNode>& geometryNode);
142     OffsetF MenuLayoutAvoidAlgorithm(const RefPtr<MenuLayoutProperty>& menuProp, const RefPtr<MenuPattern>& menuPattern,
143         const SizeF& size, bool didNeedArrow = false, LayoutWrapper* layoutWrapper = nullptr);
144     void PlacementRTL(LayoutWrapper* layoutWrapper, Placement& placement_);
145     void SetMenuPlacementForAnimation(LayoutWrapper* layoutWrapper);
146 
147     void LayoutArrow(const LayoutWrapper* layoutWrapper);
148     OffsetF GetArrowPositionWithPlacement(const SizeF& menuSize, const LayoutWrapper* layoutWrapper);
149     bool GetIfNeedArrow(const LayoutWrapper* layoutWrapper, const SizeF& menuSize);
150     void UpdateArrowOffsetWithMenuLimit(const SizeF& menuSize, const LayoutWrapper* layoutWrapper);
151     void UpdatePropArrowOffset();
152     void LimitContainerModalMenuRect(double& rectWidth, double& rectHeight);
153 
154     // get option LayoutWrapper for measure get max width
155     std::list<RefPtr<LayoutWrapper>> GetOptionsLayoutWrappper(LayoutWrapper* layoutWrapper);
156 
157     OffsetF GetPositionWithPlacement(const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition);
158     void InitTargetSizeAndPosition(const LayoutWrapper* layoutWrapper, bool isContextMenu,
159         const RefPtr<MenuPattern>& menuPattern);
160     bool SkipUpdateTargetNodeSize(const RefPtr<FrameNode>& targetNode, const RefPtr<MenuPattern>& menuPattern);
161     OffsetF GetChildPosition(const SizeF& childSize, bool didNeedArrow = false);
162     OffsetF FitToScreen(const OffsetF& position, const SizeF& childSize, bool didNeedArrow = false);
163     bool CheckPosition(const OffsetF& position, const SizeF& childSize);
164 
165     OffsetF GetPositionWithPlacementTop(const SizeF&, const OffsetF&, const OffsetF&);
166     OffsetF GetPositionWithPlacementTopLeft(const SizeF&, const OffsetF&, const OffsetF&);
167     OffsetF GetPositionWithPlacementTopRight(const SizeF&, const OffsetF&, const OffsetF&);
168     OffsetF GetPositionWithPlacementBottom(const SizeF&, const OffsetF&, const OffsetF&);
169     OffsetF GetPositionWithPlacementBottomLeft(const SizeF&, const OffsetF&, const OffsetF&);
170     OffsetF GetPositionWithPlacementBottomRight(const SizeF&, const OffsetF&, const OffsetF&);
171     OffsetF GetPositionWithPlacementLeft(const SizeF&, const OffsetF&, const OffsetF&);
172     OffsetF GetPositionWithPlacementLeftTop(const SizeF&, const OffsetF&, const OffsetF&);
173     OffsetF GetPositionWithPlacementLeftBottom(const SizeF&, const OffsetF&, const OffsetF&);
174     OffsetF GetPositionWithPlacementRight(const SizeF&, const OffsetF&, const OffsetF&);
175     OffsetF GetPositionWithPlacementRightTop(const SizeF&, const OffsetF&, const OffsetF&);
176     OffsetF GetPositionWithPlacementRightBottom(const SizeF&, const OffsetF&, const OffsetF&);
177     OffsetF AddTargetSpace(const OffsetF& position);
178     OffsetF AddOffset(const OffsetF& position);
179     bool CheckPositionInPlacementRect(const Rect& rect, const OffsetF& position, const SizeF& childSize);
180     OffsetF AdjustPosition(const OffsetF& position, float width, float height, float space);
181     OffsetF GetAdjustPosition(std::vector<Placement>& currentPlacementStates, size_t step, const SizeF& childSize,
182         const OffsetF& topPosition, const OffsetF& bottomPosition);
183 
184     RefPtr<PipelineContext> GetCurrentPipelineContext();
185 
186     void LayoutPreviewMenu(LayoutWrapper* layoutWrapper);
187     void UpdatePreviewPositionAndOffset(
188         RefPtr<LayoutWrapper>& previewLayoutWrapper, RefPtr<LayoutWrapper>& menuLayoutWrapper);
189     void ModifyPreviewMenuPlacement(LayoutWrapper* layoutWrapper);
190     void GetPreviewNodeTotalSize(const RefPtr<LayoutWrapper>& child, const Rect& menuWindowRect,
191         RefPtr<LayoutWrapper>& previewLayoutWrapper, SizeF& size, const RefPtr<LayoutWrapper>& menuLayoutWrapper);
192     SizeF GetPreviewNodeAndMenuNodeTotalSize(const RefPtr<FrameNode>& frameNode,
193         RefPtr<LayoutWrapper>& previewLayoutWrapper, RefPtr<LayoutWrapper>& menuLayoutWrapper);
194 
195     void LayoutNormalTopPreviewBottomMenu(const RefPtr<GeometryNode>& previewGeometryNode,
196         const RefPtr<GeometryNode>& menuGeometryNode, SizeF& totalSize, float menuItemTotalHeight);
197     void LayoutNormalTopPreviewBottomMenuLessThan(const RefPtr<GeometryNode>& previewGeometryNode,
198         const RefPtr<GeometryNode>& menuGeometryNode, SizeF& totalSize);
199     void LayoutNormalTopPreviewBottomMenuGreateThan(const RefPtr<GeometryNode>& previewGeometryNode,
200         const RefPtr<GeometryNode>& menuGeometryNode, SizeF& totalSize);
201     void LayoutNormalBottomPreviewTopMenu(const RefPtr<GeometryNode>& previewGeometryNode,
202         const RefPtr<GeometryNode>& menuGeometryNode, SizeF& totalSize, float menuItemTotalHeight);
203     void LayoutNormalBottomPreviewTopMenuLessThan(const RefPtr<GeometryNode>& previewGeometryNode,
204         const RefPtr<GeometryNode>& menuGeometryNode, SizeF& totalSize);
205     void LayoutNormalBottomPreviewTopMenuGreateThan(const RefPtr<GeometryNode>& previewGeometryNode,
206         const RefPtr<GeometryNode>& menuGeometryNode, SizeF& totalSize);
207 
208     float CheckHorizontalLayoutPreviewOffsetX(
209         const RefPtr<GeometryNode>& previewGeometryNode, const RefPtr<GeometryNode>& menuGeometryNode, float offsetX);
210     void LayoutOtherDeviceLeftPreviewRightMenu(const RefPtr<GeometryNode>& previewGeometryNode,
211         const RefPtr<GeometryNode>& menuGeometryNode, SizeF& totalSize, float menuItemTotalHeight);
212     void LayoutOtherDeviceLeftPreviewRightMenuLessThan(const RefPtr<GeometryNode>& previewGeometryNode,
213         const RefPtr<GeometryNode>& menuGeometryNode, SizeF& totalSize);
214     void LayoutOtherDeviceLeftPreviewRightMenuGreateThan(const RefPtr<GeometryNode>& previewGeometryNode,
215         const RefPtr<GeometryNode>& menuGeometryNode, SizeF& totalSize);
216     void UpdateScrollAndColumnLayoutConstraint(
217         const RefPtr<LayoutWrapper>& previewLayoutWrapper, const RefPtr<LayoutWrapper>& menuLayoutWrapper);
218     float GetMenuItemTotalHeight(const RefPtr<LayoutWrapper>& menuLayoutWrapper);
219     OffsetF FixMenuOriginOffset(float beforeAnimationScale, float afterAnimationScale);
220     bool CheckPlacement(const SizeF& childSize);
221 
222     void ProcessArrowParams(const LayoutWrapper* layoutWrapper, const SizeF& menuSize);
223     BorderRadiusProperty GetMenuRadius(const LayoutWrapper* layoutWrapper, const SizeF& menuSize);
224 
225     void CalculateIdealSize(LayoutWrapper* layoutWrapper, LayoutConstraintF& childConstraint,
226         PaddingPropertyF padding, SizeF& idealSize, RefPtr<FrameNode> parentItem);
227     void TranslateOptions(LayoutWrapper* layoutWrapper);
228     bool CheckChildConstraintCondition(const RefPtr<MenuPattern>& menuPattern);
229     void UpdateChildConstraintByDevice(const RefPtr<MenuPattern>& menuPattern,
230         LayoutConstraintF& childConstraint, const LayoutConstraintF& layoutConstraint);
231     void CheckPreviewConstraint(const RefPtr<FrameNode>& frameNode, const Rect& menuWindowRect);
232     void CheckPreviewSize(const RefPtr<LayoutWrapper>& previewLayoutWrapper, const RefPtr<MenuPattern>& menuPattern);
233     void ModifyTargetOffset();
234 
235     std::optional<OffsetF> lastPosition_;
236     OffsetF targetOffset_;
237     SizeF targetSize_;
238     Placement placement_ = Placement::BOTTOM_LEFT;
239     int32_t targetNodeId_ = -1;
240     std::string targetTag_;
241     float targetSecurity_ = TARGET_SECURITY.ConvertToPx();
242 
243     // current page offset relative to window.
244     float topSpace_ = 0.0f;
245     float bottomSpace_ = 0.0f;
246     float leftSpace_ = 0.0f;
247     float rightSpace_ = 0.0f;
248 
249     // arrow
250     float targetSpace_ = 0.0f;
251     float arrowMinLimit_ = 0.0f;
252     float arrowOffset_ = 0.0f;
253     float arrowWidth_ = 0.0f;
254     bool arrowInMenu_ = false;
255     bool propNeedArrow_ = false;
256     OffsetF arrowPosition_;
257     Dimension propArrowOffset_;
258     std::unordered_set<Placement> setHorizontal_;
259     std::unordered_set<Placement> setVertical_;
260     Placement arrowPlacement_ = Placement::NONE;
261 
262     float margin_ = 0.0f;
263     float paddingStart_ = 0.0f;
264     float paddingEnd_ = 0.0f;
265     float paddingTop_ = 0.0f;
266     float paddingBottom_ = 0.0f;
267     float optionPadding_ = 0.0f;
268     OffsetF targetCenterOffset_;
269     OffsetF previewOriginOffset_;
270     OffsetF previewOffset_;
271     SizeF previewSize_;
272     int32_t state_ = 0;
273     int32_t prevState_ = -1;
274     OffsetF preOffset_;
275     Rect preRect_;
276     bool flag_ = false;
277     // previewSacle_ must be greater than 0
278     float previewScale_ = 1.0f;
279     MenuDumpInfo dumpInfo_;
280     MarginPropertyF layoutRegionMargin_;
281     bool isExpandDisplay_ = false;
282     bool isFreeMultiWindow_ = false;
283     bool isUIExtensionSubWindow_ = false;
284     RectF displayWindowRect_;
285     RectF UIExtensionHostWindowRect_;
286     bool isPreviewContainScale_ = false;
287 
288     using PlacementFunc = OffsetF (MenuLayoutAlgorithm::*)(const SizeF&, const OffsetF&, const OffsetF&);
289     std::map<Placement, PlacementFunc> placementFuncMap_;
290 
291     ACE_DISALLOW_COPY_AND_MOVE(MenuLayoutAlgorithm);
292 };
293 } // namespace OHOS::Ace::NG
294 
295 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_MENU_MENU_LAYOUT_ALGORITHM_H
296