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