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 GetIsFirstShow()325 bool GetIsFirstShow() const 326 { 327 return isFirstShow_; 328 } 329 SetOriginOffset(const OffsetF & offset)330 void SetOriginOffset(const OffsetF& offset) 331 { 332 originOffset_ = offset; 333 } 334 SetEndOffset(const OffsetF & offset)335 void SetEndOffset(const OffsetF& offset) 336 { 337 endOffset_ = offset; 338 } 339 GetEndOffset()340 OffsetF GetEndOffset() const 341 { 342 return endOffset_; 343 } 344 SetSelectOverlayExtensionMenuShow()345 void SetSelectOverlayExtensionMenuShow() 346 { 347 isExtensionMenuShow_ = true; 348 } 349 SetDisappearAnimation(bool hasAnimation)350 void SetDisappearAnimation(bool hasAnimation) 351 { 352 // false:exit from BOTTOM to TOP 353 // true:exit from LEFT_BOTTOM to RIGHT_TOP 354 hasAnimation_ = hasAnimation; 355 } 356 GetDisappearAnimation()357 bool GetDisappearAnimation() const 358 { 359 return hasAnimation_; 360 } 361 SetSubMenuShow()362 void SetSubMenuShow() 363 { 364 isSubMenuShow_ = true; 365 } 366 SetMenuShow()367 void SetMenuShow() 368 { 369 isMenuShow_ = true; 370 } 371 SetPreviewOriginOffset(const OffsetF & offset)372 void SetPreviewOriginOffset(const OffsetF& offset) 373 { 374 previewOriginOffset_ = offset; 375 } 376 GetPreviewOriginOffset()377 OffsetF GetPreviewOriginOffset() const 378 { 379 return previewOriginOffset_; 380 } 381 SetPreviewRect(RectF rect)382 void SetPreviewRect(RectF rect) 383 { 384 previewRect_ = rect; 385 } 386 GetPreviewRect()387 RectF GetPreviewRect() const 388 { 389 return previewRect_; 390 } 391 SetPreviewIdealSize(SizeF size)392 void SetPreviewIdealSize(SizeF size) 393 { 394 previewIdealSize_ = size; 395 } 396 GetPreviewIdealSize()397 SizeF GetPreviewIdealSize() const 398 { 399 return previewIdealSize_; 400 } 401 SetHasLaid(bool hasLaid)402 void SetHasLaid(bool hasLaid) 403 { 404 hasLaid_ = hasLaid; 405 } 406 HasLaid()407 bool HasLaid() const 408 { 409 return hasLaid_; 410 } 411 SetTargetSize(const SizeF & size)412 void SetTargetSize(const SizeF& size) 413 { 414 targetSize_ = size; 415 } 416 GetTargetSize()417 SizeF GetTargetSize() const 418 { 419 return targetSize_; 420 } 421 SetTargetOffset(const OffsetF & offset)422 void SetTargetOffset(const OffsetF& offset) 423 { 424 targetOffset_ = offset; 425 } 426 GetTargetOffset()427 OffsetF GetTargetOffset() const 428 { 429 return targetOffset_; 430 } 431 SetIsHeightModifiedBySelect(bool isModified)432 void SetIsHeightModifiedBySelect(bool isModified) 433 { 434 isHeightModifiedBySelect_ = isModified; 435 } 436 IsHeightModifiedBySelect()437 bool IsHeightModifiedBySelect() const 438 { 439 return isHeightModifiedBySelect_; 440 } 441 GetMenuExpandDisplay()442 bool GetMenuExpandDisplay() const 443 { 444 return expandDisplay_; 445 } 446 447 void ShowMenuDisappearAnimation(); 448 void ShowStackExpandDisappearAnimation(const RefPtr<FrameNode>& menuNode, 449 const RefPtr<FrameNode>& subMenuNode, AnimationOption& option) const; 450 SetBuilderFunc(SelectMakeCallback && makeFunc)451 void SetBuilderFunc(SelectMakeCallback&& makeFunc) 452 { 453 makeFunc_ = std::move(makeFunc); 454 } 455 ResetBuilderFunc()456 void ResetBuilderFunc() 457 { 458 makeFunc_ = std::nullopt; 459 } 460 461 void UpdateSelectIndex(int32_t index); 462 SetSelectProperties(const std::vector<SelectParam> & params)463 void SetSelectProperties(const std::vector<SelectParam>& params) 464 { 465 auto list = selectProperties_; 466 selectParams_ = params; 467 selectProperties_.clear(); 468 for (size_t i = 0; i < params.size(); i++) { 469 SelectProperties selectProperty; 470 selectProperty.value = params[i].text; 471 selectProperty.icon = params[i].icon; 472 selectProperty.symbolModifier = params[i].symbolModifier; 473 selectProperty.index = static_cast<int>(i); 474 if (i < list.size()) { 475 selectProperty.selected = list[i].selected; 476 selectProperty.selectEnable = list[i].selectEnable; 477 } 478 selectProperties_.push_back(selectProperty); 479 } 480 } 481 482 bool GetShadowFromTheme(ShadowStyle shadowStyle, Shadow& shadow); 483 UseContentModifier()484 bool UseContentModifier() 485 { 486 return builderNode_.Upgrade() != nullptr; 487 } 488 489 void FireBuilder(); 490 491 BorderRadiusProperty CalcIdealBorderRadius(const BorderRadiusProperty& borderRadius, const SizeF& menuSize); 492 GetLastSelectedItem()493 RefPtr<FrameNode> GetLastSelectedItem() 494 { 495 return lastSelectedItem_; 496 } 497 SetLastSelectedItem(const RefPtr<FrameNode> & lastSelectedItem)498 void SetLastSelectedItem(const RefPtr<FrameNode>& lastSelectedItem) 499 { 500 lastSelectedItem_ = lastSelectedItem; 501 } 502 UpdateLastPosition(std::optional<OffsetF> lastPosition)503 void UpdateLastPosition(std::optional<OffsetF> lastPosition) 504 { 505 lastPosition_ = lastPosition; 506 } 507 508 void OnItemPressed(const RefPtr<UINode>& parent, int32_t index, bool press, bool hover = false); 509 SetIsEmbedded()510 void SetIsEmbedded() 511 { 512 isEmbedded_ = true; 513 } IsEmbedded()514 bool IsEmbedded() 515 { 516 return isEmbedded_; 517 } SetIsStackSubmenu()518 void SetIsStackSubmenu() 519 { 520 isStackSubmenu_ = true; 521 } IsStackSubmenu()522 bool IsStackSubmenu() 523 { 524 return isStackSubmenu_; 525 } SetMenuWindowRect(const Rect & menuWindowRect)526 void SetMenuWindowRect(const Rect& menuWindowRect) 527 { 528 menuWindowRect_ = menuWindowRect; 529 } GetMenuWindowRect()530 Rect GetMenuWindowRect() const 531 { 532 return menuWindowRect_; 533 } 534 535 protected: 536 void UpdateMenuItemChildren(RefPtr<UINode>& host); 537 void SetMenuAttribute(RefPtr<FrameNode>& host); 538 void SetAccessibilityAction(); SetType(MenuType value)539 void SetType(MenuType value) 540 { 541 type_ = value; 542 } ResetNeedDivider()543 void ResetNeedDivider() 544 { 545 isNeedDivider_ = false; 546 } 547 virtual void InitTheme(const RefPtr<FrameNode>& host); 548 virtual void UpdateBorderRadius(const RefPtr<FrameNode>& menuNode, const BorderRadiusProperty& borderRadius); 549 550 private: 551 void OnAttachToFrameNode() override; 552 void OnDetachFromFrameNode(FrameNode* frameNode) override; 553 void RegisterOnTouch(); 554 void OnTouchEvent(const TouchEventInfo& info); 555 bool OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config) override; 556 557 // If CustomBuilder is declared with <Menu> and <MenuItem>, 558 // reset outer menu container and only apply theme on the inner <Menu> node. 559 void ResetTheme(const RefPtr<FrameNode>& host, bool resetForDesktopMenu); 560 void CopyMenuAttr(const RefPtr<FrameNode>& menuNode) const; 561 562 void RegisterOnKeyEvent(const RefPtr<FocusHub>& focusHub); 563 bool OnKeyEvent(const KeyEvent& event) const; 564 565 void DisableTabInMenu(); 566 567 Offset GetTransformCenter() const; 568 void ShowPreviewMenuAnimation(); 569 void ShowPreviewMenuScaleAnimation(); 570 void ShowMenuAppearAnimation(); 571 void ShowStackExpandMenu(); 572 std::pair<OffsetF, OffsetF> GetMenuOffset(const RefPtr<FrameNode>& outterMenu, 573 bool isNeedRestoreNodeId = false) const; 574 MenuItemInfo GetInnerMenuOffset(const RefPtr<UINode>& child, bool isNeedRestoreNodeId) const; 575 MenuItemInfo GetMenuItemInfo(const RefPtr<UINode>& child, bool isNeedRestoreNodeId) const; 576 void ShowArrowRotateAnimation() const; 577 RefPtr<FrameNode> GetImageNode(const RefPtr<FrameNode>& host) const; 578 579 void InitPanEvent(const RefPtr<GestureEventHub>& gestureHub); 580 void HandleDragEnd(float offsetX, float offsetY, float velocity); 581 void HandleScrollDragEnd(float offsetX, float offsetY, float velocity); 582 RefPtr<UINode> GetForEachMenuItem(const RefPtr<UINode>& parent, bool next); 583 RefPtr<UINode> GetOutsideForEachMenuItem(const RefPtr<UINode>& forEachNode, bool next); 584 585 RefPtr<FrameNode> BuildContentModifierNode(int index); 586 bool IsMenuScrollable() const; 587 588 RefPtr<ClickEvent> onClick_; 589 RefPtr<TouchEventImpl> onTouch_; 590 std::optional<Offset> lastTouchOffset_; 591 const int32_t targetId_ = -1; 592 const std::string targetTag_; 593 MenuType type_ = MenuType::MENU; 594 std::vector<SelectProperties> selectProperties_; 595 std::vector<SelectParam> selectParams_; 596 std::optional<SelectMakeCallback> makeFunc_; 597 598 RefPtr<FrameNode> parentMenuItem_; 599 RefPtr<FrameNode> showedSubMenu_; 600 std::vector<RefPtr<FrameNode>> options_; 601 std::optional<int32_t> foldDisplayModeChangedCallbackId_; 602 603 bool isSelectMenu_ = false; 604 MenuPreviewMode previewMode_ = MenuPreviewMode::NONE; 605 MenuPreviewAnimationOptions previewAnimationOptions_; 606 bool isShowHoverImage_ = false; 607 bool isFirstShow_ = false; 608 bool isExtensionMenuShow_ = false; 609 bool isSubMenuShow_ = false; 610 bool isMenuShow_ = false; 611 bool hasAnimation_ = true; 612 bool needHideAfterTouch_ = true; 613 614 std::optional<OffsetF> lastPosition_; 615 OffsetF originOffset_; 616 OffsetF endOffset_; 617 OffsetF previewOriginOffset_; 618 RectF previewRect_; 619 SizeF previewIdealSize_; 620 621 WeakPtr<FrameNode> builderNode_; 622 bool isWidthModifiedBySelect_ = false; 623 bool isHeightModifiedBySelect_ = false; 624 bool hasLaid_ = false; 625 bool hasOptionWidth_ = false; 626 OffsetF targetOffset_; 627 SizeF targetSize_; 628 bool expandDisplay_ = false; 629 RefPtr<FrameNode> lastSelectedItem_ = nullptr; 630 bool isEmbedded_ = false; 631 bool isStackSubmenu_ = false; 632 bool isNeedDivider_ = false; 633 Rect menuWindowRect_; 634 635 ACE_DISALLOW_COPY_AND_MOVE(MenuPattern); 636 }; 637 638 // pattern of inner menu, corersponds to <Menu> tag in the frontend 639 class InnerMenuPattern : public MenuPattern { 640 DECLARE_ACE_TYPE(InnerMenuPattern, MenuPattern); 641 642 public: InnerMenuPattern(int32_t targetId,std::string tag,MenuType type)643 InnerMenuPattern(int32_t targetId, std::string tag, MenuType type) : MenuPattern(targetId, std::move(tag), type) {} 644 ~InnerMenuPattern() override = default; 645 void OnModifyDone() override; 646 void BeforeCreateLayoutWrapper() override; 647 GetItemsAndGroups()648 const std::list<WeakPtr<UINode>>& GetItemsAndGroups() const 649 { 650 return itemsAndGroups_; 651 } 652 653 private: 654 void InitTheme(const RefPtr<FrameNode>& host) override; 655 void UpdateBorderRadius(const RefPtr<FrameNode>& menuNode, const BorderRadiusProperty& borderRadius) override; 656 uint32_t FindSiblingMenuCount(); 657 void ApplyDesktopMenuTheme(); 658 void ApplyMultiMenuTheme(); 659 660 void RecordItemsAndGroups(); 661 662 // Record menu's items and groups at first level, 663 // use for group header and footer padding 664 std::list<WeakPtr<UINode>> itemsAndGroups_; 665 666 ACE_DISALLOW_COPY_AND_MOVE(InnerMenuPattern); 667 }; 668 } // namespace OHOS::Ace::NG 669 670 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_MENU_MENU_PATTERN_H 671