• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_PATTERNS_MENU_MENU_PATTERN_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_MENU_MENU_PATTERN_H
18 
19 #include <optional>
20 #include <vector>
21 
22 #include "base/memory/referenced.h"
23 #include "base/utils/utils.h"
24 #include "core/components_ng/pattern/menu/menu_accessibility_property.h"
25 #include "core/components_ng/pattern/menu/menu_layout_algorithm.h"
26 #include "core/components_ng/pattern/menu/menu_layout_property.h"
27 #include "core/components_ng/pattern/menu/menu_paint_method.h"
28 #include "core/components_ng/pattern/menu/menu_paint_property.h"
29 #include "core/components_ng/pattern/pattern.h"
30 #include "core/components_ng/pattern/select/select_model.h"
31 #include "core/components_v2/inspector/inspector_constants.h"
32 
33 constexpr int32_t DEFAULT_CLICK_DISTANCE = 15;
34 constexpr uint32_t MAX_SEARCH_DEPTH = 5;
35 namespace OHOS::Ace::NG {
36 enum class MenuType {
37     // ----- Menu Containers ------
38     MENU,         // corresponds to .bindMenu attribute
39     CONTEXT_MENU, // corresponds to .bindContextMenu attribute, lives in a SubWindow
40     SUB_MENU,     // secondary menu container in a multi-level menu
41 
42     // ----- innerMenu Node, corersponds to <Menu> tag in the frontend ------
43     MULTI_MENU,   // called multi because it's a multi-leveled menu, its MenuItems can trigger subMenus
44     DESKTOP_MENU, // menu specialized for desktop UI, enabled when multiple sibiling <Menu> nodes are present
45 
46     // ----- special menu used in other components ------
47     NAVIGATION_MENU,               // menu used in a Navigation component
48     SELECT_OVERLAY_EXTENSION_MENU, // menu used in SelectOverlay Extension of text component,skip menu layout algorithm
49     SELECT_OVERLAY_CUSTOM_MENU,    // menu used in SelectOverlay for custom menu
50                                    // click menu item whill not trigger close menu
51     SELECT_OVERLAY_SUB_MENU,       // menu type used for select overlay sub menu
52     SELECT_OVERLAY_RIGHT_CLICK_MENU, // menu type used for select overlay menu triggered by right-click
53 };
54 
55 class MenuPattern : public Pattern {
56     DECLARE_ACE_TYPE(MenuPattern, Pattern);
57 
58 public:
MenuPattern(int32_t targetId,std::string tag,MenuType type)59     MenuPattern(int32_t targetId, std::string tag, MenuType type)
60         : targetId_(targetId), targetTag_(std::move(tag)), type_(type)
61     {}
62     ~MenuPattern() override = default;
63 
IsAtomicNode()64     bool IsAtomicNode() const override
65     {
66         return false;
67     }
68 
GetFocusPattern()69     FocusPattern GetFocusPattern() const override
70     {
71         return { FocusType::SCOPE, true };
72     }
73 
CreateLayoutProperty()74     RefPtr<LayoutProperty> CreateLayoutProperty() override
75     {
76         return MakeRefPtr<MenuLayoutProperty>();
77     }
78 
CreateAccessibilityProperty()79     RefPtr<AccessibilityProperty> CreateAccessibilityProperty() override
80     {
81         return MakeRefPtr<MenuAccessibilityProperty>();
82     }
83 
84     RefPtr<LayoutAlgorithm> CreateLayoutAlgorithm() override;
85 
CreatePaintProperty()86     RefPtr<PaintProperty> CreatePaintProperty() override
87     {
88         return MakeRefPtr<MenuPaintProperty>();
89     }
90 
CreateNodePaintMethod()91     RefPtr<NodePaintMethod> CreateNodePaintMethod() override
92     {
93         return AceType::MakeRefPtr<MenuPaintMethod>();
94     }
95 
GetMenuType()96     MenuType GetMenuType() const
97     {
98         return type_;
99     }
100 
IsContextMenu()101     bool IsContextMenu() const
102     {
103         return type_ == MenuType::CONTEXT_MENU;
104     }
105 
SetPreviewMode(MenuPreviewMode mode)106     void SetPreviewMode(MenuPreviewMode mode)
107     {
108         previewMode_ = mode;
109     }
110 
GetPreviewMode()111     MenuPreviewMode GetPreviewMode() const
112     {
113         return previewMode_;
114     }
115 
SetPreviewBeforeAnimationScale(float scaleBeforeAnimation)116     void SetPreviewBeforeAnimationScale(float scaleBeforeAnimation)
117     {
118         previewAnimationOptions_.scaleFrom = scaleBeforeAnimation;
119     }
120 
GetPreviewBeforeAnimationScale()121     float GetPreviewBeforeAnimationScale() const
122     {
123         return previewAnimationOptions_.scaleFrom;
124     }
125 
SetPreviewAfterAnimationScale(float scaleAfterAnimation)126     void SetPreviewAfterAnimationScale(float scaleAfterAnimation)
127     {
128         previewAnimationOptions_.scaleTo = scaleAfterAnimation;
129     }
130 
GetPreviewAfterAnimationScale()131     float GetPreviewAfterAnimationScale() const
132     {
133         return previewAnimationOptions_.scaleTo;
134     }
135 
IsNavigationMenu()136     bool IsNavigationMenu() const
137     {
138         return type_ == MenuType::NAVIGATION_MENU;
139     }
140 
IsMultiMenu()141     bool IsMultiMenu() const
142     {
143         return type_ == MenuType::MULTI_MENU;
144     }
145 
IsDesktopMenu()146     bool IsDesktopMenu() const
147     {
148         return type_ == MenuType::DESKTOP_MENU;
149     }
150 
IsMenu()151     bool IsMenu() const
152     {
153         return type_ == MenuType::MENU;
154     }
155 
IsSubMenu()156     bool IsSubMenu() const
157     {
158         return type_ == MenuType::SUB_MENU;
159     }
160 
IsSelectOverlayExtensionMenu()161     bool IsSelectOverlayExtensionMenu() const
162     {
163         return type_ == MenuType::SELECT_OVERLAY_EXTENSION_MENU;
164     }
165 
IsSelectOverlayCustomMenu()166     bool IsSelectOverlayCustomMenu() const
167     {
168         return type_ == MenuType::SELECT_OVERLAY_CUSTOM_MENU;
169     }
170 
IsSelectOverlaySubMenu()171     bool IsSelectOverlaySubMenu() const
172     {
173         return type_ == MenuType::SELECT_OVERLAY_SUB_MENU;
174     }
175 
IsSelectOverlayRightClickMenu()176     bool IsSelectOverlayRightClickMenu() const
177     {
178         return type_ == MenuType::SELECT_OVERLAY_RIGHT_CLICK_MENU;
179     }
180 
SetParentMenuItem(const RefPtr<FrameNode> & parentMenuItem)181     void SetParentMenuItem(const RefPtr<FrameNode>& parentMenuItem)
182     {
183         parentMenuItem_ = parentMenuItem;
184     }
185 
GetParentMenuItem()186     RefPtr<FrameNode> GetParentMenuItem()
187     {
188         return parentMenuItem_;
189     }
190 
GetTargetId()191     int32_t GetTargetId() const
192     {
193         return targetId_;
194     }
195 
GetTargetTag()196     const std::string& GetTargetTag() const
197     {
198         return targetTag_;
199     }
200 
SetIsSelectMenu(bool isSelectMenu)201     void SetIsSelectMenu(bool isSelectMenu)
202     {
203         isSelectMenu_ = isSelectMenu;
204     }
IsSelectMenu()205     bool IsSelectMenu() const
206     {
207         return isSelectMenu_;
208     }
209 
SetHasOptionWidth(bool hasOptionWidth)210     void SetHasOptionWidth(bool hasOptionWidth)
211     {
212         hasOptionWidth_ = hasOptionWidth;
213     }
214 
GetHasOptionWidth()215     bool GetHasOptionWidth()
216     {
217         return hasOptionWidth_;
218     }
219 
AddOptionNode(const RefPtr<FrameNode> & option)220     void AddOptionNode(const RefPtr<FrameNode>& option)
221     {
222         CHECK_NULL_VOID(option);
223         options_.emplace_back(option);
224     }
225 
PopOptionNode()226     void PopOptionNode()
227     {
228         if (options_.empty()) {
229             LOGW("options is empty.");
230             return;
231         }
232         options_.pop_back();
233     }
234 
GetOptions()235     const std::vector<RefPtr<FrameNode>>& GetOptions() const
236     {
237         return options_;
238     }
239 
240     void RemoveParentHoverStyle();
241 
242     void UpdateSelectParam(const std::vector<SelectParam>& params);
243 
244     void HideMenu(bool isMenuOnTouch = false) const;
245 
246     void MountOption(const RefPtr<FrameNode>& option);
247 
248     void RemoveOption();
249 
250     RefPtr<FrameNode> GetMenuColumn() const;
251 
SetShowedSubMenu(const RefPtr<FrameNode> & subMenu)252     void SetShowedSubMenu(const RefPtr<FrameNode>& subMenu)
253     {
254         showedSubMenu_ = subMenu;
255     }
GetShowedSubMenu()256     const RefPtr<FrameNode>& GetShowedSubMenu() const
257     {
258         return showedSubMenu_;
259     }
260 
SetIsWidthModifiedBySelect(bool isModified)261     void SetIsWidthModifiedBySelect(bool isModified)
262     {
263         isWidthModifiedBySelect_ = isModified;
264     }
265 
IsWidthModifiedBySelect()266     bool IsWidthModifiedBySelect() const
267     {
268         return isWidthModifiedBySelect_;
269     }
270 
271     float GetSelectMenuWidth();
272     void HideSubMenu();
273     void OnModifyDone() override;
274 
275     // acquire first menu node in wrapper node by submenu node
276     RefPtr<MenuPattern> GetMainMenuPattern() const;
277     uint32_t GetInnerMenuCount() const;
278     void OnColorConfigurationUpdate() override;
279 
280     RefPtr<FrameNode> GetMenuWrapper() const;
281     RefPtr<FrameNode> GetFirstInnerMenu() const;
282     void DumpInfo() override;
283 
SetFirstShow()284     void SetFirstShow()
285     {
286         isFirstShow_ = true;
287     }
288 
SetOriginOffset(const OffsetF & offset)289     void SetOriginOffset(const OffsetF& offset)
290     {
291         originOffset_ = offset;
292     }
293 
SetEndOffset(const OffsetF & offset)294     void SetEndOffset(const OffsetF& offset)
295     {
296         endOffset_ = offset;
297     }
298 
GetEndOffset()299     OffsetF GetEndOffset() const
300     {
301         return endOffset_;
302     }
303 
SetPreviewOriginOffset(const OffsetF & offset)304     void SetPreviewOriginOffset(const OffsetF& offset)
305     {
306         previewOriginOffset_ = offset;
307     }
308 
GetPreviewOriginOffset()309     OffsetF GetPreviewOriginOffset() const
310     {
311         return previewOriginOffset_;
312     }
313 
SetHasLaid(bool hasLaid)314     void SetHasLaid(bool hasLaid)
315     {
316         hasLaid_ = hasLaid;
317     }
318 
HasLaid()319     bool HasLaid() const
320     {
321         return hasLaid_;
322     }
323 
SetTargetSize(const SizeF & size)324     void SetTargetSize(const SizeF& size)
325     {
326         targetSize_ = size;
327     }
328 
GetTargetSize()329     SizeF GetTargetSize() const
330     {
331         return targetSize_;
332     }
333 
SetIsHeightModifiedBySelect(bool isModified)334     void SetIsHeightModifiedBySelect(bool isModified)
335     {
336         isHeightModifiedBySelect_ = isModified;
337     }
338 
IsHeightModifiedBySelect()339     bool IsHeightModifiedBySelect() const
340     {
341         return isHeightModifiedBySelect_;
342     }
343 
GetMenuExpandDisplay()344     bool GetMenuExpandDisplay() const
345     {
346         return expandDisplay_;
347     }
348 
349 protected:
350     void UpdateMenuItemChildren(RefPtr<FrameNode>& host);
351     void SetMenuAttribute(RefPtr<FrameNode>& host);
352     void SetAccessibilityAction();
SetType(MenuType value)353     void SetType(MenuType value)
354     {
355         type_ = value;
356     }
357     virtual void InitTheme(const RefPtr<FrameNode>& host);
358 
359 private:
360     void OnAttachToFrameNode() override;
361     void RegisterOnTouch();
362     void OnTouchEvent(const TouchEventInfo& info);
363     bool OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config) override;
364 
365     // If CustomBuilder is declared with <Menu> and <MenuItem>,
366     // reset outer menu container and only apply theme on the inner <Menu> node.
367     void ResetTheme(const RefPtr<FrameNode>& host, bool resetForDesktopMenu);
368     void ResetScrollTheme(const RefPtr<FrameNode>& host);
369     void CopyMenuAttr(const RefPtr<FrameNode>& menuNode) const;
370 
371     void RegisterOnKeyEvent(const RefPtr<FocusHub>& focusHub);
372     bool OnKeyEvent(const KeyEvent& event) const;
373 
374     void DisableTabInMenu();
375 
376     Offset GetTransformCenter() const;
377     void ShowPreviewMenuAnimation();
378 
379     void InitPanEvent(const RefPtr<GestureEventHub>& gestureHub);
380     void HandleDragEnd(float offsetX, float offsetY, float velocity);
381     void HandleScrollDragEnd(float offsetX, float offsetY, float velocity);
382 
383     RefPtr<ClickEvent> onClick_;
384     RefPtr<TouchEventImpl> onTouch_;
385     std::optional<Offset> lastTouchOffset_;
386     const int32_t targetId_ = -1;
387     const std::string targetTag_;
388     MenuType type_ = MenuType::MENU;
389 
390     RefPtr<FrameNode> parentMenuItem_;
391     RefPtr<FrameNode> showedSubMenu_;
392     std::vector<RefPtr<FrameNode>> options_;
393 
394     bool isSelectMenu_ = false;
395     MenuPreviewMode previewMode_ = MenuPreviewMode::NONE;
396     MenuPreviewAnimationOptions previewAnimationOptions_;
397     bool isFirstShow_ = false;
398     OffsetF originOffset_;
399     OffsetF endOffset_;
400     OffsetF previewOriginOffset_;
401 
402     bool isWidthModifiedBySelect_ = false;
403     bool isHeightModifiedBySelect_ = false;
404     bool hasLaid_ = false;
405     bool hasOptionWidth_ = false;
406     SizeF targetSize_;
407     bool expandDisplay_ = false;
408 
409     ACE_DISALLOW_COPY_AND_MOVE(MenuPattern);
410 };
411 
412 // pattern of inner menu, corersponds to <Menu> tag in the frontend
413 class InnerMenuPattern : public MenuPattern {
414     DECLARE_ACE_TYPE(InnerMenuPattern, MenuPattern);
415 
416 public:
InnerMenuPattern(int32_t targetId,std::string tag,MenuType type)417     InnerMenuPattern(int32_t targetId, std::string tag, MenuType type) : MenuPattern(targetId, std::move(tag), type) {}
418     ~InnerMenuPattern() override = default;
419     void OnModifyDone() override;
420     void BeforeCreateLayoutWrapper() override;
421 
GetItemsAndGroups()422     const std::list<WeakPtr<UINode>>& GetItemsAndGroups() const
423     {
424         return itemsAndGroups_;
425     }
426 
427 private:
428     void InitTheme(const RefPtr<FrameNode>& host) override;
429     uint32_t FindSiblingMenuCount();
430     void ApplyDesktopMenuTheme();
431     void ApplyMultiMenuTheme();
432 
433     void RecordItemsAndGroups();
434 
435     // Record menu's items and groups at first level,
436     // use for group header and footer padding
437     std::list<WeakPtr<UINode>> itemsAndGroups_;
438 
439     ACE_DISALLOW_COPY_AND_MOVE(InnerMenuPattern);
440 };
441 } // namespace OHOS::Ace::NG
442 
443 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_MENU_MENU_PATTERN_H
444