1 /*
2  * Copyright (c) 2022 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_WRAPPER_PATTERN_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_MENU_MENU_WRAPPER_PATTERN_H
18 
19 #include "base/memory/ace_type.h"
20 #include "base/memory/referenced.h"
21 #include "base/subwindow/subwindow_manager.h"
22 #include "base/utils/string_utils.h"
23 #include "base/utils/utils.h"
24 #include "core/components/common/properties/color.h"
25 #include "core/components/common/properties/placement.h"
26 #include "core/components_ng/base/frame_node.h"
27 #include "core/components_ng/pattern/menu/menu_item/menu_item_pattern.h"
28 #include "core/components_ng/pattern/menu/menu_layout_algorithm.h"
29 #include "core/components_ng/pattern/menu/menu_pattern.h"
30 #include "core/components_ng/pattern/menu/wrapper/menu_wrapper_layout_algorithm.h"
31 #include "core/components_ng/pattern/overlay/popup_base_pattern.h"
32 #include "core/components_ng/pattern/pattern.h"
33 #include "core/components_v2/inspector/inspector_constants.h"
34 #include "core/pipeline_ng/ui_task_scheduler.h"
35 
36 namespace OHOS::Ace::NG {
37 
38 enum class MenuStatus {
39     INIT,              // Neither exists in the menuMap_ nor on the tree
40     ON_SHOW_ANIMATION, // Exists in the menuMap_ also exists on the tree
41     SHOW,              // Exists in the menuMap_ also exists on the tree
42     ON_HIDE_ANIMATION, // Exists in the menuMap_ also exists on the tree
43     HIDE               // Exists in the menuMap_ but not on the tree
44 };
45 
46 // has full screen size
47 // used for detecting clicks outside Menu area
48 class MenuWrapperPattern : public PopupBasePattern {
49     DECLARE_ACE_TYPE(MenuWrapperPattern, Pattern);
50 
51 public:
MenuWrapperPattern(int32_t Id)52     explicit MenuWrapperPattern(int32_t Id) : targetId_(Id) {}
53     ~MenuWrapperPattern() override = default;
54 
IsAtomicNode()55     bool IsAtomicNode() const override
56     {
57         return false;
58     }
59 
GetFocusPattern()60     FocusPattern GetFocusPattern() const override
61     {
62         return { FocusType::SCOPE, true };
63     }
64 
CreateLayoutAlgorithm()65     RefPtr<LayoutAlgorithm> CreateLayoutAlgorithm() override
66     {
67         return MakeRefPtr<MenuWrapperLayoutAlgorithm>();
68     }
69 
70     void HandleMouseEvent(const MouseInfo& info, RefPtr<MenuItemPattern>& menuItem);
71 
GetTargetId()72     int32_t GetTargetId() const override
73     {
74         return targetId_;
75     }
76 
77     void HideMenu();
78 
IsHide()79     bool IsHide() const
80     {
81         return menuStatus_ == MenuStatus::ON_HIDE_ANIMATION || menuStatus_ == MenuStatus::HIDE;
82     }
83 
IsContextMenu()84     bool IsContextMenu() const
85     {
86         auto menu = GetMenu();
87         CHECK_NULL_RETURN(menu, false);
88         auto menuPattern = menu->GetPattern<MenuPattern>();
89         CHECK_NULL_RETURN(menuPattern, false);
90         return menuPattern->IsContextMenu();
91     }
92 
GetPreviewMode()93     MenuPreviewMode GetPreviewMode() const
94     {
95         auto menu = GetMenu();
96         CHECK_NULL_RETURN(menu, MenuPreviewMode::NONE);
97         auto menuPattern = menu->GetPattern<MenuPattern>();
98         CHECK_NULL_RETURN(menuPattern, MenuPreviewMode::NONE);
99         return menuPattern->GetPreviewMode();
100     }
101 
IsSelectMenu()102     bool IsSelectMenu() const
103     {
104         auto menu = GetMenu();
105         CHECK_NULL_RETURN(menu, false);
106         auto menuPattern = menu->GetPattern<MenuPattern>();
107         CHECK_NULL_RETURN(menuPattern, false);
108         return menuPattern->IsSelectMenu();
109     }
110 
111     void HideSubMenu();
112     RefPtr<FrameNode> MenuFocusViewShow();
113     void HideStackExpandMenu(const RefPtr<UINode>& subMenu);
114     void GetExpandingMode(const RefPtr<UINode>& subMenu, SubMenuExpandingMode& expandingMode, bool& hasAnimation);
GetMenu()115     RefPtr<FrameNode> GetMenu() const
116     {
117         auto host = GetHost();
118         CHECK_NULL_RETURN(host, nullptr);
119         auto menu = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(0));
120         CHECK_NULL_RETURN(menu, nullptr);
121         return menu;
122     }
123 
GetHoverImageFlexNode()124     RefPtr<FrameNode> GetHoverImageFlexNode() const
125     {
126         auto host = GetHost();
127         CHECK_NULL_RETURN(host, nullptr);
128         auto node = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(1));
129         CHECK_NULL_RETURN(node, nullptr);
130         if (node->GetTag() != V2::FLEX_ETS_TAG) {
131             return nullptr;
132         }
133         return node;
134     }
135 
GetHoverImageStackNode()136     RefPtr<FrameNode> GetHoverImageStackNode() const
137     {
138         auto hoverImageFlexNode = GetHoverImageFlexNode();
139         CHECK_NULL_RETURN(hoverImageFlexNode, nullptr);
140         auto node = AceType::DynamicCast<FrameNode>(hoverImageFlexNode->GetChildAtIndex(0));
141         CHECK_NULL_RETURN(node, nullptr);
142         if (node->GetTag() != V2::STACK_ETS_TAG) {
143             return nullptr;
144         }
145         return node;
146     }
147 
GetHoverImagePreview()148     RefPtr<FrameNode> GetHoverImagePreview() const
149     {
150         auto hoverImageStackNode = GetHoverImageStackNode();
151         CHECK_NULL_RETURN(hoverImageStackNode, nullptr);
152         auto node = AceType::DynamicCast<FrameNode>(hoverImageStackNode->GetChildAtIndex(0));
153         CHECK_NULL_RETURN(node, nullptr);
154         if (node->GetTag() != V2::IMAGE_ETS_TAG) {
155             return nullptr;
156         }
157         return node;
158     }
159 
GetHoverImageCustomPreview()160     RefPtr<FrameNode> GetHoverImageCustomPreview() const
161     {
162         auto hoverImageStackNode = GetHoverImageStackNode();
163         CHECK_NULL_RETURN(hoverImageStackNode, nullptr);
164         auto node = AceType::DynamicCast<FrameNode>(hoverImageStackNode->GetChildAtIndex(1));
165         CHECK_NULL_RETURN(node, nullptr);
166         if (node->GetTag() != V2::MENU_PREVIEW_ETS_TAG) {
167             return nullptr;
168         }
169         return node;
170     }
171 
GetPreview()172     RefPtr<FrameNode> GetPreview() const
173     {
174         auto host = GetHost();
175         CHECK_NULL_RETURN(host, nullptr);
176         auto preview = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(1));
177         CHECK_NULL_RETURN(preview, nullptr);
178         if (preview->GetTag() == V2::FLEX_ETS_TAG) {
179             auto hoverImageCustomPreview = GetHoverImageCustomPreview();
180             CHECK_NULL_RETURN(hoverImageCustomPreview, preview);
181             return hoverImageCustomPreview;
182         }
183         return preview;
184     }
185 
186     // used to obtain the Badge node and delete it.
GetBadgeNode()187     RefPtr<FrameNode> GetBadgeNode() const
188     {
189         auto host = GetHost();
190         CHECK_NULL_RETURN(host, nullptr);
191         for (const auto& child : host->GetChildren()) {
192             auto node = DynamicCast<FrameNode>(child);
193             if (node && node->GetTag() == V2::TEXT_ETS_TAG) {
194                 return node;
195             }
196         }
197         return nullptr;
198     }
199 
200     OffsetT<Dimension> GetAnimationOffset();
201     void SetAniamtinOption(const AnimationOption& animationOption);
202 
SetMenuPlacementAfterLayout(const Placement & placement)203     void SetMenuPlacementAfterLayout(const Placement& placement)
204     {
205         menuPlacement_ = placement;
206     }
207 
SetFirstShow()208     void SetFirstShow()
209     {
210         isFirstShow_ = true;
211     }
212 
GetIsFirstShow()213     bool GetIsFirstShow() const
214     {
215         return isFirstShow_;
216     }
217 
SetIsShowHoverImage(bool isShow)218     void SetIsShowHoverImage(bool isShow)
219     {
220         isShowHoverImage_ = isShow;
221     }
222 
GetIsShowHoverImage()223     bool GetIsShowHoverImage() const
224     {
225         return isShowHoverImage_;
226     }
227 
SetIsStopHoverImageAnimation(bool isStop)228     void SetIsStopHoverImageAnimation(bool isStop)
229     {
230         isStopHoverImageAnimation_ = isStop;
231     }
232 
IsStopHoverImageAnimation()233     bool IsStopHoverImageAnimation() const
234     {
235         return isStopHoverImageAnimation_;
236     }
237 
SetIsShowHoverImagePreviewStartDrag(bool isStart)238     void SetIsShowHoverImagePreviewStartDrag(bool isStart)
239     {
240         isShowHoverImagePreviewStartDrag_ = isStart;
241     }
242 
GetIsShowHoverImagePreviewStartDrag()243     bool GetIsShowHoverImagePreviewStartDrag() const
244     {
245         return isShowHoverImagePreviewStartDrag_;
246     }
247 
248     void RegisterMenuCallback(const RefPtr<FrameNode>& menuWrapperNode, const MenuParam& menuParam);
249 
RegisterMenuAppearCallback(const std::function<void ()> & onAppear)250     void RegisterMenuAppearCallback(const std::function<void()>& onAppear)
251     {
252         onAppearCallback_ = onAppear;
253     }
254 
RegisterMenuDisappearCallback(const std::function<void ()> & onDisappear)255     void RegisterMenuDisappearCallback(const std::function<void()>& onDisappear)
256     {
257         onDisappearCallback_ = onDisappear;
258     }
259 
RegisterMenuAboutToAppearCallback(const std::function<void ()> & aboutToAppear)260     void RegisterMenuAboutToAppearCallback(const std::function<void()>& aboutToAppear)
261     {
262         aboutToAppearCallback_ = aboutToAppear;
263     }
264 
RegisterMenuAboutToDisappearCallback(const std::function<void ()> & aboutToDisappear)265     void RegisterMenuAboutToDisappearCallback(const std::function<void()>& aboutToDisappear)
266     {
267         aboutToDisappearCallback_ = aboutToDisappear;
268     }
269 
RegisterMenuStateChangeCallback(const std::function<void (const std::string &)> & callback)270     void RegisterMenuStateChangeCallback(const std::function<void(const std::string&)>& callback)
271     {
272         onStateChangeCallback_ = callback;
273     }
274 
CallMenuAppearCallback()275     void CallMenuAppearCallback()
276     {
277         if (onAppearCallback_) {
278             onAppearCallback_();
279         }
280     }
281 
CallMenuDisappearCallback()282     void CallMenuDisappearCallback()
283     {
284         if (onDisappearCallback_) {
285             onDisappearCallback_();
286         }
287     }
288 
CallMenuAboutToAppearCallback()289     void CallMenuAboutToAppearCallback()
290     {
291         if (aboutToAppearCallback_) {
292             aboutToAppearCallback_();
293         }
294     }
295 
CallMenuAboutToDisappearCallback()296     void CallMenuAboutToDisappearCallback()
297     {
298         if (aboutToDisappearCallback_) {
299             aboutToDisappearCallback_();
300         }
301     }
302 
CallMenuStateChangeCallback(const std::string & value)303     void CallMenuStateChangeCallback(const std::string& value)
304     {
305         if (onStateChangeCallback_) {
306             onStateChangeCallback_(value);
307         }
308     }
309 
GetMenuDisappearCallback()310     const std::function<void()>& GetMenuDisappearCallback()
311     {
312         return onDisappearCallback_;
313     }
314 
IsShow()315     bool IsShow() const
316     {
317         return menuStatus_ == MenuStatus::ON_SHOW_ANIMATION || menuStatus_ == MenuStatus::SHOW;
318     }
319 
SetMenuStatus(MenuStatus value)320     void SetMenuStatus(MenuStatus value)
321     {
322         menuStatus_ = value;
323     }
324 
GetMenuStatus()325     MenuStatus GetMenuStatus() const
326     {
327         return menuStatus_;
328     }
329 
HasTransitionEffect()330     bool HasTransitionEffect() const
331     {
332         return hasTransitionEffect_;
333     }
334 
SetHasTransitionEffect(bool hasTransitionEffect)335     void SetHasTransitionEffect(bool hasTransitionEffect)
336     {
337         hasTransitionEffect_ = hasTransitionEffect;
338     }
339 
340     void SetMenuTransitionEffect(const RefPtr<FrameNode>& menuWrapperNode, const MenuParam& menuParam);
341 
HasPreviewTransitionEffect()342     bool HasPreviewTransitionEffect() const
343     {
344         return hasPreviewTransitionEffect_;
345     }
346 
SetHasPreviewTransitionEffect(bool hasPreviewTransitionEffect)347     void SetHasPreviewTransitionEffect(bool hasPreviewTransitionEffect)
348     {
349         hasPreviewTransitionEffect_ = hasPreviewTransitionEffect;
350     }
351 
HasFoldModeChangedTransition()352     bool HasFoldModeChangedTransition() const
353     {
354         return hasFoldModeChangeTransition_;
355     }
356 
SetHasFoldModeChangedTransition(bool hasTransition)357     void SetHasFoldModeChangedTransition(bool hasTransition)
358     {
359         hasFoldModeChangeTransition_ = hasTransition;
360     }
361 
SetFilterColumnNode(const RefPtr<FrameNode> & columnNode)362     void SetFilterColumnNode(const RefPtr<FrameNode>& columnNode)
363     {
364         filterColumnNode_ = columnNode;
365     }
366 
GetFilterColumnNode()367     RefPtr<FrameNode> GetFilterColumnNode()
368     {
369         return filterColumnNode_;
370     }
371 
372     void DumpInfo() override;
373 
GetDumpInfo()374     MenuDumpInfo GetDumpInfo() const
375     {
376         return dumpInfo_;
377     }
378 
SetDumpInfo(const MenuDumpInfo & dumpInfo)379     void SetDumpInfo(const MenuDumpInfo& dumpInfo)
380     {
381         dumpInfo_.menuPreviewMode = dumpInfo.menuPreviewMode;
382         dumpInfo_.menuType = dumpInfo.menuType;
383         dumpInfo_.enableArrow = dumpInfo.enableArrow;
384         dumpInfo_.targetNode = dumpInfo.targetNode;
385         dumpInfo_.targetOffset = dumpInfo.targetOffset;
386         dumpInfo_.targetSize = dumpInfo.targetSize;
387         dumpInfo_.menuWindowRect = dumpInfo.menuWindowRect;
388         dumpInfo_.wrapperRect = dumpInfo.wrapperRect;
389         dumpInfo_.previewBeginScale = dumpInfo.previewBeginScale;
390         dumpInfo_.previewEndScale = dumpInfo.previewEndScale;
391         dumpInfo_.top = dumpInfo.top;
392         dumpInfo_.bottom = dumpInfo.bottom;
393         dumpInfo_.globalLocation = dumpInfo.globalLocation;
394         dumpInfo_.originPlacement = dumpInfo.originPlacement;
395         dumpInfo_.defaultPlacement = dumpInfo.defaultPlacement;
396         dumpInfo_.finalPosition = dumpInfo.finalPosition;
397         dumpInfo_.finalPlacement = dumpInfo.finalPlacement;
398     }
399 
GetHasCustomRadius()400     bool GetHasCustomRadius() const
401     {
402         return hasCustomRadius_;
403     }
404 
SetHasCustomRadius(bool hasCustomRadius)405     void SetHasCustomRadius(bool hasCustomRadius)
406     {
407         hasCustomRadius_ = hasCustomRadius;
408     }
409 
GetLastTouchItem()410     RefPtr<FrameNode> GetLastTouchItem()
411     {
412         return lastTouchItem_;
413     }
414 
SetLastTouchItem(const RefPtr<FrameNode> & lastTouchItem)415     void SetLastTouchItem(const RefPtr<FrameNode>& lastTouchItem)
416     {
417         lastTouchItem_ = lastTouchItem;
418     }
419 
420     RefPtr<FrameNode> GetMenuChild(const RefPtr<UINode>& node);
421     RefPtr<FrameNode> GetShowedSubMenu();
422     bool IsSelectOverlayCustomMenu(const RefPtr<FrameNode>& menu) const;
423     bool HasStackSubMenu();
424 
IncreaseEmbeddedSubMenuCount()425     int IncreaseEmbeddedSubMenuCount()
426     {
427         return ++embeddedSubMenuCount_;
428     }
429 
DecreaseEmbeddedSubMenuCount()430     int DecreaseEmbeddedSubMenuCount()
431     {
432         return --embeddedSubMenuCount_;
433     }
434 
435     bool HasEmbeddedSubMenu();
436     void UpdateMenuAnimation(const RefPtr<FrameNode>& host);
437     void ClearAllSubMenu();
438     int embeddedSubMenuCount_ = 0;
439     void StopHoverImageToPreviewAnimation();
440 
SetHoverImageToPreviewScale(float scale)441     void SetHoverImageToPreviewScale(float scale)
442     {
443         hoverImageToPreviewScale_ = scale;
444     }
445 
GetHoverImageToPreviewScale()446     float GetHoverImageToPreviewScale() const
447     {
448         return hoverImageToPreviewScale_;
449     }
450 
SetHoverImageToPreviewRate(float rate)451     void SetHoverImageToPreviewRate(float rate)
452     {
453         hoverImageToPreviewRate_ = rate;
454     }
455 
GetHoverImageToPreviewRate()456     float GetHoverImageToPreviewRate() const
457     {
458         return hoverImageToPreviewRate_;
459     }
460 
SetMenuParam(const MenuParam & param)461     void SetMenuParam(const MenuParam& param)
462     {
463         menuParam_ = param;
464     }
465 
GetMenuParam()466     const MenuParam& GetMenuParam() const
467     {
468         return menuParam_;
469     }
470 
SetIsShowFromUser(bool isShow)471     void SetIsShowFromUser(bool isShow)
472     {
473         isShowFromUser_ = isShow;
474     }
475 
GetIsShowFromUser()476     bool GetIsShowFromUser() const
477     {
478         return isShowFromUser_;
479     }
480 
SetChildLayoutConstraint(LayoutConstraintF constraint)481     void SetChildLayoutConstraint(LayoutConstraintF constraint)
482     {
483         childLayoutConstraint_ = constraint;
484     }
485 
GetChildLayoutConstraint()486     LayoutConstraintF GetChildLayoutConstraint() const
487     {
488         return childLayoutConstraint_;
489     }
490 
491 protected:
492     void OnTouchEvent(const TouchEventInfo& info);
493     void CheckAndShowAnimation();
494 
495 private:
AvoidKeyboard()496     bool AvoidKeyboard() const override
497     {
498         return false;
499     }
AvoidBottom()500     bool AvoidBottom() const override
501     {
502         return false;
503     }
504     void OnModifyDone() override;
505     void InitFocusEvent();
506     void OnAttachToFrameNode() override;
507     void RegisterOnTouch();
508     bool OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config) override;
509     // mark self and all children no-draggable
510     void MarkWholeSubTreeNoDraggable(const RefPtr<FrameNode>& frameNode);
511     void MarkAllMenuNoDraggable();
512     void SetHotAreas(const RefPtr<LayoutWrapper>& layoutWrapper);
513     void StartShowAnimation();
514     void HandleInteraction(const TouchEventInfo& info);
515     void ChangeTouchItem(const TouchEventInfo& info, TouchType touchType);
516     void ChangeCurMenuItemBgColor();
517     void ClearLastMenuItem();
518     RectF GetMenuZone(RefPtr<UINode>& innerMenuNode);
519     RefPtr<FrameNode> FindTouchedMenuItem(const RefPtr<UINode>& menuNode, const OffsetF& position);
520 
521     void HideMenu(const RefPtr<FrameNode>& menu);
522     void HideMenu(const RefPtr<MenuPattern>& menuPattern, const RefPtr<FrameNode>& menu, const OffsetF& position);
523     void SetExitAnimation(const RefPtr<FrameNode>& host);
524     void SendToAccessibility(const RefPtr<UINode>& subMenu, bool isShow);
525     std::function<void()> onAppearCallback_ = nullptr;
526     std::function<void()> onDisappearCallback_ = nullptr;
527     std::function<void()> aboutToAppearCallback_ = nullptr;
528     std::function<void()> aboutToDisappearCallback_ = nullptr;
529     std::function<void(const std::string&)> onStateChangeCallback_ = nullptr;
530     RefPtr<TouchEventImpl> onTouch_;
531     RefPtr<FrameNode> lastTouchItem_ = nullptr;
532     RefPtr<FrameNode> currentTouchItem_ = nullptr;
533     // menuId in OverlayManager's map
534     int32_t targetId_ = -1;
535     LayoutConstraintF childLayoutConstraint_;
536 
537     AnimationOption animationOption_;
538     Placement menuPlacement_ = Placement::NONE;
539     bool isFirstShow_ = true;
540     bool isShowInSubWindow_ = true;
541     bool isShowHoverImage_ = false;
542     bool isStopHoverImageAnimation_ = false;
543     bool isShowHoverImagePreviewStartDrag_ = false;
544     MenuStatus menuStatus_ = MenuStatus::INIT;
545     bool hasTransitionEffect_ = false;
546     bool hasPreviewTransitionEffect_ = false;
547     bool hasFoldModeChangeTransition_ = false;
548     RefPtr<FrameNode> filterColumnNode_;
549     MenuDumpInfo dumpInfo_;
550     bool hasCustomRadius_ = false;
551     float hoverImageToPreviewRate_ = -1.0;
552     float hoverImageToPreviewScale_ = -1.0;
553     MenuParam menuParam_;
554     bool isShowFromUser_ = false;
555     int32_t fingerId_ = -1;
556     ACE_DISALLOW_COPY_AND_MOVE(MenuWrapperPattern);
557 };
558 } // namespace OHOS::Ace::NG
559 
560 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_MENU_MENU_WRAPPER_PATTERN_H
561