• 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/geometry/ng/size_t.h"
23 #include "base/memory/referenced.h"
24 #include "base/utils/utils.h"
25 #include "core/components_ng/base/symbol_modifier.h"
26 #include "core/components_ng/pattern/menu/menu_accessibility_property.h"
27 #include "core/components_ng/pattern/menu/menu_layout_algorithm.h"
28 #include "core/components_ng/pattern/menu/menu_layout_property.h"
29 #include "core/components_ng/pattern/menu/menu_paint_method.h"
30 #include "core/components_ng/pattern/menu/menu_paint_property.h"
31 #include "core/components_ng/pattern/pattern.h"
32 #include "core/components_ng/pattern/select/select_model.h"
33 #include "core/components_ng/property/border_property.h"
34 #include "core/components_v2/inspector/inspector_constants.h"
35 
36 constexpr int32_t DEFAULT_CLICK_DISTANCE = 15;
37 constexpr uint32_t MAX_SEARCH_DEPTH = 5;
38 namespace OHOS::Ace::NG {
39 
40 struct SelectProperties {
41     std::string value;
42     std::string icon;
43     RefPtr<SymbolModifier> symbolModifier;
44     int index;
45     bool selected = false;
46     bool selectEnable = true;
47 };
48 
49 struct MenuItemInfo {
50     OffsetF originOffset = OffsetF();
51     OffsetF endOffset = OffsetF();
52     bool isFindTargetId = false;
53 };
54 
55 class MenuPattern : public Pattern, public FocusView {
56     DECLARE_ACE_TYPE(MenuPattern, Pattern, FocusView);
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 
GetRouteOfFirstScope()74     std::list<int32_t> GetRouteOfFirstScope() override
75     {
76         return { 0, 0 };
77     }
78 
IsFocusViewLegal()79     bool IsFocusViewLegal() override
80     {
81         return type_ == MenuType::MENU || type_ == MenuType::CONTEXT_MENU || type_ == MenuType::SUB_MENU;
82     }
83 
CreateLayoutProperty()84     RefPtr<LayoutProperty> CreateLayoutProperty() override
85     {
86         return MakeRefPtr<MenuLayoutProperty>();
87     }
88 
CreateAccessibilityProperty()89     RefPtr<AccessibilityProperty> CreateAccessibilityProperty() override
90     {
91         return MakeRefPtr<MenuAccessibilityProperty>();
92     }
93 
94     RefPtr<LayoutAlgorithm> CreateLayoutAlgorithm() override;
95 
CreatePaintProperty()96     RefPtr<PaintProperty> CreatePaintProperty() override
97     {
98         return MakeRefPtr<MenuPaintProperty>();
99     }
100 
CreateNodePaintMethod()101     RefPtr<NodePaintMethod> CreateNodePaintMethod() override
102     {
103         return AceType::MakeRefPtr<MenuPaintMethod>();
104     }
105 
GetMenuType()106     MenuType GetMenuType() const
107     {
108         return type_;
109     }
110 
IsContextMenu()111     bool IsContextMenu() const
112     {
113         return type_ == MenuType::CONTEXT_MENU;
114     }
115 
SetPreviewMode(MenuPreviewMode mode)116     void SetPreviewMode(MenuPreviewMode mode)
117     {
118         previewMode_ = mode;
119     }
120 
GetPreviewMode()121     MenuPreviewMode GetPreviewMode() const
122     {
123         return previewMode_;
124     }
125 
SetPreviewBeforeAnimationScale(float scaleBeforeAnimation)126     void SetPreviewBeforeAnimationScale(float scaleBeforeAnimation)
127     {
128         previewAnimationOptions_.scaleFrom = scaleBeforeAnimation;
129     }
130 
GetPreviewBeforeAnimationScale()131     float GetPreviewBeforeAnimationScale() const
132     {
133         return previewAnimationOptions_.scaleFrom;
134     }
135 
SetPreviewAfterAnimationScale(float scaleAfterAnimation)136     void SetPreviewAfterAnimationScale(float scaleAfterAnimation)
137     {
138         previewAnimationOptions_.scaleTo = scaleAfterAnimation;
139     }
140 
GetPreviewAfterAnimationScale()141     float GetPreviewAfterAnimationScale() const
142     {
143         return previewAnimationOptions_.scaleTo;
144     }
145 
SetIsShowHoverImage(bool isShow)146     void SetIsShowHoverImage(bool isShow)
147     {
148         isShowHoverImage_ = isShow;
149     }
150 
GetIsShowHoverImage()151     bool GetIsShowHoverImage() const
152     {
153         return isShowHoverImage_;
154     }
155 
IsNavigationMenu()156     bool IsNavigationMenu() const
157     {
158         return type_ == MenuType::NAVIGATION_MENU;
159     }
160 
IsMultiMenu()161     bool IsMultiMenu() const
162     {
163         return type_ == MenuType::MULTI_MENU;
164     }
165 
IsDesktopMenu()166     bool IsDesktopMenu() const
167     {
168         return type_ == MenuType::DESKTOP_MENU;
169     }
170 
IsMenu()171     bool IsMenu() const
172     {
173         return type_ == MenuType::MENU;
174     }
175 
IsSubMenu()176     bool IsSubMenu() const
177     {
178         return type_ == MenuType::SUB_MENU;
179     }
180 
IsSelectOverlayExtensionMenu()181     bool IsSelectOverlayExtensionMenu() const
182     {
183         return type_ == MenuType::SELECT_OVERLAY_EXTENSION_MENU;
184     }
185 
IsSelectOverlayCustomMenu()186     bool IsSelectOverlayCustomMenu() const
187     {
188         return type_ == MenuType::SELECT_OVERLAY_CUSTOM_MENU;
189     }
190 
IsSelectOverlaySubMenu()191     bool IsSelectOverlaySubMenu() const
192     {
193         return type_ == MenuType::SELECT_OVERLAY_SUB_MENU;
194     }
195 
IsSelectOverlayRightClickMenu()196     bool IsSelectOverlayRightClickMenu() const
197     {
198         return type_ == MenuType::SELECT_OVERLAY_RIGHT_CLICK_MENU;
199     }
200 
SetParentMenuItem(const RefPtr<FrameNode> & parentMenuItem)201     void SetParentMenuItem(const RefPtr<FrameNode>& parentMenuItem)
202     {
203         parentMenuItem_ = parentMenuItem;
204     }
205 
GetParentMenuItem()206     RefPtr<FrameNode> GetParentMenuItem()
207     {
208         return parentMenuItem_;
209     }
210 
GetTargetId()211     int32_t GetTargetId() const
212     {
213         return targetId_;
214     }
215 
GetTargetTag()216     const std::string& GetTargetTag() const
217     {
218         return targetTag_;
219     }
220 
SetIsSelectMenu(bool isSelectMenu)221     void SetIsSelectMenu(bool isSelectMenu)
222     {
223         isSelectMenu_ = isSelectMenu;
224     }
IsSelectMenu()225     bool IsSelectMenu() const
226     {
227         return isSelectMenu_;
228     }
229 
SetHasOptionWidth(bool hasOptionWidth)230     void SetHasOptionWidth(bool hasOptionWidth)
231     {
232         hasOptionWidth_ = hasOptionWidth;
233     }
234 
GetHasOptionWidth()235     bool GetHasOptionWidth()
236     {
237         return hasOptionWidth_;
238     }
239 
AddOptionNode(const RefPtr<FrameNode> & option)240     void AddOptionNode(const RefPtr<FrameNode>& option)
241     {
242         CHECK_NULL_VOID(option);
243         options_.emplace_back(option);
244     }
245 
GetBuilderId()246     int32_t GetBuilderId()
247     {
248         auto node = builderNode_.Upgrade();
249         CHECK_NULL_RETURN(node, -1);
250         return node->GetId();
251     }
252 
PopOptionNode()253     void PopOptionNode()
254     {
255         if (options_.empty()) {
256             LOGW("options is empty.");
257             return;
258         }
259         options_.pop_back();
260     }
261 
GetOptions()262     const std::vector<RefPtr<FrameNode>>& GetOptions() const
263     {
264         return options_;
265     }
266 
267     void RemoveParentHoverStyle();
268 
269     void UpdateSelectParam(const std::vector<SelectParam>& params);
270 
SetNeedHideAfterTouch(bool needHideAfterTouch)271     void SetNeedHideAfterTouch(bool needHideAfterTouch)
272     {
273         needHideAfterTouch_ = needHideAfterTouch;
274     }
275 
276     void HideMenu(bool isMenuOnTouch = false, OffsetF position = OffsetF()) const;
277 
278     bool HideStackExpandMenu(const OffsetF& position) const;
279 
280     void HideStackMenu() const;
281 
282     void MountOption(const RefPtr<FrameNode>& option);
283 
284     void RemoveOption();
285 
286     RefPtr<FrameNode> GetMenuColumn() const;
287 
SetShowedSubMenu(const RefPtr<FrameNode> & subMenu)288     void SetShowedSubMenu(const RefPtr<FrameNode>& subMenu)
289     {
290         showedSubMenu_ = subMenu;
291     }
GetShowedSubMenu()292     const RefPtr<FrameNode>& GetShowedSubMenu() const
293     {
294         return showedSubMenu_;
295     }
296 
SetIsWidthModifiedBySelect(bool isModified)297     void SetIsWidthModifiedBySelect(bool isModified)
298     {
299         isWidthModifiedBySelect_ = isModified;
300     }
301 
IsWidthModifiedBySelect()302     bool IsWidthModifiedBySelect() const
303     {
304         return isWidthModifiedBySelect_;
305     }
306 
307     float GetSelectMenuWidth();
308     void HideSubMenu();
309     void OnModifyDone() override;
310 
311     // acquire first menu node in wrapper node by submenu node
312     RefPtr<MenuPattern> GetMainMenuPattern() const;
313     uint32_t GetInnerMenuCount() const;
314     void OnColorConfigurationUpdate() override;
315 
316     RefPtr<FrameNode> GetMenuWrapper() const;
317     RefPtr<FrameNode> GetFirstInnerMenu() const;
318     void DumpInfo() override;
319 
SetFirstShow()320     void SetFirstShow()
321     {
322         isFirstShow_ = true;
323     }
324 
SetOriginOffset(const OffsetF & offset)325     void SetOriginOffset(const OffsetF& offset)
326     {
327         originOffset_ = offset;
328     }
329 
SetEndOffset(const OffsetF & offset)330     void SetEndOffset(const OffsetF& offset)
331     {
332         endOffset_ = offset;
333     }
334 
GetEndOffset()335     OffsetF GetEndOffset() const
336     {
337         return endOffset_;
338     }
339 
SetSelectOverlayExtensionMenuShow()340     void SetSelectOverlayExtensionMenuShow()
341     {
342         isExtensionMenuShow_ = true;
343     }
344 
SetDisappearAnimation(bool hasAnimation)345     void SetDisappearAnimation(bool hasAnimation)
346     {
347         // false:exit from BOTTOM to TOP
348         // true:exit from LEFT_BOTTOM to RIGHT_TOP
349         hasAnimation_ = hasAnimation;
350     }
351 
GetDisappearAnimation()352     bool GetDisappearAnimation() const
353     {
354         return hasAnimation_;
355     }
356 
SetSubMenuShow()357     void SetSubMenuShow()
358     {
359         isSubMenuShow_ = true;
360     }
361 
SetMenuShow()362     void SetMenuShow()
363     {
364         isMenuShow_ = true;
365     }
366 
SetPreviewOriginOffset(const OffsetF & offset)367     void SetPreviewOriginOffset(const OffsetF& offset)
368     {
369         previewOriginOffset_ = offset;
370     }
371 
GetPreviewOriginOffset()372     OffsetF GetPreviewOriginOffset() const
373     {
374         return previewOriginOffset_;
375     }
376 
SetHasLaid(bool hasLaid)377     void SetHasLaid(bool hasLaid)
378     {
379         hasLaid_ = hasLaid;
380     }
381 
HasLaid()382     bool HasLaid() const
383     {
384         return hasLaid_;
385     }
386 
SetTargetSize(const SizeF & size)387     void SetTargetSize(const SizeF& size)
388     {
389         targetSize_ = size;
390     }
391 
GetTargetSize()392     SizeF GetTargetSize() const
393     {
394         return targetSize_;
395     }
396 
SetIsHeightModifiedBySelect(bool isModified)397     void SetIsHeightModifiedBySelect(bool isModified)
398     {
399         isHeightModifiedBySelect_ = isModified;
400     }
401 
IsHeightModifiedBySelect()402     bool IsHeightModifiedBySelect() const
403     {
404         return isHeightModifiedBySelect_;
405     }
406 
GetMenuExpandDisplay()407     bool GetMenuExpandDisplay() const
408     {
409         return expandDisplay_;
410     }
411 
412     void ShowMenuDisappearAnimation();
413     void ShowStackExpandDisappearAnimation(const RefPtr<FrameNode>& menuNode,
414         const RefPtr<FrameNode>& subMenuNode, AnimationOption& option) const;
415 
SetBuilderFunc(SelectMakeCallback && makeFunc)416     void SetBuilderFunc(SelectMakeCallback&& makeFunc)
417     {
418         makeFunc_ = std::move(makeFunc);
419     }
420 
ResetBuilderFunc()421     void ResetBuilderFunc()
422     {
423         makeFunc_ = std::nullopt;
424     }
425 
426     void UpdateSelectIndex(int32_t index);
427 
SetSelectProperties(const std::vector<SelectParam> & params)428     void SetSelectProperties(const std::vector<SelectParam>& params)
429     {
430         auto list = selectProperties_;
431         selectParams_ = params;
432         selectProperties_.clear();
433         for (size_t i = 0; i < params.size(); i++) {
434             SelectProperties selectProperty;
435             selectProperty.value = params[i].text;
436             selectProperty.icon = params[i].icon;
437             selectProperty.symbolModifier = params[i].symbolModifier;
438             selectProperty.index = static_cast<int>(i);
439             if (i < list.size()) {
440                 selectProperty.selected = list[i].selected;
441                 selectProperty.selectEnable = list[i].selectEnable;
442             }
443             selectProperties_.push_back(selectProperty);
444         }
445     }
446 
447     bool GetShadowFromTheme(ShadowStyle shadowStyle, Shadow& shadow);
448 
UseContentModifier()449     bool UseContentModifier()
450     {
451         return builderNode_.Upgrade() != nullptr;
452     }
453 
454     void FireBuilder();
455 
456     BorderRadiusProperty CalcIdealBorderRadius(const BorderRadiusProperty& borderRadius, const SizeF& menuSize);
457 
GetLastSelectedItem()458     RefPtr<FrameNode> GetLastSelectedItem()
459     {
460         return lastSelectedItem_;
461     }
462 
SetLastSelectedItem(const RefPtr<FrameNode> & lastSelectedItem)463     void SetLastSelectedItem(const RefPtr<FrameNode>& lastSelectedItem)
464     {
465         lastSelectedItem_ = lastSelectedItem;
466     }
467 
UpdateLastPosition(std::optional<OffsetF> lastPosition)468     void UpdateLastPosition(std::optional<OffsetF> lastPosition)
469     {
470         lastPosition_ = lastPosition;
471     }
472 
473     void OnItemPressed(const RefPtr<UINode>& parent, int32_t index, bool press, bool hover = false);
474 
SetIsEmbedded()475     void SetIsEmbedded()
476     {
477         isEmbedded_ = true;
478     }
IsEmbedded()479     bool IsEmbedded()
480     {
481         return isEmbedded_;
482     }
SetIsStackSubmenu()483     void SetIsStackSubmenu()
484     {
485         isStackSubmenu_ = true;
486     }
IsStackSubmenu()487     bool IsStackSubmenu()
488     {
489         return isStackSubmenu_;
490     }
SetMenuWindowRect(const Rect & menuWindowRect)491     void SetMenuWindowRect(const Rect& menuWindowRect)
492     {
493         menuWindowRect_ = menuWindowRect;
494     }
GetMenuWindowRect()495     Rect GetMenuWindowRect() const
496     {
497         return menuWindowRect_;
498     }
499 
500 protected:
501     void UpdateMenuItemChildren(RefPtr<UINode>& host);
502     void SetMenuAttribute(RefPtr<FrameNode>& host);
503     void SetAccessibilityAction();
SetType(MenuType value)504     void SetType(MenuType value)
505     {
506         type_ = value;
507     }
ResetNeedDivider()508     void ResetNeedDivider()
509     {
510         isNeedDivider_ = false;
511     }
512     virtual void InitTheme(const RefPtr<FrameNode>& host);
513     virtual void UpdateBorderRadius(const RefPtr<FrameNode>& menuNode, const BorderRadiusProperty& borderRadius);
514 
515 private:
516     void OnAttachToFrameNode() override;
517     void OnDetachFromFrameNode(FrameNode* frameNode) override;
518     void RegisterOnTouch();
519     void OnTouchEvent(const TouchEventInfo& info);
520     bool OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config) override;
521 
522     // If CustomBuilder is declared with <Menu> and <MenuItem>,
523     // reset outer menu container and only apply theme on the inner <Menu> node.
524     void ResetTheme(const RefPtr<FrameNode>& host, bool resetForDesktopMenu);
525     void CopyMenuAttr(const RefPtr<FrameNode>& menuNode) const;
526 
527     void RegisterOnKeyEvent(const RefPtr<FocusHub>& focusHub);
528     bool OnKeyEvent(const KeyEvent& event) const;
529 
530     void DisableTabInMenu();
531 
532     Offset GetTransformCenter() const;
533     void ShowPreviewMenuAnimation();
534     void ShowPreviewMenuScaleAnimation();
535     void ShowMenuAppearAnimation();
536     void ShowStackExpandMenu();
537     std::pair<OffsetF, OffsetF> GetMenuOffset(const RefPtr<FrameNode>& outterMenu,
538         bool isNeedRestoreNodeId = false) const;
539     MenuItemInfo GetInnerMenuOffset(const RefPtr<UINode>& child, bool isNeedRestoreNodeId) const;
540     MenuItemInfo GetMenuItemInfo(const RefPtr<UINode>& child, bool isNeedRestoreNodeId) const;
541     void ShowArrowRotateAnimation() const;
542     RefPtr<FrameNode> GetImageNode(const RefPtr<FrameNode>& host) const;
543 
544     void InitPanEvent(const RefPtr<GestureEventHub>& gestureHub);
545     void HandleDragEnd(float offsetX, float offsetY, float velocity);
546     void HandleScrollDragEnd(float offsetX, float offsetY, float velocity);
547     RefPtr<UINode> GetForEachMenuItem(const RefPtr<UINode>& parent, bool next);
548     RefPtr<UINode> GetOutsideForEachMenuItem(const RefPtr<UINode>& forEachNode, bool next);
549 
550     RefPtr<FrameNode> BuildContentModifierNode(int index);
551     bool IsMenuScrollable() const;
552 
553     RefPtr<ClickEvent> onClick_;
554     RefPtr<TouchEventImpl> onTouch_;
555     std::optional<Offset> lastTouchOffset_;
556     const int32_t targetId_ = -1;
557     const std::string targetTag_;
558     MenuType type_ = MenuType::MENU;
559     std::vector<SelectProperties> selectProperties_;
560     std::vector<SelectParam> selectParams_;
561     std::optional<SelectMakeCallback> makeFunc_;
562 
563     RefPtr<FrameNode> parentMenuItem_;
564     RefPtr<FrameNode> showedSubMenu_;
565     std::vector<RefPtr<FrameNode>> options_;
566     std::optional<int32_t> foldDisplayModeChangedCallbackId_;
567 
568     bool isSelectMenu_ = false;
569     MenuPreviewMode previewMode_ = MenuPreviewMode::NONE;
570     MenuPreviewAnimationOptions previewAnimationOptions_;
571     bool isShowHoverImage_ = false;
572     bool isFirstShow_ = false;
573     bool isExtensionMenuShow_ = false;
574     bool isSubMenuShow_ = false;
575     bool isMenuShow_ = false;
576     bool hasAnimation_ = true;
577     bool needHideAfterTouch_ = true;
578 
579     std::optional<OffsetF> lastPosition_;
580     OffsetF originOffset_;
581     OffsetF endOffset_;
582     OffsetF previewOriginOffset_;
583 
584     WeakPtr<FrameNode> builderNode_;
585     bool isWidthModifiedBySelect_ = false;
586     bool isHeightModifiedBySelect_ = false;
587     bool hasLaid_ = false;
588     bool hasOptionWidth_ = false;
589     SizeF targetSize_;
590     bool expandDisplay_ = false;
591     RefPtr<FrameNode> lastSelectedItem_ = nullptr;
592     bool isEmbedded_ = false;
593     bool isStackSubmenu_ = false;
594     bool isNeedDivider_ = false;
595     Rect menuWindowRect_;
596 
597     ACE_DISALLOW_COPY_AND_MOVE(MenuPattern);
598 };
599 
600 // pattern of inner menu, corersponds to <Menu> tag in the frontend
601 class InnerMenuPattern : public MenuPattern {
602     DECLARE_ACE_TYPE(InnerMenuPattern, MenuPattern);
603 
604 public:
InnerMenuPattern(int32_t targetId,std::string tag,MenuType type)605     InnerMenuPattern(int32_t targetId, std::string tag, MenuType type) : MenuPattern(targetId, std::move(tag), type) {}
606     ~InnerMenuPattern() override = default;
607     void OnModifyDone() override;
608     void BeforeCreateLayoutWrapper() override;
609 
GetItemsAndGroups()610     const std::list<WeakPtr<UINode>>& GetItemsAndGroups() const
611     {
612         return itemsAndGroups_;
613     }
614 
615 private:
616     void InitTheme(const RefPtr<FrameNode>& host) override;
617     void UpdateBorderRadius(const RefPtr<FrameNode>& menuNode, const BorderRadiusProperty& borderRadius) override;
618     uint32_t FindSiblingMenuCount();
619     void ApplyDesktopMenuTheme();
620     void ApplyMultiMenuTheme();
621 
622     void RecordItemsAndGroups();
623 
624     // Record menu's items and groups at first level,
625     // use for group header and footer padding
626     std::list<WeakPtr<UINode>> itemsAndGroups_;
627 
628     ACE_DISALLOW_COPY_AND_MOVE(InnerMenuPattern);
629 };
630 } // namespace OHOS::Ace::NG
631 
632 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_MENU_MENU_PATTERN_H
633