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