1 /*
2 * Copyright (c) 2022-2023 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/search/search_pattern.h"
17
18 #include <cstdint>
19
20 #include "base/geometry/rect.h"
21 #include "base/utils/system_properties.h"
22 #include "base/utils/utils.h"
23 #include "core/common/recorder/node_data_cache.h"
24 #include "core/components/search/search_theme.h"
25 #include "core/components_ng/base/view_stack_processor.h"
26 #include "core/components_ng/pattern/button/button_pattern.h"
27 #include "core/components_ng/pattern/image/image_pattern.h"
28 #include "core/components_ng/pattern/search/search_model.h"
29 #include "core/components_ng/pattern/text/text_layout_property.h"
30 #include "core/components_ng/pattern/text/text_pattern.h"
31 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
32
33 namespace OHOS::Ace::NG {
34
35 namespace {
36 constexpr int32_t TEXTFIELD_INDEX = 0;
37 constexpr int32_t IMAGE_INDEX = 1;
38 constexpr int32_t CANCEL_IMAGE_INDEX = 2;
39 constexpr int32_t CANCEL_BUTTON_INDEX = 3;
40 constexpr int32_t BUTTON_INDEX = 4;
41 constexpr int32_t DOUBLE = 2;
42 constexpr int32_t ERROR = -1;
43
44 // The focus state requires an 2vp inner stroke, which should be indented by 1vp when drawn.
45 constexpr Dimension FOCUS_OFFSET = 1.0_vp;
46 constexpr Dimension UP_AND_DOWN_PADDING = 8.0_vp;
47 constexpr float HOVER_OPACITY = 0.05f;
48 constexpr float TOUCH_OPACITY = 0.1f;
49 constexpr int32_t HOVER_TO_TOUCH_DURATION = 100;
50 constexpr int32_t HOVER_DURATION = 250;
51 constexpr int32_t TOUCH_DURATION = 250;
52 } // namespace
53
UpdateChangeEvent(const std::string & value)54 void SearchPattern::UpdateChangeEvent(const std::string& value)
55 {
56 auto frameNode = GetHost();
57 CHECK_NULL_VOID(frameNode);
58 auto buttonHost = AceType::DynamicCast<FrameNode>(frameNode->GetChildAtIndex(CANCEL_BUTTON_INDEX));
59 CHECK_NULL_VOID(buttonHost);
60 auto imageHost = AceType::DynamicCast<FrameNode>(frameNode->GetChildAtIndex(CANCEL_IMAGE_INDEX));
61 CHECK_NULL_VOID(imageHost);
62 auto cancelButtonRenderContext = buttonHost->GetRenderContext();
63 CHECK_NULL_VOID(cancelButtonRenderContext);
64 auto cancelImageRenderContext = imageHost->GetRenderContext();
65 CHECK_NULL_VOID(cancelImageRenderContext);
66 auto layoutProperty = frameNode->GetLayoutProperty<SearchLayoutProperty>();
67 CHECK_NULL_VOID(layoutProperty);
68 auto cancelButtonEvent = buttonHost->GetEventHub<ButtonEventHub>();
69 CHECK_NULL_VOID(cancelButtonEvent);
70 auto imageEvent = imageHost->GetEventHub<ImageEventHub>();
71 CHECK_NULL_VOID(imageEvent);
72
73 auto style = layoutProperty->GetCancelButtonStyle().value_or(CancelButtonStyle::INPUT);
74 if ((style == CancelButtonStyle::CONSTANT) || ((style == CancelButtonStyle::INPUT) && !value.empty())) {
75 cancelButtonRenderContext->UpdateOpacity(1.0);
76 cancelImageRenderContext->UpdateOpacity(1.0);
77 cancelButtonEvent->SetEnabled(true);
78 imageEvent->SetEnabled(true);
79 } else {
80 cancelButtonRenderContext->UpdateOpacity(0.0);
81 cancelImageRenderContext->UpdateOpacity(0.0);
82 cancelButtonEvent->SetEnabled(false);
83 imageEvent->SetEnabled(false);
84 }
85 buttonHost->MarkModifyDone();
86 imageHost->MarkModifyDone();
87 buttonHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
88 imageHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
89 }
90
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig &)91 bool SearchPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& /*config*/)
92 {
93 auto geometryNode = dirty->GetGeometryNode();
94 CHECK_NULL_RETURN(geometryNode, true);
95 searchSize_ = geometryNode->GetContentSize();
96 searchOffset_ = geometryNode->GetContentOffset();
97
98 auto textFieldLayoutWrapper = dirty->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
99 CHECK_NULL_RETURN(textFieldLayoutWrapper, true);
100 auto textFieldGeometryNode = textFieldLayoutWrapper->GetGeometryNode();
101 CHECK_NULL_RETURN(textFieldGeometryNode, true);
102 textFieldOffset_ = textFieldGeometryNode->GetFrameOffset();
103 textFieldSize_ = textFieldGeometryNode->GetFrameSize();
104
105 auto buttonLayoutWrapper = dirty->GetOrCreateChildByIndex(BUTTON_INDEX);
106 CHECK_NULL_RETURN(buttonLayoutWrapper, true);
107 auto buttonGeometryNode = buttonLayoutWrapper->GetGeometryNode();
108 CHECK_NULL_RETURN(buttonGeometryNode, true);
109 buttonOffset_ = buttonGeometryNode->GetFrameOffset();
110
111 auto buttonNode = buttonLayoutWrapper->GetHostNode();
112 CHECK_NULL_RETURN(buttonNode, true);
113 auto searchButtonEvent = buttonNode->GetEventHub<ButtonEventHub>();
114 CHECK_NULL_RETURN(searchButtonEvent, true);
115
116 if (!searchButtonEvent->IsEnabled()) {
117 buttonSize_.Reset();
118 } else {
119 buttonSize_ = buttonGeometryNode->GetFrameSize();
120 }
121
122 auto cancelButtonLayoutWrapper = dirty->GetOrCreateChildByIndex(CANCEL_BUTTON_INDEX);
123 CHECK_NULL_RETURN(cancelButtonLayoutWrapper, true);
124 auto cancelButtonGeometryNode = cancelButtonLayoutWrapper->GetGeometryNode();
125 CHECK_NULL_RETURN(cancelButtonGeometryNode, true);
126
127 auto cancelButtonNode = cancelButtonLayoutWrapper->GetHostNode();
128 CHECK_NULL_RETURN(cancelButtonNode, true);
129 auto cancelButtonEvent = cancelButtonNode->GetEventHub<ButtonEventHub>();
130 CHECK_NULL_RETURN(cancelButtonEvent, true);
131 cancelButtonOffset_ = cancelButtonGeometryNode->GetFrameOffset();
132 if (!cancelButtonEvent->IsEnabled()) {
133 cancelButtonSize_.Reset();
134 } else {
135 cancelButtonSize_ = cancelButtonGeometryNode->GetFrameSize();
136 }
137
138 return true;
139 }
140
OnModifyDone()141 void SearchPattern::OnModifyDone()
142 {
143 Pattern::OnModifyDone();
144 auto host = GetHost();
145 CHECK_NULL_VOID(host);
146 auto layoutProperty = host->GetLayoutProperty<SearchLayoutProperty>();
147 CHECK_NULL_VOID(layoutProperty);
148 if (!layoutProperty->GetMarginProperty()) {
149 MarginProperty margin;
150 margin.top = CalcLength(UP_AND_DOWN_PADDING.ConvertToPx());
151 margin.bottom = CalcLength(UP_AND_DOWN_PADDING.ConvertToPx());
152 layoutProperty->UpdateMargin(margin);
153 }
154
155 HandleBackgroundColor();
156
157 auto searchButton = layoutProperty->GetSearchButton();
158 searchButton_ = searchButton.has_value() ? searchButton->value() : "";
159 InitSearchController();
160 auto imageFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(IMAGE_INDEX));
161 CHECK_NULL_VOID(imageFrameNode);
162 imageFrameNode->MarkModifyDone();
163 auto buttonFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(BUTTON_INDEX));
164 CHECK_NULL_VOID(buttonFrameNode);
165 auto buttonLayoutProperty = buttonFrameNode->GetLayoutProperty<ButtonLayoutProperty>();
166 CHECK_NULL_VOID(buttonLayoutProperty);
167 buttonLayoutProperty->UpdateLabel(searchButton_);
168 buttonLayoutProperty->UpdateTextOverflow(TextOverflow::ELLIPSIS);
169 buttonFrameNode->MarkModifyDone();
170
171 auto searchButtonEvent = buttonFrameNode->GetEventHub<ButtonEventHub>();
172 isSearchButtonEnabled_ = searchButtonEvent->IsEnabled();
173
174 auto cancelButtonFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(CANCEL_BUTTON_INDEX));
175 CHECK_NULL_VOID(cancelButtonFrameNode);
176 auto cancelButtonLayoutProperty = cancelButtonFrameNode->GetLayoutProperty<ButtonLayoutProperty>();
177 CHECK_NULL_VOID(cancelButtonLayoutProperty);
178 cancelButtonLayoutProperty->UpdateLabel("");
179 cancelButtonFrameNode->MarkModifyDone();
180 InitButtonAndImageClickEvent();
181 InitCancelButtonClickEvent();
182 InitTextFieldValueChangeEvent();
183 InitTextFieldDragEvent();
184 InitTextFieldClickEvent();
185 InitButtonMouseAndTouchEvent();
186 HandleTouchableAndHitTestMode();
187 auto focusHub = host->GetFocusHub();
188 CHECK_NULL_VOID(focusHub);
189 InitOnKeyEvent(focusHub);
190 InitFocusEvent(focusHub);
191 InitClickEvent();
192 HandleEnabled();
193 }
194
HandleBackgroundColor()195 void SearchPattern::HandleBackgroundColor()
196 {
197 auto host = GetHost();
198 CHECK_NULL_VOID(host);
199 auto renderContext = host->GetRenderContext();
200 CHECK_NULL_VOID(renderContext);
201 auto textFieldTheme = PipelineBase::GetCurrentContext()->GetTheme<TextFieldTheme>();
202 CHECK_NULL_VOID(textFieldTheme);
203 if (!renderContext->HasBackgroundColor()) {
204 renderContext->UpdateBackgroundColor(textFieldTheme->GetBgColor());
205 }
206 }
207
HandleEnabled()208 void SearchPattern::HandleEnabled()
209 {
210 auto host = GetHost();
211 CHECK_NULL_VOID(host);
212 auto searchEventHub = host->GetEventHub<EventHub>();
213 CHECK_NULL_VOID(searchEventHub);
214 auto textFieldFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(TEXTFIELD_INDEX));
215 CHECK_NULL_VOID(textFieldFrameNode);
216 auto eventHub = textFieldFrameNode->GetEventHub<TextFieldEventHub>();
217 eventHub->SetEnabled(searchEventHub->IsEnabled()? true : false);
218 textFieldFrameNode->MarkModifyDone();
219 }
220
HandleTouchableAndHitTestMode()221 void SearchPattern::HandleTouchableAndHitTestMode()
222 {
223 auto host = GetHost();
224 CHECK_NULL_VOID(host);
225 auto searchEventHub = host->GetEventHub<EventHub>();
226 CHECK_NULL_VOID(searchEventHub);
227 auto searchGestureHub = searchEventHub->GetGestureEventHub();
228 CHECK_NULL_VOID(searchGestureHub);
229 bool searchTouchable = true;
230 HitTestMode searchHitTestMode = HitTestMode::HTMDEFAULT;
231 if (searchGestureHub) {
232 searchTouchable = searchGestureHub->GetTouchable();
233 searchHitTestMode = searchGestureHub->GetHitTestMode();
234 }
235 for (int32_t childIndex = TEXTFIELD_INDEX; childIndex <= BUTTON_INDEX; childIndex++) {
236 auto childFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(childIndex));
237 CHECK_NULL_VOID(childFrameNode);
238 auto childEventHub = childFrameNode->GetEventHub<EventHub>();
239 auto childGestureHub = childEventHub->GetGestureEventHub();
240 CHECK_NULL_VOID(childGestureHub);
241 childGestureHub->SetTouchable(searchTouchable);
242 childGestureHub->SetHitTestMode(searchHitTestMode);
243 childFrameNode->MarkModifyDone();
244 }
245 }
246
InitButtonMouseAndTouchEvent()247 void SearchPattern::InitButtonMouseAndTouchEvent()
248 {
249 InitButtonMouseEvent(searchButtonMouseEvent_, BUTTON_INDEX);
250 InitButtonMouseEvent(cancelButtonMouseEvent_, CANCEL_BUTTON_INDEX);
251 InitButtonTouchEvent(searchButtonTouchListener_, BUTTON_INDEX);
252 InitButtonTouchEvent(cancelButtonTouchListener_, CANCEL_BUTTON_INDEX);
253 }
254
InitTextFieldValueChangeEvent()255 void SearchPattern::InitTextFieldValueChangeEvent()
256 {
257 auto host = GetHost();
258 CHECK_NULL_VOID(host);
259 auto textFieldFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
260 CHECK_NULL_VOID(textFieldFrameNode);
261 auto eventHub = textFieldFrameNode->GetEventHub<TextFieldEventHub>();
262 CHECK_NULL_VOID(eventHub);
263 if (!eventHub->GetOnChange()) {
264 auto searchChangeFunc = [weak = AceType::WeakClaim(this)](const std::string& value) {
265 auto searchPattern = weak.Upgrade();
266 searchPattern->UpdateChangeEvent(value);
267 };
268 eventHub->SetOnChange(std::move(searchChangeFunc));
269 }
270 }
271
InitTextFieldDragEvent()272 void SearchPattern::InitTextFieldDragEvent()
273 {
274 auto host = GetHost();
275 CHECK_NULL_VOID(host);
276 auto searchEventHub = host->GetEventHub<EventHub>();
277 CHECK_NULL_VOID(searchEventHub);
278 auto textFieldFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
279 CHECK_NULL_VOID(textFieldFrameNode);
280 auto textFieldEventHub = textFieldFrameNode->GetEventHub<EventHub>();
281 CHECK_NULL_VOID(textFieldEventHub);
282
283 textFieldFrameNode->SetDragPreview(host->GetDragPreview());
284
285 auto dragStart = searchEventHub->GetOnDragStart();
286 if (dragStart != nullptr) {
287 textFieldEventHub->SetOnDragStart(std::move(dragStart));
288 }
289
290 auto customerDragEnter = searchEventHub->GetCustomerOnDragFunc(DragFuncType::DRAG_ENTER);
291 if (customerDragEnter != nullptr) {
292 textFieldEventHub->SetCustomerOnDragFunc(DragFuncType::DRAG_ENTER, std::move(customerDragEnter));
293 }
294
295 auto customerDragLeave = searchEventHub->GetCustomerOnDragFunc(DragFuncType::DRAG_LEAVE);
296 if (customerDragLeave != nullptr) {
297 textFieldEventHub->SetCustomerOnDragFunc(DragFuncType::DRAG_LEAVE, std::move(customerDragLeave));
298 }
299
300 auto customerDragMove = searchEventHub->GetCustomerOnDragFunc(DragFuncType::DRAG_MOVE);
301 if (customerDragMove != nullptr) {
302 textFieldEventHub->SetCustomerOnDragFunc(DragFuncType::DRAG_MOVE, std::move(customerDragMove));
303 }
304
305 auto customerDragDrop = searchEventHub->GetCustomerOnDragFunc(DragFuncType::DRAG_DROP);
306 if (customerDragDrop != nullptr) {
307 textFieldEventHub->SetCustomerOnDragFunc(DragFuncType::DRAG_DROP, std::move(customerDragDrop));
308 }
309
310 auto customerDragEnd = searchEventHub->GetCustomerOnDragEndFunc();
311 if (customerDragEnd != nullptr) {
312 textFieldEventHub->SetCustomerOnDragFunc(DragFuncType::DRAG_END, std::move(customerDragEnd));
313 }
314
315 searchEventHub->ClearCustomerOnDragFunc();
316 RemoveDragFrameNodeFromManager();
317 }
318
RemoveDragFrameNodeFromManager()319 void SearchPattern::RemoveDragFrameNodeFromManager()
320 {
321 auto frameNode = GetHost();
322 CHECK_NULL_VOID(frameNode);
323 auto context = PipelineContext::GetCurrentContext();
324 CHECK_NULL_VOID(context);
325 auto dragDropManager = context->GetDragDropManager();
326 CHECK_NULL_VOID(dragDropManager);
327 dragDropManager->RemoveDragFrameNode(frameNode->GetId());
328 }
329
OnAfterModifyDone()330 void SearchPattern::OnAfterModifyDone()
331 {
332 auto host = GetHost();
333 CHECK_NULL_VOID(host);
334 auto inspectorId = host->GetInspectorId().value_or("");
335 if (!inspectorId.empty()) {
336 auto textFieldFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(TEXTFIELD_INDEX));
337 CHECK_NULL_VOID(textFieldFrameNode);
338 auto textFieldPattern = textFieldFrameNode->GetPattern<TextFieldPattern>();
339 CHECK_NULL_VOID(textFieldPattern);
340 auto text = textFieldPattern->GetTextValue();
341 Recorder::NodeDataCache::Get().PutString(inspectorId, text);
342 }
343 }
344
InitButtonAndImageClickEvent()345 void SearchPattern::InitButtonAndImageClickEvent()
346 {
347 // Image click event
348 if (imageClickListener_) {
349 return;
350 }
351 auto host = GetHost();
352 CHECK_NULL_VOID(host);
353 auto imageFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(IMAGE_INDEX));
354 CHECK_NULL_VOID(imageFrameNode);
355 CHECK_NULL_VOID(!imageClickListener_);
356 auto imageGesture = imageFrameNode->GetOrCreateGestureEventHub();
357 CHECK_NULL_VOID(imageGesture);
358 auto imageClickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
359 auto searchPattern = weak.Upgrade();
360 CHECK_NULL_VOID(searchPattern);
361 searchPattern->OnClickButtonAndImage();
362 };
363 imageClickListener_ = MakeRefPtr<ClickEvent>(std::move(imageClickCallback));
364 imageGesture->AddClickEvent(imageClickListener_);
365 // Button click event
366 if (buttonClickListener_) {
367 return;
368 }
369 auto buttonFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(BUTTON_INDEX));
370 CHECK_NULL_VOID(buttonFrameNode);
371 CHECK_NULL_VOID(!buttonClickListener_);
372 auto buttonGesture = buttonFrameNode->GetOrCreateGestureEventHub();
373 CHECK_NULL_VOID(buttonGesture);
374 auto buttonClickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
375 auto searchPattern = weak.Upgrade();
376 CHECK_NULL_VOID(searchPattern);
377 searchPattern->OnClickButtonAndImage();
378 };
379 buttonClickListener_ = MakeRefPtr<ClickEvent>(std::move(buttonClickCallback));
380 buttonGesture->AddClickEvent(buttonClickListener_);
381 }
382
InitCancelButtonClickEvent()383 void SearchPattern::InitCancelButtonClickEvent()
384 {
385 // CancelButton click event
386 if (cancelButtonClickListener_) {
387 return;
388 }
389 auto host = GetHost();
390 CHECK_NULL_VOID(host);
391 auto cancelButtonFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(CANCEL_BUTTON_INDEX));
392 CHECK_NULL_VOID(cancelButtonFrameNode);
393 auto cancelButtonGesture = cancelButtonFrameNode->GetOrCreateGestureEventHub();
394 CHECK_NULL_VOID(cancelButtonGesture);
395 auto cancelButtonClickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
396 auto searchPattern = weak.Upgrade();
397 CHECK_NULL_VOID(searchPattern);
398 searchPattern->OnClickCancelButton();
399 };
400 cancelButtonClickListener_ = MakeRefPtr<ClickEvent>(std::move(cancelButtonClickCallback));
401 cancelButtonGesture->AddClickEvent(cancelButtonClickListener_);
402 }
403
InitTextFieldClickEvent()404 void SearchPattern::InitTextFieldClickEvent()
405 {
406 if (textFieldClickListener_) {
407 return;
408 }
409 auto host = GetHost();
410 CHECK_NULL_VOID(host);
411 auto textFieldFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(TEXTFIELD_INDEX));
412 CHECK_NULL_VOID(textFieldFrameNode);
413 auto textFieldGesture = textFieldFrameNode->GetOrCreateGestureEventHub();
414 CHECK_NULL_VOID(textFieldGesture);
415 auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
416 auto searchPattern = weak.Upgrade();
417 CHECK_NULL_VOID(searchPattern);
418 searchPattern->OnClickTextField();
419 };
420 textFieldClickListener_ = MakeRefPtr<ClickEvent>(std::move(clickCallback));
421 textFieldGesture->AddClickEvent(textFieldClickListener_);
422 }
423
InitSearchController()424 void SearchPattern::InitSearchController()
425 {
426 searchController_->SetCaretPosition([weak = WeakClaim(this)](int32_t caretPosition) {
427 auto search = weak.Upgrade();
428 CHECK_NULL_VOID(search);
429 search->HandleCaretPosition(caretPosition);
430 });
431
432 searchController_->SetGetTextContentRect([weak = WeakClaim(this)]() {
433 auto search = weak.Upgrade();
434 CHECK_NULL_RETURN(search, Rect(0, 0, 0, 0));
435 auto rect = search->searchController_->GetTextContentRect();
436 search->HandleTextContentRect(rect);
437 return rect;
438 });
439
440 searchController_->SetGetTextContentLinesNum([weak = WeakClaim(this)]() {
441 auto search = weak.Upgrade();
442 CHECK_NULL_RETURN(search, 0);
443 return search->HandleTextContentLines();
444 });
445
446 searchController_->SetGetCaretIndex([weak = WeakClaim(this)]() {
447 auto search = weak.Upgrade();
448 CHECK_NULL_RETURN(search, ERROR);
449 return search->HandleGetCaretIndex();
450 });
451
452 searchController_->SetGetCaretPosition([weak = WeakClaim(this)]() {
453 auto search = weak.Upgrade();
454 CHECK_NULL_RETURN(search, NG::OffsetF(ERROR, ERROR));
455 return search->HandleGetCaretPosition();
456 });
457
458 searchController_->SetStopEditing([weak = WeakClaim(this)]() {
459 auto search = weak.Upgrade();
460 CHECK_NULL_VOID(search);
461 search->StopEditing();
462 });
463 }
464
HandleGetCaretIndex()465 int32_t SearchPattern::HandleGetCaretIndex()
466 {
467 auto host = GetHost();
468 CHECK_NULL_RETURN(host, ERROR);
469 auto textFieldFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
470 CHECK_NULL_RETURN(textFieldFrameNode, ERROR);
471 auto textFieldPattern = textFieldFrameNode->GetPattern<TextFieldPattern>();
472 CHECK_NULL_RETURN(textFieldPattern, ERROR);
473 return textFieldPattern->GetCaretIndex();
474 }
475
HandleGetCaretPosition()476 NG::OffsetF SearchPattern::HandleGetCaretPosition()
477 {
478 auto host = GetHost();
479 CHECK_NULL_RETURN(host, NG::OffsetF(ERROR, ERROR));
480 auto textFieldFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
481 CHECK_NULL_RETURN(textFieldFrameNode, NG::OffsetF(ERROR, ERROR));
482 auto textFieldPattern = textFieldFrameNode->GetPattern<TextFieldPattern>();
483 CHECK_NULL_RETURN(textFieldPattern, NG::OffsetF(ERROR, ERROR));
484 return textFieldPattern->GetCaretOffset();
485 }
486
HandleCaretPosition(int32_t caretPosition)487 void SearchPattern::HandleCaretPosition(int32_t caretPosition)
488 {
489 auto host = GetHost();
490 CHECK_NULL_VOID(host);
491 auto textFieldFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
492 CHECK_NULL_VOID(textFieldFrameNode);
493 auto textFieldPattern = textFieldFrameNode->GetPattern<TextFieldPattern>();
494 CHECK_NULL_VOID(textFieldPattern);
495 textFieldPattern->SetCaretPosition(caretPosition);
496 }
497
HandleTextContentRect(Rect & rect)498 void SearchPattern::HandleTextContentRect(Rect& rect)
499 {
500 auto host = GetHost();
501 CHECK_NULL_VOID(host);
502 auto textFieldFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
503 CHECK_NULL_VOID(textFieldFrameNode);
504 auto textFieldPattern = textFieldFrameNode->GetPattern<TextFieldPattern>();
505 CHECK_NULL_VOID(textFieldPattern);
506 RectF frameRect = textFieldPattern->GetFrameRect();
507 rect.SetLeft(rect.Left() + frameRect.Left());
508 rect.SetTop(rect.Top() + frameRect.Top());
509 }
510
HandleTextContentLines()511 int32_t SearchPattern::HandleTextContentLines()
512 {
513 int lines = 0;
514 auto host = GetHost();
515 CHECK_NULL_RETURN(host, lines);
516 auto textFieldFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
517 CHECK_NULL_RETURN(textFieldFrameNode, lines);
518 auto textFieldPattern = textFieldFrameNode->GetPattern<TextFieldPattern>();
519 CHECK_NULL_RETURN(textFieldPattern, lines);
520 if (!textFieldPattern->IsOperation()) {
521 return lines;
522 }
523 RectF textRect = textFieldPattern->GetTextRect();
524
525 if ((int32_t)textFieldPattern->GetLineHeight() == 0) {
526 return lines;
527 }
528 lines = (int32_t)textRect.Height() / (int32_t)textFieldPattern->GetLineHeight();
529 return lines;
530 }
531
StopEditing()532 void SearchPattern::StopEditing()
533 {
534 auto host = GetHost();
535 CHECK_NULL_VOID(host);
536 auto textFieldFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
537 CHECK_NULL_VOID(textFieldFrameNode);
538 auto textFieldPattern = textFieldFrameNode->GetPattern<TextFieldPattern>();
539 CHECK_NULL_VOID(textFieldPattern);
540 textFieldPattern->StopEditing();
541 }
542
OnClickButtonAndImage()543 void SearchPattern::OnClickButtonAndImage()
544 {
545 auto host = GetHost();
546 CHECK_NULL_VOID(host);
547 auto searchEventHub = host->GetEventHub<SearchEventHub>();
548 CHECK_NULL_VOID(searchEventHub);
549 auto textFieldFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
550 CHECK_NULL_VOID(textFieldFrameNode);
551 auto textFieldPattern = textFieldFrameNode->GetPattern<TextFieldPattern>();
552 CHECK_NULL_VOID(textFieldPattern);
553 auto text = textFieldPattern->GetTextValue();
554 searchEventHub->UpdateSubmitEvent(text);
555 textFieldPattern->CloseKeyboard(true);
556 }
557
OnClickCancelButton()558 void SearchPattern::OnClickCancelButton()
559 {
560 auto host = GetHost();
561 CHECK_NULL_VOID(host);
562 auto textFieldFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
563 CHECK_NULL_VOID(textFieldFrameNode);
564 auto textFieldPattern = textFieldFrameNode->GetPattern<TextFieldPattern>();
565 CHECK_NULL_VOID(textFieldPattern);
566 CHECK_NULL_VOID(!textFieldPattern->IsDragging());
567 focusChoice_ = FocusChoice::SEARCH;
568 textFieldPattern->InitEditingValueText("");
569 auto textRect = textFieldPattern->GetTextRect();
570 textRect.SetLeft(0.0f);
571 textFieldPattern->SetTextRect(textRect);
572 auto textFieldLayoutProperty = textFieldFrameNode->GetLayoutProperty<TextFieldLayoutProperty>();
573 CHECK_NULL_VOID(textFieldLayoutProperty);
574 textFieldLayoutProperty->UpdateValue("");
575 auto eventHub = textFieldFrameNode->GetEventHub<TextFieldEventHub>();
576 eventHub->FireOnChange("");
577 auto focusHub = host->GetOrCreateFocusHub();
578 CHECK_NULL_VOID(focusHub);
579 focusHub->RequestFocusImmediately();
580 textFieldPattern->HandleFocusEvent();
581 host->MarkModifyDone();
582 textFieldFrameNode->MarkModifyDone();
583 }
584
OnClickTextField()585 void SearchPattern::OnClickTextField()
586 {
587 focusChoice_ = FocusChoice::SEARCH;
588 auto host = GetHost();
589 CHECK_NULL_VOID(host);
590 RoundRect focusRect;
591 GetInnerFocusPaintRect(focusRect);
592 auto focusHub = host->GetFocusHub();
593 CHECK_NULL_VOID(focusHub);
594 focusHub->PaintInnerFocusState(focusRect);
595 host->MarkModifyDone();
596 }
597
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)598 void SearchPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
599 {
600 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
601 auto pattern = wp.Upgrade();
602 CHECK_NULL_RETURN(pattern, false);
603 return pattern->OnKeyEvent(event);
604 };
605 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
606
607 auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
608 auto pattern = wp.Upgrade();
609 if (pattern) {
610 pattern->GetInnerFocusPaintRect(paintRect);
611 }
612 };
613 focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
614 }
615
OnKeyEvent(const KeyEvent & event)616 bool SearchPattern::OnKeyEvent(const KeyEvent& event)
617 {
618 auto host = GetHost();
619 CHECK_NULL_RETURN(host, false);
620 auto textFieldFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(TEXTFIELD_INDEX));
621 CHECK_NULL_RETURN(textFieldFrameNode, false);
622 auto textFieldPattern = textFieldFrameNode->GetPattern<TextFieldPattern>();
623 CHECK_NULL_RETURN(textFieldPattern, false);
624
625 bool isAllTextSelected = textFieldPattern->IsSelectAll();
626 bool isCaretVisible = textFieldPattern->GetCursorVisible();
627 bool isTextEmpty = textFieldPattern->GetTextValue().empty();
628 bool isOnlyTabPressed = event.pressedCodes.size() == 1 && event.code == KeyCode::KEY_TAB;
629
630 auto parentHub = host->GetOrCreateFocusHub()->GetParentFocusHub();
631 auto getMaxFocusableCount = [](auto self, const RefPtr<FocusHub>& focusHub) -> size_t {
632 CHECK_NULL_RETURN(focusHub, 0);
633 auto parentHub = focusHub->GetParentFocusHub();
634 return std::max(focusHub->GetFocusableCount(), self(self, parentHub));
635 };
636 constexpr int ONE = 1; // Only one focusable component on scene
637 bool isOnlyOneFocusableComponent = getMaxFocusableCount(getMaxFocusableCount, parentHub) == ONE;
638
639 if (event.action == KeyAction::UP && event.code == KeyCode::KEY_TAB &&
640 focusChoice_ != FocusChoice::SEARCH) {
641 textFieldPattern->HandleSetSelection(0, 0, false); // Clear selection and caret when tab pressed
642 }
643
644 if (event.action != KeyAction::DOWN) {
645 if (event.code == KeyCode::KEY_TAB && focusChoice_ == FocusChoice::SEARCH) {
646 textFieldPattern->OnKeyEvent(event);
647 }
648 return false;
649 }
650
651 // If the focus is on the search, press Enter to request keyboard.
652 if (event.code == KeyCode::KEY_ENTER && focusChoice_ == FocusChoice::SEARCH) {
653 RequestKeyboard();
654 return true;
655 }
656 // If the focus is on the search button, press Enter to submit the content.
657 if (event.code == KeyCode::KEY_ENTER && focusChoice_ == FocusChoice::SEARCH_BUTTON) {
658 OnClickButtonAndImage();
659 return true;
660 }
661 // If the focus is on the Delete button, press Enter to delete the content.
662 if (event.code == KeyCode::KEY_ENTER && focusChoice_ == FocusChoice::CANCEL_BUTTON) {
663 OnClickCancelButton();
664 PaintFocusState();
665 return true;
666 }
667 // When press '->' or '<-', focus delete button or search button according to whether there is text in the search.
668 if (event.code == KeyCode::KEY_DPAD_LEFT || event.IsShiftWith(KeyCode::KEY_TAB)) {
669 if (focusChoice_ == FocusChoice::CANCEL_BUTTON) {
670 focusChoice_ = FocusChoice::SEARCH;
671 PaintFocusState();
672 return true;
673 }
674 if (focusChoice_ == FocusChoice::SEARCH_BUTTON) {
675 if (NearZero(cancelButtonSize_.Height())) {
676 focusChoice_ = FocusChoice::SEARCH;
677 } else {
678 focusChoice_ = FocusChoice::CANCEL_BUTTON;
679 }
680 PaintFocusState();
681 return true;
682 }
683 if (focusChoice_ == FocusChoice::SEARCH && isOnlyOneFocusableComponent && event.IsShiftWith(KeyCode::KEY_TAB)) {
684 if (isSearchButtonEnabled_) {
685 focusChoice_ = FocusChoice::SEARCH_BUTTON;
686 } else if (!isTextEmpty) {
687 focusChoice_ = FocusChoice::CANCEL_BUTTON;
688 }
689 PaintFocusState();
690 return true;
691 }
692 if (focusChoice_ == FocusChoice::SEARCH && event.IsShiftWith(KeyCode::KEY_TAB)) {
693 textFieldPattern->CloseKeyboard(true);
694 return false;
695 }
696 if (focusChoice_ == FocusChoice::SEARCH && !isAllTextSelected && !isTextEmpty) {
697 return textFieldPattern->OnKeyEvent(event);
698 }
699 if (focusChoice_ == FocusChoice::SEARCH && isAllTextSelected && !isCaretVisible &&
700 event.code == KeyCode::KEY_DPAD_LEFT) {
701 return true; // no action
702 }
703 }
704 if (event.code == KeyCode::KEY_DPAD_RIGHT || (event.pressedCodes.size() == 1 && event.code == KeyCode::KEY_TAB)) {
705 if (focusChoice_ == FocusChoice::SEARCH && (isAllTextSelected || isTextEmpty || isOnlyTabPressed)) {
706 if (NearZero(cancelButtonSize_.Height()) && !isSearchButtonEnabled_ &&
707 event.code == KeyCode::KEY_DPAD_RIGHT) {
708 return true;
709 } else if (NearZero(cancelButtonSize_.Height()) && !isSearchButtonEnabled_) {
710 textFieldPattern->CloseKeyboard(true);
711 return false;
712 }
713 if (NearZero(cancelButtonSize_.Height())) {
714 focusChoice_ = FocusChoice::SEARCH_BUTTON;
715 } else {
716 focusChoice_ = FocusChoice::CANCEL_BUTTON;
717 }
718 PaintFocusState();
719 return true;
720 } else if (focusChoice_ == FocusChoice::SEARCH && event.code == KeyCode::KEY_DPAD_RIGHT) {
721 textFieldPattern->OnKeyEvent(event);
722 return true;
723 }
724 if (focusChoice_ == FocusChoice::CANCEL_BUTTON) {
725 if (!NearZero(cancelButtonSize_.Height()) && (!isSearchButtonEnabled_) &&
726 (event.code == KeyCode::KEY_DPAD_RIGHT)) {
727 return false; // Go out of Search
728 }
729 if (isOnlyOneFocusableComponent && isOnlyTabPressed && !isSearchButtonEnabled_) {
730 focusChoice_ = FocusChoice::SEARCH;
731 PaintFocusState();
732 return true;
733 }
734 if (!isSearchButtonEnabled_) {
735 return !isOnlyTabPressed; // go outside if Tab pressed, or no action if arrow pressed
736 }
737 focusChoice_ = FocusChoice::SEARCH_BUTTON;
738 PaintFocusState();
739 return true;
740 }
741 if (focusChoice_ == FocusChoice::SEARCH_BUTTON && isOnlyOneFocusableComponent && isOnlyTabPressed) {
742 focusChoice_ = FocusChoice::SEARCH;
743 PaintFocusState();
744 return true;
745 }
746 if (focusChoice_ == FocusChoice::SEARCH_BUTTON &&
747 (event.pressedCodes.size() == 1 && event.code == KeyCode::KEY_TAB)) {
748 textFieldPattern->CloseKeyboard(true);
749 return false;
750 }
751 if (focusChoice_ == FocusChoice::SEARCH_BUTTON && isSearchButtonEnabled_ &&
752 (event.code == KeyCode::KEY_DPAD_RIGHT)) {
753 return false; // Go out of Search
754 }
755 }
756
757 if (focusChoice_ == FocusChoice::SEARCH) {
758 return textFieldPattern->OnKeyEvent(event);
759 } else {
760 return true;
761 }
762 }
763
PaintFocusState(bool recoverFlag)764 void SearchPattern::PaintFocusState(bool recoverFlag)
765 {
766 auto host = GetHost();
767 CHECK_NULL_VOID(host);
768 auto textFieldFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(TEXTFIELD_INDEX));
769 CHECK_NULL_VOID(textFieldFrameNode);
770 auto textFieldPattern = textFieldFrameNode->GetPattern<TextFieldPattern>();
771 CHECK_NULL_VOID(textFieldPattern);
772
773 if (focusChoice_ == FocusChoice::SEARCH) {
774 if (!recoverFlag) {
775 if (!textFieldPattern->GetTextValue().empty()) {
776 textFieldPattern->NeedRequestKeyboard();
777 textFieldPattern->HandleOnSelectAll(true); // Select all text
778 textFieldPattern->StopTwinkling(); // Hide caret
779 } else {
780 textFieldPattern->HandleFocusEvent(); // Show caret
781 }
782 } else {
783 textFieldPattern->HandleFocusEvent();
784 }
785 } else {
786 if (textFieldPattern->IsSelected() || textFieldPattern->GetCursorVisible()) {
787 textFieldPattern->HandleSetSelection(0, 0, false); // Clear text selection & caret if focus has gone
788 }
789 textFieldPattern->CloseKeyboard(true);
790 }
791
792 auto context = PipelineContext::GetCurrentContext();
793 CHECK_NULL_VOID(context);
794 RoundRect focusRect;
795 GetInnerFocusPaintRect(focusRect);
796 auto focusHub = host->GetFocusHub();
797 CHECK_NULL_VOID(focusHub);
798 focusHub->PaintInnerFocusState(focusRect, true);
799 host->MarkModifyDone();
800 }
801
GetInnerFocusPaintRect(RoundRect & paintRect)802 void SearchPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
803 {
804 float originX = 0.0f;
805 float originY = 0.0f;
806 float endX = 0.0f;
807 float endY = 0.0f;
808 float radiusTopLeft = 0.0f;
809 float radiusTopRight = 0.0f;
810 float radiusBottomLeft = 0.0f;
811 float radiusBottomRight = 0.0f;
812 float focusOffset = FOCUS_OFFSET.ConvertToPx();
813 if (focusChoice_ == FocusChoice::SEARCH) {
814 return;
815 }
816 if (focusChoice_ == FocusChoice::CANCEL_BUTTON) {
817 originX = cancelButtonOffset_.GetX() + focusOffset;
818 originY = cancelButtonOffset_.GetY() + focusOffset;
819 endX = cancelButtonSize_.Width() + originX - DOUBLE * focusOffset;
820 endY = cancelButtonSize_.Height() + originY - DOUBLE * focusOffset;
821 radiusTopLeft = cancelButtonSize_.Height() / DOUBLE - focusOffset;
822 radiusTopRight = cancelButtonSize_.Height() / DOUBLE - focusOffset;
823 radiusBottomLeft = cancelButtonSize_.Height() / DOUBLE - focusOffset;
824 radiusBottomRight = cancelButtonSize_.Height() / DOUBLE - focusOffset;
825 }
826 if (focusChoice_ == FocusChoice::SEARCH_BUTTON) {
827 originX = buttonOffset_.GetX() + focusOffset;
828 originY = buttonOffset_.GetY() + focusOffset;
829 endX = buttonSize_.Width() + originX - DOUBLE * focusOffset;
830 endY = buttonSize_.Height() + originY - DOUBLE * focusOffset;
831 radiusTopLeft = buttonSize_.Height() / DOUBLE - focusOffset;
832 radiusTopRight = buttonSize_.Height() / DOUBLE - focusOffset;
833 radiusBottomLeft = buttonSize_.Height() / DOUBLE - focusOffset;
834 radiusBottomRight = buttonSize_.Height() / DOUBLE - focusOffset;
835 }
836
837 paintRect.SetRect({ originX, originY, endX - originX, endY - originY });
838 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, radiusTopLeft, radiusTopLeft);
839 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, radiusTopRight, radiusTopRight);
840 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, radiusBottomLeft, radiusBottomLeft);
841 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, radiusBottomRight, radiusBottomRight);
842 }
843
GetFocusPattern() const844 FocusPattern SearchPattern::GetFocusPattern() const
845 {
846 FocusPattern focusPattern = { FocusType::NODE, true, FocusStyleType::CUSTOM_REGION };
847 focusPattern.SetIsFocusActiveWhenFocused(true);
848 return focusPattern;
849 }
850
RequestKeyboard()851 void SearchPattern::RequestKeyboard()
852 {
853 auto host = GetHost();
854 CHECK_NULL_VOID(host);
855 auto textFieldFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(TEXTFIELD_INDEX));
856 CHECK_NULL_VOID(textFieldFrameNode);
857 auto textFieldPattern = textFieldFrameNode->GetPattern<TextFieldPattern>();
858 textFieldPattern->SearchRequestKeyboard();
859 }
860
InitButtonTouchEvent(RefPtr<TouchEventImpl> & touchEvent,int32_t childId)861 void SearchPattern::InitButtonTouchEvent(RefPtr<TouchEventImpl>& touchEvent, int32_t childId)
862 {
863 if (touchEvent) {
864 return;
865 }
866 auto host = GetHost();
867 CHECK_NULL_VOID(host);
868 auto buttonFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(childId));
869 CHECK_NULL_VOID(buttonFrameNode);
870 auto gesture = buttonFrameNode->GetOrCreateGestureEventHub();
871 CHECK_NULL_VOID(gesture);
872 auto eventHub = buttonFrameNode->GetEventHub<ButtonEventHub>();
873 CHECK_NULL_VOID(eventHub);
874 eventHub->SetStateEffect(false);
875 auto touchTask = [weak = WeakClaim(this), childId](const TouchEventInfo& info) {
876 auto pattern = weak.Upgrade();
877 CHECK_NULL_VOID(pattern);
878 auto touchType = info.GetTouches().front().GetTouchType();
879 if (touchType == TouchType::DOWN) {
880 pattern->OnButtonTouchDown(childId);
881 }
882 if (touchType == TouchType::UP) {
883 pattern->OnButtonTouchUp(childId);
884 }
885 };
886 touchEvent = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
887 gesture->AddTouchEvent(touchEvent);
888 }
889
InitButtonMouseEvent(RefPtr<InputEvent> & inputEvent,int32_t childId)890 void SearchPattern::InitButtonMouseEvent(RefPtr<InputEvent>& inputEvent, int32_t childId)
891 {
892 if (inputEvent) {
893 return;
894 }
895 auto host = GetHost();
896 CHECK_NULL_VOID(host);
897 auto buttonFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(childId));
898 CHECK_NULL_VOID(buttonFrameNode);
899 auto eventHub = buttonFrameNode->GetEventHub<ButtonEventHub>();
900 auto inputHub = eventHub->GetOrCreateInputEventHub();
901 auto buttonPattern = buttonFrameNode->GetPattern<ButtonPattern>();
902 CHECK_NULL_VOID(buttonPattern);
903 auto buttonHoverListener = buttonPattern->GetHoverListener();
904 inputHub->RemoveOnHoverEvent(buttonHoverListener);
905 auto mouseTask = [weak = WeakClaim(this), childId](bool isHover) {
906 auto pattern = weak.Upgrade();
907 if (pattern) {
908 pattern->HandleButtonMouseEvent(isHover, childId);
909 }
910 };
911 inputEvent = MakeRefPtr<InputEvent>(std::move(mouseTask));
912 inputHub->AddOnHoverEvent(inputEvent);
913 }
914
OnButtonTouchDown(int32_t childId)915 void SearchPattern::OnButtonTouchDown(int32_t childId)
916 {
917 auto host = GetHost();
918 CHECK_NULL_VOID(host);
919 auto buttonFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(childId));
920 CHECK_NULL_VOID(buttonFrameNode);
921 auto renderContext = buttonFrameNode->GetRenderContext();
922 CHECK_NULL_VOID(renderContext);
923 if (childId == CANCEL_BUTTON_INDEX ? isCancelButtonHover_ : isSearchButtonHover_) {
924 AnimateTouchAndHover(renderContext, HOVER_OPACITY, TOUCH_OPACITY, HOVER_TO_TOUCH_DURATION, Curves::SHARP);
925 } else {
926 AnimateTouchAndHover(renderContext, 0.0f, TOUCH_OPACITY, TOUCH_DURATION, Curves::FRICTION);
927 }
928 }
929
OnButtonTouchUp(int32_t childId)930 void SearchPattern::OnButtonTouchUp(int32_t childId)
931 {
932 auto host = GetHost();
933 CHECK_NULL_VOID(host);
934 auto buttonFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(childId));
935 CHECK_NULL_VOID(buttonFrameNode);
936 auto renderContext = buttonFrameNode->GetRenderContext();
937 CHECK_NULL_VOID(renderContext);
938 if (childId == CANCEL_BUTTON_INDEX ? isCancelButtonHover_ : isSearchButtonHover_) {
939 AnimateTouchAndHover(renderContext, TOUCH_OPACITY, HOVER_OPACITY, HOVER_TO_TOUCH_DURATION, Curves::SHARP);
940 } else {
941 AnimateTouchAndHover(renderContext, TOUCH_OPACITY, 0.0f, TOUCH_DURATION, Curves::FRICTION);
942 }
943 }
944
SetMouseStyle(MouseFormat format)945 void SearchPattern::SetMouseStyle(MouseFormat format)
946 {
947 auto pipeline = PipelineContext::GetCurrentContext();
948 CHECK_NULL_VOID(pipeline);
949 auto windowId = pipeline->GetWindowId();
950 auto mouseStyle = MouseStyle::CreateMouseStyle();
951 CHECK_NULL_VOID(mouseStyle);
952
953 int32_t currentPointerStyle = 0;
954 mouseStyle->GetPointerStyle(windowId, currentPointerStyle);
955 if (currentPointerStyle != static_cast<int32_t>(format)) {
956 mouseStyle->SetPointerStyle(windowId, format);
957 }
958 }
959
HandleButtonMouseEvent(bool isHover,int32_t childId)960 void SearchPattern::HandleButtonMouseEvent(bool isHover, int32_t childId)
961 {
962 if (childId == CANCEL_BUTTON_INDEX) {
963 isCancelButtonHover_ = isHover;
964 } else {
965 isSearchButtonHover_ = isHover;
966 }
967 auto host = GetHost();
968 CHECK_NULL_VOID(host);
969 auto buttonFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(childId));
970 CHECK_NULL_VOID(buttonFrameNode);
971 auto renderContext = buttonFrameNode->GetRenderContext();
972 CHECK_NULL_VOID(renderContext);
973 if (isHover) {
974 AnimateTouchAndHover(renderContext, 0.0f, HOVER_OPACITY, HOVER_DURATION, Curves::FRICTION);
975 } else {
976 AnimateTouchAndHover(renderContext, HOVER_OPACITY, 0.0f, HOVER_DURATION, Curves::FRICTION);
977 }
978 }
979
AnimateTouchAndHover(RefPtr<RenderContext> & renderContext,float startOpacity,float endOpacity,int32_t duration,const RefPtr<Curve> & curve)980 void SearchPattern::AnimateTouchAndHover(RefPtr<RenderContext>& renderContext, float startOpacity, float endOpacity,
981 int32_t duration, const RefPtr<Curve>& curve)
982 {
983 auto colorMode = SystemProperties::GetColorMode();
984 Color touchColorFrom = Color::FromRGBO(0, 0, 0, startOpacity);
985 Color touchColorTo = Color::FromRGBO(0, 0, 0, endOpacity);
986 if (colorMode == ColorMode::DARK) {
987 touchColorFrom = Color::FromRGBO(255, 255, 255, startOpacity);
988 touchColorTo = Color::FromRGBO(255, 255, 255, endOpacity);
989 }
990 Color highlightStart = renderContext->GetBackgroundColor().value_or(Color::TRANSPARENT).BlendColor(touchColorFrom);
991 Color highlightEnd = renderContext->GetBackgroundColor().value_or(Color::TRANSPARENT).BlendColor(touchColorTo);
992 renderContext->OnBackgroundColorUpdate(highlightStart);
993 AnimationOption option = AnimationOption();
994 option.SetDuration(duration);
995 option.SetCurve(curve);
996 AnimationUtils::Animate(
997 option, [renderContext, highlightEnd]() { renderContext->OnBackgroundColorUpdate(highlightEnd); });
998 }
999
ResetDragOption()1000 void SearchPattern::ResetDragOption()
1001 {
1002 ClearButtonStyle(BUTTON_INDEX);
1003 ClearButtonStyle(CANCEL_BUTTON_INDEX);
1004 }
1005
ClearButtonStyle(int32_t childId)1006 void SearchPattern::ClearButtonStyle(int32_t childId)
1007 {
1008 auto host = GetHost();
1009 CHECK_NULL_VOID(host);
1010 auto buttonFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(childId));
1011 CHECK_NULL_VOID(buttonFrameNode);
1012 auto renderContext = buttonFrameNode->GetRenderContext();
1013 CHECK_NULL_VOID(renderContext);
1014 AnimateTouchAndHover(renderContext, TOUCH_OPACITY, 0.0f, HOVER_TO_TOUCH_DURATION, Curves::SHARP);
1015 }
1016
InitFocusEvent(const RefPtr<FocusHub> & focusHub)1017 void SearchPattern::InitFocusEvent(const RefPtr<FocusHub>& focusHub)
1018 {
1019 auto focusTask = [weak = WeakClaim(this)]() {
1020 auto pattern = weak.Upgrade();
1021 if (!pattern) {
1022 return;
1023 }
1024 bool backwardFocusMovement = false;
1025 bool forwardFocusMovement = false;
1026 auto host = pattern->GetHost();
1027 if (host) {
1028 auto rootHub = host->GetOrCreateFocusHub()->GetRootFocusHub();
1029 backwardFocusMovement = rootHub && rootHub->HasBackwardFocusMovementInChildren();
1030 forwardFocusMovement = rootHub && rootHub->HasForwardFocusMovementInChildren();
1031 if (rootHub) {
1032 rootHub->ClearFocusMovementFlagsInChildren();
1033 }
1034 }
1035 pattern->HandleFocusEvent(forwardFocusMovement, backwardFocusMovement);
1036 };
1037 focusHub->SetOnFocusInternal(focusTask);
1038 auto blurTask = [weak = WeakClaim(this)]() {
1039 auto pattern = weak.Upgrade();
1040 CHECK_NULL_VOID(pattern);
1041 pattern->HandleBlurEvent();
1042 };
1043 focusHub->SetOnBlurInternal(blurTask);
1044 }
1045
HandleFocusEvent(bool forwardFocusMovement,bool backwardFocusMovement)1046 void SearchPattern::HandleFocusEvent(bool forwardFocusMovement, bool backwardFocusMovement)
1047 {
1048 auto host = GetHost();
1049 CHECK_NULL_VOID(host);
1050 auto textFieldFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(TEXTFIELD_INDEX));
1051 CHECK_NULL_VOID(textFieldFrameNode);
1052 auto textFieldPattern = textFieldFrameNode->GetPattern<TextFieldPattern>();
1053 CHECK_NULL_VOID(textFieldPattern);
1054
1055 if (forwardFocusMovement || backwardFocusMovement) { // Don't update focus if no factical focus movement
1056 focusChoice_ = backwardFocusMovement ? FocusChoice::SEARCH_BUTTON : FocusChoice::SEARCH;
1057 if (focusChoice_ == FocusChoice::SEARCH_BUTTON && !isSearchButtonEnabled_) {
1058 bool isCancelHidden = NearZero(cancelButtonSize_.Height());
1059 focusChoice_ = isCancelHidden ? FocusChoice::SEARCH : FocusChoice::CANCEL_BUTTON;
1060 }
1061 }
1062 PaintFocusState(!(forwardFocusMovement || backwardFocusMovement));
1063 }
1064
HandleBlurEvent()1065 void SearchPattern::HandleBlurEvent()
1066 {
1067 auto host = GetHost();
1068 CHECK_NULL_VOID(host);
1069 auto textFieldFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(TEXTFIELD_INDEX));
1070 CHECK_NULL_VOID(textFieldFrameNode);
1071 auto textFieldPattern = textFieldFrameNode->GetPattern<TextFieldPattern>();
1072 CHECK_NULL_VOID(textFieldPattern);
1073 textFieldPattern->HandleBlurEvent();
1074 }
1075
InitClickEvent()1076 void SearchPattern::InitClickEvent()
1077 {
1078 if (clickListener_) {
1079 return;
1080 }
1081 auto host = GetHost();
1082 CHECK_NULL_VOID(host);
1083 auto gesture = host->GetOrCreateGestureEventHub();
1084 CHECK_NULL_VOID(gesture);
1085 auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
1086 auto pattern = weak.Upgrade();
1087 CHECK_NULL_VOID(pattern);
1088 pattern->HandleClickEvent(info);
1089 };
1090 clickListener_ = MakeRefPtr<ClickEvent>(std::move(clickCallback));
1091 gesture->AddClickEvent(clickListener_);
1092 }
1093
HandleClickEvent(GestureEvent & info)1094 void SearchPattern::HandleClickEvent(GestureEvent& info)
1095 {
1096 auto host = GetHost();
1097 CHECK_NULL_VOID(host);
1098 auto textFieldFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(TEXTFIELD_INDEX));
1099 CHECK_NULL_VOID(textFieldFrameNode);
1100 auto textFieldPattern = textFieldFrameNode->GetPattern<TextFieldPattern>();
1101 CHECK_NULL_VOID(textFieldPattern);
1102 textFieldPattern->HandleClickEvent(info);
1103 }
1104
HandleInputChildOnFocus() const1105 bool SearchPattern::HandleInputChildOnFocus() const
1106 {
1107 #if !defined(PREVIEW)
1108 return false;
1109 #endif
1110 auto focusHub = GetHost()->GetOrCreateFocusHub();
1111 focusHub->RequestFocusImmediately();
1112 return true;
1113 }
1114
ToJsonValueForTextField(std::unique_ptr<JsonValue> & json) const1115 void SearchPattern::ToJsonValueForTextField(std::unique_ptr<JsonValue>& json) const
1116 {
1117 auto host = GetHost();
1118 CHECK_NULL_VOID(host);
1119 auto textFieldFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(TEXTFIELD_INDEX));
1120 CHECK_NULL_VOID(textFieldFrameNode);
1121 auto textFieldLayoutProperty = textFieldFrameNode->GetLayoutProperty<TextFieldLayoutProperty>();
1122 CHECK_NULL_VOID(textFieldLayoutProperty);
1123 auto textFieldPattern = textFieldFrameNode->GetPattern<TextFieldPattern>();
1124 CHECK_NULL_VOID(textFieldPattern);
1125
1126 json->Put("value", textFieldPattern->GetTextValue().c_str());
1127 json->Put("placeholder", textFieldPattern->GetPlaceHolder().c_str());
1128 json->Put("placeholderColor", textFieldPattern->GetPlaceholderColor().c_str());
1129 json->Put("placeholderFont", textFieldPattern->GetPlaceholderFont().c_str());
1130 json->Put("textAlign", V2::ConvertWrapTextAlignToString(textFieldPattern->GetTextAlign()).c_str());
1131 auto textColor = textFieldLayoutProperty->GetTextColor().value_or(Color());
1132 json->Put("fontColor", textColor.ColorToString().c_str());
1133 auto textFontJson = JsonUtil::Create(true);
1134 textFontJson->Put("fontSize", textFieldPattern->GetFontSize().c_str());
1135 textFontJson->Put("fontStyle",
1136 textFieldPattern->GetItalicFontStyle() == Ace::FontStyle::NORMAL ? "FontStyle.Normal" : "FontStyle.Italic");
1137 textFontJson->Put("fontWeight", V2::ConvertWrapFontWeightToStirng(textFieldPattern->GetFontWeight()).c_str());
1138 textFontJson->Put("fontFamily", textFieldPattern->GetFontFamily().c_str());
1139 json->Put("textFont", textFontJson->ToString().c_str());
1140 json->Put("copyOption",
1141 ConvertCopyOptionsToString(textFieldLayoutProperty->GetCopyOptionsValue(CopyOptions::None)).c_str());
1142 auto maxLength = GetMaxLength();
1143 json->Put("maxLength", GreatOrEqual(maxLength, Infinity<uint32_t>()) ? "INF" : std::to_string(maxLength).c_str());
1144 json->Put("type", textFieldPattern->TextInputTypeToString().c_str());
1145 textFieldLayoutProperty->HasCopyOptions();
1146 }
1147
ToJsonValueForSearchIcon(std::unique_ptr<JsonValue> & json) const1148 void SearchPattern::ToJsonValueForSearchIcon(std::unique_ptr<JsonValue>& json) const
1149 {
1150 auto host = GetHost();
1151 CHECK_NULL_VOID(host);
1152 auto imageFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(IMAGE_INDEX));
1153 CHECK_NULL_VOID(imageFrameNode);
1154 auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
1155 CHECK_NULL_VOID(imageLayoutProperty);
1156 auto searchIconJson = JsonUtil::Create(true);
1157
1158 // icon size
1159 auto searchIconGeometryNode = imageFrameNode->GetGeometryNode();
1160 CHECK_NULL_VOID(searchIconGeometryNode);
1161 auto searchIconFrameSize = searchIconGeometryNode->GetFrameSize().Width();
1162 auto searchLayoutProperty = host->GetLayoutProperty<SearchLayoutProperty>();
1163 CHECK_NULL_VOID(searchLayoutProperty);
1164 auto searchIconSize = searchLayoutProperty->GetSearchIconUDSizeValue(Dimension(searchIconFrameSize)).ConvertToPx();
1165 searchIconJson->Put("size", Dimension(searchIconSize, DimensionUnit::PX).ToString().c_str());
1166
1167 // icon color
1168 auto searchIconColor = imageLayoutProperty->GetImageSourceInfo()->GetFillColor().value_or(Color());
1169 searchIconJson->Put("color", searchIconColor.ColorToString().c_str());
1170
1171 // icon path
1172 auto searchIconPath = imageLayoutProperty->GetImageSourceInfo()->GetSrc();
1173 searchIconJson->Put("src", searchIconPath.c_str());
1174 json->Put("icon", searchIconPath.c_str());
1175 json->Put("searchIcon", searchIconJson);
1176 }
1177
ToJsonValueForCancelButton(std::unique_ptr<JsonValue> & json) const1178 void SearchPattern::ToJsonValueForCancelButton(std::unique_ptr<JsonValue>& json) const
1179 {
1180 auto host = GetHost();
1181 CHECK_NULL_VOID(host);
1182 auto layoutProperty = host->GetLayoutProperty<SearchLayoutProperty>();
1183 CHECK_NULL_VOID(layoutProperty);
1184 auto cancelImageFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(CANCEL_IMAGE_INDEX));
1185 CHECK_NULL_VOID(cancelImageFrameNode);
1186 auto cancelImageLayoutProperty = cancelImageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
1187 CHECK_NULL_VOID(cancelImageLayoutProperty);
1188 auto cancelButtonJson = JsonUtil::Create(true);
1189
1190 // style
1191 if (layoutProperty->GetCancelButtonStyle() == CancelButtonStyle::CONSTANT) {
1192 cancelButtonJson->Put("style", "CancelButtonStyle.CONSTANT");
1193 } else if (layoutProperty->GetCancelButtonStyle() == CancelButtonStyle::INVISIBLE) {
1194 cancelButtonJson->Put("style", "CancelButtonStyle.INVISIBLE");
1195 } else {
1196 cancelButtonJson->Put("style", "CancelButtonStyle.INPUT");
1197 }
1198
1199 auto cancelIconJson = JsonUtil::Create(true);
1200
1201 // icon size
1202 auto cancelIconGeometryNode = cancelImageFrameNode->GetGeometryNode();
1203 CHECK_NULL_VOID(cancelIconGeometryNode);
1204 auto cancelIconFrameSize = cancelIconGeometryNode->GetFrameSize().Width();
1205 auto searchLayoutProperty = host->GetLayoutProperty<SearchLayoutProperty>();
1206 CHECK_NULL_VOID(searchLayoutProperty);
1207 auto cancelIconSize =
1208 searchLayoutProperty->GetCancelButtonUDSizeValue(Dimension(cancelIconFrameSize)).ConvertToPx();
1209 cancelIconJson->Put("size", Dimension(cancelIconSize, DimensionUnit::PX).ToString().c_str());
1210
1211 // icon color
1212 auto cancelImageRenderProperty = cancelImageFrameNode->GetPaintProperty<ImageRenderProperty>();
1213 CHECK_NULL_VOID(cancelImageRenderProperty);
1214 auto cancelIconColor = cancelImageRenderProperty->GetSvgFillColor().value_or(Color());
1215 cancelIconJson->Put("color", cancelIconColor.ColorToString().c_str());
1216
1217 // right icon src path
1218 auto cancelImageSrc = cancelImageLayoutProperty->GetImageSourceInfo()->GetSrc();
1219 cancelIconJson->Put("src", cancelImageSrc.c_str());
1220 cancelButtonJson->Put("icon", cancelIconJson);
1221 json->Put("cancelButton", cancelButtonJson);
1222 }
1223
ToJsonValueForSearchButtonOption(std::unique_ptr<JsonValue> & json) const1224 void SearchPattern::ToJsonValueForSearchButtonOption(std::unique_ptr<JsonValue>& json) const
1225 {
1226 auto host = GetHost();
1227 CHECK_NULL_VOID(host);
1228 auto searchButtonFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(BUTTON_INDEX));
1229 CHECK_NULL_VOID(searchButtonFrameNode);
1230 auto searchButtonLayoutProperty = searchButtonFrameNode->GetLayoutProperty<ButtonLayoutProperty>();
1231 CHECK_NULL_VOID(searchButtonLayoutProperty);
1232 auto searchButtonJson = JsonUtil::Create(true);
1233
1234 // font size
1235 auto searchButtonFontSize = searchButtonLayoutProperty->GetFontSize().value_or(Dimension(0, DimensionUnit::VP));
1236 searchButtonJson->Put("fontSize", searchButtonFontSize.ToString().c_str());
1237
1238 // font color
1239 auto searchButtonFontColor = searchButtonLayoutProperty->GetFontColor().value_or(Color());
1240 searchButtonJson->Put("fontColor", searchButtonFontColor.ColorToString().c_str());
1241 json->Put("searchButtonOption", searchButtonJson);
1242 }
1243
ToJsonValueForCursor(std::unique_ptr<JsonValue> & json) const1244 void SearchPattern::ToJsonValueForCursor(std::unique_ptr<JsonValue>& json) const
1245 {
1246 auto host = GetHost();
1247 CHECK_NULL_VOID(host);
1248 auto textFieldFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(TEXTFIELD_INDEX));
1249 CHECK_NULL_VOID(textFieldFrameNode);
1250 auto textFieldPaintProperty = textFieldFrameNode->GetPaintProperty<TextFieldPaintProperty>();
1251 CHECK_NULL_VOID(textFieldPaintProperty);
1252 auto cursorJson = JsonUtil::Create(true);
1253
1254 // color
1255 auto caretColor = textFieldPaintProperty->GetCursorColor().value_or(Color());
1256 cursorJson->Put("color", caretColor.ColorToString().c_str());
1257 auto caretWidth = textFieldPaintProperty->GetCursorWidth().value_or(Dimension(0, DimensionUnit::VP));
1258 cursorJson->Put("width", caretWidth.ToString().c_str());
1259 json->Put("caretStyle", cursorJson);
1260 }
1261
ToJsonValue(std::unique_ptr<JsonValue> & json) const1262 void SearchPattern::ToJsonValue(std::unique_ptr<JsonValue>& json) const
1263 {
1264 Pattern::ToJsonValue(json);
1265
1266 ToJsonValueForTextField(json);
1267 ToJsonValueForSearchIcon(json);
1268 ToJsonValueForCancelButton(json);
1269 ToJsonValueForCursor(json);
1270 ToJsonValueForSearchButtonOption(json);
1271 }
1272
OnColorConfigurationUpdate()1273 void SearchPattern::OnColorConfigurationUpdate()
1274 {
1275 auto host = GetHost();
1276 CHECK_NULL_VOID(host);
1277 host->SetNeedCallChildrenUpdate(false);
1278 auto pipeline = PipelineBase::GetCurrentContext();
1279 CHECK_NULL_VOID(pipeline);
1280 auto textFieldTheme = pipeline->GetTheme<TextFieldTheme>();
1281 CHECK_NULL_VOID(textFieldTheme);
1282 auto renderContext = host->GetRenderContext();
1283 CHECK_NULL_VOID(renderContext);
1284 renderContext->UpdateBackgroundColor(textFieldTheme->GetBgColor());
1285 CHECK_NULL_VOID(pipeline);
1286 auto searchTheme = pipeline->GetTheme<SearchTheme>();
1287 CHECK_NULL_VOID(searchTheme);
1288 if (cancelButtonNode_) {
1289 auto cancelButtonRenderContext = cancelButtonNode_->GetRenderContext();
1290 CHECK_NULL_VOID(cancelButtonRenderContext);
1291 cancelButtonRenderContext->UpdateBackgroundColor(Color::TRANSPARENT);
1292 auto textFrameNode = AceType::DynamicCast<FrameNode>(cancelButtonNode_->GetChildren().front());
1293 CHECK_NULL_VOID(textFrameNode);
1294 auto textLayoutProperty = textFrameNode->GetLayoutProperty<TextLayoutProperty>();
1295 CHECK_NULL_VOID(textLayoutProperty);
1296 textLayoutProperty->UpdateTextColor(searchTheme->GetSearchButtonTextColor());
1297 cancelButtonNode_->MarkModifyDone();
1298 cancelButtonNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1299 }
1300 if (buttonNode_) {
1301 auto buttonRenderContext = buttonNode_->GetRenderContext();
1302 CHECK_NULL_VOID(buttonRenderContext);
1303 buttonRenderContext->UpdateBackgroundColor(Color::TRANSPARENT);
1304 auto textFrameNode = AceType::DynamicCast<FrameNode>(buttonNode_->GetChildren().front());
1305 CHECK_NULL_VOID(textFrameNode);
1306 auto textLayoutProperty = textFrameNode->GetLayoutProperty<TextLayoutProperty>();
1307 CHECK_NULL_VOID(textLayoutProperty);
1308 textLayoutProperty->UpdateTextColor(searchTheme->GetSearchButtonTextColor());
1309 buttonNode_->MarkModifyDone();
1310 buttonNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1311 }
1312 if (textField_) {
1313 auto textFieldLayoutProperty = textField_->GetLayoutProperty<TextFieldLayoutProperty>();
1314 CHECK_NULL_VOID(textFieldLayoutProperty);
1315 textFieldLayoutProperty->UpdateTextColor(searchTheme->GetTextColor());
1316 textFieldLayoutProperty->UpdatePlaceholderTextColor(searchTheme->GetPlaceholderColor());
1317 textField_->MarkModifyDone();
1318 textField_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1319 }
1320 }
1321
GetMaxLength() const1322 uint32_t SearchPattern::GetMaxLength() const
1323 {
1324 auto host = GetHost();
1325 CHECK_NULL_RETURN(host, Infinity<uint32_t>());
1326 auto textFieldFrameNode = DynamicCast<FrameNode>(host->GetChildAtIndex(TEXTFIELD_INDEX));
1327 CHECK_NULL_RETURN(textFieldFrameNode, Infinity<uint32_t>());
1328 auto textFieldLayoutProperty = textFieldFrameNode->GetLayoutProperty<TextFieldLayoutProperty>();
1329 CHECK_NULL_RETURN(textFieldLayoutProperty, Infinity<uint32_t>());
1330 return textFieldLayoutProperty->HasMaxLength() ? textFieldLayoutProperty->GetMaxLengthValue(Infinity<uint32_t>())
1331 : Infinity<uint32_t>();
1332 }
1333
1334 } // namespace OHOS::Ace::NG
1335