1 /*
2 * Copyright (c) 2022 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/select_overlay/select_overlay_node.h"
17
18 #include <cstdint>
19 #include <functional>
20 #include <memory>
21 #include <optional>
22 #include <securec.h>
23
24 #include "base/geometry/dimension.h"
25 #include "base/geometry/ng/offset_t.h"
26 #include "base/i18n/localization.h"
27 #include "base/utils/utils.h"
28 #include "core/animation/curves.h"
29 #include "core/components/common/layout/constants.h"
30 #include "core/components/common/properties/color.h"
31 #include "core/components/common/properties/placement.h"
32 #include "core/components/common/properties/shadow_config.h"
33 #include "core/components/common/properties/text_style.h"
34 #include "core/components/text_overlay/text_overlay_theme.h"
35 #include "core/components/theme/shadow_theme.h"
36 #include "core/components_ng/base/frame_node.h"
37 #include "core/components_ng/base/view_stack_processor.h"
38 #include "core/components_ng/event/event_hub.h"
39 #include "core/components_ng/pattern/button/button_pattern.h"
40 #include "core/components_ng/pattern/image/image_pattern.h"
41 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
42 #include "core/components_ng/pattern/menu/menu_layout_property.h"
43 #include "core/components_ng/pattern/menu/menu_pattern.h"
44 #include "core/components_ng/pattern/menu/menu_view.h"
45 #include "core/components_ng/pattern/relative_container/relative_container_pattern.h"
46 #include "core/components_ng/pattern/security_component/paste_button/paste_button_common.h"
47 #include "core/components_ng/pattern/security_component/paste_button/paste_button_model_ng.h"
48 #include "core/components_ng/pattern/security_component/security_component_pattern.h"
49 #include "core/components_ng/pattern/select_content_overlay/select_content_overlay_pattern.h"
50 #include "core/components_ng/pattern/select_overlay/expanded_menu_plugin_loader.h"
51 #include "core/components_ng/pattern/select_overlay/select_overlay_event_hub.h"
52 #include "core/components_ng/pattern/select_overlay/select_overlay_property.h"
53 #include "core/components_ng/pattern/symbol/symbol_model_ng.h"
54 #include "core/components_ng/pattern/text/text_pattern.h"
55 #include "core/components_ng/property/calc_length.h"
56 #include "frameworks/base/utils/measure_util.h"
57 #include "frameworks/core/components_ng/pattern/menu/menu_model_ng.h"
58
59 #ifdef ENABLE_ROSEN_BACKEND
60 #include "core/components/custom_paint/rosen_render_custom_paint.h"
61 #endif
62
63 namespace OHOS::Ace::NG {
64 namespace {
65 constexpr int32_t OPTION_INDEX_CUT = 0;
66 constexpr int32_t OPTION_INDEX_COPY = 1;
67 constexpr int32_t OPTION_INDEX_PASTE = 2;
68 constexpr int32_t OPTION_INDEX_COPY_ALL = 3;
69 // Advanced options, consider to support disableMenuItems and disableSystemServiceMenuItems
70 constexpr int32_t OPTION_INDEX_TRANSLATE = 4;
71 constexpr int32_t OPTION_INDEX_SEARCH = 5;
72 constexpr int32_t OPTION_INDEX_SHARE = 6;
73 constexpr int32_t OPTION_INDEX_CAMERA_INPUT = 7;
74 constexpr int32_t OPTION_INDEX_AI_WRITE = 8;
75 constexpr int32_t OPTION_INDEX_AI_MENU = 9;
76 constexpr int32_t OPTION_INDEX_ASK_CELIA = 10;
77 constexpr int32_t ANIMATION_DURATION1 = 350;
78 constexpr int32_t ANIMATION_DURATION2 = 150;
79 constexpr int32_t SYMBOL_ANIMATION_DELAY = 50;
80 #ifdef OHOS_PLATFORM
81 constexpr int32_t PASTEBUTTON_ICON_CONTENT_PADDING_COUNT = 2;
82 #endif
83
84 constexpr Dimension MORE_MENU_TRANSLATE = -7.5_vp;
85 constexpr Dimension MAX_DIAMETER = 3.5_vp;
86 constexpr Dimension MIN_DIAMETER = 1.5_vp;
87 constexpr Dimension MIN_ARROWHEAD_DIAMETER = 2.0_vp;
88 constexpr Dimension ANIMATION_TEXT_OFFSET = 12.0_vp;
89 constexpr Dimension OVERLAY_MAX_WIDTH = 280.0_vp;
90 constexpr Dimension EXTENSION_MENU_DEFAULT_WIDTH = 224.0_vp;
91 constexpr Dimension MIN_HOTSPOT_WIDTH = 40.0_vp;
92 constexpr float AGING_MIN_SCALE = 1.75f;
93
94 std::unordered_map<TextDataDetectType, std::pair<std::string, std::function<bool()>>> AI_TYPE_ID_MAP = {
95 { TextDataDetectType::PHONE_NUMBER, std::make_pair(OH_DEFAULT_AI_MENU_PHONE, &TextSystemMenu::IsShowAIPhone) },
96 { TextDataDetectType::URL, std::make_pair(OH_DEFAULT_AI_MENU_URL, &TextSystemMenu::IsShowAIUrl) },
97 { TextDataDetectType::EMAIL, std::make_pair(OH_DEFAULT_AI_MENU_EMAIL, &TextSystemMenu::IsShowAIEmail) },
98 { TextDataDetectType::ADDRESS, std::make_pair(OH_DEFAULT_AI_MENU_ADDRESS, &TextSystemMenu::IsShowAIAddress) },
99 { TextDataDetectType::DATE_TIME, std::make_pair(OH_DEFAULT_AI_MENU_DATETIME, &TextSystemMenu::IsShowAIDatetime) },
100 };
101
102 std::unordered_map<std::string, TextDataDetectType> AI_ID_TYPE_MAP = {
103 { OH_DEFAULT_AI_MENU_PHONE, TextDataDetectType::PHONE_NUMBER },
104 { OH_DEFAULT_AI_MENU_URL, TextDataDetectType::URL },
105 { OH_DEFAULT_AI_MENU_EMAIL, TextDataDetectType::EMAIL },
106 { OH_DEFAULT_AI_MENU_ADDRESS, TextDataDetectType::ADDRESS },
107 { OH_DEFAULT_AI_MENU_DATETIME, TextDataDetectType::DATE_TIME },
108 };
109
IsAIMenuOption(const std::string & id)110 bool IsAIMenuOption(const std::string& id)
111 {
112 return id == OH_DEFAULT_AI_MENU_PHONE || id == OH_DEFAULT_AI_MENU_URL || id == OH_DEFAULT_AI_MENU_EMAIL ||
113 id == OH_DEFAULT_AI_MENU_ADDRESS || id == OH_DEFAULT_AI_MENU_DATETIME;
114 }
115
IsAskCeliaOption(const std::string & id)116 bool IsAskCeliaOption(const std::string& id)
117 {
118 return id == OH_DEFAULT_ASK_CELIA;
119 }
120
IsShowAIMenuOption(OHOS::Ace::TextDataDetectType type)121 bool IsShowAIMenuOption(OHOS::Ace::TextDataDetectType type)
122 {
123 auto isShowAIMenu = type != TextDataDetectType::INVALID;
124 auto findIter = AI_TYPE_ID_MAP.find(type);
125 isShowAIMenu = isShowAIMenu && (findIter != AI_TYPE_ID_MAP.end()) && findIter->second.second();
126 return isShowAIMenu;
127 }
128
129 const std::unordered_map<std::string, std::function<bool(const SelectMenuInfo&)>> isMenuItemEnabledFuncMap = {
__anond9a0f38e0202()130 { OH_DEFAULT_CUT, [](const SelectMenuInfo& info){ return info.showCut; } },
__anond9a0f38e0302()131 { OH_DEFAULT_COPY, [](const SelectMenuInfo& info){ return info.showCopy; } },
__anond9a0f38e0402()132 { OH_DEFAULT_SELECT_ALL, [](const SelectMenuInfo& info){ return info.showCopyAll; } },
__anond9a0f38e0502()133 { OH_DEFAULT_PASTE, [](const SelectMenuInfo& info){ return info.showPaste; } },
__anond9a0f38e0602()134 { OH_DEFAULT_TRANSLATE, [](const SelectMenuInfo& info){ return info.showTranslate; } },
__anond9a0f38e0702()135 { OH_DEFAULT_SEARCH, [](const SelectMenuInfo& info){ return info.showSearch; } },
__anond9a0f38e0802()136 { OH_DEFAULT_SHARE, [](const SelectMenuInfo& info){ return info.showShare; } },
__anond9a0f38e0902()137 { OH_DEFAULT_AI_WRITE, [](const SelectMenuInfo& info){ return info.showAIWrite; } }
138 };
139
140 const std::unordered_map<std::string, std::function<uint32_t(RefPtr<OHOS::Ace::TextOverlayTheme>)>> getSymbolIdMap = {
141 { OH_DEFAULT_CUT,
__anond9a0f38e0a02() 142 [](const RefPtr<OHOS::Ace::TextOverlayTheme>& textOverlayTheme) { return textOverlayTheme->GetCutSymbolId();}
143 },
144 { OH_DEFAULT_COPY,
__anond9a0f38e0b02() 145 [](const RefPtr<OHOS::Ace::TextOverlayTheme>& textOverlayTheme) { return textOverlayTheme->GetCopySymbolId();}
146 },
147 { OH_DEFAULT_SELECT_ALL, [](const RefPtr<OHOS::Ace::TextOverlayTheme>& textOverlayTheme)
__anond9a0f38e0c02() 148 { return textOverlayTheme->GetCopyAllSymbolId();}
149 },
150 { OH_DEFAULT_PASTE,
__anond9a0f38e0d02() 151 [](const RefPtr<OHOS::Ace::TextOverlayTheme>& textOverlayTheme) { return textOverlayTheme->GetPasteSymbolId();}
152 },
153 { OH_DEFAULT_CAMERA_INPUT, [](const RefPtr<OHOS::Ace::TextOverlayTheme>& textOverlayTheme)
__anond9a0f38e0e02() 154 { return textOverlayTheme->GetCameraInputSymbolId();}
155 },
156 { OH_DEFAULT_AI_WRITE, [](const RefPtr<OHOS::Ace::TextOverlayTheme>& textOverlayTheme)
__anond9a0f38e0f02() 157 { return textOverlayTheme->GetAIWriteSymbolId();}
158 },
159 { OH_DEFAULT_SEARCH, [](const RefPtr<OHOS::Ace::TextOverlayTheme>& textOverlayTheme)
__anond9a0f38e1002() 160 { return textOverlayTheme->GetSearchSymbolId();}
161 },
162 { OH_DEFAULT_TRANSLATE, [](const RefPtr<OHOS::Ace::TextOverlayTheme>& textOverlayTheme)
__anond9a0f38e1102() 163 { return textOverlayTheme->GetTranslateSymbolId();}
164 },
165 { OH_DEFAULT_SHARE, [](const RefPtr<OHOS::Ace::TextOverlayTheme>& textOverlayTheme)
__anond9a0f38e1202() 166 { return textOverlayTheme->GetShareSymbolId();}
167 },
168 { OH_DEFAULT_AI_MENU_PHONE, [](const RefPtr<OHOS::Ace::TextOverlayTheme>& textOverlayTheme)
__anond9a0f38e1302() 169 { return textOverlayTheme->GetAIMenuSymbolId();}
170 },
171 { OH_DEFAULT_AI_MENU_URL, [](const RefPtr<OHOS::Ace::TextOverlayTheme>& textOverlayTheme)
__anond9a0f38e1402() 172 { return textOverlayTheme->GetAIMenuSymbolId();}
173 },
174 { OH_DEFAULT_AI_MENU_EMAIL, [](const RefPtr<OHOS::Ace::TextOverlayTheme>& textOverlayTheme)
__anond9a0f38e1502() 175 { return textOverlayTheme->GetAIMenuSymbolId();}
176 },
177 { OH_DEFAULT_AI_MENU_ADDRESS, [](const RefPtr<OHOS::Ace::TextOverlayTheme>& textOverlayTheme)
__anond9a0f38e1602() 178 { return textOverlayTheme->GetAIMenuSymbolId();}
179 },
180 { OH_DEFAULT_AI_MENU_DATETIME, [](const RefPtr<OHOS::Ace::TextOverlayTheme>& textOverlayTheme)
__anond9a0f38e1702() 181 { return textOverlayTheme->GetAIMenuSymbolId();}
182 },
183 { OH_DEFAULT_ASK_CELIA, [](const RefPtr<OHOS::Ace::TextOverlayTheme>& textOverlayTheme)
__anond9a0f38e1802() 184 { return textOverlayTheme->GetAskCeliaSymbolId();}
185 }
186 };
187
188 enum class SelectOverlayMenuButtonType {
189 NORMAL,
190 AIBUTTON
191 };
192
193 struct ButtonBasicInfo {
194 std::string data;
195 SelectOverlayMenuButtonType buttonType = SelectOverlayMenuButtonType::NORMAL;
196 };
197
GetCallerScopedId(const std::shared_ptr<SelectOverlayInfo> & info)198 int32_t GetCallerScopedId(const std::shared_ptr<SelectOverlayInfo>& info)
199 {
200 CHECK_NULL_RETURN(info, 0);
201 auto caller = info->callerFrameNode.Upgrade();
202 CHECK_NULL_RETURN(caller, 0);
203 return caller->GetThemeScopeId();
204 }
205
SetResponseRegion(RefPtr<FrameNode> & node)206 void SetResponseRegion(RefPtr<FrameNode>& node)
207 {
208 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
209 CHECK_NULL_VOID(pipeline);
210 if (GreatOrEqual(pipeline->GetFontScale(), AGING_MIN_SCALE)) {
211 return;
212 }
213 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
214 CHECK_NULL_VOID(textOverlayTheme);
215 auto gestureHub = node->GetOrCreateGestureEventHub();
216 std::vector<DimensionRect> vector;
217 auto menuPadding = textOverlayTheme->GetMenuPadding();
218 auto buttonHeight = textOverlayTheme->GetMenuButtonHeight();
219 auto top = menuPadding.Top();
220 auto responseHeight = top.Value() + menuPadding.Bottom().Value() + buttonHeight.Value();
221 vector.emplace_back(
222 DimensionRect(Dimension(1, DimensionUnit::PERCENT), Dimension(responseHeight, DimensionUnit::VP),
223 DimensionOffset(Dimension(0), Dimension(-top.Value(), top.Unit()))));
224 gestureHub->SetResponseRegion(vector);
225 }
226
SetMoreOrBackButtonResponse(RefPtr<FrameNode> & node)227 void SetMoreOrBackButtonResponse(RefPtr<FrameNode>& node)
228 {
229 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
230 CHECK_NULL_VOID(pipeline);
231 if (GreatOrEqual(pipeline->GetFontScale(), AGING_MIN_SCALE)) {
232 return;
233 }
234 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
235 CHECK_NULL_VOID(textOverlayTheme);
236 auto gestureHub = node->GetOrCreateGestureEventHub();
237 CHECK_NULL_VOID(gestureHub);
238 std::vector<DimensionRect> vector;
239 auto menuPadding = textOverlayTheme->GetMenuPadding();
240 auto buttonWidth = textOverlayTheme->GetMenuButtonWidth();
241 auto top = menuPadding.Top();
242 auto responseHeight = top.Value() + menuPadding.Bottom().Value() + textOverlayTheme->GetMenuButtonHeight().Value();
243 auto responseWidth = std::max(buttonWidth, MIN_HOTSPOT_WIDTH);
244 constexpr int32_t centerDivider = 2;
245 vector.emplace_back(DimensionRect(responseWidth, Dimension(responseHeight, DimensionUnit::VP),
246 DimensionOffset(
247 Dimension(-(responseWidth - buttonWidth) / centerDivider), Dimension(-top.Value(), top.Unit()))));
248 gestureHub->SetResponseRegion(vector);
249 }
250
251 #ifdef OHOS_PLATFORM
PreparePasteButtonLayoutProperty(RefPtr<OHOS::Ace::NG::SecurityComponentLayoutProperty> & buttonLayoutProperty,const OHOS::Ace::TextStyle & textStyle,float & buttonWidth,float fontScale,RefPtr<OHOS::Ace::TextOverlayTheme> & textOverlayTheme)252 void PreparePasteButtonLayoutProperty(RefPtr<OHOS::Ace::NG::SecurityComponentLayoutProperty>& buttonLayoutProperty,
253 const OHOS::Ace::TextStyle& textStyle, float& buttonWidth, float fontScale,
254 RefPtr<OHOS::Ace::TextOverlayTheme>& textOverlayTheme)
255 {
256 CHECK_NULL_VOID(buttonLayoutProperty);
257 CHECK_NULL_VOID(textOverlayTheme);
258 auto descriptionId = static_cast<int32_t>(PasteButtonPasteDescription::PASTE);
259
260 buttonLayoutProperty->UpdateFontSize(textStyle.GetFontSize());
261 buttonLayoutProperty->UpdateFontWeight(textStyle.GetFontWeight());
262
263 const auto& padding = textOverlayTheme->GetMenuButtonPadding();
264 buttonLayoutProperty->UpdateBackgroundLeftPadding(padding.Left());
265 buttonLayoutProperty->UpdateBackgroundRightPadding(padding.Right());
266 std::string buttonContent;
267 PasteButtonModelNG::GetInstance()->GetTextResource(descriptionId, buttonContent);
268 buttonWidth = MeasureUtil::MeasureTextWidth(textStyle, buttonContent);
269 buttonWidth = buttonWidth + padding.Left().ConvertToPx() + padding.Right().ConvertToPx();
270 if (GreatOrEqual(fontScale, AGING_MIN_SCALE)) {
271 buttonLayoutProperty->UpdateUserDefinedIdealSize({ CalcLength(buttonWidth), std::nullopt });
272 } else {
273 buttonLayoutProperty->UpdateUserDefinedIdealSize(
274 { CalcLength(buttonWidth), CalcLength(textOverlayTheme->GetMenuButtonHeight()) });
275 }
276 }
277
BuildPasteButton(const std::shared_ptr<SelectOverlayInfo> & info,const std::function<void ()> & callback,int32_t overlayId,float & buttonWidth,bool isSelectAll=false)278 RefPtr<FrameNode> BuildPasteButton(const std::shared_ptr<SelectOverlayInfo>& info,
279 const std::function<void()>& callback, int32_t overlayId, float& buttonWidth, bool isSelectAll = false)
280 {
281 auto descriptionId = static_cast<int32_t>(PasteButtonPasteDescription::PASTE);
282 auto pasteButton = PasteButtonModelNG::GetInstance()->CreateNode(descriptionId,
283 static_cast<int32_t>(PasteButtonIconStyle::ICON_NULL), static_cast<int32_t>(ButtonType::CAPSULE),
284 true, static_cast<int32_t>(PasteButtonIconStyle::ICON_NULL));
285 CHECK_NULL_RETURN(pasteButton, nullptr);
286 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
287 CHECK_NULL_RETURN(pipeline, pasteButton);
288 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>(GetCallerScopedId(info)); // enable Get from withTheme
289 CHECK_NULL_RETURN(textOverlayTheme, pasteButton);
290 auto textStyle = textOverlayTheme->GetMenuButtonTextStyle();
291
292 auto buttonLayoutProperty = pasteButton->GetLayoutProperty<SecurityComponentLayoutProperty>();
293 PreparePasteButtonLayoutProperty(
294 buttonLayoutProperty, textStyle, buttonWidth, pipeline->GetFontScale(), textOverlayTheme);
295
296 auto buttonPaintProperty = pasteButton->GetPaintProperty<SecurityComponentPaintProperty>();
297 CHECK_NULL_RETURN(buttonPaintProperty, nullptr);
298 buttonPaintProperty->UpdateBackgroundColor(Color::TRANSPARENT);
299 if (callback) {
300 buttonPaintProperty->UpdateFontColor(textStyle.GetTextColor());
301 auto id = Container::CurrentIdSafelyWithCheck();
302 pasteButton->GetOrCreateGestureEventHub()->SetUserOnClick([callback, id](GestureEvent& info) {
303 ContainerScope scope(id);
304 if (!PasteButtonModelNG::GetInstance()->IsClickResultSuccess(info)) {
305 return;
306 }
307 if (callback) {
308 callback();
309 }
310 });
311 } else {
312 buttonPaintProperty->UpdateFontColor(
313 textStyle.GetTextColor().BlendOpacity(textOverlayTheme->GetAlphaDisabled()));
314 auto buttonEventHub = pasteButton->GetOrCreateEventHub<MenuItemEventHub>();
315 CHECK_NULL_RETURN(buttonEventHub, pasteButton);
316 buttonEventHub->SetEnabled(false);
317 }
318 SetResponseRegion(pasteButton);
319 auto buttonNode = GetSecCompChildNode(pasteButton, V2::BUTTON_ETS_TAG);
320 CHECK_NULL_RETURN(buttonNode, pasteButton);
321 if (buttonNode->GetPatternPtr<ButtonPattern>()) {
322 buttonNode->GetPatternPtr<ButtonPattern>()->SetClickedColor(textOverlayTheme->GetButtonClickedColor());
323 buttonNode->GetPatternPtr<ButtonPattern>()->SetBlendColor(textOverlayTheme->GetButtonClickedColor(),
324 textOverlayTheme->GetButtonHoverColor());
325 }
326 pasteButton->MarkModifyDone();
327 return pasteButton;
328 }
329
CreatePasteButtonForCreateMenu(const std::shared_ptr<SelectOverlayInfo> & info,int32_t overlayId,const MenuOptionsParam & item,float & buttonWidth)330 RefPtr<FrameNode> CreatePasteButtonForCreateMenu(
331 const std::shared_ptr<SelectOverlayInfo>& info, int32_t overlayId, const MenuOptionsParam& item, float& buttonWidth)
332 {
333 auto id = Container::CurrentIdSafelyWithCheck();
334 auto onPaste = [onPaste = info->menuCallback.onPaste, onCreateCallback = info->onCreateCallback,
335 menuOptionsParam = item, id]() {
336 ContainerScope scope(id);
337 bool result = false;
338 if (onCreateCallback.onMenuItemClick) {
339 MenuItemParam menuItem;
340 menuItem.menuOptionsParam = menuOptionsParam;
341 int32_t start = -1;
342 int32_t end = -1;
343 if (onCreateCallback.textRangeCallback) {
344 onCreateCallback.textRangeCallback(start, end);
345 }
346 menuItem.start = start;
347 menuItem.end = end;
348 result = onCreateCallback.onMenuItemClick(menuItem);
349 }
350 if (!result && onPaste) {
351 onPaste();
352 }
353 };
354 auto button = BuildPasteButton(info, onPaste, overlayId, buttonWidth);
355 return button;
356 }
357 #endif
358
PrepareButtonTextProp(RefPtr<OHOS::Ace::NG::TextLayoutProperty> & textLayoutProperty,bool hasCallback,float & buttonWidth,const ButtonBasicInfo & buttonBasicInfo,const std::shared_ptr<SelectOverlayInfo> & info)359 bool PrepareButtonTextProp(
360 RefPtr<OHOS::Ace::NG::TextLayoutProperty>& textLayoutProperty, bool hasCallback, float& buttonWidth,
361 const ButtonBasicInfo& buttonBasicInfo, const std::shared_ptr<SelectOverlayInfo>& info)
362 {
363 auto data = buttonBasicInfo.data;
364 auto buttonType = buttonBasicInfo.buttonType;
365 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
366 CHECK_NULL_RETURN(pipeline, false);
367 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>(GetCallerScopedId(info));
368 CHECK_NULL_RETURN(textOverlayTheme, false);
369 auto textStyle = textOverlayTheme->GetMenuButtonTextStyle();
370 // Body_M
371 textLayoutProperty->UpdateFontSize(textStyle.GetFontSize());
372 textLayoutProperty->UpdateFontWeight(textStyle.GetFontWeight());
373 textLayoutProperty->UpdateMaxLines(1);
374 // font_primary
375 if (hasCallback) {
376 textLayoutProperty->UpdateTextColor(textStyle.GetTextColor());
377 } else {
378 textLayoutProperty->UpdateTextColor(
379 textStyle.GetTextColor().BlendOpacity(textOverlayTheme->GetAlphaDisabled()));
380 }
381 auto textSize = MeasureUtil::MeasureTextSize(textStyle, data);
382 buttonWidth = std::max(static_cast<float>(textSize.Width()), 0.0f);
383 if (buttonType == SelectOverlayMenuButtonType::AIBUTTON) {
384 FontForegroudGradiantColor colorInfo;
385 colorInfo.points = { NG::PointF(0, 0),
386 NG::PointF(static_cast<float>(textSize.Width()), static_cast<float>(textSize.Height())) };
387 colorInfo.colors = textOverlayTheme->GetAiMenuFontGradientColors();
388 colorInfo.scalars = textOverlayTheme->GetAiMenuFontGradientScalars();
389 textLayoutProperty->UpdateFontForegroudGradiantColor(colorInfo);
390 }
391 return true;
392 }
393
PrepareButtonProp(RefPtr<OHOS::Ace::NG::ButtonLayoutProperty> & buttonLayoutProperty,float & buttonWidth,const RefPtr<OHOS::Ace::NG::FrameNode> & buttonNode,const std::shared_ptr<SelectOverlayInfo> & info)394 bool PrepareButtonProp(RefPtr<OHOS::Ace::NG::ButtonLayoutProperty>& buttonLayoutProperty,
395 float& buttonWidth, const RefPtr<OHOS::Ace::NG::FrameNode>& buttonNode,
396 const std::shared_ptr<SelectOverlayInfo>& info)
397 {
398 CHECK_NULL_RETURN(buttonNode, false);
399 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
400 CHECK_NULL_RETURN(pipeline, false);
401 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>(GetCallerScopedId(info));
402 CHECK_NULL_RETURN(textOverlayTheme, false);
403 CHECK_NULL_RETURN(buttonLayoutProperty, false);
404 if (buttonNode->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
405 buttonLayoutProperty->UpdateType(ButtonType::ROUNDED_RECTANGLE);
406 buttonLayoutProperty->UpdateControlSize(ControlSize::SMALL);
407 } else {
408 buttonLayoutProperty->UpdateType(ButtonType::CAPSULE);
409 }
410 buttonLayoutProperty->UpdateBorderRadius(BorderRadiusProperty(textOverlayTheme->GetMenuButtonRadius()));
411 const auto& padding = textOverlayTheme->GetMenuButtonPadding();
412 auto left = CalcLength(padding.Left().ConvertToPx());
413 auto right = CalcLength(padding.Right().ConvertToPx());
414 auto top = CalcLength(padding.Top().ConvertToPx());
415 auto bottom = CalcLength(padding.Bottom().ConvertToPx());
416 buttonLayoutProperty->UpdatePadding({ left, right, top, bottom, std::nullopt, std::nullopt });
417 // Calculate the width of default option include button padding.
418 buttonWidth = buttonWidth + padding.Left().ConvertToPx() + padding.Right().ConvertToPx();
419 if (GreatOrEqual(pipeline->GetFontScale(), AGING_MIN_SCALE)) {
420 buttonLayoutProperty->UpdateUserDefinedIdealSize({ CalcLength(buttonWidth), std::nullopt });
421 } else {
422 buttonLayoutProperty->UpdateUserDefinedIdealSize(
423 { CalcLength(buttonWidth), CalcLength(textOverlayTheme->GetMenuButtonHeight()) });
424 }
425 buttonLayoutProperty->UpdateFlexShrink(0);
426
427 // interactive_hover and interactive_click
428 CHECK_NULL_RETURN(buttonNode->GetPatternPtr<ButtonPattern>(), false);
429 if (buttonNode->GetPatternPtr<ButtonPattern>()) {
430 buttonNode->GetPatternPtr<ButtonPattern>()->SetClickedColor(textOverlayTheme->GetButtonClickedColor());
431 buttonNode->GetPatternPtr<ButtonPattern>()->SetBlendColor(textOverlayTheme->GetButtonClickedColor(),
432 textOverlayTheme->GetButtonHoverColor());
433 }
434 return true;
435 }
436
BuildButton(const std::shared_ptr<SelectOverlayInfo> & info,std::variant<const std::function<void ()>,const std::function<void (std::string)>> callbackVariant,int32_t overlayId,float & buttonWidth,const ButtonBasicInfo & buttonBasicInfo)437 RefPtr<FrameNode> BuildButton(const std::shared_ptr<SelectOverlayInfo>& info, std::variant<const std::function<void()>,
438 const std::function<void(std::string)>> callbackVariant, int32_t overlayId, float& buttonWidth,
439 const ButtonBasicInfo& buttonBasicInfo)
440 {
441 auto button = FrameNode::GetOrCreateFrameNode("SelectMenuButton", ElementRegister::GetInstance()->MakeUniqueId(),
442 []() { return AceType::MakeRefPtr<ButtonPattern>(); });
443 auto text = FrameNode::GetOrCreateFrameNode("SelectMenuButtonText", ElementRegister::GetInstance()->MakeUniqueId(),
444 []() { return AceType::MakeRefPtr<TextPattern>(); });
445 CHECK_NULL_RETURN(text, button);
446 auto textLayoutProperty = text->GetLayoutProperty<TextLayoutProperty>();
447 CHECK_NULL_RETURN(textLayoutProperty, button);
448 auto data = buttonBasicInfo.data;
449 auto buttonType = buttonBasicInfo.buttonType;
450 textLayoutProperty->UpdateContent(data);
451 text->MountToParent(button);
452 auto hasCallback = false;
453 if ((std::holds_alternative<const std::function<void()>>(callbackVariant) &&
454 std::get<const std::function<void()>>(callbackVariant)) ||
455 (std::holds_alternative<const std::function<void(std::string)>>(callbackVariant) &&
456 std::get<const std::function<void(std::string)>>(callbackVariant))) {
457 hasCallback = true;
458 }
459 auto retPrepare = PrepareButtonTextProp(textLayoutProperty, hasCallback, buttonWidth, buttonBasicInfo, info);
460 CHECK_NE_RETURN(retPrepare, true, button);
461 text->MarkModifyDone();
462
463 auto buttonLayoutProperty = button->GetLayoutProperty<ButtonLayoutProperty>();
464 CHECK_NULL_RETURN(buttonLayoutProperty, button);
465 retPrepare = PrepareButtonProp(buttonLayoutProperty, buttonWidth, button, info);
466 CHECK_NE_RETURN(retPrepare, true, button);
467
468 button->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
469
470 if (hasCallback) {
471 button->GetOrCreateGestureEventHub()->SetUserOnClick(
472 [lableInfo = data, callbackVariant, overlayId,
473 id = Container::CurrentIdSafelyWithCheck(), buttonType = buttonType]
474 (GestureEvent& /* info */) {
475 ContainerScope scope(id);
476 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
477 CHECK_NULL_VOID(pipeline);
478 auto overlayManager = pipeline->GetSelectOverlayManager();
479 CHECK_NULL_VOID(overlayManager);
480 auto selectOverlay = overlayManager->GetSelectOverlayNode(overlayId);
481 CHECK_NULL_VOID(selectOverlay);
482 auto isDoingAnimation = selectOverlay->GetAnimationStatus();
483 CHECK_NULL_VOID(!isDoingAnimation);
484 auto isExtensionMenu = selectOverlay->GetIsExtensionMenu();
485 CHECK_NULL_VOID(!isExtensionMenu);
486 if (std::holds_alternative<const std::function<void()>>(callbackVariant) &&
487 std::get<const std::function<void()>>(callbackVariant)) {
488 std::get<const std::function<void()>>(callbackVariant)();
489 } else if (std::holds_alternative<const std::function<void(std::string)>>(callbackVariant) &&
490 std::get<const std::function<void(std::string)>>(callbackVariant)) {
491 std::get<const std::function<void(std::string)>>(callbackVariant)(lableInfo);
492 }
493 });
494 } else {
495 auto buttonEventHub = button->GetOrCreateEventHub<MenuItemEventHub>();
496 CHECK_NULL_RETURN(buttonEventHub, button);
497 buttonEventHub->SetEnabled(false);
498 }
499 SetResponseRegion(button);
500 button->MarkModifyDone();
501 return button;
502 }
503
BindButtonClickEvent(const RefPtr<FrameNode> & button,const MenuOptionsParam & menuOption,int32_t overlayId)504 void BindButtonClickEvent(const RefPtr<FrameNode>& button, const MenuOptionsParam& menuOption, int32_t overlayId)
505 {
506 auto callback = menuOption.action;
507 auto id = Container::CurrentIdSafelyWithCheck();
508 button->GetOrCreateGestureEventHub()->SetUserOnClick([callback, overlayId, id](GestureEvent& /*info*/) {
509 ContainerScope scope(id);
510 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
511 CHECK_NULL_VOID(pipeline);
512 auto overlayManager = pipeline->GetSelectOverlayManager();
513 CHECK_NULL_VOID(overlayManager);
514
515 auto selectOverlay = overlayManager->GetSelectOverlayNode(overlayId);
516 CHECK_NULL_VOID(selectOverlay);
517 auto pattern = selectOverlay->GetPattern<SelectOverlayPattern>();
518 auto selectInfo = pattern->GetSelectInfo();
519 if (callback) {
520 callback(selectInfo);
521 }
522 // close text overlay.
523 overlayManager->DestroySelectOverlay(overlayId);
524 overlayManager->CloseSelectContentOverlay(overlayId, CloseReason::CLOSE_REASON_TOOL_BAR, false);
525 });
526 }
527
BuildButton(const MenuOptionsParam & menuOption,int32_t overlayId,float & contentWidth,const std::shared_ptr<SelectOverlayInfo> & info)528 RefPtr<FrameNode> BuildButton(const MenuOptionsParam& menuOption, int32_t overlayId, float& contentWidth,
529 const std::shared_ptr<SelectOverlayInfo>& info)
530 {
531 auto button = FrameNode::GetOrCreateFrameNode("SelectMenuButton", ElementRegister::GetInstance()->MakeUniqueId(),
532 []() { return AceType::MakeRefPtr<ButtonPattern>(); });
533 auto text = FrameNode::GetOrCreateFrameNode("SelectMenuButtonText", ElementRegister::GetInstance()->MakeUniqueId(),
534 []() { return AceType::MakeRefPtr<TextPattern>(); });
535
536 // Update text property and mount to button.
537 auto textLayoutProperty = text->GetLayoutProperty<TextLayoutProperty>();
538 CHECK_NULL_RETURN(textLayoutProperty, button);
539 auto data = menuOption.content.value_or("");
540 textLayoutProperty->UpdateContent(data);
541 text->MountToParent(button);
542 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
543 CHECK_NULL_RETURN(pipeline, button);
544 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>(GetCallerScopedId(info));
545 CHECK_NULL_RETURN(textOverlayTheme, button);
546 auto textStyle = textOverlayTheme->GetMenuButtonTextStyle();
547 textLayoutProperty->UpdateFontSize(textStyle.GetFontSize());
548 textLayoutProperty->UpdateTextColor(textStyle.GetTextColor());
549 textLayoutProperty->UpdateFontWeight(textStyle.GetFontWeight());
550 textLayoutProperty->UpdateMaxLines(1);
551 text->MarkModifyDone();
552 // Calculate the width of entension option include button padding.
553 contentWidth = static_cast<float>(MeasureUtil::MeasureTextWidth(textStyle, data));
554 const auto& padding = textOverlayTheme->GetMenuButtonPadding();
555 auto left = CalcLength(padding.Left().ConvertToPx());
556 auto right = CalcLength(padding.Right().ConvertToPx());
557 auto top = CalcLength(padding.Top().ConvertToPx());
558 auto bottom = CalcLength(padding.Bottom().ConvertToPx());
559 contentWidth = contentWidth + padding.Left().ConvertToPx() + padding.Right().ConvertToPx();
560
561 // Update button property.
562 auto buttonLayoutProperty = button->GetLayoutProperty<ButtonLayoutProperty>();
563 CHECK_NULL_RETURN(buttonLayoutProperty, button);
564 buttonLayoutProperty->UpdatePadding({ left, right, top, bottom, std::nullopt, std::nullopt });
565 if (GreatOrEqual(pipeline->GetFontScale(), AGING_MIN_SCALE)) {
566 buttonLayoutProperty->UpdateUserDefinedIdealSize({ CalcLength(contentWidth), std::nullopt });
567 } else {
568 buttonLayoutProperty->UpdateUserDefinedIdealSize(
569 { CalcLength(contentWidth), CalcLength(textOverlayTheme->GetMenuButtonHeight()) });
570 }
571 buttonLayoutProperty->UpdateFlexShrink(0);
572 button->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
573 BindButtonClickEvent(button, menuOption, overlayId);
574 SetResponseRegion(button);
575 if (button->GetPatternPtr<ButtonPattern>()) {
576 button->GetPatternPtr<ButtonPattern>()->SetClickedColor(textOverlayTheme->GetButtonClickedColor());
577 button->GetPatternPtr<ButtonPattern>()->SetBlendColor(textOverlayTheme->GetButtonClickedColor(),
578 textOverlayTheme->GetButtonHoverColor());
579 }
580 button->MarkModifyDone();
581 return button;
582 }
583
BindCreateMenuItemClickEvent(const RefPtr<FrameNode> & button,const MenuOptionsParam & menuOptionsParam,int32_t overlayId,const std::function<void ()> & systemCallback,const OnMenuItemCallback & onCreateCallback)584 void BindCreateMenuItemClickEvent(const RefPtr<FrameNode>& button, const MenuOptionsParam& menuOptionsParam,
585 int32_t overlayId, const std::function<void()>& systemCallback, const OnMenuItemCallback& onCreateCallback)
586 {
587 auto id = Container::CurrentIdSafelyWithCheck();
588 button->GetOrCreateGestureEventHub()->SetUserOnClick(
589 [menuOptionsParam, systemCallback, onCreateCallback, id](GestureEvent& /*info*/) {
590 ContainerScope scope(id);
591 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
592 CHECK_NULL_VOID(pipeline);
593 auto overlayManager = pipeline->GetSelectOverlayManager();
594 CHECK_NULL_VOID(overlayManager);
595 auto newOverlayManager = overlayManager->GetSelectContentOverlayManager();
596 CHECK_NULL_VOID(newOverlayManager);
597 bool result = false;
598 if (onCreateCallback.onMenuItemClick) {
599 MenuItemParam menuItem;
600 menuItem.menuOptionsParam = menuOptionsParam;
601 int32_t start = -1;
602 int32_t end = -1;
603 if (onCreateCallback.textRangeCallback) {
604 onCreateCallback.textRangeCallback(start, end);
605 }
606 menuItem.start = start;
607 menuItem.end = end;
608 result = onCreateCallback.onMenuItemClick(menuItem);
609 }
610 if (!result && systemCallback) {
611 systemCallback();
612 }
613 if (!systemCallback && !result) {
614 newOverlayManager->HideOptionMenu(true);
615 }
616 });
617 }
618
BuildCreateMenuItemButton(const MenuOptionsParam & menuOptionsParam,const std::function<void ()> & systemCallback,int32_t overlayId,float & remainderWidth,const std::shared_ptr<SelectOverlayInfo> & info)619 RefPtr<FrameNode> BuildCreateMenuItemButton(const MenuOptionsParam& menuOptionsParam,
620 const std::function<void()>& systemCallback, int32_t overlayId,
621 float& remainderWidth, const std::shared_ptr<SelectOverlayInfo>& info)
622 {
623 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
624 CHECK_NULL_RETURN(pipeline, nullptr);
625 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>(GetCallerScopedId(info));
626 CHECK_NULL_RETURN(textOverlayTheme, nullptr);
627 CHECK_NULL_RETURN(info, nullptr);
628 const OnMenuItemCallback& menuItemCallback = info->onCreateCallback;
629 auto textStyle = textOverlayTheme->GetMenuButtonTextStyle();
630 auto data = menuOptionsParam.content.value_or("");
631 auto contentWidth = 0.0f;
632
633 auto button = FrameNode::GetOrCreateFrameNode("SelectMenuButton", ElementRegister::GetInstance()->MakeUniqueId(),
634 []() { return AceType::MakeRefPtr<ButtonPattern>(); });
635 auto text = FrameNode::GetOrCreateFrameNode("SelectMenuButtonText", ElementRegister::GetInstance()->MakeUniqueId(),
636 []() { return AceType::MakeRefPtr<TextPattern>(); });
637 // Update text property and mount to button.
638 auto textLayoutProperty = text->GetLayoutProperty<TextLayoutProperty>();
639 CHECK_NULL_RETURN(textLayoutProperty, button);
640 textLayoutProperty->UpdateContent(data);
641 auto buttonType = IsAIMenuOption(menuOptionsParam.id) || IsAskCeliaOption(menuOptionsParam.id) ?
642 SelectOverlayMenuButtonType::AIBUTTON : SelectOverlayMenuButtonType::NORMAL;
643 ButtonBasicInfo buttonBasicInfo = {.data = data, .buttonType = buttonType};
644 PrepareButtonTextProp(textLayoutProperty, true, contentWidth, buttonBasicInfo, info);
645 textLayoutProperty->UpdateWordBreak(WordBreak::BREAK_ALL);
646 text->MountToParent(button);
647
648 // Calculate the width of entension option include button padding.
649 const auto& padding = textOverlayTheme->GetMenuButtonPadding();
650 auto left = CalcLength(padding.Left().ConvertToPx());
651 auto right = CalcLength(padding.Right().ConvertToPx());
652 auto top = CalcLength(padding.Top().ConvertToPx());
653 auto bottom = CalcLength(padding.Bottom().ConvertToPx());
654 contentWidth = contentWidth + padding.Left().ConvertToPx() + padding.Right().ConvertToPx();
655 auto isOverWidth = GreatOrEqual(remainderWidth, contentWidth);
656 CHECK_NULL_RETURN(isOverWidth || menuOptionsParam.isFirstOption, nullptr);
657 contentWidth = std::min(contentWidth, remainderWidth);
658
659 if (!isOverWidth && menuOptionsParam.isFirstOption) {
660 textLayoutProperty->UpdateTextOverflow(TextOverflow::ELLIPSIS);
661 }
662 text->MarkModifyDone();
663
664 // Update button property.
665 auto buttonLayoutProperty = button->GetLayoutProperty<ButtonLayoutProperty>();
666 CHECK_NULL_RETURN(buttonLayoutProperty, button);
667 buttonLayoutProperty->UpdatePadding({ left, right, top, bottom, std::nullopt, std::nullopt });
668 if (GreatOrEqual(pipeline->GetFontScale(), AGING_MIN_SCALE)) {
669 buttonLayoutProperty->UpdateUserDefinedIdealSize({ CalcLength(contentWidth), std::nullopt });
670 } else {
671 buttonLayoutProperty->UpdateUserDefinedIdealSize(
672 { CalcLength(contentWidth), CalcLength(textOverlayTheme->GetMenuButtonHeight()) });
673 }
674 buttonLayoutProperty->UpdateFlexShrink(0);
675 if (button->GetPatternPtr<ButtonPattern>()) {
676 button->GetPatternPtr<ButtonPattern>()->SetClickedColor(textOverlayTheme->GetButtonClickedColor());
677 button->GetPatternPtr<ButtonPattern>()->SetBlendColor(textOverlayTheme->GetButtonClickedColor(),
678 textOverlayTheme->GetButtonHoverColor());
679 }
680
681 if (button->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
682 buttonLayoutProperty->UpdateType(ButtonType::ROUNDED_RECTANGLE);
683 buttonLayoutProperty->UpdateControlSize(ControlSize::SMALL);
684 } else {
685 buttonLayoutProperty->UpdateType(ButtonType::CAPSULE);
686 }
687
688 buttonLayoutProperty->UpdateBorderRadius(BorderRadiusProperty(textOverlayTheme->GetMenuButtonRadius()));
689 button->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
690 BindCreateMenuItemClickEvent(button, menuOptionsParam, overlayId, systemCallback, menuItemCallback);
691 SetResponseRegion(button);
692 button->MarkModifyDone();
693 remainderWidth -= contentWidth;
694 return button;
695 }
696
UpdateBackButtonPadding(const RefPtr<FrameNode> & button,const CalcLength & sideWidth,const Edge & padding,int32_t overlayId)697 void UpdateBackButtonPadding(
698 const RefPtr<FrameNode>& button, const CalcLength& sideWidth, const Edge& padding, int32_t overlayId)
699 {
700 CHECK_NULL_VOID(button);
701 auto buttonLayoutProperty = button->GetLayoutProperty<ButtonLayoutProperty>();
702 CHECK_NULL_VOID(buttonLayoutProperty);
703 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
704 CHECK_NULL_VOID(pipeline);
705 buttonLayoutProperty->UpdateUserDefinedIdealSize({ sideWidth, sideWidth });
706 auto left = CalcLength(padding.Left().ConvertToPx());
707 auto right = CalcLength(padding.Right().ConvertToPx());
708 auto top = CalcLength(padding.Top().ConvertToPx());
709 auto bottom = CalcLength(padding.Bottom().ConvertToPx());
710 if (GreatOrEqual(pipeline->GetFontScale(), AGING_MIN_SCALE)) {
711 auto overlayManager = pipeline->GetSelectOverlayManager();
712 CHECK_NULL_VOID(overlayManager);
713 auto selectOverlay = overlayManager->GetSelectOverlayNode(overlayId);
714 if (selectOverlay) {
715 auto selectMenu = AceType::DynamicCast<FrameNode>(selectOverlay->GetFirstChild());
716 CHECK_NULL_VOID(selectMenu);
717 auto geometryNode = selectMenu->GetGeometryNode();
718 CHECK_NULL_VOID(geometryNode);
719 auto selectMenuHeight = geometryNode->GetFrameSize().Height();
720 top = CalcLength((selectMenuHeight - sideWidth.GetDimension().Value()) / 2.0f);
721 bool isSymbol = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE);
722 top = isSymbol ? CalcLength(padding.Top().ConvertToPx()) : top;
723 }
724 }
725 buttonLayoutProperty->UpdatePadding({ left, right, top, bottom });
726 }
727
PrepareMoreOrBackButtonNode(RefPtr<OHOS::Ace::NG::FrameNode> & button,int32_t overlayId,bool isMoreButton,const RefPtr<OHOS::Ace::TextOverlayTheme> & textOverlayTheme)728 void PrepareMoreOrBackButtonNode(RefPtr<OHOS::Ace::NG::FrameNode>& button,
729 int32_t overlayId, bool isMoreButton, const RefPtr<OHOS::Ace::TextOverlayTheme>& textOverlayTheme)
730 {
731 auto id = Container::CurrentIdSafelyWithCheck();
732 button->GetOrCreateGestureEventHub()->SetUserOnClick([overlayId, isMoreButton, id](GestureEvent& /*info*/) {
733 auto container = Container::GetContainer(id);
734 CHECK_NULL_VOID(container);
735 auto pipeline = AceType::DynamicCast<PipelineContext>(container->GetPipelineContext());
736 CHECK_NULL_VOID(pipeline);
737 auto overlayManager = pipeline->GetSelectOverlayManager();
738 CHECK_NULL_VOID(overlayManager);
739 auto selectOverlay = overlayManager->GetSelectOverlayNode(overlayId);
740 CHECK_NULL_VOID(selectOverlay);
741 // When click button , change to extensionMenu or change to the default menu(selectMenu_).
742 selectOverlay->MoreOrBackAnimation(isMoreButton);
743 });
744
745 button->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
746 if (button->GetPatternPtr<ButtonPattern>()) {
747 button->GetPatternPtr<ButtonPattern>()->SetClickedColor(textOverlayTheme->GetButtonClickedColor());
748 button->GetPatternPtr<ButtonPattern>()->SetBlendColor(textOverlayTheme->GetButtonClickedColor(),
749 textOverlayTheme->GetButtonHoverColor());
750 }
751 }
752
BuildMoreOrBackButton(const std::shared_ptr<SelectOverlayInfo> & info,int32_t overlayId,bool isMoreButton)753 RefPtr<FrameNode> BuildMoreOrBackButton(const std::shared_ptr<SelectOverlayInfo>& info,
754 int32_t overlayId, bool isMoreButton)
755 {
756 auto button = FrameNode::GetOrCreateFrameNode("SelectMoreOrBackButton",
757 ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<ButtonPattern>(); });
758 CHECK_NULL_RETURN(button, button);
759 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
760 CHECK_NULL_RETURN(pipeline, button);
761 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>(GetCallerScopedId(info));
762 CHECK_NULL_RETURN(textOverlayTheme, button);
763
764 // Update property.
765 auto buttonLayoutProperty = button->GetLayoutProperty<ButtonLayoutProperty>();
766 CHECK_NULL_RETURN(buttonLayoutProperty, button);
767
768 const auto& padding = textOverlayTheme->GetMenuPadding();
769
770 auto accessibilityProperty = button->GetAccessibilityProperty<AccessibilityProperty>();
771 CHECK_NULL_RETURN(accessibilityProperty, button);
772
773 if (isMoreButton) {
774 auto sideWidth = CalcLength(textOverlayTheme->GetMenuToolbarHeight().ConvertToPx() -
775 padding.Top().ConvertToPx() - padding.Bottom().ConvertToPx());
776 buttonLayoutProperty->UpdateUserDefinedIdealSize({ sideWidth, sideWidth });
777 accessibilityProperty->SetAccessibilityText(textOverlayTheme->GetMoreAccessibilityText());
778 SetMoreOrBackButtonResponse(button);
779 } else {
780 auto sideWidth = CalcLength(textOverlayTheme->GetMenuToolbarHeight().ConvertToPx());
781 UpdateBackButtonPadding(button, sideWidth, padding, overlayId);
782 accessibilityProperty->SetAccessibilityText(textOverlayTheme->GetBackAccessibilityText());
783 }
784
785 accessibilityProperty->SetAccessibilityCustomRole("button");
786
787 PrepareMoreOrBackButtonNode(button, overlayId, isMoreButton, textOverlayTheme);
788
789 button->MarkModifyDone();
790 return button;
791 }
792
BuildMoreOrBackSymbol()793 RefPtr<FrameNode> BuildMoreOrBackSymbol()
794 {
795 auto symbol = FrameNode::GetOrCreateFrameNode(V2::SYMBOL_ETS_TAG,
796 ElementRegister::GetInstance()->MakeUniqueId(),
797 []() { return AceType::MakeRefPtr<TextPattern>(); });
798 CHECK_NULL_RETURN(symbol, nullptr);
799 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
800 CHECK_NULL_RETURN(pipeline, symbol);
801 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
802 CHECK_NULL_RETURN(textOverlayTheme, symbol);
803 auto layoutProperty = symbol->GetLayoutProperty<TextLayoutProperty>();
804 CHECK_NULL_RETURN(layoutProperty, symbol);
805 layoutProperty->UpdateSymbolSourceInfo(SymbolSourceInfo(textOverlayTheme->GetMoreSymbolId()));
806 layoutProperty->UpdateFontSize(textOverlayTheme->GetSymbolSize());
807 layoutProperty->UpdateFontWeight(FontWeight::MEDIUM);
808 layoutProperty->UpdateSymbolColorList({textOverlayTheme->GetSymbolColor()});
809 auto symbolEffectOptions = layoutProperty->GetSymbolEffectOptionsValue(SymbolEffectOptions());
810 symbolEffectOptions.SetEffectType(SymbolEffectType::REPLACE);
811 symbolEffectOptions.SetScopeType(Ace::ScopeType::WHOLE);
812 symbolEffectOptions.SetIsTxtActive(false);
813 layoutProperty->UpdateSymbolEffectOptions(symbolEffectOptions);
814 symbol->MarkModifyDone();
815 return symbol;
816 }
817
GetPageOffset()818 OffsetF GetPageOffset()
819 {
820 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
821 CHECK_NULL_RETURN(pipeline, OffsetF());
822 auto stageManager = pipeline->GetStageManager();
823 CHECK_NULL_RETURN(stageManager, OffsetF());
824 auto page = stageManager->GetLastPage();
825 CHECK_NULL_RETURN(page, OffsetF());
826 return page->GetOffsetRelativeToWindow();
827 }
828
GetMenuCallbackWithContainerId(std::function<void ()> callback)829 std::function<void()> GetMenuCallbackWithContainerId(std::function<void()> callback)
830 {
831 auto optionCallback = [func = std::move(callback), mainId = Container::CurrentIdSafelyWithCheck()]() {
832 ContainerScope scope(mainId);
833 func();
834 };
835 return optionCallback;
836 }
837
GetMenuCallbackWithContainerId(std::function<void (std::string)> callback,const std::string & info)838 std::function<void()> GetMenuCallbackWithContainerId(
839 std::function<void(std::string)> callback, const std::string& info)
840 {
841 auto optionCallback = [func = std::move(callback), mainId = Container::CurrentIdSafelyWithCheck(), info]() {
842 ContainerScope scope(mainId);
843 func(info);
844 };
845 return optionCallback;
846 }
847
ConvertToVoidFunction(std::function<void (std::string)> funcWithArg,const std::string & arg)848 std::function<void()> ConvertToVoidFunction(std::function<void(std::string)> funcWithArg, const std::string& arg)
849 {
850 return [funcWithArg, arg]() {
851 funcWithArg(arg);
852 };
853 }
854
GetOptionsParamsHasSymbol(const std::shared_ptr<SelectOverlayInfo> & info,RefPtr<TextOverlayTheme> & theme,std::vector<OptionParam> & params)855 void GetOptionsParamsHasSymbol(
856 const std::shared_ptr<SelectOverlayInfo>& info, RefPtr<TextOverlayTheme>& theme, std::vector<OptionParam>& params)
857 {
858 CHECK_NULL_VOID(info);
859 CHECK_NULL_VOID(theme);
860 params.emplace_back(theme->GetCutLabel(), GetMenuCallbackWithContainerId(info->menuCallback.onCut),
861 theme->GetCutLabelInfo(), info->menuInfo.showCut, theme->GetCutSymbolId());
862 params.emplace_back(theme->GetCopyLabel(), GetMenuCallbackWithContainerId(info->menuCallback.onCopy),
863 theme->GetCopyLabelInfo(), info->menuInfo.showCopy, theme->GetCopySymbolId());
864 params.emplace_back(theme->GetPasteLabel(), GetMenuCallbackWithContainerId(info->menuCallback.onPaste),
865 theme->GetPasteLabelInfo(), info->menuInfo.showPaste, theme->GetPasteSymbolId());
866 params.emplace_back(theme->GetSelectAllLabel(), GetMenuCallbackWithContainerId(info->menuCallback.onSelectAll),
867 theme->GetSelectAllLabelInfo(), info->menuInfo.showCopyAll, theme->GetCopyAllSymbolId());
868
869 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_FIFTEEN) &&
870 TextSystemMenu::IsShowTranslate()) {
871 params.emplace_back(theme->GetTranslateLabel(), GetMenuCallbackWithContainerId(info->menuCallback.onTranslate),
872 "", info->menuInfo.showTranslate);
873 params.back().symbolId = theme->GetTranslateSymbolId();
874 }
875 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
876 if (TextSystemMenu::IsShowShare()) {
877 params.emplace_back(theme->GetShareLabel(), GetMenuCallbackWithContainerId(info->menuCallback.onShare), "",
878 info->menuInfo.showShare);
879 params.back().symbolId = theme->GetShareSymbolId();
880 }
881 if (TextSystemMenu::IsShowSearch()) {
882 params.emplace_back(theme->GetSearchLabel(), GetMenuCallbackWithContainerId(info->menuCallback.onSearch),
883 "", info->menuInfo.showSearch);
884 params.back().symbolId = theme->GetSearchSymbolId();
885 }
886 }
887 if (info->menuInfo.aiMenuOptionType != TextDataDetectType::INVALID) {
888 auto inheritFunc = ConvertToVoidFunction(info->menuCallback.onAIMenuOption, "From_Right_Click");
889 params.emplace_back(theme->GetAiMenuOptionName(info->menuInfo.aiMenuOptionType),
890 GetMenuCallbackWithContainerId(inheritFunc), "", true);
891 params.back().symbolId = theme->GetAIMenuSymbolId();
892 params.back().isAIMenuOption = true;
893 }
894 if (TextSystemMenu::IsShowAskCelia() && info->menuInfo.isAskCeliaEnabled) {
895 params.emplace_back(theme->GetAskCelia(),
896 GetMenuCallbackWithContainerId(info->menuCallback.onAskCelia), "", true);
897 params.back().symbolId = theme->GetAskCeliaSymbolId();
898 params.back().isAskCeliaOption = true;
899 }
900 }
901
GetOptionsParams(const std::shared_ptr<SelectOverlayInfo> & info)902 std::vector<OptionParam> GetOptionsParams(const std::shared_ptr<SelectOverlayInfo>& info)
903 {
904 std::vector<OptionParam> params;
905 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
906 CHECK_NULL_RETURN(pipeline, params);
907 auto theme = pipeline->GetTheme<TextOverlayTheme>();
908 CHECK_NULL_RETURN(theme, params);
909 if (theme->GetShowShortcut()) {
910 GetOptionsParamsHasSymbol(info, theme, params);
911 return params;
912 }
913 params.emplace_back(theme->GetCutLabel(), GetMenuCallbackWithContainerId(info->menuCallback.onCut),
914 theme->GetCutLabelInfo(), info->menuInfo.showCut);
915 params.emplace_back(theme->GetCopyLabel(), GetMenuCallbackWithContainerId(info->menuCallback.onCopy),
916 theme->GetCopyLabelInfo(), info->menuInfo.showCopy);
917 params.emplace_back(theme->GetPasteLabel(), GetMenuCallbackWithContainerId(info->menuCallback.onPaste),
918 theme->GetPasteLabelInfo(), info->menuInfo.showPaste);
919 params.emplace_back(theme->GetSelectAllLabel(), GetMenuCallbackWithContainerId(info->menuCallback.onSelectAll),
920 theme->GetSelectAllLabelInfo(), info->menuInfo.showCopyAll);
921 // Below is advanced options, consider support disableMenuItems and disableSystemServiceMenuItems by TextSystemMenu
922 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_FIFTEEN) &&
923 TextSystemMenu::IsShowTranslate()) {
924 params.emplace_back(theme->GetTranslateLabel(),
925 GetMenuCallbackWithContainerId(info->menuCallback.onTranslate), "", info->menuInfo.showTranslate);
926 }
927 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
928 if (TextSystemMenu::IsShowShare()) {
929 params.emplace_back(theme->GetShareLabel(), GetMenuCallbackWithContainerId(info->menuCallback.onShare), "",
930 info->menuInfo.showShare);
931 }
932 if (TextSystemMenu::IsShowSearch()) {
933 params.emplace_back(theme->GetSearchLabel(), GetMenuCallbackWithContainerId(info->menuCallback.onSearch),
934 "", info->menuInfo.showSearch);
935 }
936 }
937
938 if (IsShowAIMenuOption(info->menuInfo.aiMenuOptionType)) {
939 auto inheritFunc = ConvertToVoidFunction(info->menuCallback.onAIMenuOption, "From_Right_Click");
940 params.emplace_back(theme->GetAiMenuOptionName(info->menuInfo.aiMenuOptionType),
941 GetMenuCallbackWithContainerId(inheritFunc), "", true);
942 params.back().isAIMenuOption = true;
943 }
944
945 if (TextSystemMenu::IsShowAskCelia() && info->menuInfo.isAskCeliaEnabled) {
946 params.emplace_back(theme->GetAskCelia(),
947 GetMenuCallbackWithContainerId(info->menuCallback.onAskCelia), "", true);
948 params.back().isAskCeliaOption = true;
949 }
950
951 return params;
952 }
953
GetSystemCallback(const std::shared_ptr<SelectOverlayInfo> & info,bool isCallbackWithParam=false)954 std::unordered_map<std::string, std::function<void()>> GetSystemCallback(
955 const std::shared_ptr<SelectOverlayInfo>& info, bool isCallbackWithParam = false)
956 {
957 CHECK_NULL_RETURN(info, {});
958 std::unordered_map<std::string, std::function<void()>> systemCallback = {
959 { OH_DEFAULT_CUT, info->menuCallback.onCut }, { OH_DEFAULT_COPY, info->menuCallback.onCopy },
960 { OH_DEFAULT_SELECT_ALL, info->menuCallback.onSelectAll }, { OH_DEFAULT_PASTE, info->menuCallback.onPaste },
961 { OH_DEFAULT_TRANSLATE, info->menuCallback.onTranslate },
962 { OH_DEFAULT_SEARCH, info->menuCallback.onSearch },
963 { OH_DEFAULT_SHARE, info->menuCallback.onShare },
964 { OH_DEFAULT_CAMERA_INPUT, info->menuCallback.onCameraInput },
965 { OH_DEFAULT_AI_WRITE, info->menuCallback.onAIWrite },
966 { OH_DEFAULT_AI_MENU_PHONE, ConvertToVoidFunction(
967 info->menuCallback.onAIMenuOption, OH_DEFAULT_AI_MENU_PHONE) },
968 { OH_DEFAULT_AI_MENU_URL, ConvertToVoidFunction(
969 info->menuCallback.onAIMenuOption, OH_DEFAULT_AI_MENU_URL) },
970 { OH_DEFAULT_AI_MENU_EMAIL, ConvertToVoidFunction(
971 info->menuCallback.onAIMenuOption, OH_DEFAULT_AI_MENU_EMAIL) },
972 { OH_DEFAULT_AI_MENU_ADDRESS, ConvertToVoidFunction(
973 info->menuCallback.onAIMenuOption, OH_DEFAULT_AI_MENU_ADDRESS) },
974 { OH_DEFAULT_AI_MENU_DATETIME, ConvertToVoidFunction(
975 info->menuCallback.onAIMenuOption, OH_DEFAULT_AI_MENU_DATETIME) },
976 { OH_DEFAULT_ASK_CELIA, info->menuCallback.onAskCelia }
977 };
978 return systemCallback;
979 }
980
IsSystemMenuItemEnabled(const std::shared_ptr<SelectOverlayInfo> & info,const std::string & id)981 bool IsSystemMenuItemEnabled(const std::shared_ptr<SelectOverlayInfo>& info, const std::string& id)
982 {
983 CHECK_NULL_RETURN(info, true);
984 auto isEnabledFunc = isMenuItemEnabledFuncMap.find(id);
985 return isEnabledFunc == isMenuItemEnabledFuncMap.end() ? true : (isEnabledFunc->second)(info->menuInfo);
986 }
987
GetSystemIconPath(const std::string & id,const std::string & iconPath)988 std::string GetSystemIconPath(const std::string& id, const std::string& iconPath)
989 {
990 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
991 CHECK_NULL_RETURN(pipeline, iconPath);
992 auto iconTheme = pipeline->GetTheme<IconTheme>();
993 CHECK_NULL_RETURN(iconTheme, iconPath);
994 if (id == OH_DEFAULT_CUT) {
995 return iconTheme->GetIconPath(InternalResource::ResourceId::IC_CUT_SVG);
996 }
997 if (id == OH_DEFAULT_COPY) {
998 return iconTheme->GetIconPath(InternalResource::ResourceId::IC_COPY_SVG);
999 }
1000 if (id == OH_DEFAULT_SELECT_ALL) {
1001 return iconTheme->GetIconPath(InternalResource::ResourceId::IC_SELECT_ALL_SVG);
1002 }
1003 if (id == OH_DEFAULT_TRANSLATE) {
1004 return iconTheme->GetIconPath(InternalResource::ResourceId::IC_TRANSLATE_SVG);
1005 }
1006 if (id == OH_DEFAULT_SEARCH) {
1007 return iconTheme->GetIconPath(InternalResource::ResourceId::IC_SEARCH_SVG);
1008 }
1009 if (id == OH_DEFAULT_SHARE) {
1010 return iconTheme->GetIconPath(InternalResource::ResourceId::IC_SHARE_SVG);
1011 }
1012 if (id == OH_DEFAULT_CAMERA_INPUT) {
1013 return iconTheme->GetIconPath(InternalResource::ResourceId::IC_TAKEPHOTO_SVG);
1014 }
1015 if (id == OH_DEFAULT_AI_WRITE) {
1016 return iconTheme->GetIconPath(InternalResource::ResourceId::IC_AI_WRITE_SVG);
1017 }
1018 return iconPath;
1019 }
1020
GetItemContent(const std::string & id,const std::string & content,const std::shared_ptr<SelectOverlayInfo> & info=nullptr)1021 std::string GetItemContent(const std::string& id, const std::string& content,
1022 const std::shared_ptr<SelectOverlayInfo>& info = nullptr)
1023 {
1024 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
1025 CHECK_NULL_RETURN(pipeline, content);
1026 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
1027 CHECK_NULL_RETURN(textOverlayTheme, content);
1028 if (id == OH_DEFAULT_CUT) {
1029 return textOverlayTheme->GetCutLabel();
1030 }
1031 if (id == OH_DEFAULT_COPY) {
1032 return textOverlayTheme->GetCopyLabel();
1033 }
1034 if (id == OH_DEFAULT_SELECT_ALL) {
1035 return textOverlayTheme->GetSelectAllLabel();
1036 }
1037 if (id == OH_DEFAULT_PASTE) {
1038 return textOverlayTheme->GetPasteLabel();
1039 }
1040 if (id == OH_DEFAULT_TRANSLATE) {
1041 return textOverlayTheme->GetTranslateLabel();
1042 }
1043 if (id == OH_DEFAULT_SEARCH) {
1044 return textOverlayTheme->GetSearchLabel();
1045 }
1046 if (id == OH_DEFAULT_SHARE) {
1047 return textOverlayTheme->GetShareLabel();
1048 }
1049 if (id == OH_DEFAULT_AI_WRITE) {
1050 return textOverlayTheme->GetAIWrite();
1051 }
1052 if (id == OH_DEFAULT_CAMERA_INPUT) {
1053 return textOverlayTheme->GetCameraInput();
1054 }
1055 if (IsAIMenuOption(id)) {
1056 if (info) {
1057 return textOverlayTheme->GetAiMenuOptionName(info->menuInfo.aiMenuOptionType);
1058 } else {
1059 return textOverlayTheme->GetAiMenuOptionName(AI_ID_TYPE_MAP[id]);
1060 }
1061 }
1062 if (id == OH_DEFAULT_ASK_CELIA) {
1063 return textOverlayTheme->GetAskCelia();
1064 }
1065 return content;
1066 }
1067
AddParams(const MenuOptionsParam & item,std::function<void ()> callback,std::vector<OptionParam> & params)1068 void AddParams(const MenuOptionsParam& item, std::function<void()> callback, std::vector<OptionParam>& params)
1069 {
1070 params.emplace_back(
1071 GetItemContent(item.id, item.content.value_or("")), "", item.labelInfo.value_or(""), callback);
1072 if (item.symbolId.has_value()) {
1073 params.back().symbolId = item.symbolId.value();
1074 }
1075 params.back().disableSystemClick = true;
1076 }
1077
CloseOverlayIfNecessary(const RefPtr<SelectOverlayManager> & overlayManager)1078 void CloseOverlayIfNecessary(const RefPtr<SelectOverlayManager>& overlayManager)
1079 {
1080 CHECK_NULL_VOID(overlayManager);
1081 overlayManager->DestroySelectOverlay(true);
1082 auto contentOverlayManager = overlayManager->GetSelectContentOverlayManager();
1083 CHECK_NULL_VOID(contentOverlayManager);
1084 contentOverlayManager->CloseCurrent(true, CloseReason::CLOSE_REASON_TOOL_BAR);
1085 }
1086
GetCreateMenuOptionsParams(const std::vector<MenuOptionsParam> & menuOptionItems,const std::shared_ptr<SelectOverlayInfo> & info,int32_t startIndex)1087 std::vector<OptionParam> GetCreateMenuOptionsParams(const std::vector<MenuOptionsParam>& menuOptionItems,
1088 const std::shared_ptr<SelectOverlayInfo>& info, int32_t startIndex)
1089 {
1090 auto id = Container::CurrentIdSafelyWithCheck();
1091 std::vector<OptionParam> params;
1092 const auto systemCallback = GetSystemCallback(info);
1093 int32_t itemNum = 0;
1094 for (auto item : menuOptionItems) {
1095 if (itemNum < startIndex) {
1096 itemNum++;
1097 continue;
1098 }
1099 std::function<void()> systemEvent;
1100 auto clickCallback = systemCallback.find(item.id);
1101 if (clickCallback != systemCallback.end()) {
1102 systemEvent = clickCallback->second;
1103 }
1104 auto callback = [onCreateCallback = info->onCreateCallback, systemEvent, item, id]() {
1105 ContainerScope scope(id);
1106 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
1107 CHECK_NULL_VOID(pipeline);
1108 auto overlayManager = pipeline->GetSelectOverlayManager();
1109 CHECK_NULL_VOID(overlayManager);
1110 bool result = false;
1111 if (onCreateCallback.onMenuItemClick) {
1112 MenuItemParam menuItem;
1113 menuItem.menuOptionsParam = item;
1114 int32_t start = -1;
1115 int32_t end = -1;
1116 if (onCreateCallback.textRangeCallback) {
1117 onCreateCallback.textRangeCallback(start, end);
1118 }
1119 menuItem.start = start;
1120 menuItem.end = end;
1121 result = onCreateCallback.onMenuItemClick(menuItem);
1122 }
1123 if (!result && systemEvent) {
1124 systemEvent();
1125 }
1126 if (!systemEvent && !result) {
1127 CloseOverlayIfNecessary(overlayManager);
1128 }
1129 };
1130 AddParams(item, std::move(callback), params);
1131 params.back().enabled = IsSystemMenuItemEnabled(info, item.id);
1132 params.back().isAIMenuOption = IsAIMenuOption(item.id);
1133 params.back().isAskCeliaOption = IsAskCeliaOption(item.id);
1134 params.back().icon = item.icon.value_or("");
1135 itemNum++;
1136 }
1137 return params;
1138 }
1139
1140 #ifdef OHOS_PLATFORM
CreateMenuTextNode(const std::string & value,const RefPtr<FrameNode> & parent,bool isAIMenuEnabled=false)1141 RefPtr<FrameNode> CreateMenuTextNode(const std::string& value, const RefPtr<FrameNode>& parent,
1142 bool isAIMenuEnabled = false)
1143 {
1144 auto textId = ElementRegister::GetInstance()->MakeUniqueId();
1145 auto textNode = FrameNode::CreateFrameNode(V2::TEXT_ETS_TAG, textId, AceType::MakeRefPtr<TextPattern>());
1146 CHECK_NULL_RETURN(textNode, nullptr);
1147 auto textProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
1148 CHECK_NULL_RETURN(textProperty, nullptr);
1149 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
1150 CHECK_NULL_RETURN(pipeline, nullptr);
1151 auto theme = pipeline->GetTheme<SelectTheme>();
1152 CHECK_NULL_RETURN(theme, nullptr);
1153 textProperty->UpdateMaxLines(1);
1154 textProperty->UpdateTextOverflow(TextOverflow::ELLIPSIS);
1155 textProperty->UpdateFontSize(theme->GetMenuFontSize());
1156 textProperty->UpdateFontWeight(FontWeight::REGULAR);
1157 textProperty->UpdateTextColor(Color::TRANSPARENT);
1158 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
1159 if (isAIMenuEnabled == true && textOverlayTheme) {
1160 TextStyle textStyle;
1161 textStyle.SetFontSize(theme->GetMenuFontSize());
1162 textStyle.SetFontWeight(FontWeight::REGULAR);
1163 auto textSize = MeasureUtil::MeasureTextSize(textStyle, value);
1164 FontForegroudGradiantColor colorInfo;
1165 colorInfo.points = { NG::PointF(0, 0),
1166 NG::PointF(static_cast<float>(textSize.Width()), static_cast<float>(textSize.Height())) };
1167 colorInfo.colors = textOverlayTheme->GetAiMenuFontGradientColors();
1168 colorInfo.scalars = textOverlayTheme->GetAiMenuFontGradientScalars();
1169 textProperty->UpdateFontForegroudGradiantColor(colorInfo);
1170 }
1171
1172 auto textRenderContext = textNode->GetRenderContext();
1173 CHECK_NULL_RETURN(textRenderContext, nullptr);
1174 textRenderContext->UpdateForegroundColor(theme->GetMenuFontColor());
1175 textProperty->UpdateContent(value);
1176 textNode->MountToParent(parent);
1177 textNode->MarkModifyDone();
1178 return textNode;
1179 }
1180
SetPasteNodeProperties(const RefPtr<FrameNode> & pasteNode,const RefPtr<SelectTheme> & theme,bool enabled)1181 void SetPasteNodeProperties(const RefPtr<FrameNode>& pasteNode, const RefPtr<SelectTheme>& theme, bool enabled)
1182 {
1183 CHECK_NULL_VOID(pasteNode);
1184 CHECK_NULL_VOID(theme);
1185 auto pasteLayoutProperty = pasteNode->GetLayoutProperty<SecurityComponentLayoutProperty>();
1186 CHECK_NULL_VOID(pasteLayoutProperty);
1187 auto pastePaintProperty = pasteNode->GetPaintProperty<SecurityComponentPaintProperty>();
1188 CHECK_NULL_VOID(pastePaintProperty);
1189 pastePaintProperty->UpdateBackgroundColor(Color::TRANSPARENT);
1190 pasteLayoutProperty->UpdateBackgroundBorderRadius(BorderRadiusProperty(theme->GetInnerBorderRadius()));
1191 pasteLayoutProperty->UpdateFontSize(theme->GetMenuFontSize());
1192 pasteLayoutProperty->UpdateFontWeight(FontWeight::REGULAR);
1193 pastePaintProperty->UpdateFontColor(theme->GetMenuFontColor());
1194 pasteLayoutProperty->UpdateStateEffect(true);
1195 auto horInterval = static_cast<float>(theme->GetMenuIconPadding().ConvertToPx()) -
1196 static_cast<float>(theme->GetOutPadding().ConvertToPx());
1197 auto pasteButtonRenderContext = pasteNode->GetRenderContext();
1198 CHECK_NULL_VOID(pasteButtonRenderContext);
1199 pasteLayoutProperty->UpdateBackgroundLeftPadding(Dimension(horInterval));
1200 pasteLayoutProperty->UpdateTextIconSpace(
1201 Dimension(theme->GetIconContentPadding().ConvertToPx() * PASTEBUTTON_ICON_CONTENT_PADDING_COUNT));
1202 pasteButtonRenderContext->UpdateOpacity(1.0);
1203 }
1204
UpdatePasteOpacityFont(bool isPaste,RefPtr<FrameNode> & leftRowNode,OptionParam & param,const RefPtr<SelectTheme> & theme,const RefPtr<FrameNode> & menuItem)1205 void UpdatePasteOpacityFont(bool isPaste, RefPtr<FrameNode>& leftRowNode, OptionParam& param,
1206 const RefPtr<SelectTheme>& theme, const RefPtr<FrameNode>& menuItem)
1207 {
1208 CHECK_NULL_VOID(leftRowNode);
1209 auto leftRowRenderContext = leftRowNode->GetRenderContext();
1210 CHECK_NULL_VOID(leftRowRenderContext);
1211 if (isPaste) {
1212 if (!param.enabled) {
1213 leftRowRenderContext->UpdateOpacity(theme->GetDisabledFontColorAlpha());
1214 leftRowNode->MarkModifyDone();
1215 }
1216 }
1217 auto menuItemPattern = menuItem->GetPattern<MenuItemPattern>();
1218 CHECK_NULL_VOID(menuItemPattern);
1219 auto eventHub = menuItemPattern->GetOrCreateEventHub<MenuItemEventHub>();
1220 CHECK_NULL_VOID(eventHub);
1221 eventHub->SetSelectedChangeEvent([action = param.action](bool isSelected) {
1222 if (isSelected) {
1223 action();
1224 }
1225 });
1226 eventHub->SetEnabled(param.enabled);
1227 auto focusHub = menuItem->GetFocusHub();
1228 CHECK_NULL_VOID(focusHub);
1229 focusHub->SetEnabled(param.enabled);
1230 if (menuItemPattern->IsDisabled()) {
1231 leftRowRenderContext->UpdateOpacity(theme->GetDisabledFontColorAlpha());
1232 leftRowNode->MarkModifyDone();
1233 }
1234 menuItemPattern->SetBlockClick(param.disableSystemClick);
1235 }
1236
SetMenuItemSymbolIcon(const RefPtr<FrameNode> & menuItem,const OptionParam & param,RefPtr<FrameNode> & leftRow)1237 void SetMenuItemSymbolIcon(const RefPtr<FrameNode>& menuItem, const OptionParam& param, RefPtr<FrameNode>& leftRow)
1238 {
1239 auto symbol = FrameNode::GetOrCreateFrameNode(V2::SYMBOL_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
1240 []() { return AceType::MakeRefPtr<TextPattern>(); });
1241 CHECK_NULL_VOID(symbol);
1242 auto layoutProperty = symbol->GetLayoutProperty<TextLayoutProperty>();
1243 CHECK_NULL_VOID(layoutProperty);
1244 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
1245 CHECK_NULL_VOID(pipeline);
1246 auto theme = pipeline->GetTheme<SelectTheme>();
1247 CHECK_NULL_VOID(theme);
1248 layoutProperty->UpdateFontSize(theme->GetEndIconWidth());
1249 layoutProperty->UpdateSymbolColorList({ theme->GetMenuIconColor() });
1250 layoutProperty->UpdateAlignment(Alignment::CENTER_LEFT);
1251 MarginProperty margin;
1252 if (param.symbolId != 0) {
1253 layoutProperty->UpdateSymbolSourceInfo(SymbolSourceInfo(param.symbolId));
1254 margin.right = CalcLength(theme->GetIconContentPadding());
1255 } else {
1256 margin.right = CalcLength(theme->GetIconContentPadding() + theme->GetIconSideLength());
1257 }
1258 layoutProperty->UpdateMargin(margin);
1259 symbol->MountToParent(leftRow);
1260 }
1261
UpdateIconSrc(RefPtr<FrameNode> & node,const Dimension & horizontalSize,const Dimension & verticalSize,const Color & color,const bool & useDefaultIcon)1262 void UpdateIconSrc(RefPtr<FrameNode>& node, const Dimension& horizontalSize, const Dimension& verticalSize,
1263 const Color& color, const bool& useDefaultIcon)
1264 {
1265 auto props = node->GetLayoutProperty<ImageLayoutProperty>();
1266 CHECK_NULL_VOID(props);
1267 props->UpdateAlignment(Alignment::CENTER);
1268 CalcSize idealSize = { CalcLength(horizontalSize), CalcLength(verticalSize) };
1269 MeasureProperty layoutConstraint;
1270 layoutConstraint.selfIdealSize = idealSize;
1271 props->UpdateCalcLayoutProperty(layoutConstraint);
1272 if (useDefaultIcon) {
1273 auto iconRenderProperty = node->GetPaintProperty<ImageRenderProperty>();
1274 CHECK_NULL_VOID(iconRenderProperty);
1275 iconRenderProperty->UpdateSvgFillColor(color);
1276 }
1277 }
1278
SetMenuItemImageIcon(const RefPtr<FrameNode> & menuItem,const OptionParam & param,RefPtr<FrameNode> & leftRow)1279 void SetMenuItemImageIcon(const RefPtr<FrameNode>& menuItem, const OptionParam& param, RefPtr<FrameNode>& leftRow)
1280 {
1281 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
1282 CHECK_NULL_VOID(pipeline);
1283 auto theme = pipeline->GetTheme<SelectTheme>();
1284 CHECK_NULL_VOID(theme);
1285 auto iconNode = FrameNode::CreateFrameNode(
1286 V2::IMAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ImagePattern>());
1287 CHECK_NULL_VOID(iconNode);
1288 auto props = iconNode->GetLayoutProperty<ImageLayoutProperty>();
1289 CHECK_NULL_VOID(props);
1290 MarginProperty margin;
1291 bool iconIsEmpty = param.icon.empty();
1292 if (!iconIsEmpty) {
1293 ImageSourceInfo imageSourceInfo(param.icon, pipeline->GetBundleName(), pipeline->GetModuleName());
1294 props->UpdateImageSourceInfo(imageSourceInfo);
1295 }
1296 margin.right = CalcLength(theme->GetIconContentPadding());
1297 Ace::NG::UpdateIconSrc(
1298 iconNode, theme->GetIconSideLength(), theme->GetIconSideLength(), theme->GetMenuIconColor(), iconIsEmpty);
1299 props->UpdateMargin(margin);
1300 iconNode->MarkModifyDone();
1301 iconNode->MountToParent(leftRow);
1302 }
1303
SetupMenuItemChildrenAndFocus(const RefPtr<FrameNode> & menuItem,const std::string & content,const std::string & labelInfo,const RefPtr<SelectTheme> & theme,OptionParam & param,bool isPaste)1304 void SetupMenuItemChildrenAndFocus(const RefPtr<FrameNode>& menuItem, const std::string& content,
1305 const std::string& labelInfo, const RefPtr<SelectTheme>& theme, OptionParam& param, bool isPaste)
1306 {
1307 auto leftRow = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
1308 AceType::MakeRefPtr<LinearLayoutPattern>(false));
1309 CHECK_NULL_VOID(leftRow);
1310 auto leftRowLayoutProps = leftRow->GetLayoutProperty<LinearLayoutProperty>();
1311 CHECK_NULL_VOID(leftRowLayoutProps);
1312 leftRowLayoutProps->UpdateMainAxisAlign(FlexAlign::FLEX_START);
1313 leftRowLayoutProps->UpdateCrossAxisAlign(FlexAlign::CENTER);
1314 leftRowLayoutProps->UpdateSpace(theme->GetIconContentPadding());
1315 if (!isPaste) {
1316 if (param.symbolId != 0) {
1317 SetMenuItemSymbolIcon(menuItem, param, leftRow);
1318 } else {
1319 SetMenuItemImageIcon(menuItem, param, leftRow);
1320 }
1321 }
1322 auto leftTextNode = CreateMenuTextNode(content, leftRow, param.isAIMenuOption || param.isAskCeliaOption);
1323 CHECK_NULL_VOID(leftTextNode);
1324 leftRow->MountToParent(menuItem);
1325 leftRow->MarkModifyDone();
1326 auto rightRow = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
1327 AceType::MakeRefPtr<LinearLayoutPattern>(false));
1328 CHECK_NULL_VOID(rightRow);
1329 auto rightRowLayoutProps = rightRow->GetLayoutProperty<LinearLayoutProperty>();
1330 CHECK_NULL_VOID(rightRowLayoutProps);
1331 rightRowLayoutProps->UpdateMainAxisAlign(FlexAlign::CENTER);
1332 rightRowLayoutProps->UpdateCrossAxisAlign(FlexAlign::CENTER);
1333 rightRowLayoutProps->UpdateSpace(theme->GetIconContentPadding());
1334 auto rightTextNode = CreateMenuTextNode(labelInfo, rightRow, param.isAIMenuOption || param.isAskCeliaOption);
1335 CHECK_NULL_VOID(rightTextNode);
1336 rightRow->MountToParent(menuItem);
1337 auto rightTextRenderContext = rightTextNode->GetRenderContext();
1338 CHECK_NULL_VOID(rightTextRenderContext);
1339 auto menuItemPattern = menuItem->GetPattern<MenuItemPattern>();
1340 CHECK_NULL_VOID(menuItemPattern);
1341 UpdatePasteOpacityFont(isPaste, leftRow, param, theme, menuItem);
1342 rightTextRenderContext->UpdateOpacity(theme->GetDisabledFontColorAlpha());
1343 rightTextNode->MarkModifyDone();
1344 }
1345
SetPasteMenuItemEvent(const RefPtr<FrameNode> & menuItem,const RefPtr<FrameNode> & pasteNode,OptionParam & param,const RefPtr<SelectTheme> & theme)1346 void SetPasteMenuItemEvent(const RefPtr<FrameNode>& menuItem, const RefPtr<FrameNode>& pasteNode, OptionParam& param,
1347 const RefPtr<SelectTheme>& theme)
1348 {
1349 auto eventHub = menuItem->GetOrCreateEventHub<MenuItemEventHub>();
1350 CHECK_NULL_VOID(eventHub);
1351 eventHub->SetEnabled(false);
1352 auto focusHub = menuItem->GetFocusHub();
1353 CHECK_NULL_VOID(focusHub);
1354 focusHub->SetEnabled(false);
1355 auto pasteEventHub = pasteNode->GetOrCreateEventHub<EventHub>();
1356 CHECK_NULL_VOID(pasteEventHub);
1357 pasteEventHub->SetEnabled(param.enabled);
1358 auto pasteFocusHub = pasteNode->GetFocusHub();
1359 CHECK_NULL_VOID(pasteFocusHub);
1360 pasteFocusHub->SetEnabled(param.enabled);
1361 auto id = Container::CurrentIdSafelyWithCheck();
1362 pasteNode->GetOrCreateGestureEventHub()->SetUserOnClick([action = param.action, id](GestureEvent& info) {
1363 ContainerScope scope(id);
1364 if (!PasteButtonModelNG::GetInstance()->IsClickResultSuccess(info)) {
1365 return;
1366 }
1367 if (action) {
1368 action();
1369 }
1370 });
1371 auto menuItemPattern = menuItem->GetPattern<MenuItemPattern>();
1372 CHECK_NULL_VOID(menuItemPattern);
1373 menuItemPattern->SetBlockClick(param.disableSystemClick);
1374 menuItemPattern->SetPasteButton(pasteNode);
1375 }
1376
CreateRelativeContainer(const RefPtr<FrameNode> & menuItem,const RefPtr<FrameNode> & pasteNode)1377 RefPtr<FrameNode> CreateRelativeContainer(const RefPtr<FrameNode>& menuItem, const RefPtr<FrameNode>& pasteNode)
1378 {
1379 auto relativeContainer =
1380 FrameNode::GetOrCreateFrameNode(V2::RELATIVE_CONTAINER_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
1381 []() { return AceType::MakeRefPtr<OHOS::Ace::NG::RelativeContainerPattern>(); });
1382 CHECK_NULL_RETURN(relativeContainer, nullptr);
1383 auto relativeContainerLayoutProperty = relativeContainer->GetLayoutProperty();
1384 CHECK_NULL_RETURN(relativeContainerLayoutProperty, nullptr);
1385 relativeContainerLayoutProperty->UpdateUserDefinedIdealSize(
1386 { CalcLength(0.0, DimensionUnit::AUTO), CalcLength(0.0, DimensionUnit::AUTO) });
1387 auto menuItemRow = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
1388 AceType::MakeRefPtr<LinearLayoutPattern>(false));
1389 CHECK_NULL_RETURN(menuItemRow, nullptr);
1390 auto buttonRow = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
1391 AceType::MakeRefPtr<LinearLayoutPattern>(false));
1392 CHECK_NULL_RETURN(buttonRow, nullptr);
1393 std::string menuItemRowId = "__menuItemRow__";
1394 menuItemRow->UpdateInspectorId(menuItemRowId);
1395 auto buttonRowLayoutProperty = buttonRow->GetLayoutProperty();
1396 CHECK_NULL_RETURN(buttonRowLayoutProperty, nullptr);
1397 buttonRowLayoutProperty->UpdateAlignRules(
1398 { { AlignDirection::LEFT, { .anchor = menuItemRowId, .horizontal = HorizontalAlign::START } },
1399 { AlignDirection::TOP, { .anchor = menuItemRowId, .vertical = VerticalAlign::TOP } },
1400 { AlignDirection::RIGHT, { .anchor = menuItemRowId, .horizontal = HorizontalAlign::END } },
1401 { AlignDirection::BOTTOM, { .anchor = menuItemRowId, .vertical = VerticalAlign::BOTTOM } } });
1402 auto menuItemLayoutProperty = menuItem->GetLayoutProperty();
1403 CHECK_NULL_RETURN(menuItemLayoutProperty, nullptr);
1404 menuItemLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
1405 menuItem->MountToParent(menuItemRow);
1406 pasteNode->MountToParent(buttonRow);
1407 relativeContainer->AddChild(menuItemRow);
1408 relativeContainer->AddChild(buttonRow);
1409 return relativeContainer;
1410 }
1411
CreateMenuItemPaste(const std::string & labelInfo,RefPtr<FrameNode> innerMenuNode,OptionParam & param,size_t index)1412 RefPtr<FrameNode> CreateMenuItemPaste(
1413 const std::string& labelInfo, RefPtr<FrameNode> innerMenuNode, OptionParam& param, size_t index)
1414 {
1415 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
1416 CHECK_NULL_RETURN(pipeline, nullptr);
1417 auto theme = pipeline->GetTheme<SelectTheme>();
1418 CHECK_NULL_RETURN(theme, nullptr);
1419 auto pasteNode = PasteButtonModelNG::GetInstance()->CreateNode(
1420 static_cast<int32_t>(PasteButtonPasteDescription::PASTE), static_cast<int32_t>(PasteButtonIconStyle::ICON_NULL),
1421 static_cast<int32_t>(ButtonType::NORMAL), true, param.symbolId);
1422 CHECK_NULL_RETURN(pasteNode, nullptr);
1423 SetPasteNodeProperties(pasteNode, theme, param.enabled);
1424 auto menuItem =
1425 FrameNode::GetOrCreateFrameNode(V2::MENU_ITEM_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
1426 [index]() { return AceType::MakeRefPtr<MenuItemPattern>(false, index); });
1427 CHECK_NULL_RETURN(menuItem, nullptr);
1428 BorderRadiusProperty border;
1429 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1430 border.SetRadius(theme->GetMenuDefaultInnerRadius());
1431 } else {
1432 border.SetRadius(theme->GetInnerBorderRadius());
1433 }
1434 auto renderContext = menuItem->GetRenderContext();
1435 CHECK_NULL_RETURN(renderContext, nullptr);
1436 renderContext->UpdateBorderRadius(border);
1437 SetupMenuItemChildrenAndFocus(menuItem, "", labelInfo, theme, param, true);
1438
1439 SetPasteMenuItemEvent(menuItem, pasteNode, param, theme);
1440 auto relativeContainer = CreateRelativeContainer(menuItem, pasteNode);
1441 CHECK_NULL_RETURN(relativeContainer, nullptr);
1442 menuItem->MarkModifyDone();
1443 pasteNode->MarkModifyDone();
1444 relativeContainer->MountToParent(innerMenuNode);
1445 relativeContainer->MarkModifyDone();
1446 return relativeContainer;
1447 }
1448
CreateMenuItem(const std::string & content,const std::string & labelInfo,RefPtr<FrameNode> innerMenuNode,OptionParam & param,size_t index)1449 RefPtr<FrameNode> CreateMenuItem(const std::string& content, const std::string& labelInfo,
1450 RefPtr<FrameNode> innerMenuNode, OptionParam& param, size_t index)
1451 {
1452 CHECK_NULL_RETURN(innerMenuNode, nullptr);
1453 auto* stack = ViewStackProcessor::GetInstance();
1454 CHECK_NULL_RETURN(stack, nullptr);
1455 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
1456 CHECK_NULL_RETURN(pipeline, nullptr);
1457 auto menuItem =
1458 FrameNode::GetOrCreateFrameNode(V2::MENU_ITEM_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
1459 [index]() { return AceType::MakeRefPtr<MenuItemPattern>(false, index); });
1460 CHECK_NULL_RETURN(menuItem, nullptr);
1461 auto renderContext = menuItem->GetRenderContext();
1462 CHECK_NULL_RETURN(renderContext, nullptr);
1463 auto theme = pipeline->GetTheme<SelectTheme>();
1464 CHECK_NULL_RETURN(theme, nullptr);
1465 BorderRadiusProperty border;
1466 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1467 border.SetRadius(theme->GetMenuDefaultInnerRadius());
1468 } else {
1469 border.SetRadius(theme->GetInnerBorderRadius());
1470 }
1471 renderContext->UpdateBorderRadius(border);
1472 SetupMenuItemChildrenAndFocus(menuItem, content, labelInfo, theme, param, false);
1473 menuItem->MountToParent(innerMenuNode);
1474 menuItem->MarkModifyDone();
1475 return menuItem;
1476 }
1477 #endif
1478
GetMenuWrapper(std::vector<OptionParam> & params,const RefPtr<TextOverlayTheme> & textOverlayTheme)1479 RefPtr<FrameNode> GetMenuWrapper(std::vector<OptionParam>& params, const RefPtr<TextOverlayTheme>& textOverlayTheme)
1480 {
1481 CHECK_NULL_RETURN(textOverlayTheme, nullptr);
1482 RefPtr<FrameNode> menuWrapper = nullptr;
1483 auto showShortcut = textOverlayTheme->GetShowShortcut();
1484 auto targetNodeId = ElementRegister::GetInstance()->MakeUniqueId();
1485 if (showShortcut) {
1486 auto* stack = ViewStackProcessor::GetInstance();
1487 CHECK_NULL_RETURN(stack, nullptr);
1488 auto innerMenuNode = FrameNode::GetOrCreateFrameNode(V2::MENU_ETS_TAG, stack->ClaimNodeId(), [targetNodeId]() {
1489 return AceType::MakeRefPtr<InnerMenuPattern>(targetNodeId, V2::MENU_ETS_TAG, MenuType::MULTI_MENU);
1490 });
1491 CHECK_NULL_RETURN(innerMenuNode, nullptr);
1492 #ifdef OHOS_PLATFORM
1493 RefPtr<FrameNode> menuItem = nullptr;
1494 for (size_t i = 0; i < params.size(); i++) {
1495 if (params[i].value == textOverlayTheme->GetPasteLabel()) {
1496 menuItem = CreateMenuItemPaste(params[i].labelInfo, innerMenuNode, params[i], i);
1497 } else {
1498 menuItem = CreateMenuItem(params[i].value, params[i].labelInfo, innerMenuNode, params[i], i);
1499 }
1500 if (!menuItem) {
1501 continue;
1502 }
1503 }
1504 menuWrapper = MenuView::Create(innerMenuNode, targetNodeId, "SelectOverlayMenuByRightClick",
1505 { .isShowInSubWindow = false, .type = MenuType::SELECT_OVERLAY_RIGHT_CLICK_MENU });
1506 menuWrapper->UpdateInspectorId("select_overlay_right_click_menuWrapper");
1507 #else
1508 menuWrapper = MenuView::Create(std::move(params), targetNodeId, "SelectOverlayMenuByRightClick",
1509 MenuType::SELECT_OVERLAY_RIGHT_CLICK_MENU, { .isShowInSubWindow = false });
1510 #endif
1511 } else {
1512 menuWrapper = MenuView::Create(std::move(params), targetNodeId, "SelectOverlayMenuByRightClick",
1513 MenuType::SELECT_OVERLAY_RIGHT_CLICK_MENU, { .isShowInSubWindow = false });
1514 }
1515 return menuWrapper;
1516 }
1517
FindAccessibleFocusNodeInExtMenu(const RefPtr<FrameNode> & extensionMenu)1518 RefPtr<UINode> FindAccessibleFocusNodeInExtMenu(const RefPtr<FrameNode>& extensionMenu)
1519 {
1520 CHECK_NULL_RETURN(extensionMenu, nullptr);
1521 auto child = extensionMenu->GetFirstChild();
1522 CHECK_NULL_RETURN(child, nullptr);
1523 while (child) {
1524 if (child->GetTag() == V2::OPTION_ETS_TAG) {
1525 bool isPasteOption = SelectContentOverlayManager::IsPasteOption(child);
1526 auto row = child->GetFirstChild();
1527 if (isPasteOption && row) {
1528 return row->GetFirstChild();
1529 }
1530 return child;
1531 }
1532 child = child->GetFirstChild();
1533 }
1534 return nullptr;
1535 }
1536
GetMenuOptionsParamsWithEditMenuOption(const std::shared_ptr<SelectOverlayInfo> & info,const std::vector<MenuItemParam> systemMenuItemParams)1537 std::vector<MenuOptionsParam> GetMenuOptionsParamsWithEditMenuOption(
1538 const std::shared_ptr<SelectOverlayInfo>& info, const std::vector<MenuItemParam> systemMenuItemParams)
1539 {
1540 std::vector<MenuOptionsParam> createMenuItems;
1541 CHECK_NULL_RETURN(info, createMenuItems);
1542 if (info->onCreateCallback.onPrepareMenuCallback && info->onCreateCallback.beforeOnPrepareMenuCallback) {
1543 info->onCreateCallback.beforeOnPrepareMenuCallback();
1544 }
1545 if (info->onCreateCallback.onCreateMenuCallback) {
1546 createMenuItems = info->onCreateCallback.onCreateMenuCallback(systemMenuItemParams);
1547 }
1548 CHECK_NULL_RETURN(info->onCreateCallback.onPrepareMenuCallback, createMenuItems);
1549 std::vector<MenuItemParam> menuItemParams;
1550 for (const auto& optionsParamItem : createMenuItems) {
1551 MenuItemParam menuItemParam;
1552 menuItemParam.menuOptionsParam = optionsParamItem;
1553 menuItemParams.push_back(menuItemParam);
1554 }
1555 createMenuItems = info->onCreateCallback.onPrepareMenuCallback(menuItemParams);
1556 return createMenuItems;
1557 }
1558
GetCustomMenuItemSymbolFunc(const MenuOptionsParam & item)1559 std::function<void(WeakPtr<NG::FrameNode>)> GetCustomMenuItemSymbolFunc(const MenuOptionsParam& item)
1560 {
1561 std::function<void(WeakPtr<NG::FrameNode>)> symbolFunc = nullptr;
1562 if (item.symbolId.has_value() && item.symbolId.value() != 0) {
1563 auto symbolId = item.symbolId.value();
1564 symbolFunc = [symbolId](WeakPtr<NG::FrameNode> weak) {
1565 auto symbolNode = weak.Upgrade();
1566 SymbolModelNG::InitialSymbol(AceType::RawPtr(symbolNode), symbolId);
1567 };
1568 }
1569 return symbolFunc;
1570 }
1571 } // namespace
1572
SelectOverlayNode(const RefPtr<Pattern> & pattern)1573 SelectOverlayNode::SelectOverlayNode(const RefPtr<Pattern>& pattern)
1574 : FrameNode(V2::SELECT_OVERLAY_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), pattern)
1575 {
1576 stateFuncs_[FrameNodeStatus::VISIBLE] = &SelectOverlayNode::DispatchVisibleState;
1577 stateFuncs_[FrameNodeStatus::VISIBLETOGONE] = &SelectOverlayNode::DispatchVisibleToGoneState;
1578 stateFuncs_[FrameNodeStatus::GONE] = &SelectOverlayNode::DispatchGoneState;
1579 stateFuncs_[FrameNodeStatus::GONETOVISIBLE] = &SelectOverlayNode::DispatchGoneToVisibleState;
1580 }
1581
DispatchVisibleState(FrameNodeType type,FrameNodeTrigger trigger)1582 void SelectOverlayNode::DispatchVisibleState(FrameNodeType type, FrameNodeTrigger trigger)
1583 {
1584 AnimationOption option;
1585 option.SetDuration(MENU_HIDE_ANIMATION_DURATION);
1586 option.SetCurve(Curves::SHARP);
1587
1588 switch (trigger) {
1589 case FrameNodeTrigger::HIDE:
1590 SetFrameNodeStatus(type, FrameNodeStatus::VISIBLETOGONE);
1591 AnimationUtils::Animate(
1592 option,
1593 [weak = WeakClaim(this), type, id = Container::CurrentId()]() {
1594 ContainerScope scope(id);
1595 auto node = weak.Upgrade();
1596 CHECK_NULL_VOID(node);
1597 node->SetFrameNodeOpacity(type, 0.0);
1598 },
1599 [weak = WeakClaim(this), type, id = Container::CurrentId()]() {
1600 ContainerScope scope(id);
1601 auto node = weak.Upgrade();
1602 CHECK_NULL_VOID(node);
1603 node->ExecuteOverlayStatus(type, FrameNodeTrigger::HIDDEN);
1604 },
1605 nullptr, GetContextRefPtr());
1606 break;
1607 case FrameNodeTrigger::SHOW:
1608 case FrameNodeTrigger::SHOWN:
1609 case FrameNodeTrigger::HIDDEN:
1610 default:
1611 break;
1612 }
1613 }
1614
DispatchVisibleToGoneState(FrameNodeType type,FrameNodeTrigger trigger)1615 void SelectOverlayNode::DispatchVisibleToGoneState(FrameNodeType type, FrameNodeTrigger trigger)
1616 {
1617 AnimationOption option;
1618 option.SetDuration(MENU_SHOW_ANIMATION_DURATION);
1619 option.SetCurve(Curves::SHARP);
1620
1621 switch (trigger) {
1622 case FrameNodeTrigger::SHOW:
1623 SetFrameNodeStatus(type, FrameNodeStatus::GONETOVISIBLE);
1624 SetFrameNodeVisibility(type, VisibleType::VISIBLE);
1625 AnimationUtils::Animate(
1626 option,
1627 [weak = WeakClaim(this), type, id = Container::CurrentId()]() {
1628 ContainerScope scope(id);
1629 auto node = weak.Upgrade();
1630 CHECK_NULL_VOID(node);
1631 node->SetFrameNodeOpacity(type, 1.0);
1632 },
1633 [weak = WeakClaim(this), type, id = Container::CurrentId()]() {
1634 ContainerScope scope(id);
1635 auto node = weak.Upgrade();
1636 CHECK_NULL_VOID(node);
1637 node->ExecuteOverlayStatus(type, FrameNodeTrigger::SHOWN);
1638 },
1639 nullptr, GetContextRefPtr());
1640 break;
1641 case FrameNodeTrigger::HIDDEN:
1642 SetFrameNodeStatus(type, FrameNodeStatus::GONE);
1643 SetFrameNodeVisibility(type, VisibleType::GONE);
1644 break;
1645 case FrameNodeTrigger::SHOWN:
1646 case FrameNodeTrigger::HIDE:
1647 default:
1648 break;
1649 }
1650 }
1651
DispatchGoneState(FrameNodeType type,FrameNodeTrigger trigger)1652 void SelectOverlayNode::DispatchGoneState(FrameNodeType type, FrameNodeTrigger trigger)
1653 {
1654 AnimationOption option;
1655 option.SetDuration(MENU_SHOW_ANIMATION_DURATION);
1656 option.SetCurve(Curves::SHARP);
1657
1658 switch (trigger) {
1659 case FrameNodeTrigger::SHOW:
1660 SetFrameNodeStatus(type, FrameNodeStatus::GONETOVISIBLE);
1661 SetFrameNodeVisibility(type, VisibleType::VISIBLE);
1662 AnimationUtils::Animate(
1663 option,
1664 [weak = WeakClaim(this), type, id = Container::CurrentId()]() {
1665 ContainerScope scope(id);
1666 auto node = weak.Upgrade();
1667 CHECK_NULL_VOID(node);
1668 node->SetFrameNodeOpacity(type, 1.0);
1669 },
1670 [weak = WeakClaim(this), type, id = Container::CurrentId()]() {
1671 ContainerScope scope(id);
1672 auto node = weak.Upgrade();
1673 CHECK_NULL_VOID(node);
1674 node->ExecuteOverlayStatus(type, FrameNodeTrigger::SHOWN);
1675 },
1676 nullptr, GetContextRefPtr());
1677 break;
1678 case FrameNodeTrigger::SHOWN:
1679 case FrameNodeTrigger::HIDE:
1680 case FrameNodeTrigger::HIDDEN:
1681 default:
1682 break;
1683 }
1684 }
1685
DispatchGoneToVisibleState(FrameNodeType type,FrameNodeTrigger trigger)1686 void SelectOverlayNode::DispatchGoneToVisibleState(FrameNodeType type, FrameNodeTrigger trigger)
1687 {
1688 AnimationOption option;
1689 option.SetDuration(MENU_HIDE_ANIMATION_DURATION);
1690 option.SetCurve(Curves::SHARP);
1691
1692 switch (trigger) {
1693 case FrameNodeTrigger::SHOWN:
1694 SetFrameNodeStatus(type, FrameNodeStatus::VISIBLE);
1695 break;
1696 case FrameNodeTrigger::HIDE:
1697 SetFrameNodeStatus(type, FrameNodeStatus::VISIBLETOGONE);
1698 AnimationUtils::Animate(
1699 option,
1700 [weak = WeakClaim(this), type, id = Container::CurrentId()]() {
1701 ContainerScope scope(id);
1702 auto node = weak.Upgrade();
1703 CHECK_NULL_VOID(node);
1704 node->SetFrameNodeOpacity(type, 0.0);
1705 },
1706 [weak = WeakClaim(this), type, id = Container::CurrentId()]() {
1707 ContainerScope scope(id);
1708 auto node = weak.Upgrade();
1709 CHECK_NULL_VOID(node);
1710 node->ExecuteOverlayStatus(type, FrameNodeTrigger::HIDDEN);
1711 },
1712 nullptr, GetContextRefPtr());
1713 break;
1714 case FrameNodeTrigger::SHOW:
1715 case FrameNodeTrigger::HIDDEN:
1716 break;
1717 default:
1718 break;
1719 }
1720 }
1721
CreateCustomSelectMenu(const std::shared_ptr<SelectOverlayInfo> & info)1722 RefPtr<UINode> CreateCustomSelectMenu(const std::shared_ptr<SelectOverlayInfo>& info)
1723 {
1724 CHECK_NULL_RETURN(info, nullptr);
1725 CHECK_NULL_RETURN(info->menuInfo.menuBuilder, nullptr);
1726 NG::ScopedViewStackProcessor builderViewStackProcessor;
1727 info->menuInfo.menuBuilder();
1728 auto customNode = NG::ViewStackProcessor::GetInstance()->Finish();
1729 CHECK_NULL_RETURN(customNode, nullptr);
1730 return customNode;
1731 }
1732
CreateSelectOverlayNode(const std::shared_ptr<SelectOverlayInfo> & info,SelectOverlayMode mode)1733 RefPtr<FrameNode> SelectOverlayNode::CreateSelectOverlayNode(
1734 const std::shared_ptr<SelectOverlayInfo>& info, SelectOverlayMode mode)
1735 {
1736 auto isShowHandleOnly = (mode == SelectOverlayMode::HANDLE_ONLY);
1737 if (info->isUsingMouse && !info->menuInfo.menuBuilder && !isShowHandleOnly) {
1738 return CreateMenuNode(info);
1739 }
1740 RefPtr<Pattern> selectOverlayPattern;
1741 if (info->isUseOverlayNG) {
1742 selectOverlayPattern = AceType::MakeRefPtr<SelectContentOverlayPattern>(info, mode);
1743 } else {
1744 selectOverlayPattern = AceType::MakeRefPtr<SelectOverlayPattern>(info, mode);
1745 }
1746 auto selectOverlayNode = AceType::MakeRefPtr<SelectOverlayNode>(selectOverlayPattern);
1747 selectOverlayNode->InitializePatternAndContext();
1748 ElementRegister::GetInstance()->AddUINode(selectOverlayNode);
1749 selectOverlayNode->CreateToolBar();
1750 selectOverlayNode->UpdateToolBar(true);
1751 auto selectContext = selectOverlayNode->GetRenderContext();
1752 selectContext->UpdateUseShadowBatching(true);
1753
1754 auto accessibilityProperty = selectOverlayNode->GetAccessibilityProperty<AccessibilityProperty>();
1755 if (accessibilityProperty) {
1756 accessibilityProperty->SetAccessibilityLevel("no");
1757 }
1758 return selectOverlayNode;
1759 }
1760
CreateCustomSelectOverlay(const std::shared_ptr<SelectOverlayInfo> & info)1761 void SelectOverlayNode::CreateCustomSelectOverlay(const std::shared_ptr<SelectOverlayInfo>& info)
1762 {
1763 selectMenu_ =
1764 FrameNode::GetOrCreateFrameNode(V2::MENU_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), []() {
1765 return AceType::MakeRefPtr<MenuPattern>(
1766 ElementRegister::GetInstance()->MakeUniqueId(), V2::MENU_ETS_TAG, MenuType::SELECT_OVERLAY_CUSTOM_MENU);
1767 });
1768 selectMenu_->MountToParent(Claim(this));
1769 TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY, "CreateCustomSelectOverlay by menu:%{public}d", selectMenu_->GetId());
1770 AddCustomMenuCallbacks(info);
1771 auto renderContext = selectMenu_->GetRenderContext();
1772 CHECK_NULL_VOID(renderContext);
1773 renderContext->UpdateClipEdge(false);
1774 renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
1775 renderContext->UpdateBackShadow(ShadowConfig::NoneShadow);
1776 auto layoutProperty = selectMenu_->GetLayoutProperty<MenuLayoutProperty>();
1777 auto customMenu = CreateCustomSelectMenu(info);
1778 CHECK_NULL_VOID(selectMenu_);
1779 CHECK_NULL_VOID(customMenu);
1780 customMenu->MountToParent(selectMenu_);
1781 auto pattern = GetPattern<SelectOverlayPattern>();
1782 CHECK_NULL_VOID(pattern);
1783 InitSelectMenuStatus(pattern->GetMode(), info, false);
1784 selectMenu_->MarkModifyDone();
1785 }
1786
MoreOrBackAnimation(bool isMore,bool noAnimation)1787 void SelectOverlayNode::MoreOrBackAnimation(bool isMore, bool noAnimation)
1788 {
1789 CHECK_NULL_VOID(!isDoingAnimation_);
1790 CHECK_NULL_VOID(selectMenu_);
1791 CHECK_NULL_VOID(selectMenuInner_);
1792 CHECK_NULL_VOID(extensionMenu_);
1793 CHECK_NULL_VOID(backButton_);
1794 if (isMore && !isExtensionMenu_) {
1795 MoreAnimation(noAnimation);
1796 } else if (!isMore && isExtensionMenu_) {
1797 BackAnimation(noAnimation);
1798 }
1799 }
1800
MoreAnimation(bool noAnimation)1801 void SelectOverlayNode::MoreAnimation(bool noAnimation)
1802 {
1803 auto extensionContext = extensionMenu_->GetRenderContext();
1804 CHECK_NULL_VOID(extensionContext);
1805 auto selectMenuInnerContext = selectMenuInner_->GetRenderContext();
1806 CHECK_NULL_VOID(selectMenuInnerContext);
1807
1808 auto extensionProperty = extensionMenu_->GetLayoutProperty();
1809 CHECK_NULL_VOID(extensionProperty);
1810 auto selectProperty = selectMenu_->GetLayoutProperty();
1811 CHECK_NULL_VOID(selectProperty);
1812 auto selectMenuInnerProperty = selectMenuInner_->GetLayoutProperty();
1813 CHECK_NULL_VOID(selectMenuInnerProperty);
1814 auto backButtonProperty = backButton_->GetLayoutProperty();
1815 CHECK_NULL_VOID(backButtonProperty);
1816
1817 auto pattern = GetPattern<SelectOverlayPattern>();
1818 CHECK_NULL_VOID(pattern);
1819 auto modifier = pattern->GetOverlayModifier();
1820 CHECK_NULL_VOID(modifier);
1821
1822 auto pipeline = GetContext();
1823 CHECK_NULL_VOID(pipeline);
1824
1825 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
1826 CHECK_NULL_VOID(textOverlayTheme);
1827
1828 auto shadowTheme = pipeline->GetTheme<ShadowTheme>();
1829 CHECK_NULL_VOID(shadowTheme);
1830
1831 isExtensionMenu_ = true;
1832
1833 extensionProperty->UpdateVisibility(VisibleType::VISIBLE);
1834 backButtonProperty->UpdateVisibility(VisibleType::VISIBLE);
1835 extensionMenuStatus_ = FrameNodeStatus::VISIBLE;
1836 UpdateMoreOrBackSymbolOptions(false, true);
1837 AnimationOption extensionOption;
1838 extensionOption.SetDuration(ANIMATION_DURATION2);
1839 extensionOption.SetCurve(Curves::FAST_OUT_SLOW_IN);
1840 auto toolbarHeight = textOverlayTheme->GetMenuToolbarHeight();
1841 auto frameSize = CalcSize(CalcLength(toolbarHeight.ConvertToPx()), CalcLength(toolbarHeight.ConvertToPx()));
1842 auto containerId = pipeline->GetInstanceId();
1843 AnimationUtils::Animate(
1844 extensionOption, [extensionContext, selectMenuInnerContext, id = containerId, shadowTheme]() {
1845 ContainerScope scope(id);
1846 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1847 extensionContext->UpdateOpacity(1.0);
1848 }
1849 extensionContext->UpdateTransformTranslate({ 0.0f, 0.0f, 0.0f });
1850 auto colorMode = Container::CurrentColorMode();
1851 extensionContext->UpdateBackShadow(shadowTheme->GetShadow(ShadowStyle::OuterDefaultMD, colorMode));
1852 selectMenuInnerContext->UpdateOpacity(0.0);
1853 }, nullptr, nullptr, GetContextRefPtr());
1854 modifier->SetOtherPointRadius(MIN_DIAMETER / 2.0f, noAnimation);
1855 modifier->SetHeadPointRadius(MIN_ARROWHEAD_DIAMETER / 2.0f, noAnimation);
1856 modifier->SetLineEndOffset(true, noAnimation);
1857 auto menuPattern = extensionMenu_->GetPattern<MenuPattern>();
1858 CHECK_NULL_VOID(menuPattern);
1859 menuPattern->SetMenuShow();
1860 FinishCallback callback = [selectMenuInnerProperty, extensionProperty, backButtonProperty, id = containerId,
1861 weak = WeakClaim(this), weakExtensionMenu = WeakClaim(RawPtr(extensionMenu_))]() {
1862 ContainerScope scope(id);
1863 selectMenuInnerProperty->UpdateVisibility(VisibleType::GONE);
1864 extensionProperty->UpdateVisibility(VisibleType::VISIBLE);
1865 auto selectOverlay = weak.Upgrade();
1866 CHECK_NULL_VOID(selectOverlay);
1867 selectOverlay->SetAnimationStatus(false);
1868 auto extensionMenu = weakExtensionMenu.Upgrade();
1869 CHECK_NULL_VOID(extensionMenu);
1870 auto child = FindAccessibleFocusNodeInExtMenu(extensionMenu);
1871 CHECK_NULL_VOID(child);
1872 auto target = AceType::DynamicCast<FrameNode>(child);
1873 CHECK_NULL_VOID(target);
1874 target->OnAccessibilityEvent(AccessibilityEventType::REQUEST_FOCUS);
1875 };
1876 AnimationOption selectOption;
1877 selectOption.SetDuration(ANIMATION_DURATION1);
1878 selectOption.SetCurve(Curves::FRICTION);
1879 pipeline->FlushUITasks();
1880 extensionMenu_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1881 pipeline->FlushUITasks();
1882 AnimationUtils::OpenImplicitAnimation(selectOption, Curves::FRICTION, callback, GetContextRefPtr());
1883 selectProperty->UpdateUserDefinedIdealSize(frameSize);
1884 selectMenuInnerContext->UpdateTransformTranslate({ ANIMATION_TEXT_OFFSET.ConvertToPx(), 0.0f, 0.0f });
1885 selectMenu_->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
1886 pipeline->FlushUITasks();
1887 AnimationUtils::CloseImplicitAnimation(GetContextRefPtr());
1888 isDoingAnimation_ = true;
1889 }
1890
BackAnimation(bool noAnimation)1891 void SelectOverlayNode::BackAnimation(bool noAnimation)
1892 {
1893 auto selectContext = selectMenu_->GetRenderContext();
1894 CHECK_NULL_VOID(selectContext);
1895 auto extensionContext = extensionMenu_->GetRenderContext();
1896 CHECK_NULL_VOID(extensionContext);
1897 auto selectMenuInnerContext = selectMenuInner_->GetRenderContext();
1898 CHECK_NULL_VOID(selectMenuInnerContext);
1899
1900 auto extensionProperty = extensionMenu_->GetLayoutProperty();
1901 CHECK_NULL_VOID(extensionProperty);
1902 auto selectProperty = selectMenu_->GetLayoutProperty();
1903 CHECK_NULL_VOID(selectProperty);
1904 auto selectMenuInnerProperty = selectMenuInner_->GetLayoutProperty();
1905 CHECK_NULL_VOID(selectMenuInnerProperty);
1906 auto backButtonProperty = backButton_->GetLayoutProperty();
1907 CHECK_NULL_VOID(backButtonProperty);
1908
1909 auto pattern = GetPattern<SelectOverlayPattern>();
1910 CHECK_NULL_VOID(pattern);
1911 auto modifier = pattern->GetOverlayModifier();
1912 CHECK_NULL_VOID(modifier);
1913
1914 auto pipeline = GetContext();
1915 CHECK_NULL_VOID(pipeline);
1916
1917 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
1918 CHECK_NULL_VOID(textOverlayTheme);
1919
1920 isExtensionMenu_ = false;
1921 auto menuWidth = pattern->GetMenuWidth();
1922
1923 selectMenuInnerProperty->UpdateVisibility(VisibleType::VISIBLE);
1924
1925 auto menuPattern = extensionMenu_->GetPattern<MenuPattern>();
1926 CHECK_NULL_VOID(menuPattern);
1927 menuPattern->ShowMenuDisappearAnimation();
1928 AnimationOption extensionOption;
1929 extensionOption.SetDuration(ANIMATION_DURATION2);
1930 extensionOption.SetCurve(Curves::FAST_OUT_SLOW_IN);
1931 auto containerId = pipeline->GetInstanceId();
1932 AnimationUtils::Animate(extensionOption, [extensionContext, selectMenuInnerContext, id = containerId]() {
1933 ContainerScope scope(id);
1934 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1935 extensionContext->UpdateOpacity(0.0);
1936 }
1937 extensionContext->UpdateTransformTranslate({ 0.0f, MORE_MENU_TRANSLATE.ConvertToPx(), 0.0f });
1938 selectMenuInnerContext->UpdateOpacity(1.0);
1939 }, nullptr, nullptr, GetContextRefPtr());
1940
1941 modifier->SetOtherPointRadius(MAX_DIAMETER / 2.0f, noAnimation);
1942 modifier->SetHeadPointRadius(MAX_DIAMETER / 2.0f, noAnimation);
1943 modifier->SetLineEndOffset(false, noAnimation);
1944
1945 auto toolbarHeight = textOverlayTheme->GetMenuToolbarHeight();
1946 auto frameSize =
1947 CalcSize(CalcLength(menuWidth.value_or(toolbarHeight.ConvertToPx())), CalcLength(toolbarHeight.ConvertToPx()));
1948
1949 FinishCallback callback = [selectMenuInnerProperty, extensionProperty, backButtonProperty, id = containerId,
1950 weak = WeakClaim(this)]() {
1951 ContainerScope scope(id);
1952 selectMenuInnerProperty->UpdateVisibility(VisibleType::VISIBLE);
1953 extensionProperty->UpdateVisibility(VisibleType::GONE);
1954 backButtonProperty->UpdateVisibility(VisibleType::GONE);
1955 auto selectOverlay = weak.Upgrade();
1956 CHECK_NULL_VOID(selectOverlay);
1957 selectOverlay->UpdateMoreOrBackSymbolOptions(true, false);
1958 selectOverlay->SetAnimationStatus(false);
1959 auto child = selectOverlay->GetFirstChild();
1960 while (child) {
1961 if (child->GetTag() == "SelectMenuButton" || child->GetTag() == V2::PASTE_BUTTON_ETS_TAG) {
1962 auto target = AceType::DynamicCast<FrameNode>(child);
1963 CHECK_NULL_VOID(target);
1964 target->OnAccessibilityEvent(AccessibilityEventType::REQUEST_FOCUS);
1965 break;
1966 }
1967 child = child->GetFirstChild();
1968 }
1969 };
1970
1971 AnimationOption selectOption;
1972 selectOption.SetDuration(ANIMATION_DURATION1);
1973 selectOption.SetCurve(Curves::FRICTION);
1974 pipeline->FlushUITasks();
1975 AnimationUtils::OpenImplicitAnimation(selectOption, Curves::FRICTION, callback, GetContextRefPtr());
1976 UpdateMoreOrBackSymbolOptionsWithDelay();
1977 if (GreatOrEqual(pipeline->GetFontScale(), AGING_MIN_SCALE)) {
1978 auto geometryNode = selectMenu_->GetGeometryNode();
1979 CHECK_NULL_VOID(geometryNode);
1980 auto selectMenuHeight = geometryNode->GetFrameSize().Height();
1981 auto menuHeight = pattern->GetMenuHeight();
1982 frameSize = CalcSize(
1983 CalcLength(menuWidth.value_or(selectMenuHeight)), CalcLength(menuHeight.value_or(selectMenuHeight)));
1984 }
1985 selectProperty->UpdateUserDefinedIdealSize(frameSize);
1986 selectMenuInnerContext->UpdateTransformTranslate({ 0.0f, 0.0f, 0.0f });
1987 selectContext->UpdateOffset(OffsetT<Dimension>(0.0_px, 0.0_px));
1988 selectMenu_->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
1989 pipeline->FlushUITasks();
1990 AnimationUtils::CloseImplicitAnimation(GetContextRefPtr());
1991 isDoingAnimation_ = true;
1992 }
1993
UpdateMoreOrBackSymbolOptions(bool isAttachToMoreButton,bool isReplaceEffectEnable)1994 void SelectOverlayNode::UpdateMoreOrBackSymbolOptions(bool isAttachToMoreButton, bool isReplaceEffectEnable)
1995 {
1996 if (!isMoreOrBackSymbolIcon_) {
1997 return;
1998 }
1999 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
2000 CHECK_NULL_VOID(pipeline);
2001 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
2002 CHECK_NULL_VOID(textOverlayTheme);
2003 if (!moreOrBackSymbol_) {
2004 moreOrBackSymbol_ = BuildMoreOrBackSymbol();
2005 }
2006 auto button = isAttachToMoreButton ? backButton_ : moreButton_;
2007 if (button) {
2008 button->RemoveChild(moreOrBackSymbol_);
2009 }
2010 moreOrBackSymbol_->MountToParent(isAttachToMoreButton ? moreButton_ : backButton_);
2011 auto layoutProperty = moreOrBackSymbol_->GetLayoutProperty<TextLayoutProperty>();
2012 layoutProperty->UpdateSymbolSourceInfo(SymbolSourceInfo(
2013 isAttachToMoreButton ? textOverlayTheme->GetMoreSymbolId() : textOverlayTheme->GetBackSymbolId()
2014 ));
2015 auto symbolEffectOptions = layoutProperty->GetSymbolEffectOptionsValue(SymbolEffectOptions());
2016 symbolEffectOptions.SetIsTxtActive(isReplaceEffectEnable);
2017 layoutProperty->UpdateSymbolEffectOptions(symbolEffectOptions);
2018 moreOrBackSymbol_->MarkModifyDone();
2019 moreOrBackSymbol_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2020 }
2021
UpdateMoreOrBackSymbolOptionsWithDelay()2022 void SelectOverlayNode::UpdateMoreOrBackSymbolOptionsWithDelay()
2023 {
2024 if (!isMoreOrBackSymbolIcon_) {
2025 return;
2026 }
2027 auto context = PipelineContext::GetCurrentContextSafelyWithCheck();
2028 CHECK_NULL_VOID(context);
2029 auto taskExecutor = context->GetTaskExecutor();
2030 CHECK_NULL_VOID(taskExecutor);
2031 auto textOverlayTheme = context->GetTheme<TextOverlayTheme>();
2032 CHECK_NULL_VOID(textOverlayTheme);
2033 CancelableCallback<void()> symbolReplaceTask_;
2034 auto moreSymbolId = textOverlayTheme->GetMoreSymbolId();
2035 symbolReplaceTask_.Reset([moreSymbolId, weak = WeakClaim(this)] {
2036 auto selectOverlay = weak.Upgrade();
2037 CHECK_NULL_VOID(selectOverlay);
2038 if (!selectOverlay->moreOrBackSymbol_) {
2039 selectOverlay->moreOrBackSymbol_ = BuildMoreOrBackSymbol();
2040 }
2041 auto layoutProperty = selectOverlay->moreOrBackSymbol_->GetLayoutProperty<TextLayoutProperty>();
2042 layoutProperty->UpdateSymbolSourceInfo(SymbolSourceInfo(moreSymbolId));
2043 auto symbolEffectOptions = layoutProperty->GetSymbolEffectOptionsValue(SymbolEffectOptions());
2044 symbolEffectOptions.SetIsTxtActive(true);
2045 layoutProperty->UpdateSymbolEffectOptions(symbolEffectOptions);
2046 selectOverlay->moreOrBackSymbol_->MarkModifyDone();
2047 selectOverlay->moreOrBackSymbol_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2048 });
2049 taskExecutor->PostDelayedTask(
2050 symbolReplaceTask_, TaskExecutor::TaskType::UI, SYMBOL_ANIMATION_DELAY, "ArkUISelectOverlaySymbolReplace");
2051 }
2052
GetDefaultOptionCallback()2053 std::function<void()> SelectOverlayNode::GetDefaultOptionCallback()
2054 {
2055 auto id = GetId();
2056 auto defaultOptionCallback = [overlayId = id, mainId = Container::CurrentIdSafelyWithCheck()]() {
2057 ContainerScope scope(mainId);
2058 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
2059 CHECK_NULL_VOID(pipeline);
2060 auto overlayManager = pipeline->GetSelectOverlayManager();
2061 CHECK_NULL_VOID(overlayManager);
2062 overlayManager->DestroySelectOverlay(overlayId);
2063 overlayManager->CloseSelectContentOverlay(overlayId, CloseReason::CLOSE_REASON_TOOL_BAR, false);
2064 };
2065 return defaultOptionCallback;
2066 }
2067
GetSymbolFunc(const std::string & symbolId)2068 std::function<void(WeakPtr<NG::FrameNode>)> SelectOverlayNode::GetSymbolFunc(const std::string& symbolId)
2069 {
2070 std::function<void(WeakPtr<NG::FrameNode>)> symbol = nullptr;
2071 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
2072 CHECK_NULL_RETURN(pipeline, symbol);
2073 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
2074 CHECK_NULL_RETURN(textOverlayTheme, symbol);
2075 std::vector<Color> symbolColor;
2076 if (symbolId == OH_DEFAULT_AI_MENU_PHONE || symbolId == OH_DEFAULT_ASK_CELIA) {
2077 symbolColor = { textOverlayTheme->GetAIMenuSymbolColor() };
2078 }
2079
2080 auto symbolIdFunc = getSymbolIdMap.find(symbolId);
2081 if (symbolIdFunc != getSymbolIdMap.end()) {
2082 auto symbolId = (symbolIdFunc->second)(textOverlayTheme);
2083 auto symbolSize = textOverlayTheme->GetSymbolSize();
2084 symbol = [symbolId, symbolSize, symbolColor](WeakPtr<NG::FrameNode> weak) {
2085 auto node = weak.Upgrade();
2086 CHECK_NULL_VOID(node);
2087 auto symbolNode = Referenced::RawPtr(node);
2088 SymbolModelNG::InitialSymbol(symbolNode, symbolId);
2089 SymbolModelNG::SetFontSize(symbolNode, symbolSize);
2090 if (!symbolColor.empty()) {
2091 SymbolModelNG::SetFontColor(symbolNode, symbolColor);
2092 }
2093 };
2094 }
2095 return symbol;
2096 }
2097
GetDefaultOptionsParams(const std::shared_ptr<SelectOverlayInfo> & info)2098 std::vector<OptionParam> SelectOverlayNode::GetDefaultOptionsParams(const std::shared_ptr<SelectOverlayInfo>& info)
2099 {
2100 std::vector<OptionParam> params;
2101 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
2102 CHECK_NULL_RETURN(pipeline, params);
2103 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
2104 CHECK_NULL_RETURN(textOverlayTheme, params);
2105 auto iconTheme = pipeline->GetTheme<IconTheme>();
2106 auto defaultOptionCallback = GetDefaultOptionCallback();
2107 if (!isShowInDefaultMenu_[OPTION_INDEX_CUT]) {
2108 auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_CUT_SVG) : "";
2109 params.emplace_back(textOverlayTheme->GetCutLabel(), iconPath,
2110 GetMenuCallbackWithContainerId(info->menuCallback.onCut), GetSymbolFunc(OH_DEFAULT_CUT));
2111 }
2112 if (!isShowInDefaultMenu_[OPTION_INDEX_COPY]) {
2113 auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_COPY_SVG) : "";
2114 params.emplace_back(textOverlayTheme->GetCopyLabel(), iconPath,
2115 GetMenuCallbackWithContainerId(info->menuCallback.onCopy), GetSymbolFunc(OH_DEFAULT_COPY));
2116 }
2117 if (!isShowInDefaultMenu_[OPTION_INDEX_PASTE]) {
2118 auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_PASTE_SVG) : "";
2119 params.emplace_back(textOverlayTheme->GetPasteLabel(), iconPath,
2120 GetMenuCallbackWithContainerId(info->menuCallback.onPaste), GetSymbolFunc(OH_DEFAULT_PASTE));
2121 }
2122 if (!isShowInDefaultMenu_[OPTION_INDEX_COPY_ALL]) {
2123 auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_SELECT_ALL_SVG) : "";
2124 params.emplace_back(textOverlayTheme->GetSelectAllLabel(), iconPath,
2125 GetMenuCallbackWithContainerId(info->menuCallback.onSelectAll), GetSymbolFunc(OH_DEFAULT_SELECT_ALL));
2126 }
2127 if (!isShowInDefaultMenu_[OPTION_INDEX_TRANSLATE]) {
2128 auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_TRANSLATE_SVG) : "";
2129 params.emplace_back(textOverlayTheme->GetTranslateLabel(), iconPath,
2130 GetMenuCallbackWithContainerId(info->menuCallback.onTranslate), GetSymbolFunc(OH_DEFAULT_TRANSLATE));
2131 }
2132 if (!isShowInDefaultMenu_[OPTION_INDEX_SHARE]) {
2133 auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_SHARE_SVG) : "";
2134 params.emplace_back(textOverlayTheme->GetShareLabel(), iconPath,
2135 GetMenuCallbackWithContainerId(info->menuCallback.onShare), GetSymbolFunc(OH_DEFAULT_SHARE));
2136 }
2137 if (!isShowInDefaultMenu_[OPTION_INDEX_SEARCH]) {
2138 auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_SEARCH_SVG) : "";
2139 params.emplace_back(textOverlayTheme->GetSearchLabel(), iconPath,
2140 GetMenuCallbackWithContainerId(info->menuCallback.onSearch), GetSymbolFunc(OH_DEFAULT_SEARCH));
2141 }
2142 GetFlexibleOptionsParams(info, params);
2143 return params;
2144 }
2145
GetFlexibleOptionsParams(const std::shared_ptr<SelectOverlayInfo> & info,std::vector<OptionParam> & params)2146 void SelectOverlayNode::GetFlexibleOptionsParams(
2147 const std::shared_ptr<SelectOverlayInfo>& info, std::vector<OptionParam>& params)
2148 {
2149 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
2150 CHECK_NULL_VOID(pipeline);
2151 auto iconTheme = pipeline->GetTheme<IconTheme>();
2152 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
2153 if (!isShowInDefaultMenu_[OPTION_INDEX_CAMERA_INPUT]) {
2154 auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_TAKEPHOTO_SVG) : "";
2155 auto iconName = textOverlayTheme ? textOverlayTheme->GetCameraInput() : "";
2156 params.emplace_back(iconName, iconPath, GetMenuCallbackWithContainerId(info->menuCallback.onCameraInput),
2157 GetSymbolFunc(OH_DEFAULT_CAMERA_INPUT));
2158 }
2159 if (!isShowInDefaultMenu_[OPTION_INDEX_AI_WRITE]) {
2160 auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_AI_WRITE_SVG) : "";
2161 auto iconName = textOverlayTheme ? textOverlayTheme->GetAIWrite() : "";
2162 params.emplace_back(iconName, iconPath, GetMenuCallbackWithContainerId(info->menuCallback.onAIWrite),
2163 GetSymbolFunc(OH_DEFAULT_AI_WRITE));
2164 }
2165 if (!isShowInDefaultMenu_[OPTION_INDEX_AI_MENU]) {
2166 auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_AI_WRITE_SVG) : "";
2167 std::function<void(WeakPtr<NG::FrameNode>)> symbolFunc = GetSymbolFunc(OH_DEFAULT_AI_MENU_PHONE);
2168 auto iconName = textOverlayTheme ?
2169 textOverlayTheme->GetAiMenuOptionName(info->menuInfo.aiMenuOptionType) : "";
2170 params.emplace_back(iconName, iconPath, GetMenuCallbackWithContainerId(
2171 info->menuCallback.onAIMenuOption, iconName), symbolFunc);
2172 params.back().isAIMenuOption = true;
2173 }
2174 if (!isShowInDefaultMenu_[OPTION_INDEX_ASK_CELIA]) {
2175 auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_AI_WRITE_SVG) : "";
2176 std::function<void(WeakPtr<NG::FrameNode>)> symbolFunc = GetSymbolFunc(OH_DEFAULT_ASK_CELIA);
2177 auto iconName = textOverlayTheme ? textOverlayTheme->GetAskCelia() : "";
2178 params.emplace_back(iconName, iconPath, GetMenuCallbackWithContainerId(info->menuCallback.onAskCelia),
2179 symbolFunc);
2180 params.back().isAskCeliaOption = true;
2181 }
2182 }
2183
addMenuOptionItemsParams(std::vector<OptionParam> & params,const std::shared_ptr<SelectOverlayInfo> & info,int32_t index)2184 void SelectOverlayNode::addMenuOptionItemsParams(
2185 std::vector<OptionParam>& params, const std::shared_ptr<SelectOverlayInfo>& info, int32_t index)
2186 {
2187 auto mainId = Container::CurrentIdSafelyWithCheck();
2188 auto id = GetId();
2189 int32_t itemNum = 0;
2190 for (auto item : info->menuOptionItems) {
2191 if (itemNum >= index) {
2192 auto callback = [overlayId = id, func = std::move(item.action), mainId]() {
2193 ContainerScope scope(mainId);
2194 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
2195 CHECK_NULL_VOID(pipeline);
2196 auto overlayManager = pipeline->GetSelectOverlayManager();
2197 CHECK_NULL_VOID(overlayManager);
2198
2199 auto selectOverlay = overlayManager->GetSelectOverlayNode(overlayId);
2200 auto pattern = selectOverlay->GetPattern<SelectOverlayPattern>();
2201 auto selectInfo = pattern->GetSelectInfo();
2202 func(selectInfo);
2203 overlayManager->DestroySelectOverlay(overlayId);
2204 overlayManager->CloseSelectContentOverlay(overlayId, CloseReason::CLOSE_REASON_TOOL_BAR, false);
2205 };
2206 params.emplace_back(item.content.value_or("null"), item.icon.value_or(" "), callback);
2207 }
2208 itemNum++;
2209 }
2210 }
2211
AddExtensionMenuOptions(const std::shared_ptr<SelectOverlayInfo> & info,int32_t index)2212 void SelectOverlayNode::AddExtensionMenuOptions(const std::shared_ptr<SelectOverlayInfo>& info, int32_t index)
2213 {
2214 CHECK_NULL_VOID(!extensionMenu_);
2215 std::vector<OptionParam> params = GetDefaultOptionsParams(info);
2216 addMenuOptionItemsParams(params, info, index);
2217 CreatExtensionMenu(std::move(params));
2218 }
2219
CreatExtensionMenu(std::vector<OptionParam> && params)2220 void SelectOverlayNode::CreatExtensionMenu(std::vector<OptionParam>&& params)
2221 {
2222 CHECK_NULL_VOID(!params.empty());
2223 CHECK_NULL_VOID(backButton_);
2224 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
2225 CHECK_NULL_VOID(pipeline);
2226 auto buttonId = backButton_->GetId();
2227 MenuParam menuParam;
2228 menuParam.placement = Placement::BOTTOM_RIGHT;
2229 menuParam.isShowInSubWindow = false;
2230 auto menuWrapper = MenuView::Create(
2231 std::move(params), buttonId, "SelectMoreOrBackButton", MenuType::SELECT_OVERLAY_EXTENSION_MENU, menuParam);
2232 CHECK_NULL_VOID(menuWrapper);
2233 auto menu = DynamicCast<FrameNode>(menuWrapper->GetChildAtIndex(0));
2234 CHECK_NULL_VOID(menu);
2235 menuWrapper->RemoveChild(menu);
2236 menuWrapper.Reset();
2237
2238 // set click position to menu
2239 auto props = menu->GetLayoutProperty<MenuLayoutProperty>();
2240 auto context = menu->GetRenderContext();
2241 CHECK_NULL_VOID(props);
2242 props->UpdateMenuOffset(GetPageOffset());
2243 // 224vp
2244 props->UpdateMenuWidth(EXTENSION_MENU_DEFAULT_WIDTH);
2245 context->UpdateBackShadow(ShadowConfig::NoneShadow);
2246 auto menuPattern = menu->GetPattern<MenuPattern>();
2247 CHECK_NULL_VOID(menuPattern);
2248 auto options = menuPattern->GetOptions();
2249 ElementRegister::GetInstance()->AddUINode(menu);
2250 menu->MountToParent(Claim(this));
2251
2252 extensionMenu_ = menu;
2253 auto extensionMenuContext = extensionMenu_->GetRenderContext();
2254 CHECK_NULL_VOID(extensionMenuContext);
2255
2256 extensionMenu_->GetLayoutProperty()->UpdateVisibility(VisibleType::GONE);
2257 extensionMenuStatus_ = FrameNodeStatus::GONE;
2258 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
2259 extensionMenuContext->UpdateOpacity(0.0);
2260 }
2261 extensionMenuContext->UpdateTransformTranslate({ 0.0f, MORE_MENU_TRANSLATE.ConvertToPx(), 0.0f });
2262 extensionMenu_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2263 extensionMenu_->MarkModifyDone();
2264 menuPattern->SetSelectOverlayExtensionMenuShow();
2265 }
2266
AddCreateMenuExtensionMenuOptions(const std::vector<MenuOptionsParam> & menuOptionItems,const std::shared_ptr<SelectOverlayInfo> & info,int32_t startIndex)2267 void SelectOverlayNode::AddCreateMenuExtensionMenuOptions(const std::vector<MenuOptionsParam>& menuOptionItems,
2268 const std::shared_ptr<SelectOverlayInfo>& info, int32_t startIndex)
2269 {
2270 std::vector<OptionParam> params;
2271 AddCreateMenuExtensionMenuParams(menuOptionItems, info, startIndex, params);
2272 CreatExtensionMenu(std::move(params));
2273 }
2274
CreateExtensionMenuOptionCallback(int32_t id,const OnMenuItemCallback & onCreateCallback,const std::function<void ()> & systemEvent,const MenuOptionsParam & item)2275 std::function<void()> SelectOverlayNode::CreateExtensionMenuOptionCallback(int32_t id,
2276 const OnMenuItemCallback& onCreateCallback, const std::function<void()>& systemEvent, const MenuOptionsParam& item)
2277 {
2278 auto callback = [onCreateCallback = onCreateCallback, systemEvent, item,
2279 mainId = Container::CurrentIdSafelyWithCheck()]() {
2280 ContainerScope scope(mainId);
2281 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
2282 CHECK_NULL_VOID(pipeline);
2283 auto overlayManager = pipeline->GetSelectOverlayManager();
2284 CHECK_NULL_VOID(overlayManager);
2285 auto newOverlayManager = overlayManager->GetSelectContentOverlayManager();
2286 CHECK_NULL_VOID(newOverlayManager);
2287 bool result = false;
2288 if (onCreateCallback.onMenuItemClick) {
2289 MenuItemParam menuItem;
2290 menuItem.menuOptionsParam = item;
2291 int32_t start = -1;
2292 int32_t end = -1;
2293 if (onCreateCallback.textRangeCallback) {
2294 onCreateCallback.textRangeCallback(start, end);
2295 }
2296 menuItem.start = start;
2297 menuItem.end = end;
2298 result = onCreateCallback.onMenuItemClick(menuItem);
2299 }
2300 if (!result && systemEvent) {
2301 systemEvent();
2302 }
2303 if (!systemEvent && !result) {
2304 newOverlayManager->HideOptionMenu(true);
2305 }
2306 };
2307 return callback;
2308 }
2309
AddCreateMenuExtensionMenuParams(const std::vector<MenuOptionsParam> & menuOptionItems,const std::shared_ptr<SelectOverlayInfo> & info,int32_t startIndex,std::vector<OptionParam> & params)2310 void SelectOverlayNode::AddCreateMenuExtensionMenuParams(const std::vector<MenuOptionsParam>& menuOptionItems,
2311 const std::shared_ptr<SelectOverlayInfo>& info, int32_t startIndex, std::vector<OptionParam>& params)
2312 {
2313 CHECK_NULL_VOID(!extensionMenu_);
2314 const auto systemCallback = GetSystemCallback(info);
2315 auto id = GetId();
2316 int32_t itemNum = 0;
2317 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
2318 CHECK_NULL_VOID(pipeline);
2319 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
2320 CHECK_NULL_VOID(textOverlayTheme);
2321 for (auto item : menuOptionItems) {
2322 if (itemNum < startIndex) {
2323 itemNum++;
2324 continue;
2325 }
2326 std::function<void()> systemEvent;
2327 auto clickCallback = systemCallback.find(item.id);
2328 if (clickCallback != systemCallback.end()) {
2329 systemEvent = clickCallback->second;
2330 }
2331 auto callback = CreateExtensionMenuOptionCallback(id, info->onCreateCallback, systemEvent, item);
2332 auto content = GetItemContent(item.id, item.content.value_or(""), info);
2333 std::function<void(WeakPtr<NG::FrameNode>)> symbol = nullptr;
2334 auto symbolIdFunc = getSymbolIdMap.find(item.id);
2335 std::vector<Color> symbolColor;
2336 if (IsAIMenuOption(item.id) || IsAskCeliaOption(item.id)) {
2337 symbolColor = { textOverlayTheme->GetAIMenuSymbolColor() };
2338 }
2339 if (symbolIdFunc != getSymbolIdMap.end()) {
2340 auto symbolId = (symbolIdFunc->second)(textOverlayTheme);
2341 auto symbolSize = textOverlayTheme->GetSymbolSize();
2342 symbol = [symbolId, symbolSize, symbolColor](WeakPtr<NG::FrameNode> weak) {
2343 auto symbolNode = weak.Upgrade();
2344 SymbolModelNG::InitialSymbol(RawPtr(symbolNode), symbolId);
2345 SymbolModelNG::SetFontSize(RawPtr(symbolNode), symbolSize);
2346 if (!symbolColor.empty()) {
2347 SymbolModelNG::SetFontColor(RawPtr(symbolNode), symbolColor);
2348 }
2349 };
2350 } else {
2351 symbol = GetCustomMenuItemSymbolFunc(item);
2352 }
2353 auto param = OptionParam(content, GetSystemIconPath(item.id, item.icon.value_or(" ")), callback, symbol);
2354 param.isPasteOption = item.id == OH_DEFAULT_PASTE;
2355 param.isAIMenuOption = IsAIMenuOption(item.id) ? true : false;
2356 param.isAskCeliaOption = IsAskCeliaOption(item.id) ? true : false;
2357 params.emplace_back(param);
2358 itemNum++;
2359 }
2360 }
2361
CreateToolBar()2362 void SelectOverlayNode::CreateToolBar()
2363 {
2364 auto pattern = GetPattern<SelectOverlayPattern>();
2365 CHECK_NULL_VOID(pattern);
2366 if (!pattern->CheckIfNeedMenu()) {
2367 return;
2368 }
2369 auto info = pattern->GetSelectOverlayInfo();
2370 if (info->menuInfo.menuBuilder) {
2371 CreateCustomSelectOverlay(info);
2372 return;
2373 }
2374
2375 selectMenu_ = FrameNode::GetOrCreateFrameNode("SelectMenu", ElementRegister::GetInstance()->MakeUniqueId(),
2376 []() { return AceType::MakeRefPtr<LinearLayoutPattern>(false); });
2377 // Increase the node to realize the animation effect of font transparency and offset.
2378 selectMenuInner_ =
2379 FrameNode::GetOrCreateFrameNode("SelectMenuInner", ElementRegister::GetInstance()->MakeUniqueId(),
2380 []() { return AceType::MakeRefPtr<LinearLayoutPattern>(false); });
2381 TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY, "CreateSelectOverlay default, id:%{public}d", selectMenu_->GetId());
2382 SelectMenuAndInnerInitProperty();
2383 // Menu initial state.
2384 InitSelectMenuStatus(pattern->GetMode(), info);
2385
2386 selectMenuInner_->MountToParent(selectMenu_);
2387 selectMenu_->MountToParent(Claim(this));
2388 selectMenu_->MarkModifyDone();
2389 }
2390
SelectMenuAndInnerInitProperty()2391 void SelectOverlayNode::SelectMenuAndInnerInitProperty()
2392 {
2393 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
2394 CHECK_NULL_VOID(pipeline);
2395 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
2396 CHECK_NULL_VOID(textOverlayTheme);
2397 auto shadowTheme = pipeline->GetTheme<ShadowTheme>();
2398 CHECK_NULL_VOID(shadowTheme);
2399 selectMenu_->GetLayoutProperty<LinearLayoutProperty>()->UpdateMainAxisAlign(FlexAlign::FLEX_END);
2400 selectMenu_->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_CONTENT);
2401
2402 auto colorMode = pipeline->GetColorMode();
2403 selectMenu_->GetRenderContext()->UpdateBackShadow(shadowTheme->GetShadow(ShadowStyle::OuterDefaultMD, colorMode));
2404 selectMenu_->GetRenderContext()->UpdateBackgroundColor(textOverlayTheme->GetMenuBackgroundColor());
2405 selectMenu_->GetRenderContext()->SetClipToFrame(true);
2406
2407 const auto& border = textOverlayTheme->GetMenuBorder();
2408 auto borderWidth = Dimension(border.Left().GetWidth().ConvertToPx());
2409 selectMenu_->GetLayoutProperty()->UpdateBorderWidth({ borderWidth, borderWidth, borderWidth, borderWidth,
2410 std::nullopt, std::nullopt });
2411 auto borderRadius = textOverlayTheme->GetMenuToolbarHeight() / 2.0f;
2412 selectMenu_->GetRenderContext()->UpdateBorderRadius({ borderRadius, borderRadius, borderRadius, borderRadius });
2413 auto borderColor = border.Left().GetColor();
2414 selectMenu_->GetRenderContext()->UpdateBorderColor({ borderColor, borderColor, borderColor, borderColor,
2415 std::nullopt, std::nullopt });
2416 auto borderStyle = border.Left().GetBorderStyle();
2417 selectMenu_->GetRenderContext()->UpdateBorderStyle({ borderStyle, borderStyle, borderStyle, borderStyle });
2418
2419 selectMenuInner_->GetLayoutProperty<LinearLayoutProperty>()->UpdateMainAxisAlign(FlexAlign::FLEX_END);
2420 selectMenuInner_->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_CONTENT);
2421
2422 BlurStyleOption styleOption;
2423 styleOption.blurStyle = BlurStyle::COMPONENT_ULTRA_THICK;
2424 selectMenu_->GetRenderContext()->UpdateBackBlurStyle(styleOption);
2425 selectMenu_->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
2426
2427 selectMenuInner_->GetRenderContext()->UpdateOpacity(1.0);
2428 selectMenuInner_->GetRenderContext()->UpdateTransformTranslate({ 0.0f, 0.0f, 0.0f });
2429 const auto& padding = textOverlayTheme->GetMenuPadding();
2430 auto left = CalcLength(padding.Left().ConvertToPx());
2431 auto right = CalcLength(padding.Right().ConvertToPx());
2432 auto top = CalcLength(padding.Top().ConvertToPx());
2433 auto bottom = CalcLength(padding.Bottom().ConvertToPx());
2434 selectMenuInner_->GetLayoutProperty()->UpdatePadding({ left, right, top, bottom, std::nullopt, std::nullopt });
2435 SetSelectMenuInnerSize();
2436 }
2437
InitSelectMenuStatus(SelectOverlayMode mode,const std::shared_ptr<SelectOverlayInfo> & info,bool changeOpacity)2438 void SelectOverlayNode::InitSelectMenuStatus(
2439 SelectOverlayMode mode, const std::shared_ptr<SelectOverlayInfo>& info, bool changeOpacity)
2440 {
2441 if (mode == SelectOverlayMode::MENU_ONLY) {
2442 // In SelectOverlayMode::MENU_ONLY mode, SelectOverlay controls the animation by self.
2443 if (changeOpacity) {
2444 SetFrameNodeOpacity(FrameNodeType::MENUONLY, 0.0f);
2445 }
2446 if (info->menuInfo.menuIsShow) {
2447 GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
2448 menuOnlyStatus_ = FrameNodeStatus::VISIBLE;
2449 } else {
2450 GetLayoutProperty()->UpdateVisibility(VisibleType::GONE);
2451 menuOnlyStatus_ = FrameNodeStatus::GONE;
2452 }
2453 } else {
2454 CHECK_NULL_VOID(selectMenu_);
2455 // In SelectOverlayMode::ALL mode, SelectOverlay controls the animation through the children individually.
2456 if (changeOpacity) {
2457 selectMenu_->GetRenderContext()->UpdateOpacity(0.0);
2458 }
2459 if (info->menuInfo.menuIsShow) {
2460 selectMenu_->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
2461 selectMenuStatus_ = FrameNodeStatus::VISIBLE;
2462 } else {
2463 selectMenu_->GetLayoutProperty()->UpdateVisibility(VisibleType::GONE);
2464 selectMenuStatus_ = FrameNodeStatus::GONE;
2465 }
2466 }
2467 }
2468
GetDefaultButtonAndMenuWidth(float & maxWidth)2469 void SelectOverlayNode::GetDefaultButtonAndMenuWidth(float& maxWidth)
2470 {
2471 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
2472 CHECK_NULL_VOID(pipeline);
2473 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
2474 CHECK_NULL_VOID(textOverlayTheme);
2475 auto selectOverlayMaxWidth = OVERLAY_MAX_WIDTH.ConvertToPx();
2476 auto container = Container::Current();
2477 if (container && container->IsUIExtensionWindow()) {
2478 auto curWindowRect = pipeline->GetCurrentWindowRect();
2479 selectOverlayMaxWidth = std::min(selectOverlayMaxWidth, curWindowRect.Width());
2480 }
2481
2482 const auto& menuPadding = textOverlayTheme->GetMenuPadding();
2483
2484 auto backButtonWidth = textOverlayTheme->GetMenuToolbarHeight().ConvertToPx() - menuPadding.Top().ConvertToPx() -
2485 menuPadding.Bottom().ConvertToPx();
2486
2487 maxWidth =
2488 selectOverlayMaxWidth - menuPadding.Left().ConvertToPx() - menuPadding.Right().ConvertToPx() - backButtonWidth;
2489 }
2490
AddSystemDefaultOptions(float maxWidth,float & allocatedSize)2491 bool SelectOverlayNode::AddSystemDefaultOptions(float maxWidth, float& allocatedSize)
2492 {
2493 auto info = GetPattern<SelectOverlayPattern>()->GetSelectOverlayInfo();
2494 memset_s(isShowInDefaultMenu_, sizeof(isShowInDefaultMenu_), 0, sizeof(isShowInDefaultMenu_));
2495
2496 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
2497 CHECK_NULL_RETURN(pipeline, false);
2498 auto theme = pipeline->GetTheme<TextOverlayTheme>();
2499 CHECK_NULL_RETURN(theme, false);
2500 ShowCut(maxWidth, allocatedSize, info, theme->GetCutLabel());
2501 ShowCopy(maxWidth, allocatedSize, info, theme->GetCopyLabel());
2502 ShowPaste(maxWidth, allocatedSize, info, theme->GetPasteLabel());
2503 ShowCopyAll(maxWidth, allocatedSize, info, theme->GetSelectAllLabel());
2504 // Below is advanced options, consider support disableMenuItems and disableSystemServiceMenuItems by TextSystemMenu
2505 ShowTranslate(maxWidth, allocatedSize, info, theme->GetTranslateLabel());
2506 ShowShare(maxWidth, allocatedSize, info, theme->GetShareLabel());
2507 ShowSearch(maxWidth, allocatedSize, info, theme->GetSearchLabel());
2508 ShowCamera(maxWidth, allocatedSize, info, theme->GetCameraInput());
2509 ShowAIWrite(maxWidth, allocatedSize, info, theme->GetAIWrite());
2510 ShowAIMenuOptions(maxWidth, allocatedSize, info, theme->GetAiMenuOptionName(info->menuInfo.aiMenuOptionType));
2511 ShowAskCelia(maxWidth, allocatedSize, info, theme->GetAskCelia());
2512 if (isDefaultBtnOverMaxWidth_) {
2513 isDefaultBtnOverMaxWidth_ = false;
2514 return true;
2515 }
2516
2517 return false;
2518 }
2519
ShowCut(float maxWidth,float & allocatedSize,std::shared_ptr<SelectOverlayInfo> & info,const std::string & label)2520 void SelectOverlayNode::ShowCut(
2521 float maxWidth, float& allocatedSize, std::shared_ptr<SelectOverlayInfo>& info, const std::string& label)
2522 {
2523 if (info->menuInfo.showCut) {
2524 float buttonWidth = 0.0f;
2525 ButtonBasicInfo buttonBasicInfo = { .data = label, .buttonType = SelectOverlayMenuButtonType::NORMAL };
2526 auto button = BuildButton(info, info->menuCallback.onCut, GetId(), buttonWidth, buttonBasicInfo);
2527 CHECK_NULL_VOID(button);
2528 if (GreatOrEqual(maxWidth - allocatedSize, buttonWidth)) {
2529 button->MountToParent(selectMenuInner_);
2530 allocatedSize += buttonWidth;
2531 isShowInDefaultMenu_[OPTION_INDEX_CUT] = true;
2532 } else {
2533 button.Reset();
2534 isDefaultBtnOverMaxWidth_ = true;
2535 }
2536 } else {
2537 isShowInDefaultMenu_[OPTION_INDEX_CUT] = true;
2538 }
2539 }
2540
ShowCopy(float maxWidth,float & allocatedSize,std::shared_ptr<SelectOverlayInfo> & info,const std::string & label)2541 void SelectOverlayNode::ShowCopy(
2542 float maxWidth, float& allocatedSize, std::shared_ptr<SelectOverlayInfo>& info, const std::string& label)
2543 {
2544 if (info->menuInfo.showCopy) {
2545 CHECK_EQUAL_VOID(isDefaultBtnOverMaxWidth_, true);
2546 float buttonWidth = 0.0f;
2547 ButtonBasicInfo buttonBasicInfo = { .data = label, .buttonType = SelectOverlayMenuButtonType::NORMAL };
2548 auto button = BuildButton(info, info->menuCallback.onCopy, GetId(), buttonWidth, buttonBasicInfo);
2549 CHECK_NULL_VOID(button);
2550 if (GreatOrEqual(maxWidth - allocatedSize, buttonWidth)) {
2551 button->MountToParent(selectMenuInner_);
2552 allocatedSize += buttonWidth;
2553 isShowInDefaultMenu_[OPTION_INDEX_COPY] = true;
2554 } else {
2555 button.Reset();
2556 isDefaultBtnOverMaxWidth_ = true;
2557 }
2558 } else {
2559 isShowInDefaultMenu_[OPTION_INDEX_COPY] = true;
2560 }
2561 }
2562
ShowPaste(float maxWidth,float & allocatedSize,std::shared_ptr<SelectOverlayInfo> & info,const std::string & label)2563 void SelectOverlayNode::ShowPaste(
2564 float maxWidth, float& allocatedSize, std::shared_ptr<SelectOverlayInfo>& info, const std::string& label)
2565 {
2566 if (info->menuInfo.showPaste) {
2567 CHECK_EQUAL_VOID(isDefaultBtnOverMaxWidth_, true);
2568 float buttonWidth = 0.0f;
2569 #ifdef OHOS_PLATFORM
2570 auto button = BuildPasteButton(info, info->menuCallback.onPaste, GetId(), buttonWidth);
2571 #else
2572 ButtonBasicInfo buttonBasicInfo = { .data = label, .buttonType = SelectOverlayMenuButtonType::NORMAL };
2573 auto button = BuildButton(info, info->menuCallback.onPaste, GetId(), buttonWidth, buttonBasicInfo);
2574 #endif
2575 CHECK_NULL_VOID(button);
2576 if (GreatOrEqual(maxWidth - allocatedSize, buttonWidth)) {
2577 button->MountToParent(selectMenuInner_);
2578 allocatedSize += buttonWidth;
2579 isShowInDefaultMenu_[OPTION_INDEX_PASTE] = true;
2580 } else {
2581 button.Reset();
2582 isDefaultBtnOverMaxWidth_ = true;
2583 }
2584 } else {
2585 isShowInDefaultMenu_[OPTION_INDEX_PASTE] = true;
2586 }
2587 }
2588
ShowCopyAll(float maxWidth,float & allocatedSize,std::shared_ptr<SelectOverlayInfo> & info,const std::string & label)2589 void SelectOverlayNode::ShowCopyAll(
2590 float maxWidth, float& allocatedSize, std::shared_ptr<SelectOverlayInfo>& info, const std::string& label)
2591 {
2592 if (info->menuInfo.showCopyAll) {
2593 CHECK_EQUAL_VOID(isDefaultBtnOverMaxWidth_, true);
2594 float buttonWidth = 0.0f;
2595 ButtonBasicInfo buttonBasicInfo = { .data = label, .buttonType = SelectOverlayMenuButtonType::NORMAL };
2596 auto button = BuildButton(info, info->menuCallback.onSelectAll, GetId(), buttonWidth, buttonBasicInfo);
2597 CHECK_NULL_VOID(button);
2598 if (GreatOrEqual(maxWidth - allocatedSize, buttonWidth)) {
2599 button->MountToParent(selectMenuInner_);
2600 allocatedSize += buttonWidth;
2601 isShowInDefaultMenu_[OPTION_INDEX_COPY_ALL] = true;
2602 } else {
2603 button.Reset();
2604 isDefaultBtnOverMaxWidth_ = true;
2605 }
2606 } else {
2607 isShowInDefaultMenu_[OPTION_INDEX_COPY_ALL] = true;
2608 }
2609 }
2610
ShowTranslate(float maxWidth,float & allocatedSize,std::shared_ptr<SelectOverlayInfo> & info,const std::string & label)2611 void SelectOverlayNode::ShowTranslate(
2612 float maxWidth, float& allocatedSize, std::shared_ptr<SelectOverlayInfo>& info, const std::string& label)
2613 {
2614 if (!IsShowTranslateOnTargetAPIVersion() || !TextSystemMenu::IsShowTranslate()) {
2615 isShowInDefaultMenu_[OPTION_INDEX_TRANSLATE] = true;
2616 return;
2617 }
2618 if (info->menuInfo.showTranslate) {
2619 CHECK_EQUAL_VOID(isDefaultBtnOverMaxWidth_, true);
2620 float buttonWidth = 0.0f;
2621 ButtonBasicInfo buttonBasicInfo = { .data = label, .buttonType = SelectOverlayMenuButtonType::NORMAL };
2622 auto button = BuildButton(info, info->menuCallback.onTranslate, GetId(), buttonWidth, buttonBasicInfo);
2623 CHECK_NULL_VOID(button);
2624 if (GreatOrEqual(maxWidth - allocatedSize, buttonWidth)) {
2625 button->MountToParent(selectMenuInner_);
2626 allocatedSize += buttonWidth;
2627 isShowInDefaultMenu_[OPTION_INDEX_TRANSLATE] = true;
2628 } else {
2629 button.Reset();
2630 isDefaultBtnOverMaxWidth_ = true;
2631 }
2632 } else {
2633 isShowInDefaultMenu_[OPTION_INDEX_TRANSLATE] = true;
2634 }
2635 }
2636
ShowSearch(float maxWidth,float & allocatedSize,std::shared_ptr<SelectOverlayInfo> & info,const std::string & label)2637 void SelectOverlayNode::ShowSearch(
2638 float maxWidth, float& allocatedSize, std::shared_ptr<SelectOverlayInfo>& info, const std::string& label)
2639 {
2640 if (!IsShowOnTargetAPIVersion() || !TextSystemMenu::IsShowSearch()) {
2641 isShowInDefaultMenu_[OPTION_INDEX_SEARCH] = true;
2642 return;
2643 }
2644 if (info->menuInfo.showSearch) {
2645 CHECK_EQUAL_VOID(isDefaultBtnOverMaxWidth_, true);
2646 float buttonWidth = 0.0f;
2647 ButtonBasicInfo buttonBasicInfo = { .data = label, .buttonType = SelectOverlayMenuButtonType::NORMAL };
2648 auto button = BuildButton(info, info->menuCallback.onSearch, GetId(), buttonWidth, buttonBasicInfo);
2649 CHECK_NULL_VOID(button);
2650 if (GreatOrEqual(maxWidth - allocatedSize, buttonWidth)) {
2651 button->MountToParent(selectMenuInner_);
2652 allocatedSize += buttonWidth;
2653 isShowInDefaultMenu_[OPTION_INDEX_SEARCH] = true;
2654 } else {
2655 button.Reset();
2656 isDefaultBtnOverMaxWidth_ = true;
2657 }
2658 } else {
2659 isShowInDefaultMenu_[OPTION_INDEX_SEARCH] = true;
2660 }
2661 }
2662
ShowShare(float maxWidth,float & allocatedSize,std::shared_ptr<SelectOverlayInfo> & info,const std::string & label)2663 void SelectOverlayNode::ShowShare(
2664 float maxWidth, float& allocatedSize, std::shared_ptr<SelectOverlayInfo>& info, const std::string& label)
2665 {
2666 if (!IsShowOnTargetAPIVersion() || !TextSystemMenu::IsShowShare()) {
2667 isShowInDefaultMenu_[OPTION_INDEX_SHARE] = true;
2668 return;
2669 }
2670 if (info->menuInfo.showShare) {
2671 CHECK_EQUAL_VOID(isDefaultBtnOverMaxWidth_, true);
2672 float buttonWidth = 0.0f;
2673 ButtonBasicInfo buttonBasicInfo = { .data = label, .buttonType = SelectOverlayMenuButtonType::NORMAL };
2674 auto button = BuildButton(info, info->menuCallback.onShare, GetId(), buttonWidth, buttonBasicInfo);
2675 CHECK_NULL_VOID(button);
2676 if (GreatOrEqual(maxWidth - allocatedSize, buttonWidth)) {
2677 button->MountToParent(selectMenuInner_);
2678 allocatedSize += buttonWidth;
2679 isShowInDefaultMenu_[OPTION_INDEX_SHARE] = true;
2680 } else {
2681 button.Reset();
2682 isDefaultBtnOverMaxWidth_ = true;
2683 }
2684 } else {
2685 isShowInDefaultMenu_[OPTION_INDEX_SHARE] = true;
2686 }
2687 }
2688
ShowAIWrite(float maxWidth,float & allocatedSize,std::shared_ptr<SelectOverlayInfo> & info,const std::string & label)2689 void SelectOverlayNode::ShowAIWrite(
2690 float maxWidth, float& allocatedSize, std::shared_ptr<SelectOverlayInfo>& info, const std::string& label)
2691 {
2692 if (info->menuInfo.showAIWrite && TextSystemMenu::IsShowAIWriter()) {
2693 CHECK_EQUAL_VOID(isDefaultBtnOverMaxWidth_, true);
2694 float buttonWidth = 0.0f;
2695 ButtonBasicInfo buttonBasicInfo = { .data = label, .buttonType = SelectOverlayMenuButtonType::NORMAL };
2696 auto button = BuildButton(info, info->menuCallback.onAIWrite, GetId(), buttonWidth, buttonBasicInfo);
2697 CHECK_NULL_VOID(button);
2698 if (GreatOrEqual(maxWidth - allocatedSize, buttonWidth)) {
2699 button->MountToParent(selectMenuInner_);
2700 allocatedSize += buttonWidth;
2701 isShowInDefaultMenu_[OPTION_INDEX_AI_WRITE] = true;
2702 } else {
2703 button.Reset();
2704 isDefaultBtnOverMaxWidth_ = true;
2705 }
2706 } else {
2707 isShowInDefaultMenu_[OPTION_INDEX_AI_WRITE] = true;
2708 }
2709 }
2710
ShowCamera(float maxWidth,float & allocatedSize,std::shared_ptr<SelectOverlayInfo> & info,const std::string & label)2711 void SelectOverlayNode::ShowCamera(
2712 float maxWidth, float& allocatedSize, std::shared_ptr<SelectOverlayInfo>& info, const std::string& label)
2713 {
2714 if (info->menuInfo.showCameraInput && TextSystemMenu::IsShowCameraInput()) {
2715 CHECK_EQUAL_VOID(isDefaultBtnOverMaxWidth_, true);
2716 float buttonWidth = 0.0f;
2717 ButtonBasicInfo buttonBasicInfo = { .data = label, .buttonType = SelectOverlayMenuButtonType::NORMAL };
2718 auto button = BuildButton(info, info->menuCallback.onCameraInput, GetId(), buttonWidth, buttonBasicInfo);
2719 CHECK_NULL_VOID(button);
2720 if (GreatOrEqual(maxWidth - allocatedSize, buttonWidth)) {
2721 button->MountToParent(selectMenuInner_);
2722 allocatedSize += buttonWidth;
2723 isShowInDefaultMenu_[OPTION_INDEX_CAMERA_INPUT] = true;
2724 } else {
2725 button.Reset();
2726 isDefaultBtnOverMaxWidth_ = true;
2727 }
2728 } else {
2729 isShowInDefaultMenu_[OPTION_INDEX_CAMERA_INPUT] = true;
2730 }
2731 }
2732
ShowAIMenuOptions(float maxWidth,float & allocatedSize,std::shared_ptr<SelectOverlayInfo> & info,const std::string & label)2733 void SelectOverlayNode::ShowAIMenuOptions(
2734 float maxWidth, float& allocatedSize, std::shared_ptr<SelectOverlayInfo>& info, const std::string& label)
2735 {
2736 if (IsShowAIMenuOption(info->menuInfo.aiMenuOptionType)) {
2737 CHECK_EQUAL_VOID(isDefaultBtnOverMaxWidth_, true);
2738 float buttonWidth = 0.0f;
2739 ButtonBasicInfo buttonBasicInfo = { .data = label, .buttonType = SelectOverlayMenuButtonType::AIBUTTON };
2740 auto button = BuildButton(info, info->menuCallback.onAIMenuOption, GetId(), buttonWidth, buttonBasicInfo);
2741 CHECK_NULL_VOID(button);
2742 if (GreatOrEqual(maxWidth - allocatedSize, buttonWidth)) {
2743 button->MountToParent(selectMenuInner_);
2744 allocatedSize += buttonWidth;
2745 isShowInDefaultMenu_[OPTION_INDEX_AI_MENU] = true;
2746 } else {
2747 button.Reset();
2748 isDefaultBtnOverMaxWidth_ = true;
2749 }
2750 } else {
2751 isShowInDefaultMenu_[OPTION_INDEX_AI_MENU] = true;
2752 }
2753 }
2754
IsShowOnTargetAPIVersion()2755 bool SelectOverlayNode::IsShowOnTargetAPIVersion()
2756 {
2757 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) &&
2758 LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
2759 return false;
2760 }
2761 return true;
2762 }
2763
IsShowTranslateOnTargetAPIVersion()2764 bool SelectOverlayNode::IsShowTranslateOnTargetAPIVersion()
2765 {
2766 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) &&
2767 LessThanAPITargetVersion(PlatformVersion::VERSION_FIFTEEN)) {
2768 return false;
2769 }
2770 return true;
2771 }
2772
AddMenuItemByCreateMenuCallback(const std::shared_ptr<SelectOverlayInfo> & info,float maxWidth)2773 void SelectOverlayNode::AddMenuItemByCreateMenuCallback(const std::shared_ptr<SelectOverlayInfo>& info, float maxWidth)
2774 {
2775 CHECK_NULL_VOID(info);
2776 CHECK_NULL_VOID((info->onCreateCallback.onCreateMenuCallback || info->onCreateCallback.onPrepareMenuCallback));
2777 auto systemItemParams = GetSystemMenuItemParams(info);
2778 std::vector<MenuOptionsParam> createMenuItems = GetMenuOptionsParamsWithEditMenuOption(info, systemItemParams);
2779 auto extensionOptionStartIndex = AddCreateMenuItems(createMenuItems, info, maxWidth) + 1;
2780 if (backButton_) {
2781 isExtensionMenu_ = false;
2782 RemoveChild(backButton_);
2783 backButton_.Reset();
2784 }
2785 if (extensionMenu_) {
2786 RemoveChild(extensionMenu_);
2787 extensionMenu_.Reset();
2788 }
2789 if (static_cast<size_t>(extensionOptionStartIndex) < createMenuItems.size()) {
2790 moreButton_ = BuildMoreOrBackButton(info, GetId(), true);
2791 moreButton_->MountToParent(selectMenuInner_);
2792 CHECK_NULL_VOID(moreButton_);
2793 isMoreOrBackSymbolIcon_ = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE);
2794 if (isMoreOrBackSymbolIcon_) {
2795 moreOrBackSymbol_ = BuildMoreOrBackSymbol();
2796 moreOrBackSymbol_->MountToParent(moreButton_);
2797 }
2798 // add back button
2799 if (!backButton_) {
2800 backButton_ = BuildMoreOrBackButton(info, GetId(), false);
2801 CHECK_NULL_VOID(backButton_);
2802 backButton_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2803 backButton_->GetLayoutProperty()->UpdateVisibility(VisibleType::GONE);
2804 backButton_->MountToParent(Claim(this));
2805 }
2806 }
2807 AddCreateMenuExtensionMenuOptions(createMenuItems, info, extensionOptionStartIndex);
2808 }
2809
AddCreateMenuItems(const std::vector<NG::MenuOptionsParam> & menuItems,const std::shared_ptr<SelectOverlayInfo> & info,float maxWidth)2810 int32_t SelectOverlayNode::AddCreateMenuItems(
2811 const std::vector<NG::MenuOptionsParam>& menuItems, const std::shared_ptr<SelectOverlayInfo>& info, float maxWidth)
2812 {
2813 auto id = GetId();
2814 const auto systemCallback = GetSystemCallback(info);
2815 float remainderWidth = maxWidth;
2816 int32_t index = -1;
2817 for (auto item : menuItems) {
2818 auto callback = systemCallback.find(item.id);
2819 RefPtr<FrameNode> button;
2820 if (item.id == "OH_DEFAULT_PASTE") {
2821 #ifdef OHOS_PLATFORM
2822 float buttonWidth = 0.0f;
2823 button = CreatePasteButtonForCreateMenu(info, id, item, buttonWidth);
2824 if (!button) {
2825 continue;
2826 }
2827 if (GreatOrEqual(remainderWidth, buttonWidth)) {
2828 button->MountToParent(selectMenuInner_);
2829 remainderWidth -= buttonWidth;
2830 index++;
2831 } else {
2832 button.Reset();
2833 return index;
2834 }
2835 #else
2836 button = BuildCreateMenuItemButton(item, callback != systemCallback.end() ? callback->second : nullptr,
2837 id, remainderWidth, info);
2838 if (button) {
2839 button->MountToParent(selectMenuInner_);
2840 index++;
2841 } else {
2842 break;
2843 }
2844 #endif
2845 } else {
2846 item.isFirstOption = index == -1;
2847 item.content = GetItemContent(item.id, item.content.value_or(""), info);
2848
2849 button = BuildCreateMenuItemButton(item, callback != systemCallback.end() ? callback->second : nullptr,
2850 id, remainderWidth, info);
2851 if (button) {
2852 button->MountToParent(selectMenuInner_);
2853 index++;
2854 } else {
2855 break;
2856 }
2857 }
2858 }
2859 return index;
2860 }
2861
GetSystemMenuItemParams(const std::shared_ptr<SelectOverlayInfo> & info)2862 const std::vector<MenuItemParam> SelectOverlayNode::GetSystemMenuItemParams(
2863 const std::shared_ptr<SelectOverlayInfo>& info)
2864 {
2865 std::vector<MenuItemParam> systemItemParams;
2866 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
2867 CHECK_NULL_RETURN(pipeline, systemItemParams);
2868 auto theme = pipeline->GetTheme<TextOverlayTheme>();
2869 CHECK_NULL_RETURN(theme, systemItemParams);
2870 auto isUsingMouse = info->isUsingMouse;
2871 auto menuInfo = info->menuInfo;
2872 AddMenuItemParamIf(
2873 menuInfo.showCopy || isUsingMouse, OH_DEFAULT_COPY, theme->GetCopyLabel(), systemItemParams);
2874 AddMenuItemParamIf(
2875 menuInfo.showPaste || isUsingMouse, OH_DEFAULT_PASTE, theme->GetPasteLabel(), systemItemParams);
2876 AddMenuItemParamIf(menuInfo.showCut || isUsingMouse, OH_DEFAULT_CUT, theme->GetCutLabel(), systemItemParams);
2877 AddMenuItemParamIf(menuInfo.showCopyAll || isUsingMouse, OH_DEFAULT_SELECT_ALL, theme->GetSelectAllLabel(),
2878 systemItemParams);
2879 // Below is advanced options, consider support disableMenuItems and disableSystemServiceMenuItems by TextSystemMenu
2880 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_FIFTEEN) &&
2881 TextSystemMenu::IsShowTranslate()) {
2882 AddMenuItemParamIf(menuInfo.showTranslate || isUsingMouse, OH_DEFAULT_TRANSLATE,
2883 theme->GetTranslateLabel(), systemItemParams);
2884 }
2885 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
2886 AddMenuItemParamIf((menuInfo.showShare || isUsingMouse) && TextSystemMenu::IsShowShare(),
2887 OH_DEFAULT_SHARE, theme->GetShareLabel(), systemItemParams);
2888 AddMenuItemParamIf((menuInfo.showSearch || isUsingMouse) && TextSystemMenu::IsShowSearch(),
2889 OH_DEFAULT_SEARCH, theme->GetSearchLabel(), systemItemParams);
2890 }
2891 AddMenuItemParamIf(menuInfo.showCameraInput && TextSystemMenu::IsShowCameraInput(),
2892 OH_DEFAULT_CAMERA_INPUT, theme->GetCameraInput(), systemItemParams);
2893 AddMenuItemParamIf(menuInfo.showAIWrite && TextSystemMenu::IsShowAIWriter(), OH_DEFAULT_AI_WRITE,
2894 theme->GetAIWrite(), systemItemParams);
2895
2896 if (IsShowAIMenuOption(info->menuInfo.aiMenuOptionType)) {
2897 auto findIter = AI_TYPE_ID_MAP.find(info->menuInfo.aiMenuOptionType);
2898 AddMenuItemParamIf(true, findIter->second.first,
2899 theme->GetAiMenuOptionName(info->menuInfo.aiMenuOptionType), systemItemParams);
2900 }
2901
2902 AddMenuItemParamIf(menuInfo.isAskCeliaEnabled && TextSystemMenu::IsShowAskCelia(), OH_DEFAULT_ASK_CELIA,
2903 theme->GetAskCelia(), systemItemParams);
2904 return systemItemParams;
2905 }
2906
AddMenuItemParamIf(bool condition,const std::string & menuId,const std::string & menuButton,std::vector<MenuItemParam> & items)2907 void SelectOverlayNode::AddMenuItemParamIf(
2908 bool condition, const std::string& menuId, const std::string& menuButton, std::vector<MenuItemParam>& items)
2909 {
2910 if (condition) {
2911 MenuOptionsParam menuOptionsParam;
2912 menuOptionsParam.id = menuId;
2913 menuOptionsParam.content = menuButton;
2914 MenuItemParam param;
2915 param.menuOptionsParam = menuOptionsParam;
2916 items.emplace_back(param);
2917 }
2918 }
2919
MenuOnlyStatusChange(const std::shared_ptr<SelectOverlayInfo> & info,bool noAnimation)2920 void SelectOverlayNode::MenuOnlyStatusChange(const std::shared_ptr<SelectOverlayInfo>& info, bool noAnimation)
2921 {
2922 auto pattern = GetPattern<SelectOverlayPattern>();
2923 CHECK_NULL_VOID(pattern);
2924 bool isHideMenu = info->menuInfo.menuDisable || !info->menuInfo.menuIsShow;
2925 if (isHideMenu) {
2926 (noAnimation) ? HideMenuOnlyImmediately()
2927 : ExecuteOverlayStatus(FrameNodeType::MENUONLY, FrameNodeTrigger::HIDE);
2928 if (pattern->GetIsMenuShowInSubWindow()) {
2929 pattern->DeleteHotAreas();
2930 }
2931 } else {
2932 ExecuteOverlayStatus(FrameNodeType::MENUONLY, FrameNodeTrigger::SHOW);
2933 }
2934 FireCustomMenuChangeEvent(!isHideMenu);
2935 if (pattern->GetIsMenuShowInSubWindow() && isExtensionMenu_ && extensionMenu_) {
2936 auto pipeline = extensionMenu_->GetContext();
2937 CHECK_NULL_VOID(pipeline);
2938 auto containerId = pipeline->GetInstanceId();
2939 ContainerScope scope(containerId);
2940 extensionMenu_->MarkModifyDone();
2941 extensionMenu_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2942 pipeline->FlushUITasks();
2943 }
2944 }
2945
HideMenuOnlyImmediately()2946 void SelectOverlayNode::HideMenuOnlyImmediately()
2947 {
2948 SetFrameNodeStatus(FrameNodeType::MENUONLY, FrameNodeStatus::GONE);
2949 SetFrameNodeVisibility(FrameNodeType::MENUONLY, VisibleType::GONE);
2950 SetFrameNodeOpacity(FrameNodeType::MENUONLY, 0.0f);
2951 }
2952
UpdateToolBar(bool menuItemChanged,bool noAnimation)2953 void SelectOverlayNode::UpdateToolBar(bool menuItemChanged, bool noAnimation)
2954 {
2955 auto pattern = GetPattern<SelectOverlayPattern>();
2956 CHECK_NULL_VOID(pattern);
2957 if (!pattern->CheckIfNeedMenu()) {
2958 NotifyUpdateToolBar(menuItemChanged, noAnimation);
2959 MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2960 return;
2961 }
2962 auto info = pattern->GetSelectOverlayInfo();
2963 if (menuItemChanged && info->menuInfo.menuBuilder == nullptr) {
2964 UpdateMenuInner(info, noAnimation);
2965 }
2966 selectMenu_->MarkModifyDone();
2967 MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2968 if (selectMenuInner_) {
2969 selectMenuInner_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2970 }
2971 auto mode = pattern->GetMode();
2972 // In SelectOverlayMode::MENU_ONLY mode, SelectOverlay controls the animation by self.
2973 if (mode == SelectOverlayMode::MENU_ONLY) {
2974 MenuOnlyStatusChange(info, noAnimation);
2975 return;
2976 }
2977 if (info->menuInfo.menuDisable || !info->menuInfo.menuIsShow) {
2978 (noAnimation) ? HideFrameNodeImmediately(FrameNodeType::SELECTMENU)
2979 : ExecuteOverlayStatus(FrameNodeType::SELECTMENU, FrameNodeTrigger::HIDE);
2980 FireCustomMenuChangeEvent(false);
2981 } else {
2982 ExecuteOverlayStatus(FrameNodeType::SELECTMENU, FrameNodeTrigger::SHOW);
2983 FireCustomMenuChangeEvent(true);
2984 }
2985
2986 if (isExtensionMenu_ && extensionMenu_) {
2987 auto nodeTrigger = FrameNodeTrigger::SHOW;
2988 if (info->menuInfo.menuDisable || !info->menuInfo.menuIsShow) {
2989 nodeTrigger = FrameNodeTrigger::HIDE;
2990 if (backButton_) {
2991 backButton_->RemoveChild(moreOrBackSymbol_);
2992 moreOrBackSymbol_.Reset();
2993 }
2994 }
2995 ExecuteOverlayStatus(FrameNodeType::EXTENSIONMENU, nodeTrigger);
2996 if (backButton_) {
2997 ExecuteOverlayStatus(FrameNodeType::BACKBUTTON, nodeTrigger);
2998 }
2999 extensionMenu_->MarkModifyDone();
3000 if (backButton_) {
3001 backButton_->MarkModifyDone();
3002 }
3003 }
3004 }
3005
UpdateMenuOptions(const std::shared_ptr<SelectOverlayInfo> & info)3006 void SelectOverlayNode::UpdateMenuOptions(const std::shared_ptr<SelectOverlayInfo>& info)
3007 {
3008 float maxWidth = 0.0f;
3009 GetDefaultButtonAndMenuWidth(maxWidth);
3010 if (info->onCreateCallback.onCreateMenuCallback || info->onCreateCallback.onPrepareMenuCallback) {
3011 AddMenuItemByCreateMenuCallback(info, maxWidth);
3012 return;
3013 }
3014 float allocatedSize = 0.0f;
3015 bool isDefaultOverMaxWidth = AddSystemDefaultOptions(maxWidth, allocatedSize);
3016 auto extensionOptionStartIndex = -1;
3017 LandscapeMenuAddMenuOptions(isDefaultOverMaxWidth, maxWidth, allocatedSize, extensionOptionStartIndex, info);
3018
3019 if (backButton_) {
3020 isExtensionMenu_ = false;
3021 RemoveChild(backButton_);
3022 backButton_.Reset();
3023 }
3024 if (extensionMenu_) {
3025 RemoveChild(extensionMenu_);
3026 extensionMenu_.Reset();
3027 }
3028 if (extensionOptionStartIndex != -1 || isDefaultOverMaxWidth) {
3029 moreButton_ = BuildMoreOrBackButton(info, GetId(), true);
3030 CHECK_NULL_VOID(moreButton_);
3031 moreButton_->MountToParent(selectMenuInner_);
3032 isMoreOrBackSymbolIcon_ = Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE);
3033 if (isMoreOrBackSymbolIcon_) {
3034 moreOrBackSymbol_ = BuildMoreOrBackSymbol();
3035 moreOrBackSymbol_->MountToParent(moreButton_);
3036 }
3037 if (!backButton_) {
3038 backButton_ = BuildMoreOrBackButton(info, GetId(), false);
3039 CHECK_NULL_VOID(backButton_);
3040 backButton_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3041 backButton_->GetLayoutProperty()->UpdateVisibility(VisibleType::GONE);
3042 backButton_->MountToParent(Claim(this));
3043 }
3044 }
3045 AddExtensionMenuOptions(info, extensionOptionStartIndex);
3046 }
3047
UpdateMenuInner(const std::shared_ptr<SelectOverlayInfo> & info,bool noAnimation)3048 void SelectOverlayNode::UpdateMenuInner(const std::shared_ptr<SelectOverlayInfo>& info, bool noAnimation)
3049 {
3050 CHECK_NULL_VOID(selectMenuInner_);
3051 selectMenuInner_->Clean();
3052 auto selectMenuLayoutProperty = selectMenuInner_->GetLayoutProperty();
3053 CHECK_NULL_VOID(selectMenuLayoutProperty);
3054 selectMenuLayoutProperty->ClearUserDefinedIdealSize(true, true);
3055 SetSelectMenuInnerSize();
3056 selectMenuInner_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
3057 if (isExtensionMenu_) {
3058 MoreOrBackAnimation(false, noAnimation);
3059 }
3060 auto selectProperty = selectMenu_->GetLayoutProperty();
3061 CHECK_NULL_VOID(selectProperty);
3062 selectProperty->ClearUserDefinedIdealSize(true, true);
3063 UpdateMenuOptions(info);
3064 }
3065
SetSelectMenuInnerSize()3066 void SelectOverlayNode::SetSelectMenuInnerSize()
3067 {
3068 CHECK_NULL_VOID(selectMenuInner_);
3069 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
3070 CHECK_NULL_VOID(pipeline);
3071 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
3072 CHECK_NULL_VOID(textOverlayTheme);
3073 if (LessNotEqual(pipeline->GetFontScale(), AGING_MIN_SCALE)) {
3074 selectMenuInner_->GetLayoutProperty()->UpdateUserDefinedIdealSize(
3075 { std::nullopt, CalcLength(textOverlayTheme->GetMenuToolbarHeight()) });
3076 } else {
3077 selectMenuInner_->GetLayoutProperty()->UpdateUserDefinedIdealSize({ std::nullopt, std::nullopt });
3078 }
3079 }
3080
LandscapeMenuAddMenuOptions(bool isDefaultOverMaxWidth,float maxWidth,float allocatedSize,int32_t & extensionOptionStartIndex,const std::shared_ptr<SelectOverlayInfo> & info)3081 void SelectOverlayNode::LandscapeMenuAddMenuOptions(
3082 bool isDefaultOverMaxWidth, float maxWidth, float allocatedSize, int32_t& extensionOptionStartIndex,
3083 const std::shared_ptr<SelectOverlayInfo>& info)
3084 {
3085 if (isDefaultOverMaxWidth) {
3086 return;
3087 }
3088 auto itemNum = -1;
3089 CHECK_NULL_VOID(info);
3090 const std::vector<MenuOptionsParam>& menuOptionItems = info->menuOptionItems;
3091 for (auto item : menuOptionItems) {
3092 itemNum++;
3093 float extensionOptionWidth = 0.0f;
3094 auto button = BuildButton(item, GetId(), extensionOptionWidth, info); // check, different from 5 parameters
3095 CHECK_NULL_VOID(button);
3096 allocatedSize += extensionOptionWidth;
3097 if (GreatNotEqual(allocatedSize, maxWidth)) {
3098 button.Reset();
3099 extensionOptionStartIndex = itemNum;
3100 break;
3101 }
3102 button->MountToParent(selectMenuInner_);
3103 }
3104 }
3105
HandleCollaborationMenuItem(const std::vector<MenuOptionsParam> & params)3106 std::pair<std::vector<MenuOptionsParam>, bool> SelectOverlayNode::HandleCollaborationMenuItem(
3107 const std::vector<MenuOptionsParam>& params)
3108 {
3109 std::vector<MenuOptionsParam> newParams;
3110 bool needCollaboration = false;
3111 for (const auto& item : params) {
3112 if (item.id == OH_DEFAULT_COLLABORATION_SERVICE) {
3113 needCollaboration = true;
3114 continue;
3115 }
3116 newParams.push_back(item);
3117 }
3118 return { newParams, needCollaboration };
3119 }
3120
CreateMenuNode(const std::shared_ptr<SelectOverlayInfo> & info)3121 RefPtr<FrameNode> SelectOverlayNode::CreateMenuNode(const std::shared_ptr<SelectOverlayInfo>& info)
3122 {
3123 bool hasCollaborationMenu =
3124 ExpandedMenuPluginLoader::GetInstance().HasCollaborationMenu() && TextSystemMenu::IsShowCollaborationService();
3125 bool needCollaborationMenu = true;
3126 std::vector<OptionParam> params;
3127 if (info->onCreateCallback.onCreateMenuCallback || info->onCreateCallback.onPrepareMenuCallback) {
3128 auto systemItemParams = GetSystemMenuItemParams(info);
3129 if (hasCollaborationMenu) {
3130 systemItemParams.push_back({ .menuOptionsParam = { .id = OH_DEFAULT_COLLABORATION_SERVICE } });
3131 }
3132 auto createMenuItems = GetMenuOptionsParamsWithEditMenuOption(info, systemItemParams);
3133 std::tie(createMenuItems, needCollaborationMenu) = HandleCollaborationMenuItem(createMenuItems);
3134 params = GetCreateMenuOptionsParams(createMenuItems, info, 0);
3135 } else {
3136 params = GetOptionsParams(info);
3137 }
3138 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
3139 CHECK_NULL_RETURN(pipeline, nullptr);
3140 auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
3141 CHECK_NULL_RETURN(textOverlayTheme, nullptr);
3142 RefPtr<FrameNode> menuWrapper = GetMenuWrapper(params, textOverlayTheme);
3143 CHECK_NULL_RETURN(menuWrapper, nullptr);
3144 if (hasCollaborationMenu && needCollaborationMenu) {
3145 ExpandedMenuPluginLoader::GetInstance().CreateServiceCollaborationMenu(menuWrapper, info);
3146 }
3147 auto menu = DynamicCast<FrameNode>(menuWrapper->GetChildAtIndex(0));
3148 // set click position to menu
3149 CHECK_NULL_RETURN(menu, nullptr);
3150 auto props = menu->GetLayoutProperty<MenuLayoutProperty>();
3151 CHECK_NULL_RETURN(props, nullptr);
3152 OffsetF pageOffset;
3153 auto windowManager = pipeline->GetWindowManager();
3154 auto isContainerModal = pipeline->GetWindowModal() == WindowModal::CONTAINER_MODAL && windowManager &&
3155 windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING;
3156 if (isContainerModal) {
3157 pageOffset = GetPageOffset();
3158 TAG_LOGD(AceLogTag::ACE_SELECT_OVERLAY, "CreateMenuNode pageOffset:%{public}s", pageOffset.ToString().c_str());
3159 }
3160 props->UpdateMenuOffset(info->rightClickOffset + pageOffset);
3161
3162 menu->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3163 ElementRegister::GetInstance()->AddUINode(menu);
3164
3165 auto gestureEventHub = menuWrapper->GetOrCreateGestureEventHub();
3166 if (gestureEventHub) {
3167 gestureEventHub->SetHitTestMode(HitTestMode::HTMDEFAULT);
3168 }
3169 return menuWrapper;
3170 }
3171
IsInSelectedOrSelectOverlayArea(const PointF & point)3172 bool SelectOverlayNode::IsInSelectedOrSelectOverlayArea(const PointF& point)
3173 {
3174 auto pattern = GetPattern<SelectOverlayPattern>();
3175 CHECK_NULL_RETURN(pattern, false);
3176
3177 std::vector<RectF> rects;
3178 auto offset = GetGeometryNode() ? GetGeometryNode()->GetFrameOffset() : OffsetF();
3179 rects.emplace_back(pattern->GetHandleRegion(true) + offset);
3180 rects.emplace_back(pattern->GetHandleRegion(false) + offset);
3181 if (selectMenu_ && selectMenu_->GetGeometryNode()) {
3182 rects.emplace_back(selectMenu_->GetGeometryNode()->GetFrameRect() + offset);
3183 }
3184 if (extensionMenu_ && extensionMenu_->GetGeometryNode()) {
3185 rects.emplace_back(extensionMenu_->GetGeometryNode()->GetFrameRect() + offset);
3186 }
3187
3188 if (pattern->IsCustomMenu()) {
3189 for (auto& child : pattern->GetHost()->GetChildren()) {
3190 auto childFrameNode = DynamicCast<FrameNode>(child);
3191 if (!childFrameNode) {
3192 continue;
3193 }
3194 rects.emplace_back(childFrameNode->GetGeometryNode()->GetFrameRect() + offset);
3195 }
3196 }
3197
3198 for (const auto& rect : rects) {
3199 if (rect.IsInRegion(point)) {
3200 return true;
3201 }
3202 }
3203 return false;
3204 }
3205
SetClosedByGlobalEvent(bool closedByGlobalEvent)3206 void SelectOverlayNode::SetClosedByGlobalEvent(bool closedByGlobalEvent)
3207 {
3208 auto selectOverlayPattern = GetPattern<SelectOverlayPattern>();
3209 CHECK_NULL_VOID(selectOverlayPattern);
3210 selectOverlayPattern->SetClosedByGlobalTouchEvent(closedByGlobalEvent);
3211 }
3212
ShowSelectOverlay(bool animation)3213 void SelectOverlayNode::ShowSelectOverlay(bool animation)
3214 {
3215 auto pattern = GetPattern<SelectOverlayPattern>();
3216 CHECK_NULL_VOID(pattern);
3217
3218 // In SelectOverlayMode::MENU_ONLY mode, SelectOverlay controls the animation by self.
3219 if (pattern->GetMode() == SelectOverlayMode::MENU_ONLY) {
3220 if (animation) {
3221 AnimationOption option;
3222 option.SetDuration(MENU_SHOW_ANIMATION_DURATION);
3223 option.SetCurve(Curves::SHARP);
3224 AnimationUtils::Animate(option, [weak = WeakClaim(this), id = Container::CurrentId()]() {
3225 ContainerScope scope(id);
3226 auto node = weak.Upgrade();
3227 CHECK_NULL_VOID(node);
3228 node->SetFrameNodeOpacity(FrameNodeType::MENUONLY, 1.0f);
3229 }, nullptr, nullptr, GetContextRefPtr());
3230 } else {
3231 SetFrameNodeOpacity(FrameNodeType::MENUONLY, 1.0f);
3232 }
3233 return;
3234 }
3235 if (animation) {
3236 AnimationOption option;
3237 option.SetDuration(MENU_SHOW_ANIMATION_DURATION);
3238 option.SetCurve(Curves::SHARP);
3239
3240 AnimationUtils::Animate(option, [weak = WeakClaim(this), id = Container::CurrentId()]() {
3241 ContainerScope scope(id);
3242 auto node = weak.Upgrade();
3243 CHECK_NULL_VOID(node);
3244 node->SetSelectMenuOpacity(1.0);
3245 node->SetExtensionMenuOpacity(1.0);
3246 node->SetBackButtonOpacity(1.0);
3247 }, nullptr, nullptr, GetContextRefPtr());
3248 } else {
3249 SetSelectMenuOpacity(1.0);
3250 SetExtensionMenuOpacity(1.0);
3251 SetBackButtonOpacity(1.0);
3252 }
3253 pattern->SetHasShowAnimation(animation);
3254 }
3255
HideSelectOverlay(const std::function<void ()> & callback)3256 void SelectOverlayNode::HideSelectOverlay(const std::function<void()>& callback)
3257 {
3258 AnimationOption handleOption;
3259 handleOption.SetDuration(HANDLE_ANIMATION_DURATION);
3260 handleOption.SetCurve(Curves::SHARP);
3261
3262 AnimationUtils::Animate(handleOption, [weak = WeakClaim(this), id = Container::CurrentId()]() {
3263 ContainerScope scope(id);
3264 auto node = weak.Upgrade();
3265 CHECK_NULL_VOID(node);
3266 auto pattern = node->GetPattern<SelectOverlayPattern>();
3267 CHECK_NULL_VOID(pattern);
3268 auto contentModifier = pattern->GetContentModifier();
3269 CHECK_NULL_VOID(contentModifier);
3270 contentModifier->SetHandleOpacity(0.0);
3271 }, nullptr, nullptr, GetContextRefPtr());
3272
3273 AnimationOption overlayOption;
3274 overlayOption.SetDuration(MENU_HIDE_ANIMATION_DURATION);
3275 overlayOption.SetCurve(Curves::SHARP);
3276 auto pattern = GetPattern<SelectOverlayPattern>();
3277 CHECK_NULL_VOID(pattern);
3278
3279 // In SelectOverlayMode::MENU_ONLY mode, SelectOverlay controls the animation by self.
3280 if (pattern->GetMode() == SelectOverlayMode::MENU_ONLY) {
3281 AnimationUtils::Animate(
3282 overlayOption,
3283 [weak = WeakClaim(this), id = Container::CurrentId()]() {
3284 ContainerScope scope(id);
3285 auto node = weak.Upgrade();
3286 CHECK_NULL_VOID(node);
3287 node->SetFrameNodeOpacity(FrameNodeType::MENUONLY, 0.0f);
3288 },
3289 callback, nullptr, GetContextRefPtr());
3290 return;
3291 }
3292
3293 AnimationUtils::Animate(
3294 overlayOption,
3295 [weak = WeakClaim(this), id = Container::CurrentId()]() {
3296 ContainerScope scope(id);
3297 auto node = weak.Upgrade();
3298 CHECK_NULL_VOID(node);
3299 node->SetSelectMenuOpacity(0.0);
3300 node->SetExtensionMenuOpacity(0.0);
3301 node->SetBackButtonOpacity(0.0);
3302 auto pattern = node->GetPattern<SelectOverlayPattern>();
3303 CHECK_NULL_VOID(pattern);
3304 auto overlayModifier = pattern->GetOverlayModifier();
3305 CHECK_NULL_VOID(overlayModifier);
3306 overlayModifier->SetCirclesAndBackArrowOpacity(0.0);
3307 },
3308 callback, nullptr, GetContextRefPtr());
3309 }
3310
ExecuteOverlayStatus(FrameNodeType type,FrameNodeTrigger trigger)3311 void SelectOverlayNode::ExecuteOverlayStatus(FrameNodeType type, FrameNodeTrigger trigger)
3312 {
3313 FrameNodeStatus status = FrameNodeStatus::VISIBLE;
3314 switch (type) {
3315 case FrameNodeType::SELECTMENU:
3316 status = selectMenuStatus_;
3317 break;
3318 case FrameNodeType::EXTENSIONMENU:
3319 status = extensionMenuStatus_;
3320 break;
3321 case FrameNodeType::BACKBUTTON:
3322 status = backButtonStatus_;
3323 break;
3324 case FrameNodeType::MENUONLY:
3325 status = menuOnlyStatus_;
3326 break;
3327 default:
3328 break;
3329 }
3330
3331 auto stateFuncIter = stateFuncs_.find(status);
3332 if (stateFuncIter != stateFuncs_.end()) {
3333 auto stateFunc = stateFuncIter->second;
3334 CHECK_NULL_VOID(stateFunc);
3335 (this->*stateFunc)(type, trigger);
3336 }
3337 }
3338
SetFrameNodeStatus(FrameNodeType type,FrameNodeStatus status)3339 void SelectOverlayNode::SetFrameNodeStatus(FrameNodeType type, FrameNodeStatus status)
3340 {
3341 switch (type) {
3342 case FrameNodeType::SELECTMENU:
3343 selectMenuStatus_ = status;
3344 break;
3345 case FrameNodeType::EXTENSIONMENU:
3346 extensionMenuStatus_ = status;
3347 break;
3348 case FrameNodeType::BACKBUTTON:
3349 backButtonStatus_ = status;
3350 break;
3351 case FrameNodeType::MENUONLY:
3352 menuOnlyStatus_ = status;
3353 break;
3354 default:
3355 break;
3356 }
3357 }
3358
SetFrameNodeVisibility(FrameNodeType type,VisibleType visibleType)3359 void SelectOverlayNode::SetFrameNodeVisibility(FrameNodeType type, VisibleType visibleType)
3360 {
3361 switch (type) {
3362 case FrameNodeType::SELECTMENU:
3363 selectMenu_->GetLayoutProperty()->UpdateVisibility(visibleType);
3364 break;
3365 case FrameNodeType::EXTENSIONMENU:
3366 extensionMenu_->GetLayoutProperty()->UpdateVisibility(visibleType);
3367 break;
3368 case FrameNodeType::BACKBUTTON:
3369 backButton_->GetLayoutProperty()->UpdateVisibility(visibleType);
3370 break;
3371 case FrameNodeType::MENUONLY:
3372 {
3373 auto layoutProperty = GetLayoutProperty();
3374 CHECK_NULL_VOID(layoutProperty);
3375 layoutProperty->UpdateVisibility(visibleType);
3376 break;
3377 }
3378 default:
3379 break;
3380 }
3381 }
3382
SetFrameNodeOpacity(FrameNodeType type,float opacity)3383 void SelectOverlayNode::SetFrameNodeOpacity(FrameNodeType type, float opacity)
3384 {
3385 switch (type) {
3386 case FrameNodeType::SELECTMENU:
3387 SetSelectMenuOpacity(opacity);
3388 break;
3389 case FrameNodeType::EXTENSIONMENU:
3390 SetExtensionMenuOpacity(opacity);
3391 break;
3392 case FrameNodeType::BACKBUTTON:
3393 SetBackButtonOpacity(opacity);
3394 break;
3395 case FrameNodeType::MENUONLY:
3396 {
3397 auto renderContext = GetRenderContext();
3398 CHECK_NULL_VOID(renderContext);
3399 renderContext->UpdateOpacity(opacity);
3400 break;
3401 }
3402 default:
3403 break;
3404 }
3405 }
3406
HideFrameNodeImmediately(FrameNodeType type)3407 void SelectOverlayNode::HideFrameNodeImmediately(FrameNodeType type)
3408 {
3409 SetFrameNodeStatus(type, FrameNodeStatus::GONE);
3410 SetFrameNodeVisibility(type, VisibleType::GONE);
3411 SetFrameNodeOpacity(type, 0.0f);
3412 HideOrShowCirclesAndBackArrow(type, 0.0f);
3413 }
3414
HideOrShowCirclesAndBackArrow(FrameNodeType type,float value)3415 void SelectOverlayNode::HideOrShowCirclesAndBackArrow(FrameNodeType type, float value)
3416 {
3417 if (type == FrameNodeType::SELECTMENU) { // select menu
3418 auto pattern = GetPattern<SelectOverlayPattern>();
3419 CHECK_NULL_VOID(pattern);
3420 auto overlayModifier = pattern->GetOverlayModifier();
3421 CHECK_NULL_VOID(overlayModifier);
3422 overlayModifier->SetCirclesAndBackArrowOpacity(value);
3423 }
3424 }
3425
SetSelectMenuOpacity(float value)3426 void SelectOverlayNode::SetSelectMenuOpacity(float value)
3427 {
3428 CHECK_NULL_VOID(selectMenu_);
3429 CHECK_NULL_VOID(selectMenu_->GetRenderContext());
3430 selectMenu_->GetRenderContext()->UpdateOpacity(value);
3431 HideOrShowCirclesAndBackArrow(FrameNodeType::SELECTMENU, value);
3432 }
3433
SetExtensionMenuOpacity(float value)3434 void SelectOverlayNode::SetExtensionMenuOpacity(float value)
3435 {
3436 CHECK_NULL_VOID(extensionMenu_);
3437 CHECK_NULL_VOID(extensionMenu_->GetRenderContext());
3438 extensionMenu_->GetRenderContext()->UpdateOpacity(value);
3439 }
3440
SetBackButtonOpacity(float value)3441 void SelectOverlayNode::SetBackButtonOpacity(float value)
3442 {
3443 CHECK_NULL_VOID(backButton_);
3444 CHECK_NULL_VOID(backButton_->GetRenderContext());
3445 backButton_->GetRenderContext()->UpdateOpacity(value);
3446 }
3447
NotifyUpdateToolBar(bool itemChanged,bool withoutAnimation)3448 void SelectOverlayNode::NotifyUpdateToolBar(bool itemChanged, bool withoutAnimation)
3449 {
3450 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
3451 CHECK_NULL_VOID(pipeline);
3452 auto overlayManager = pipeline->GetSelectOverlayManager();
3453 CHECK_NULL_VOID(overlayManager);
3454 auto newOverlayManager = overlayManager->GetSelectContentOverlayManager();
3455 CHECK_NULL_VOID(newOverlayManager);
3456 newOverlayManager->NotifyUpdateToolBar(itemChanged, withoutAnimation);
3457 }
3458
SwitchToOverlayMode()3459 void SelectOverlayNode::SwitchToOverlayMode()
3460 {
3461 auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
3462 CHECK_NULL_VOID(pipeline);
3463 auto overlayManager = pipeline->GetSelectOverlayManager();
3464 CHECK_NULL_VOID(overlayManager);
3465 auto newOverlayManager = overlayManager->GetSelectContentOverlayManager();
3466 CHECK_NULL_VOID(newOverlayManager);
3467 newOverlayManager->SwitchToHandleMode(HandleLevelMode::OVERLAY, false);
3468 }
3469
UpdateSelectMenuBg()3470 void SelectOverlayNode::UpdateSelectMenuBg()
3471 {
3472 CHECK_NULL_VOID(selectMenu_);
3473 auto pipelineContext = GetContext();
3474 CHECK_NULL_VOID(pipelineContext);
3475 auto textOverlayTheme = pipelineContext->GetTheme<TextOverlayTheme>();
3476 CHECK_NULL_VOID(textOverlayTheme);
3477 auto shadowTheme = pipelineContext->GetTheme<ShadowTheme>();
3478 CHECK_NULL_VOID(shadowTheme);
3479 auto colorMode = pipelineContext->GetColorMode();
3480 auto renderContext = selectMenu_->GetRenderContext();
3481 CHECK_NULL_VOID(renderContext);
3482 renderContext->UpdateBackShadow(shadowTheme->GetShadow(ShadowStyle::OuterDefaultMD, colorMode));
3483 BlurStyleOption styleOption;
3484 styleOption.blurStyle = BlurStyle::COMPONENT_ULTRA_THICK;
3485 renderContext->UpdateBackBlurStyle(styleOption);
3486 renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
3487 }
3488
AddCustomMenuCallbacks(const std::shared_ptr<SelectOverlayInfo> & info)3489 void SelectOverlayNode::AddCustomMenuCallbacks(const std::shared_ptr<SelectOverlayInfo>& info)
3490 {
3491 auto overlayEventHub = GetOrCreateEventHub<SelectOverlayEventHub>();
3492 CHECK_NULL_VOID(overlayEventHub);
3493 if (info->menuCallback.onMenuShow) {
3494 overlayEventHub->SetMenuShowCallback(std::move(info->menuCallback.onMenuShow));
3495 }
3496 if (info->menuCallback.onMenuHide) {
3497 overlayEventHub->SetMenuHideCallback(std::move(info->menuCallback.onMenuHide));
3498 }
3499 if (info->menuCallback.onAppear) {
3500 overlayEventHub->SetMenuAppearCallback(std::move(info->menuCallback.onAppear));
3501 }
3502 if (info->menuCallback.onDisappear) {
3503 overlayEventHub->SetMenuDisappearCallback(std::move(info->menuCallback.onDisappear));
3504 }
3505 CHECK_NULL_VOID(selectMenu_);
3506 auto eventHub = selectMenu_->GetOrCreateEventHub<EventHub>();
3507 CHECK_NULL_VOID(eventHub);
3508 eventHub->SetOnAppear([weak = WeakClaim(this)]() {
3509 auto overlayNode = weak.Upgrade();
3510 CHECK_NULL_VOID(overlayNode);
3511 overlayNode->OnCustomSelectMenuAppear();
3512 });
3513 eventHub->SetOnDisappear([weakHub = WeakClaim(AceType::RawPtr(overlayEventHub))]() {
3514 auto overlayEventHub = weakHub.Upgrade();
3515 CHECK_NULL_VOID(overlayEventHub);
3516 overlayEventHub->FireDisappearEvent();
3517 });
3518 }
3519
OnCustomSelectMenuAppear()3520 void SelectOverlayNode::OnCustomSelectMenuAppear()
3521 {
3522 isCustomMenuAppear_ = true;
3523 auto eventHub = GetOrCreateEventHub<SelectOverlayEventHub>();
3524 CHECK_NULL_VOID(eventHub);
3525 // fire appear event.
3526 eventHub->FireAppearEvent();
3527 // fire onMenuShow
3528 auto pattern = GetPattern<SelectOverlayPattern>();
3529 CHECK_NULL_VOID(pattern);
3530 auto info = pattern->GetSelectOverlayInfo();
3531 CHECK_NULL_VOID(info);
3532 bool isHideMenu = info->menuInfo.menuDisable || !info->menuInfo.menuIsShow;
3533 if (isHideMenu) {
3534 eventHub->FireMenuVisibilityChangeEvent(true);
3535 }
3536 eventHub->FireMenuVisibilityChangeEvent(!isHideMenu);
3537 }
3538
FireCustomMenuChangeEvent(bool isMenuShow)3539 void SelectOverlayNode::FireCustomMenuChangeEvent(bool isMenuShow)
3540 {
3541 if (isCustomMenuAppear_) {
3542 auto eventHub = GetOrCreateEventHub<SelectOverlayEventHub>();
3543 CHECK_NULL_VOID(eventHub);
3544 eventHub->FireMenuVisibilityChangeEvent(isMenuShow);
3545 }
3546 }
3547
OnDetachFromMainTree(bool recursive,PipelineContext * context)3548 void SelectOverlayNode::OnDetachFromMainTree(bool recursive, PipelineContext* context)
3549 {
3550 FireCustomMenuChangeEvent(false);
3551 isCustomMenuAppear_ = false;
3552 FrameNode::OnDetachFromMainTree(recursive, context);
3553 }
3554
UpdateToolBarFromMainWindow(bool menuItemChanged,bool noAnimation)3555 void SelectOverlayNode::UpdateToolBarFromMainWindow(bool menuItemChanged, bool noAnimation)
3556 {
3557 auto pattern = GetPattern<SelectOverlayPattern>();
3558 CHECK_NULL_VOID(pattern);
3559 if (pattern->GetIsMenuShowInSubWindow()) {
3560 auto containerId = pattern->GetContainerId();
3561 if (containerId != -1) {
3562 ContainerScope scope(containerId);
3563 UpdateToolBar(menuItemChanged, noAnimation);
3564 return;
3565 }
3566 }
3567
3568 UpdateToolBar(menuItemChanged, noAnimation);
3569 }
3570
ShowAskCelia(float maxWidth,float & allocatedSize,std::shared_ptr<SelectOverlayInfo> & info,const std::string & label)3571 void SelectOverlayNode::ShowAskCelia(
3572 float maxWidth, float& allocatedSize, std::shared_ptr<SelectOverlayInfo>& info, const std::string& label)
3573 {
3574 if (info->menuInfo.isAskCeliaEnabled && TextSystemMenu::IsShowAskCelia()) {
3575 CHECK_EQUAL_VOID(isDefaultBtnOverMaxWidth_, true);
3576 float buttonWidth = 0.0f;
3577 ButtonBasicInfo buttonBasicInfo = { .data = label, .buttonType = SelectOverlayMenuButtonType::AIBUTTON };
3578 auto button = BuildButton(info, info->menuCallback.onAskCelia, GetId(), buttonWidth, buttonBasicInfo);
3579 CHECK_NULL_VOID(button);
3580 if (GreatOrEqual(maxWidth - allocatedSize, buttonWidth)) {
3581 button->MountToParent(selectMenuInner_);
3582 allocatedSize += buttonWidth;
3583 isShowInDefaultMenu_[OPTION_INDEX_ASK_CELIA] = true;
3584 } else {
3585 button.Reset();
3586 isDefaultBtnOverMaxWidth_ = true;
3587 }
3588 } else {
3589 isShowInDefaultMenu_[OPTION_INDEX_ASK_CELIA] = true;
3590 }
3591 }
3592 } // namespace OHOS::Ace::NG
3593