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