• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/shadow_config.h"
32 #include "core/components/custom_paint/rosen_render_custom_paint.h"
33 #include "core/components/text_overlay/text_overlay_theme.h"
34 #include "core/components_ng/base/frame_node.h"
35 #include "core/components_ng/base/view_stack_processor.h"
36 #include "core/components_ng/event/event_hub.h"
37 #include "core/components_ng/pattern/button/button_pattern.h"
38 #include "core/components_ng/pattern/image/image_pattern.h"
39 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
40 #include "core/components_ng/pattern/menu/menu_pattern.h"
41 #include "core/components_ng/pattern/menu/menu_view.h"
42 #include "core/components_ng/pattern/select_overlay/select_overlay_pattern.h"
43 #include "core/components_ng/pattern/select_overlay/select_overlay_property.h"
44 #include "core/components_ng/pattern/text/text_pattern.h"
45 #include "core/components_ng/property/calc_length.h"
46 #include "core/components_ng/property/property.h"
47 #include "core/gestures/gesture_info.h"
48 #include "core/pipeline/base/element_register.h"
49 #include "core/pipeline_ng/pipeline_context.h"
50 
51 namespace OHOS::Ace::NG {
52 namespace {
53 constexpr char BUTTON_COPY_ALL[] = "textoverlay.select_all";
54 constexpr char BUTTON_CUT[] = "textoverlay.cut";
55 constexpr char BUTTON_COPY[] = "textoverlay.copy";
56 constexpr char BUTTON_PASTE[] = "textoverlay.paste";
57 constexpr char BUTTON_SHARE[] = "textoverlay.share";
58 constexpr char BUTTON_TRANSLATE[] = "textoverlay.translate";
59 constexpr char BUTTON_SEARCH[] = "textoverlay.search";
60 
61 constexpr int32_t OPTION_INDEX_CUT = 0;
62 constexpr int32_t OPTION_INDEX_COPY = 1;
63 constexpr int32_t OPTION_INDEX_PASTE = 2;
64 constexpr int32_t OPTION_INDEX_COPY_ALL = 3;
65 constexpr int32_t OPTION_INDEX_SHARE = 4;
66 constexpr int32_t OPTION_INDEX_TRANSLATE = 5;
67 constexpr int32_t OPTION_INDEX_SEARCH = 6;
68 constexpr int32_t ANIMATION_DURATION1 = 350;
69 constexpr int32_t ANIMATION_DURATION2 = 150;
70 
71 constexpr Dimension MORE_MENU_TRANSLATE = -7.5_vp;
72 constexpr Dimension MAX_DIAMETER = 3.5_vp;
73 constexpr Dimension MIN_DIAMETER = 1.5_vp;
74 constexpr Dimension MIN_ARROWHEAD_DIAMETER = 2.0_vp;
75 constexpr Dimension ANIMATION_TEXT_OFFSET = 12.0_vp;
76 
BuildButton(const std::string & data,const std::function<void ()> & callback,int32_t overlayId,float & buttonWidth,bool isSelectAll=false)77 RefPtr<FrameNode> BuildButton(const std::string& data, const std::function<void()>& callback, int32_t overlayId,
78     float& buttonWidth, bool isSelectAll = false)
79 {
80     auto button = FrameNode::GetOrCreateFrameNode("SelectMenuButton", ElementRegister::GetInstance()->MakeUniqueId(),
81         []() { return AceType::MakeRefPtr<ButtonPattern>(); });
82     auto text = FrameNode::GetOrCreateFrameNode("SelectMenuButtonText", ElementRegister::GetInstance()->MakeUniqueId(),
83         []() { return AceType::MakeRefPtr<TextPattern>(); });
84     auto textLayoutProperty = text->GetLayoutProperty<TextLayoutProperty>();
85     CHECK_NULL_RETURN(textLayoutProperty, button);
86     textLayoutProperty->UpdateContent(data);
87     text->MountToParent(button);
88     auto pipeline = PipelineContext::GetCurrentContext();
89     CHECK_NULL_RETURN(pipeline, button);
90     auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
91     CHECK_NULL_RETURN(textOverlayTheme, button);
92     auto textStyle = textOverlayTheme->GetMenuButtonTextStyle();
93     textLayoutProperty->UpdateFontSize(textStyle.GetFontSize());
94     textLayoutProperty->UpdateFontWeight(textStyle.GetFontWeight());
95     textLayoutProperty->UpdateMaxLines(1);
96     if (callback) {
97         textLayoutProperty->UpdateTextColor(textStyle.GetTextColor());
98     } else {
99         textLayoutProperty->UpdateTextColor(
100             textStyle.GetTextColor().BlendOpacity(textOverlayTheme->GetAlphaDisabled()));
101     }
102     text->MarkModifyDone();
103 
104     auto buttonLayoutProperty = button->GetLayoutProperty<ButtonLayoutProperty>();
105     CHECK_NULL_RETURN(buttonLayoutProperty, button);
106     const auto& padding = textOverlayTheme->GetMenuButtonPadding();
107     auto left = CalcLength(padding.Left().ConvertToPx());
108     auto right = CalcLength(padding.Right().ConvertToPx());
109     auto top = CalcLength(padding.Top().ConvertToPx());
110     auto bottom = CalcLength(padding.Bottom().ConvertToPx());
111     buttonLayoutProperty->UpdatePadding({ left, right, top, bottom });
112     MeasureContext content;
113     content.textContent = data;
114     content.fontSize = textStyle.GetFontSize();
115     auto fontweight = StringUtils::FontWeightToString(textStyle.GetFontWeight());
116     content.fontWeight = fontweight;
117 #ifdef ENABLE_ROSEN_BACKEND
118     buttonWidth = static_cast<float>(RosenRenderCustomPaint::MeasureTextSizeInner(content).Width());
119 #else
120     buttonWidth = 0.0f;
121 #endif
122     // Calculate the width of default option include button padding.
123     buttonWidth = buttonWidth + padding.Left().ConvertToPx() + padding.Right().ConvertToPx();
124     buttonLayoutProperty->UpdateUserDefinedIdealSize(
125         { CalcLength(buttonWidth), CalcLength(textOverlayTheme->GetMenuButtonHeight()) });
126     buttonLayoutProperty->UpdateFlexShrink(0);
127     button->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
128 
129     if (callback) {
130         button->GetOrCreateGestureEventHub()->SetUserOnClick(
131             [callback, overlayId, isSelectAll](GestureEvent& /*info*/) {
132                 auto pipeline = PipelineContext::GetCurrentContext();
133                 CHECK_NULL_VOID(pipeline);
134                 auto overlayManager = pipeline->GetSelectOverlayManager();
135                 CHECK_NULL_VOID(overlayManager);
136                 auto selectOverlay = overlayManager->GetSelectOverlayNode(overlayId);
137                 CHECK_NULL_VOID(selectOverlay);
138                 auto isDoingAnimation = selectOverlay->GetAnimationStatus();
139                 CHECK_NULL_VOID(!isDoingAnimation);
140                 auto isExtensionMenu = selectOverlay->GetIsExtensionMenu();
141                 CHECK_NULL_VOID(!isExtensionMenu);
142                 if (callback) {
143                     callback();
144                 }
145                 // close text overlay.
146                 if (!isSelectAll) {
147                     overlayManager->DestroySelectOverlay(overlayId, true);
148                 }
149             });
150     } else {
151         auto buttonEventHub = button->GetEventHub<OptionEventHub>();
152         CHECK_NULL_RETURN(buttonEventHub, button);
153         buttonEventHub->SetEnabled(false);
154     }
155     button->MarkModifyDone();
156     return button;
157 }
158 
BuildButton(const std::string & data,const std::function<void (std::string &)> & callback,int32_t overlayId,float & contentWidth)159 RefPtr<FrameNode> BuildButton(
160     const std::string& data, const std::function<void(std::string&)>& callback, int32_t overlayId, float& contentWidth)
161 {
162     auto button = FrameNode::GetOrCreateFrameNode("SelectMenuButton", ElementRegister::GetInstance()->MakeUniqueId(),
163         []() { return AceType::MakeRefPtr<ButtonPattern>(); });
164     auto text = FrameNode::GetOrCreateFrameNode("SelectMenuButtonText", ElementRegister::GetInstance()->MakeUniqueId(),
165         []() { return AceType::MakeRefPtr<TextPattern>(); });
166 
167     // Update text property and mount to button.
168     auto textLayoutProperty = text->GetLayoutProperty<TextLayoutProperty>();
169     CHECK_NULL_RETURN(textLayoutProperty, button);
170     textLayoutProperty->UpdateContent(data);
171     text->MountToParent(button);
172     auto pipeline = PipelineContext::GetCurrentContext();
173     CHECK_NULL_RETURN(pipeline, button);
174     auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
175     CHECK_NULL_RETURN(textOverlayTheme, button);
176     auto textStyle = textOverlayTheme->GetMenuButtonTextStyle();
177     textLayoutProperty->UpdateFontSize(textStyle.GetFontSize());
178     textLayoutProperty->UpdateTextColor(textStyle.GetTextColor());
179     textLayoutProperty->UpdateFontWeight(textStyle.GetFontWeight());
180     text->MarkModifyDone();
181 
182     // Calculate the width of entension option include button padding.
183     MeasureContext content;
184     content.textContent = data;
185     content.fontSize = textStyle.GetFontSize();
186     auto fontweight = StringUtils::FontWeightToString(textStyle.GetFontWeight());
187     content.fontWeight = fontweight;
188 #ifdef ENABLE_ROSEN_BACKEND
189     contentWidth = static_cast<float>(RosenRenderCustomPaint::MeasureTextSizeInner(content).Width());
190 #else
191     contentWidth = 0.0f;
192 #endif
193     const auto& padding = textOverlayTheme->GetMenuButtonPadding();
194     auto left = CalcLength(padding.Left().ConvertToPx());
195     auto right = CalcLength(padding.Right().ConvertToPx());
196     auto top = CalcLength(padding.Top().ConvertToPx());
197     auto bottom = CalcLength(padding.Bottom().ConvertToPx());
198     contentWidth = contentWidth + padding.Left().ConvertToPx() + padding.Right().ConvertToPx();
199 
200     // Update button property.
201     auto buttonLayoutProperty = button->GetLayoutProperty<ButtonLayoutProperty>();
202     CHECK_NULL_RETURN(buttonLayoutProperty, button);
203     buttonLayoutProperty->UpdatePadding({ left, right, top, bottom });
204     buttonLayoutProperty->UpdateUserDefinedIdealSize(
205         { CalcLength(contentWidth), CalcLength(textOverlayTheme->GetMenuButtonHeight()) });
206     buttonLayoutProperty->UpdateFlexShrink(0);
207     button->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
208     button->GetOrCreateGestureEventHub()->SetUserOnClick([callback, overlayId](GestureEvent& /*info*/) {
209         auto pipeline = PipelineContext::GetCurrentContext();
210         CHECK_NULL_VOID(pipeline);
211         auto overlayManager = pipeline->GetSelectOverlayManager();
212         CHECK_NULL_VOID(overlayManager);
213 
214         auto selectOverlay = overlayManager->GetSelectOverlayNode(overlayId);
215         CHECK_NULL_VOID(selectOverlay);
216         auto pattern = selectOverlay->GetPattern<SelectOverlayPattern>();
217         auto selectInfo = pattern->GetSelectInfo();
218         if (callback) {
219             callback(selectInfo);
220         }
221         // close text overlay.
222         overlayManager->DestroySelectOverlay(overlayId);
223     });
224     button->MarkModifyDone();
225     return button;
226 }
227 
BuildMoreOrBackButton(int32_t overlayId,bool isMoreButton)228 RefPtr<FrameNode> BuildMoreOrBackButton(int32_t overlayId, bool isMoreButton)
229 {
230     auto button = FrameNode::GetOrCreateFrameNode("SelectMoreOrBackButton",
231         ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<ButtonPattern>(); });
232     auto pipeline = PipelineContext::GetCurrentContext();
233     CHECK_NULL_RETURN(pipeline, button);
234     auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
235     CHECK_NULL_RETURN(textOverlayTheme, button);
236 
237     // Update property.
238     auto buttonLayoutProperty = button->GetLayoutProperty<ButtonLayoutProperty>();
239     CHECK_NULL_RETURN(buttonLayoutProperty, button);
240 
241     const auto& padding = textOverlayTheme->GetMenuPadding();
242 
243     auto sideWidth = CalcLength(textOverlayTheme->GetMenuToolbarHeight().ConvertToPx() - padding.Top().ConvertToPx() -
244                                 padding.Bottom().ConvertToPx());
245     buttonLayoutProperty->UpdateUserDefinedIdealSize({ sideWidth, sideWidth });
246 
247     if (!isMoreButton) {
248         auto left = CalcLength(padding.Left().ConvertToPx());
249         auto right = CalcLength(padding.Right().ConvertToPx());
250         auto top = CalcLength(padding.Top().ConvertToPx());
251         auto bottom = CalcLength(padding.Bottom().ConvertToPx());
252         buttonLayoutProperty->UpdateMargin({ left, right, top, bottom });
253         buttonLayoutProperty->UpdateVisibility(VisibleType::GONE);
254     }
255 
256     button->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
257     button->GetOrCreateGestureEventHub()->SetUserOnClick([overlayId, isMore = isMoreButton](GestureEvent& /*info*/) {
258         auto pipeline = PipelineContext::GetCurrentContext();
259         CHECK_NULL_VOID(pipeline);
260         auto overlayManager = pipeline->GetSelectOverlayManager();
261         CHECK_NULL_VOID(overlayManager);
262         auto selectOverlay = overlayManager->GetSelectOverlayNode(overlayId);
263         CHECK_NULL_VOID(selectOverlay);
264         // When click button , change to extensionMenu or change to the default menu(selectMenu_).
265         selectOverlay->MoreOrBackAnimation(isMore);
266     });
267     button->MarkModifyDone();
268     return button;
269 }
270 
GetPageOffset()271 OffsetF GetPageOffset()
272 {
273     auto pipeline = PipelineContext::GetCurrentContext();
274     CHECK_NULL_RETURN(pipeline, OffsetF());
275     auto stageManager = pipeline->GetStageManager();
276     CHECK_NULL_RETURN(stageManager, OffsetF());
277     auto page = stageManager->GetLastPage();
278     CHECK_NULL_RETURN(page, OffsetF());
279     return page->GetOffsetRelativeToWindow();
280 }
281 
GetOptionsParams(const std::shared_ptr<SelectOverlayInfo> & info)282 std::vector<OptionParam> GetOptionsParams(const std::shared_ptr<SelectOverlayInfo>& info)
283 {
284     std::vector<OptionParam> params;
285     params.emplace_back(Localization::GetInstance()->GetEntryLetters(BUTTON_CUT), info->menuCallback.onCut);
286     params.emplace_back(Localization::GetInstance()->GetEntryLetters(BUTTON_COPY), info->menuCallback.onCopy);
287     params.emplace_back(Localization::GetInstance()->GetEntryLetters(BUTTON_PASTE), info->menuCallback.onPaste);
288     params.emplace_back(Localization::GetInstance()->GetEntryLetters(BUTTON_COPY_ALL), info->menuCallback.onSelectAll);
289     return params;
290 }
291 
SetOptionDisable(const RefPtr<FrameNode> & option)292 void SetOptionDisable(const RefPtr<FrameNode>& option)
293 {
294     CHECK_NULL_VOID(option);
295     auto optionEventHub = option->GetEventHub<OptionEventHub>();
296     CHECK_NULL_VOID(optionEventHub);
297     optionEventHub->SetEnabled(false);
298     option->MarkModifyDone();
299 }
300 
SetOptionsAction(const std::shared_ptr<SelectOverlayInfo> & info,const std::vector<RefPtr<FrameNode>> & options)301 void SetOptionsAction(const std::shared_ptr<SelectOverlayInfo>& info, const std::vector<RefPtr<FrameNode>>& options)
302 {
303     if (options.empty()) {
304         return;
305     }
306     if (!info->menuInfo.showCut) {
307         SetOptionDisable(options[OPTION_INDEX_CUT]);
308     }
309     if (!info->menuInfo.showCopy) {
310         SetOptionDisable(options[OPTION_INDEX_COPY]);
311     }
312     if (!info->menuInfo.showPaste) {
313         SetOptionDisable(options[OPTION_INDEX_PASTE]);
314     }
315     if (!info->menuInfo.showCopyAll) {
316         SetOptionDisable(options[OPTION_INDEX_COPY_ALL]);
317     }
318 }
319 
SetOptionsAction(const std::vector<RefPtr<FrameNode>> & options)320 void SetOptionsAction(const std::vector<RefPtr<FrameNode>>& options)
321 {
322     for (const auto& option : options) {
323         SetOptionDisable(option);
324     }
325 }
326 } // namespace
327 
SelectOverlayNode(const std::shared_ptr<SelectOverlayInfo> & info)328 SelectOverlayNode::SelectOverlayNode(const std::shared_ptr<SelectOverlayInfo>& info)
329     : FrameNode(V2::SELECT_OVERLAY_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
330           MakeRefPtr<SelectOverlayPattern>(info))
331 {
332     stateFuncs_[FrameNodeStatus::VISIBLE] = &SelectOverlayNode::DispatchVisibleState;
333     stateFuncs_[FrameNodeStatus::VISIBLETOGONE] = &SelectOverlayNode::DispatchVisibleToGoneState;
334     stateFuncs_[FrameNodeStatus::GONE] = &SelectOverlayNode::DispatchGoneState;
335     stateFuncs_[FrameNodeStatus::GONETOVISIBLE] = &SelectOverlayNode::DispatchGoneToVisibleState;
336 }
337 
DispatchVisibleState(FrameNodeType type,FrameNodeTrigger trigger)338 void SelectOverlayNode::DispatchVisibleState(FrameNodeType type, FrameNodeTrigger trigger)
339 {
340     AnimationOption option;
341     option.SetDuration(MENU_HIDE_ANIMATION_DURATION);
342     option.SetCurve(Curves::SHARP);
343 
344     switch (trigger) {
345         case FrameNodeTrigger::HIDE:
346             SetFrameNodeStatus(type, FrameNodeStatus::VISIBLETOGONE);
347             AnimationUtils::Animate(
348                 option,
349                 [weak = WeakClaim(this), type]() {
350                     auto node = weak.Upgrade();
351                     CHECK_NULL_VOID(node);
352                     node->SetFrameNodeOpacity(type, 0.0);
353                 },
354                 [weak = WeakClaim(this), type]() {
355                     auto node = weak.Upgrade();
356                     CHECK_NULL_VOID(node);
357                     node->ExecuteOverlayStatus(type, FrameNodeTrigger::HIDDEN);
358                 });
359             break;
360         case FrameNodeTrigger::SHOW:
361         case FrameNodeTrigger::SHOWN:
362         case FrameNodeTrigger::HIDDEN:
363         default:
364             break;
365     }
366 }
367 
DispatchVisibleToGoneState(FrameNodeType type,FrameNodeTrigger trigger)368 void SelectOverlayNode::DispatchVisibleToGoneState(FrameNodeType type, FrameNodeTrigger trigger)
369 {
370     AnimationOption option;
371     option.SetDuration(MENU_SHOW_ANIMATION_DURATION);
372     option.SetCurve(Curves::SHARP);
373 
374     switch (trigger) {
375         case FrameNodeTrigger::SHOW:
376             SetFrameNodeStatus(type, FrameNodeStatus::GONETOVISIBLE);
377             SetFrameNodeVisibility(type, VisibleType::VISIBLE);
378             AnimationUtils::Animate(
379                 option,
380                 [weak = WeakClaim(this), type]() {
381                     auto node = weak.Upgrade();
382                     CHECK_NULL_VOID(node);
383                     node->SetFrameNodeOpacity(type, 1.0);
384                 },
385                 [weak = WeakClaim(this), type]() {
386                     auto node = weak.Upgrade();
387                     CHECK_NULL_VOID(node);
388                     node->ExecuteOverlayStatus(type, FrameNodeTrigger::SHOWN);
389                 });
390             break;
391         case FrameNodeTrigger::HIDDEN:
392             SetFrameNodeStatus(type, FrameNodeStatus::GONE);
393             SetFrameNodeVisibility(type, VisibleType::GONE);
394             break;
395         case FrameNodeTrigger::SHOWN:
396         case FrameNodeTrigger::HIDE:
397         default:
398             break;
399     }
400 }
401 
DispatchGoneState(FrameNodeType type,FrameNodeTrigger trigger)402 void SelectOverlayNode::DispatchGoneState(FrameNodeType type, FrameNodeTrigger trigger)
403 {
404     AnimationOption option;
405     option.SetDuration(MENU_SHOW_ANIMATION_DURATION);
406     option.SetCurve(Curves::SHARP);
407 
408     switch (trigger) {
409         case FrameNodeTrigger::SHOW:
410             SetFrameNodeStatus(type, FrameNodeStatus::GONETOVISIBLE);
411             SetFrameNodeVisibility(type, VisibleType::VISIBLE);
412             AnimationUtils::Animate(
413                 option,
414                 [weak = WeakClaim(this), type]() {
415                     auto node = weak.Upgrade();
416                     CHECK_NULL_VOID(node);
417                     node->SetFrameNodeOpacity(type, 1.0);
418                 },
419                 [weak = WeakClaim(this), type]() {
420                     auto node = weak.Upgrade();
421                     CHECK_NULL_VOID(node);
422                     node->ExecuteOverlayStatus(type, FrameNodeTrigger::SHOWN);
423                 });
424             break;
425         case FrameNodeTrigger::SHOWN:
426         case FrameNodeTrigger::HIDE:
427         case FrameNodeTrigger::HIDDEN:
428         default:
429             break;
430     }
431 }
432 
DispatchGoneToVisibleState(FrameNodeType type,FrameNodeTrigger trigger)433 void SelectOverlayNode::DispatchGoneToVisibleState(FrameNodeType type, FrameNodeTrigger trigger)
434 {
435     AnimationOption option;
436     option.SetDuration(MENU_HIDE_ANIMATION_DURATION);
437     option.SetCurve(Curves::SHARP);
438 
439     switch (trigger) {
440         case FrameNodeTrigger::SHOWN:
441             SetFrameNodeStatus(type, FrameNodeStatus::VISIBLE);
442             break;
443         case FrameNodeTrigger::HIDE:
444             SetFrameNodeStatus(type, FrameNodeStatus::VISIBLETOGONE);
445             AnimationUtils::Animate(
446                 option,
447                 [weak = WeakClaim(this), type]() {
448                     auto node = weak.Upgrade();
449                     CHECK_NULL_VOID(node);
450                     node->SetFrameNodeOpacity(type, 0.0);
451                 },
452                 [weak = WeakClaim(this), type]() {
453                     auto node = weak.Upgrade();
454                     CHECK_NULL_VOID(node);
455                     node->ExecuteOverlayStatus(type, FrameNodeTrigger::HIDDEN);
456                 });
457             break;
458         case FrameNodeTrigger::SHOW:
459         case FrameNodeTrigger::HIDDEN:
460             break;
461         default:
462             break;
463     }
464 }
465 
CreateCustomSelectMenu(const std::shared_ptr<SelectOverlayInfo> & info)466 RefPtr<FrameNode> CreateCustomSelectMenu(const std::shared_ptr<SelectOverlayInfo>& info)
467 {
468     CHECK_NULL_RETURN(info, nullptr);
469     CHECK_NULL_RETURN(info->menuInfo.menuBuilder, nullptr);
470     NG::ScopedViewStackProcessor builderViewStackProcessor;
471     info->menuInfo.menuBuilder();
472     auto customNode = NG::ViewStackProcessor::GetInstance()->Finish();
473     auto menuNode =
474         MenuView::Create(customNode, -1, "", MenuType::SELECT_OVERLAY_CUSTOM_MENU, MenuParam(), info->isUsingMouse);
475     auto eventHub = menuNode->GetEventHub<EventHub>();
476     if (eventHub && info->menuCallback.onAppear) {
477         eventHub->SetOnAppear(std::move(info->menuCallback.onAppear));
478     }
479     if (eventHub && info->menuCallback.onDisappear) {
480         eventHub->SetOnDisappear(std::move(info->menuCallback.onDisappear));
481     }
482     return menuNode;
483 }
484 
CreateSelectOverlayNode(const std::shared_ptr<SelectOverlayInfo> & info)485 RefPtr<FrameNode> SelectOverlayNode::CreateSelectOverlayNode(const std::shared_ptr<SelectOverlayInfo>& info)
486 {
487     if (info->isUsingMouse) {
488         return CreateMenuNode(info);
489     }
490     auto selectOverlayNode = AceType::MakeRefPtr<SelectOverlayNode>(info);
491     selectOverlayNode->InitializePatternAndContext();
492     ElementRegister::GetInstance()->AddUINode(selectOverlayNode);
493     selectOverlayNode->CreateToolBar();
494     selectOverlayNode->UpdateToolBar(true);
495     return selectOverlayNode;
496 }
497 
MoreOrBackAnimation(bool isMore)498 void SelectOverlayNode::MoreOrBackAnimation(bool isMore)
499 {
500     CHECK_NULL_VOID(!isDoingAnimation_);
501     CHECK_NULL_VOID(selectMenu_);
502     CHECK_NULL_VOID(selectMenuInner_);
503     CHECK_NULL_VOID(extensionMenu_);
504     CHECK_NULL_VOID(backButton_);
505     if (isMore && !isExtensionMenu_) {
506         MoreAnimation();
507     } else if (!isMore && isExtensionMenu_) {
508         BackAnimation();
509     }
510 }
511 
MoreAnimation()512 void SelectOverlayNode::MoreAnimation()
513 {
514     auto extensionContext = extensionMenu_->GetRenderContext();
515     CHECK_NULL_VOID(extensionContext);
516     auto selectMenuInnerContext = selectMenuInner_->GetRenderContext();
517     CHECK_NULL_VOID(selectMenuInnerContext);
518 
519     auto extensionProperty = extensionMenu_->GetLayoutProperty();
520     CHECK_NULL_VOID(extensionProperty);
521     auto selectProperty = selectMenu_->GetLayoutProperty();
522     CHECK_NULL_VOID(selectProperty);
523     auto selectMenuInnerProperty = selectMenuInner_->GetLayoutProperty();
524     CHECK_NULL_VOID(selectMenuInnerProperty);
525     auto backButtonProperty = backButton_->GetLayoutProperty();
526     CHECK_NULL_VOID(backButtonProperty);
527 
528     auto pattern = GetPattern<SelectOverlayPattern>();
529     CHECK_NULL_VOID(pattern);
530     auto modifier = pattern->GetOverlayModifier();
531     CHECK_NULL_VOID(modifier);
532 
533     auto pipeline = PipelineContext::GetCurrentContext();
534     CHECK_NULL_VOID(pipeline);
535 
536     auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
537     CHECK_NULL_VOID(textOverlayTheme);
538 
539     isDoingAnimation_ = true;
540     isExtensionMenu_ = true;
541 
542     extensionProperty->UpdateVisibility(VisibleType::VISIBLE);
543     extensionMenuStatus_ = FrameNodeStatus::VISIBLE;
544     AnimationOption extensionOption;
545     extensionOption.SetDuration(ANIMATION_DURATION2);
546     extensionOption.SetCurve(Curves::FAST_OUT_SLOW_IN);
547     auto toolbarHeight = textOverlayTheme->GetMenuToolbarHeight();
548     auto frameSize = CalcSize(CalcLength(toolbarHeight.ConvertToPx()), CalcLength(toolbarHeight.ConvertToPx()));
549 
550     AnimationUtils::Animate(extensionOption, [extensionContext, selectMenuInnerContext]() {
551         extensionContext->UpdateOpacity(1.0);
552         extensionContext->UpdateTransformTranslate({ 0.0f, 0.0f, 0.0f });
553         selectMenuInnerContext->UpdateOpacity(0.0);
554     });
555     modifier->SetOtherPointRadius(MIN_DIAMETER / 2.0f);
556     modifier->SetHeadPointRadius(MIN_ARROWHEAD_DIAMETER / 2.0f);
557     modifier->SetLineEndOffset(true);
558 
559     FinishCallback callback = [selectMenuInnerProperty, extensionProperty, backButtonProperty,
560                                   id = Container::CurrentId(), weak = WeakClaim(this)]() {
561         ContainerScope scope(id);
562         auto pipeline = PipelineBase::GetCurrentContext();
563         CHECK_NULL_VOID_NOLOG(pipeline);
564         auto taskExecutor = pipeline->GetTaskExecutor();
565         CHECK_NULL_VOID_NOLOG(taskExecutor);
566         taskExecutor->PostTask(
567             [selectMenuInnerProperty, extensionProperty, backButtonProperty, id, weak]() {
568                 ContainerScope scope(id);
569                 selectMenuInnerProperty->UpdateVisibility(VisibleType::GONE);
570                 extensionProperty->UpdateVisibility(VisibleType::VISIBLE);
571                 backButtonProperty->UpdateVisibility(VisibleType::VISIBLE);
572                 auto selectOverlay = weak.Upgrade();
573                 CHECK_NULL_VOID(selectOverlay);
574                 selectOverlay->SetAnimationStatus(false);
575             },
576             TaskExecutor::TaskType::UI);
577     };
578     AnimationOption selectOption;
579     selectOption.SetDuration(ANIMATION_DURATION1);
580     selectOption.SetCurve(Curves::FRICTION);
581     pipeline->FlushUITasks();
582     AnimationUtils::OpenImplicitAnimation(selectOption, Curves::FRICTION, callback);
583     selectProperty->UpdateUserDefinedIdealSize(frameSize);
584     selectMenuInnerContext->UpdateTransformTranslate({ ANIMATION_TEXT_OFFSET.ConvertToPx(), 0.0f, 0.0f });
585     selectMenu_->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
586     pipeline->FlushUITasks();
587     AnimationUtils::CloseImplicitAnimation();
588 }
589 
BackAnimation()590 void SelectOverlayNode::BackAnimation()
591 {
592     auto selectContext = selectMenu_->GetRenderContext();
593     CHECK_NULL_VOID(selectContext);
594     auto extensionContext = extensionMenu_->GetRenderContext();
595     CHECK_NULL_VOID(extensionContext);
596     auto selectMenuInnerContext = selectMenuInner_->GetRenderContext();
597     CHECK_NULL_VOID(selectMenuInnerContext);
598 
599     auto extensionProperty = extensionMenu_->GetLayoutProperty();
600     CHECK_NULL_VOID(extensionProperty);
601     auto selectProperty = selectMenu_->GetLayoutProperty();
602     CHECK_NULL_VOID(selectProperty);
603     auto selectMenuInnerProperty = selectMenuInner_->GetLayoutProperty();
604     CHECK_NULL_VOID(selectMenuInnerProperty);
605     auto backButtonProperty = backButton_->GetLayoutProperty();
606     CHECK_NULL_VOID(backButtonProperty);
607 
608     auto pattern = GetPattern<SelectOverlayPattern>();
609     CHECK_NULL_VOID(pattern);
610     auto modifier = pattern->GetOverlayModifier();
611     CHECK_NULL_VOID(modifier);
612 
613     auto pipeline = PipelineContext::GetCurrentContext();
614     CHECK_NULL_VOID(pipeline);
615 
616     auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
617     CHECK_NULL_VOID(textOverlayTheme);
618 
619     isDoingAnimation_ = true;
620     isExtensionMenu_ = false;
621     auto meanuWidth = pattern->GetMenuWidth();
622 
623     selectMenuInnerProperty->UpdateVisibility(VisibleType::VISIBLE);
624     AnimationOption extensionOption;
625     extensionOption.SetDuration(ANIMATION_DURATION2);
626     extensionOption.SetCurve(Curves::FAST_OUT_SLOW_IN);
627 
628     AnimationUtils::Animate(extensionOption, [extensionContext, selectMenuInnerContext]() {
629         extensionContext->UpdateOpacity(0.0);
630         extensionContext->UpdateTransformTranslate({ 0.0f, MORE_MENU_TRANSLATE.ConvertToPx(), 0.0f });
631         selectMenuInnerContext->UpdateOpacity(1.0);
632     });
633 
634     modifier->SetOtherPointRadius(MAX_DIAMETER / 2.0f);
635     modifier->SetHeadPointRadius(MAX_DIAMETER / 2.0f);
636     modifier->SetLineEndOffset(false);
637 
638     auto toolbarHeight = textOverlayTheme->GetMenuToolbarHeight();
639     auto frameSize = CalcSize(CalcLength(meanuWidth), CalcLength(toolbarHeight.ConvertToPx()));
640 
641     FinishCallback callback = [selectMenuInnerProperty, extensionProperty, backButtonProperty,
642                                   id = Container::CurrentId(), weak = WeakClaim(this)]() {
643         ContainerScope scope(id);
644         auto pipeline = PipelineBase::GetCurrentContext();
645         CHECK_NULL_VOID_NOLOG(pipeline);
646         auto taskExecutor = pipeline->GetTaskExecutor();
647         CHECK_NULL_VOID_NOLOG(taskExecutor);
648         taskExecutor->PostTask(
649             [selectMenuInnerProperty, extensionProperty, backButtonProperty, id, weak]() {
650                 ContainerScope scope(id);
651                 selectMenuInnerProperty->UpdateVisibility(VisibleType::VISIBLE);
652                 extensionProperty->UpdateVisibility(VisibleType::GONE);
653                 backButtonProperty->UpdateVisibility(VisibleType::GONE);
654                 auto selectOverlay = weak.Upgrade();
655                 CHECK_NULL_VOID(selectOverlay);
656                 selectOverlay->SetAnimationStatus(false);
657             },
658             TaskExecutor::TaskType::UI);
659     };
660 
661     AnimationOption selectOption;
662     selectOption.SetDuration(ANIMATION_DURATION1);
663     selectOption.SetCurve(Curves::FRICTION);
664     pipeline->FlushUITasks();
665     AnimationUtils::OpenImplicitAnimation(selectOption, Curves::FRICTION, callback);
666     selectProperty->UpdateUserDefinedIdealSize(frameSize);
667     selectMenuInnerContext->UpdateTransformTranslate({ 0.0f, 0.0f, 0.0f });
668     selectContext->UpdateOffset(OffsetT<Dimension>(0.0_px, 0.0_px));
669     selectMenu_->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
670     pipeline->FlushUITasks();
671     AnimationUtils::CloseImplicitAnimation();
672 }
673 
AddExtensionMenuOptions(const std::vector<MenuOptionsParam> & menuOptionItems,int32_t index)674 void SelectOverlayNode::AddExtensionMenuOptions(const std::vector<MenuOptionsParam>& menuOptionItems, int32_t index)
675 {
676     CHECK_NULL_VOID(!extensionMenu_);
677     std::vector<OptionParam> params;
678     auto id = GetId();
679 
680     auto pipeline = PipelineContext::GetCurrentContext();
681     CHECK_NULL_VOID(pipeline);
682     auto iconTheme = pipeline->GetTheme<IconTheme>();
683     auto defaultOptionCallback = [overlayId = id]() {
684         auto pipeline = PipelineContext::GetCurrentContext();
685         CHECK_NULL_VOID(pipeline);
686         auto overlayManager = pipeline->GetSelectOverlayManager();
687         CHECK_NULL_VOID(overlayManager);
688         overlayManager->DestroySelectOverlay(overlayId);
689     };
690     if (!isShowInDefaultMenu_[OPTION_INDEX_CUT]) {
691         auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_CUT_SVG) : "";
692         params.emplace_back(Localization::GetInstance()->GetEntryLetters(BUTTON_CUT), iconPath, defaultOptionCallback);
693     }
694     if (!isShowInDefaultMenu_[OPTION_INDEX_COPY]) {
695         auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_COPY_SVG) : "";
696         params.emplace_back(Localization::GetInstance()->GetEntryLetters(BUTTON_COPY), iconPath, defaultOptionCallback);
697     }
698     if (!isShowInDefaultMenu_[OPTION_INDEX_PASTE]) {
699         auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_PASTE_SVG) : "";
700         params.emplace_back(
701             Localization::GetInstance()->GetEntryLetters(BUTTON_PASTE), iconPath, defaultOptionCallback);
702     }
703     if (!isShowInDefaultMenu_[OPTION_INDEX_COPY_ALL]) {
704         auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_SELECT_ALL_SVG) : "";
705         params.emplace_back(
706             Localization::GetInstance()->GetEntryLetters(BUTTON_COPY_ALL), iconPath, defaultOptionCallback);
707     }
708     if (!isShowInDefaultMenu_[OPTION_INDEX_SHARE]) {
709         auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_SHARE_SVG) : "";
710         params.emplace_back(
711             Localization::GetInstance()->GetEntryLetters(BUTTON_SHARE), iconPath, defaultOptionCallback);
712     }
713     if (!isShowInDefaultMenu_[OPTION_INDEX_TRANSLATE]) {
714         auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_TRANSLATE_SVG) : "";
715         params.emplace_back(
716             Localization::GetInstance()->GetEntryLetters(BUTTON_TRANSLATE), iconPath, defaultOptionCallback);
717     }
718     if (!isShowInDefaultMenu_[OPTION_INDEX_SEARCH]) {
719         auto iconPath = iconTheme ? iconTheme->GetIconPath(InternalResource::ResourceId::IC_SEARCH_SVG) : "";
720         params.emplace_back(
721             Localization::GetInstance()->GetEntryLetters(BUTTON_SEARCH), iconPath, defaultOptionCallback);
722     }
723     int32_t itemNum = 0;
724     for (auto item : menuOptionItems) {
725         if (itemNum >= index) {
726             auto callback = [overlayId = id, func = std::move(item.action)]() {
727                 auto pipeline = PipelineContext::GetCurrentContext();
728                 CHECK_NULL_VOID(pipeline);
729                 auto overlayManager = pipeline->GetSelectOverlayManager();
730                 CHECK_NULL_VOID(overlayManager);
731 
732                 auto selectOverlay = overlayManager->GetSelectOverlayNode(overlayId);
733                 auto pattern = selectOverlay->GetPattern<SelectOverlayPattern>();
734                 auto selectInfo = pattern->GetSelectInfo();
735                 func(selectInfo);
736                 overlayManager->DestroySelectOverlay(overlayId);
737             };
738             params.emplace_back(item.content.value_or("null"), item.icon.value_or(" "), callback);
739         }
740         itemNum++;
741     }
742     if (!params.empty()) {
743         auto menuWrapper =
744             MenuView::Create(std::move(params), -1, "ExtensionMenu", MenuType::SELECT_OVERLAY_EXTENSION_MENU);
745         CHECK_NULL_VOID(menuWrapper);
746         auto menu = DynamicCast<FrameNode>(menuWrapper->GetChildAtIndex(0));
747         CHECK_NULL_VOID(menu);
748         menuWrapper->RemoveChild(menu);
749         menuWrapper.Reset();
750 
751         // set click position to menu
752         auto props = menu->GetLayoutProperty<MenuLayoutProperty>();
753         auto context = menu->GetRenderContext();
754         CHECK_NULL_VOID(props);
755         auto offsetY = 0.0f;
756         auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
757         if (textOverlayTheme) {
758             offsetY = textOverlayTheme->GetMenuToolbarHeight().ConvertToPx();
759         }
760         props->UpdateMenuOffset(GetPageOffset());
761         context->UpdateBackShadow(ShadowConfig::NoneShadow);
762         auto menuPattern = menu->GetPattern<MenuPattern>();
763         CHECK_NULL_VOID(menuPattern);
764         auto options = menuPattern->GetOptions();
765         SetOptionsAction(options);
766         ElementRegister::GetInstance()->AddUINode(menu);
767         menu->MountToParent(Claim(this));
768 
769         extensionMenu_ = menu;
770         auto extensionMenuContext = extensionMenu_->GetRenderContext();
771         CHECK_NULL_VOID(extensionMenuContext);
772 
773         extensionMenu_->GetLayoutProperty()->UpdateVisibility(VisibleType::GONE);
774         extensionMenuStatus_ = FrameNodeStatus::GONE;
775         extensionMenuContext->UpdateOpacity(0.0);
776 
777         extensionMenuContext->UpdateTransformTranslate({ 0.0f, MORE_MENU_TRANSLATE.ConvertToPx(), 0.0f });
778         extensionMenu_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
779         extensionMenu_->MarkModifyDone();
780     }
781 }
782 
CreateToolBar()783 void SelectOverlayNode::CreateToolBar()
784 {
785     auto info = GetPattern<SelectOverlayPattern>()->GetSelectOverlayInfo();
786     if (info->menuInfo.menuBuilder) {
787         selectMenu_ = CreateCustomSelectMenu(info);
788         if (info->menuInfo.menuIsShow) {
789             selectMenu_->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
790             selectMenuStatus_ = FrameNodeStatus::VISIBLE;
791         } else {
792             selectMenu_->GetLayoutProperty()->UpdateVisibility(VisibleType::GONE);
793             selectMenuStatus_ = FrameNodeStatus::GONE;
794         }
795         selectMenu_->MountToParent(Claim(this));
796         selectMenu_->MarkModifyDone();
797         return;
798     }
799 
800     selectMenu_ = FrameNode::GetOrCreateFrameNode("SelectMenu", ElementRegister::GetInstance()->MakeUniqueId(),
801         []() { return AceType::MakeRefPtr<LinearLayoutPattern>(false); });
802     selectMenu_->GetLayoutProperty<LinearLayoutProperty>()->UpdateMainAxisAlign(FlexAlign::FLEX_END);
803     selectMenu_->GetRenderContext()->SetClipToFrame(true);
804     selectMenu_->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_CONTENT);
805 
806     // Increase the node to realize the animation effect of font transparency and offset.
807     selectMenuInner_ =
808         FrameNode::GetOrCreateFrameNode("SelectMenuInner", ElementRegister::GetInstance()->MakeUniqueId(),
809             []() { return AceType::MakeRefPtr<LinearLayoutPattern>(false); });
810     selectMenuInner_->GetLayoutProperty<LinearLayoutProperty>()->UpdateMainAxisAlign(FlexAlign::FLEX_END);
811     selectMenuInner_->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_CONTENT);
812 
813     auto pipeline = PipelineContext::GetCurrentContext();
814     CHECK_NULL_VOID(pipeline);
815     auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
816     CHECK_NULL_VOID(textOverlayTheme);
817     selectMenu_->GetRenderContext()->UpdateOpacity(0.0);
818     selectMenu_->GetRenderContext()->UpdateBackgroundColor(textOverlayTheme->GetMenuBackgroundColor());
819     selectMenuInner_->GetRenderContext()->UpdateOpacity(1.0);
820     selectMenuInner_->GetRenderContext()->UpdateTransformTranslate({ 0.0f, 0.0f, 0.0f });
821 
822     const auto& border = textOverlayTheme->GetMenuBorder();
823     auto borderWidth = Dimension(border.Left().GetWidth().ConvertToPx());
824     selectMenu_->GetLayoutProperty()->UpdateBorderWidth({ borderWidth, borderWidth, borderWidth, borderWidth });
825     auto borderRadius = textOverlayTheme->GetMenuToolbarHeight() / 2.0f;
826     selectMenu_->GetRenderContext()->UpdateBorderRadius({ borderRadius, borderRadius, borderRadius, borderRadius });
827     auto borderColor = border.Left().GetColor();
828     selectMenu_->GetRenderContext()->UpdateBorderColor({ borderColor, borderColor, borderColor, borderColor });
829     auto borderStyle = border.Left().GetBorderStyle();
830     selectMenu_->GetRenderContext()->UpdateBorderStyle({ borderStyle, borderStyle, borderStyle, borderStyle });
831 
832     const auto& padding = textOverlayTheme->GetMenuPadding();
833     auto left = CalcLength(padding.Left().ConvertToPx());
834     auto right = CalcLength(padding.Right().ConvertToPx());
835     auto top = CalcLength(padding.Top().ConvertToPx());
836     auto bottom = CalcLength(padding.Bottom().ConvertToPx());
837     selectMenuInner_->GetLayoutProperty()->UpdatePadding({ left, right, top, bottom });
838 
839     selectMenuInner_->GetLayoutProperty()->UpdateUserDefinedIdealSize(
840         { std::nullopt, CalcLength(textOverlayTheme->GetMenuToolbarHeight()) });
841 
842     if (info->menuInfo.menuIsShow) {
843         selectMenu_->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
844         selectMenuStatus_ = FrameNodeStatus::VISIBLE;
845     } else {
846         selectMenu_->GetLayoutProperty()->UpdateVisibility(VisibleType::GONE);
847         selectMenuStatus_ = FrameNodeStatus::GONE;
848     }
849 
850     selectMenuInner_->MountToParent(selectMenu_);
851     selectMenuInner_->GetOrCreateGestureEventHub()->MarkResponseRegion(true);
852 
853     selectMenu_->GetRenderContext()->UpdateBackShadow(ShadowConfig::DefaultShadowM);
854     selectMenu_->MountToParent(Claim(this));
855     selectMenu_->GetOrCreateGestureEventHub()->MarkResponseRegion(true);
856     selectMenu_->MarkModifyDone();
857 }
858 
GetDefaultButtonAndMenuWidth(float & maxWidth)859 void SelectOverlayNode::GetDefaultButtonAndMenuWidth(float& maxWidth)
860 {
861     auto pipeline = PipelineContext::GetCurrentContext();
862     CHECK_NULL_VOID(pipeline);
863     auto textOverlayTheme = pipeline->GetTheme<TextOverlayTheme>();
864     CHECK_NULL_VOID(textOverlayTheme);
865     auto selectOverlayMaxWidth = textOverlayTheme->GetSelectOverlayMaxWidth().ConvertToPx();
866 
867     const auto& menuPadding = textOverlayTheme->GetMenuPadding();
868 
869     maxWidth = selectOverlayMaxWidth - menuPadding.Left().ConvertToPx() - menuPadding.Right().ConvertToPx() -
870                textOverlayTheme->GetMoreButtonHeight().ConvertToPx();
871 }
872 
AddSystemDefaultOptions(float maxWidth,float & allocatedSize)873 bool SelectOverlayNode::AddSystemDefaultOptions(float maxWidth, float& allocatedSize)
874 {
875     auto info = GetPattern<SelectOverlayPattern>()->GetSelectOverlayInfo();
876     memset_s(isShowInDefaultMenu_, sizeof(isShowInDefaultMenu_), 0, sizeof(isShowInDefaultMenu_));
877     if (info->menuInfo.showCut) {
878         float buttonWidth = 0.0f;
879         auto button = BuildButton(
880             Localization::GetInstance()->GetEntryLetters(BUTTON_CUT), info->menuCallback.onCut, GetId(), buttonWidth);
881         if (maxWidth - allocatedSize >= buttonWidth) {
882             button->MountToParent(selectMenuInner_);
883             allocatedSize += buttonWidth;
884             isShowInDefaultMenu_[OPTION_INDEX_CUT] = true;
885         } else {
886             button.Reset();
887         }
888     } else {
889         isShowInDefaultMenu_[OPTION_INDEX_CUT] = true;
890     }
891     if (info->menuInfo.showCopy) {
892         float buttonWidth = 0.0f;
893         auto button = BuildButton(
894             Localization::GetInstance()->GetEntryLetters(BUTTON_COPY), info->menuCallback.onCopy, GetId(), buttonWidth);
895         if (maxWidth - allocatedSize >= buttonWidth) {
896             button->MountToParent(selectMenuInner_);
897             allocatedSize += buttonWidth;
898             isShowInDefaultMenu_[OPTION_INDEX_COPY] = true;
899         } else {
900             button.Reset();
901             return true;
902         }
903     } else {
904         isShowInDefaultMenu_[OPTION_INDEX_COPY] = true;
905     }
906     if (info->menuInfo.showPaste) {
907         float buttonWidth = 0.0f;
908         auto button = BuildButton(Localization::GetInstance()->GetEntryLetters(BUTTON_PASTE),
909             info->menuCallback.onPaste, GetId(), buttonWidth);
910         if (maxWidth - allocatedSize >= buttonWidth) {
911             button->MountToParent(selectMenuInner_);
912             allocatedSize += buttonWidth;
913             isShowInDefaultMenu_[OPTION_INDEX_PASTE] = true;
914         } else {
915             button.Reset();
916             return true;
917         }
918     } else {
919         isShowInDefaultMenu_[OPTION_INDEX_PASTE] = true;
920     }
921     if (info->menuInfo.showCopyAll) {
922         float buttonWidth = 0.0f;
923         auto button = BuildButton(Localization::GetInstance()->GetEntryLetters(BUTTON_COPY_ALL),
924             info->menuCallback.onSelectAll, GetId(), buttonWidth, true);
925         if (maxWidth - allocatedSize >= buttonWidth) {
926             button->MountToParent(selectMenuInner_);
927             allocatedSize += buttonWidth;
928             isShowInDefaultMenu_[OPTION_INDEX_COPY_ALL] = true;
929         } else {
930             button.Reset();
931             return true;
932         }
933     } else {
934         isShowInDefaultMenu_[OPTION_INDEX_COPY_ALL] = true;
935     }
936 
937     if (info->menuInfo.showCopy) {
938         float buttonWidth = 0.0f;
939         auto buttonShare = BuildButton(
940             Localization::GetInstance()->GetEntryLetters(BUTTON_SHARE), nullptr, GetId(), buttonWidth, false);
941         if (maxWidth - allocatedSize >= buttonWidth) {
942             buttonShare->MountToParent(selectMenuInner_);
943             allocatedSize += buttonWidth;
944             isShowInDefaultMenu_[OPTION_INDEX_SHARE] = true;
945         } else {
946             buttonShare.Reset();
947             return true;
948         }
949         auto buttonTranslase = BuildButton(
950             Localization::GetInstance()->GetEntryLetters(BUTTON_TRANSLATE), nullptr, GetId(), buttonWidth, false);
951         if (maxWidth - allocatedSize >= buttonWidth) {
952             buttonTranslase->MountToParent(selectMenuInner_);
953             allocatedSize += buttonWidth;
954             isShowInDefaultMenu_[OPTION_INDEX_TRANSLATE] = true;
955         } else {
956             buttonTranslase.Reset();
957             return true;
958         }
959         auto buttonSearch = BuildButton(
960             Localization::GetInstance()->GetEntryLetters(BUTTON_SEARCH), nullptr, GetId(), buttonWidth, false);
961         if (maxWidth - allocatedSize >= buttonWidth) {
962             buttonSearch->MountToParent(selectMenuInner_);
963             allocatedSize += buttonWidth;
964             isShowInDefaultMenu_[OPTION_INDEX_SEARCH] = true;
965         } else {
966             buttonSearch.Reset();
967             return true;
968         }
969     } else {
970         isShowInDefaultMenu_[OPTION_INDEX_SHARE] = true;
971         isShowInDefaultMenu_[OPTION_INDEX_TRANSLATE] = true;
972         isShowInDefaultMenu_[OPTION_INDEX_SEARCH] = true;
973     }
974     return false;
975 }
976 
UpdateToolBar(bool menuItemChanged)977 void SelectOverlayNode::UpdateToolBar(bool menuItemChanged)
978 {
979     auto info = GetPattern<SelectOverlayPattern>()->GetSelectOverlayInfo();
980     if (menuItemChanged && info->menuInfo.menuBuilder == nullptr && selectMenuInner_) {
981         selectMenuInner_->Clean();
982         selectMenuInner_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
983         if (isExtensionMenu_) {
984             MoreOrBackAnimation(false);
985         }
986         auto selectProperty = selectMenu_->GetLayoutProperty();
987         CHECK_NULL_VOID(selectProperty);
988         selectProperty->ClearUserDefinedIdealSize(true, false);
989         bool isDefaultOverMaxWidth = false;
990         float allocatedSize = 0.0f;
991         float maxWidth = 0.0f;
992         GetDefaultButtonAndMenuWidth(maxWidth);
993         isDefaultOverMaxWidth = AddSystemDefaultOptions(maxWidth, allocatedSize);
994         auto itemNum = -1;
995         auto extensionOptionStartIndex = -1;
996         if (!info->menuOptionItems.empty()) {
997             for (auto item : info->menuOptionItems) {
998                 itemNum++;
999                 float extensionOptionWidth = 0.0f;
1000                 auto button = BuildButton(item.content.value_or("null"), item.action, GetId(), extensionOptionWidth);
1001                 allocatedSize += extensionOptionWidth;
1002                 if (allocatedSize > maxWidth) {
1003                     button.Reset();
1004                     extensionOptionStartIndex = itemNum;
1005                     break;
1006                 }
1007                 button->MountToParent(selectMenuInner_);
1008             }
1009         }
1010         if (backButton_) {
1011             isExtensionMenu_ = false;
1012             RemoveChild(backButton_);
1013             backButton_.Reset();
1014         }
1015         if (extensionMenu_) {
1016             RemoveChild(extensionMenu_);
1017             extensionMenu_.Reset();
1018         }
1019         if (extensionOptionStartIndex != -1 || isDefaultOverMaxWidth) {
1020             auto backButton = BuildMoreOrBackButton(GetId(), true);
1021             backButton->MountToParent(selectMenuInner_);
1022             // add back button
1023             auto id = GetId();
1024             if (!backButton_) {
1025                 backButton_ = BuildMoreOrBackButton(id, false);
1026                 CHECK_NULL_VOID(backButton_);
1027                 backButton_->GetRenderContext()->UpdateOpacity(0.0);
1028                 backButton_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1029                 backButton_->MountToParent(Claim(this));
1030             }
1031         }
1032         AddExtensionMenuOptions(info->menuOptionItems, extensionOptionStartIndex);
1033     }
1034     if (info->menuInfo.menuDisable) {
1035         ExecuteOverlayStatus(FrameNodeType::SELECTMENU, FrameNodeTrigger::HIDE);
1036     } else if (info->menuInfo.menuIsShow) {
1037         ExecuteOverlayStatus(FrameNodeType::SELECTMENU, FrameNodeTrigger::SHOW);
1038     } else {
1039         ExecuteOverlayStatus(FrameNodeType::SELECTMENU, FrameNodeTrigger::HIDE);
1040     }
1041     selectMenu_->MarkModifyDone();
1042     if (isExtensionMenu_ && extensionMenu_) {
1043         if (info->menuInfo.menuDisable) {
1044             ExecuteOverlayStatus(FrameNodeType::EXTENSIONMENU, FrameNodeTrigger::HIDE);
1045             if (backButton_) {
1046                 ExecuteOverlayStatus(FrameNodeType::BACKBUTTON, FrameNodeTrigger::HIDE);
1047             }
1048         } else if (info->menuInfo.menuIsShow) {
1049             ExecuteOverlayStatus(FrameNodeType::EXTENSIONMENU, FrameNodeTrigger::SHOW);
1050             if (backButton_) {
1051                 ExecuteOverlayStatus(FrameNodeType::BACKBUTTON, FrameNodeTrigger::SHOW);
1052             }
1053         } else {
1054             ExecuteOverlayStatus(FrameNodeType::EXTENSIONMENU, FrameNodeTrigger::HIDE);
1055             if (backButton_) {
1056                 ExecuteOverlayStatus(FrameNodeType::BACKBUTTON, FrameNodeTrigger::HIDE);
1057             }
1058         }
1059         extensionMenu_->MarkModifyDone();
1060         if (backButton_) {
1061             backButton_->MarkModifyDone();
1062         }
1063     }
1064     MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1065 }
1066 
CreateMenuNode(const std::shared_ptr<SelectOverlayInfo> & info)1067 RefPtr<FrameNode> SelectOverlayNode::CreateMenuNode(const std::shared_ptr<SelectOverlayInfo>& info)
1068 {
1069     RefPtr<FrameNode> menuWrapper;
1070     if (info->menuInfo.menuBuilder) {
1071         menuWrapper = CreateCustomSelectMenu(info);
1072     } else {
1073         std::vector<OptionParam> params = GetOptionsParams(info);
1074         menuWrapper = MenuView::Create(std::move(params), -1);
1075     }
1076     CHECK_NULL_RETURN(menuWrapper, nullptr);
1077     auto menu = DynamicCast<FrameNode>(menuWrapper->GetChildAtIndex(0));
1078     // set click position to menu
1079     CHECK_NULL_RETURN(menu, nullptr);
1080     auto props = menu->GetLayoutProperty<MenuLayoutProperty>();
1081     CHECK_NULL_RETURN(props, nullptr);
1082     OffsetF pageOffset;
1083     auto pipeline = PipelineContext::GetCurrentContext();
1084     CHECK_NULL_RETURN(pipeline, nullptr);
1085     auto windowManager = pipeline->GetWindowManager();
1086     auto isContainerModal = pipeline->GetWindowModal() == WindowModal::CONTAINER_MODAL && windowManager &&
1087                             windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING;
1088     if (isContainerModal) {
1089         pageOffset = GetPageOffset();
1090     }
1091     props->UpdateMenuOffset(info->rightClickOffset + pageOffset);
1092 
1093     auto menuPattern = menu->GetPattern<MenuPattern>();
1094     CHECK_NULL_RETURN(menuPattern, nullptr);
1095     auto options = menuPattern->GetOptions();
1096     SetOptionsAction(info, options);
1097 
1098     menu->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1099     ElementRegister::GetInstance()->AddUINode(menu);
1100 
1101     auto gestureEventHub = menuWrapper->GetOrCreateGestureEventHub();
1102     if (gestureEventHub) {
1103         gestureEventHub->SetHitTestMode(HitTestMode::HTMTRANSPARENT_SELF);
1104     }
1105     return menuWrapper;
1106 }
1107 
IsInSelectedOrSelectOverlayArea(const PointF & point)1108 bool SelectOverlayNode::IsInSelectedOrSelectOverlayArea(const PointF& point)
1109 {
1110     auto pattern = GetPattern<SelectOverlayPattern>();
1111     CHECK_NULL_RETURN(pattern, false);
1112 
1113     std::vector<RectF> rects;
1114     auto offset = GetGeometryNode() ? GetGeometryNode()->GetFrameOffset() : OffsetF();
1115     rects.emplace_back(pattern->GetHandleRegion(true) + offset);
1116     rects.emplace_back(pattern->GetHandleRegion(false) + offset);
1117     if (selectMenu_ && selectMenu_->GetGeometryNode()) {
1118         rects.emplace_back(selectMenu_->GetGeometryNode()->GetFrameRect() + offset);
1119     }
1120     if (extensionMenu_ && extensionMenu_->GetGeometryNode()) {
1121         rects.emplace_back(extensionMenu_->GetGeometryNode()->GetFrameRect() + offset);
1122     }
1123 
1124     if (pattern->IsCustomMenu()) {
1125         for (auto& child : pattern->GetHost()->GetChildren()) {
1126             auto childFrameNode = DynamicCast<FrameNode>(child);
1127             if (!childFrameNode) {
1128                 continue;
1129             }
1130             rects.emplace_back(childFrameNode->GetGeometryNode()->GetFrameRect() + offset);
1131         }
1132     }
1133 
1134     for (const auto& rect : rects) {
1135         if (rect.IsInRegion(point)) {
1136             LOGD("point is in select overlay rects");
1137             return true;
1138         }
1139     }
1140     return false;
1141 }
1142 
SetClosedByGlobalEvent(bool closedByGlobalEvent)1143 void SelectOverlayNode::SetClosedByGlobalEvent(bool closedByGlobalEvent)
1144 {
1145     auto selectOverlayPattern = GetPattern<SelectOverlayPattern>();
1146     CHECK_NULL_VOID(selectOverlayPattern);
1147     selectOverlayPattern->SetClosedByGlobalTouchEvent(closedByGlobalEvent);
1148 }
1149 
ShowSelectOverlay(bool animation)1150 void SelectOverlayNode::ShowSelectOverlay(bool animation)
1151 {
1152     auto pattern = GetPattern<SelectOverlayPattern>();
1153     CHECK_NULL_VOID(pattern);
1154 
1155     if (animation) {
1156         AnimationOption option;
1157         option.SetDuration(MENU_SHOW_ANIMATION_DURATION);
1158         option.SetCurve(Curves::SHARP);
1159 
1160         AnimationUtils::Animate(option, [weak = WeakClaim(this)]() {
1161             auto node = weak.Upgrade();
1162             CHECK_NULL_VOID(node);
1163             node->SetSelectMenuOpacity(1.0);
1164             node->SetExtensionMenuOpacity(1.0);
1165             node->SetBackButtonOpacity(1.0);
1166         });
1167     } else {
1168         SetSelectMenuOpacity(1.0);
1169         SetExtensionMenuOpacity(1.0);
1170         SetBackButtonOpacity(1.0);
1171     }
1172 
1173     pattern->SetHasShowAnimation(animation);
1174 }
1175 
HideSelectOverlay(const std::function<void ()> & callback)1176 void SelectOverlayNode::HideSelectOverlay(const std::function<void()>& callback)
1177 {
1178     AnimationOption handleOption;
1179     handleOption.SetDuration(HANDLE_ANIMATION_DURATION);
1180     handleOption.SetCurve(Curves::SHARP);
1181 
1182     AnimationUtils::Animate(handleOption, [weak = WeakClaim(this)]() {
1183         auto node = weak.Upgrade();
1184         CHECK_NULL_VOID(node);
1185         auto pattern = node->GetPattern<SelectOverlayPattern>();
1186         CHECK_NULL_VOID(pattern);
1187         auto contentModifier = pattern->GetContentModifier();
1188         CHECK_NULL_VOID(contentModifier);
1189         contentModifier->SetHandleOpacity(0.0);
1190     });
1191 
1192     AnimationOption overlayOption;
1193     overlayOption.SetDuration(MENU_HIDE_ANIMATION_DURATION);
1194     overlayOption.SetCurve(Curves::SHARP);
1195 
1196     AnimationUtils::Animate(
1197         overlayOption,
1198         [weak = WeakClaim(this)]() {
1199             auto node = weak.Upgrade();
1200             CHECK_NULL_VOID(node);
1201             node->SetSelectMenuOpacity(0.0);
1202             node->SetExtensionMenuOpacity(0.0);
1203             node->SetBackButtonOpacity(0.0);
1204             auto pattern = node->GetPattern<SelectOverlayPattern>();
1205             CHECK_NULL_VOID(pattern);
1206             auto overlayModifier = pattern->GetOverlayModifier();
1207             CHECK_NULL_VOID(overlayModifier);
1208             overlayModifier->SetCirclesAndBackArrowOpacity(0.0);
1209         },
1210         callback);
1211 }
1212 
ExecuteOverlayStatus(FrameNodeType type,FrameNodeTrigger trigger)1213 void SelectOverlayNode::ExecuteOverlayStatus(FrameNodeType type, FrameNodeTrigger trigger)
1214 {
1215     FrameNodeStatus status = FrameNodeStatus::VISIBLE;
1216     switch (type) {
1217         case FrameNodeType::SELECTMENU:
1218             status = selectMenuStatus_;
1219             break;
1220         case FrameNodeType::EXTENSIONMENU:
1221             status = extensionMenuStatus_;
1222             break;
1223         case FrameNodeType::BACKBUTTON:
1224             status = backButtonStatus_;
1225             break;
1226         default:
1227             break;
1228     }
1229 
1230     auto stateFuncIter = stateFuncs_.find(status);
1231     if (stateFuncIter != stateFuncs_.end()) {
1232         auto stateFunc = stateFuncIter->second;
1233         CHECK_NULL_VOID(stateFunc);
1234         (this->*stateFunc)(type, trigger);
1235     }
1236 }
1237 
SetFrameNodeStatus(FrameNodeType type,FrameNodeStatus status)1238 void SelectOverlayNode::SetFrameNodeStatus(FrameNodeType type, FrameNodeStatus status)
1239 {
1240     switch (type) {
1241         case FrameNodeType::SELECTMENU:
1242             selectMenuStatus_ = status;
1243             break;
1244         case FrameNodeType::EXTENSIONMENU:
1245             extensionMenuStatus_ = status;
1246             break;
1247         case FrameNodeType::BACKBUTTON:
1248             backButtonStatus_ = status;
1249             break;
1250         default:
1251             break;
1252     }
1253 }
1254 
SetFrameNodeVisibility(FrameNodeType type,VisibleType visibleType)1255 void SelectOverlayNode::SetFrameNodeVisibility(FrameNodeType type, VisibleType visibleType)
1256 {
1257     switch (type) {
1258         case FrameNodeType::SELECTMENU:
1259             selectMenu_->GetLayoutProperty()->UpdateVisibility(visibleType);
1260             break;
1261         case FrameNodeType::EXTENSIONMENU:
1262             extensionMenu_->GetLayoutProperty()->UpdateVisibility(visibleType);
1263             break;
1264         case FrameNodeType::BACKBUTTON:
1265             backButton_->GetLayoutProperty()->UpdateVisibility(visibleType);
1266             break;
1267         default:
1268             break;
1269     }
1270 }
1271 
SetFrameNodeOpacity(FrameNodeType type,float opacity)1272 void SelectOverlayNode::SetFrameNodeOpacity(FrameNodeType type, float opacity)
1273 {
1274     switch (type) {
1275         case FrameNodeType::SELECTMENU:
1276             SetSelectMenuOpacity(opacity);
1277             break;
1278         case FrameNodeType::EXTENSIONMENU:
1279             SetExtensionMenuOpacity(opacity);
1280             break;
1281         case FrameNodeType::BACKBUTTON:
1282             SetBackButtonOpacity(opacity);
1283             break;
1284         default:
1285             break;
1286     }
1287 }
1288 
SetSelectMenuOpacity(float value)1289 void SelectOverlayNode::SetSelectMenuOpacity(float value)
1290 {
1291     CHECK_NULL_VOID(selectMenu_);
1292     CHECK_NULL_VOID(selectMenu_->GetRenderContext());
1293     selectMenu_->GetRenderContext()->UpdateOpacity(value);
1294 }
1295 
SetExtensionMenuOpacity(float value)1296 void SelectOverlayNode::SetExtensionMenuOpacity(float value)
1297 {
1298     CHECK_NULL_VOID(extensionMenu_);
1299     CHECK_NULL_VOID(extensionMenu_->GetRenderContext());
1300     extensionMenu_->GetRenderContext()->UpdateOpacity(value);
1301 }
1302 
SetBackButtonOpacity(float value)1303 void SelectOverlayNode::SetBackButtonOpacity(float value)
1304 {
1305     CHECK_NULL_VOID(backButton_);
1306     CHECK_NULL_VOID(backButton_->GetRenderContext());
1307     backButton_->GetRenderContext()->UpdateOpacity(value);
1308 }
1309 
1310 } // namespace OHOS::Ace::NG
1311