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