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