• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "core/components_ng/pattern/menu/menu_view.h"
17 
18 #include "base/geometry/dimension.h"
19 #include "base/i18n/localization.h"
20 #include "base/memory/ace_type.h"
21 #include "core/components_ng/base/view_stack_processor.h"
22 #include "core/components_ng/manager/drag_drop/drag_drop_func_wrapper.h"
23 #include "core/components_ng/manager/drag_drop/utils/drag_animation_helper.h"
24 #include "core/components_ng/pattern/flex/flex_layout_pattern.h"
25 #include "core/components_ng/pattern/image/image_layout_property.h"
26 #include "core/components_ng/pattern/image/image_pattern.h"
27 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
28 #include "core/components_ng/pattern/menu/menu_item/menu_item_row_pattern.h"
29 #include "core/components_ng/pattern/menu/menu_layout_property.h"
30 #include "core/components_ng/pattern/menu/menu_pattern.h"
31 #include "core/components_ng/pattern/menu/menu_theme.h"
32 #include "core/components_ng/pattern/menu/preview/menu_preview_pattern.h"
33 #include "core/components_ng/pattern/menu/wrapper/menu_wrapper_pattern.h"
34 #include "core/components_ng/pattern/overlay/overlay_manager.h"
35 #include "core/components_ng/pattern/security_component/paste_button/paste_button_common.h"
36 #include "core/components_ng/pattern/security_component/paste_button/paste_button_model_ng.h"
37 #include "core/components_ng/pattern/security_component/security_component_pattern.h"
38 #include "core/components_ng/pattern/scroll/scroll_pattern.h"
39 #include "core/components_ng/pattern/stack/stack_pattern.h"
40 #include "core/components_ng/pattern/text/text_pattern.h"
41 #include "core/components_ng/property/menu_property.h"
42 #include "core/components_v2/inspector/inspector_constants.h"
43 #include "core/components/text_overlay/text_overlay_theme.h"
44 #include "core/components_ng/manager/drag_drop/drag_drop_global_controller.h"
45 
46 namespace OHOS::Ace::NG {
47 
48 /**
49  * The structure of menu is designed as follows :
50  * |--menuWrapper(size is same as root)
51  *   |--menu
52  *      |--scroll
53  *          |--column(for bindMenu/select)
54  *            |--options
55  *          |--customNode(for custom builder)
56  */
57 
58 namespace {
59 constexpr float PAN_MAX_VELOCITY = 2000.0f;
60 constexpr float HALF_DIVIDE = 2.0f;
61 constexpr float PREVIEW_ORIGIN_SCALE = 1.0f;
62 const RefPtr<Curve> CUSTOM_PREVIEW_ANIMATION_CURVE =
63     AceType::MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 380.0f, 34.0f);
64 const std::string HOVER_IMAGE_CLIP_PROPERTY_NAME = "hoverImageClip";
65 constexpr float MIN_HOVER_SCALE_DIFF = 0.0001f;
66 
MountTextNode(const RefPtr<FrameNode> & wrapperNode,const RefPtr<UINode> & previewCustomNode=nullptr)67 void MountTextNode(const RefPtr<FrameNode>& wrapperNode, const RefPtr<UINode>& previewCustomNode = nullptr)
68 {
69     CHECK_NULL_VOID(previewCustomNode);
70     auto pipeline = PipelineContext::GetMainPipelineContext();
71     CHECK_NULL_VOID(pipeline);
72     auto manager = pipeline->GetOverlayManager();
73     CHECK_NULL_VOID(manager);
74     auto gatherNode = manager->GetGatherNode();
75     CHECK_NULL_VOID(gatherNode);
76     auto textNode = FrameNode::GetOrCreateFrameNode(V2::TEXT_ETS_TAG,
77         ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<TextPattern>(); });
78     CHECK_NULL_VOID(textNode);
79     textNode->MountToParent(wrapperNode);
80     textNode->MarkModifyDone();
81 }
82 
CreatePreviewLayoutConstraint(const RefPtr<LayoutProperty> & layoutProperty)83 LayoutConstraintF CreatePreviewLayoutConstraint(const RefPtr<LayoutProperty>& layoutProperty)
84 {
85     CHECK_NULL_RETURN(layoutProperty, {});
86     LayoutConstraintF constraint = layoutProperty->GetLayoutConstraint().value_or(LayoutConstraintF());
87 
88     auto currentId = Container::CurrentId();
89     auto subWindow = SubwindowManager::GetInstance()->GetSubwindowByType(currentId, SubwindowType::TYPE_MENU);
90     CHECK_NULL_RETURN(subWindow, constraint);
91     auto subwindowSize = subWindow->GetRect().GetSize();
92     if (!subwindowSize.IsPositive()) {
93         return constraint;
94     }
95 
96     if (subwindowSize != constraint.maxSize || subwindowSize != constraint.percentReference) {
97         constraint.maxSize.SetSizeT(subwindowSize);
98         constraint.percentReference.SetSizeT(subwindowSize);
99     }
100     return constraint;
101 }
102 
CustomPreviewNodeProc(const RefPtr<FrameNode> & previewNode,const MenuParam & menuParam,const RefPtr<UINode> & previewCustomNode=nullptr)103 void CustomPreviewNodeProc(const RefPtr<FrameNode>& previewNode, const MenuParam& menuParam,
104     const RefPtr<UINode>& previewCustomNode = nullptr)
105 {
106     CHECK_NULL_VOID(previewCustomNode);
107     CHECK_NULL_VOID(previewNode);
108     auto previewPattern = previewNode->GetPattern<MenuPreviewPattern>();
109     CHECK_NULL_VOID(previewPattern);
110     previewPattern->SetHasPreviewTransitionEffect(menuParam.hasPreviewTransitionEffect);
111     auto layoutProperty = previewNode->GetLayoutProperty();
112     CHECK_NULL_VOID(layoutProperty);
113     layoutProperty->UpdateVisibility(VisibleType::VISIBLE, true);
114     previewNode->AddChild(previewCustomNode);
115 
116     CHECK_NULL_VOID(menuParam.isShowHoverImage);
117     auto pipeline = previewNode->GetContextWithCheck();
118     CHECK_NULL_VOID(pipeline);
119     ScopedLayout scope(pipeline);
120     auto layoutConstraint = CreatePreviewLayoutConstraint(layoutProperty);
121     previewNode->Measure(layoutConstraint);
122     auto previewSize = previewNode->GetGeometryNode()->GetFrameSize();
123     previewPattern->SetIsShowHoverImage(true);
124     previewPattern->SetCustomPreviewWidth(previewSize.Width());
125     previewPattern->SetCustomPreviewHeight(previewSize.Height());
126 
127     auto previewScaleTo = menuParam.previewAnimationOptions.scaleTo;
128     CHECK_NULL_VOID(previewScaleTo);
129     auto menuTheme = pipeline->GetTheme<NG::MenuTheme>();
130     CHECK_NULL_VOID(menuTheme);
131     previewScaleTo = LessOrEqual(previewScaleTo, 0.0) ? menuTheme->GetPreviewAfterAnimationScale() : previewScaleTo;
132     previewPattern->SetCustomPreviewScaleTo(previewScaleTo);
133 }
134 
135 // create menuWrapper and menu node, update menu props
CreateMenu(int32_t targetId,const std::string & targetTag="",MenuType type=MenuType::MENU)136 std::pair<RefPtr<FrameNode>, RefPtr<FrameNode>> CreateMenu(int32_t targetId, const std::string& targetTag = "",
137     MenuType type = MenuType::MENU)
138 {
139     // use wrapper to detect click events outside menu
140     auto wrapperNode = FrameNode::CreateFrameNode(V2::MENU_WRAPPER_ETS_TAG,
141         ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<MenuWrapperPattern>(targetId));
142 
143     auto nodeId = ElementRegister::GetInstance()->MakeUniqueId();
144     auto menuNode = FrameNode::CreateFrameNode(
145         V2::MENU_ETS_TAG, nodeId, AceType::MakeRefPtr<MenuPattern>(targetId, targetTag, type));
146 
147     auto renderContext = menuNode->GetRenderContext();
148     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) && renderContext->IsUniRenderEnabled()) {
149         BlurStyleOption styleOption;
150         auto pipeLineContext = menuNode->GetContextWithCheck();
151         if (!pipeLineContext) {
152             return { wrapperNode, menuNode };
153         }
154         auto selectTheme = pipeLineContext->GetTheme<SelectTheme>();
155         if (!selectTheme) {
156             return { wrapperNode, menuNode };
157         }
158         if (selectTheme->GetMenuBlendBgColor()) {
159             styleOption.blurStyle = static_cast<BlurStyle>(selectTheme->GetMenuNormalBackgroundBlurStyle());
160             renderContext->UpdateBackgroundColor(selectTheme->GetBackgroundColor());
161         } else {
162             styleOption.blurStyle = static_cast<BlurStyle>(selectTheme->GetMenuBackgroundBlurStyle());
163             renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
164         }
165         renderContext->UpdateBackBlurStyle(styleOption);
166     }
167 
168     menuNode->MountToParent(wrapperNode);
169 
170     return { wrapperNode, menuNode };
171 }
172 
CreateTitleNode(const std::string & title,RefPtr<FrameNode> & column)173 void CreateTitleNode(const std::string& title, RefPtr<FrameNode>& column)
174 {
175     auto textNode = FrameNode::CreateFrameNode(
176         V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
177     CHECK_NULL_VOID(textNode);
178     auto textProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
179     CHECK_NULL_VOID(textProperty);
180 
181     auto pipeline = textNode->GetContextWithCheck();
182     CHECK_NULL_VOID(pipeline);
183     auto theme = pipeline->GetTheme<SelectTheme>();
184     CHECK_NULL_VOID(theme);
185     auto padding = static_cast<float>(theme->GetMenuItemHorIntervalPadding().ConvertToPx());
186     PaddingProperty textPadding;
187     textPadding.left = CalcLength(padding);
188     textPadding.right = CalcLength(padding);
189     textProperty->UpdatePadding(textPadding);
190     textProperty->UpdateFontSize(theme->GetMenuTitleFontSize());
191     textProperty->UpdateFontWeight(FontWeight::MEDIUM);
192     textProperty->UpdateItalicFontStyle(Ace::FontStyle::NORMAL);
193     textProperty->UpdateTextColor(theme->GetMenuTitleFontColor());
194     textProperty->UpdateContent(title);
195     textProperty->UpdateMaxLines(1);
196     textProperty->UpdateTextOverflow(TextOverflow::ELLIPSIS);
197 
198     CalcSize idealSize;
199     idealSize.SetHeight(CalcLength(theme->GetMenuTitleHeight()));
200     MeasureProperty layoutConstraint;
201     layoutConstraint.selfIdealSize = idealSize;
202     textProperty->UpdateCalcLayoutProperty(layoutConstraint);
203 
204     textNode->MountToParent(column);
205     textNode->MarkModifyDone();
206 }
207 
CreateMenuScroll(const RefPtr<UINode> & node)208 RefPtr<FrameNode> CreateMenuScroll(const RefPtr<UINode>& node)
209 {
210     auto scroll = FrameNode::CreateFrameNode(
211         V2::SCROLL_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ScrollPattern>());
212     CHECK_NULL_RETURN(scroll, nullptr);
213     auto props = scroll->GetLayoutProperty<ScrollLayoutProperty>();
214     props->UpdateAxis(Axis::VERTICAL);
215     props->UpdateAlignment(Alignment::CENTER_LEFT);
216     auto pipeline = scroll->GetContextWithCheck();
217     CHECK_NULL_RETURN(pipeline, nullptr);
218     auto theme = pipeline->GetTheme<SelectTheme>();
219     float contentPadding = 0.0f;
220     if (theme) {
221         contentPadding = static_cast<float>(theme->GetMenuPadding().ConvertToPx());
222     }
223     PaddingProperty padding;
224     padding.left = padding.right = padding.top = padding.bottom = CalcLength(contentPadding);
225     props->UpdatePadding(padding);
226     if (node) {
227         node->MountToParent(scroll);
228     }
229     auto renderContext = scroll->GetRenderContext();
230     CHECK_NULL_RETURN(renderContext, nullptr);
231     BorderRadiusProperty borderRadius;
232     if (theme) {
233         auto defaultRadius = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) ?
234             theme->GetMenuDefaultRadius() : theme->GetMenuBorderRadius();
235         borderRadius.SetRadius(defaultRadius);
236     }
237     renderContext->UpdateBorderRadius(borderRadius);
238     return scroll;
239 }
240 
MountScrollToMenu(const RefPtr<UINode> & customNode,RefPtr<FrameNode> scroll,MenuType type,RefPtr<FrameNode> menuNode)241 void MountScrollToMenu(
242     const RefPtr<UINode>& customNode, RefPtr<FrameNode> scroll, MenuType type, RefPtr<FrameNode> menuNode)
243 {
244     auto customMenuNode = AceType::DynamicCast<FrameNode>(customNode);
245     if (customMenuNode) {
246         customMenuNode->SetDraggable(false);
247     }
248     scroll->MountToParent(menuNode);
249     scroll->MarkModifyDone();
250 }
251 
OptionKeepMenu(RefPtr<FrameNode> & option,WeakPtr<FrameNode> & menuWeak)252 void OptionKeepMenu(RefPtr<FrameNode>& option, WeakPtr<FrameNode>& menuWeak)
253 {
254     auto pattern = option->GetPattern<MenuItemPattern>();
255     CHECK_NULL_VOID(pattern);
256     pattern->SetMenu(menuWeak);
257 }
258 
GetHasIcon(const std::vector<OptionParam> & params)259 bool GetHasIcon(const std::vector<OptionParam>& params)
260 {
261     for (size_t i = 0; i < params.size(); ++i) {
262         if (!params[i].icon.empty() || params[i].isPasteOption) {
263             return true;
264         }
265     }
266     return false;
267 }
268 
GetHasSymbol(const std::vector<OptionParam> & params)269 bool GetHasSymbol(const std::vector<OptionParam>& params)
270 {
271     for (size_t i = 0; i < params.size(); ++i) {
272         if (params[i].symbol != nullptr) {
273             return true;
274         }
275     }
276     return false;
277 }
278 
GetFloatImageOffset(const RefPtr<FrameNode> & frameNode)279 OffsetF GetFloatImageOffset(const RefPtr<FrameNode>& frameNode)
280 {
281     auto offsetToWindow = frameNode->GetPaintRectOffset(false, true);
282     auto offsetX = offsetToWindow.GetX();
283     auto offsetY = offsetToWindow.GetY();
284     return OffsetF(offsetX, offsetY);
285 }
286 
UpdateContainerIdealSizeConstraint(const RefPtr<FrameNode> & node,const CalcSize & idealSize)287 void UpdateContainerIdealSizeConstraint(const RefPtr<FrameNode>& node, const CalcSize& idealSize)
288 {
289     CHECK_NULL_VOID(node);
290     MeasureProperty layoutConstraint;
291     layoutConstraint.selfIdealSize = idealSize;
292     auto nodeLayoutProperty = node->GetLayoutProperty<LayoutProperty>();
293     CHECK_NULL_VOID(nodeLayoutProperty);
294     nodeLayoutProperty->UpdateCalcLayoutProperty(layoutConstraint);
295 }
296 
ShowBorderRadiusAndShadowAnimation(const RefPtr<MenuTheme> & menuTheme,const RefPtr<FrameNode> & imageNode,bool isShowHoverImage)297 void ShowBorderRadiusAndShadowAnimation(
298     const RefPtr<MenuTheme>& menuTheme, const RefPtr<FrameNode>& imageNode, bool isShowHoverImage)
299 {
300     CHECK_NULL_VOID(imageNode);
301     auto imageContext = imageNode->GetRenderContext();
302     CHECK_NULL_VOID(imageContext);
303     auto shadow = imageContext->GetBackShadow();
304     if (!shadow.has_value()) {
305         shadow = Shadow::CreateShadow(ShadowStyle::None);
306     }
307     AnimationOption option;
308     option.SetDuration(menuTheme->GetPreviewAnimationDuration());
309     option.SetCurve(Curves::SHARP);
310     auto previewBorderRadius = BorderRadiusProperty(menuTheme->GetPreviewBorderRadius());
311     if (auto presetRad = imageContext->GetBorderRadius(); presetRad) {
312         previewBorderRadius = presetRad.value();
313         imageContext->ResetBorderRadius();
314     }
315 
316     imageContext->UpdateBorderRadius(imageContext->GetBorderRadius().value_or(BorderRadiusProperty()));
317     auto pipelineContext = imageNode->GetContext();
318     CHECK_NULL_VOID(pipelineContext);
319     pipelineContext->AddAfterLayoutTask([option, imageContext, previewBorderRadius, shadow, isShowHoverImage]() {
320         AnimationUtils::Animate(
321             option,
322             [imageContext, previewBorderRadius, shadow, isShowHoverImage]() mutable {
323                 CHECK_NULL_VOID(imageContext && shadow);
324                 auto color = shadow->GetColor();
325                 auto newColor = Color::FromARGB(100, color.GetRed(), color.GetGreen(), color.GetBlue());
326                 shadow->SetColor(newColor);
327                 imageContext->UpdateBackShadow(shadow.value());
328 
329                 CHECK_NULL_VOID(!isShowHoverImage);
330                 imageContext->UpdateBorderRadius(previewBorderRadius);
331             },
332             option.GetOnFinishEvent());
333     });
334 }
335 
UpdateOpacityInFinishEvent(const RefPtr<FrameNode> & previewNode,const RefPtr<RenderContext> & imageContext,const RefPtr<MenuTheme> & menuTheme)336 void UpdateOpacityInFinishEvent(const RefPtr<FrameNode>& previewNode, const RefPtr<RenderContext>& imageContext,
337     const RefPtr<MenuTheme>& menuTheme)
338 {
339     CHECK_NULL_VOID(imageContext && menuTheme);
340     // hover image disappear opacity animation
341     AnimationOption option;
342     option.SetDuration(menuTheme->GetHoverImageSwitchToPreviewOpacityDuration());
343     option.SetCurve(Curves::FRICTION);
344 
345     CHECK_NULL_VOID(previewNode);
346     auto previewContext = previewNode->GetRenderContext();
347     CHECK_NULL_VOID(previewContext);
348 
349     imageContext->UpdateOpacity(1.0);
350     previewContext->UpdateOpacity(0.0);
351     AnimationUtils::Animate(
352         option, [previewContext]() {
353             CHECK_NULL_VOID(previewContext);
354             previewContext->UpdateOpacity(1.0);
355         });
356 }
357 
GetPreviewBorderRadiusFromPattern(const RefPtr<MenuPreviewPattern> & previewPattern,const RefPtr<MenuTheme> & menuTheme)358 RadiusF GetPreviewBorderRadiusFromPattern(
359     const RefPtr<MenuPreviewPattern>& previewPattern, const RefPtr<MenuTheme>& menuTheme)
360 {
361     CHECK_NULL_RETURN(menuTheme, RadiusF(EdgeF()));
362     auto previewBorderRadius = menuTheme->GetPreviewBorderRadius().ConvertToPx();
363     auto topLeft = previewBorderRadius;
364     auto topRight = previewBorderRadius;
365     auto bottomLeft = previewBorderRadius;
366     auto bottomRight = previewBorderRadius;
367 
368     auto radius = RadiusF(EdgeF(topLeft, topLeft), EdgeF(topRight, topRight), EdgeF(bottomLeft, bottomLeft),
369         EdgeF(bottomRight, bottomRight));
370 
371     CHECK_NULL_RETURN(previewPattern, radius);
372     auto menuWrapper = previewPattern->GetMenuWrapper();
373     CHECK_NULL_RETURN(menuWrapper, radius);
374     auto menuWrapperPattern = menuWrapper->GetPattern<MenuWrapperPattern>();
375     CHECK_NULL_RETURN(menuWrapperPattern, radius);
376 
377     auto borderRadius = menuWrapperPattern->GetMenuParam().previewBorderRadius;
378     if (!borderRadius.has_value()) {
379         return radius;
380     }
381 
382     auto previewWidth = previewPattern->GetCustomPreviewWidth();
383     if (borderRadius->radiusTopLeft.has_value()) {
384         topLeft = borderRadius->radiusTopLeft->ConvertToPxWithSize(previewWidth);
385     }
386 
387     if (borderRadius->radiusTopRight.has_value()) {
388         topRight = borderRadius->radiusTopRight->ConvertToPxWithSize(previewWidth);
389     }
390 
391     if (borderRadius->radiusBottomLeft.has_value()) {
392         bottomLeft = borderRadius->radiusBottomLeft->ConvertToPxWithSize(previewWidth);
393     }
394 
395     if (borderRadius->radiusBottomRight.has_value()) {
396         bottomRight = borderRadius->radiusBottomRight->ConvertToPxWithSize(previewWidth);
397     }
398 
399     return RadiusF(EdgeF(topLeft, topLeft), EdgeF(topRight, topRight), EdgeF(bottomLeft, bottomLeft),
400         EdgeF(bottomRight, bottomRight));
401 }
402 
GetHoverImagePreviewProperty(const RefPtr<MenuPreviewPattern> & previewPattern,const RadiusF & radius)403 RefPtr<NodeAnimatablePropertyFloat> GetHoverImagePreviewProperty(
404     const RefPtr<MenuPreviewPattern>& previewPattern, const RadiusF& radius)
405 {
406     CHECK_NULL_RETURN(previewPattern, nullptr);
407     auto menuWrapper = previewPattern->GetMenuWrapper();
408     CHECK_NULL_RETURN(menuWrapper, nullptr);
409     auto menuWrapperPattern = menuWrapper->GetPattern<MenuWrapperPattern>();
410     CHECK_NULL_RETURN(menuWrapperPattern, nullptr);
411 
412     BorderRadiusProperty previewRadius;
413     previewRadius.radiusTopLeft = Dimension(radius.GetCorner(RoundRect::CornerPos::TOP_LEFT_POS).x);
414     previewRadius.radiusTopRight = Dimension(radius.GetCorner(RoundRect::CornerPos::TOP_RIGHT_POS).x);
415     previewRadius.radiusBottomLeft = Dimension(radius.GetCorner(RoundRect::CornerPos::BOTTOM_LEFT_POS).x);
416     previewRadius.radiusBottomRight = Dimension(radius.GetCorner(RoundRect::CornerPos::BOTTOM_RIGHT_POS).x);
417 
418     auto callback = [menuWrapperPattern, previewRadius](float rate) {
419         CHECK_NULL_VOID(menuWrapperPattern && !menuWrapperPattern->IsHide());
420         menuWrapperPattern->SetAnimationClipRate(rate);
421         menuWrapperPattern->SetAnimationBorderRadius(rate, previewRadius);
422     };
423 
424     return AceType::MakeRefPtr<NodeAnimatablePropertyFloat>(-1.0, std::move(callback));
425 }
426 
UpdateHoverImagePreviewScale(const RefPtr<FrameNode> & hoverImageStackNode,const RefPtr<MenuPreviewPattern> & previewPattern,const RefPtr<MenuTheme> & menuTheme)427 void UpdateHoverImagePreviewScale(const RefPtr<FrameNode>& hoverImageStackNode,
428     const RefPtr<MenuPreviewPattern>& previewPattern, const RefPtr<MenuTheme>& menuTheme)
429 {
430     CHECK_NULL_VOID(hoverImageStackNode && previewPattern && menuTheme);
431     auto stackContext = hoverImageStackNode->GetRenderContext();
432     CHECK_NULL_VOID(stackContext);
433 
434     auto scaleBefore = previewPattern->GetHoverImageScaleTo();
435     auto scaleFrom =
436         LessOrEqual(scaleBefore, 0.0) ? menuTheme->GetPreviewBeforeAnimationScale() : scaleBefore;
437     stackContext->UpdateTransformScale(VectorF(scaleFrom, scaleFrom));
438 
439     auto scaleAfter = previewPattern->GetCustomPreviewScaleTo();
440     auto scaleTo =
441         LessOrEqual(scaleAfter, 0.0) ? menuTheme->GetPreviewAfterAnimationScale() : scaleAfter;
442 
443     auto startWidth = previewPattern->GetHoverImageAfterScaleWidth();
444     auto startHeight = previewPattern->GetHoverImageAfterScaleHeight();
445     auto offset = previewPattern->GetHoverImageAfterScaleOffset();
446     auto clipStartRect = RectF(offset, SizeF(startWidth - offset.GetX(), startHeight - offset.GetY()));
447     stackContext->ClipWithRRect(clipStartRect, RadiusF(EdgeF(0.0f, 0.0f)));
448 
449     AnimationOption scaleOption = AnimationOption();
450     scaleOption.SetCurve(CUSTOM_PREVIEW_ANIMATION_CURVE);
451     previewPattern->SetIsHoverImagePreviewScalePlaying(true);
452     scaleOption.SetOnFinishEvent([weak = WeakPtr<MenuPreviewPattern>(previewPattern)] {
453         auto previewPattern = weak.Upgrade();
454         CHECK_NULL_VOID(previewPattern);
455         previewPattern->SetIsHoverImagePreviewScalePlaying(false);
456     });
457 
458     auto endWidth = previewPattern->GetStackAfterScaleActualWidth();
459     auto endHeight = previewPattern->GetStackAfterScaleActualHeight();
460     auto clipRect = RectF(OffsetF(), SizeF(endWidth, endHeight));
461     auto clipRadius = GetPreviewBorderRadiusFromPattern(previewPattern, menuTheme);
462 
463     auto animateProperty = GetHoverImagePreviewProperty(previewPattern, clipRadius);
464     CHECK_NULL_VOID(animateProperty);
465     stackContext->AttachNodeAnimatableProperty(animateProperty);
466     animateProperty->Set(0.0);
467 
468     AnimationUtils::Animate(
469         scaleOption,
470         [stackContext, scaleTo, clipRect, clipRadius, animateProperty]() {
471             CHECK_NULL_VOID(stackContext);
472             stackContext->UpdateTransformScale(VectorF(scaleTo, scaleTo));
473             stackContext->ClipWithRRect(clipRect, clipRadius);
474 
475             CHECK_NULL_VOID(animateProperty);
476             animateProperty->Set(1.0);
477         },
478         scaleOption.GetOnFinishEvent());
479 }
480 
SetHoverImageFinishEvent(const RefPtr<FrameNode> & hoverImageStackNode,const RefPtr<FrameNode> & previewNode,const RefPtr<RenderContext> & imageContext,const RefPtr<MenuTheme> & menuTheme,const RefPtr<MenuWrapperPattern> & wrapperPattern)481 void SetHoverImageFinishEvent(const RefPtr<FrameNode>& hoverImageStackNode, const RefPtr<FrameNode>& previewNode,
482     const RefPtr<RenderContext>& imageContext, const RefPtr<MenuTheme>& menuTheme,
483     const RefPtr<MenuWrapperPattern>& wrapperPattern)
484 {
485     CHECK_NULL_VOID(previewNode);
486     auto previewPattern = previewNode->GetPattern<MenuPreviewPattern>();
487     CHECK_NULL_VOID(previewPattern);
488     previewPattern->SetIsHoverImageScalePlaying(false);
489 
490     CHECK_NULL_VOID(wrapperPattern);
491     // if the animation is interrupted during the image hover phase, the next dynamic effects are not processed.
492     CHECK_NULL_VOID(!wrapperPattern->IsStopHoverImageAnimation());
493 
494     UpdateOpacityInFinishEvent(previewNode, imageContext, menuTheme);
495 
496     UpdateHoverImagePreviewScale(hoverImageStackNode, previewPattern, menuTheme);
497 }
498 
ShowHoverImageAnimationProc(const RefPtr<FrameNode> & hoverImageStackNode,const RefPtr<FrameNode> & previewNode,const RefPtr<RenderContext> & imageContext,const RefPtr<MenuWrapperPattern> & wrapperPattern)499 void ShowHoverImageAnimationProc(const RefPtr<FrameNode>& hoverImageStackNode, const RefPtr<FrameNode>& previewNode,
500     const RefPtr<RenderContext>& imageContext, const RefPtr<MenuWrapperPattern>& wrapperPattern)
501 {
502     CHECK_NULL_VOID(wrapperPattern && wrapperPattern->GetIsShowHoverImage());
503     CHECK_NULL_VOID(hoverImageStackNode && previewNode);
504     auto stackContext = hoverImageStackNode->GetRenderContext();
505     CHECK_NULL_VOID(stackContext);
506     stackContext->UpdateClipEdge(true);
507     auto previewPattern = previewNode->GetPattern<MenuPreviewPattern>();
508     CHECK_NULL_VOID(previewPattern);
509     auto pipeline = previewNode->GetContextWithCheck();
510     CHECK_NULL_VOID(pipeline);
511     auto menuTheme = pipeline->GetTheme<NG::MenuTheme>();
512     CHECK_NULL_VOID(menuTheme);
513 
514     DragEventActuator::ExecutePreDragAction(PreDragStatus::PREVIEW_LIFT_STARTED);
515     auto scaleBefore = previewPattern->GetHoverImageScaleFrom();
516     auto scaleFrom =
517         LessOrEqual(scaleBefore, 0.0) ? menuTheme->GetPreviewBeforeAnimationScale() : scaleBefore;
518     stackContext->UpdateTransformScale(VectorF(scaleFrom, scaleFrom));
519 
520     auto scaleAfter = previewPattern->GetHoverImageScaleTo();
521     auto scaleTo =
522         LessOrEqual(scaleAfter, 0.0) ? menuTheme->GetPreviewAfterAnimationScale() : scaleAfter;
523 
524     previewPattern->SetIsHoverImageScalePlaying(true);
525     // when the scaling start and end sizes are the same, the end callback method should not be relied on
526     AnimationOption scaleOption = AnimationOption();
527     scaleOption.SetOnFinishEvent([hoverImageStackNode, previewNode, imageContext, menuTheme, wrapperPattern]() {
528         DragEventActuator::ExecutePreDragAction(PreDragStatus::PREVIEW_LIFT_FINISHED);
529         SetHoverImageFinishEvent(hoverImageStackNode, previewNode, imageContext, menuTheme, wrapperPattern);
530     });
531     scaleOption.SetDuration(menuTheme->GetHoverImageDelayDuration());
532     scaleOption.SetCurve(Curves::SHARP);
533     scaleTo += NearEqual(scaleFrom, scaleTo) ? MIN_HOVER_SCALE_DIFF : 0.f;
534     AnimationUtils::Animate(
535         scaleOption, [stackContext, scaleTo]() {
536             CHECK_NULL_VOID(stackContext);
537             stackContext->UpdateTransformScale(VectorF(scaleTo, scaleTo));
538         },
539         scaleOption.GetOnFinishEvent());
540 }
541 
ShowPixelMapScaleAnimationProc(const RefPtr<MenuTheme> & menuTheme,const RefPtr<FrameNode> & imageNode,const RefPtr<MenuPattern> & menuPattern)542 void ShowPixelMapScaleAnimationProc(
543     const RefPtr<MenuTheme>& menuTheme, const RefPtr<FrameNode>& imageNode, const RefPtr<MenuPattern>& menuPattern)
544 {
545     CHECK_NULL_VOID(menuPattern && menuTheme);
546     auto scaleBefore = menuPattern->GetPreviewBeforeAnimationScale();
547     auto scaleAfter = menuPattern->GetPreviewAfterAnimationScale();
548     auto previewBeforeAnimationScale =
549         LessNotEqual(scaleBefore, 0.0) ? menuTheme->GetPreviewBeforeAnimationScale() : scaleBefore;
550     auto previewAfterAnimationScale =
551         LessNotEqual(scaleAfter, 0.0) ? menuTheme->GetPreviewAfterAnimationScale() : scaleAfter;
552 
553     auto imagePattern = imageNode->GetPattern<ImagePattern>();
554     CHECK_NULL_VOID(imagePattern);
555     DragEventActuator::ExecutePreDragAction(PreDragStatus::PREVIEW_LIFT_STARTED);
556     auto imageRawSize = imagePattern->GetRawImageSize();
557     auto geometryNode = imageNode->GetGeometryNode();
558     CHECK_NULL_VOID(geometryNode);
559     auto geometrySize = geometryNode->GetFrameSize();
560     if (geometrySize.IsPositive() && imageRawSize.IsPositive() && imageRawSize > geometrySize) {
561         previewBeforeAnimationScale *= imageRawSize.Width() / geometrySize.Width();
562     }
563 
564     CHECK_NULL_VOID(imageNode);
565     auto imageContext = imageNode->GetRenderContext();
566     CHECK_NULL_VOID(imageContext);
567     imageContext->UpdateTransformScale(VectorF(previewBeforeAnimationScale, previewBeforeAnimationScale));
568 
569     AnimationOption scaleOption = AnimationOption();
570     auto motion = AceType::MakeRefPtr<ResponsiveSpringMotion>(
571         menuTheme->GetSpringMotionResponse(), menuTheme->GetSpringMotionDampingFraction());
572     scaleOption.SetCurve(motion);
573     scaleOption.SetOnFinishEvent(
574         []() { DragEventActuator::ExecutePreDragAction(PreDragStatus::PREVIEW_LIFT_FINISHED); });
575 
576     AnimationUtils::Animate(
577         scaleOption,
578         [imageContext, previewAfterAnimationScale]() {
579             CHECK_NULL_VOID(imageContext);
580             imageContext->UpdateTransformScale(VectorF(previewAfterAnimationScale, previewAfterAnimationScale));
581         },
582         scaleOption.GetOnFinishEvent());
583 }
584 
HandleDragEnd(float offsetX,float offsetY,float velocity,const RefPtr<FrameNode> & menuWrapper)585 void HandleDragEnd(float offsetX, float offsetY, float velocity, const RefPtr<FrameNode>& menuWrapper)
586 {
587     if ((LessOrEqual(std::abs(offsetY), std::abs(offsetX)) || LessOrEqual(offsetY, 0.0f)) &&
588         LessOrEqual(velocity, PAN_MAX_VELOCITY)) {
589         return;
590     }
591     CHECK_NULL_VOID(menuWrapper);
592     auto wrapperPattern = menuWrapper->GetPattern<MenuWrapperPattern>();
593     CHECK_NULL_VOID(wrapperPattern);
594     TAG_LOGI(AceLogTag::ACE_MENU, "will hide menu");
595     wrapperPattern->HideMenu();
596 }
597 
InitPanEvent(const RefPtr<GestureEventHub> & targetGestureHub,const RefPtr<GestureEventHub> & gestureHub,const RefPtr<FrameNode> & menuWrapper)598 void InitPanEvent(const RefPtr<GestureEventHub>& targetGestureHub, const RefPtr<GestureEventHub>& gestureHub,
599     const RefPtr<FrameNode>& menuWrapper)
600 {
601     auto dragEventActuator = targetGestureHub->GetDragEventActuator();
602     auto actionStartTask = [actuator = AceType::WeakClaim(AceType::RawPtr(dragEventActuator))](
603                                const GestureEvent& info) {
604         auto dragEventActuator = actuator.Upgrade();
605         CHECK_NULL_VOID(dragEventActuator);
606         dragEventActuator->RestartDragTask(info);
607     };
608     auto actionEndTask = [menuWrapper](const GestureEvent& info) {
609         auto offsetX = static_cast<float>(info.GetOffsetX());
610         auto offsetY = static_cast<float>(info.GetOffsetY());
611         auto offsetPerSecondX = info.GetVelocity().GetOffsetPerSecond().GetX();
612         auto offsetPerSecondY = info.GetVelocity().GetOffsetPerSecond().GetY();
613         auto velocity =
614             static_cast<float>(std::sqrt(offsetPerSecondX * offsetPerSecondX + offsetPerSecondY * offsetPerSecondY));
615         HandleDragEnd(offsetX, offsetY, velocity, menuWrapper);
616     };
617     PanDirection panDirection;
618     panDirection.type = PanDirection::ALL;
619     auto panEvent =
620         AceType::MakeRefPtr<PanEvent>(std::move(actionStartTask), nullptr, std::move(actionEndTask), nullptr);
621     auto distance = SystemProperties::GetDragStartPanDistanceThreshold();
622     gestureHub->AddPanEvent(panEvent, panDirection, 1, Dimension(distance, DimensionUnit::VP));
623 
624     // add TouchEvent for Menu dragStart Move
625     auto touchTask = [actuator = AceType::WeakClaim(AceType::RawPtr(dragEventActuator))](const TouchEventInfo& info) {
626         auto dragEventActuator = actuator.Upgrade();
627         CHECK_NULL_VOID(dragEventActuator);
628         dragEventActuator->HandleTouchEvent(info, true);
629     };
630     auto touchListener = AceType::MakeRefPtr<TouchEventImpl>(std::move(touchTask));
631     gestureHub->AddTouchEvent(touchListener);
632 }
633 
GetHoverImageCustomPreviewBaseScaleInfo(const MenuParam & menuParam,int32_t width,int32_t height,const RefPtr<MenuPreviewPattern> & previewPattern)634 float GetHoverImageCustomPreviewBaseScaleInfo(const MenuParam& menuParam, int32_t width, int32_t height,
635     const RefPtr<MenuPreviewPattern>& previewPattern)
636 {
637     float scaleRet = PREVIEW_ORIGIN_SCALE;
638     CHECK_NULL_RETURN(menuParam.isShowHoverImage, scaleRet);
639     CHECK_NULL_RETURN(previewPattern, scaleRet);
640     // if the parent container is smaller than the child component, the child container will be squeezed
641     auto previewWidth = previewPattern->GetStackAfterScaleActualWidth();
642     auto previewHeight = previewPattern->GetStackAfterScaleActualHeight();
643     CHECK_NULL_RETURN(width > 0 && height > 0, scaleRet);
644     if (LessOrEqual(previewWidth / width, previewHeight / height)) {
645         CHECK_EQUAL_RETURN(previewWidth, 0, scaleRet);
646         scaleRet = width / previewWidth;
647         previewPattern->SetIsWidthDistLarger(false);
648     } else {
649         CHECK_EQUAL_RETURN(previewHeight, 0, scaleRet);
650         scaleRet = height / previewHeight;
651         previewPattern->SetIsWidthDistLarger(true);
652     }
653     return scaleRet;
654 }
655 
SetHoverImageCustomPreviewInfo(const RefPtr<FrameNode> & previewNode,const MenuParam & menuParam,int32_t width,int32_t height)656 void SetHoverImageCustomPreviewInfo(const RefPtr<FrameNode>& previewNode, const MenuParam& menuParam,
657     int32_t width, int32_t height)
658 {
659     CHECK_NULL_VOID(previewNode);
660     auto previewPattern = previewNode->GetPattern<MenuPreviewPattern>();
661     CHECK_NULL_VOID(previewPattern);
662     auto baseScale = GetHoverImageCustomPreviewBaseScaleInfo(menuParam, width, height, previewPattern);
663     CHECK_NULL_VOID(baseScale);
664 
665     auto hoverImageScaleFrom = menuParam.hoverImageAnimationOptions.scaleFrom;
666     hoverImageScaleFrom = LessOrEqual(hoverImageScaleFrom, 0.0) ? PREVIEW_ORIGIN_SCALE : hoverImageScaleFrom;
667     previewPattern->SetHoverImageScaleFrom(baseScale * hoverImageScaleFrom);
668 
669     auto hoverImageScaleTo = menuParam.hoverImageAnimationOptions.scaleTo;
670     hoverImageScaleTo = LessOrEqual(hoverImageScaleTo, 0.0) ? PREVIEW_ORIGIN_SCALE : hoverImageScaleTo;
671     auto hoverImageScaleToNew = baseScale * hoverImageScaleTo;
672     previewPattern->SetHoverImageScaleTo(hoverImageScaleToNew);
673 
674     // get actual area size for clip visible area
675     previewPattern->SetHoverImageAfterScaleWidth(width / baseScale);
676     previewPattern->SetHoverImageAfterScaleHeight(height  / baseScale);
677 
678     // stack attr will not changed by the scale animation, but a start cooradinate is required to calc the clip diff
679     previewPattern->SetClipStartWidth(previewPattern->GetStackAfterScaleActualWidth() * hoverImageScaleToNew);
680     previewPattern->SetClipStartHeight(previewPattern->GetStackAfterScaleActualHeight() * hoverImageScaleToNew);
681     previewPattern->SetClipStartValue(previewPattern->GetIsWidthDistLarger() ? previewPattern->GetClipStartWidth() :
682         previewPattern->GetClipStartHeight());
683     previewPattern->SetClipEndValue(previewPattern->GetIsWidthDistLarger() ?
684         previewPattern->GetStackAfterScaleActualWidth() : previewPattern->GetStackAfterScaleActualHeight());
685 
686     previewPattern->SetHoverImageAfterScaleOffset(OffsetF((previewPattern->GetStackAfterScaleActualWidth() -
687         previewPattern->GetHoverImageAfterScaleWidth()) / HALF_DIVIDE,
688         (previewPattern->GetStackAfterScaleActualHeight() -
689         previewPattern->GetHoverImageAfterScaleHeight()) / HALF_DIVIDE));
690 }
691 
SetAccessibilityPixelMap(const RefPtr<FrameNode> & targetNode,RefPtr<FrameNode> & imageNode)692 void SetAccessibilityPixelMap(const RefPtr<FrameNode>& targetNode, RefPtr<FrameNode>& imageNode)
693 {
694     auto targetProps = targetNode->GetAccessibilityProperty<AccessibilityProperty>();
695     CHECK_NULL_VOID(targetProps);
696     targetProps->SetOnAccessibilityFocusCallback([targetWK = AceType::WeakClaim(AceType::RawPtr(targetNode)),
697         imageWK = AceType::WeakClaim(AceType::RawPtr(imageNode))](bool focus) {
698         if (!focus) {
699             auto targetNode = targetWK.Upgrade();
700             CHECK_NULL_VOID(targetNode);
701             auto context = targetNode->GetRenderContext();
702             CHECK_NULL_VOID(context);
703             auto pixelMap = context->GetThumbnailPixelMap();
704             CHECK_NULL_VOID(pixelMap);
705             auto imageNode = imageWK.Upgrade();
706             CHECK_NULL_VOID(imageNode);
707             auto props = imageNode->GetLayoutProperty<ImageLayoutProperty>();
708             CHECK_NULL_VOID(props);
709             props->UpdateAutoResize(false);
710             props->UpdateImageSourceInfo(ImageSourceInfo(pixelMap));
711             imageNode->MarkModifyDone();
712         }
713     });
714 }
715 
GetPreviewBorderRadiusFromNode(const RefPtr<FrameNode> & previewNode,const MenuParam & menuParam)716 BorderRadiusProperty GetPreviewBorderRadiusFromNode(const RefPtr<FrameNode>& previewNode, const MenuParam& menuParam)
717 {
718     CHECK_NULL_RETURN(previewNode, {});
719     auto pipelineContext = previewNode->GetContextWithCheck();
720     CHECK_NULL_RETURN(pipelineContext, {});
721     auto menuTheme = pipelineContext->GetTheme<NG::MenuTheme>();
722     CHECK_NULL_RETURN(menuTheme, {});
723     auto previewBorderRadiusValue = menuTheme->GetPreviewBorderRadius();
724 
725     CHECK_NULL_RETURN(menuParam.previewBorderRadius, {});
726     if (menuParam.previewBorderRadius.has_value()) {
727         BorderRadiusProperty previewBorderRadius;
728         previewBorderRadius.SetRadius(Dimension(previewBorderRadiusValue));
729         previewBorderRadius.UpdateWithCheck(menuParam.previewBorderRadius.value());
730         return previewBorderRadius;
731     }
732     return BorderRadiusProperty((Dimension(previewBorderRadiusValue)));
733 }
734 
SetPixelMap(const RefPtr<FrameNode> & target,const RefPtr<FrameNode> & wrapperNode,const RefPtr<FrameNode> & hoverImageStackNode,const RefPtr<FrameNode> & previewNode,const MenuParam & menuParam)735 void SetPixelMap(const RefPtr<FrameNode>& target, const RefPtr<FrameNode>& wrapperNode,
736     const RefPtr<FrameNode>& hoverImageStackNode, const RefPtr<FrameNode>& previewNode, const MenuParam& menuParam)
737 {
738     CHECK_NULL_VOID(target);
739     auto eventHub = target->GetEventHub<NG::EventHub>();
740     CHECK_NULL_VOID(eventHub);
741     auto gestureHub = eventHub->GetGestureEventHub();
742     CHECK_NULL_VOID(gestureHub);
743     RefPtr<PixelMap> pixelMap = gestureHub->GetPixelMap();
744     CHECK_NULL_VOID(pixelMap);
745     auto width = pixelMap->GetWidth();
746     auto height = pixelMap->GetHeight();
747     auto imageOffset = GetFloatImageOffset(target);
748     auto imageNode = FrameNode::GetOrCreateFrameNode(V2::IMAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
749         []() { return AceType::MakeRefPtr<ImagePattern>(); });
750     imageNode->GetPaintProperty<ImageRenderProperty>()->UpdateImageInterpolation(ImageInterpolation::HIGH);
751     auto props = imageNode->GetLayoutProperty<ImageLayoutProperty>();
752     props->UpdateAutoResize(false);
753     props->UpdateImageSourceInfo(ImageSourceInfo(pixelMap));
754     imageNode->GetPattern<ImagePattern>()->SetSyncLoad(true);
755     SetAccessibilityPixelMap(target, imageNode);
756     auto hub = imageNode->GetEventHub<EventHub>();
757     CHECK_NULL_VOID(hub);
758     auto imageGestureHub = hub->GetOrCreateGestureEventHub();
759     CHECK_NULL_VOID(imageGestureHub);
760     InitPanEvent(gestureHub, imageGestureHub, wrapperNode);
761 
762     if (menuParam.isShowHoverImage) {
763         props->UpdateImageFit(ImageFit::CONTAIN);
764 
765         imageNode->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT);
766         imageNode->MarkModifyDone();
767         imageNode->MountToParent(hoverImageStackNode);
768     } else {
769         auto targetSize = CalcSize(NG::CalcLength(width), NG::CalcLength(height));
770         props->UpdateUserDefinedIdealSize(targetSize);
771         props->UpdateImageFit(ImageFit::FILL);
772 
773         auto imageContext = imageNode->GetRenderContext();
774         CHECK_NULL_VOID(imageContext);
775         BorderRadiusProperty borderRadius = GetPreviewBorderRadiusFromNode(previewNode, menuParam);
776         if (menuParam.previewBorderRadius) {
777             imageContext->UpdateBorderRadius(borderRadius);
778         }
779         imageNode->MarkModifyDone();
780         imageNode->MountToParent(wrapperNode);
781         DragAnimationHelper::UpdateGatherNodeToTop();
782         DragDropFuncWrapper::UpdatePositionFromFrameNode(imageNode, target, width, height);
783         imageOffset = DragDropFuncWrapper::GetPaintRectCenterToScreen(target) -
784             OffsetF(width / HALF_DIVIDE, height / HALF_DIVIDE);
785         imageOffset -= DragDropFuncWrapper::GetCurrentWindowOffset(imageNode->GetContextRefPtr());
786         MountTextNode(wrapperNode, previewNode);
787     }
788 
789     auto geometryNode = imageNode->GetGeometryNode();
790     CHECK_NULL_VOID(geometryNode);
791     geometryNode->SetFrameOffset(imageOffset);
792 }
793 
SetFilter(const RefPtr<FrameNode> & targetNode,const RefPtr<FrameNode> & menuWrapperNode)794 void SetFilter(const RefPtr<FrameNode>& targetNode, const RefPtr<FrameNode>& menuWrapperNode)
795 {
796     auto parent = targetNode->GetParent();
797     CHECK_NULL_VOID(parent);
798     while (parent->GetDepth() != 1) {
799         parent = parent->GetParent();
800         CHECK_NULL_VOID(parent);
801     }
802     auto containerId = Container::CurrentId();
803     if (containerId >= MIN_SUBCONTAINER_ID) {
804         containerId = SubwindowManager::GetInstance()->GetParentContainerId(containerId);
805     }
806     ContainerScope scope(containerId);
807     auto container = Container::Current();
808     CHECK_NULL_VOID(container);
809     auto pipelineContext = AceType::DynamicCast<PipelineContext>(container->GetPipelineContext());
810     CHECK_NULL_VOID(pipelineContext);
811     auto manager = pipelineContext->GetOverlayManager();
812     CHECK_NULL_VOID(manager);
813     auto menuTheme = pipelineContext->GetTheme<NG::MenuTheme>();
814     CHECK_NULL_VOID(menuTheme);
815     if (!manager->GetHasFilter() && !manager->GetIsOnAnimation()) {
816         bool isBindOverlayValue = targetNode->GetLayoutProperty()->GetIsBindOverlayValue(false);
817         CHECK_NULL_VOID(isBindOverlayValue && menuTheme->GetHasFilter());
818         // insert columnNode to rootNode
819         auto columnNode = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
820             AceType::MakeRefPtr<LinearLayoutPattern>(true));
821         columnNode->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT);
822         auto accessibilityProperty = columnNode->GetAccessibilityProperty<NG::AccessibilityProperty>();
823         if (accessibilityProperty) {
824             accessibilityProperty->SetAccessibilityHoverPriority(true); // consume barrierfree hover event
825         }
826         // set filter
827         if (container->IsScenceBoardWindow()) {
828             auto windowScene = manager->FindWindowScene(targetNode);
829             manager->MountFilterToWindowScene(columnNode, windowScene);
830             manager->ShowFilterAnimation(columnNode);
831         } else if (container->IsUIExtensionWindow()) {
832             // mount filter node on subwindow to ensure filter node's size equals to host window's size
833             CHECK_NULL_VOID(menuWrapperNode);
834             auto menuWrapperPattern = menuWrapperNode->GetPattern<MenuWrapperPattern>();
835             CHECK_NULL_VOID(menuWrapperPattern);
836             menuWrapperPattern->SetFilterColumnNode(columnNode);
837         } else {
838             columnNode->MountToParent(parent);
839             columnNode->OnMountToParentDone();
840             manager->SetHasFilter(true);
841             manager->SetFilterActive(true);
842             manager->SetFilterColumnNode(columnNode);
843             parent->MarkDirtyNode(NG::PROPERTY_UPDATE_BY_CHILD_REQUEST);
844             manager->ShowFilterAnimation(columnNode);
845         }
846     }
847 }
848 
SetPreviewInfoToMenu(const RefPtr<FrameNode> & targetNode,const RefPtr<FrameNode> & wrapperNode,const RefPtr<FrameNode> & hoverImageStackNode,const RefPtr<FrameNode> & previewNode,const MenuParam & menuParam)849 void SetPreviewInfoToMenu(const RefPtr<FrameNode>& targetNode, const RefPtr<FrameNode>& wrapperNode,
850     const RefPtr<FrameNode>& hoverImageStackNode, const RefPtr<FrameNode>& previewNode, const MenuParam& menuParam)
851 {
852     CHECK_NULL_VOID(targetNode);
853     auto eventHub = targetNode->GetEventHub<EventHub>();
854     CHECK_NULL_VOID(eventHub);
855     auto gestureEventHub = eventHub->GetGestureEventHub();
856     CHECK_NULL_VOID(gestureEventHub);
857     auto isAllowedDrag = gestureEventHub->IsAllowedDrag(eventHub) && !gestureEventHub->GetTextDraggable();
858     auto isLiftingDisabled = targetNode->GetDragPreviewOption().isLiftingDisabled;
859     if (targetNode->GetTag() == V2::TEXT_ETS_TAG && targetNode->IsDraggable() && !targetNode->IsCustomerSet()) {
860         auto textPattern = targetNode->GetPattern<TextPattern>();
861         if (textPattern && textPattern->GetCopyOptions() == CopyOptions::None) {
862             isAllowedDrag = false;
863         }
864     }
865     if (menuParam.previewMode != MenuPreviewMode::NONE || (isAllowedDrag && !isLiftingDisabled)) {
866         DragDropGlobalController::GetInstance().UpdateDragFilterShowingStatus(true);
867         SetFilter(targetNode, wrapperNode);
868     }
869     if (menuParam.previewMode == MenuPreviewMode::IMAGE ||
870         (menuParam.previewMode == MenuPreviewMode::NONE && menuParam.menuBindType == MenuBindingType::LONG_PRESS &&
871             isAllowedDrag && !isLiftingDisabled) ||
872         menuParam.isShowHoverImage) {
873         SetPixelMap(targetNode, wrapperNode, hoverImageStackNode, previewNode, menuParam);
874     }
875     if (menuParam.previewMode == MenuPreviewMode::NONE && isAllowedDrag && !isLiftingDisabled) {
876         CHECK_NULL_VOID(wrapperNode);
877         auto pixelMapNode = AceType::DynamicCast<FrameNode>(wrapperNode->GetChildAtIndex(1));
878         CHECK_NULL_VOID(pixelMapNode);
879         auto renderContext = pixelMapNode->GetRenderContext();
880         CHECK_NULL_VOID(renderContext);
881         renderContext->UpdateZIndex(-1);
882         auto menuNode = AceType::DynamicCast<FrameNode>(wrapperNode->GetChildAtIndex(0));
883         if (menuNode) {
884             MenuView::ShowPixelMapAnimation(menuNode);
885         }
886         // if filter set in subwindow, need to adjust zOrder to show in back.
887         auto menuWrapperPattern = wrapperNode->GetPattern<MenuWrapperPattern>();
888         CHECK_NULL_VOID(menuWrapperPattern);
889         auto columnNode = menuWrapperPattern->GetFilterColumnNode();
890         CHECK_NULL_VOID(columnNode);
891         auto columnRenderContext = columnNode->GetRenderContext();
892         CHECK_NULL_VOID(columnRenderContext);
893         columnRenderContext->UpdateZIndex(-1);
894     }
895 }
896 
SetHasCustomRadius(const RefPtr<FrameNode> & menuWrapperNode,const RefPtr<FrameNode> & menuNode,const MenuParam & menuParam)897 void SetHasCustomRadius(
898     const RefPtr<FrameNode>& menuWrapperNode, const RefPtr<FrameNode>& menuNode, const MenuParam& menuParam)
899 {
900     CHECK_NULL_VOID(menuWrapperNode);
901     CHECK_NULL_VOID(menuNode);
902     auto menuWrapperPattern = menuWrapperNode->GetPattern<MenuWrapperPattern>();
903     CHECK_NULL_VOID(menuWrapperPattern);
904     if (menuParam.borderRadius.has_value()) {
905         menuWrapperPattern->SetHasCustomRadius(true);
906         auto menuProperty = menuNode->GetLayoutProperty<MenuLayoutProperty>();
907         CHECK_NULL_VOID(menuProperty);
908         menuProperty->UpdateBorderRadius(menuParam.borderRadius.value());
909     } else {
910         auto menuProperty = menuNode->GetLayoutProperty<MenuLayoutProperty>();
911         CHECK_NULL_VOID(menuProperty);
912         menuWrapperPattern->SetHasCustomRadius(false);
913         auto pipeline = PipelineBase::GetCurrentContext();
914         CHECK_NULL_VOID(pipeline);
915         auto theme = pipeline->GetTheme<SelectTheme>();
916         CHECK_NULL_VOID(theme);
917         Dimension defaultDimension(0);
918         BorderRadiusProperty radius = { defaultDimension, defaultDimension, defaultDimension, defaultDimension };
919         auto defaultRadius = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)
920                                  ? theme->GetMenuDefaultRadius()
921                                  : theme->GetMenuBorderRadius();
922         radius.SetRadius(defaultRadius);
923         menuProperty->UpdateBorderRadius(radius);
924     }
925 }
926 
SetMenuFocusRule(const RefPtr<FrameNode> & menuNode)927 void SetMenuFocusRule(const RefPtr<FrameNode>& menuNode)
928 {
929     CHECK_NULL_VOID(menuNode);
930     auto focusHub = menuNode->GetFocusHub();
931     CHECK_NULL_VOID(focusHub);
932 
933     auto pipelineContext = menuNode->GetContextWithCheck();
934     CHECK_NULL_VOID(pipelineContext);
935     auto menuTheme = pipelineContext->GetTheme<NG::MenuTheme>();
936     CHECK_NULL_VOID(menuTheme);
937     focusHub->SetDirectionalKeyFocus(menuTheme->GetEnableDirectionalKeyFocus());
938 }
939 
ConvertTxtTextAlign(bool IsRightToLeft,TextAlign textAlign)940 Alignment ConvertTxtTextAlign(bool IsRightToLeft, TextAlign textAlign)
941 {
942     Alignment convertValue;
943     switch (textAlign) {
944         case TextAlign::LEFT:
945             convertValue = Alignment::CENTER_LEFT;
946             break;
947         case TextAlign::CENTER:
948             convertValue = Alignment::CENTER;
949             break;
950         case TextAlign::RIGHT:
951             convertValue = Alignment::CENTER_RIGHT;
952             break;
953         case TextAlign::START:
954             convertValue = IsRightToLeft ? Alignment::CENTER_RIGHT : Alignment::CENTER_LEFT;
955             break;
956         case TextAlign::END:
957             convertValue = IsRightToLeft ? Alignment::CENTER_LEFT : Alignment::CENTER_RIGHT;
958             break;
959         default:
960             break;
961     }
962     return convertValue;
963 }
964 
SetBackgroundBlurStyle(const RefPtr<FrameNode> & host,const BlurStyleOption & bgBlurStyle)965 void SetBackgroundBlurStyle(const RefPtr<FrameNode>& host, const BlurStyleOption& bgBlurStyle)
966 {
967     CHECK_NULL_VOID(host);
968     auto pipeline = host->GetContext();
969     CHECK_NULL_VOID(pipeline);
970     if (bgBlurStyle.policy == BlurStyleActivePolicy::FOLLOWS_WINDOW_ACTIVE_STATE) {
971         pipeline->AddWindowFocusChangedCallback(host->GetId());
972     } else {
973         pipeline->RemoveWindowFocusChangedCallback(host->GetId());
974     }
975     auto renderContext = host->GetRenderContext();
976     if (renderContext) {
977         if (renderContext->GetBackgroundEffect().has_value()) {
978             renderContext->UpdateBackgroundEffect(std::nullopt);
979         }
980         renderContext->UpdateBackBlurStyle(bgBlurStyle);
981         if (renderContext->GetBackBlurRadius().has_value()) {
982             renderContext->UpdateBackBlurRadius(Dimension());
983         }
984     }
985 }
986 
SetBackgroundEffect(const RefPtr<FrameNode> & host,const EffectOption & effectOption)987 void SetBackgroundEffect(const RefPtr<FrameNode>& host, const EffectOption &effectOption)
988 {
989     CHECK_NULL_VOID(host);
990     auto pipeline = host->GetContext();
991     CHECK_NULL_VOID(pipeline);
992     if (effectOption.policy == BlurStyleActivePolicy::FOLLOWS_WINDOW_ACTIVE_STATE) {
993         pipeline->AddWindowFocusChangedCallback(host->GetId());
994     } else {
995         pipeline->RemoveWindowFocusChangedCallback(host->GetId());
996     }
997     auto renderContext = host->GetRenderContext();
998     if (renderContext) {
999         if (renderContext->GetBackBlurRadius().has_value()) {
1000             renderContext->UpdateBackBlurRadius(Dimension());
1001         }
1002         if (renderContext->GetBackBlurStyle().has_value()) {
1003             renderContext->UpdateBackBlurStyle(std::nullopt);
1004         }
1005         renderContext->UpdateBackgroundEffect(effectOption);
1006     }
1007 }
1008 
UpdateMenuBackgroundStyleOption(const RefPtr<FrameNode> & menuNode,const MenuParam & menuParam)1009 void UpdateMenuBackgroundStyleOption(const RefPtr<FrameNode>& menuNode, const MenuParam& menuParam)
1010 {
1011     if (menuParam.backgroundBlurStyleOption.has_value()) {
1012         BlurStyleOption backgroundBlurStyleOption = menuParam.backgroundBlurStyleOption.value();
1013         SetBackgroundBlurStyle(menuNode, backgroundBlurStyleOption);
1014     }
1015     if (menuParam.backgroundEffectOption.has_value()) {
1016         EffectOption backgroundEffectOption = menuParam.backgroundEffectOption.value();
1017         SetBackgroundEffect(menuNode, backgroundEffectOption);
1018     }
1019 }
1020 } // namespace
1021 
CalcHoverScaleInfo(const RefPtr<FrameNode> & menuNode)1022 void MenuView::CalcHoverScaleInfo(const RefPtr<FrameNode>& menuNode)
1023 {
1024     CHECK_NULL_VOID(menuNode);
1025     auto menuPattern = menuNode->GetPattern<MenuPattern>();
1026     CHECK_NULL_VOID(menuPattern);
1027     CHECK_NULL_VOID(menuPattern->GetIsShowHoverImage());
1028 
1029     auto wrapperNode = menuPattern->GetMenuWrapper();
1030     CHECK_NULL_VOID(wrapperNode);
1031     auto menuWrapperPattern = wrapperNode->GetPattern<MenuWrapperPattern>();
1032     CHECK_NULL_VOID(menuWrapperPattern);
1033     auto imageNode = menuWrapperPattern->GetHoverImagePreview();
1034     CHECK_NULL_VOID(imageNode);
1035     auto imagePattern = imageNode->GetPattern<ImagePattern>();
1036     CHECK_NULL_VOID(imagePattern);
1037 
1038     auto preview = menuWrapperPattern->GetPreview();
1039     CHECK_NULL_VOID(preview);
1040     auto previewGeometryNode = preview->GetGeometryNode();
1041     CHECK_NULL_VOID(previewGeometryNode);
1042     auto previewPattern = preview->GetPattern<MenuPreviewPattern>();
1043     CHECK_NULL_VOID(previewPattern);
1044     auto previewSize = previewGeometryNode->GetMarginFrameSize();
1045     previewPattern->SetStackAfterScaleActualWidth(previewSize.Width());
1046     previewPattern->SetStackAfterScaleActualHeight(previewSize.Height());
1047 
1048     auto menuParam = menuWrapperPattern->GetMenuParam();
1049     auto imageRawSize = imagePattern->GetRawImageSize();
1050     SetHoverImageCustomPreviewInfo(preview, menuParam, imageRawSize.Width(), imageRawSize.Height());
1051 }
1052 
ShowPixelMapAnimation(const RefPtr<FrameNode> & menuNode)1053 void MenuView::ShowPixelMapAnimation(const RefPtr<FrameNode>& menuNode)
1054 {
1055     CHECK_NULL_VOID(menuNode);
1056     auto menuPattern = menuNode->GetPattern<MenuPattern>();
1057     CHECK_NULL_VOID(menuPattern);
1058     auto wrapperNode = menuPattern->GetMenuWrapper();
1059     CHECK_NULL_VOID(wrapperNode);
1060     auto menuWrapperPattern = wrapperNode->GetPattern<MenuWrapperPattern>();
1061     CHECK_NULL_VOID(menuWrapperPattern);
1062 
1063     auto preview = AceType::DynamicCast<FrameNode>(wrapperNode->GetChildAtIndex(1));
1064     CHECK_NULL_VOID(preview);
1065     auto imageNode = preview->GetTag() == V2::FLEX_ETS_TAG ? menuWrapperPattern->GetHoverImagePreview() : preview;
1066     CHECK_NULL_VOID(imageNode);
1067     auto imageContext = imageNode->GetRenderContext();
1068     CHECK_NULL_VOID(imageContext);
1069     imageContext->SetClipToBounds(true);
1070 
1071     auto pipelineContext = menuNode->GetContext();
1072     CHECK_NULL_VOID(pipelineContext);
1073     auto menuTheme = pipelineContext->GetTheme<NG::MenuTheme>();
1074     CHECK_NULL_VOID(menuTheme);
1075 
1076     auto isShowHoverImage = menuPattern->GetIsShowHoverImage();
1077     if (menuWrapperPattern->HasPreviewTransitionEffect()) {
1078         auto layoutProperty = imageNode->GetLayoutProperty();
1079         layoutProperty->UpdateVisibility(VisibleType::VISIBLE, true);
1080     }
1081     if (isShowHoverImage) {
1082         auto hoverImageStackNode = menuWrapperPattern->GetHoverImageStackNode();
1083         auto previewNode = menuWrapperPattern->GetHoverImageCustomPreview();
1084         ShowHoverImageAnimationProc(hoverImageStackNode, previewNode, imageContext, menuWrapperPattern);
1085     } else {
1086         ShowPixelMapScaleAnimationProc(menuTheme, imageNode, menuPattern);
1087     }
1088     ShowBorderRadiusAndShadowAnimation(menuTheme, imageNode, isShowHoverImage);
1089 }
1090 
GetMenuPixelMap(const RefPtr<FrameNode> & targetNode,const MenuParam & menuParam,const RefPtr<FrameNode> & wrapperNode)1091 void MenuView::GetMenuPixelMap(
1092     const RefPtr<FrameNode>& targetNode, const MenuParam& menuParam, const RefPtr<FrameNode>& wrapperNode)
1093 {
1094     CHECK_NULL_VOID(targetNode);
1095     CHECK_NULL_VOID(wrapperNode);
1096     MenuType type = MenuType::MENU;
1097     auto nodeId = ElementRegister::GetInstance()->MakeUniqueId();
1098     auto previewNode = FrameNode::CreateFrameNode(V2::MENU_PREVIEW_ETS_TAG,
1099         ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<MenuPreviewPattern>());
1100     CHECK_NULL_VOID(previewNode);
1101     auto menuNode = FrameNode::CreateFrameNode(
1102         V2::MENU_ETS_TAG, nodeId, AceType::MakeRefPtr<MenuPattern>(targetNode->GetId(), targetNode->GetTag(), type));
1103     CHECK_NULL_VOID(menuNode);
1104     ContextMenuChildMountProc(targetNode, wrapperNode, previewNode, menuNode, menuParam);
1105     MountTextNode(wrapperNode, nullptr);
1106 }
1107 
1108 // create menu with MenuElement array
Create(std::vector<OptionParam> && params,int32_t targetId,const std::string & targetTag,MenuType type,const MenuParam & menuParam)1109 RefPtr<FrameNode> MenuView::Create(std::vector<OptionParam>&& params, int32_t targetId, const std::string& targetTag,
1110     MenuType type, const MenuParam& menuParam)
1111 {
1112     auto [wrapperNode, menuNode] = CreateMenu(targetId, targetTag, type);
1113     CHECK_NULL_RETURN(wrapperNode && menuNode, nullptr);
1114     UpdateMenuBackgroundStyle(menuNode, menuParam);
1115     auto column = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
1116         AceType::MakeRefPtr<LinearLayoutPattern>(true));
1117     if (!menuParam.title.empty()) {
1118         CreateTitleNode(menuParam.title, column);
1119     }
1120     SetHasCustomRadius(wrapperNode, menuNode, menuParam);
1121     SetMenuFocusRule(menuNode);
1122     MountOptionToColumn(params, menuNode, menuParam, column);
1123     auto menuWrapperPattern = wrapperNode->GetPattern<MenuWrapperPattern>();
1124     CHECK_NULL_RETURN(menuWrapperPattern, nullptr);
1125     menuWrapperPattern->SetHoverMode(menuParam.enableHoverMode);
1126     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) && !menuParam.enableArrow.value_or(false)) {
1127         UpdateMenuBorderEffect(menuNode);
1128     }
1129     auto menuProperty = menuNode->GetLayoutProperty<MenuLayoutProperty>();
1130     if (menuProperty) {
1131         menuProperty->UpdateTitle(menuParam.title);
1132         menuProperty->UpdatePositionOffset(menuParam.positionOffset);
1133         if (menuParam.placement.has_value()) {
1134             menuProperty->UpdateMenuPlacement(menuParam.placement.value_or(OHOS::Ace::Placement::BOTTOM));
1135         }
1136         menuProperty->UpdateShowInSubWindow(menuParam.isShowInSubWindow);
1137     }
1138     UpdateMenuPaintProperty(menuNode, menuParam, type);
1139     auto scroll = CreateMenuScroll(column);
1140     CHECK_NULL_RETURN(scroll, nullptr);
1141     scroll->MountToParent(menuNode);
1142     scroll->MarkModifyDone();
1143     menuNode->MarkModifyDone();
1144     return wrapperNode;
1145 }
1146 
SetPreviewTransitionEffect(const RefPtr<FrameNode> & menuWrapperNode,const MenuParam & menuParam)1147 void SetPreviewTransitionEffect(const RefPtr<FrameNode> &menuWrapperNode, const MenuParam &menuParam)
1148 {
1149     TAG_LOGD(AceLogTag::ACE_DIALOG, "set menu transition effect");
1150     CHECK_NULL_VOID(menuWrapperNode);
1151     auto pattern = menuWrapperNode->GetPattern<MenuWrapperPattern>();
1152     CHECK_NULL_VOID(pattern);
1153     pattern->SetHasPreviewTransitionEffect(menuParam.hasPreviewTransitionEffect);
1154 }
1155 
SetPreviewScaleAndHoverImageScale(const RefPtr<FrameNode> & menuNode,const MenuParam & menuParam)1156 void SetPreviewScaleAndHoverImageScale(const RefPtr<FrameNode>& menuNode, const MenuParam& menuParam)
1157 {
1158     auto pattern = menuNode->GetPattern<MenuPattern>();
1159     CHECK_NULL_VOID(pattern);
1160     pattern->SetPreviewMode(menuParam.previewMode);
1161     pattern->SetPreviewBeforeAnimationScale(menuParam.previewAnimationOptions.scaleFrom);
1162     pattern->SetPreviewAfterAnimationScale(menuParam.previewAnimationOptions.scaleTo);
1163     pattern->SetIsShowHoverImage(menuParam.isShowHoverImage);
1164 }
1165 
CustomPreviewParentNodeCreate(const RefPtr<FrameNode> & stackNode,const RefPtr<FrameNode> & posNode,const RefPtr<FrameNode> & wrapperNode,const RefPtr<FrameNode> & previewNode)1166 void MenuView::CustomPreviewParentNodeCreate(const RefPtr<FrameNode>& stackNode, const RefPtr<FrameNode>& posNode,
1167     const RefPtr<FrameNode>& wrapperNode, const RefPtr<FrameNode>& previewNode)
1168 {
1169     CHECK_NULL_VOID(previewNode);
1170     auto previewPattern = previewNode->GetPattern<MenuPreviewPattern>();
1171     CHECK_NULL_VOID(previewPattern);
1172     auto previewWidth = previewPattern->GetCustomPreviewWidth();
1173     auto previewHeight = previewPattern->GetCustomPreviewHeight();
1174     CHECK_NULL_VOID(stackNode);
1175     CalcSize maxSize = { CalcLength(previewWidth), CalcLength(previewHeight) };
1176 
1177     CHECK_NULL_VOID(posNode);
1178     UpdateContainerIdealSizeConstraint(posNode, maxSize);
1179     auto posProps = posNode->GetLayoutProperty<FlexLayoutProperty>();
1180     CHECK_NULL_VOID(posProps);
1181     posProps->UpdateMainAxisAlign(FlexAlign::CENTER);
1182     posProps->UpdateCrossAxisAlign(FlexAlign::CENTER);
1183     stackNode->MountToParent(posNode);
1184     stackNode->MarkModifyDone();
1185 
1186     CHECK_NULL_VOID(wrapperNode);
1187     posNode->MountToParent(wrapperNode);
1188     posNode->MarkModifyDone();
1189 }
1190 
1191 // contextmenu mount info proc
ContextMenuChildMountProc(const RefPtr<FrameNode> & targetNode,const RefPtr<FrameNode> & wrapperNode,const RefPtr<FrameNode> & previewNode,const RefPtr<FrameNode> & menuNode,const MenuParam & menuParam)1192 void MenuView::ContextMenuChildMountProc(const RefPtr<FrameNode>& targetNode, const RefPtr<FrameNode>& wrapperNode,
1193     const RefPtr<FrameNode>& previewNode, const RefPtr<FrameNode>& menuNode, const MenuParam& menuParam)
1194 {
1195     // stack to put image and custom preview and control visible area when hoverImage api is using
1196     auto hoverImageStackNode = FrameNode::GetOrCreateFrameNode(V2::STACK_ETS_TAG,
1197         ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<StackPattern>(); });
1198     CHECK_NULL_VOID(hoverImageStackNode);
1199 
1200     // flex  to control visible area position
1201     auto hoverImagePosNode = FrameNode::CreateFrameNode(V2::FLEX_ETS_TAG,
1202         ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<FlexLayoutPattern>(false));
1203     CHECK_NULL_VOID(hoverImagePosNode);
1204 
1205     if (menuParam.isShowHoverImage) {
1206         CustomPreviewParentNodeCreate(hoverImageStackNode, hoverImagePosNode, wrapperNode, previewNode);
1207         CHECK_NULL_VOID(wrapperNode);
1208         auto menuWrapperPattern = wrapperNode->GetPattern<MenuWrapperPattern>();
1209         CHECK_NULL_VOID(menuWrapperPattern);
1210         menuWrapperPattern->SetIsShowHoverImage(menuParam.isShowHoverImage);
1211         auto previewRenderContext = previewNode->GetRenderContext();
1212         CHECK_NULL_VOID(previewRenderContext);
1213         previewRenderContext->UpdateOpacity(0.0);
1214     }
1215 
1216     if (menuNode) {
1217         SetPreviewInfoToMenu(targetNode, wrapperNode, hoverImageStackNode, previewNode, menuParam);
1218     }
1219 
1220     if (menuParam.previewMode == MenuPreviewMode::CUSTOM) {
1221         previewNode->MountToParent(menuParam.isShowHoverImage ? hoverImageStackNode : wrapperNode);
1222         previewNode->MarkModifyDone();
1223     }
1224 }
1225 
1226 // create menu with custom node from a builder
Create(const RefPtr<UINode> & customNode,int32_t targetId,const std::string & targetTag,const MenuParam & menuParam,bool withWrapper,const RefPtr<UINode> & previewCustomNode)1227 RefPtr<FrameNode> MenuView::Create(const RefPtr<UINode>& customNode, int32_t targetId, const std::string& targetTag,
1228     const MenuParam& menuParam, bool withWrapper, const RefPtr<UINode>& previewCustomNode)
1229 {
1230     auto type = menuParam.type;
1231     auto [wrapperNode, menuNode] = CreateMenu(targetId, targetTag, type);
1232     CHECK_NULL_RETURN(wrapperNode && menuNode, nullptr);
1233     // create previewNode
1234     auto previewNode = FrameNode::CreateFrameNode(V2::MENU_PREVIEW_ETS_TAG,
1235         ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<MenuPreviewPattern>());
1236     CHECK_NULL_RETURN(previewNode, nullptr);
1237     auto menuWrapperPattern = wrapperNode->GetPattern<MenuWrapperPattern>();
1238     CHECK_NULL_RETURN(menuWrapperPattern, nullptr);
1239     menuWrapperPattern->SetMenuParam(menuParam);
1240     menuWrapperPattern->SetHoverMode(menuParam.enableHoverMode);
1241 
1242     CustomPreviewNodeProc(previewNode, menuParam, previewCustomNode);
1243     UpdateMenuBackgroundStyle(menuNode, menuParam);
1244     SetPreviewTransitionEffect(wrapperNode, menuParam);
1245     SetHasCustomRadius(wrapperNode, menuNode, menuParam);
1246     SetMenuFocusRule(menuNode);
1247 
1248     SetPreviewScaleAndHoverImageScale(menuNode, menuParam);
1249     // put custom node in a scroll to limit its height
1250     auto scroll = CreateMenuScroll(customNode);
1251     CHECK_NULL_RETURN(scroll, nullptr);
1252     MountScrollToMenu(customNode, scroll, type, menuNode);
1253     UpdateMenuProperties(wrapperNode, menuNode, menuParam, type);
1254 
1255     if (type == MenuType::SUB_MENU || type == MenuType::SELECT_OVERLAY_SUB_MENU || !withWrapper) {
1256         wrapperNode->RemoveChild(menuNode);
1257         wrapperNode.Reset();
1258         return menuNode;
1259     }
1260     if (type == MenuType::CONTEXT_MENU) {
1261         auto targetNode = FrameNode::GetFrameNode(targetTag, targetId);
1262         ContextMenuChildMountProc(targetNode, wrapperNode, previewNode, menuNode, menuParam);
1263         MountTextNode(wrapperNode, previewCustomNode);
1264     }
1265     return wrapperNode;
1266 }
1267 
UpdateMenuParam(const RefPtr<FrameNode> & wrapperNode,const RefPtr<FrameNode> & menuNode,const MenuParam & menuParam)1268 void MenuView::UpdateMenuParam(
1269     const RefPtr<FrameNode>& wrapperNode, const RefPtr<FrameNode>& menuNode, const MenuParam& menuParam)
1270 {
1271     auto menuWrapperPattern = wrapperNode->GetPattern<MenuWrapperPattern>();
1272     CHECK_NULL_VOID(menuWrapperPattern);
1273     menuWrapperPattern->SetHoverMode(menuParam.enableHoverMode);
1274     auto menuPattern = menuNode->GetPattern<MenuPattern>();
1275     CHECK_NULL_VOID(menuPattern);
1276     UpdateMenuBackgroundStyle(menuNode, menuParam);
1277     SetPreviewTransitionEffect(wrapperNode, menuParam);
1278     SetHasCustomRadius(wrapperNode, menuNode, menuParam);
1279 }
1280 
UpdateMenuProperties(const RefPtr<FrameNode> & wrapperNode,const RefPtr<FrameNode> & menuNode,const MenuParam & menuParam,const MenuType & type)1281 void MenuView::UpdateMenuProperties(const RefPtr<FrameNode>& wrapperNode, const RefPtr<FrameNode>& menuNode,
1282     const MenuParam& menuParam, const MenuType& type)
1283 {
1284     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) && !menuParam.enableArrow.value_or(false)) {
1285         UpdateMenuBorderEffect(menuNode);
1286     }
1287     menuNode->MarkModifyDone();
1288 
1289     auto menuProperty = menuNode->GetLayoutProperty<MenuLayoutProperty>();
1290     if (menuProperty) {
1291         menuProperty->UpdateTitle(menuParam.title);
1292         menuProperty->UpdatePositionOffset(menuParam.positionOffset);
1293         if (menuParam.placement.has_value()) {
1294             menuProperty->UpdateMenuPlacement(menuParam.placement.value());
1295         }
1296         menuProperty->UpdateShowInSubWindow(menuParam.isShowInSubWindow);
1297     }
1298     UpdateMenuPaintProperty(menuNode, menuParam, type);
1299 }
1300 
UpdateMenuPaintProperty(const RefPtr<FrameNode> & menuNode,const MenuParam & menuParam,const MenuType & type)1301 void MenuView::UpdateMenuPaintProperty(
1302     const RefPtr<FrameNode>& menuNode, const MenuParam& menuParam, const MenuType& type)
1303 {
1304     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1305         if (!(type == MenuType::CONTEXT_MENU || type == MenuType::MENU)) {
1306             return;
1307         }
1308     } else {
1309         if (!(type == MenuType::CONTEXT_MENU)) {
1310             return;
1311         }
1312     }
1313 
1314     auto paintProperty = menuNode->GetPaintProperty<MenuPaintProperty>();
1315     CHECK_NULL_VOID(paintProperty);
1316     paintProperty->UpdateEnableArrow(menuParam.enableArrow.value_or(false));
1317     paintProperty->UpdateArrowOffset(menuParam.arrowOffset.value_or(Dimension(0)));
1318 }
1319 
Create(const std::vector<SelectParam> & params,int32_t targetId,const std::string & targetTag,bool autoWrapFlag)1320 RefPtr<FrameNode> MenuView::Create(
1321     const std::vector<SelectParam>& params, int32_t targetId, const std::string& targetTag, bool autoWrapFlag)
1322 {
1323     auto [wrapperNode, menuNode] = CreateMenu(targetId, targetTag);
1324     auto column = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
1325         AceType::MakeRefPtr<LinearLayoutPattern>(true));
1326     CHECK_NULL_RETURN(wrapperNode && menuNode, nullptr);
1327     SetMenuFocusRule(menuNode);
1328     auto menuPattern = menuNode->GetPattern<MenuPattern>();
1329     CHECK_NULL_RETURN(menuPattern, nullptr);
1330     auto menuProperty = menuNode->GetLayoutProperty<MenuLayoutProperty>();
1331     CHECK_NULL_RETURN(menuProperty, nullptr);
1332     menuProperty->UpdateShowInSubWindow(false);
1333     for (size_t i = 0; i < params.size(); ++i) {
1334         auto optionNode = CreateSelectOption(params[i], i, autoWrapFlag);
1335         auto optionPattern = optionNode->GetPattern<MenuItemPattern>();
1336         CHECK_NULL_RETURN(optionPattern, nullptr);
1337         optionPattern->SetIsSelectOption(true);
1338         menuPattern->AddOptionNode(optionNode);
1339         auto menuWeak = AceType::WeakClaim(AceType::RawPtr(menuNode));
1340         OptionKeepMenu(optionNode, menuWeak);
1341         // first node never paints divider
1342         if (i == 0) {
1343             auto props = optionNode->GetPaintProperty<MenuItemPaintProperty>();
1344             props->UpdateNeedDivider(false);
1345             auto focusHub = optionNode->GetOrCreateFocusHub();
1346             CHECK_NULL_RETURN(focusHub, nullptr);
1347             focusHub->SetIsDefaultFocus(true);
1348         }
1349         optionNode->MarkModifyDone();
1350         optionNode->MountToParent(column);
1351     }
1352     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
1353         UpdateMenuBorderEffect(menuNode);
1354     }
1355     auto scroll = CreateMenuScroll(column);
1356     CHECK_NULL_RETURN(scroll, nullptr);
1357     auto scrollPattern = scroll->GetPattern<ScrollPattern>();
1358     CHECK_NULL_RETURN(scrollPattern, nullptr);
1359     scrollPattern->SetIsSelectScroll(true);
1360     scroll->MountToParent(menuNode);
1361     scroll->MarkModifyDone();
1362     menuPattern->SetIsSelectMenu(true);
1363     menuNode->MarkModifyDone();
1364     return wrapperNode;
1365 }
1366 
CreateEffectOption(Dimension radius,double saturation,double brightness,Color color)1367 EffectOption CreateEffectOption(Dimension radius, double saturation, double brightness, Color color)
1368 {
1369     EffectOption option;
1370     option.radius = radius;
1371     option.saturation = saturation;
1372     option.brightness = brightness;
1373     option.color = color;
1374     return option;
1375 }
1376 
UpdateMenuBackgroundEffect(const RefPtr<FrameNode> & menuNode)1377 void MenuView::UpdateMenuBackgroundEffect(const RefPtr<FrameNode>& menuNode)
1378 {
1379     CHECK_NULL_VOID(menuNode);
1380     auto pipeLineContext = menuNode->GetContextWithCheck();
1381     CHECK_NULL_VOID(pipeLineContext);
1382     auto menuTheme = pipeLineContext->GetTheme<NG::MenuTheme>();
1383     CHECK_NULL_VOID(menuTheme);
1384     if (menuTheme->GetBgBlurEffectEnable()) {
1385         auto renderContext = menuNode->GetRenderContext();
1386         CHECK_NULL_VOID(renderContext);
1387         auto saturation = menuTheme->GetBgEffectSaturation();
1388         auto brightness = menuTheme->GetBgEffectBrightness();
1389         auto radius = menuTheme->GetBgEffectRadius();
1390         auto color = menuTheme->GetBgEffectColor();
1391         EffectOption option = CreateEffectOption(radius, saturation, brightness, color);
1392         renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
1393         renderContext->UpdateBackgroundEffect(option);
1394     }
1395 }
1396 
UpdateMenuBorderEffect(const RefPtr<FrameNode> & menuNode)1397 void MenuView::UpdateMenuBorderEffect(const RefPtr<FrameNode>& menuNode)
1398 {
1399     CHECK_NULL_VOID(menuNode);
1400     auto pipeLineContext = menuNode->GetContextWithCheck();
1401     CHECK_NULL_VOID(pipeLineContext);
1402     auto menuTheme = pipeLineContext->GetTheme<NG::MenuTheme>();
1403     CHECK_NULL_VOID(menuTheme);
1404     if (menuTheme->GetDoubleBorderEnable()) {
1405         auto renderContext = menuNode->GetRenderContext();
1406         CHECK_NULL_VOID(renderContext);
1407         BorderStyleProperty styleProp;
1408         styleProp.SetBorderStyle(BorderStyle::SOLID);
1409         BorderColorProperty outerColorProp;
1410         outerColorProp.SetColor(menuTheme->GetOuterBorderColor());
1411         auto theme = pipeLineContext->GetTheme<SelectTheme>();
1412         CHECK_NULL_VOID(theme);
1413         BorderRadiusProperty outerRadiusProp;
1414         outerRadiusProp.SetRadius(Dimension(Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) ?
1415             theme->GetMenuDefaultRadius() : theme->GetMenuBorderRadius()));
1416         BorderWidthProperty outerWidthProp;
1417         outerWidthProp.SetBorderWidth(Dimension(menuTheme->GetOuterBorderWidth()));
1418         renderContext->SetOuterBorderStyle(styleProp);
1419         renderContext->SetOuterBorderColor(outerColorProp);
1420         renderContext->UpdateOuterBorderRadius(outerRadiusProp);
1421         renderContext->SetOuterBorderWidth(outerWidthProp);
1422         BorderColorProperty innerColorProp;
1423         innerColorProp.SetColor(menuTheme->GetInnerBorderColor());
1424         BorderRadiusProperty innerRadiusProp;
1425         innerRadiusProp.SetRadius(Dimension(Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) ?
1426             theme->GetMenuDefaultRadius() : theme->GetMenuBorderRadius()));
1427         BorderWidthProperty innerWidthProp;
1428         innerWidthProp.SetBorderWidth(Dimension(menuTheme->GetInnerBorderWidth()));
1429         renderContext->SetBorderStyle(styleProp);
1430         renderContext->SetBorderColor(innerColorProp);
1431         renderContext->UpdateBorderRadius(innerRadiusProp);
1432         renderContext->SetBorderWidth(innerWidthProp);
1433     }
1434 }
1435 
UpdateMenuBackgroundStyle(const RefPtr<FrameNode> & menuNode,const MenuParam & menuParam)1436 void MenuView::UpdateMenuBackgroundStyle(const RefPtr<FrameNode>& menuNode, const MenuParam& menuParam)
1437 {
1438     auto menuNodeRenderContext = menuNode->GetRenderContext();
1439     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) &&
1440         menuNodeRenderContext->IsUniRenderEnabled()) {
1441         auto pipeLineContext = menuNode->GetContextWithCheck();
1442         CHECK_NULL_VOID(pipeLineContext);
1443         auto selectTheme = pipeLineContext->GetTheme<SelectTheme>();
1444         CHECK_NULL_VOID(selectTheme);
1445         BlurStyleOption styleOption;
1446         if (menuParam.blurStyleOption.has_value()) {
1447             styleOption = menuParam.blurStyleOption.value();
1448             if (styleOption.policy == BlurStyleActivePolicy::FOLLOWS_WINDOW_ACTIVE_STATE) {
1449                 pipeLineContext->AddWindowFocusChangedCallback(menuNode->GetId());
1450             } else {
1451                 pipeLineContext->RemoveWindowFocusChangedCallback(menuNode->GetId());
1452             }
1453         }
1454         Color color;
1455         if (selectTheme->GetMenuBlendBgColor()) {
1456             styleOption.blurStyle = static_cast<BlurStyle>(
1457                 menuParam.backgroundBlurStyle.value_or(selectTheme->GetMenuNormalBackgroundBlurStyle()));
1458             color = menuParam.backgroundColor.value_or(selectTheme->GetBackgroundColor());
1459         } else {
1460             auto menuTheme = pipeLineContext->GetTheme<NG::MenuTheme>();
1461             CHECK_NULL_VOID(menuTheme);
1462             styleOption.blurStyle = static_cast<BlurStyle>(
1463                 menuParam.backgroundBlurStyle.value_or(menuTheme->GetMenuBackgroundBlurStyle()));
1464             color = menuParam.backgroundColor.value_or(Color::TRANSPARENT);
1465         }
1466         if (menuParam.blurStyleOption.has_value() && menuNodeRenderContext->GetBackgroundEffect().has_value()) {
1467             menuNodeRenderContext->UpdateBackgroundEffect(std::nullopt);
1468         }
1469         menuNodeRenderContext->UpdateBackBlurStyle(styleOption);
1470         menuNodeRenderContext->UpdateBackgroundColor(color);
1471         if (menuParam.effectOption.has_value()) {
1472             if (menuParam.effectOption->policy == BlurStyleActivePolicy::FOLLOWS_WINDOW_ACTIVE_STATE) {
1473                 pipeLineContext->AddWindowFocusChangedCallback(menuNode->GetId());
1474             } else {
1475                 pipeLineContext->RemoveWindowFocusChangedCallback(menuNode->GetId());
1476             }
1477             if (menuNodeRenderContext->GetBackBlurStyle().has_value()) {
1478                 menuNodeRenderContext->UpdateBackBlurStyle(std::nullopt);
1479             }
1480             menuNodeRenderContext->UpdateBackgroundEffect(menuParam.effectOption.value());
1481         }
1482         UpdateMenuBackgroundStyleOption(menuNode, menuParam);
1483     } else {
1484         UpdateMenuBackgroundStyleSub(menuNode, menuParam);
1485     }
1486 }
1487 
UpdateMenuBackgroundStyleSub(const RefPtr<FrameNode> & menuNode,const MenuParam & menuParam)1488 void MenuView::UpdateMenuBackgroundStyleSub(const RefPtr<FrameNode>& menuNode, const MenuParam& menuParam)
1489 {
1490     auto menuNodeRenderContext = menuNode->GetRenderContext();
1491     auto pipeLineContext = menuNode->GetContextWithCheck();
1492     CHECK_NULL_VOID(pipeLineContext);
1493     auto selectTheme = pipeLineContext->GetTheme<SelectTheme>();
1494     CHECK_NULL_VOID(selectTheme);
1495     menuNodeRenderContext->UpdateBackgroundColor(
1496         menuParam.backgroundColor.value_or(selectTheme->GetBackgroundColor()));
1497     UpdateMenuBackgroundStyleOption(menuNode, menuParam);
1498 }
1499 
NeedAgingUpdateNode(const RefPtr<FrameNode> & optionNode)1500 void MenuView::NeedAgingUpdateNode(const RefPtr<FrameNode>& optionNode)
1501 {
1502     CHECK_NULL_VOID(optionNode);
1503     auto pipeline = optionNode->GetContextWithCheck();
1504     CHECK_NULL_VOID(pipeline);
1505     auto menuTheme = pipeline->GetTheme<NG::MenuTheme>();
1506     CHECK_NULL_VOID(menuTheme);
1507     auto fontScale = pipeline->GetFontScale();
1508     if (NearEqual(fontScale, menuTheme->GetBigFontSizeScale()) ||
1509         NearEqual(fontScale, menuTheme->GetLargeFontSizeScale()) ||
1510         NearEqual(fontScale, menuTheme->GetMaxFontSizeScale())) {
1511         auto optionPattern = optionNode->GetPattern<MenuItemPattern>();
1512         CHECK_NULL_VOID(optionPattern);
1513         auto textNode = AceType::DynamicCast<FrameNode>(optionPattern->GetTextNode());
1514         CHECK_NULL_VOID(textNode);
1515         auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
1516         CHECK_NULL_VOID(textLayoutProperty);
1517         textLayoutProperty->UpdateMaxLines(menuTheme->GetTextMaxLines());
1518     }
1519 }
1520 
CreateOption(bool optionsHasIcon,std::vector<OptionParam> & params,int32_t index,const RefPtr<FrameNode> & row,const RefPtr<FrameNode> & option)1521 void MenuView::CreateOption(bool optionsHasIcon, std::vector<OptionParam>& params, int32_t index,
1522     const RefPtr<FrameNode>& row, const RefPtr<FrameNode>& option)
1523 {
1524     auto pattern = option->GetPattern<MenuItemPattern>();
1525     CHECK_NULL_VOID(pattern);
1526     if (optionsHasIcon) {
1527         auto iconNode = CreateSymbol(params[index].symbol, row, nullptr, params[index].symbolUserDefinedIdealFontSize);
1528         pattern->SetIconNode(iconNode);
1529     }
1530     auto textNode = CreateText(params[index].value, row);
1531     row->MountToParent(option);
1532     row->MarkModifyDone();
1533     pattern->SetTextNode(textNode);
1534     pattern->SetBlockClick(params[index].disableSystemClick);
1535 
1536     auto eventHub = option->GetEventHub<MenuItemEventHub>();
1537     CHECK_NULL_VOID(eventHub);
1538     eventHub->SetMenuOnClick(params[index].action);
1539 }
1540 
CreateOption(bool optionsHasIcon,const std::string & value,const std::string & icon,const RefPtr<FrameNode> & row,const RefPtr<FrameNode> & option,const std::function<void ()> & onClickFunc)1541 void MenuView::CreateOption(bool optionsHasIcon, const std::string& value, const std::string& icon,
1542     const RefPtr<FrameNode>& row, const RefPtr<FrameNode>& option, const std::function<void()>& onClickFunc)
1543 {
1544     auto pattern = option->GetPattern<MenuItemPattern>();
1545     CHECK_NULL_VOID(pattern);
1546     if (optionsHasIcon) {
1547         auto iconNode = CreateIcon(icon, row);
1548         pattern->SetIconNode(iconNode);
1549         pattern->SetIcon(icon);
1550     }
1551     auto textNode = CreateText(value, row);
1552     row->MountToParent(option);
1553     row->MarkModifyDone();
1554     pattern->SetTextNode(textNode);
1555 
1556     auto eventHub = option->GetEventHub<MenuItemEventHub>();
1557     CHECK_NULL_VOID(eventHub);
1558     eventHub->SetMenuOnClick(onClickFunc);
1559 }
1560 
CreateMenuOption(bool optionsHasIcon,std::vector<OptionParam> & params,int32_t index)1561 RefPtr<FrameNode> MenuView::CreateMenuOption(bool optionsHasIcon, std::vector<OptionParam>& params, int32_t index)
1562 {
1563     auto option = Create(index);
1564     CHECK_NULL_RETURN(option, nullptr);
1565     auto row = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
1566         AceType::MakeRefPtr<MenuItemRowPattern>());
1567 
1568 #ifdef OHOS_PLATFORM
1569     constexpr char BUTTON_PASTE[] = "textoverlay.paste";
1570     if (params[index].value == Localization::GetInstance()->GetEntryLetters(BUTTON_PASTE)) {
1571         CreatePasteButton(optionsHasIcon, option, row, params[index].action);
1572     } else {
1573         CreateOption(optionsHasIcon, params, index, row, option);
1574     }
1575 #else
1576     CreateOption(optionsHasIcon, params, index, row, option);
1577 #endif
1578     return option;
1579 }
1580 
CreateMenuOption(bool optionsHasIcon,const OptionValueInfo & value,const std::function<void ()> & onClickFunc,int32_t index,const std::string & icon)1581 RefPtr<FrameNode> MenuView::CreateMenuOption(bool optionsHasIcon, const OptionValueInfo& value,
1582     const std::function<void()>& onClickFunc, int32_t index, const std::string& icon)
1583 {
1584     auto option = Create(index);
1585     CHECK_NULL_RETURN(option, nullptr);
1586     auto row = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
1587         AceType::MakeRefPtr<MenuItemRowPattern>());
1588 
1589 #ifdef OHOS_PLATFORM
1590     constexpr char BUTTON_PASTE[] = "textoverlay.paste";
1591     if (value.value == Localization::GetInstance()->GetEntryLetters(BUTTON_PASTE)) {
1592         CreatePasteButton(optionsHasIcon, option, row, onClickFunc, icon);
1593     } else {
1594         CreateOption(optionsHasIcon, value.value, icon, row, option, onClickFunc);
1595     }
1596 #else
1597     CreateOption(optionsHasIcon, value.value, icon, row, option, onClickFunc);
1598 #endif
1599     return option;
1600 }
1601 
MountOptionToColumn(std::vector<OptionParam> & params,const RefPtr<FrameNode> & menuNode,const MenuParam & menuParam,RefPtr<FrameNode> column)1602 void MenuView::MountOptionToColumn(std::vector<OptionParam>& params, const RefPtr<FrameNode>& menuNode,
1603     const MenuParam& menuParam, RefPtr<FrameNode> column)
1604 {
1605     bool optionsHasIcon = GetHasIcon(params);
1606     bool optionsHasSymbol = GetHasSymbol(params);
1607     RefPtr<FrameNode> optionNode = nullptr;
1608     // append options to menu
1609     for (size_t i = 0; i < params.size(); ++i) {
1610         if (params[i].symbol != nullptr) {
1611             optionNode = CreateMenuOption(optionsHasSymbol, params, i);
1612         } else {
1613             optionNode = CreateMenuOption(
1614                 optionsHasIcon, { params[i].value, params[i].isPasteOption }, params[i].action, i, params[i].icon);
1615             if (optionNode) {
1616                 auto optionPattern = optionNode->GetPattern<MenuItemPattern>();
1617                 optionPattern->SetBlockClick(params[i].disableSystemClick);
1618             }
1619         }
1620         if (!optionNode) {
1621             continue;
1622         }
1623         NeedAgingUpdateNode(optionNode);
1624         auto menuPattern = menuNode->GetPattern<MenuPattern>();
1625         CHECK_NULL_VOID(menuPattern);
1626         menuPattern->AddOptionNode(optionNode);
1627         auto menuWeak = AceType::WeakClaim(AceType::RawPtr(menuNode));
1628         auto eventHub = optionNode->GetEventHub<EventHub>();
1629         CHECK_NULL_VOID(eventHub);
1630         eventHub->SetEnabled(params[i].enabled);
1631         auto focusHub = optionNode->GetFocusHub();
1632         CHECK_NULL_VOID(focusHub);
1633         focusHub->SetEnabled(params[i].enabled);
1634 
1635         OptionKeepMenu(optionNode, menuWeak);
1636         // first node never paints divider
1637         auto props = optionNode->GetPaintProperty<MenuItemPaintProperty>();
1638         if (i == 0 && menuParam.title.empty()) {
1639             props->UpdateNeedDivider(false);
1640         }
1641         if (optionsHasIcon) {
1642             props->UpdateHasIcon(true);
1643         }
1644         optionNode->MountToParent(column);
1645         optionNode->MarkModifyDone();
1646     }
1647 }
1648 
CreatePasteButton(bool optionsHasIcon,const RefPtr<FrameNode> & option,const RefPtr<FrameNode> & row,const std::function<void ()> & onClickFunc,const std::string & icon)1649 void MenuView::CreatePasteButton(bool optionsHasIcon, const RefPtr<FrameNode>& option, const RefPtr<FrameNode>& row,
1650     const std::function<void()>& onClickFunc, const std::string& icon)
1651 {
1652     auto pipeline = PipelineBase::GetCurrentContextSafelyWithCheck();
1653     CHECK_NULL_VOID(pipeline);
1654     auto theme = pipeline->GetTheme<SelectTheme>();
1655     CHECK_NULL_VOID(theme);
1656     RefPtr<FrameNode> pasteNode;
1657     pasteNode = PasteButtonModelNG::GetInstance()->CreateNode(static_cast<int32_t>(PasteButtonPasteDescription::PASTE),
1658         optionsHasIcon ? static_cast<int32_t>(PasteButtonIconStyle::ICON_LINE) :
1659         static_cast<int32_t>(PasteButtonIconStyle::ICON_NULL),
1660         static_cast<int32_t>(ButtonType::NORMAL), true);
1661     CHECK_NULL_VOID(pasteNode);
1662     auto pattern = option->GetPattern<MenuItemPattern>();
1663     CHECK_NULL_VOID(pattern);
1664     auto pasteLayoutProperty = pasteNode->GetLayoutProperty<SecurityComponentLayoutProperty>();
1665     CHECK_NULL_VOID(pasteLayoutProperty);
1666     auto pastePaintProperty = pasteNode->GetPaintProperty<SecurityComponentPaintProperty>();
1667     CHECK_NULL_VOID(pastePaintProperty);
1668 
1669     pasteLayoutProperty->UpdateFontSize(theme->GetMenuFontSize());
1670     pasteLayoutProperty->UpdateFontWeight(FontWeight::REGULAR);
1671     pastePaintProperty->UpdateFontColor(theme->GetMenuFontColor());
1672     pastePaintProperty->UpdateBackgroundColor(Color::TRANSPARENT);
1673     pasteLayoutProperty->UpdateBackgroundBorderRadius(BorderRadiusProperty(theme->GetInnerBorderRadius()));
1674     pasteLayoutProperty->UpdateIconSize(theme->GetIconSideLength());
1675     pastePaintProperty->UpdateIconColor(theme->GetMenuIconColor());
1676     pasteLayoutProperty->UpdateStateEffect(false);
1677     pasteLayoutProperty->UpdateHoverEffect(HoverEffectType::NONE);
1678     if (optionsHasIcon) {
1679         pasteLayoutProperty->UpdateTextIconSpace(theme->GetIconContentPadding());
1680     }
1681     pasteNode->MountToParent(row);
1682     pasteNode->MarkModifyDone();
1683     row->MountToParent(option);
1684     row->MarkModifyDone();
1685     auto eventHub = option->GetEventHub<MenuItemEventHub>();
1686     CHECK_NULL_VOID(eventHub);
1687     pasteNode->GetOrCreateGestureEventHub()->SetUserOnClick([onClickFunc](GestureEvent& info) {
1688         if (!PasteButtonModelNG::GetInstance()->IsClickResultSuccess(info)) {
1689             return;
1690         }
1691         if (onClickFunc) {
1692             onClickFunc();
1693         }
1694     });
1695     pattern->SetPasteButton(pasteNode);
1696 }
1697 
CreateSymbol(const std::function<void (WeakPtr<NG::FrameNode>)> & symbolApply,const RefPtr<FrameNode> & parent,const RefPtr<FrameNode> & child,const std::optional<Dimension> & symbolUserDefinedIdealFontSize)1698 RefPtr<FrameNode> MenuView::CreateSymbol(const std::function<void(WeakPtr<NG::FrameNode>)>& symbolApply,
1699     const RefPtr<FrameNode>& parent, const RefPtr<FrameNode>& child,
1700     const std::optional<Dimension>& symbolUserDefinedIdealFontSize)
1701 {
1702     auto iconNode = FrameNode::GetOrCreateFrameNode(V2::SYMBOL_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
1703         []() { return AceType::MakeRefPtr<TextPattern>(); });
1704     CHECK_NULL_RETURN(iconNode, nullptr);
1705     auto props = iconNode->GetLayoutProperty<TextLayoutProperty>();
1706     CHECK_NULL_RETURN(props, nullptr);
1707     auto pipeline = PipelineBase::GetCurrentContext();
1708     CHECK_NULL_RETURN(pipeline, nullptr);
1709     auto theme = pipeline->GetTheme<SelectTheme>();
1710     CHECK_NULL_RETURN(theme, nullptr);
1711     props->UpdateFontSize(theme->GetEndIconWidth());
1712     props->UpdateSymbolColorList({theme->GetMenuIconColor()});
1713     props->UpdateAlignment(Alignment::CENTER_LEFT);
1714     MarginProperty margin;
1715     margin.right = CalcLength(theme->GetIconContentPadding());
1716     props->UpdateMargin(margin);
1717     if (symbolApply != nullptr) {
1718         symbolApply(AccessibilityManager::WeakClaim(AccessibilityManager::RawPtr(iconNode)));
1719     }
1720     if (symbolUserDefinedIdealFontSize.has_value()) {
1721         props->UpdateFontSize(symbolUserDefinedIdealFontSize.value());
1722     }
1723     if (child) {
1724         parent->ReplaceChild(child, iconNode);
1725     } else {
1726         iconNode->MountToParent(parent, 0);
1727     }
1728     iconNode->MarkModifyDone();
1729     return iconNode;
1730 }
1731 
CreateText(const std::string & value,const RefPtr<FrameNode> & parent,bool autoWrapFlag)1732 RefPtr<FrameNode> MenuView::CreateText(const std::string& value, const RefPtr<FrameNode>& parent, bool autoWrapFlag)
1733 {
1734     // create child text node
1735     auto textId = ElementRegister::GetInstance()->MakeUniqueId();
1736     auto textNode = FrameNode::CreateFrameNode(V2::TEXT_ETS_TAG, textId, AceType::MakeRefPtr<TextPattern>());
1737     CHECK_NULL_RETURN(textNode, nullptr);
1738 
1739     auto textProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
1740     CHECK_NULL_RETURN(textProperty, nullptr);
1741 
1742     auto pipeline = PipelineBase::GetCurrentContext();
1743     CHECK_NULL_RETURN(pipeline, nullptr);
1744     auto theme = pipeline->GetTheme<SelectTheme>();
1745     CHECK_NULL_RETURN(theme, nullptr);
1746 
1747     TAG_LOGI(AceLogTag::ACE_MENU, "MenuView::CreateText autoWrapFlag: %{public}d", autoWrapFlag);
1748     if (!autoWrapFlag) {
1749         textProperty->UpdateMaxLines(1);
1750         textProperty->UpdateTextOverflow(TextOverflow::ELLIPSIS);
1751     } else {
1752         textProperty->UpdateMaxLines(std::numeric_limits<int32_t>::max());
1753     }
1754     textProperty->UpdateFontSize(theme->GetMenuFontSize());
1755     textProperty->UpdateFontWeight(FontWeight::REGULAR);
1756     textProperty->UpdateTextColor(theme->GetMenuFontColor());
1757     // set default foregroundColor
1758     auto textRenderContext = textNode->GetRenderContext();
1759     textRenderContext->UpdateForegroundColor(theme->GetMenuFontColor());
1760     textProperty->UpdateContent(value);
1761     auto padding = theme->GetOptionContentNormalLeftRightPadding();
1762     PaddingProperty textPadding;
1763     textPadding.left = CalcLength(padding);
1764     textPadding.right = CalcLength(padding);
1765     textProperty->UpdatePadding(textPadding);
1766     auto layoutDirection = textProperty->GetNonAutoLayoutDirection();
1767     auto IsRightToLeft = layoutDirection == TextDirection::RTL;
1768     auto textAlign = static_cast<TextAlign>(theme->GetOptionContentNormalAlign());
1769     auto convertValue = ConvertTxtTextAlign(IsRightToLeft, textAlign);
1770     textProperty->UpdateAlignment(convertValue);
1771     textNode->MountToParent(parent);
1772     textNode->MarkModifyDone();
1773 
1774     return textNode;
1775 }
1776 
CreateIcon(const std::string & icon,const RefPtr<FrameNode> & parent,const RefPtr<FrameNode> & child)1777 RefPtr<FrameNode> MenuView::CreateIcon(const std::string& icon, const RefPtr<FrameNode>& parent,
1778     const RefPtr<FrameNode>& child)
1779 {
1780     auto iconNode = FrameNode::CreateFrameNode(
1781         V2::IMAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ImagePattern>());
1782     CHECK_NULL_RETURN(iconNode, nullptr);
1783     auto props = iconNode->GetLayoutProperty<ImageLayoutProperty>();
1784     auto pipeline = PipelineBase::GetCurrentContext();
1785     CHECK_NULL_RETURN(pipeline, nullptr);
1786     auto theme = pipeline->GetTheme<SelectTheme>();
1787     CHECK_NULL_RETURN(theme, nullptr);
1788     if (!icon.empty()) {
1789         ImageSourceInfo info(icon);
1790         props->UpdateImageSourceInfo(info);
1791     }
1792     props->UpdateUserDefinedIdealSize(
1793         CalcSize(CalcLength(theme->GetIconSideLength()), CalcLength(theme->GetIconSideLength())));
1794     props->UpdateAlignment(Alignment::CENTER_LEFT);
1795 
1796     if (child) {
1797         parent->ReplaceChild(child, iconNode);
1798     } else {
1799         iconNode->MountToParent(parent, 0);
1800     }
1801     iconNode->MarkModifyDone();
1802     return iconNode;
1803 }
1804 
CreateSelectOption(const SelectParam & param,int32_t index,bool autoWrapFlag)1805 RefPtr<FrameNode> MenuView::CreateSelectOption(const SelectParam& param, int32_t index, bool autoWrapFlag)
1806 {
1807     auto option = Create(index);
1808     auto row = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
1809         AceType::MakeRefPtr<MenuItemRowPattern>());
1810     row->MountToParent(option);
1811 
1812     auto pattern = option->GetPattern<MenuItemPattern>();
1813     CHECK_NULL_RETURN(pattern, option);
1814     // create icon node
1815     RefPtr<FrameNode> iconNode;
1816     if (param.symbolIcon != nullptr) {
1817         iconNode = CreateSymbol(param.symbolIcon, row);
1818     } else if (!param.icon.empty()) {
1819         iconNode = CreateIcon(param.icon, row);
1820         pattern->SetIcon(param.icon);
1821     }
1822     pattern->SetIconNode(iconNode);
1823 
1824     auto text = CreateText(param.text, row, autoWrapFlag);
1825     pattern->SetTextNode(text);
1826     return option;
1827 }
1828 
Create(int32_t index)1829 RefPtr<FrameNode> MenuView::Create(int32_t index)
1830 {
1831     auto Id = ElementRegister::GetInstance()->MakeUniqueId();
1832     ACE_LAYOUT_SCOPED_TRACE("Create[%s][self:%d]", V2::OPTION_ETS_TAG, Id);
1833     auto node = FrameNode::CreateFrameNode(V2::OPTION_ETS_TAG, Id, AceType::MakeRefPtr<MenuItemPattern>(true, index));
1834     CHECK_NULL_RETURN(node, nullptr);
1835 
1836     // set border radius
1837     auto renderContext = node->GetRenderContext();
1838     CHECK_NULL_RETURN(renderContext, nullptr);
1839     auto pipeline = PipelineBase::GetCurrentContext();
1840     CHECK_NULL_RETURN(pipeline, nullptr);
1841     auto theme = pipeline->GetTheme<SelectTheme>();
1842     CHECK_NULL_RETURN(theme, nullptr);
1843     BorderRadiusProperty border;
1844     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1845         border.SetRadius(theme->GetMenuDefaultInnerRadius());
1846     } else {
1847         border.SetRadius(theme->GetInnerBorderRadius());
1848     }
1849     renderContext->UpdateBorderRadius(border);
1850 
1851     auto props = node->GetPaintProperty<MenuItemPaintProperty>();
1852     CHECK_NULL_RETURN(props, nullptr);
1853     props->UpdateHover(false);
1854     props->UpdatePress(false);
1855 
1856     auto layoutProp = node->GetLayoutProperty();
1857     CHECK_NULL_RETURN(layoutProp, nullptr);
1858     MarginProperty margin;
1859     auto verticalMargin = CalcLength(theme->GetOptionNormalTopBottomMargin());
1860     auto leftRightMargin = CalcLength(theme->GetOptionFocusedLeftRightMargin());
1861     margin.SetEdges(leftRightMargin, leftRightMargin, verticalMargin, verticalMargin);
1862     layoutProp->UpdateMargin(margin);
1863     return node;
1864 }
1865 } // namespace OHOS::Ace::NG
1866