• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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/manager/select_content_overlay/select_content_overlay_manager.h"
17 
18 #include "base/memory/ace_type.h"
19 #include "base/memory/referenced.h"
20 #include "base/utils/utils.h"
21 #include "base/subwindow/subwindow_manager.h"
22 #include "core/common/container.h"
23 #include "core/components_ng/pattern/select_content_overlay/select_content_overlay_pattern.h"
24 #include "core/components_ng/pattern/select_overlay/select_overlay_node.h"
25 #include "core/components_ng/pattern/select_overlay/select_overlay_property.h"
26 #include "core/event/touch_event.h"
27 #include "core/pipeline_ng/pipeline_context.h"
28 
29 namespace OHOS::Ace::NG {
30 namespace {
GetSelectOverlayPattern(const WeakPtr<FrameNode> & overlayNode)31 RefPtr<SelectContentOverlayPattern> GetSelectOverlayPattern(const WeakPtr<FrameNode>& overlayNode)
32 {
33     auto node = overlayNode.Upgrade();
34     CHECK_NULL_RETURN(node, nullptr);
35     auto selectOverlayNode = AceType::DynamicCast<SelectOverlayNode>(node);
36     CHECK_NULL_RETURN(selectOverlayNode, nullptr);
37     return selectOverlayNode->GetPattern<SelectContentOverlayPattern>();
38 }
39 
GetSelectMenuPattern(const WeakPtr<SelectContentOverlayManager> & manager)40 RefPtr<SelectContentOverlayPattern> GetSelectMenuPattern(const WeakPtr<SelectContentOverlayManager>& manager)
41 {
42     auto overlayManager = manager.Upgrade();
43     CHECK_NULL_RETURN(overlayManager, nullptr);
44     auto pattern = overlayManager->GetMenuPattern();
45     return AceType::DynamicCast<SelectContentOverlayPattern>(pattern);
46 }
47 
GetSelectHandlePattern(const WeakPtr<SelectContentOverlayManager> & manager)48 RefPtr<SelectContentOverlayPattern> GetSelectHandlePattern(const WeakPtr<SelectContentOverlayManager>& manager)
49 {
50     auto overlayManager = manager.Upgrade();
51     CHECK_NULL_RETURN(overlayManager, nullptr);
52     auto pattern = overlayManager->GetHandlePattern();
53     return AceType::DynamicCast<SelectContentOverlayPattern>(pattern);
54 }
55 } // namespace
56 
GetOverlayManager(const RefPtr<SelectOverlayHolder> & holder)57 const RefPtr<SelectContentOverlayManager> SelectContentOverlayManager::GetOverlayManager(
58     const RefPtr<SelectOverlayHolder>& holder)
59 {
60     auto pipeline = PipelineContext::GetCurrentContextSafely();
61     CHECK_NULL_RETURN(pipeline, nullptr);
62     auto overlayManager = pipeline->GetSelectOverlayManager();
63     CHECK_NULL_RETURN(overlayManager, nullptr);
64     auto contentManager = overlayManager->GetSelectContentOverlayManager();
65     if (!holder) {
66         return contentManager;
67     }
68     if (!contentManager->HasHolder(holder->GetOwnerId())) {
69         contentManager->SetHolder(holder);
70     }
71     return contentManager;
72 }
73 
SetHolder(const RefPtr<SelectOverlayHolder> & holder)74 void SelectContentOverlayManager::SetHolder(const RefPtr<SelectOverlayHolder>& holder)
75 {
76     CHECK_NULL_VOID(holder);
77     if (!selectOverlayHolder_) {
78         SetHolderInternal(holder);
79         return;
80     }
81     auto prevOwnerId = selectOverlayHolder_->GetOwnerId();
82     auto ownerId = holder->GetOwnerId();
83     if (selectionHoldId_ > 0 && ownerId != selectionHoldId_) {
84         ResetSelectionRect();
85         if (legacyManagerCallbacks_.selectionResetCallback) {
86             legacyManagerCallbacks_.selectionResetCallback();
87         }
88     }
89     if (prevOwnerId == ownerId) {
90         return;
91     }
92     CloseInternal(prevOwnerId, false, CloseReason::CLOSE_REASON_HOLD_BY_OTHER);
93     SetHolderInternal(holder);
94 }
95 
SetHolderInternal(const RefPtr<SelectOverlayHolder> & holder)96 void SelectContentOverlayManager::SetHolderInternal(const RefPtr<SelectOverlayHolder>& holder)
97 {
98     // unbind old holder
99     if (selectOverlayHolder_) {
100         selectOverlayHolder_->OnBind(nullptr);
101     }
102     selectOverlayHolder_ = holder;
103     // bind new holder
104     if (selectOverlayHolder_) {
105         selectOverlayHolder_->OnBind(WeakClaim(this));
106     }
107 }
HasHolder(int32_t id)108 bool SelectContentOverlayManager::HasHolder(int32_t id)
109 {
110     CHECK_NULL_RETURN(selectOverlayHolder_, false);
111     return selectOverlayHolder_->GetOwnerId() == id;
112 }
113 
Show(bool animation,int32_t requestCode)114 void SelectContentOverlayManager::Show(bool animation, int32_t requestCode)
115 {
116     CHECK_NULL_VOID(selectOverlayHolder_);
117     auto info = BuildSelectOverlayInfo(requestCode);
118     if (!info.menuInfo.menuIsShow && info.isUsingMouse) {
119         return;
120     }
121     if (legacyManagerCallbacks_.closeCallback) {
122         legacyManagerCallbacks_.closeCallback(false, true);
123     }
124     info.enableHandleLevel = info.enableHandleLevel && !info.isUsingMouse;
125     if (IsOpen()) {
126         if (info.recreateOverlay || info.menuInfo.menuType != shareOverlayInfo_->menuInfo.menuType) {
127             auto holder = selectOverlayHolder_;
128             CloseInternal(selectOverlayHolder_->GetOwnerId(), false, CloseReason::CLOSE_REASON_BY_RECREATE);
129             SetHolder(holder);
130             CreateSelectOverlay(info, animation);
131             return;
132         }
133         UpdateExistOverlay(info, animation, requestCode);
134     } else {
135         CreateSelectOverlay(info, animation);
136     }
137 }
138 
BuildSelectOverlayInfo(int32_t requestCode)139 SelectOverlayInfo SelectContentOverlayManager::BuildSelectOverlayInfo(int32_t requestCode)
140 {
141     SelectOverlayInfo overlayInfo;
142     UpdateStatusInfos(overlayInfo);
143     overlayInfo.menuCallback.onCopy = MakeMenuCallback(OptionMenuActionId::COPY, overlayInfo);
144     overlayInfo.menuCallback.onPaste = MakeMenuCallback(OptionMenuActionId::PASTE, overlayInfo);
145     overlayInfo.menuCallback.onCut = MakeMenuCallback(OptionMenuActionId::CUT, overlayInfo);
146     overlayInfo.menuCallback.onSelectAll = MakeMenuCallback(OptionMenuActionId::SELECT_ALL, overlayInfo);
147     overlayInfo.menuCallback.onTranslate = MakeMenuCallback(OptionMenuActionId::TRANSLATE, overlayInfo);
148     overlayInfo.menuCallback.onSearch = MakeMenuCallback(OptionMenuActionId::SEARCH, overlayInfo);
149     overlayInfo.menuCallback.onShare = MakeMenuCallback(OptionMenuActionId::SHARE, overlayInfo);
150     overlayInfo.menuCallback.onCameraInput = MakeMenuCallback(OptionMenuActionId::CAMERA_INPUT, overlayInfo);
151     overlayInfo.menuCallback.onAIWrite = MakeMenuCallback(OptionMenuActionId::AI_WRITE, overlayInfo);
152     overlayInfo.menuCallback.onAppear = MakeMenuCallback(OptionMenuActionId::APPEAR, overlayInfo);
153     overlayInfo.menuCallback.onDisappear = MakeMenuCallback(OptionMenuActionId::DISAPPEAR, overlayInfo);
154     overlayInfo.isUseOverlayNG = true;
155     RegisterTouchCallback(overlayInfo);
156     RegisterHandleCallback(overlayInfo);
157     selectOverlayHolder_->OnUpdateSelectOverlayInfo(overlayInfo, requestCode);
158     UpdateSelectOverlayInfoInternal(overlayInfo);
159     TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY, "Build selectoverlay with menu info: %{public}s, requested by %{public}s",
160         overlayInfo.menuInfo.ToString().c_str(), GetOwnerDebugInfo().c_str());
161     return overlayInfo;
162 }
163 
UpdateStatusInfos(SelectOverlayInfo & overlayInfo)164 void SelectContentOverlayManager::UpdateStatusInfos(SelectOverlayInfo& overlayInfo)
165 {
166     auto firstHandle = selectOverlayHolder_->GetFirstHandleInfo();
167     auto secondHandle = selectOverlayHolder_->GetSecondHandleInfo();
168     if (firstHandle.has_value()) {
169         overlayInfo.firstHandle = firstHandle.value();
170     } else {
171         overlayInfo.firstHandle.isShow = false;
172     }
173     if (secondHandle.has_value()) {
174         overlayInfo.secondHandle = secondHandle.value();
175     } else {
176         overlayInfo.secondHandle.isShow = false;
177     }
178     SelectMenuInfo menuInfo;
179     selectOverlayHolder_->OnUpdateMenuInfo(menuInfo, DIRTY_ALL_MENU_ITEM);
180     overlayInfo.menuInfo = menuInfo;
181     overlayInfo.callerFrameNode = selectOverlayHolder_->GetOwner();
182     overlayInfo.selectText = selectOverlayHolder_->GetSelectedText();
183     overlayInfo.selectArea = selectOverlayHolder_->GetSelectArea();
184 }
185 
RegisterHandleCallback(SelectOverlayInfo & info)186 void SelectContentOverlayManager::RegisterHandleCallback(SelectOverlayInfo& info)
187 {
188     CHECK_NULL_VOID(selectOverlayHolder_);
189     auto callback = selectOverlayHolder_->GetCallback();
190     CHECK_NULL_VOID(callback);
191     if (!callback->IsRegisterHandleCallback()) {
192         return;
193     }
194     std::string ownerInfo = GetOwnerDebugInfo();
195     info.onHandleMoveStart = [weakCallback = WeakClaim(AceType::RawPtr(callback)), ownerInfo](
196                                  const GestureEvent& event, bool isFirst) {
197         auto overlayCallback = weakCallback.Upgrade();
198         CHECK_NULL_VOID(overlayCallback);
199         TAG_LOGI(
200             AceLogTag::ACE_SELECT_OVERLAY, "Start move %{public}d handle - %{public}s", isFirst, ownerInfo.c_str());
201         overlayCallback->OnHandleMoveStart(event, isFirst);
202     };
203     info.onHandleMove = [weakCallback = WeakClaim(AceType::RawPtr(callback)), weakManager = WeakClaim(this)](
204                             const RectF& rect, bool isFirst) {
205         auto overlayCallback = weakCallback.Upgrade();
206         CHECK_NULL_VOID(overlayCallback);
207         auto handle = rect;
208         if (weakManager.Upgrade()) {
209             weakManager.Upgrade()->RevertRectRelativeToRoot(handle);
210         }
211         overlayCallback->OnHandleMove(handle, isFirst);
212     };
213     info.onHandleMoveDone = [weakCallback = WeakClaim(AceType::RawPtr(callback)), weakManager = WeakClaim(this),
214                                 ownerInfo](const RectF& rect, bool isFirst) {
215         auto overlayCallback = weakCallback.Upgrade();
216         CHECK_NULL_VOID(overlayCallback);
217         auto handle = rect;
218         if (weakManager.Upgrade()) {
219             weakManager.Upgrade()->RevertRectRelativeToRoot(handle);
220         }
221         TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY, "Stop move %{public}d handle %{public}s", isFirst, ownerInfo.c_str());
222         overlayCallback->OnHandleMoveDone(rect, isFirst);
223     };
224     info.onHandleReverse = [weakCallback = WeakClaim(AceType::RawPtr(callback))](bool isReverse) {
225         auto overlayCallback = weakCallback.Upgrade();
226         CHECK_NULL_VOID(overlayCallback);
227         overlayCallback->OnHandleReverse(isReverse);
228     };
229     info.onHandleIsHidden = [weakCallback = WeakClaim(AceType::RawPtr(callback))]() {
230         auto overlayCallback = weakCallback.Upgrade();
231         CHECK_NULL_VOID(overlayCallback);
232         overlayCallback->OnHandleIsHidden();
233     };
234 }
235 
RegisterTouchCallback(SelectOverlayInfo & info)236 void SelectContentOverlayManager::RegisterTouchCallback(SelectOverlayInfo& info)
237 {
238     CHECK_NULL_VOID(selectOverlayHolder_);
239     auto callback = selectOverlayHolder_->GetCallback();
240     CHECK_NULL_VOID(callback);
241     if (!callback->IsRegisterTouchCallback()) {
242         return;
243     }
244     info.onTouchDown = [weakCallback = WeakClaim(AceType::RawPtr(callback))](const TouchEventInfo& event) {
245         auto callback = weakCallback.Upgrade();
246         CHECK_NULL_VOID(callback);
247         callback->OnOverlayTouchDown(event);
248     };
249     info.onTouchUp = [weakCallback = WeakClaim(AceType::RawPtr(callback))](const TouchEventInfo& event) {
250         auto callback = weakCallback.Upgrade();
251         CHECK_NULL_VOID(callback);
252         callback->OnOverlayTouchUp(event);
253     };
254     info.onTouchMove = [weakCallback = WeakClaim(AceType::RawPtr(callback))](const TouchEventInfo& event) {
255         auto callback = weakCallback.Upgrade();
256         CHECK_NULL_VOID(callback);
257         callback->OnOverlayTouchMove(event);
258     };
259     info.onClick = [weakCallback = WeakClaim(AceType::RawPtr(callback))](const GestureEvent& event, bool isClickCaret) {
260         auto callback = weakCallback.Upgrade();
261         CHECK_NULL_VOID(callback);
262         callback->OnOverlayClick(event, isClickCaret);
263     };
264     info.onMouseEvent = [weakCallback = WeakClaim(AceType::RawPtr(callback))](const MouseInfo& event) {
265         auto callback = weakCallback.Upgrade();
266         CHECK_NULL_VOID(callback);
267         callback->OnHandleMouseEvent(event);
268     };
269 }
270 
MakeMenuCallback(OptionMenuActionId id,const SelectOverlayInfo & info)271 std::function<void()> SelectContentOverlayManager::MakeMenuCallback(
272     OptionMenuActionId id, const SelectOverlayInfo& info)
273 {
274     auto callback = selectOverlayHolder_->GetCallback();
275     CHECK_NULL_RETURN(callback, nullptr);
276     return [actionId = id, weakCallback = WeakClaim(AceType::RawPtr(callback)), menuType = info.menuInfo.menuType,
277                logInfo = GetOwnerDebugInfo()]() {
278         auto callback = weakCallback.Upgrade();
279         CHECK_NULL_VOID(callback);
280         TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY,
281             "OnMenuItemAction called, menu id %{public}d, menu type %{public}d, consumer %{public}s", actionId,
282             menuType, logInfo.c_str());
283         callback->OnMenuItemAction(actionId, menuType);
284     };
285 }
286 
UpdateExistOverlay(const SelectOverlayInfo & info,bool animation,int32_t requestCode)287 void SelectContentOverlayManager::UpdateExistOverlay(const SelectOverlayInfo& info, bool animation, int32_t requestCode)
288 {
289     TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY, "UpdateExistOverlay called by %{public}s", GetOwnerDebugInfo().c_str());
290     // update menu node
291     auto menuPattern = GetSelectMenuPattern(WeakClaim(this));
292     if (menuPattern) {
293         if (!info.isSingleHandle) {
294             menuPattern->UpdateSelectArea(info.selectArea);
295             menuPattern->SetSelectInfo(info.selectText);
296         }
297         menuPattern->UpdateMenuInfo(info.menuInfo);
298         menuPattern->UpdateViewPort(info.ancestorViewPort);
299     }
300     // update handle node
301     auto handlePattern = GetSelectHandlePattern(WeakClaim(this));
302     if (handlePattern) {
303         handlePattern->UpdateIsSingleHandle(info.isSingleHandle);
304         handlePattern->UpdateIsShowHandleLine(info.isHandleLineShow);
305         handlePattern->UpdateFirstAndSecondHandleInfo(info.firstHandle, info.secondHandle);
306         TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY,
307             "Update first %{public}s isShow %{public}d, second %{public}s isShow %{public}d",
308             info.firstHandle.paintRect.ToString().c_str(), info.firstHandle.isShow,
309             info.secondHandle.paintRect.ToString().c_str(), info.secondHandle.isShow);
310         if (info.isSingleHandle) {
311             if (selectOverlayHolder_->CheckRestartHiddenHandleTask(requestCode)) {
312                 handlePattern->RestartHiddenHandleTask(true);
313             }
314         } else {
315             handlePattern->CancelHiddenHandleTask();
316         }
317     }
318     selectOverlayHolder_->OnHandleExistOverlay(info, requestCode);
319     NotifySelectOverlayShow(false);
320 }
321 
SwitchToHandleMode(HandleLevelMode mode,bool forceChange)322 void SelectContentOverlayManager::SwitchToHandleMode(HandleLevelMode mode, bool forceChange)
323 {
324     CHECK_NULL_VOID(shareOverlayInfo_);
325     if (shareOverlayInfo_->handleLevelMode == mode) {
326         return;
327     }
328     if (selectOverlayHolder_ && selectOverlayHolder_->GetCallback()) {
329         if (!forceChange && !selectOverlayHolder_->GetCallback()->CheckSwitchToMode(mode)) {
330             return;
331         }
332         selectOverlayHolder_->GetCallback()->OnHandleLevelModeChanged(mode);
333     }
334     TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY, "Set handle mode: %{public}d", mode);
335     shareOverlayInfo_->handleLevelMode = mode;
336     auto handleNode = handleNode_.Upgrade();
337     CHECK_NULL_VOID(handleNode);
338     auto taskExecutor = Container::CurrentTaskExecutor();
339     CHECK_NULL_VOID(taskExecutor);
340     if (mode == HandleLevelMode::OVERLAY) {
341         taskExecutor->PostTask(
342             [weak = WeakClaim(this), node = handleNode] {
343                 auto manager = weak.Upgrade();
344                 CHECK_NULL_VOID(manager);
345                 CHECK_NULL_VOID(node);
346                 if (!manager->IsOpen()) {
347                     return;
348                 }
349                 manager->DestroySelectOverlayNode(node);
350                 manager->MountNodeToRoot(node, false, NodeType::HANDLE);
351                 node->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
352             },
353             TaskExecutor::TaskType::UI, "SwitchToOverlayModeTask", PriorityType::VIP);
354     } else if (mode == HandleLevelMode::EMBED) {
355         taskExecutor->PostTask(
356             [weak = WeakClaim(this), node = handleNode] {
357                 auto manager = weak.Upgrade();
358                 CHECK_NULL_VOID(manager);
359                 CHECK_NULL_VOID(node);
360                 if (!manager->IsOpen()) {
361                     return;
362                 }
363                 manager->DestroySelectOverlayNode(node);
364                 manager->MountNodeToCaller(node, false);
365                 node->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
366             },
367             TaskExecutor::TaskType::UI, "SwitchToEmbedModeTask", PriorityType::VIP);
368     }
369 }
370 
MarkInfoChange(SelectOverlayDirtyFlag dirty)371 void SelectContentOverlayManager::MarkInfoChange(SelectOverlayDirtyFlag dirty)
372 {
373     CHECK_NULL_VOID(selectOverlayHolder_);
374     CHECK_NULL_VOID(IsOpen());
375     auto menuPattern = GetSelectMenuPattern(WeakClaim(this));
376     if (menuPattern) {
377         if ((dirty & DIRTY_SELECT_AREA) == DIRTY_SELECT_AREA) {
378             auto selectArea = selectOverlayHolder_->GetSelectArea();
379             ConvertRectRelativeToParent(selectArea);
380             menuPattern->UpdateSelectArea(selectArea);
381         }
382         if ((dirty & DIRTY_ALL_MENU_ITEM) == DIRTY_ALL_MENU_ITEM) {
383             SelectMenuInfo menuInfo;
384             selectOverlayHolder_->OnUpdateMenuInfo(menuInfo, DIRTY_ALL_MENU_ITEM);
385             TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY, "Update all menu item: %{public}s - %{public}s",
386                 menuInfo.ToString().c_str(), GetOwnerDebugInfo().c_str());
387             menuPattern->UpdateSelectMenuInfo(menuInfo);
388         }
389         if ((dirty & DIRTY_COPY_ALL_ITEM) == DIRTY_COPY_ALL_ITEM) {
390             auto oldMenuInfo = menuPattern->GetSelectMenuInfo();
391             SelectMenuInfo menuInfo = { .showCopy = oldMenuInfo.showCopy, .showCopyAll = oldMenuInfo.showCopyAll };
392             selectOverlayHolder_->OnUpdateMenuInfo(menuInfo, DIRTY_COPY_ALL_ITEM);
393             oldMenuInfo.showCopyAll = menuInfo.showCopyAll;
394             oldMenuInfo.showCopy = menuInfo.showCopy;
395             TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY, "Update select all menu: %{public}s - %{public}s",
396                 oldMenuInfo.ToString().c_str(), GetOwnerDebugInfo().c_str());
397             menuPattern->UpdateSelectMenuInfo(oldMenuInfo);
398         }
399         if ((dirty & DIRTY_SELECT_TEXT) == DIRTY_SELECT_TEXT) {
400             auto selectedInfo = selectOverlayHolder_->GetSelectedText();
401             menuPattern->SetSelectInfo(selectedInfo);
402         }
403     }
404     if ((dirty & DIRTY_VIEWPORT) == DIRTY_VIEWPORT) {
405         auto viewPort = selectOverlayHolder_->GetAncestorNodeViewPort();
406         if (viewPort) {
407             ConvertRectRelativeToParent(*viewPort);
408         }
409         if (menuPattern) {
410             menuPattern->UpdateViewPort(viewPort);
411         }
412         auto handlePattern = GetSelectHandlePattern(WeakClaim(this));
413         if (handlePattern) {
414             handlePattern->UpdateViewPort(viewPort);
415         }
416     }
417     UpdateHandleInfosWithFlag(dirty);
418     shareOverlayInfo_->containerModalOffset = GetContainerModalOffset();
419     selectOverlayHolder_->OnHandleMarkInfoChange(shareOverlayInfo_, dirty);
420 }
421 
MarkSelectOverlayDirty(PropertyChangeFlag changeFlag)422 void SelectContentOverlayManager::MarkSelectOverlayDirty(PropertyChangeFlag changeFlag)
423 {
424     CHECK_NULL_VOID(IsOpen());
425     selectOverlayNode_.Upgrade()->MarkDirtyNode(changeFlag);
426 }
427 
UpdateHandleInfosWithFlag(int32_t updateFlag)428 void SelectContentOverlayManager::UpdateHandleInfosWithFlag(int32_t updateFlag)
429 {
430     auto pattern = GetSelectHandlePattern(WeakClaim(this));
431     CHECK_NULL_VOID(pattern);
432     std::optional<SelectHandleInfo> firstHandleInfo;
433     if ((static_cast<uint32_t>(updateFlag) & DIRTY_FIRST_HANDLE) == DIRTY_FIRST_HANDLE) {
434         firstHandleInfo = selectOverlayHolder_->GetFirstHandleInfo();
435         if (firstHandleInfo) {
436             ConvertHandleRelativeToParent(*firstHandleInfo);
437             TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY, "Update first handle info %{public}s - %{public}s",
438                 firstHandleInfo->ToString().c_str(), GetOwnerDebugInfo().c_str());
439         }
440     }
441     std::optional<SelectHandleInfo> secondHandleInfo;
442     if ((static_cast<uint32_t>(updateFlag) & DIRTY_SECOND_HANDLE) == DIRTY_SECOND_HANDLE) {
443         secondHandleInfo = selectOverlayHolder_->GetSecondHandleInfo();
444         if (secondHandleInfo) {
445             ConvertHandleRelativeToParent(*secondHandleInfo);
446             TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY, "Update second handle info %{public}s - %{public}s",
447                 secondHandleInfo->ToString().c_str(), GetOwnerDebugInfo().c_str());
448         }
449     }
450     if (!firstHandleInfo && !secondHandleInfo) {
451         return;
452     }
453     if (firstHandleInfo && secondHandleInfo) {
454         pattern->UpdateFirstAndSecondHandleInfo(*firstHandleInfo, *secondHandleInfo);
455     } else if (firstHandleInfo) {
456         pattern->UpdateFirstSelectHandleInfo(*firstHandleInfo);
457     } else {
458         pattern->UpdateSecondSelectHandleInfo(*secondHandleInfo);
459     }
460 }
461 
CreateSelectOverlay(SelectOverlayInfo & info,bool animation)462 void SelectContentOverlayManager::CreateSelectOverlay(SelectOverlayInfo& info, bool animation)
463 {
464     if (!info.enableHandleLevel) {
465         CreateNormalSelectOverlay(info, animation);
466         return;
467     }
468     CreateHandleLevelSelectOverlay(info, animation, info.handleLevelMode);
469 }
470 
CreateNormalSelectOverlay(SelectOverlayInfo & info,bool animation)471 void SelectContentOverlayManager::CreateNormalSelectOverlay(SelectOverlayInfo& info, bool animation)
472 {
473     shareOverlayInfo_ = std::make_shared<SelectOverlayInfo>(info);
474     auto overlayNode = SelectOverlayNode::CreateSelectOverlayNode(shareOverlayInfo_);
475     selectOverlayNode_ = overlayNode;
476     auto taskExecutor = Container::CurrentTaskExecutor();
477     CHECK_NULL_VOID(taskExecutor);
478     taskExecutor->PostTask(
479         [animation, weak = WeakClaim(this), node = overlayNode] {
480             auto manager = weak.Upgrade();
481             CHECK_NULL_VOID(manager);
482             if (node && node == manager->selectOverlayNode_) {
483                 CHECK_NULL_VOID(manager->shareOverlayInfo_);
484                 auto nodeType =
485                     manager->shareOverlayInfo_->isUsingMouse ? NodeType::RIGHT_CLICK_MENU : NodeType::HANDLE_WITH_MENU;
486                 if (nodeType == NodeType::RIGHT_CLICK_MENU && manager->IsEnableSubWindowMenu()) {
487                     manager->MountMenuNodeToSubWindow(node, animation, nodeType);
488                 } else {
489                     manager->MountNodeToRoot(node, animation, nodeType);
490                 }
491                 manager->NotifySelectOverlayShow(true);
492             }
493         },
494         TaskExecutor::TaskType::UI, "ArkUISelectOverlayCreate", PriorityType::VIP);
495 }
496 
CreateHandleLevelSelectOverlay(SelectOverlayInfo & info,bool animation,HandleLevelMode mode)497 void SelectContentOverlayManager::CreateHandleLevelSelectOverlay(
498     SelectOverlayInfo& info, bool animation, HandleLevelMode mode)
499 {
500     TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY,
501         "Show SelectOverlay, first %{public}s isShow %{public}d, second %{public}s isShow %{public}d",
502         info.firstHandle.paintRect.ToString().c_str(), info.firstHandle.isShow,
503         info.secondHandle.paintRect.ToString().c_str(), info.secondHandle.isShow);
504     shareOverlayInfo_ = std::make_shared<SelectOverlayInfo>(info);
505     auto menuNode = SelectOverlayNode::CreateSelectOverlayNode(shareOverlayInfo_, SelectOverlayMode::MENU_ONLY);
506     menuNode_ = menuNode;
507     auto handleNode = SelectOverlayNode::CreateSelectOverlayNode(shareOverlayInfo_, SelectOverlayMode::HANDLE_ONLY);
508     handleNode_ = handleNode;
509     auto taskExecutor = Container::CurrentTaskExecutorSafely();
510     CHECK_NULL_VOID(taskExecutor);
511     taskExecutor->PostTask(
512         [animation, weak = WeakClaim(this), menuNode, handleNode, mode] {
513             auto manager = weak.Upgrade();
514             CHECK_NULL_VOID(manager);
515             auto isMenuNodeValid = (menuNode && menuNode == manager->menuNode_);
516             auto isHandleNodeValid = (handleNode && handleNode == manager->handleNode_);
517             if (!isMenuNodeValid || !isHandleNodeValid) {
518                 return;
519             }
520             if (manager->IsEnableSubWindowMenu()) {
521                 manager->MountMenuNodeToSubWindow(menuNode, animation, NodeType::TOUCH_MENU);
522             } else {
523                 manager->MountNodeToRoot(menuNode, animation, NodeType::TOUCH_MENU);
524             }
525             if (mode == HandleLevelMode::EMBED) {
526                 manager->MountNodeToCaller(handleNode, animation);
527             } else if (mode == HandleLevelMode::OVERLAY) {
528                 manager->MountNodeToRoot(handleNode, animation, NodeType::HANDLE);
529             }
530             manager->NotifySelectOverlayShow(true);
531         },
532         TaskExecutor::TaskType::UI, "CreateHandleLevelSelectOverlay", PriorityType::VIP);
533 }
534 
MountNodeToRoot(const RefPtr<FrameNode> & overlayNode,bool animation,NodeType nodeType)535 void SelectContentOverlayManager::MountNodeToRoot(
536     const RefPtr<FrameNode>& overlayNode, bool animation, NodeType nodeType)
537 {
538     auto rootNode = GetSelectOverlayRoot();
539     CHECK_NULL_VOID(rootNode);
540     const auto& children = rootNode->GetChildren();
541     auto slotIt = FindSelectOverlaySlot(rootNode, children);
542     auto index = static_cast<int32_t>(std::distance(children.begin(), slotIt));
543     auto slot = (index > 0) ? index : DEFAULT_NODE_SLOT;
544     bool isMeetSpecialNode = false;
545     std::vector<std::string> nodeTags = {
546         V2::KEYBOARD_ETS_TAG, // keep handle and menu node before keyboard node
547         V2::SELECT_OVERLAY_ETS_TAG, // keep handle node before menu node
548         V2::MAGNIFIER_TAG, // keep handle and menu node before magnifier
549         V2::SHEET_WRAPPER_TAG // keep handle and menu node before SheetWrapper
550     };
551     for (auto it = slotIt; it != children.end(); ++it) {
552         for (const auto& tag : nodeTags) {
553             if ((*it)->GetTag() == tag) {
554                 slot = std::min(slot, index);
555                 isMeetSpecialNode = true;
556                 break;
557             }
558         }
559         if (isMeetSpecialNode) {
560             break;
561         }
562         index++;
563     }
564     if (nodeType == NodeType::TOUCH_MENU || nodeType == NodeType::RIGHT_CLICK_MENU) {
565         slot = index;
566     }
567     TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY, "MountNodeToRoot:%{public}s, id:%{public}d", rootNode->GetTag().c_str(),
568         rootNode->GetId());
569     overlayNode->MountToParent(rootNode, slot);
570     rootNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
571     if (!shareOverlayInfo_->isUsingMouse) {
572         auto node = DynamicCast<SelectOverlayNode>(overlayNode);
573         if (node) {
574             node->ShowSelectOverlay(animation);
575         }
576     }
577 }
578 
FindSelectOverlaySlot(const RefPtr<FrameNode> & root,const std::list<RefPtr<UINode>> & children)579 std::list<RefPtr<UINode>>::const_iterator SelectContentOverlayManager::FindSelectOverlaySlot(
580     const RefPtr<FrameNode>& root, const std::list<RefPtr<UINode>>& children)
581 {
582     auto begin = children.begin();
583     CHECK_NULL_RETURN(selectOverlayHolder_, begin);
584     auto callerNode = selectOverlayHolder_->GetOwner();
585     CHECK_NULL_RETURN(callerNode, begin);
586     RefPtr<UINode> prevNode = nullptr;
587     auto parent = callerNode->GetParent();
588     while (parent) {
589         if (parent == root) {
590             break;
591         }
592         prevNode = parent;
593         parent = parent->GetParent();
594     }
595     CHECK_NULL_RETURN(parent, begin);
596     CHECK_NULL_RETURN(prevNode, begin);
597     for (auto it = begin; it != children.end(); ++it) {
598         if (prevNode == *it) {
599             return ++it;
600         }
601     }
602     return begin;
603 }
604 
MountNodeToCaller(const RefPtr<FrameNode> & overlayNode,bool animation)605 void SelectContentOverlayManager::MountNodeToCaller(const RefPtr<FrameNode>& overlayNode, bool animation)
606 {
607     CHECK_NULL_VOID(selectOverlayHolder_);
608     auto ownerFrameNode = selectOverlayHolder_->GetOwner();
609     CHECK_NULL_VOID(ownerFrameNode);
610     TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY,
611         "Mount SelectOverlay node: %{public}s, id: %{public}d", ownerFrameNode->GetTag().c_str(),
612         ownerFrameNode->GetId());
613     ownerFrameNode->SetOverlayNode(overlayNode);
614     overlayNode->SetParent(AceType::WeakClaim(AceType::RawPtr(ownerFrameNode)));
615     overlayNode->SetActive(true);
616     auto overlayProperty = AceType::DynamicCast<LayoutProperty>(overlayNode->GetLayoutProperty());
617     CHECK_NULL_VOID(overlayProperty);
618     overlayProperty->SetIsOverlayNode(true);
619     overlayProperty->UpdateAlignment(Alignment::CENTER);
620     overlayProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
621     ownerFrameNode->MarkNeedSyncRenderTree();
622     ownerFrameNode->RebuildRenderContextTree();
623     overlayNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
624     if (!shareOverlayInfo_->isUsingMouse) {
625         auto node = DynamicCast<SelectOverlayNode>(overlayNode);
626         if (node) {
627             node->ShowSelectOverlay(animation);
628         }
629     }
630 }
631 
NotifySelectOverlayShow(bool isCreated)632 void SelectContentOverlayManager::NotifySelectOverlayShow(bool isCreated)
633 {
634     CHECK_NULL_VOID(selectOverlayHolder_);
635     auto callback = selectOverlayHolder_->GetCallback();
636     CHECK_NULL_VOID(callback);
637     callback->OnAfterSelectOverlayShow(isCreated);
638 }
639 
GetSelectOverlayRoot()640 const RefPtr<FrameNode> SelectContentOverlayManager::GetSelectOverlayRoot()
641 {
642     auto rootNode = rootNodeWeak_.Upgrade();
643     CHECK_NULL_RETURN(shareOverlayInfo_, rootNode);
644     auto container = Container::Current();
645     if (container && container->IsScenceBoardWindow()) {
646         auto root = FindWindowScene(shareOverlayInfo_->callerFrameNode.Upgrade());
647         rootNode = DynamicCast<FrameNode>(root);
648     } else if (rootNode && selectOverlayHolder_ && selectOverlayHolder_->IsEnableContainerModal()) {
649         auto containerModalRoot = GetContainerModalRoot();
650         if (containerModalRoot) {
651             rootNode = containerModalRoot;
652         }
653     }
654     return rootNode;
655 }
656 
657 /**
658  * @description: This function will be used in SceneBoard Thread only.
659  * if need to show the select-overlay component, it expects to receive the target component bound by
660  * the select-overlay component to find the windowScene component.
661  * if need to hide the select-overlay component, it expects to receive the the select-overlay component
662  * to return the parent component. And the parent component will be the windowScene component exactly.
663  */
FindWindowScene(RefPtr<FrameNode> targetNode)664 RefPtr<UINode> SelectContentOverlayManager::FindWindowScene(RefPtr<FrameNode> targetNode)
665 {
666     auto container = Container::Current();
667     if (!container || !container->IsScenceBoardWindow()) {
668         return rootNodeWeak_.Upgrade();
669     }
670     CHECK_NULL_RETURN(targetNode, nullptr);
671     auto parent = targetNode->GetParent();
672     while (parent && parent->GetTag() != V2::WINDOW_SCENE_ETS_TAG) {
673         parent = parent->GetParent();
674     }
675     CHECK_NULL_RETURN(parent, nullptr);
676     return parent;
677 }
678 
CloseInternal(int32_t id,bool animation,CloseReason reason)679 bool SelectContentOverlayManager::CloseInternal(int32_t id, bool animation, CloseReason reason)
680 {
681     CHECK_NULL_RETURN(selectOverlayHolder_, false);
682     CHECK_NULL_RETURN(selectOverlayHolder_->GetOwnerId() == id, false);
683     CHECK_NULL_RETURN(shareOverlayInfo_, false);
684     TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY, "Close SelectOverlay, by id:%{public}d, reason %{public}d", id, reason);
685     auto callback = selectOverlayHolder_->GetCallback();
686     auto menuType = shareOverlayInfo_->menuInfo.menuType;
687     auto pattern = GetSelectHandlePattern(WeakClaim(this));
688     RefPtr<OverlayInfo> info = nullptr;
689     if (pattern) {
690         info = AceType::MakeRefPtr<OverlayInfo>();
691         info->isSingleHandle = shareOverlayInfo_->isSingleHandle;
692         info->isShowMenu = shareOverlayInfo_->menuInfo.menuIsShow;
693         info->isHiddenHandle = pattern->IsHiddenHandle();
694     }
695     auto selectOverlayNode = selectOverlayNode_.Upgrade();
696     auto menuNode = menuNode_.Upgrade();
697     auto handleNode = handleNode_.Upgrade();
698     if (animation && !shareOverlayInfo_->isUsingMouse) {
699         ClearAllStatus();
700         DestroySelectOverlayNodeWithAnimation(selectOverlayNode);
701         DestroySelectOverlayNodeWithAnimation(menuNode);
702         DestroySelectOverlayNodeWithAnimation(handleNode);
703     } else {
704         DestroySelectOverlayNode(selectOverlayNode);
705         DestroySelectOverlayNode(menuNode);
706         DestroySelectOverlayNode(handleNode);
707         ClearAllStatus();
708     }
709     if (callback) {
710         TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY, "SelectOverlay is closed with reason %{public}d - %{public}s",
711             reason, GetOwnerDebugInfo().c_str());
712         callback->OnCloseOverlay(menuType, reason, info);
713     }
714     return true;
715 }
716 
DestroySelectOverlayNodeWithAnimation(const RefPtr<FrameNode> & node)717 void SelectContentOverlayManager::DestroySelectOverlayNodeWithAnimation(const RefPtr<FrameNode>& node)
718 {
719     auto overlayNode = DynamicCast<SelectOverlayNode>(node);
720     CHECK_NULL_VOID(overlayNode);
721     overlayNode->HideSelectOverlay([weakOverlay = WeakClaim(AceType::RawPtr(node)), managerWeak = WeakClaim(this)]() {
722         auto manager = managerWeak.Upgrade();
723         CHECK_NULL_VOID(manager);
724         manager->DestroySelectOverlayNode(weakOverlay.Upgrade());
725     });
726 }
727 
DestroySelectOverlayNode(const RefPtr<FrameNode> & overlay)728 void SelectContentOverlayManager::DestroySelectOverlayNode(const RefPtr<FrameNode>& overlay)
729 {
730     CHECK_NULL_VOID(overlay);
731     auto parentNode = overlay->GetParent();
732     CHECK_NULL_VOID(parentNode);
733     auto pattern = overlay->GetPattern<SelectOverlayPattern>();
734     auto parentFrameNode = DynamicCast<FrameNode>(parentNode);
735     if (parentFrameNode) {
736         if (pattern && pattern->GetMode() == SelectOverlayMode::HANDLE_ONLY) {
737             parentFrameNode->SetOverlayNode(nullptr);
738             overlay->SetParent(nullptr);
739         }
740     }
741     TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY,
742         "Remove node [%{public}s, %{public}d] from [%{public}s, %{public}d]", overlay->GetTag().c_str(),
743         overlay->GetId(), parentNode->GetTag().c_str(), parentNode->GetId());
744     parentNode->RemoveChild(overlay);
745     parentNode->MarkNeedSyncRenderTree();
746     parentNode->RebuildRenderContextTree();
747     if (pattern && pattern->GetIsMenuShowInSubWindow()) {
748         SubwindowManager::GetInstance()->DeleteSelectOverlayHotAreas(pattern->GetContainerId(), overlay->GetId());
749         SubwindowManager::GetInstance()->HideSelectOverlay(pattern->GetContainerId());
750     } else {
751         auto menuWrapperPattern = overlay->GetPattern<MenuWrapperPattern>();
752         CHECK_NULL_VOID(menuWrapperPattern);
753         if (menuWrapperPattern->GetIsSelectOverlaySubWindowWrapper()) {
754             SubwindowManager::GetInstance()->DeleteSelectOverlayHotAreas(
755                 menuWrapperPattern->GetContainerId(), overlay->GetId());
756             SubwindowManager::GetInstance()->HideSelectOverlay(menuWrapperPattern->GetContainerId());
757         }
758     }
759 }
760 
ClearAllStatus()761 void SelectContentOverlayManager::ClearAllStatus()
762 {
763     selectOverlayNode_.Reset();
764     handleNode_.Reset();
765     menuNode_.Reset();
766     shareOverlayInfo_.reset();
767     if (selectOverlayHolder_) {
768         selectOverlayHolder_->OnBind(nullptr);
769     }
770     selectOverlayHolder_.Reset();
771 }
772 
CloseCurrent(bool animation,CloseReason reason)773 bool SelectContentOverlayManager::CloseCurrent(bool animation, CloseReason reason)
774 {
775     CHECK_NULL_RETURN(selectOverlayHolder_, false);
776     CHECK_NULL_RETURN(selectOverlayNode_.Upgrade() || menuNode_.Upgrade() || handleNode_.Upgrade(), false);
777     return CloseInternal(selectOverlayHolder_->GetOwnerId(), animation, reason);
778 }
779 
CloseWithOverlayId(int32_t overlayId,CloseReason reason,bool animation)780 void SelectContentOverlayManager::CloseWithOverlayId(int32_t overlayId, CloseReason reason, bool animation)
781 {
782     CHECK_NULL_VOID(IsOpen());
783     // call from menu button.
784     auto hasOverlayId = (selectOverlayNode_.Upgrade() && overlayId == selectOverlayNode_.Upgrade()->GetId());
785     hasOverlayId = hasOverlayId || (menuNode_.Upgrade() && menuNode_.Upgrade()->GetId());
786     if (hasOverlayId) {
787         CloseInternal(selectOverlayHolder_->GetOwnerId(), animation, reason);
788     }
789 }
790 
Close(int32_t id,bool animation,CloseReason reason)791 void SelectContentOverlayManager::Close(int32_t id, bool animation, CloseReason reason)
792 {
793     CloseInternal(id, animation, reason);
794 }
795 
ShowOptionMenu()796 void SelectContentOverlayManager::ShowOptionMenu()
797 {
798     auto pattern = GetSelectMenuPattern(WeakClaim(this));
799     CHECK_NULL_VOID(pattern);
800     pattern->UpdateMenuIsShow(true);
801 }
802 
HideOptionMenu(bool noAnimation)803 void SelectContentOverlayManager::HideOptionMenu(bool noAnimation)
804 {
805     auto pattern = GetSelectMenuPattern(WeakClaim(this));
806     CHECK_NULL_VOID(pattern);
807     pattern->UpdateMenuIsShow(false, noAnimation);
808 }
809 
ToggleOptionMenu()810 void SelectContentOverlayManager::ToggleOptionMenu()
811 {
812     CHECK_NULL_VOID(shareOverlayInfo_);
813     auto pattern = GetSelectMenuPattern(WeakClaim(this));
814     CHECK_NULL_VOID(pattern);
815     pattern->UpdateMenuIsShow(!shareOverlayInfo_->menuInfo.menuIsShow);
816 }
817 
DisableMenu()818 void SelectContentOverlayManager::DisableMenu()
819 {
820     auto pattern = GetSelectMenuPattern(WeakClaim(this));
821     CHECK_NULL_VOID(pattern);
822     pattern->DisableMenu(true);
823 }
824 
EnableMenu()825 void SelectContentOverlayManager::EnableMenu()
826 {
827     auto pattern = GetSelectMenuPattern(WeakClaim(this));
828     CHECK_NULL_VOID(pattern);
829     pattern->DisableMenu(false);
830 }
831 
HideHandle()832 void SelectContentOverlayManager::HideHandle()
833 {
834     auto pattern = GetSelectHandlePattern(WeakClaim(this));
835     CHECK_NULL_VOID(pattern);
836     pattern->StartHiddenHandleTask(false);
837 }
838 
IsOpen()839 bool SelectContentOverlayManager::IsOpen()
840 {
841     if (!IsEnableHandleLevel()) {
842         auto overlayNode = selectOverlayNode_.Upgrade();
843         return overlayNode && overlayNode->GetParent();
844     }
845     auto hasHandleNode = handleNode_.Upgrade() && handleNode_.Upgrade()->GetParent();
846     auto hasMenuNode = menuNode_.Upgrade() && menuNode_.Upgrade()->GetParent();
847     return hasHandleNode || hasMenuNode;
848 }
849 
IsCreating()850 bool SelectContentOverlayManager::IsCreating()
851 {
852     if (!IsEnableHandleLevel()) {
853         auto overlayNode = selectOverlayNode_.Upgrade();
854         return overlayNode && !overlayNode->GetParent();
855     }
856     auto menuNode = menuNode_.Upgrade();
857     auto handleNode = handleNode_.Upgrade();
858     return (menuNode && !menuNode->GetParent()) || (handleNode && !handleNode->GetParent());
859 }
860 
IsMenuShow()861 bool SelectContentOverlayManager::IsMenuShow()
862 {
863     return IsOpen() && shareOverlayInfo_ && shareOverlayInfo_->menuInfo.menuIsShow;
864 }
865 
IsSingleHandle()866 bool SelectContentOverlayManager::IsSingleHandle()
867 {
868     return IsOpen() && shareOverlayInfo_ && shareOverlayInfo_->isSingleHandle;
869 }
870 
IsHandlesShow()871 bool SelectContentOverlayManager::IsHandlesShow()
872 {
873     return IsOpen() && shareOverlayInfo_ && !shareOverlayInfo_->isSingleHandle;
874 }
875 
IsHandleReverse()876 bool SelectContentOverlayManager::IsHandleReverse()
877 {
878     return IsOpen() && shareOverlayInfo_ && shareOverlayInfo_->handleReverse;
879 }
880 
RestartHiddenHandleTask(bool isDelay)881 void SelectContentOverlayManager::RestartHiddenHandleTask(bool isDelay)
882 {
883     auto pattern = GetSelectHandlePattern(WeakClaim(this));
884     CHECK_NULL_VOID(pattern);
885     pattern->RestartHiddenHandleTask(isDelay);
886 }
887 
CancelHiddenHandleTask()888 void SelectContentOverlayManager::CancelHiddenHandleTask()
889 {
890     auto pattern = GetSelectHandlePattern(WeakClaim(this));
891     CHECK_NULL_VOID(pattern);
892     pattern->CancelHiddenHandleTask();
893 }
894 
GetSelectOverlayNode()895 RefPtr<SelectOverlayNode> SelectContentOverlayManager::GetSelectOverlayNode()
896 {
897     auto overlayNode = IsEnableHandleLevel() ? menuNode_.Upgrade() : selectOverlayNode_.Upgrade();
898     return AceType::DynamicCast<SelectOverlayNode>(overlayNode);
899 }
900 
GetShowMenuType()901 OptionMenuType SelectContentOverlayManager::GetShowMenuType()
902 {
903     return IsOpen() && shareOverlayInfo_ ? shareOverlayInfo_->menuInfo.menuType : OptionMenuType::NO_MENU;
904 }
905 
HandleGlobalEvent(const TouchEvent & touchEvent,const NG::OffsetF & rootOffset)906 void SelectContentOverlayManager::HandleGlobalEvent(const TouchEvent& touchEvent, const NG::OffsetF& rootOffset)
907 {
908     NG::PointF point { touchEvent.x - rootOffset.GetX(), touchEvent.y - rootOffset.GetY() };
909     point = point - GetContainerModalOffset();
910     if (touchEvent.type == TouchType::DOWN) {
911         isIntercept_ = IsTouchInSelectOverlayArea(point);
912     }
913     if (!isIntercept_) {
914         HandleSelectionEvent(point, touchEvent);
915         if (selectOverlayHolder_ && selectOverlayHolder_->GetCallback() && selectOverlayHolder_->GetOwner()) {
916             auto localPoint = point;
917             ConvertPointRelativeToNode(selectOverlayHolder_->GetOwner(), localPoint);
918             selectOverlayHolder_->GetCallback()->OnHandleGlobalEvent(point, localPoint, touchEvent);
919         }
920     }
921     if (touchEvent.type == TouchType::UP) {
922         isIntercept_ = false;
923     }
924 }
925 
IsTouchInSelectOverlayArea(const PointF & point)926 bool SelectContentOverlayManager::IsTouchInSelectOverlayArea(const PointF& point)
927 {
928     if (!IsEnableHandleLevel()) {
929         return IsTouchInNormalSelectOverlayArea(point);
930     }
931     return IsTouchInHandleLevelOverlayArea(point);
932 }
933 
IsTouchInNormalSelectOverlayArea(const PointF & point)934 bool SelectContentOverlayManager::IsTouchInNormalSelectOverlayArea(const PointF& point)
935 {
936     auto current = selectOverlayNode_.Upgrade();
937     CHECK_NULL_RETURN(current, false);
938     auto selectOverlayNode = DynamicCast<SelectOverlayNode>(current);
939     if (selectOverlayNode) {
940         return selectOverlayNode->IsInSelectedOrSelectOverlayArea(point);
941     }
942     // get the menu rect not the out wrapper
943     auto modalOffset = GetContainerModalOffset();
944     const auto& children = current->GetChildren();
945     for (const auto& it : children) {
946         auto child = DynamicCast<FrameNode>(it);
947         if (child == nullptr || !child->GetGeometryNode()) {
948             continue;
949         }
950         auto frameRect =
951             RectF(child->GetTransformRelativeOffset() - modalOffset, child->GetGeometryNode()->GetFrameSize());
952         if (frameRect.IsInRegion(point)) {
953             return true;
954         }
955     }
956     return false;
957 }
958 
IsTouchInHandleLevelOverlayArea(const PointF & point)959 bool SelectContentOverlayManager::IsTouchInHandleLevelOverlayArea(const PointF& point)
960 {
961     auto selectOverlayNode = DynamicCast<SelectOverlayNode>(menuNode_.Upgrade());
962     if (selectOverlayNode && selectOverlayNode->IsInSelectedOrSelectOverlayArea(point)) {
963         return true;
964     }
965     selectOverlayNode = DynamicCast<SelectOverlayNode>(handleNode_.Upgrade());
966     CHECK_NULL_RETURN(selectOverlayNode, false);
967     auto localPoint = point;
968     ConvertPointRelativeToNode(selectOverlayNode->GetAncestorNodeOfFrame(true), localPoint);
969     return selectOverlayNode->IsInSelectedOrSelectOverlayArea(localPoint);
970 }
971 
HandleSelectionEvent(const PointF & point,const TouchEvent & rawTouchEvent)972 void SelectContentOverlayManager::HandleSelectionEvent(const PointF& point, const TouchEvent& rawTouchEvent)
973 {
974     CHECK_NULL_VOID(holdSelectionInfo_);
975     CHECK_NULL_VOID(holdSelectionInfo_->checkTouchInArea);
976     CHECK_NULL_VOID(holdSelectionInfo_->resetSelectionCallback);
977     if (holdSelectionInfo_->IsAcceptEvent(rawTouchEvent.sourceType, rawTouchEvent.type) &&
978         !holdSelectionInfo_->checkTouchInArea(point) && !IsOpen()) {
979         ResetSelectionRect();
980     }
981 }
982 
ResetSelectionRect()983 void SelectContentOverlayManager::ResetSelectionRect()
984 {
985     CHECK_NULL_VOID(holdSelectionInfo_);
986     if (holdSelectionInfo_->resetSelectionCallback) {
987         holdSelectionInfo_->resetSelectionCallback();
988     }
989     selectionHoldId_ = -1;
990     holdSelectionInfo_.reset();
991 }
992 
SetHoldSelectionCallback(int32_t id,const HoldSelectionInfo & selectionInfo)993 void SelectContentOverlayManager::SetHoldSelectionCallback(int32_t id, const HoldSelectionInfo& selectionInfo)
994 {
995     if (id == selectionHoldId_) {
996         return;
997     }
998     if (holdSelectionInfo_ && id != selectionHoldId_ && holdSelectionInfo_->resetSelectionCallback) {
999         holdSelectionInfo_->resetSelectionCallback();
1000     }
1001     selectionHoldId_ = id;
1002     holdSelectionInfo_ = selectionInfo;
1003 }
1004 
RemoveHoldSelectionCallback(int32_t id)1005 void SelectContentOverlayManager::RemoveHoldSelectionCallback(int32_t id)
1006 {
1007     CHECK_NULL_VOID(holdSelectionInfo_);
1008     if (selectionHoldId_ == id) {
1009         selectionHoldId_ = -1;
1010         holdSelectionInfo_.reset();
1011     }
1012 }
1013 
IsEnableHandleLevel()1014 bool SelectContentOverlayManager::IsEnableHandleLevel()
1015 {
1016     return shareOverlayInfo_ && shareOverlayInfo_->enableHandleLevel;
1017 }
1018 
GetMenuPattern()1019 RefPtr<Pattern> SelectContentOverlayManager::GetMenuPattern()
1020 {
1021     return IsEnableHandleLevel() ? GetSelectOverlayPattern(menuNode_)
1022                                       : GetSelectOverlayPattern(selectOverlayNode_);
1023 }
1024 
GetHandlePattern()1025 RefPtr<Pattern> SelectContentOverlayManager::GetHandlePattern()
1026 {
1027     return IsEnableHandleLevel() ? GetSelectOverlayPattern(handleNode_)
1028                                       : GetSelectOverlayPattern(selectOverlayNode_);
1029 }
1030 
GetHandleOverlayNode()1031 RefPtr<FrameNode> SelectContentOverlayManager::GetHandleOverlayNode()
1032 {
1033     return handleNode_.Upgrade();
1034 }
1035 
NotifyUpdateToolBar(bool itemChanged)1036 void SelectContentOverlayManager::NotifyUpdateToolBar(bool itemChanged)
1037 {
1038     auto menuNode = DynamicCast<SelectOverlayNode>(menuNode_.Upgrade());
1039     CHECK_NULL_VOID(menuNode);
1040     menuNode->UpdateToolBar(itemChanged);
1041 }
1042 
GetHandleDiameter()1043 float SelectContentOverlayManager::GetHandleDiameter()
1044 {
1045     return SelectOverlayPattern::GetHandleDiameter();
1046 }
1047 
ConvertPointRelativeToNode(const RefPtr<FrameNode> & node,PointF & point)1048 void SelectContentOverlayManager::ConvertPointRelativeToNode(const RefPtr<FrameNode>& node, PointF& point)
1049 {
1050     CHECK_NULL_VOID(node);
1051     auto rootNode = GetSelectOverlayRoot();
1052     CHECK_NULL_VOID(rootNode);
1053     std::stack<RefPtr<FrameNode>> nodeStack;
1054     auto parent = node;
1055     while (parent && parent != rootNode) {
1056         nodeStack.push(parent);
1057         parent = parent->GetAncestorNodeOfFrame(true);
1058     }
1059     CHECK_NULL_VOID(!nodeStack.empty());
1060     PointF temp(point.GetX(), point.GetY());
1061     while (!nodeStack.empty()) {
1062         parent = nodeStack.top();
1063         CHECK_NULL_VOID(parent);
1064         nodeStack.pop();
1065         auto renderContext = parent->GetRenderContext();
1066         CHECK_NULL_VOID(renderContext);
1067         renderContext->GetPointWithRevert(temp);
1068         auto rectOffset = renderContext->GetPaintRectWithoutTransform().GetOffset();
1069         temp = temp - rectOffset;
1070     }
1071     point.SetX(temp.GetX());
1072     point.SetY(temp.GetY());
1073 }
1074 
IsTouchAtHandle(const PointF & localPoint,const PointF & globalPoint)1075 bool SelectContentOverlayManager::IsTouchAtHandle(const PointF& localPoint, const PointF& globalPoint)
1076 {
1077     auto handleNode = handleNode_.Upgrade();
1078     CHECK_NULL_RETURN(handleNode, false);
1079     auto selectOverlayNode = DynamicCast<SelectOverlayNode>(handleNode);
1080     CHECK_NULL_RETURN(selectOverlayNode, false);
1081     auto pattern = selectOverlayNode->GetPattern<SelectOverlayPattern>();
1082     CHECK_NULL_RETURN(pattern, false);
1083     if (pattern->IsHiddenHandle()) {
1084         return false;
1085     }
1086     CHECK_NULL_RETURN(selectOverlayHolder_, false);
1087     if (selectOverlayNode->GetParent() == selectOverlayHolder_->GetOwner()) {
1088         return selectOverlayNode->IsInSelectedOrSelectOverlayArea(localPoint);
1089     }
1090     return selectOverlayNode->IsInSelectedOrSelectOverlayArea(globalPoint);
1091 }
1092 
SetHandleCircleIsShow(bool isFirst,bool isShow)1093 void SelectContentOverlayManager::SetHandleCircleIsShow(bool isFirst, bool isShow)
1094 {
1095     auto pattern = GetSelectHandlePattern(WeakClaim(this));
1096     CHECK_NULL_VOID(pattern);
1097     pattern->SetHandleCircleIsShow(isFirst, isShow);
1098 }
1099 
SetIsHandleLineShow(bool isShow)1100 void SelectContentOverlayManager::SetIsHandleLineShow(bool isShow)
1101 {
1102     auto pattern = GetSelectHandlePattern(WeakClaim(this));
1103     CHECK_NULL_VOID(pattern);
1104     pattern->SetIsHandleLineShow(isShow);
1105 }
1106 
MarkHandleDirtyNode(PropertyChangeFlag flag)1107 void SelectContentOverlayManager::MarkHandleDirtyNode(PropertyChangeFlag flag)
1108 {
1109     auto pattern = GetSelectHandlePattern(WeakClaim(this));
1110     CHECK_NULL_VOID(pattern);
1111     auto host = pattern->GetHost();
1112     CHECK_NULL_VOID(host);
1113     host->MarkDirtyNode(flag);
1114 }
1115 
IsHiddenHandle()1116 bool SelectContentOverlayManager::IsHiddenHandle()
1117 {
1118     auto pattern = GetSelectHandlePattern(WeakClaim(this));
1119     CHECK_NULL_RETURN(pattern, false);
1120     return pattern->IsHiddenHandle();
1121 }
1122 
UpdateSelectOverlayInfoInternal(SelectOverlayInfo & overlayInfo)1123 void SelectContentOverlayManager::UpdateSelectOverlayInfoInternal(SelectOverlayInfo& overlayInfo)
1124 {
1125     if (!selectOverlayHolder_ || !selectOverlayHolder_->IsEnableContainerModal()) {
1126         return;
1127     }
1128     if (overlayInfo.ancestorViewPort) {
1129         ConvertRectRelativeToParent(*overlayInfo.ancestorViewPort);
1130     }
1131     ConvertRectRelativeToParent(overlayInfo.selectArea);
1132     ConvertHandleRelativeToParent(overlayInfo.firstHandle);
1133     ConvertHandleRelativeToParent(overlayInfo.secondHandle);
1134     auto containerModalOffset = GetContainerModalOffset();
1135     if (overlayInfo.isUsingMouse) {
1136         overlayInfo.rightClickOffset -= containerModalOffset;
1137     }
1138     overlayInfo.containerModalOffset = containerModalOffset;
1139 }
1140 
GetContainerModalOffset()1141 OffsetF SelectContentOverlayManager::GetContainerModalOffset()
1142 {
1143     CHECK_NULL_RETURN(selectOverlayHolder_, OffsetF());
1144     if (!selectOverlayHolder_->IsEnableContainerModal()) {
1145         return OffsetF();
1146     }
1147     auto rootNode = GetContainerModalRoot();
1148     CHECK_NULL_RETURN(rootNode, OffsetF());
1149     return rootNode->GetTransformRelativeOffset();
1150 }
1151 
ConvertRectRelativeToParent(RectF & rect)1152 void SelectContentOverlayManager::ConvertRectRelativeToParent(RectF& rect)
1153 {
1154     rect.SetOffset(rect.GetOffset() - GetContainerModalOffset());
1155 }
1156 
ConvertHandleRelativeToParent(SelectHandleInfo & info)1157 void SelectContentOverlayManager::ConvertHandleRelativeToParent(SelectHandleInfo& info)
1158 {
1159     auto modalOffset = GetContainerModalOffset();
1160     if (modalOffset.NonOffset()) {
1161         return;
1162     }
1163     ConvertRectRelativeToParent(info.paintRect);
1164     if (info.isPaintHandleWithPoints) {
1165         info.paintInfo = info.paintInfo - modalOffset;
1166     }
1167     if (info.paintInfoConverter) {
1168         info.paintInfoConverter = [weak = WeakClaim(this), converter = std::move(info.paintInfoConverter)](
1169                                       const SelectHandlePaintInfo& paintInfo) {
1170             auto manager = weak.Upgrade();
1171             CHECK_NULL_RETURN(manager, RectF());
1172             auto tmpPaintInfo = paintInfo;
1173             tmpPaintInfo = tmpPaintInfo + manager->GetContainerModalOffset();
1174             return converter(tmpPaintInfo);
1175         };
1176     }
1177 }
1178 
RevertRectRelativeToRoot(RectF & handle)1179 void SelectContentOverlayManager::RevertRectRelativeToRoot(RectF& handle)
1180 {
1181     CHECK_NULL_VOID(shareOverlayInfo_);
1182     if (shareOverlayInfo_->handleLevelMode == HandleLevelMode::EMBED) {
1183         return;
1184     }
1185     handle.SetOffset(handle.GetOffset() + GetContainerModalOffset());
1186 }
1187 
GetContainerModalRoot()1188 RefPtr<FrameNode> SelectContentOverlayManager::GetContainerModalRoot()
1189 {
1190     auto rootNode = rootNodeWeak_.Upgrade();
1191     if (rootNode) {
1192         auto context = rootNode->GetContextRefPtr();
1193         CHECK_NULL_RETURN(context, nullptr);
1194         auto windowModal = context->GetWindowModal();
1195         if (windowModal == WindowModal::CONTAINER_MODAL) {
1196             auto overlayManager = context->GetOverlayManager();
1197             CHECK_NULL_RETURN(overlayManager, nullptr);
1198             auto overlayRoot = overlayManager->GetRootNode();
1199             CHECK_NULL_RETURN(overlayRoot.Upgrade(), nullptr);
1200             return DynamicCast<FrameNode>(overlayRoot.Upgrade());
1201         }
1202     }
1203     return nullptr;
1204 }
1205 
IsStopBackPress() const1206 bool SelectContentOverlayManager::IsStopBackPress() const
1207 {
1208     CHECK_NULL_RETURN(selectOverlayHolder_, true);
1209     return selectOverlayHolder_->IsStopBackPress();
1210 }
1211 
GetOwnerDebugInfo()1212 std::string SelectContentOverlayManager::GetOwnerDebugInfo()
1213 {
1214     CHECK_NULL_RETURN(selectOverlayHolder_, "Holder NA");
1215     std::stringstream ownerInfo;
1216     if (selectOverlayHolder_->GetOwner()) {
1217         ownerInfo << "[" << selectOverlayHolder_->GetOwner()->GetTag() << "," << selectOverlayHolder_->GetOwnerId()
1218                   << "]";
1219     }
1220     return ownerInfo.str();
1221 }
1222 
MountMenuNodeToSubWindow(const RefPtr<FrameNode> & overlayNode,bool animation,NodeType nodeType)1223 void SelectContentOverlayManager::MountMenuNodeToSubWindow(
1224     const RefPtr<FrameNode>& overlayNode, bool animation, NodeType nodeType)
1225 {
1226     CHECK_NULL_VOID(shareOverlayInfo_);
1227     CHECK_NULL_VOID(overlayNode);
1228     containerId_ = SubwindowManager::GetInstance()->ShowSelectOverlay(overlayNode);
1229     if (containerId_ == -1) {
1230         TAG_LOGW(AceLogTag::ACE_SELECT_OVERLAY,
1231             "Failed to display selectoverlay menu in the subwindow, still displayed in the main window.");
1232         MountNodeToRoot(overlayNode, animation, nodeType);
1233         return;
1234     }
1235     if (!shareOverlayInfo_->isUsingMouse) {
1236         auto node = DynamicCast<SelectOverlayNode>(overlayNode);
1237         if (node) {
1238             node->ShowSelectOverlay(animation);
1239         }
1240     }
1241 
1242     if (shareOverlayInfo_->isUsingMouse && !shareOverlayInfo_->menuInfo.menuBuilder) {
1243         // if menu is "SelectOverlayMenuByRightClick", menuWrapper need containerId to set menu hot areas in subwindow
1244         auto menuWrapperPattern = overlayNode->GetPattern<MenuWrapperPattern>();
1245         CHECK_NULL_VOID(menuWrapperPattern);
1246         menuWrapperPattern->SetContainerId(containerId_);
1247         menuWrapperPattern->SetIsSelectOverlaySubWindowWrapper(true);
1248         UpdateRightClickSubWindowMenuProps(overlayNode);
1249     } else {
1250         auto selectOverlayNode = DynamicCast<SelectOverlayNode>(overlayNode);
1251         CHECK_NULL_VOID(selectOverlayNode);
1252         auto selectOverlayPattern = selectOverlayNode->GetPattern<SelectOverlayPattern>();
1253         CHECK_NULL_VOID(selectOverlayPattern);
1254         selectOverlayPattern->SetContainerId(containerId_);
1255         selectOverlayPattern->SetIsMenuShowInSubWindow(true);
1256     }
1257 }
1258 
UpdateRightClickSubWindowMenuProps(const RefPtr<FrameNode> & overlayNode)1259 void SelectContentOverlayManager::UpdateRightClickSubWindowMenuProps(const RefPtr<FrameNode>& overlayNode)
1260 {
1261     CHECK_NULL_VOID(shareOverlayInfo_);
1262     CHECK_NULL_VOID(overlayNode);
1263     auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
1264     CHECK_NULL_VOID(pipeline);
1265     auto menu = DynamicCast<FrameNode>(overlayNode->GetChildAtIndex(0));
1266     CHECK_NULL_VOID(menu);
1267     auto windowManager = pipeline->GetWindowManager();
1268     auto isContainerModal = pipeline->GetWindowModal() == WindowModal::CONTAINER_MODAL && windowManager &&
1269                             windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING;
1270     if (!isContainerModal) {
1271         auto props = menu->GetLayoutProperty<MenuLayoutProperty>();
1272         CHECK_NULL_VOID(props);
1273         OffsetF containerModalOffset = GetContainerModalOffset();
1274 
1275         props->UpdateMenuOffset(shareOverlayInfo_->rightClickOffset + containerModalOffset);
1276         TAG_LOGD(AceLogTag::ACE_SELECT_OVERLAY,
1277             "UpdateRightClickSubWindowMenuProps rightClickOffset:%{public}s containerModalOffset:%{public}s",
1278             shareOverlayInfo_->rightClickOffset.ToString().c_str(), containerModalOffset.ToString().c_str());
1279     }
1280     auto overlayNodePipeline = overlayNode->GetContext();
1281     CHECK_NULL_VOID(overlayNodePipeline);
1282     auto overlayNodeContainerId = overlayNodePipeline->GetInstanceId();
1283     ContainerScope scope(overlayNodeContainerId);
1284     menu->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1285 }
1286 
IsEnableSubWindowMenu()1287 bool SelectContentOverlayManager::IsEnableSubWindowMenu()
1288 {
1289     CHECK_NULL_RETURN(shareOverlayInfo_, false);
1290     CHECK_NULL_RETURN(shareOverlayInfo_->enableSubWindowMenu, false);
1291     auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
1292     CHECK_NULL_RETURN(pipeline, false);
1293     auto overlayManager = pipeline->GetSelectOverlayManager();
1294     CHECK_NULL_RETURN(overlayManager, false);
1295     auto showMode = overlayManager->GetMenuShowMode();
1296     TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY, "IsEnableSubWindowMenu showMode:%{public}d", showMode);
1297     if (showMode != TextMenuShowMode::PREFER_WINDOW) {
1298         return false;
1299     }
1300 #if defined(PREVIEW)
1301     TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY, "Unable to use the subWindow in the Previewer. Use default mode instead.");
1302     return false;
1303 #endif
1304     if (selectOverlayHolder_ && !selectOverlayHolder_->GetIsHostNodeEnableSubWindowMenu()) {
1305         TAG_LOGW(AceLogTag::ACE_SELECT_OVERLAY, "The callerNode does not support show menu in subwinodw.");
1306         return false;
1307     }
1308     auto containerId = Container::CurrentIdSafelyWithCheck();
1309     auto callerFrameNode = shareOverlayInfo_->callerFrameNode.Upgrade();
1310     CHECK_NULL_RETURN(callerFrameNode, false);
1311     return SubwindowManager::GetInstance()->IsWindowEnableSubWindowMenu(containerId, callerFrameNode);
1312 }
1313 
1314 // whether the menu is the default right click menu which root node is menu wrapper and is displayed in subwindow
IsRightClickSubWindowMenu()1315 bool SelectContentOverlayManager::IsRightClickSubWindowMenu()
1316 {
1317     CHECK_NULL_RETURN(shareOverlayInfo_, false);
1318     if (shareOverlayInfo_->isUsingMouse && !shareOverlayInfo_->menuInfo.menuBuilder) {
1319         auto selectOverlayNode = selectOverlayNode_.Upgrade();
1320         CHECK_NULL_RETURN(selectOverlayNode, false);
1321         auto menuWrapperPattern = selectOverlayNode->GetPattern<MenuWrapperPattern>();
1322         CHECK_NULL_RETURN(menuWrapperPattern, false);
1323         return menuWrapperPattern->GetIsSelectOverlaySubWindowWrapper();
1324     }
1325 
1326     return false;
1327 }
1328 
1329 // whether the menu is the text selection menu which root node is selectoverlay and is displayed in subwindow
IsSelectOverlaySubWindowMenu()1330 bool SelectContentOverlayManager::IsSelectOverlaySubWindowMenu()
1331 {
1332     CHECK_NULL_RETURN(shareOverlayInfo_, false);
1333     if (shareOverlayInfo_->isUsingMouse && !shareOverlayInfo_->menuInfo.menuBuilder) {
1334         return false;
1335     }
1336     RefPtr<FrameNode> menuNode;
1337     if (shareOverlayInfo_->isUsingMouse) {
1338         menuNode = selectOverlayNode_.Upgrade();
1339     } else {
1340         menuNode = menuNode_.Upgrade();
1341     }
1342     CHECK_NULL_RETURN(menuNode, false);
1343     auto selectOverlayNode = DynamicCast<SelectOverlayNode>(menuNode);
1344     CHECK_NULL_RETURN(selectOverlayNode, false);
1345     auto selectOverlayPattern = selectOverlayNode->GetPattern<SelectOverlayPattern>();
1346     CHECK_NULL_RETURN(selectOverlayPattern, false);
1347     return selectOverlayPattern->GetIsMenuShowInSubWindow();
1348 }
1349 } // namespace OHOS::Ace::NG
1350