• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/rich_editor/rich_editor_select_overlay.h"
17 
18 
19 #include <algorithm>
20 #include <optional>
21 
22 #include "base/utils/utils.h"
23 #include "base/memory/ace_type.h"
24 #include "core/components_ng/manager/select_content_overlay/select_content_overlay_manager.h"
25 #include "core/components_ng/pattern/select_overlay/select_overlay_property.h"
26 #include "core/components_ng/pattern/rich_editor/rich_editor_pattern.h"
27 #include "core/components/text_overlay/text_overlay_theme.h"
28 
29 namespace OHOS::Ace::NG {
30 namespace {
31 constexpr float BOX_EPSILON = 0.5f;
32 constexpr float DOUBLE = 2.0f;
33 constexpr SelectOverlayDirtyFlag UPDATE_HANDLE_COLOR_FLAG = 101;
34 }
35 
PreProcessOverlay(const OverlayRequest & request)36 bool RichEditorSelectOverlay::PreProcessOverlay(const OverlayRequest& request)
37 {
38     auto pipeline = PipelineContext::GetCurrentContextSafely();
39     CHECK_NULL_RETURN(pipeline, false);
40     auto pattern = GetPattern<RichEditorPattern>();
41     CHECK_NULL_RETURN(pattern, false);
42     SetUsingMouse(pattern->IsUsingMouse());
43     auto host = pattern->GetHost();
44     CHECK_NULL_RETURN(host, false);
45     pipeline->AddOnAreaChangeNode(host->GetId());
46     SetEnableHandleLevel(true);
47     return true;
48 }
49 
GetFirstHandleInfo()50 std::optional<SelectHandleInfo> RichEditorSelectOverlay::GetFirstHandleInfo()
51 {
52     auto pattern = GetPattern<RichEditorPattern>();
53     CHECK_NULL_RETURN(pattern, std::nullopt);
54     SelectHandleInfo handleInfo;
55     handleInfo.paintRect = pattern->textSelector_.firstHandle;
56     handleInfo.isShow = CheckHandleVisible(handleInfo.paintRect);
57 
58     auto localPaintRect = handleInfo.paintRect;
59     localPaintRect.SetOffset(localPaintRect.GetOffset() - GetPaintOffsetWithoutTransform());
60     handleInfo.localPaintRect = localPaintRect;
61     SetTransformPaintInfo(handleInfo, localPaintRect);
62     return handleInfo;
63 }
64 
GetSecondHandleInfo()65 std::optional<SelectHandleInfo> RichEditorSelectOverlay::GetSecondHandleInfo()
66 {
67     auto pattern = GetPattern<RichEditorPattern>();
68     CHECK_NULL_RETURN(pattern, std::nullopt);
69     SelectHandleInfo handleInfo;
70     handleInfo.paintRect = pattern->textSelector_.secondHandle;
71     handleInfo.isShow = CheckHandleVisible(handleInfo.paintRect);
72 
73     auto localPaintRect = handleInfo.paintRect;
74     localPaintRect.SetOffset(localPaintRect.GetOffset() - GetPaintOffsetWithoutTransform());
75     handleInfo.localPaintRect = localPaintRect;
76     SetTransformPaintInfo(handleInfo, localPaintRect);
77     return handleInfo;
78 }
79 
CheckHandleVisible(const RectF & paintRect)80 bool RichEditorSelectOverlay::CheckHandleVisible(const RectF& paintRect)
81 {
82     auto pattern = GetPattern<RichEditorPattern>();
83     CHECK_NULL_RETURN(pattern, false);
84     auto host = pattern->GetHost();
85     CHECK_NULL_RETURN(host, false);
86     if (IsUsingMouse()) {
87         TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "No need to show handle when using mouse");
88         return false;
89     }
90 
91     auto contentRect = pattern->GetTextContentRect();
92     auto parentGlobalOffset = pattern->GetParentGlobalOffset();
93     RectF visibleContentRect(contentRect.GetOffset() + parentGlobalOffset, contentRect.GetSize());
94     auto parent = host->GetAncestorNodeOfFrame();
95     visibleContentRect = GetVisibleContentRect();
96     if (visibleContentRect.IsEmpty()) {
97         return false;
98     }
99     auto paintLeft = paintRect.Left() + paintRect.Width() / 2.0f;
100     PointF bottomPoint = { paintLeft, paintRect.Bottom() - BOX_EPSILON };
101     PointF topPoint = { paintLeft, paintRect.Top() + BOX_EPSILON };
102     visibleContentRect.SetLeft(visibleContentRect.GetX() - BOX_EPSILON);
103     visibleContentRect.SetWidth(visibleContentRect.Width() + DOUBLE * BOX_EPSILON);
104     visibleContentRect.SetTop(visibleContentRect.GetY() - BOX_EPSILON);
105     visibleContentRect.SetHeight(visibleContentRect.Height() + DOUBLE * BOX_EPSILON);
106     return visibleContentRect.IsInRegion(bottomPoint) && visibleContentRect.IsInRegion(topPoint);
107 }
108 
OnResetTextSelection()109 void RichEditorSelectOverlay::OnResetTextSelection()
110 {
111     auto textPattern = GetPattern<TextPattern>();
112     CHECK_NULL_VOID(textPattern);
113     textPattern->ResetSelection();
114 }
115 
AfterCloseOverlay()116 void RichEditorSelectOverlay::AfterCloseOverlay()
117 {
118     RemoveAreaChangeInner();
119     CloseMagnifier();
120 }
121 
RemoveAreaChangeInner()122 void RichEditorSelectOverlay::RemoveAreaChangeInner()
123 {
124     auto textPattern = GetPattern<TextPattern>();
125     CHECK_NULL_VOID(textPattern);
126     textPattern->RemoveAreaChangeInner();
127 }
128 
CloseMagnifier()129 void RichEditorSelectOverlay::CloseMagnifier()
130 {
131     auto pattern = GetPattern<RichEditorPattern>();
132     CHECK_NULL_VOID(pattern);
133     pattern->magnifierController_->RemoveMagnifierFrameNode();
134 }
135 
OnHandleMove(const RectF & handleRect,bool isFirst)136 void RichEditorSelectOverlay::OnHandleMove(const RectF& handleRect, bool isFirst)
137 {
138     auto pattern = GetPattern<RichEditorPattern>();
139     CHECK_NULL_VOID(pattern);
140     CHECK_NULL_VOID(pattern->HasFocus());
141     CHECK_NULL_VOID(SelectOverlayIsOn());
142     CHECK_NULL_VOID(!pattern->spans_.empty());
143     TextSelectOverlay::OnHandleMove(handleRect, isFirst);
144     auto parentGlobalOffset = pattern->GetParentGlobalOffset();
145     if (hasTransform_) {
146         parentGlobalOffset = GetPaintOffsetWithoutTransform();
147     }
148     auto localOffset = handleRect.GetOffset();
149     if (IsOverlayMode()) {
150         localOffset = localOffset - parentGlobalOffset; // original offset
151     }
152 
153     // update moving handle offset
154     auto movingHandleOffset = pattern->ConvertTouchOffsetToTextOffset(Offset(localOffset.GetX(), localOffset.GetY()));
155     auto movingHandleOffsetF = OffsetF(movingHandleOffset.GetX(), movingHandleOffset.GetY());
156     GetLocalPointWithTransform(movingHandleOffsetF); // do affine transformation
157     pattern->SetMovingHandleOffset(movingHandleOffsetF);
158 
159     float x = localOffset.GetX();
160     float handleHeight = IsSingleHandle() ? pattern->CalculateCaretOffsetAndHeight().second : handleRect.Height();
161     float y = localOffset.GetY() + handleRect.Height() - handleHeight / 2; // 2: Half the height of the handle
162     auto magnifierLocalOffset = OffsetF(x, y);
163     GetLocalPointWithTransform(magnifierLocalOffset); // do affine transformation
164     pattern->magnifierController_->SetLocalOffset(magnifierLocalOffset);
165 
166     if (isFirst) {
167         pattern->textSelector_.firstHandle.SetOffset(localOffset);
168     } else {
169         pattern->textSelector_.secondHandle.SetOffset(localOffset);
170     }
171     AutoScrollParam param = { .autoScrollEvent = AutoScrollEvent::HANDLE,
172         .handleRect = handleRect,
173         .isFirstHandle = isFirst,
174         .showScrollbar = true };
175     pattern->AutoScrollByEdgeDetection(param, localOffset, EdgeDetectionStrategy::OUT_BOUNDARY);
176 }
177 
GetLocalPointWithTransform(OffsetF & localPoint)178 void RichEditorSelectOverlay::GetLocalPointWithTransform(OffsetF& localPoint)
179 {
180     if (!IsOverlayMode()) {
181         return;
182     }
183     BaseTextSelectOverlay::GetLocalPointWithTransform(localPoint);
184 }
185 
UpdateSelectorOnHandleMove(const OffsetF & handleOffset,bool isFirst)186 void RichEditorSelectOverlay::UpdateSelectorOnHandleMove(const OffsetF& handleOffset, bool isFirst)
187 {
188     auto pattern = GetPattern<RichEditorPattern>();
189     auto& textSelector = pattern->textSelector_;
190     auto currentHandleIndex = pattern->GetHandleIndex(Offset(handleOffset.GetX(), handleOffset.GetY()));
191     auto preHandleIndex = isFirst ? textSelector.baseOffset : textSelector.destinationOffset;
192     pattern->StartVibratorByIndexChange(currentHandleIndex, preHandleIndex);
193     pattern->SetCaretPosition(currentHandleIndex);
194     if (isFirst) {
195         pattern->HandleSelectionChange(currentHandleIndex, initSelector_.second);
196     } else {
197         pattern->SetCaretPosition(currentHandleIndex);
198         if (IsSingleHandle()) {
199             auto textOffset = handleOffset + pattern->contentRect_.GetOffset() - pattern->richTextRect_.GetOffset();
200             pattern->CalcAndRecordLastClickCaretInfo(Offset(textOffset.GetX(), textOffset.GetY()));
201             textSelector.Update(currentHandleIndex);
202         } else {
203             pattern->HandleSelectionChange(initSelector_.first, currentHandleIndex);
204         }
205     }
206 }
207 
OnHandleMoveDone(const RectF & handleRect,bool isFirstHandle)208 void RichEditorSelectOverlay::OnHandleMoveDone(const RectF& handleRect, bool isFirstHandle)
209 {
210     isHandleMoving_ = false;
211     auto pattern = GetPattern<RichEditorPattern>();
212     CHECK_NULL_VOID(pattern);
213     TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "handleRect=%{public}s, isFirstHandle=%{public}d",
214         handleRect.ToString().c_str(), isFirstHandle);
215     auto host = pattern->GetHost();
216     CHECK_NULL_VOID(host);
217     auto& textSelector = pattern->textSelector_;
218     auto selectStart = std::min(textSelector.baseOffset, textSelector.destinationOffset);
219     auto selectEnd = std::max(textSelector.baseOffset, textSelector.destinationOffset);
220     pattern->FireOnSelect(selectStart, selectEnd);
221     if (!IsSingleHandle()) {
222         pattern->SetCaretPositionWithAffinity({ selectEnd, TextAffinity::UPSTREAM });
223     }
224     pattern->StopAutoScroll();
225     pattern->magnifierController_->RemoveMagnifierFrameNode();
226     if (!IsSingleHandle() && textSelector.StartEqualToDest()) {
227         HideMenu();
228         CloseOverlay(true, CloseReason::CLOSE_REASON_NORMAL);
229         IF_TRUE(pattern->IsEditing(), pattern->StartTwinkling());
230         return;
231     }
232     auto overlayManager = GetManager<SelectContentOverlayManager>();
233     CHECK_NULL_VOID(overlayManager);
234     overlayManager->SetHandleCircleIsShow(isFirstHandle, true);
235     if (!isFirstHandle && IsSingleHandle()) {
236         overlayManager->SetIsHandleLineShow(true);
237         SwitchCaretState();
238     }
239     pattern->CalculateHandleOffsetAndShowOverlay();
240     overlayManager->MarkInfoChange((isFirstHandle ? DIRTY_FIRST_HANDLE : DIRTY_SECOND_HANDLE) | DIRTY_SELECT_AREA |
241                             DIRTY_SELECT_TEXT | DIRTY_COPY_ALL_ITEM);
242     ProcessOverlay({ .animation = true });
243     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
244 }
245 
GetSelectedText()246 std::string RichEditorSelectOverlay::GetSelectedText()
247 {
248     return TextSelectOverlay::GetSelectedText();
249 }
250 
GetSelectArea()251 RectF RichEditorSelectOverlay::GetSelectArea()
252 {
253     auto pattern = GetPattern<RichEditorPattern>();
254     CHECK_NULL_RETURN(pattern, {});
255     auto intersectRect = pattern->GetSelectArea();
256 
257     if (hasTransform_) {
258         auto textPaintOffset = GetPaintOffsetWithoutTransform();
259         intersectRect.SetOffset(intersectRect.GetOffset() - textPaintOffset);
260         GetGlobalRectWithTransform(intersectRect);
261     }
262     return intersectRect;
263 }
264 
OnUpdateMenuInfo(SelectMenuInfo & menuInfo,SelectOverlayDirtyFlag dirtyFlag)265 void RichEditorSelectOverlay::OnUpdateMenuInfo(SelectMenuInfo& menuInfo, SelectOverlayDirtyFlag dirtyFlag)
266 {
267     auto pattern = GetPattern<RichEditorPattern>();
268     CHECK_NULL_VOID(pattern);
269     auto hasValue = pattern->GetTextContentLength() > 0;
270     menuInfo.showCopyAll = !pattern->IsSelectAll() && hasValue;
271     if (dirtyFlag == DIRTY_COPY_ALL_ITEM) {
272         return;
273     }
274     bool isShowItem = pattern->copyOption_ != CopyOptions::None;
275     menuInfo.showCopy = isShowItem && hasValue && !pattern->textSelector_.SelectNothing();
276     menuInfo.showCut = isShowItem && hasValue && !pattern->textSelector_.SelectNothing();
277     menuInfo.showPaste = IsShowPaste();
278     menuInfo.menuIsShow = IsShowMenu();
279     menuInfo.showAIWrite = pattern->IsShowAIWrite() && hasValue;
280     pattern->UpdateSelectMenuInfo(menuInfo);
281 }
282 
283 // param filling except callback
OnUpdateSelectOverlayInfo(SelectOverlayInfo & selectInfo,int32_t requestCode)284 void RichEditorSelectOverlay::OnUpdateSelectOverlayInfo(SelectOverlayInfo& selectInfo, int32_t requestCode)
285 {
286     auto pattern = GetPattern<RichEditorPattern>();
287     CHECK_NULL_VOID(pattern);
288     BaseTextSelectOverlay::OnUpdateSelectOverlayInfo(selectInfo, requestCode);
289     selectInfo.pattern = AceType::WeakClaim(AceType::RawPtr(pattern));
290     selectInfo.handlerColor = pattern->GetCaretColor();
291     selectInfo.handleReverse = IsHandleReverse();
292     OnUpdateOnCreateMenuCallback(selectInfo);
293     bool usingMouse = pattern->IsUsingMouse();
294     auto responseType = pattern->textResponseType_.value_or(TextResponseType::NONE);
295     auto& firstHandle = pattern->textSelector_.firstHandle;
296     auto& secondHandle = pattern->textSelector_.secondHandle;
297     if (usingMouse && pattern->sourceType_ == SourceType::MOUSE) {
298         if (responseType == TextResponseType::LONG_PRESS) {
299             pattern->SetTextResponseType(TextResponseType::RIGHT_CLICK);
300             responseType = TextResponseType::RIGHT_CLICK;
301         }
302         selectInfo.isUsingMouse = true;
303         selectInfo.rightClickOffset = pattern->GetSelectionMenuOffset();
304         pattern->ResetIsMousePressed();
305     } else {
306         selectInfo.firstHandle.paintRect = firstHandle;
307         selectInfo.secondHandle.paintRect = secondHandle;
308     }
309     selectInfo.menuInfo.responseType = static_cast<int32_t>(responseType);
310     selectInfo.menuInfo.editorType = static_cast<int32_t>(pattern->GetEditorType());
311     selectInfo.callerFrameNode = pattern->GetHost();
312     selectInfo.isNewAvoid = true;
313     selectInfo.selectArea = GetSelectArea();
314     selectInfo.checkIsTouchInHostArea =
315     [weak = AceType::WeakClaim(AceType::RawPtr(pattern))](const PointF& touchPoint) -> bool {
316         auto pattern = weak.Upgrade();
317         CHECK_NULL_RETURN(pattern, false);
318         return pattern->IsTouchInFrameArea(touchPoint);
319     };
320     selectInfo.isSingleHandle = IsSingleHandle();
321     selectInfo.recreateOverlay = requestCode == REQUEST_RECREATE;
322     CheckMenuParamChange(selectInfo, pattern->GetEditorType(), responseType);
323     pattern->CopySelectionMenuParams(selectInfo, responseType);
324     if (hasTransform_) {
325         selectInfo.callerNodeInfo = {
326             .paintFrameRect = GetPaintRectWithTransform(),
327             .paintOffset = GetPaintRectOffsetWithTransform()
328         };
329     }
330 }
CheckMenuParamChange(SelectOverlayInfo & selectInfo,TextSpanType selectType,TextResponseType responseType)331 void RichEditorSelectOverlay::CheckMenuParamChange(SelectOverlayInfo& selectInfo,
332     TextSpanType selectType, TextResponseType responseType)
333 {
334     auto pattern = GetPattern<RichEditorPattern>();
335     auto menuParams = pattern ? pattern->GetMenuParams(selectType, responseType) : nullptr;
336     std::pair<TextSpanType, TextResponseType> selectResponseComb = { selectType, responseType };
337     selectInfo.recreateOverlay |= (lastMenuParams_ || menuParams) && selectResponseComb != lastSelectResponseComb_;
338     lastMenuParams_ = menuParams;
339     lastSelectResponseComb_ = selectResponseComb;
340 }
341 
342 // set menu callback
OnMenuItemAction(OptionMenuActionId id,OptionMenuType type)343 void RichEditorSelectOverlay::OnMenuItemAction(OptionMenuActionId id, OptionMenuType type)
344 {
345     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "MenuActionId=%{public}d, MenuType=%{public}d", id, type);
346     auto pattern = GetPattern<RichEditorPattern>();
347     CHECK_NULL_VOID(pattern);
348     auto usingMouse = pattern->IsUsingMouse();
349     switch (id) {
350         case OptionMenuActionId::COPY:
351             needRefreshMenu_ = !IsShowPaste() && pattern->copyOption_ != CopyOptions::None;
352             pattern->HandleOnCopy();
353             break;
354         case OptionMenuActionId::CUT:
355             pattern->HandleOnCut();
356             break;
357         case OptionMenuActionId::PASTE:
358             pattern->HandleOnPaste();
359             CloseOverlay(true, CloseReason::CLOSE_REASON_NORMAL);
360             break;
361         case OptionMenuActionId::SELECT_ALL:
362             pattern->isMousePressed_ = usingMouse;
363             pattern->HandleMenuCallbackOnSelectAll();
364             break;
365         case OptionMenuActionId::CAMERA_INPUT:
366             pattern->HandleOnCameraInput();
367             break;
368         case OptionMenuActionId::AI_WRITE:
369             pattern->HandleOnAIWrite();
370             break;
371         case OptionMenuActionId::DISAPPEAR:
372             if (pattern->GetTextDetectEnable() && !pattern->HasFocus()) {
373                 pattern->ResetSelection();
374             }
375             break;
376         default:
377             TAG_LOGI(AceLogTag::ACE_TEXT, "Unsupported menu option id %{public}d", id);
378             break;
379     }
380 }
381 
ToggleMenu()382 void RichEditorSelectOverlay::ToggleMenu()
383 {
384     auto manager = GetManager<SelectContentOverlayManager>();
385     if (manager && !manager->IsMenuShow() && needRefreshMenu_) {
386         needRefreshMenu_ = false;
387         ProcessOverlay({ .menuIsShow = true, .animation = true, .requestCode = REQUEST_RECREATE });
388         return;
389     }
390     BaseTextSelectOverlay::ToggleMenu();
391 }
392 
OnCloseOverlay(OptionMenuType menuType,CloseReason reason,RefPtr<OverlayInfo> info)393 void RichEditorSelectOverlay::OnCloseOverlay(OptionMenuType menuType, CloseReason reason, RefPtr<OverlayInfo> info)
394 {
395     TAG_LOGD(AceLogTag::ACE_TEXT, "menuType=%{public}d, closeReason=%{public}d", menuType, reason);
396     auto pattern = GetPattern<RichEditorPattern>();
397     CHECK_NULL_VOID(pattern);
398     BaseTextSelectOverlay::OnCloseOverlay(menuType, reason, info);
399     isHandleMoving_ = false;
400     auto needResetSelection = pattern->GetTextDetectEnable() && !pattern->HasFocus() &&
401         reason != CloseReason::CLOSE_REASON_DRAG_FLOATING;
402     auto isBackPressed = reason == CloseReason::CLOSE_REASON_BACK_PRESSED;
403     auto isHoldByOther = reason == CloseReason::CLOSE_REASON_HOLD_BY_OTHER;
404     needResetSelection = needResetSelection || isBackPressed || isHoldByOther;
405     IF_TRUE(needResetSelection, pattern->ResetSelection());
406     IF_TRUE(isHoldByOther, pattern->CloseSelectOverlay());
407     if (isBackPressed) {
408         if (pattern->IsEditing()) {
409             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "only show caret for edit state");
410             pattern->isCursorAlwaysDisplayed_ = false;
411             pattern->StartTwinkling();
412         }
413     }
414 }
415 
OnHandleGlobalTouchEvent(SourceType sourceType,TouchType touchType,bool touchInside)416 void RichEditorSelectOverlay::OnHandleGlobalTouchEvent(SourceType sourceType, TouchType touchType, bool touchInside)
417 {
418     BaseTextSelectOverlay::OnHandleGlobalTouchEvent(sourceType, touchType);
419 }
420 
OnHandleLevelModeChanged(HandleLevelMode mode)421 void RichEditorSelectOverlay::OnHandleLevelModeChanged(HandleLevelMode mode)
422 {
423     if (handleLevelMode_ != mode && mode == HandleLevelMode::OVERLAY) {
424         auto pattern = GetPattern<RichEditorPattern>();
425         CHECK_NULL_VOID(pattern);
426         pattern->CalculateHandleOffsetAndShowOverlay();
427     }
428     BaseTextSelectOverlay::OnHandleLevelModeChanged(mode);
429 }
430 
GetSelectOverlayInfo()431 std::optional<SelectOverlayInfo> RichEditorSelectOverlay::GetSelectOverlayInfo()
432 {
433     auto manager = GetManager<SelectContentOverlayManager>();
434     CHECK_NULL_RETURN(manager, std::optional<SelectOverlayInfo>());
435     return manager->GetSelectOverlayInfo();
436 }
437 
IsSingleHandleShow()438 bool RichEditorSelectOverlay::IsSingleHandleShow()
439 {
440     auto manager = GetManager<SelectContentOverlayManager>();
441     CHECK_NULL_RETURN(manager && manager->IsSingleHandle(), false);
442     auto overlayInfo = manager->GetSelectOverlayInfo();
443     CHECK_NULL_RETURN(overlayInfo, false);
444     return overlayInfo->secondHandle.isShow;
445 }
446 
UpdateMenuOffset()447 void RichEditorSelectOverlay::UpdateMenuOffset()
448 {
449     auto manager = GetManager<SelectContentOverlayManager>();
450     CHECK_NULL_VOID(manager);
451     manager->MarkInfoChange(DIRTY_SELECT_AREA | DIRTY_ALL_MENU_ITEM);
452 }
453 
IsBothHandlesShow()454 bool RichEditorSelectOverlay::IsBothHandlesShow()
455 {
456     auto manager = GetManager<SelectContentOverlayManager>();
457     CHECK_NULL_RETURN(manager && manager->IsHandlesShow(), false);
458     auto overlayInfo = manager->GetSelectOverlayInfo();
459     CHECK_NULL_RETURN(overlayInfo, false);
460     return overlayInfo->firstHandle.isShow && overlayInfo->secondHandle.isShow;
461 }
462 
IsHandleShow()463 bool RichEditorSelectOverlay::IsHandleShow()
464 {
465     return IsBothHandlesShow() || IsSingleHandleShow();
466 }
467 
OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)468 void RichEditorSelectOverlay::OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)
469 {
470     if (IsAncestorNodeGeometryChange(flag)) {
471         UpdateAllHandlesOffset();
472     }
473     BaseTextSelectOverlay::OnAncestorNodeChanged(flag);
474 }
475 
OnHandleMoveStart(const GestureEvent & event,bool isFirst)476 void RichEditorSelectOverlay::OnHandleMoveStart(const GestureEvent& event, bool isFirst)
477 {
478     isHandleMoving_ = true;
479     auto pattern = GetPattern<RichEditorPattern>();
480     CHECK_NULL_VOID(pattern);
481     initSelector_ = { pattern->textSelector_.GetTextStart(), pattern->textSelector_.GetTextEnd() };
482     pattern->ChangeHandleHeight(event, isFirst, IsOverlayMode());
483     auto manager = GetManager<SelectContentOverlayManager>();
484     CHECK_NULL_VOID(manager);
485     manager->MarkInfoChange(isFirst ? DIRTY_FIRST_HANDLE : DIRTY_SECOND_HANDLE);
486     manager->SetHandleCircleIsShow(isFirst, false);
487     if (IsSingleHandle()) {
488         pattern->ShowCaretWithoutTwinkling();
489         manager->SetIsHandleLineShow(false);
490     }
491 }
492 
OnOverlayTouchDown(const TouchEventInfo & event)493 void RichEditorSelectOverlay::OnOverlayTouchDown(const TouchEventInfo& event)
494 {
495     auto pattern = GetPattern<RichEditorPattern>();
496     CHECK_NULL_VOID(pattern);
497     if (event.GetSourceTool() == SourceTool::MOUSE && IsHandleShow()) {
498         pattern->CloseSelectOverlay();
499     }
500     pattern->RequestFocusWhenSelected();
501 }
502 
UpdateHandleOffset()503 void RichEditorSelectOverlay::UpdateHandleOffset()
504 {
505     auto manager = GetManager<SelectContentOverlayManager>();
506     CHECK_NULL_VOID(manager);
507     manager->MarkInfoChange(DIRTY_FIRST_HANDLE | DIRTY_SECOND_HANDLE);
508 }
509 
UpdateSelectOverlayOnAreaChanged()510 void RichEditorSelectOverlay::UpdateSelectOverlayOnAreaChanged()
511 {
512     CHECK_NULL_VOID(SelectOverlayIsOn() || SelectOverlayIsCreating());
513     auto pattern = GetPattern<RichEditorPattern>();
514     CHECK_NULL_VOID(pattern);
515     pattern->CalculateHandleOffsetAndShowOverlay();
516     UpdateHandleOffset();
517     SwitchCaretState();
518 }
519 
SwitchCaretState()520 void RichEditorSelectOverlay::SwitchCaretState()
521 {
522     CHECK_NULL_VOID(IsSingleHandle() && !isHandleMoving_);
523     auto pattern = GetPattern<RichEditorPattern>();
524     CHECK_NULL_VOID(pattern);
525     auto singleHandlePaintRect = pattern->textSelector_.secondHandle;
526     bool isSingleHandleShow = !handleIsHidden_ && CheckHandleVisible(singleHandlePaintRect);
527     bool isCaretTwinkling = pattern->caretTwinkling_;
528     CHECK_NULL_VOID(isSingleHandleShow == isCaretTwinkling);
529     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Switch caret state singleHandleShow=%{public}d", isSingleHandleShow);
530     if (isSingleHandleShow) {
531         pattern->StopTwinkling();
532     } else {
533         pattern->isCursorAlwaysDisplayed_ = false;
534         pattern->StartTwinkling();
535     }
536 }
537 
OnHandleIsHidden()538 void RichEditorSelectOverlay::OnHandleIsHidden()
539 {
540     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "Start twinking when singleHandle hide");
541     auto pattern = GetPattern<RichEditorPattern>();
542     CHECK_NULL_VOID(pattern);
543     pattern->isCursorAlwaysDisplayed_ = false;
544     pattern->StartTwinkling();
545     handleIsHidden_ = true;
546 }
547 
OnOverlayClick(const GestureEvent & event,bool isFirst)548 void RichEditorSelectOverlay::OnOverlayClick(const GestureEvent& event, bool isFirst)
549 {
550     auto pattern = GetPattern<RichEditorPattern>();
551     CHECK_NULL_VOID(pattern);
552     if (!pattern->IsEditing() && !IsSingleHandle()) {
553         ToggleMenu();
554     }
555     auto globalOffset = pattern->GetGlobalOffset();
556     auto overlayEvent = event;
557     auto localLocation = Offset(overlayEvent.GetGlobalLocation().GetX() - globalOffset.GetX(),
558         overlayEvent.GetGlobalLocation().GetY() - globalOffset.GetY());
559     overlayEvent.SetLocalLocation(localLocation);
560     pattern->HandleClickEvent(overlayEvent);
561 }
562 
OnHandleMouseEvent(const MouseInfo & event)563 void RichEditorSelectOverlay::OnHandleMouseEvent(const MouseInfo& event)
564 {
565     auto pattern = GetPattern<RichEditorPattern>();
566     CHECK_NULL_VOID(pattern);
567     if (event.GetAction() == MouseAction::PRESS && IsHandleShow()) {
568         pattern->CloseSelectOverlay();
569     }
570 }
571 
OnAfterSelectOverlayShow(bool isCreate)572 void RichEditorSelectOverlay::OnAfterSelectOverlayShow(bool isCreate)
573 {
574     handleIsHidden_ = false;
575     auto manager = GetManager<SelectContentOverlayManager>();
576     CHECK_NULL_VOID(manager);
577     manager->MarkInfoChange(DIRTY_SELECT_AREA);
578     if (IsSingleHandleShow()) {
579         auto pattern = GetPattern<RichEditorPattern>();
580         CHECK_NULL_VOID(pattern);
581         pattern->StopTwinkling();
582     }
583 }
584 
GetHandleHotZoneRadius()585 float RichEditorSelectOverlay::GetHandleHotZoneRadius()
586 {
587     auto hotZoneRadius = 0.0f;
588     auto pattern = GetPattern<RichEditorPattern>();
589     CHECK_NULL_RETURN(pattern, hotZoneRadius);
590     auto host = pattern->GetHost();
591     CHECK_NULL_RETURN(host, hotZoneRadius);
592     auto pipeline = host->GetContext();
593     CHECK_NULL_RETURN(pipeline, hotZoneRadius);
594     auto theme = pipeline->GetTheme<TextOverlayTheme>();
595     CHECK_NULL_RETURN(theme, hotZoneRadius);
596     hotZoneRadius = theme->GetHandleHotZoneRadius().ConvertToPx();
597     return hotZoneRadius;
598 }
599 
OnHandleMarkInfoChange(std::shared_ptr<SelectOverlayInfo> info,SelectOverlayDirtyFlag flag)600 void RichEditorSelectOverlay::OnHandleMarkInfoChange(
601     std::shared_ptr<SelectOverlayInfo> info, SelectOverlayDirtyFlag flag)
602 {
603     CHECK_NULL_VOID((flag & UPDATE_HANDLE_COLOR_FLAG) == UPDATE_HANDLE_COLOR_FLAG);
604     CHECK_NULL_VOID(info);
605 
606     auto manager = GetManager<SelectContentOverlayManager>();
607     CHECK_NULL_VOID(manager);
608     auto pattern = GetPattern<RichEditorPattern>();
609     CHECK_NULL_VOID(pattern);
610     info->handlerColor = pattern->caretColor_;
611     manager->MarkHandleDirtyNode(PROPERTY_UPDATE_RENDER);
612 }
613 
UpdateHandleColor()614 void RichEditorSelectOverlay::UpdateHandleColor()
615 {
616     auto manager = GetManager<SelectContentOverlayManager>();
617     CHECK_NULL_VOID(manager);
618     manager->MarkInfoChange(UPDATE_HANDLE_COLOR_FLAG);
619 }
620 
621 } // namespace OHOS::Ace::NG
622