From b0aed64565f2f01f664510090ce96c3067a3718c Mon Sep 17 00:00:00 2001 From: Tintin9529 Date: Fri, 17 Jan 2025 17:58:21 +0800 Subject: [PATCH] =?UTF-8?q?menu=E6=94=AF=E6=8C=81=E5=9C=A8=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E5=9B=9E=E8=B0=83=E4=B8=AD=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tintin9529 Change-Id: Ic698f430bd2cdc33a6de37102ec66b71c8d0cd2d --- .../engine/jsUIContext.js | 61 ++++++ .../declarative_frontend/jsview/js_popups.cpp | 42 ++++- .../jsview/js_view_abstract.h | 6 + .../jsview/js_view_context.cpp | 125 +++++++++++++ .../jsview/js_view_context.h | 3 + .../jsview/models/view_abstract_model_impl.h | 13 ++ .../core/components_ng/base/view_abstract.cpp | 173 ++++++++++++++++++ .../core/components_ng/base/view_abstract.h | 10 + .../components_ng/base/view_abstract_model.h | 4 + .../base/view_abstract_model_ng.h | 13 ++ .../pattern/menu/menu_pattern.cpp | 2 + .../components_ng/pattern/menu/menu_pattern.h | 12 ++ .../components_ng/pattern/menu/menu_view.cpp | 93 ++++++++-- .../components_ng/pattern/menu/menu_view.h | 7 + .../pattern/overlay/overlay_manager.cpp | 30 +++ .../pattern/overlay/overlay_manager.h | 16 +- 16 files changed, 593 insertions(+), 17 deletions(-) diff --git a/frameworks/bridge/declarative_frontend/engine/jsUIContext.js b/frameworks/bridge/declarative_frontend/engine/jsUIContext.js index e87442ed733..2ff937c6550 100644 --- a/frameworks/bridge/declarative_frontend/engine/jsUIContext.js +++ b/frameworks/bridge/declarative_frontend/engine/jsUIContext.js @@ -1388,6 +1388,67 @@ class PromptAction { return result_; } + openMenu(content, target, options) { + __JSScopeUtil__.syncInstanceId(this.instanceId_); + let argLength = arguments.length; + let paramErrMsg = + 'Parameter error. Possible causes: 1. Mandatory parameters are left unspecified;' + + ' 2. Incorrect parameter types; 3. Parameter verification failed.'; + if (argLength < 2 || argLength > 3 || content === null || content === undefined || target === null || target === undefined) { + __JSScopeUtil__.restoreInstanceId(); + return new Promise((resolve, reject) => { + reject({ message: paramErrMsg, code: 401 }); + }); + } + let result_; + if (argLength === 2) { + result_ = Context.openMenu(content.getNodePtr(), target); + } else { + result_ = Context.openMenu(content.getNodePtr(), target, options); + } + __JSScopeUtil__.restoreInstanceId(); + return result_; + } + + updateMenu(content, options, partialUpdate) { + __JSScopeUtil__.syncInstanceId(this.instanceId_); + let argLength = arguments.length; + let paramErrMsg = + 'Parameter error. Possible causes: 1. Mandatory parameters are left unspecified;' + + ' 2. Incorrect parameter types; 3. Parameter verification failed.'; + if (argLength < 2 || argLength > 3 || content === null || content === undefined || options === null || options === undefined) { + __JSScopeUtil__.restoreInstanceId(); + return new Promise((resolve, reject) => { + reject({ message: paramErrMsg, code: 401 }); + }); + } + let result_; + if (argLength === 2) { + result_ = Context.updateMenu(content.getNodePtr(), options); + } else { + result_ = Context.updateMenu(content.getNodePtr(), options, partialUpdate); + } + __JSScopeUtil__.restoreInstanceId(); + return result_; + } + + closeMenu(content) { + __JSScopeUtil__.syncInstanceId(this.instanceId_); + let argLength = arguments.length; + const paramErrMsg = + 'Parameter error. Possible causes: 1. Mandatory parameters are left unspecified;' + + ' 2. Incorrect parameter types; 3. Parameter verification failed.'; + if (argLength !== 1 || content === null || content === undefined) { + __JSScopeUtil__.restoreInstanceId(); + return new Promise((resolve, reject) => { + reject({ message: paramErrMsg, code: 401 }); + }); + } + let result_ = Context.closeMenu(content.getNodePtr()); + __JSScopeUtil__.restoreInstanceId(); + return result_; + } + showActionMenu(options, callback) { __JSScopeUtil__.syncInstanceId(this.instanceId_); if (typeof callback !== 'undefined') { diff --git a/frameworks/bridge/declarative_frontend/jsview/js_popups.cpp b/frameworks/bridge/declarative_frontend/jsview/js_popups.cpp index 70eb669ba1a..b7ebe1947d9 100644 --- a/frameworks/bridge/declarative_frontend/jsview/js_popups.cpp +++ b/frameworks/bridge/declarative_frontend/jsview/js_popups.cpp @@ -1847,9 +1847,7 @@ bool JSViewAbstract::ParseSheetHeight(const JSRef& args, NG::SheetHeight& void JSViewAbstract::JsBindMenu(const JSCallbackInfo& info) { NG::MenuParam menuParam; - if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) { - menuParam.placement = Placement::BOTTOM_LEFT; - } + MenuDefaultParam(menuParam); size_t builderIndex = 0; GetMenuShowInSubwindow(menuParam); if (info.Length() > PARAMETER_LENGTH_FIRST) { @@ -1910,6 +1908,44 @@ void JSViewAbstract::JsBindMenu(const JSCallbackInfo& info) } } +void JSViewAbstract::MenuDefaultParam(NG::MenuParam& menuParam) +{ + if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) { + menuParam.placement = Placement::BOTTOM_LEFT; + } +} + +void JSViewAbstract::ParseContentMenuCommonParam( + const JSCallbackInfo& info, const JSRef& menuObj, NG::MenuParam& menuParam) +{ + CHECK_EQUAL_VOID(menuObj->IsEmpty(), true); + if (!menuParam.placement.has_value()) { + MenuDefaultParam(menuParam); + } + ParseMenuParam(info, menuObj, menuParam); + auto preview = menuObj->GetProperty("preview"); + if (preview->IsNumber() && preview->ToNumber() == 1) { + menuParam.previewMode = MenuPreviewMode::IMAGE; + ParseContentPreviewAnimationOptionsParam(info, menuObj, menuParam); + } +} + +int32_t JSViewAbstract::OpenMenu( + NG::MenuParam& menuParam, const RefPtr& customNode, const int32_t& targetId) +{ + return ViewAbstractModel::GetInstance()->OpenMenu(menuParam, customNode, targetId); +} + +int32_t JSViewAbstract::UpdateMenu(const NG::MenuParam& menuParam, const RefPtr& customNode) +{ + return ViewAbstractModel::GetInstance()->UpdateMenu(menuParam, customNode); +} + +int32_t JSViewAbstract::CloseMenu(const RefPtr& customNode) +{ + return ViewAbstractModel::GetInstance()->CloseMenu(customNode); +} + void JSViewAbstract::ParseDialogCallback(const JSRef& paramObj, std::function& onWillDismiss) { diff --git a/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.h b/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.h index 5c55b2a15a7..8afbdeca5b4 100755 --- a/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.h +++ b/frameworks/bridge/declarative_frontend/jsview/js_view_abstract.h @@ -161,6 +161,12 @@ public: static void JsBackground(const JSCallbackInfo& info); static void JsBindMenu(const JSCallbackInfo& info); static void JsBindContextMenu(const JSCallbackInfo& info); + static void MenuDefaultParam(NG::MenuParam& menuParam); + static void ParseContentMenuCommonParam( + const JSCallbackInfo& info, const JSRef& menuObj, NG::MenuParam& menuParam); + static int32_t OpenMenu(NG::MenuParam& menuParam, const RefPtr& customNode, const int32_t& targetId); + static int32_t UpdateMenu(const NG::MenuParam& menuParam, const RefPtr& customNode); + static int32_t CloseMenu(const RefPtr& customNode); static void JsBindContentCover(const JSCallbackInfo& info); static void ParseModalStyle(const JSRef& paramObj, NG::ModalStyle& modalStyle); static void JsBindSheet(const JSCallbackInfo& info); diff --git a/frameworks/bridge/declarative_frontend/jsview/js_view_context.cpp b/frameworks/bridge/declarative_frontend/jsview/js_view_context.cpp index fc5afaa29fc..d74f459a664 100644 --- a/frameworks/bridge/declarative_frontend/jsview/js_view_context.cpp +++ b/frameworks/bridge/declarative_frontend/jsview/js_view_context.cpp @@ -39,6 +39,7 @@ #include "core/components_ng/base/view_stack_model.h" #include "core/components_ng/base/view_stack_processor.h" #include "core/components_ng/pattern/view_context/view_context_model_ng.h" +#include "core/components_ng/pattern/menu/wrapper/menu_wrapper_pattern.h" #ifdef USE_ARK_ENGINE #include "bridge/declarative_frontend/engine/jsi/jsi_declarative_engine.h" @@ -1146,6 +1147,127 @@ void JSViewContext::JSClosePopup(const JSCallbackInfo& info) return; } +int32_t GetMenuParam(NG::MenuParam& menuParam, const RefPtr& node) +{ + if (!node) { + TAG_LOGE(AceLogTag::ACE_DIALOG, "Content of menu is null."); + return ERROR_CODE_DIALOG_CONTENT_ERROR; + } + auto context = node->GetContextWithCheck(); + CHECK_NULL_RETURN(context, ERROR_CODE_INTERNAL_ERROR); + auto overlayManager = context->GetOverlayManager(); + if (!overlayManager) { + return ERROR_CODE_INTERNAL_ERROR; + } + auto menuNode = overlayManager->GetMenuNodeWithExistContent(node); + if (!menuNode) { + TAG_LOGE(AceLogTag::ACE_DIALOG, "GetMenuParam failed because cannot find menuNode."); + return ERROR_CODE_DIALOG_CONTENT_NOT_FOUND; + } + auto wrapperPattern = AceType::DynamicCast(menuNode->GetPattern()); + CHECK_NULL_RETURN(wrapperPattern, ERROR_CODE_INTERNAL_ERROR); + auto menuProperties = wrapperPattern->GetMenuParam(); + menuParam = menuProperties; + return ERROR_CODE_NO_ERROR; +} + +void JSViewContext::JSOpenMenu(const JSCallbackInfo& info) +{ + auto paramCnt = info.Length(); + if (paramCnt < LENGTH_TWO) { + ReturnPromise(info, ERROR_CODE_PARAM_INVALID); + return; + } + auto menuContentNode = ParseContentNode(info); + if (menuContentNode == nullptr) { + ReturnPromise(info, ERROR_CODE_DIALOG_CONTENT_ERROR); + return; + } + int32_t targetId = INVALID_ID; + if (info[INDEX_ONE]->IsObject()) { + auto menuObj = JSRef::Cast(info[INDEX_ONE]); + auto result = ParseTargetInfo(menuObj, targetId); + if (result != ERROR_CODE_NO_ERROR) { + ReturnPromise(info, result); + return; + } + } else { + ReturnPromise(info, ERROR_CODE_PARAM_INVALID); + return; + } + NG::MenuParam menuParam; + if (paramCnt == LENGTH_THREE && info[INDEX_TWO]->IsObject()) { + auto menuObj = JSRef::Cast(info[INDEX_TWO]); + JSViewAbstract::ParseContentMenuCommonParam(info, menuObj, menuParam); + } + auto ret = JSViewAbstract::OpenMenu(menuParam, menuContentNode, targetId); + if (ret != ERROR_CODE_INTERNAL_ERROR) { + ReturnPromise(info, ret); + } + return; +} + +void JSViewContext::JSUpdateMenu(const JSCallbackInfo& info) +{ + auto paramCnt = info.Length(); + if (paramCnt < LENGTH_TWO) { + ReturnPromise(info, ERROR_CODE_PARAM_INVALID); + return; + } + auto menuContentNode = ParseContentNode(info); + if (menuContentNode == nullptr) { + ReturnPromise(info, ERROR_CODE_DIALOG_CONTENT_ERROR); + return; + } + bool isPartialUpdate = false; + if (paramCnt == LENGTH_THREE) { + if (!info[INDEX_TWO]->IsBoolean()) { + ReturnPromise(info, ERROR_CODE_PARAM_INVALID); + return; + } + isPartialUpdate = info[INDEX_TWO]->ToBoolean(); + } + NG::MenuParam menuParam; + if (paramCnt >= LENGTH_TWO && info[INDEX_ONE]->IsObject()) { + if (isPartialUpdate) { + auto result = GetMenuParam(menuParam, menuContentNode); + if (result != ERROR_CODE_NO_ERROR && result != ERROR_CODE_INTERNAL_ERROR) { + ReturnPromise(info, result); + return; + } + } + auto menuObj = JSRef::Cast(info[INDEX_ONE]); + JSViewAbstract::ParseContentMenuCommonParam(info, menuObj, menuParam); + } else { + ReturnPromise(info, ERROR_CODE_PARAM_INVALID); + return; + } + auto ret = JSViewAbstract::UpdateMenu(menuParam, menuContentNode); + if (ret != ERROR_CODE_INTERNAL_ERROR) { + ReturnPromise(info, ret); + } + return; +} + +void JSViewContext::JSCloseMenu(const JSCallbackInfo& info) +{ + auto paramCnt = info.Length(); + if (paramCnt < LENGTH_ONE) { + ReturnPromise(info, ERROR_CODE_PARAM_INVALID); + return; + } + auto menuContentNode = ParseContentNode(info); + if (menuContentNode == nullptr) { + ReturnPromise(info, ERROR_CODE_DIALOG_CONTENT_ERROR); + return; + } + auto ret = JSViewAbstract::CloseMenu(menuContentNode); + if (ret != ERROR_CODE_INTERNAL_ERROR) { + ReturnPromise(info, ret); + } + return; +} + void JSViewContext::IsFollowingSystemFontScale(const JSCallbackInfo& info) { auto container = Container::CurrentSafely(); @@ -1199,6 +1321,9 @@ void JSViewContext::JSBind(BindingTarget globalObj) JSClass::StaticMethod("openPopup", JSOpenPopup); JSClass::StaticMethod("updatePopup", JSUpdatePopup); JSClass::StaticMethod("closePopup", JSClosePopup); + JSClass::StaticMethod("openMenu", JSOpenMenu); + JSClass::StaticMethod("updateMenu", JSUpdateMenu); + JSClass::StaticMethod("closeMenu", JSCloseMenu); JSClass::StaticMethod("isFollowingSystemFontScale", IsFollowingSystemFontScale); JSClass::StaticMethod("getMaxFontScale", GetMaxFontScale); JSClass::StaticMethod("bindTabsToScrollable", JSTabsFeature::BindTabsToScrollable); diff --git a/frameworks/bridge/declarative_frontend/jsview/js_view_context.h b/frameworks/bridge/declarative_frontend/jsview/js_view_context.h index 6fc2fe5ed17..e134c7be5fe 100644 --- a/frameworks/bridge/declarative_frontend/jsview/js_view_context.h +++ b/frameworks/bridge/declarative_frontend/jsview/js_view_context.h @@ -36,6 +36,9 @@ public: static void JSOpenPopup(const JSCallbackInfo& info); static void JSUpdatePopup(const JSCallbackInfo& info); static void JSClosePopup(const JSCallbackInfo& info); + static void JSOpenMenu(const JSCallbackInfo& info); + static void JSUpdateMenu(const JSCallbackInfo& info); + static void JSCloseMenu(const JSCallbackInfo& info); static void IsFollowingSystemFontScale(const JSCallbackInfo& info); static void GetMaxFontScale(const JSCallbackInfo& info); static void SetEnableSwipeBack(const JSCallbackInfo& info); diff --git a/frameworks/bridge/declarative_frontend/jsview/models/view_abstract_model_impl.h b/frameworks/bridge/declarative_frontend/jsview/models/view_abstract_model_impl.h index f3edb81d3bc..70e1b19f68f 100755 --- a/frameworks/bridge/declarative_frontend/jsview/models/view_abstract_model_impl.h +++ b/frameworks/bridge/declarative_frontend/jsview/models/view_abstract_model_impl.h @@ -290,6 +290,19 @@ public: void BindContextMenu(ResponseType type, std::function& buildFunc, const NG::MenuParam& menuParam, std::function& previewBuildFunc) override; + + int32_t OpenMenu(NG::MenuParam& menuParam, const RefPtr& customNode, const int32_t& targetId) override + { + return 0; + }; + int32_t UpdateMenu(const NG::MenuParam& menuParam, const RefPtr& customNode) override + { + return 0; + }; + int32_t CloseMenu(const RefPtr& customNode) override + { + return 0; + }; void BindDragWithContextMenuParams(const NG::MenuParam& menuParam) override {}; void BindContentCover(bool isShow, std::function&& callback, std::function&& buildFunc, NG::ModalStyle& modalStyle, std::function&& onAppear, diff --git a/frameworks/core/components_ng/base/view_abstract.cpp b/frameworks/core/components_ng/base/view_abstract.cpp index 98d78f23e47..5cab86c9c69 100644 --- a/frameworks/core/components_ng/base/view_abstract.cpp +++ b/frameworks/core/components_ng/base/view_abstract.cpp @@ -14,6 +14,10 @@ */ #include "core/components_ng/base/view_abstract.h" +#include +#include +#include +#include "core/components_ng/pattern/overlay/overlay_manager.h" #if !defined(PREVIEW) && !defined(ACE_UNITTEST) && defined(OHOS_PLATFORM) #include "interfaces/inner_api/ui_session/ui_session_manager.h" @@ -23,6 +27,7 @@ #include "base/subwindow/subwindow.h" #include "base/utils/system_properties.h" #include "base/utils/utils.h" +#include "core/common/ace_engine.h" #include "core/common/container.h" #include "core/common/container_scope.h" #include "core/components/common/layout/constants.h" @@ -2078,6 +2083,35 @@ PopupInfo ViewAbstract::GetPopupInfoWithTargetId(const RefPtr& customNod return popupInfoError; } +RefPtr ViewAbstract::GetCurOverlayManager(const RefPtr& node) +{ + auto context = node->GetContextWithCheck(); + CHECK_NULL_RETURN(context, nullptr); + if (GetTargetNodeIsInSubwindow(node)) { + auto instanceId = context->GetInstanceId(); + auto subwindow = SubwindowManager::GetInstance()->GetSubwindow(instanceId); + if (subwindow) { + auto overlayManager = subwindow->GetOverlayManager(); + return overlayManager; + } else { + return nullptr; + } + } + auto overlayManager = context->GetOverlayManager(); + return overlayManager; +} + +bool ViewAbstract::GetTargetNodeIsInSubwindow(const RefPtr& targetNode) +{ + CHECK_NULL_RETURN(targetNode, false); + auto pipelineContext = targetNode->GetContext(); + CHECK_NULL_RETURN(pipelineContext, false); + auto instanceId = pipelineContext->GetInstanceId(); + auto aceContainer = AceEngine::Get().GetContainer(instanceId); + CHECK_NULL_RETURN(aceContainer, false); + return aceContainer->IsSubContainer(); +} + RefPtr ViewAbstract::GetPopupOverlayManager(const RefPtr& customNode, const int32_t targetId) { auto context = customNode->GetContextWithCheck(); @@ -2284,6 +2318,145 @@ void ViewAbstract::DismissDialog() } } +void ViewAbstract::ShowMenuPreview( + const RefPtr& targetNode, const RefPtr& wrapperNode, const NG::MenuParam& menuParam) +{ + CHECK_NULL_VOID(targetNode); + CHECK_NULL_VOID(wrapperNode); + auto menuWrapperPattern = wrapperNode->GetPattern(); + CHECK_NULL_VOID(menuWrapperPattern); + if (menuParam.previewMode == MenuPreviewMode::IMAGE || menuParam.isShowHoverImage) { + ACE_UPDATE_NODE_LAYOUT_PROPERTY(LayoutProperty, IsBindOverlay, true, targetNode); + auto context = targetNode->GetRenderContext(); + CHECK_NULL_VOID(context); + auto eventHub = targetNode->GetEventHub(); + CHECK_NULL_VOID(eventHub); + auto gestureHub = eventHub->GetGestureEventHub(); + CHECK_NULL_VOID(gestureHub); + auto pixelMap = context->GetThumbnailPixelMap(); + CHECK_NULL_VOID(pixelMap); + gestureHub->SetPixelMap(pixelMap); + menuWrapperPattern->SetIsShowFromUser(true); + MenuView::GetMenuPixelMap(targetNode, menuParam, wrapperNode); + } +} + +void ViewAbstract::CheckMenuPreview(NG::MenuParam& menuParam) +{ +#ifdef PREVIEW + menuParam.previewMode = MenuPreviewMode::NONE; +#endif +} + +int32_t ViewAbstract::OpenMenu(NG::MenuParam& menuParam, const RefPtr& customNode, const int32_t& targetId) +{ + if (!customNode) { + TAG_LOGE(AceLogTag::ACE_DIALOG, "Content of menu is null."); + return ERROR_CODE_DIALOG_CONTENT_ERROR; + } + auto targetNode = ElementRegister::GetInstance()->GetSpecificItemById(targetId); + if (!targetNode) { + TAG_LOGE(AceLogTag::ACE_DIALOG, "The targetNode does not exist."); + return ERROR_CODE_TARGET_INFO_NOT_EXIST; + } + if (!targetNode->IsOnMainTree()) { + TAG_LOGE(AceLogTag::ACE_DIALOG, "The targetNode does not on main tree."); + return ERROR_CODE_TARGET_NOT_ON_COMPONET_TREE; + } + auto overlayManager = GetCurOverlayManager(customNode); + CHECK_NULL_RETURN(overlayManager, ERROR_CODE_INTERNAL_ERROR); + if (overlayManager->GetMenuNodeWithExistContent(customNode)) { + TAG_LOGW(AceLogTag::ACE_DIALOG, "Content of menu already existed."); + return ERROR_CODE_DIALOG_CONTENT_ALREADY_EXIST; + } + CheckMenuPreview(menuParam); + auto openMenuFunc = [targetNode, customNode, overlayManager, menuParam]()->int32_t { + auto wrapperNode = NG::MenuView::Create(customNode, targetNode->GetId(), targetNode->GetTag(), menuParam); + CHECK_NULL_RETURN(wrapperNode, ERROR_CODE_INTERNAL_ERROR); + ShowMenuPreview(targetNode, wrapperNode, menuParam); + auto menuWrapperPattern = wrapperNode->GetPattern(); + CHECK_NULL_RETURN(menuWrapperPattern, ERROR_CODE_INTERNAL_ERROR); + menuWrapperPattern->RegisterMenuCallback(wrapperNode, menuParam); + menuWrapperPattern->SetMenuTransitionEffect(wrapperNode, menuParam); + auto menu = menuWrapperPattern->GetMenu(); + CHECK_NULL_RETURN(menu, ERROR_CODE_INTERNAL_ERROR); + auto menuPattern = AceType::DynamicCast(menu->GetPattern()); + CHECK_NULL_RETURN(menuPattern, ERROR_CODE_INTERNAL_ERROR); + auto node = WeakPtr(customNode); + menuPattern->SetCustomNode(node); + auto pipelineContext = targetNode->GetContext(); + CHECK_NULL_RETURN(pipelineContext, ERROR_CODE_INTERNAL_ERROR); + auto theme = pipelineContext->GetTheme(); + CHECK_NULL_RETURN(theme, ERROR_CODE_INTERNAL_ERROR); + auto expandDisplay = theme->GetExpandDisplay(); + if (expandDisplay && menuParam.isShowInSubWindow && targetNode->GetTag() != V2::SELECT_ETS_TAG) { + SubwindowManager::GetInstance()->ShowMenuNG(wrapperNode, menuParam, targetNode, menuParam.positionOffset); + return ERROR_CODE_NO_ERROR; + } + overlayManager->ShowMenu(targetNode->GetId(), menuParam.positionOffset, wrapperNode); + return ERROR_CODE_NO_ERROR; + }; + return OpenMenuMode(targetNode, overlayManager, std::move(openMenuFunc)); +} + +int32_t ViewAbstract::OpenMenuMode(const RefPtr& targetNode, RefPtr& overlayManager, + std::function&& openMenuFunc) +{ + auto isShowMenu = overlayManager->GetMenuById(targetNode->GetId()); + if (isShowMenu) { + // The menu is already opened, close the previous menu first + overlayManager->SetOpenNextMenu(std::move(openMenuFunc)); + overlayManager->HideMenu(isShowMenu, targetNode->GetId(), false); + return ERROR_CODE_NO_ERROR; + } else { + // Open the menu directly + return openMenuFunc(); + } +} + +int32_t ViewAbstract::UpdateMenu(const NG::MenuParam& menuParam, const RefPtr& customNode) +{ + if (!customNode) { + TAG_LOGE(AceLogTag::ACE_DIALOG, "Content of menu is null."); + return ERROR_CODE_DIALOG_CONTENT_ERROR; + } + auto overlayManager = GetCurOverlayManager(customNode); + if (!overlayManager) { + return ERROR_CODE_INTERNAL_ERROR; + } + auto menuWrapperNode = overlayManager->GetMenuNodeWithExistContent(customNode); + if (!menuWrapperNode) { + return ERROR_CODE_DIALOG_CONTENT_NOT_FOUND; + } + auto wrapperPattern = AceType::DynamicCast(menuWrapperNode->GetPattern()); + CHECK_NULL_RETURN(wrapperPattern, ERROR_CODE_INTERNAL_ERROR); + auto menu = wrapperPattern->GetMenu(); + CHECK_NULL_RETURN(menu, ERROR_CODE_INTERNAL_ERROR); + wrapperPattern->SetMenuParam(menuParam); + MenuView::UpdateMenuParam(menuWrapperNode, menu, menuParam); + MenuView::UpdateMenuProperties(menuWrapperNode, menu, menuParam, menuParam.type); + menu->MarkDirtyNode(PROPERTY_UPDATE_MEASURE); + return ERROR_CODE_NO_ERROR; +} + +int32_t ViewAbstract::CloseMenu(const RefPtr& customNode) +{ + if (!customNode) { + TAG_LOGE(AceLogTag::ACE_DIALOG, "Content of menu is null."); + return ERROR_CODE_DIALOG_CONTENT_ERROR; + } + auto overlayManager = GetCurOverlayManager(customNode); + if (!overlayManager) { + return ERROR_CODE_INTERNAL_ERROR; + } + auto menuWrapperNode = overlayManager->GetMenuNodeWithExistContent(customNode); + if (!menuWrapperNode) { + return ERROR_CODE_DIALOG_CONTENT_NOT_FOUND; + } + overlayManager->HideMenu(menuWrapperNode, customNode->GetId(), false); + return ERROR_CODE_NO_ERROR; +} + void ViewAbstract::BindMenuWithItems(std::vector&& params, const RefPtr& targetNode, const NG::OffsetF& offset, const MenuParam& menuParam) { diff --git a/frameworks/core/components_ng/base/view_abstract.h b/frameworks/core/components_ng/base/view_abstract.h index b26aa828bea..13ef54e7196 100644 --- a/frameworks/core/components_ng/base/view_abstract.h +++ b/frameworks/core/components_ng/base/view_abstract.h @@ -360,12 +360,19 @@ public: // Bind properties static void BindPopup(const RefPtr ¶m, const RefPtr &targetNode, const RefPtr &customNode); + static RefPtr GetCurOverlayManager(const RefPtr& node); + static bool GetTargetNodeIsInSubwindow(const RefPtr& targetNode); static int32_t OpenPopup(const RefPtr& param, const RefPtr& customNode); static int32_t UpdatePopup(const RefPtr& param, const RefPtr& customNode); static int32_t ClosePopup(const RefPtr& customNode); static int32_t GetPopupParam(RefPtr& param, const RefPtr& customNode); static void DismissDialog(); static void DismissPopup(); + static void ShowMenuPreview( + const RefPtr& targetNode, const RefPtr& wrapperNode, const NG::MenuParam& menuParam); + static int32_t OpenMenu(NG::MenuParam& menuParam, const RefPtr& customNode, const int32_t& targetId); + static int32_t UpdateMenu(const NG::MenuParam& menuParam, const RefPtr& customNode); + static int32_t CloseMenu(const RefPtr& customNode); static void BindMenuWithItems(std::vector &¶ms, const RefPtr &targetNode, const NG::OffsetF &offset, const MenuParam &menuParam); static void BindMenuWithCustomNode(std::function&& buildFunc, const RefPtr& targetNode, @@ -841,6 +848,9 @@ private: static PopupInfo GetPopupInfoWithCustomNode(const RefPtr& customNode); static PopupInfo GetPopupInfoWithTargetId(const RefPtr& customNode, const int32_t targetId); static RefPtr GetPopupOverlayManager(const RefPtr& customNode, const int32_t targetId); + static int32_t OpenMenuMode(const RefPtr& targetNode, RefPtr& overlayManager, + std::function&& openMenuFunc); + static void CheckMenuPreview(NG::MenuParam& menuParam); static OEMVisualEffectFunc oemVisualEffectFunc; static std::mutex visualEffectMutex_; diff --git a/frameworks/core/components_ng/base/view_abstract_model.h b/frameworks/core/components_ng/base/view_abstract_model.h index bc81e7d0459..6f2b958fcc8 100755 --- a/frameworks/core/components_ng/base/view_abstract_model.h +++ b/frameworks/core/components_ng/base/view_abstract_model.h @@ -372,6 +372,10 @@ public: virtual int32_t ClosePopup(const RefPtr& customNode) = 0; virtual int32_t GetPopupParam(RefPtr& param, const RefPtr& customNode) = 0; virtual void DismissPopup() = 0; + virtual int32_t OpenMenu( + NG::MenuParam& menuParam, const RefPtr& customNode, const int32_t& targetId) = 0; + virtual int32_t UpdateMenu(const NG::MenuParam& menuParam, const RefPtr& customNode) = 0; + virtual int32_t CloseMenu(const RefPtr& customNode) = 0; virtual void BindMenu( std::vector&& params, std::function&& buildFunc, const NG::MenuParam& menuParam) = 0; virtual void BindContextMenu(ResponseType type, std::function& buildFunc, const NG::MenuParam& menuParam, diff --git a/frameworks/core/components_ng/base/view_abstract_model_ng.h b/frameworks/core/components_ng/base/view_abstract_model_ng.h index d60bf160a6e..383b8b3a6b5 100755 --- a/frameworks/core/components_ng/base/view_abstract_model_ng.h +++ b/frameworks/core/components_ng/base/view_abstract_model_ng.h @@ -1300,6 +1300,19 @@ public: void BindBackground(std::function&& buildFunc, const Alignment& align) override; + int32_t OpenMenu(NG::MenuParam& menuParam, const RefPtr& customNode, const int32_t& targetId) override + { + return ViewAbstract::OpenMenu(menuParam, customNode, targetId); + } + int32_t UpdateMenu(const NG::MenuParam& menuParam, const RefPtr& customNode) override + { + return ViewAbstract::UpdateMenu(menuParam, customNode); + } + int32_t CloseMenu(const RefPtr& customNode) override + { + return ViewAbstract::CloseMenu(customNode); + } + void BindMenuGesture( std::vector&& params, std::function&& buildFunc, const MenuParam& menuParam); diff --git a/frameworks/core/components_ng/pattern/menu/menu_pattern.cpp b/frameworks/core/components_ng/pattern/menu/menu_pattern.cpp index a3fd411dbf3..1eb17b68e93 100644 --- a/frameworks/core/components_ng/pattern/menu/menu_pattern.cpp +++ b/frameworks/core/components_ng/pattern/menu/menu_pattern.cpp @@ -1605,6 +1605,8 @@ bool MenuPattern::OnDirtyLayoutWrapperSwap(const RefPtr& dirty, c CHECK_NULL_RETURN(theme, false); auto renderContext = dirty->GetHostNode()->GetRenderContext(); CHECK_NULL_RETURN(renderContext, false); + renderContext->UpdateClipShape(nullptr); + renderContext->ResetClipShape(); auto menuProp = DynamicCast(dirty->GetLayoutProperty()); CHECK_NULL_RETURN(menuProp, false); diff --git a/frameworks/core/components_ng/pattern/menu/menu_pattern.h b/frameworks/core/components_ng/pattern/menu/menu_pattern.h index 36ae77a1216..314d013a2b4 100644 --- a/frameworks/core/components_ng/pattern/menu/menu_pattern.h +++ b/frameworks/core/components_ng/pattern/menu/menu_pattern.h @@ -583,6 +583,17 @@ public: { return pathParams_; } + + void SetCustomNode(WeakPtr customNode) + { + customNode_ = customNode; + } + + RefPtr GetCustomNode() const + { + return customNode_.Upgrade(); + } + void InitPreviewMenuAnimationInfo(const RefPtr& menuTheme); float GetSelectMenuWidthFromTheme() const; @@ -734,6 +745,7 @@ private: bool isStackSubmenu_ = false; bool isNeedDivider_ = false; Rect menuWindowRect_; + WeakPtr customNode_ = nullptr; std::optional pathParams_ = std::nullopt; ACE_DISALLOW_COPY_AND_MOVE(MenuPattern); diff --git a/frameworks/core/components_ng/pattern/menu/menu_view.cpp b/frameworks/core/components_ng/pattern/menu/menu_view.cpp index b2c1c42c8e3..b3093341116 100644 --- a/frameworks/core/components_ng/pattern/menu/menu_view.cpp +++ b/frameworks/core/components_ng/pattern/menu/menu_view.cpp @@ -871,7 +871,20 @@ void SetHasCustomRadius( CHECK_NULL_VOID(menuProperty); menuProperty->UpdateBorderRadius(menuParam.borderRadius.value()); } else { + auto menuProperty = menuNode->GetLayoutProperty(); + CHECK_NULL_VOID(menuProperty); menuWrapperPattern->SetHasCustomRadius(false); + auto pipeline = PipelineBase::GetCurrentContext(); + CHECK_NULL_VOID(pipeline); + auto theme = pipeline->GetTheme(); + CHECK_NULL_VOID(theme); + Dimension defaultDimension(0); + BorderRadiusProperty radius = { defaultDimension, defaultDimension, defaultDimension, defaultDimension }; + auto defaultRadius = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) + ? theme->GetMenuDefaultRadius() + : theme->GetMenuBorderRadius(); + radius.SetRadius(defaultRadius); + menuProperty->UpdateBorderRadius(radius); } } @@ -983,6 +996,23 @@ void MenuView::ShowPixelMapAnimation(const RefPtr& menuNode) ShowBorderRadiusAndShadowAnimation(menuTheme, imageNode, isShowHoverImage); } +void MenuView::GetMenuPixelMap( + const RefPtr& targetNode, const MenuParam& menuParam, const RefPtr& wrapperNode) +{ + CHECK_NULL_VOID(targetNode); + CHECK_NULL_VOID(wrapperNode); + MenuType type = MenuType::MENU; + auto nodeId = ElementRegister::GetInstance()->MakeUniqueId(); + auto previewNode = FrameNode::CreateFrameNode(V2::MENU_PREVIEW_ETS_TAG, + ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr()); + CHECK_NULL_VOID(previewNode); + auto menuNode = FrameNode::CreateFrameNode( + V2::MENU_ETS_TAG, nodeId, AceType::MakeRefPtr(targetNode->GetId(), targetNode->GetTag(), type)); + CHECK_NULL_VOID(menuNode); + ContextMenuChildMountProc(targetNode, wrapperNode, previewNode, menuNode, menuParam); + MountTextNode(wrapperNode, nullptr); +} + // create menu with MenuElement array RefPtr MenuView::Create(std::vector&& params, int32_t targetId, const std::string& targetTag, MenuType type, const MenuParam& menuParam) @@ -1128,7 +1158,37 @@ RefPtr MenuView::Create(const RefPtr& customNode, int32_t tar auto scroll = CreateMenuScroll(customNode); CHECK_NULL_RETURN(scroll, nullptr); MountScrollToMenu(customNode, scroll, type, menuNode); + UpdateMenuProperties(wrapperNode, menuNode, menuParam, type); + + if (type == MenuType::SUB_MENU || type == MenuType::SELECT_OVERLAY_SUB_MENU || !withWrapper) { + wrapperNode->RemoveChild(menuNode); + wrapperNode.Reset(); + return menuNode; + } + if (type == MenuType::CONTEXT_MENU) { + auto targetNode = FrameNode::GetFrameNode(targetTag, targetId); + ContextMenuChildMountProc(targetNode, wrapperNode, previewNode, menuNode, menuParam); + MountTextNode(wrapperNode, previewCustomNode); + } + return wrapperNode; +} +void MenuView::UpdateMenuParam( + const RefPtr& wrapperNode, const RefPtr& menuNode, const MenuParam& menuParam) +{ + auto menuWrapperPattern = wrapperNode->GetPattern(); + CHECK_NULL_VOID(menuWrapperPattern); + menuWrapperPattern->SetHoverMode(menuParam.enableHoverMode); + auto menuPattern = menuNode->GetPattern(); + CHECK_NULL_VOID(menuPattern); + UpdateMenuBackgroundStyle(menuNode, menuParam); + SetPreviewTransitionEffect(wrapperNode, menuParam); + SetHasCustomRadius(wrapperNode, menuNode, menuParam); +} + +void MenuView::UpdateMenuProperties(const RefPtr& wrapperNode, const RefPtr& menuNode, + const MenuParam& menuParam, const MenuType& type) +{ if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) && !menuParam.enableArrow.value_or(false)) { UpdateMenuBorderEffect(menuNode); } @@ -1144,17 +1204,6 @@ RefPtr MenuView::Create(const RefPtr& customNode, int32_t tar menuProperty->UpdateShowInSubWindow(menuParam.isShowInSubWindow); } UpdateMenuPaintProperty(menuNode, menuParam, type); - if (type == MenuType::SUB_MENU || type == MenuType::SELECT_OVERLAY_SUB_MENU || !withWrapper) { - wrapperNode->RemoveChild(menuNode); - wrapperNode.Reset(); - return menuNode; - } - if (type == MenuType::CONTEXT_MENU) { - auto targetNode = FrameNode::GetFrameNode(targetTag, targetId); - ContextMenuChildMountProc(targetNode, wrapperNode, previewNode, menuNode, menuParam); - MountTextNode(wrapperNode, previewCustomNode); - } - return wrapperNode; } void MenuView::UpdateMenuPaintProperty( @@ -1292,6 +1341,7 @@ void MenuView::UpdateMenuBorderEffect(const RefPtr& menuNode) renderContext->SetBorderWidth(innerWidthProp); } } + void MenuView::UpdateMenuBackgroundStyle(const RefPtr& menuNode, const MenuParam& menuParam) { auto menuNodeRenderContext = menuNode->GetRenderContext(); @@ -1338,9 +1388,26 @@ void MenuView::UpdateMenuBackgroundStyle(const RefPtr& menuNode, cons } menuNodeRenderContext->UpdateBackgroundEffect(menuParam.effectOption.value()); } - } else if (menuParam.backgroundColor.has_value()) { - menuNodeRenderContext->UpdateBackgroundColor(menuParam.backgroundColor.value()); + } else { + UpdateMenuBackgroundStyleSub(menuNode, menuParam); + } +} + +void MenuView::UpdateMenuBackgroundStyleSub(const RefPtr& menuNode, const MenuParam& menuParam) +{ + auto menuNodeRenderContext = menuNode->GetRenderContext(); + auto pipeLineContext = menuNode->GetContextWithCheck(); + CHECK_NULL_VOID(pipeLineContext); + auto selectTheme = pipeLineContext->GetTheme(); + CHECK_NULL_VOID(selectTheme); + menuNodeRenderContext->UpdateBackgroundColor( + menuParam.backgroundColor.value_or(selectTheme->GetBackgroundColor())); + BlurStyleOption blurStyleOption; + blurStyleOption.blurStyle = static_cast(selectTheme->GetMenuBackgroundBlurStyle()); + if (menuParam.backgroundBlurStyle.has_value()) { + blurStyleOption.blurStyle = static_cast(menuParam.backgroundBlurStyle.value()); } + menuNodeRenderContext->UpdateBackBlurStyle(blurStyleOption); } void MenuView::NeedAgingUpdateNode(const RefPtr& optionNode) diff --git a/frameworks/core/components_ng/pattern/menu/menu_view.h b/frameworks/core/components_ng/pattern/menu/menu_view.h index 7c27f1cc1e7..cc5f896c5dd 100644 --- a/frameworks/core/components_ng/pattern/menu/menu_view.h +++ b/frameworks/core/components_ng/pattern/menu/menu_view.h @@ -51,6 +51,12 @@ public: const std::vector& params, int32_t targetId, const std::string& targetTag); static void ShowPixelMapAnimation(const RefPtr& menuNode); + static void GetMenuPixelMap( + const RefPtr& targetNode, const MenuParam& menuParam, const RefPtr& wrapperNode); + static void UpdateMenuParam( + const RefPtr& wrapperNode, const RefPtr& menuNode, const MenuParam& menuParam); + static void UpdateMenuProperties(const RefPtr& wrapperNode, const RefPtr& menuNode, + const MenuParam& menuParam, const MenuType& type); static void CalcHoverScaleInfo(const RefPtr& menuNode); static RefPtr CreateIcon(const std::string& icon, const RefPtr& parent, @@ -84,6 +90,7 @@ private: const RefPtr& row, const RefPtr& option); static void MountOptionToColumn(std::vector& params, const RefPtr& menuNode, const MenuParam& menuParam, RefPtr column); + static void UpdateMenuBackgroundStyleSub(const RefPtr& menuNode, const MenuParam& menuParam); }; } // namespace OHOS::Ace::NG diff --git a/frameworks/core/components_ng/pattern/overlay/overlay_manager.cpp b/frameworks/core/components_ng/pattern/overlay/overlay_manager.cpp index 8ec05cb287d..4ab8e06c9cd 100644 --- a/frameworks/core/components_ng/pattern/overlay/overlay_manager.cpp +++ b/frameworks/core/components_ng/pattern/overlay/overlay_manager.cpp @@ -1216,6 +1216,15 @@ void OverlayManager::OnPopMenuAnimationFinished(const WeakPtr menuWK, } overlayManager->RemoveMenuNotInSubWindow(menuWK, rootWeak, weak); overlayManager->SetIsMenuShow(false); + ToOpenMenuAtAnimationFinished(); +} + +void OverlayManager::ToOpenMenuAtAnimationFinished() +{ + if (openNextMenu_) { + openNextMenu_(); + openNextMenu_ = nullptr; + } } void OverlayManager::PopMenuAnimation(const RefPtr& menu, bool showPreviewAnimation, bool startDrag) @@ -2190,6 +2199,27 @@ void OverlayManager::HideMenuInSubWindow(bool showPreviewAnimation, bool startDr } } +RefPtr OverlayManager::GetMenuNodeWithExistContent(const RefPtr& node) +{ + CHECK_NULL_RETURN(node, nullptr); + auto iter = menuMap_.begin(); + while (iter != menuMap_.end()) { + auto menuNode = (*iter).second; + CHECK_NULL_RETURN(menuNode, nullptr); + auto menuWrapperPattern = menuNode->GetPattern(); + CHECK_NULL_RETURN(menuWrapperPattern, nullptr); + auto menu = menuWrapperPattern->GetMenu(); + CHECK_NULL_RETURN(menu, nullptr); + auto menuPattern = AceType::DynamicCast(menu->GetPattern()); + CHECK_NULL_RETURN(menuPattern, nullptr); + if (menuPattern->GetCustomNode() == node) { + return menuNode; + } + iter++; + } + return nullptr; +} + RefPtr OverlayManager::GetMenuNode(int32_t targetId) { auto it = menuMap_.find(targetId); diff --git a/frameworks/core/components_ng/pattern/overlay/overlay_manager.h b/frameworks/core/components_ng/pattern/overlay/overlay_manager.h index 4e5107b3ac2..93444f8b6a9 100644 --- a/frameworks/core/components_ng/pattern/overlay/overlay_manager.h +++ b/frameworks/core/components_ng/pattern/overlay/overlay_manager.h @@ -158,6 +158,7 @@ public: void DeleteMenu(int32_t targetId); void ShowMenuInSubWindow(int32_t targetId, const NG::OffsetF& offset, RefPtr menu = nullptr); void HideMenuInSubWindow(const RefPtr& menu, int32_t targetId); + RefPtr GetMenuNodeWithExistContent(const RefPtr& node); RefPtr GetMenuNode(int32_t targetId); void HideMenuInSubWindow(bool showPreviewAnimation = true, bool startDrag = false); void CleanMenuInSubWindow(int32_t targetId); @@ -629,6 +630,18 @@ public: menuMap_.erase(targetId); } } + RefPtr GetMenuById(int32_t targetId) + { + auto it = menuMap_.find(targetId); + if (it == menuMap_.end()) { + return nullptr; + } + return AceType::DynamicCast(it->second); + } + void SetOpenNextMenu(std::function&& func) + { + openNextMenu_ = std::move(func); + } bool IsRootExpansive() const; void DumpOverlayInfo() const; @@ -853,7 +866,7 @@ private: void SetDragNodeNeedClean(); void MountCustomKeyboard(const RefPtr& customKeyboard, int32_t targetId); void FireNavigationLifecycle(const RefPtr& uiNode, int32_t lifecycleId, bool isLowerOnly, int32_t reason); - + void ToOpenMenuAtAnimationFinished(); RefPtr overlayNode_; // Key: frameNode Id, Value: index std::unordered_map frameNodeMapOnOverlay_; @@ -868,6 +881,7 @@ private: std::list> modalList_; std::unordered_map, SheetKeyHash> sheetMap_; std::function cleanViewContextMapCallback_ = nullptr; + std::function openNextMenu_ = nullptr; std::unordered_map> sheetMaskClickEventMap_; // Key: maskNodeId WeakPtr lastModalNode_; // Previous Modal Node float sheetHeight_ { 0.0 }; -- Gitee