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/text_field/text_field_select_overlay.h"
17
18 #include <algorithm>
19 #include <cstdint>
20
21 #include "base/geometry/ng/rect_t.h"
22 #include "base/memory/ace_type.h"
23 #include "base/utils/utils.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/text_field/text_field_paint_property.h"
27 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
28 #include "core/event/ace_events.h"
29 #include "core/event/touch_event.h"
30
31 #ifndef ACE_UNITTEST
32 #ifdef ENABLE_STANDARD_INPUT
33 #include "input_method_controller.h"
34 #endif
35 #endif
36
37 namespace OHOS::Ace::NG {
38 namespace {
39 // uncertainty range when comparing selectedTextBox to contentRect
40 constexpr float BOX_EPSILON = 0.5f;
41 constexpr uint32_t REQUEST_SELECT_ALL = 1 << 1;
42 } // namespace
43
PreProcessOverlay(const OverlayRequest & request)44 bool TextFieldSelectOverlay::PreProcessOverlay(const OverlayRequest& request)
45 {
46 auto pattern = GetPattern<TextFieldPattern>();
47 CHECK_NULL_RETURN(pattern, false);
48 auto host = pattern->GetHost();
49 CHECK_NULL_RETURN(host, false);
50 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
51 CHECK_NULL_RETURN(layoutProperty, false);
52 bool isHideRightClickMenu = layoutProperty->GetSelectionMenuHiddenValue(false) && IsUsingMouse();
53 bool isFontSizeZero = layoutProperty->HasFontSize() && NearZero(layoutProperty->GetFontSize()->Value());
54 if (isHideRightClickMenu || isFontSizeZero) {
55 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
56 "The selection menu is not displayed cause Font size is zero or selectionMenuHidden is true");
57 return false;
58 }
59 UpdatePattern(request);
60 CHECK_NULL_RETURN(!pattern->IsTransparent(), false);
61 pattern->ShowSelect();
62 SetEnableHandleLevel(true);
63 return true;
64 }
65
UpdatePattern(const OverlayRequest & request)66 void TextFieldSelectOverlay::UpdatePattern(const OverlayRequest& request)
67 {
68 auto pattern = GetPattern<TextFieldPattern>();
69 CHECK_NULL_VOID(pattern);
70 bool isRequestSelectAll = (static_cast<uint32_t>(request.requestCode) & REQUEST_SELECT_ALL) == REQUEST_SELECT_ALL;
71 auto selectController = pattern->GetTextSelectController();
72 if ((static_cast<uint32_t>(request.requestCode) & REQUEST_SELECT_ALL) != REQUEST_SELECT_ALL) {
73 selectController->CalculateHandleOffset();
74 }
75 if (pattern->IsSelected() && selectController->IsHandleSamePosition()) {
76 SetIsSingleHandle(true);
77 selectController->UpdateCaretIndex(selectController->GetFirstHandleIndex());
78 selectController->UpdateCaretOffset();
79 selectController->MoveCaretToContentRect(selectController->GetCaretIndex());
80 } else if (!IsSingleHandle() && !isRequestSelectAll) {
81 auto rects = pattern->GetTextBoxes();
82 if (!rects.empty() && NearEqual(rects.size(), 1) && NearZero(rects[0].Width())) {
83 SetIsSingleHandle(true);
84 selectController->UpdateCaretIndex(selectController->GetFirstHandleIndex());
85 selectController->UpdateCaretOffset();
86 }
87 }
88 if (IsSingleHandle()) {
89 pattern->StartTwinkling();
90 }
91 }
92
OnAfterSelectOverlayShow(bool isCreate)93 void TextFieldSelectOverlay::OnAfterSelectOverlayShow(bool isCreate)
94 {
95 CHECK_NULL_VOID(latestReqeust_);
96 auto manager = GetManager<SelectContentOverlayManager>();
97 CHECK_NULL_VOID(manager);
98 if (latestReqeust_->hideHandle) {
99 manager->HideHandle();
100 }
101 manager->MarkInfoChange(DIRTY_SELECT_TEXT);
102 latestReqeust_.reset();
103 }
104
OnCloseOverlay(OptionMenuType menuType,CloseReason reason,RefPtr<OverlayInfo> info)105 void TextFieldSelectOverlay::OnCloseOverlay(OptionMenuType menuType, CloseReason reason, RefPtr<OverlayInfo> info)
106 {
107 BaseTextSelectOverlay::OnCloseOverlay(menuType, reason, info);
108 auto pattern = GetPattern<TextFieldPattern>();
109 CHECK_NULL_VOID(pattern);
110 CloseMagnifier();
111 if (CloseReason::CLOSE_REASON_BACK_PRESSED == reason) {
112 OnResetTextSelection();
113 if (info && info->isSingleHandle) {
114 pattern->OnBackPressed();
115 }
116 }
117 }
118
OnHandleGlobalTouchEvent(SourceType sourceType,TouchType touchType,bool touchInside)119 void TextFieldSelectOverlay::OnHandleGlobalTouchEvent(SourceType sourceType, TouchType touchType, bool touchInside)
120 {
121 BaseTextSelectOverlay::OnHandleGlobalTouchEvent(sourceType, touchType);
122 SetLastSourceType(sourceType);
123 }
124
HandleOnShowMenu()125 void TextFieldSelectOverlay::HandleOnShowMenu()
126 {
127 auto selectArea = GetSelectArea();
128 if (Negative(selectArea.Width()) || Negative(selectArea.Height())) {
129 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "The selected area is not visible.");
130 return;
131 }
132 if (SelectOverlayIsOn()) {
133 auto manager = GetManager<SelectContentOverlayManager>();
134 manager->ShowOptionMenu();
135 return;
136 }
137 auto pattern = GetPattern<TextFieldPattern>();
138 CHECK_NULL_VOID(pattern);
139 SetUsingMouse(lastSourceType_ == SourceType::MOUSE);
140 if (IsUsingMouse()) {
141 auto controller = pattern->GetTextSelectController();
142 SetMouseMenuOffset(controller->GetCaretRect().GetOffset() + pattern->GetParentGlobalOffset());
143 } else {
144 auto isSingleHandle = pattern->GetTextContentController()->IsEmpty() || !pattern->IsSelected();
145 SetIsSingleHandle(isSingleHandle);
146 }
147 ProcessOverlay({ .animation = true });
148 }
149
GetFirstHandleInfo()150 std::optional<SelectHandleInfo> TextFieldSelectOverlay::GetFirstHandleInfo()
151 {
152 if (IsSingleHandle()) {
153 return std::nullopt;
154 }
155 auto handleRect = GetFirstHandleLocalPaintRect();
156 return GetHandleInfo(handleRect);
157 }
158
GetSecondHandleInfo()159 std::optional<SelectHandleInfo> TextFieldSelectOverlay::GetSecondHandleInfo()
160 {
161 auto handleRect = GetSecondHandleLocalPaintRect();
162 return GetHandleInfo(handleRect);
163 }
164
GetFirstHandleLocalPaintRect()165 RectF TextFieldSelectOverlay::GetFirstHandleLocalPaintRect()
166 {
167 auto pattern = GetPattern<TextFieldPattern>();
168 CHECK_NULL_RETURN(pattern, RectF());
169 auto controller = pattern->GetTextSelectController();
170 CHECK_NULL_RETURN(controller, RectF());
171 return controller->GetFirstHandleRect();
172 }
173
GetSecondHandleLocalPaintRect()174 RectF TextFieldSelectOverlay::GetSecondHandleLocalPaintRect()
175 {
176 auto pattern = GetPattern<TextFieldPattern>();
177 CHECK_NULL_RETURN(pattern, RectF());
178 auto controller = pattern->GetTextSelectController();
179 CHECK_NULL_RETURN(controller, RectF());
180 if (IsSingleHandle()) {
181 return controller->GetCaretRect();
182 }
183 auto handleRect = controller->GetSecondHandleRect();
184 auto contentHeight = pattern->GetTextContentRect().Height();
185 auto handleHeight = std::min(handleRect.Height(), contentHeight);
186 handleRect.SetHeight(handleHeight);
187 return handleRect;
188 }
189
GetHandleInfo(const RectF & handlePaintRect)190 std::optional<SelectHandleInfo> TextFieldSelectOverlay::GetHandleInfo(const RectF& handlePaintRect)
191 {
192 auto handleRect = handlePaintRect;
193 SelectHandleInfo handleInfo;
194 handleInfo.localPaintRect = handlePaintRect;
195 handleRect.SetOffset(handleRect.GetOffset() + GetPaintOffsetWithoutTransform());
196 handleInfo.paintRect = handleRect;
197 handleInfo.isShow = CheckHandleVisible(handleRect);
198
199 SetTransformPaintInfo(handleInfo, handlePaintRect);
200 return handleInfo;
201 }
202
CheckHandleVisible(const RectF & handlePaintRect)203 bool TextFieldSelectOverlay::CheckHandleVisible(const RectF& handlePaintRect)
204 {
205 auto pattern = GetPattern<TextFieldPattern>();
206 CHECK_NULL_RETURN(pattern, false);
207 // use global offset.
208 auto contentRect = pattern->GetContentRect();
209 auto visibleRect = GetVisibleContentRect();
210 // revert to original offset.
211 auto paintRect = handlePaintRect;
212 paintRect.SetOffset(OffsetF(paintRect.GetX() + paintRect.Width() / 2.0f, paintRect.GetY()));
213 if (!pattern->IsTextArea()) {
214 auto verticalEpsilon = std::max(0.0f, paintRect.Height() - contentRect.Height());
215 return GreatOrEqual(paintRect.Top() + verticalEpsilon, visibleRect.Top()) &&
216 LessOrEqual(paintRect.Bottom() - verticalEpsilon, visibleRect.Bottom()) &&
217 LessOrEqual(paintRect.Left() - paintRect.Width() - BOX_EPSILON, visibleRect.Right()) &&
218 GreatOrEqual(paintRect.Right(), visibleRect.Left());
219 }
220 PointF bottomPoint = { paintRect.Left(), paintRect.Bottom() - BOX_EPSILON };
221 PointF topPoint = { paintRect.Left(), paintRect.Top() + BOX_EPSILON };
222 visibleRect.SetLeft(visibleRect.GetX() - BOX_EPSILON);
223 visibleRect.SetWidth(visibleRect.Width() + 2.0f * BOX_EPSILON);
224 visibleRect.SetTop(visibleRect.GetY() - BOX_EPSILON);
225 visibleRect.SetHeight(visibleRect.Height() + 2.0f * BOX_EPSILON);
226 return visibleRect.IsInRegion(bottomPoint) && visibleRect.IsInRegion(topPoint);
227 }
228
OnResetTextSelection()229 void TextFieldSelectOverlay::OnResetTextSelection()
230 {
231 auto pattern = GetPattern<TextFieldPattern>();
232 CHECK_NULL_VOID(pattern);
233 pattern->SetCaretPosition(pattern->GetTextSelectController()->GetEndIndex());
234 }
235
AfterCloseOverlay()236 void TextFieldSelectOverlay::AfterCloseOverlay()
237 {
238 CloseMagnifier();
239 }
240
CloseMagnifier()241 void TextFieldSelectOverlay::CloseMagnifier()
242 {
243 auto pattern = GetPattern<TextFieldPattern>();
244 CHECK_NULL_VOID(pattern);
245 if (pattern->GetMagnifierController()->GetShowMagnifier()) {
246 pattern->GetMagnifierController()->RemoveMagnifierFrameNode();
247 }
248 }
249
OnUpdateMenuInfo(SelectMenuInfo & menuInfo,SelectOverlayDirtyFlag dirtyFlag)250 void TextFieldSelectOverlay::OnUpdateMenuInfo(SelectMenuInfo& menuInfo, SelectOverlayDirtyFlag dirtyFlag)
251 {
252 auto pattern = GetPattern<TextFieldPattern>();
253 CHECK_NULL_VOID(pattern);
254 auto host = pattern->GetHost();
255 CHECK_NULL_VOID(host);
256 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
257 CHECK_NULL_VOID(layoutProperty);
258 auto hasText = pattern->IsOperation();
259 if ((dirtyFlag & DIRTY_COPY_ALL_ITEM) == DIRTY_COPY_ALL_ITEM) {
260 menuInfo.showCopyAll = hasText && !pattern->IsSelectAll();
261 return;
262 }
263 bool isHideSelectionMenu = layoutProperty->GetSelectionMenuHiddenValue(false);
264 #if defined(ENABLE_STANDARD_INPUT)
265 auto inputMethod = MiscServices::InputMethodController::GetInstance();
266 auto isSupportCameraInput = inputMethod &&
267 inputMethod->IsInputTypeSupported(MiscServices::InputType::CAMERA_INPUT) &&
268 !pattern->IsInPasswordMode();
269 #else
270 auto isSupportCameraInput = false;
271 #endif
272 menuInfo.showCameraInput = !pattern->IsSelected() && isSupportCameraInput && !pattern->HasCustomKeyboard();
273 if (IsUsingMouse()) {
274 auto manager = SelectContentOverlayManager::GetOverlayManager();
275 CHECK_NULL_VOID(manager);
276 menuInfo.menuIsShow = !isHideSelectionMenu || manager->IsOpen();
277 } else {
278 menuInfo.menuIsShow = (hasText || IsShowPaste() || menuInfo.showCameraInput) &&
279 !isHideSelectionMenu && IsShowMenu();
280 }
281 menuInfo.menuDisable = isHideSelectionMenu;
282 menuInfo.showPaste = IsShowPaste();
283 menuInfo.menuType = IsUsingMouse() ? OptionMenuType::MOUSE_MENU : OptionMenuType::TOUCH_MENU;
284 menuInfo.showCopy = hasText && pattern->AllowCopy() && pattern->IsSelected();
285 menuInfo.showCut = menuInfo.showCopy;
286 menuInfo.showCopyAll = hasText && !pattern->IsSelectAll();
287 menuInfo.showAIWrite = pattern->IsShowAIWrite() && pattern->IsSelected();
288 }
289
OnUpdateSelectOverlayInfo(SelectOverlayInfo & overlayInfo,int32_t requestCode)290 void TextFieldSelectOverlay::OnUpdateSelectOverlayInfo(SelectOverlayInfo& overlayInfo, int32_t requestCode)
291 {
292 overlayInfo.clipHandleDrawRect = IsClipHandleWithViewPort();
293 BaseTextSelectOverlay::OnUpdateSelectOverlayInfo(overlayInfo, requestCode);
294 auto textFieldPattern = GetPattern<TextFieldPattern>();
295 CHECK_NULL_VOID(textFieldPattern);
296 auto paintProperty = textFieldPattern->GetPaintProperty<TextFieldPaintProperty>();
297 CHECK_NULL_VOID(paintProperty);
298 overlayInfo.handlerColor = paintProperty->GetCursorColor();
299 OnUpdateOnCreateMenuCallback(overlayInfo);
300 auto layoutProperty =
301 DynamicCast<TextFieldLayoutProperty>(textFieldPattern->GetLayoutProperty<TextFieldLayoutProperty>());
302 CHECK_NULL_VOID(layoutProperty);
303 if (layoutProperty->HasMaxLines()) {
304 uint32_t maxLine = layoutProperty->GetMaxLinesValue(Infinity<uint32_t>());
305 if (1 == maxLine) {
306 overlayInfo.isSingleLine = true;
307 }
308 }
309 }
310
GetSelectArea()311 RectF TextFieldSelectOverlay::GetSelectArea()
312 {
313 auto pattern = GetPattern<TextFieldPattern>();
314 CHECK_NULL_RETURN(pattern, {});
315 auto host = pattern->GetHost();
316 CHECK_NULL_RETURN(host, {});
317 auto selectRects = pattern->GetTextBoxes();
318 RectF res(pattern->GetCaretRect());
319 auto textPaintOffset = host->GetTransformRelativeOffset();
320 if (selectRects.empty()) {
321 res.SetOffset(res.GetOffset() + textPaintOffset);
322 } else {
323 auto contentRect = pattern->GetContentRect();
324 auto textRect = pattern->GetTextRect();
325 res = MergeSelectedBoxes(selectRects, contentRect, textRect, textPaintOffset);
326 }
327 auto globalContentRect = GetVisibleContentRect();
328 auto intersectRect = res.IntersectRectT(globalContentRect);
329 if (hasTransform_) {
330 intersectRect.SetOffset(intersectRect.GetOffset() - textPaintOffset);
331 GetGlobalRectWithTransform(intersectRect);
332 }
333 ApplySelectAreaWithKeyboard(intersectRect);
334 return intersectRect;
335 }
336
GetSelectedText()337 std::string TextFieldSelectOverlay::GetSelectedText()
338 {
339 auto pattern = GetPattern<TextFieldPattern>();
340 CHECK_NULL_RETURN(pattern, "");
341 auto start = pattern->GetTextSelectController()->GetStartIndex();
342 auto end = pattern->GetTextSelectController()->GetEndIndex();
343 return pattern->GetTextContentController()->GetSelectedValue(start, end);
344 }
345
OnMenuItemAction(OptionMenuActionId id,OptionMenuType type)346 void TextFieldSelectOverlay::OnMenuItemAction(OptionMenuActionId id, OptionMenuType type)
347 {
348 auto pattern = GetPattern<TextFieldPattern>();
349 CHECK_NULL_VOID(pattern);
350 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Handle overlay menu, men id %{public}d, menu type %{public}d", id, type);
351 switch (id) {
352 case OptionMenuActionId::COPY:
353 pattern->HandleOnCopy();
354 return;
355 case OptionMenuActionId::CUT:
356 pattern->HandleOnCut();
357 return;
358 case OptionMenuActionId::SELECT_ALL:
359 pattern->HandleOnSelectAll(type == OptionMenuType::MOUSE_MENU, false, true);
360 return;
361 case OptionMenuActionId::PASTE:
362 pattern->HandleOnPaste();
363 return;
364 case OptionMenuActionId::CAMERA_INPUT:
365 pattern->HandleOnCameraInput();
366 return;
367 case OptionMenuActionId::AI_WRITE:
368 pattern->HandleOnAIWrite();
369 return;
370 default:
371 return;
372 }
373 }
374
GetTextAreaCaretPosition(const OffsetF & localOffset)375 int32_t TextFieldSelectOverlay::GetTextAreaCaretPosition(const OffsetF& localOffset)
376 {
377 auto pattern = GetPattern<TextFieldPattern>();
378 auto contentRect = pattern->GetContentRect();
379 auto paddingLeft = pattern->GetPaddingLeft();
380 auto textRect = pattern->GetTextRect();
381 auto lineHeight = pattern->PreferredLineHeight();
382 Offset offset;
383 if (LessNotEqual(localOffset.GetY(), contentRect.GetY())) {
384 offset = Offset(localOffset.GetX() - paddingLeft, localOffset.GetY() - textRect.GetY() - lineHeight);
385 } else if (GreatOrEqual(localOffset.GetY(), contentRect.GetY() + contentRect.Height())) {
386 offset = Offset(localOffset.GetX() - paddingLeft, localOffset.GetY() - textRect.GetY() + lineHeight);
387 } else {
388 offset = Offset(localOffset.GetX() - paddingLeft, localOffset.GetY() - textRect.GetY());
389 }
390 return pattern->ConvertTouchOffsetToCaretPosition(offset);
391 }
392
GetTextInputCaretPosition(const OffsetF & localOffset,bool isFirst)393 int32_t TextFieldSelectOverlay::GetTextInputCaretPosition(const OffsetF& localOffset, bool isFirst)
394 {
395 auto pattern = GetPattern<TextFieldPattern>();
396 auto contentRect = pattern->GetContentRect();
397 auto selectController = pattern->GetTextSelectController();
398 auto wideText = pattern->GetWideText();
399 if (LessNotEqual(localOffset.GetX(), contentRect.GetX())) {
400 auto index = selectController->GetStartIndex();
401 if ((!isFirst && !IsHandleReverse()) || (isFirst && IsHandleReverse())) {
402 index = selectController->GetEndIndex();
403 }
404 auto len = pattern->GetGraphemeClusterLength(wideText, index, true);
405 return std::max(index - len, 0);
406 }
407 if (GreatOrEqual(localOffset.GetX(), contentRect.GetX() + contentRect.Width())) {
408 auto index = selectController->GetEndIndex();
409 if ((isFirst && !IsHandleReverse()) || (!isFirst && IsHandleReverse())) {
410 index = selectController->GetStartIndex();
411 }
412 auto len = pattern->GetGraphemeClusterLength(wideText, index);
413 return std::min(index + len, pattern->GetContentWideTextLength());
414 }
415 Offset offset(localOffset.GetX() - pattern->GetTextRect().GetX(), 0.0f);
416 return pattern->ConvertTouchOffsetToCaretPosition(offset);
417 }
418
GetCaretPositionOnHandleMove(const OffsetF & localOffset,bool isFirst)419 int32_t TextFieldSelectOverlay::GetCaretPositionOnHandleMove(const OffsetF& localOffset, bool isFirst)
420 {
421 auto pattern = GetPattern<TextFieldPattern>();
422 CHECK_NULL_RETURN(pattern, 0);
423 if (pattern->IsTextArea()) {
424 return GetTextAreaCaretPosition(localOffset);
425 }
426 return GetTextInputCaretPosition(localOffset, isFirst);
427 }
428
OnHandleMove(const RectF & handleRect,bool isFirst)429 void TextFieldSelectOverlay::OnHandleMove(const RectF& handleRect, bool isFirst)
430 {
431 auto pattern = GetPattern<TextFieldPattern>();
432 CHECK_NULL_VOID(pattern);
433 CHECK_NULL_VOID(pattern->IsOperation());
434 auto localOffset = handleRect.GetOffset();
435 localOffset.SetY(localOffset.GetY() + handleRect.Height() / 2.0f);
436 if (IsOverlayMode()) {
437 localOffset = localOffset - GetPaintOffsetWithoutTransform();
438 }
439 auto selectController = pattern->GetTextSelectController();
440 CHECK_NULL_VOID(selectController);
441 int32_t startIndex = selectController->GetFirstHandleIndex();
442 int32_t endIndex = selectController->GetSecondHandleIndex();
443 if (pattern->GetMagnifierController() && SelectOverlayIsOn()) {
444 auto magnifierLocalOffsetY = localOffset.GetY();
445 auto magnifierLocalOffset = OffsetF(localOffset.GetX(), magnifierLocalOffsetY);
446 if (IsOverlayMode()) {
447 GetLocalPointWithTransform(magnifierLocalOffset);
448 }
449 pattern->GetMagnifierController()->SetLocalOffset(magnifierLocalOffset);
450 }
451 if (IsSingleHandle()) {
452 int32_t preIndex = selectController->GetCaretIndex();
453 selectController->UpdateCaretInfoByOffset(Offset(localOffset.GetX(), localOffset.GetY()));
454 pattern->ShowCaretAndStopTwinkling();
455 pattern->StartVibratorByIndexChange(selectController->GetCaretIndex(), preIndex);
456 } else {
457 auto position = GetCaretPositionOnHandleMove(localOffset, isFirst);
458 if (isFirst) {
459 pattern->StartVibratorByIndexChange(position, startIndex);
460 selectController->MoveFirstHandleToContentRect(position, false);
461 UpdateSecondHandleOffset();
462 } else {
463 pattern->StartVibratorByIndexChange(position, endIndex);
464 selectController->MoveSecondHandleToContentRect(position, false);
465 UpdateFirstHandleOffset();
466 }
467 }
468 pattern->PlayScrollBarAppearAnimation();
469 auto tmpHost = pattern->GetHost();
470 CHECK_NULL_VOID(tmpHost);
471 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
472 }
473
OnHandleMoveDone(const RectF & rect,bool isFirst)474 void TextFieldSelectOverlay::OnHandleMoveDone(const RectF& rect, bool isFirst)
475 {
476 BaseTextSelectOverlay::OnHandleMoveDone(rect, isFirst);
477 auto pattern = GetPattern<TextFieldPattern>();
478 CHECK_NULL_VOID(pattern);
479 auto host = pattern->GetHost();
480 CHECK_NULL_VOID(host);
481 auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
482 CHECK_NULL_VOID(layoutProperty);
483 auto overlayManager = GetManager<SelectContentOverlayManager>();
484 CHECK_NULL_VOID(overlayManager);
485 if (!layoutProperty->GetSelectionMenuHiddenValue(false)) {
486 overlayManager->MarkInfoChange(DIRTY_COPY_ALL_ITEM);
487 }
488 if (pattern->GetMagnifierController()) {
489 pattern->GetMagnifierController()->RemoveMagnifierFrameNode();
490 }
491 auto selectController = pattern->GetTextSelectController();
492 if (!IsSingleHandle()) {
493 if (selectController->GetFirstHandleIndex() == selectController->GetSecondHandleIndex()) {
494 CloseOverlay(true, CloseReason::CLOSE_REASON_NORMAL);
495 pattern->StartTwinkling();
496 selectController->MoveCaretToContentRect(pattern->GetCaretIndex());
497 } else {
498 overlayManager->MarkInfoChange(DIRTY_DOUBLE_HANDLE | DIRTY_SELECT_AREA | DIRTY_SELECT_TEXT);
499 }
500 } else {
501 pattern->StopTwinkling();
502 overlayManager->MarkInfoChange(DIRTY_SECOND_HANDLE);
503 }
504 overlayManager->ShowOptionMenu();
505 overlayManager->SetHandleCircleIsShow(isFirst, true);
506 if (IsSingleHandle()) {
507 overlayManager->SetIsHandleLineShow(true);
508 }
509 pattern->ScheduleDisappearDelayTask();
510 pattern->UpdateCaretInfoToController();
511 auto tmpHost = pattern->GetHost();
512 CHECK_NULL_VOID(tmpHost);
513 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
514 }
515
ProcessSelectAllOverlay(const OverlayRequest & request)516 void TextFieldSelectOverlay::ProcessSelectAllOverlay(const OverlayRequest& request)
517 {
518 OverlayRequest newRequest = request;
519 newRequest.requestCode = static_cast<uint32_t>(newRequest.requestCode) | REQUEST_SELECT_ALL;
520 ProcessOverlay(newRequest);
521 }
522
OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)523 void TextFieldSelectOverlay::OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)
524 {
525 if (IsAncestorNodeGeometryChange(flag) || IsAncestorNodeTransformChange(flag)) {
526 UpdateAllHandlesOffset();
527 }
528 BaseTextSelectOverlay::OnAncestorNodeChanged(flag);
529 }
530
OnHandleLevelModeChanged(HandleLevelMode mode)531 void TextFieldSelectOverlay::OnHandleLevelModeChanged(HandleLevelMode mode)
532 {
533 if (handleLevelMode_ != mode && mode == HandleLevelMode::OVERLAY) {
534 auto pattern = GetPattern<TextFieldPattern>();
535 if (pattern) {
536 pattern->UpdateParentGlobalOffset();
537 pattern->GetTextSelectController()->CalculateHandleOffset();
538 }
539 }
540 BaseTextSelectOverlay::OnHandleLevelModeChanged(mode);
541 }
542
OnOverlayClick(const GestureEvent & event,bool isFirst)543 void TextFieldSelectOverlay::OnOverlayClick(const GestureEvent& event, bool isFirst)
544 {
545 auto pattern = GetPattern<TextFieldPattern>();
546 CHECK_NULL_VOID(pattern);
547 auto recognizer = pattern->GetMultipleClickRecognizer();
548 CHECK_NULL_VOID(recognizer);
549 if (recognizer->IsRunning() && recognizer->IsValidClick(event)) {
550 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield overlayClick multiple click recognizer is running.");
551 auto overlayEvent = event;
552 overlayEvent.SetLocalLocation(recognizer->GetBeginLocalLocation());
553 overlayEvent.SetGlobalLocation(recognizer->GetBeginGlobalLocation());
554 pattern->HandleClickEvent(overlayEvent);
555 } else if (!IsSingleHandle()) {
556 if (pattern->HandleBetweenSelectedPosition(event)) {
557 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield HandleBetweenSelectedPosition");
558 return;
559 }
560 auto selectController = pattern->GetTextSelectController();
561 auto index = isFirst ? selectController->GetFirstHandleIndex() : selectController->GetSecondHandleIndex();
562 pattern->HandleSetSelection(index, index, false);
563 pattern->StartTwinkling();
564 } else {
565 TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield overlayClick");
566 }
567 }
568
OnHandleIsHidden()569 void TextFieldSelectOverlay::OnHandleIsHidden()
570 {
571 auto pattern = GetPattern<TextFieldPattern>();
572 CHECK_NULL_VOID(pattern);
573 pattern->StartTwinkling();
574 }
575
OnHandleMoveStart(const GestureEvent & event,bool isFirst)576 void TextFieldSelectOverlay::OnHandleMoveStart(const GestureEvent& event, bool isFirst)
577 {
578 BaseTextSelectOverlay::OnHandleMoveStart(event, isFirst);
579 auto manager = GetManager<SelectContentOverlayManager>();
580 CHECK_NULL_VOID(manager);
581 auto pattern = GetPattern<TextFieldPattern>();
582 CHECK_NULL_VOID(pattern);
583 manager->SetHandleCircleIsShow(isFirst, false);
584 if (IsSingleHandle()) {
585 manager->SetIsHandleLineShow(false);
586 if (!pattern->IsOperation()) {
587 pattern->StartTwinkling();
588 }
589 }
590 }
591
GetHandleColor()592 std::optional<Color> TextFieldSelectOverlay::GetHandleColor()
593 {
594 auto textFieldPattern = GetPattern<TextFieldPattern>();
595 CHECK_NULL_RETURN(textFieldPattern, std::nullopt);
596 auto paintProperty = textFieldPattern->GetPaintProperty<TextFieldPaintProperty>();
597 CHECK_NULL_RETURN(paintProperty, std::nullopt);
598 return paintProperty->GetCursorColor();
599 }
600 } // namespace OHOS::Ace::NG
601