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