1 /*
2 * Copyright (c) 2022 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/select_overlay/select_overlay_pattern.h"
17
18 #include <algorithm>
19
20 #include "base/geometry/dimension.h"
21 #include "base/geometry/dimension_rect.h"
22 #include "base/geometry/ng/offset_t.h"
23 #include "base/geometry/ng/point_t.h"
24 #include "base/geometry/ng/rect_t.h"
25 #include "base/geometry/offset.h"
26 #include "base/utils/utils.h"
27 #include "core/components/menu/menu_component.h"
28 #include "core/components/text_overlay/text_overlay_theme.h"
29 #include "core/components_ng/base/ui_node.h"
30 #include "core/components_ng/pattern/menu/menu_layout_property.h"
31 #include "core/components_ng/pattern/select_overlay/select_overlay_node.h"
32 #include "core/components_ng/pattern/select_overlay/select_overlay_property.h"
33 #include "core/components_ng/property/property.h"
34 #include "core/components_ng/property/safe_area_insets.h"
35 #include "core/pipeline/base/constants.h"
36 #include "core/pipeline_ng/pipeline_context.h"
37
38 namespace OHOS::Ace::NG {
39 namespace {
40 constexpr uint32_t HIDDEN_HANDLE_TIMER_MS = 4000; // 4000ms
41 } // namespace
42
OnAttachToFrameNode()43 void SelectOverlayPattern::OnAttachToFrameNode()
44 {
45 auto host = GetHost();
46 CHECK_NULL_VOID(host);
47 host->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT);
48 host->GetLayoutProperty()->UpdateAlignment(Alignment::TOP_LEFT);
49
50 UpdateHandleHotZone();
51 auto gesture = host->GetOrCreateGestureEventHub();
52 if (overlayMode_ == SelectOverlayMode::MENU_ONLY) {
53 gesture->SetHitTestMode(HitTestMode::HTMTRANSPARENT_SELF);
54 return;
55 }
56 gesture->SetHitTestMode(info_->hitTestMode);
57 SetGestureEvent();
58 if (info_->isSingleHandle) {
59 StartHiddenHandleTask();
60 }
61 }
62
SetGestureEvent()63 void SelectOverlayPattern::SetGestureEvent()
64 {
65 auto host = GetHost();
66 CHECK_NULL_VOID(host);
67 auto gesture = host->GetOrCreateGestureEventHub();
68 clickEvent_ = MakeRefPtr<ClickEvent>([weak = WeakClaim(this)](GestureEvent& info) {
69 auto pattern = weak.Upgrade();
70 CHECK_NULL_VOID(pattern);
71 pattern->HandleOnClick(info);
72 });
73 gesture->AddClickEvent(clickEvent_);
74 auto panStart = [weak = WeakClaim(this)](GestureEvent& info) {
75 auto pattern = weak.Upgrade();
76 CHECK_NULL_VOID(pattern);
77 pattern->HandlePanStart(info);
78 };
79 auto panUpdate = [weak = WeakClaim(this)](GestureEvent& info) {
80 auto pattern = weak.Upgrade();
81 CHECK_NULL_VOID(pattern);
82 pattern->HandlePanMove(info);
83 };
84 auto panEnd = [weak = WeakClaim(this)](GestureEvent& info) {
85 auto pattern = weak.Upgrade();
86 CHECK_NULL_VOID(pattern);
87 pattern->HandlePanEnd(info);
88 };
89 auto panCancel = [weak = WeakClaim(this)]() {
90 auto pattern = weak.Upgrade();
91 CHECK_NULL_VOID(pattern);
92 pattern->HandlePanCancel();
93 };
94 panEvent_ =
95 MakeRefPtr<PanEvent>(std::move(panStart), std::move(panUpdate), std::move(panEnd), std::move(panCancel));
96 gesture->AddPanEvent(panEvent_, { PanDirection::ALL }, 1, DEFAULT_PAN_DISTANCE);
97
98 auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
99 auto pattern = weak.Upgrade();
100 if (pattern) {
101 pattern->HandleTouchEvent(info);
102 }
103 };
104 touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
105 gesture->AddTouchEvent(touchEvent_);
106 InitMouseEvent();
107 }
108
InitMouseEvent()109 void SelectOverlayPattern::InitMouseEvent()
110 {
111 auto host = GetHost();
112 CHECK_NULL_VOID(host);
113 auto eventHub = host->GetEventHub<EventHub>();
114 CHECK_NULL_VOID(eventHub);
115 auto inputHub = eventHub->GetOrCreateInputEventHub();
116 CHECK_NULL_VOID(inputHub);
117 auto mouseTask = [weak = WeakClaim(this)](MouseInfo& info) {
118 auto pattern = weak.Upgrade();
119 CHECK_NULL_VOID(pattern);
120 pattern->HandleMouseEvent(info);
121 };
122 auto mouseEvent = MakeRefPtr<InputEvent>(std::move(mouseTask));
123 inputHub->AddOnMouseEvent(mouseEvent);
124 }
125
OnDetachFromFrameNode(FrameNode *)126 void SelectOverlayPattern::OnDetachFromFrameNode(FrameNode* /*frameNode*/)
127 {
128 CHECK_NULL_VOID(info_);
129 if (info_->onClose) {
130 info_->onClose(closedByGlobalTouchEvent_);
131 closedByGlobalTouchEvent_ = false;
132 }
133 }
134
AddMenuResponseRegion(std::vector<DimensionRect> & responseRegion)135 void SelectOverlayPattern::AddMenuResponseRegion(std::vector<DimensionRect>& responseRegion)
136 {
137 auto layoutProps = GetLayoutProperty<LayoutProperty>();
138 CHECK_NULL_VOID(layoutProps);
139 float safeAreaInsetsLeft = 0.0f;
140 float safeAreaInsetsTop = 0.0f;
141 auto&& safeAreaInsets = layoutProps->GetSafeAreaInsets();
142 if (safeAreaInsets) {
143 safeAreaInsetsLeft = static_cast<float>(safeAreaInsets->left_.end);
144 safeAreaInsetsTop = static_cast<float>(safeAreaInsets->top_.end);
145 }
146 const auto& children = GetHost()->GetChildren();
147 for (const auto& it : children) {
148 auto child = DynamicCast<FrameNode>(it);
149 if (child == nullptr) {
150 continue;
151 }
152 auto frameRect = child->GetGeometryNode()->GetFrameRect();
153 // rect is relative to window
154 auto rect = Rect(frameRect.GetX() + safeAreaInsetsLeft, frameRect.GetY() + safeAreaInsetsTop, frameRect.Width(),
155 frameRect.Height());
156
157 DimensionRect region;
158 region.SetSize({ Dimension(rect.GetSize().Width()), Dimension(rect.GetSize().Height()) });
159 region.SetOffset(DimensionOffset(Offset(rect.GetOffset().GetX(), rect.GetOffset().GetY())));
160
161 responseRegion.emplace_back(region);
162 }
163 }
164
UpdateHandleHotZone()165 void SelectOverlayPattern::UpdateHandleHotZone()
166 {
167 if (!CheckIfNeedHandle()) {
168 return;
169 }
170 auto host = GetHost();
171 CHECK_NULL_VOID(host);
172 auto pipeline = host->GetContext();
173 CHECK_NULL_VOID(pipeline);
174 auto firstHandle = info_->GetFirstHandlePaintRect();
175 auto secondHandle = info_->GetSecondHandlePaintRect();
176
177 auto theme = pipeline->GetTheme<TextOverlayTheme>();
178 CHECK_NULL_VOID(theme);
179 auto hotZone = theme->GetHandleHotZoneRadius().ConvertToPx();
180 firstHandleRegion_.SetSize({ hotZone * 2, hotZone * 2 + firstHandle.Height() });
181 auto firstHandleOffsetX = (firstHandle.Left() + firstHandle.Right()) / 2;
182 secondHandleRegion_.SetSize({ hotZone * 2, hotZone * 2 + secondHandle.Height() });
183 auto secondHandleOffsetX = (secondHandle.Left() + secondHandle.Right()) / 2;
184 std::vector<DimensionRect> responseRegion;
185 if (info_->isSingleHandle) {
186 if (!info_->firstHandle.isShow && info_->secondHandle.isShow) {
187 // Use the second handle to make a single handle.
188 auto secondHandleOffsetY = secondHandle.Top();
189 secondHandleRegion_.SetOffset({ secondHandleOffsetX - hotZone, secondHandleOffsetY });
190 DimensionRect secondHandleRegion;
191 secondHandleRegion.SetSize({ Dimension(secondHandleRegion_.GetSize().Width()),
192 Dimension(secondHandleRegion_.GetSize().Height()) });
193 secondHandleRegion.SetOffset(DimensionOffset(
194 Offset(secondHandleRegion_.GetOffset().GetX(), secondHandleRegion_.GetOffset().GetY())));
195 responseRegion.emplace_back(secondHandleRegion);
196 host->GetOrCreateGestureEventHub()->SetResponseRegion(responseRegion);
197 firstHandleRegion_.Reset();
198 } else {
199 // Use the first handle to make a single handle.
200 auto firstHandleOffsetY = firstHandle.Top();
201 firstHandleRegion_.SetOffset({ firstHandleOffsetX - hotZone, firstHandleOffsetY });
202 DimensionRect firstHandleRegion;
203 firstHandleRegion.SetSize(
204 { Dimension(firstHandleRegion_.GetSize().Width()), Dimension(firstHandleRegion_.GetSize().Height()) });
205 firstHandleRegion.SetOffset(
206 DimensionOffset(Offset(firstHandleRegion_.GetOffset().GetX(), firstHandleRegion_.GetOffset().GetY())));
207 responseRegion.emplace_back(firstHandleRegion);
208 host->GetOrCreateGestureEventHub()->SetResponseRegion(responseRegion);
209 secondHandleRegion_.Reset();
210 }
211 return;
212 }
213 if (info_->handleReverse) {
214 auto firstHandleOffsetY = firstHandle.Top();
215 firstHandleRegion_.SetOffset({ firstHandleOffsetX - hotZone, firstHandleOffsetY });
216 auto secondHandleOffsetY = secondHandle.Top();
217 secondHandleRegion_.SetOffset({ secondHandleOffsetX - hotZone, secondHandleOffsetY - hotZone * 2 });
218 } else {
219 auto firstHandleOffsetY = firstHandle.Top();
220 firstHandleRegion_.SetOffset({ firstHandleOffsetX - hotZone, firstHandleOffsetY - hotZone * 2 });
221 auto secondHandleOffsetY = secondHandle.Top();
222 secondHandleRegion_.SetOffset({ secondHandleOffsetX - hotZone, secondHandleOffsetY });
223 }
224 DimensionRect firstHandleRegion;
225 firstHandleRegion.SetSize(
226 { Dimension(firstHandleRegion_.GetSize().Width()), Dimension(firstHandleRegion_.GetSize().Height()) });
227 firstHandleRegion.SetOffset(
228 DimensionOffset(Offset(firstHandleRegion_.GetOffset().GetX(), firstHandleRegion_.GetOffset().GetY())));
229 responseRegion.emplace_back(firstHandleRegion);
230 DimensionRect secondHandleRegion;
231 secondHandleRegion.SetSize(
232 { Dimension(secondHandleRegion_.GetSize().Width()), Dimension(secondHandleRegion_.GetSize().Height()) });
233 secondHandleRegion.SetOffset(
234 DimensionOffset(Offset(secondHandleRegion_.GetOffset().GetX(), secondHandleRegion_.GetOffset().GetY())));
235 responseRegion.emplace_back(secondHandleRegion);
236 if (IsCustomMenu()) {
237 AddMenuResponseRegion(responseRegion);
238 }
239 host->GetOrCreateGestureEventHub()->SetResponseRegion(responseRegion);
240 }
241
HandleOnClick(GestureEvent & info)242 void SelectOverlayPattern::HandleOnClick(GestureEvent& info)
243 {
244 if (info_->onClick) {
245 info_->onClick(info, isFirstHandleTouchDown_);
246 }
247 if (!info_->isSingleHandle) {
248 return;
249 }
250 auto host = DynamicCast<SelectOverlayNode>(GetHost());
251 CHECK_NULL_VOID(host);
252 if (!info_->menuInfo.menuDisable) {
253 info_->menuInfo.menuIsShow = !info_->menuInfo.menuIsShow;
254 host->UpdateToolBar(false);
255
256 StopHiddenHandleTask();
257 StartHiddenHandleTask();
258 info_->menuInfo.singleHandleMenuIsShow = info_->menuInfo.menuIsShow;
259 }
260 if (info_->afterOnClick) {
261 info_->afterOnClick(info, isFirstHandleTouchDown_);
262 }
263 }
264
HandleTouchEvent(const TouchEventInfo & info)265 void SelectOverlayPattern::HandleTouchEvent(const TouchEventInfo& info)
266 {
267 const auto& changedPoint = info.GetChangedTouches().front();
268 if (changedPoint.GetTouchType() == TouchType::DOWN) {
269 HandleTouchDownEvent(info);
270 } else if (info_->onTouchDown && changedPoint.GetTouchType() == TouchType::UP) {
271 info_->onTouchUp(info);
272 } else if (info_->onTouchMove && changedPoint.GetTouchType() == TouchType::MOVE) {
273 info_->onTouchMove(info);
274 }
275 if (IsCustomMenu()) {
276 MenuWrapperPattern::OnTouchEvent(info);
277 }
278 if (changedPoint.GetTouchType() == TouchType::UP) {
279 SwitchHandleToOverlayMode(false);
280 }
281 }
282
HandleTouchDownEvent(const TouchEventInfo & info)283 void SelectOverlayPattern::HandleTouchDownEvent(const TouchEventInfo& info)
284 {
285 if (info_->onTouchDown) {
286 info_->onTouchDown(info);
287 }
288 auto touchOffset = info.GetChangedTouches().front().GetLocalLocation();
289 PointF point = { touchOffset.GetX(), touchOffset.GetY() };
290 if (firstHandleRegion_.IsInRegion(point)) {
291 isFirstHandleTouchDown_ = true;
292 } else if (secondHandleRegion_.IsInRegion(point)) {
293 isSecondHandleTouchDown_ = true;
294 }
295 }
296
HandlePanStart(GestureEvent & info)297 void SelectOverlayPattern::HandlePanStart(GestureEvent& info)
298 {
299 if (info.GetSourceDevice() == SourceType::MOUSE) {
300 return;
301 }
302 if (!isFirstHandleTouchDown_ && !isSecondHandleTouchDown_) {
303 LOGW("no handle is pressed");
304 return;
305 }
306 if (IsFirstHandleMoveStart(info.GetLocalLocation())) {
307 firstHandleDrag_ = true;
308 secondHandleDrag_ = false;
309 if (info_->onHandleMoveStart) {
310 info_->onHandleMoveStart(info, firstHandleDrag_);
311 }
312 } else {
313 firstHandleDrag_ = false;
314 secondHandleDrag_ = true;
315 if (info_->onHandleMoveStart) {
316 info_->onHandleMoveStart(info, firstHandleDrag_);
317 }
318 }
319
320 auto host = DynamicCast<SelectOverlayNode>(GetHost());
321 CHECK_NULL_VOID(host);
322 orignMenuIsShow_ = info_->menuInfo.menuIsShow;
323 if (info_->menuInfo.menuIsShow) {
324 info_->menuInfo.menuIsShow = false;
325 host->UpdateToolBar(false);
326 }
327 if (info_->isSingleHandle) {
328 StopHiddenHandleTask();
329 }
330 isFirstHandleTouchDown_ = false;
331 isSecondHandleTouchDown_ = false;
332 SwitchHandleToOverlayMode(true);
333 }
334
HandlePanMove(GestureEvent & info)335 void SelectOverlayPattern::HandlePanMove(GestureEvent& info)
336 {
337 auto host = DynamicCast<SelectOverlayNode>(GetHost());
338 CHECK_NULL_VOID(host);
339 const auto& offset = OffsetF(info.GetDelta().GetX(), info.GetDelta().GetY());
340 if (firstHandleDrag_) {
341 if (info_->onHandlePanMove) {
342 info_->onHandlePanMove(info, true);
343 }
344 UpdateOffsetOnMove(firstHandleRegion_, info_->firstHandle, offset, true);
345 } else if (secondHandleDrag_) {
346 if (info_->onHandlePanMove) {
347 info_->onHandlePanMove(info, false);
348 }
349 UpdateOffsetOnMove(secondHandleRegion_, info_->secondHandle, offset, false);
350 } else {
351 LOGW("the move point is not in drag area");
352 }
353 auto context = host->GetContext();
354 CHECK_NULL_VOID(context);
355 if (host->IsLayoutDirtyMarked()) {
356 context->AddDirtyLayoutNode(host);
357 }
358 }
359
UpdateOffsetOnMove(RectF & region,SelectHandleInfo & handleInfo,const OffsetF & offset,bool isFirst)360 void SelectOverlayPattern::UpdateOffsetOnMove(
361 RectF& region, SelectHandleInfo& handleInfo, const OffsetF& offset, bool isFirst)
362 {
363 auto host = DynamicCast<SelectOverlayNode>(GetHost());
364 CHECK_NULL_VOID(host);
365 region += offset;
366 handleInfo.paintRect += offset;
367 handleInfo.localPaintRect += offset;
368 auto isOverlayMode = info_->handleLevelMode == HandleLevelMode::OVERLAY;
369 if (!isOverlayMode && info_->getDeltaHandleOffset) {
370 handleInfo.localPaintRect += info_->getDeltaHandleOffset();
371 }
372 auto paintRect = isOverlayMode ? handleInfo.paintRect : handleInfo.localPaintRect;
373 handleInfo.paintInfo = handleInfo.paintInfo + offset;
374 if (isOverlayMode && handleInfo.isPaintHandleWithPoints && handleInfo.paintInfoConverter) {
375 paintRect = handleInfo.paintInfoConverter(handleInfo.paintInfo);
376 }
377 CheckHandleReverse();
378 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
379 if (info_->onHandleMove) {
380 info_->onHandleMove(paintRect, isFirst);
381 }
382 }
383
HandlePanEnd(GestureEvent & info)384 void SelectOverlayPattern::HandlePanEnd(GestureEvent& info)
385 {
386 auto host = DynamicCast<SelectOverlayNode>(GetHost());
387 CHECK_NULL_VOID(host);
388 if (!info_->menuInfo.menuIsShow &&
389 (!info_->menuCallback.showMenuOnMoveDone || info_->menuCallback.showMenuOnMoveDone())) {
390 info_->menuInfo.menuIsShow = orignMenuIsShow_;
391 host->UpdateToolBar(false);
392 }
393 if (firstHandleDrag_) {
394 firstHandleDrag_ = false;
395 if (info_->onHandlePanEnd) {
396 info_->onHandlePanEnd(info, true);
397 }
398 if (info_->onHandleMoveDone) {
399 auto paintRect = GetHandlePaintRect(info_->firstHandle);
400 info_->onHandleMoveDone(paintRect, true);
401 }
402 } else if (secondHandleDrag_) {
403 secondHandleDrag_ = false;
404 if (info_->onHandlePanEnd) {
405 info_->onHandlePanEnd(info, false);
406 }
407 if (info_->onHandleMoveDone) {
408 auto paintRect = GetHandlePaintRect(info_->secondHandle);
409 info_->onHandleMoveDone(paintRect, false);
410 }
411 }
412 if (info_->isSingleHandle) {
413 StartHiddenHandleTask();
414 }
415 }
416
GetHandlePaintRect(const SelectHandleInfo & handleInfo)417 RectF SelectOverlayPattern::GetHandlePaintRect(const SelectHandleInfo& handleInfo)
418 {
419 auto paintRect = handleInfo.paintRect;
420 if (info_->handleLevelMode == HandleLevelMode::OVERLAY && handleInfo.isPaintHandleWithPoints &&
421 handleInfo.paintInfoConverter) {
422 paintRect = handleInfo.paintInfoConverter(handleInfo.paintInfo);
423 }
424 return paintRect;
425 }
426
HandlePanCancel()427 void SelectOverlayPattern::HandlePanCancel()
428 {
429 GestureEvent info;
430 HandlePanEnd(info);
431 }
432
HandleMouseEvent(const MouseInfo & info)433 void SelectOverlayPattern::HandleMouseEvent(const MouseInfo& info)
434 {
435 if (info_->onMouseEvent) {
436 info_->onMouseEvent(info);
437 }
438 }
439
CheckHandleReverse()440 void SelectOverlayPattern::CheckHandleReverse()
441 {
442 bool handleReverseChanged = false;
443 if (IsHandlesInSameLine()) {
444 if (info_->firstHandle.paintRect.Left() > info_->secondHandle.paintRect.Left()) {
445 if (!info_->handleReverse) {
446 info_->handleReverse = true;
447 handleReverseChanged = true;
448 }
449 } else {
450 if (info_->handleReverse) {
451 info_->handleReverse = false;
452 handleReverseChanged = true;
453 }
454 }
455 } else if (GreatNotEqual(info_->firstHandle.paintRect.Top(), info_->secondHandle.paintRect.Top())) {
456 if (!info_->handleReverse) {
457 info_->handleReverse = true;
458 handleReverseChanged = true;
459 }
460 } else {
461 if (info_->handleReverse) {
462 info_->handleReverse = false;
463 handleReverseChanged = true;
464 }
465 }
466 if (handleReverseChanged && info_->onHandleReverse) {
467 info_->onHandleReverse(info_->handleReverse);
468 }
469 }
470
IsHandlesInSameLine()471 bool SelectOverlayPattern::IsHandlesInSameLine()
472 {
473 float lowerHandleTop = 0.0f;
474 RectF heigherHandleRect;
475 if (GreatNotEqual(info_->firstHandle.paintRect.Top(), info_->secondHandle.paintRect.Top())) {
476 lowerHandleTop = info_->firstHandle.paintRect.Top() + 0.5f;
477 heigherHandleRect = info_->secondHandle.paintRect;
478 } else {
479 lowerHandleTop = info_->secondHandle.paintRect.Top() + 0.5f;
480 heigherHandleRect = info_->firstHandle.paintRect;
481 }
482 return GreatNotEqual(lowerHandleTop, heigherHandleRect.Top())
483 && LessNotEqual(lowerHandleTop, heigherHandleRect.Bottom());
484 }
485
IsFirstHandleMoveStart(const Offset & touchOffset)486 bool SelectOverlayPattern::IsFirstHandleMoveStart(const Offset& touchOffset)
487 {
488 if (isFirstHandleTouchDown_ && isSecondHandleTouchDown_) {
489 auto firstHandleCenter = Offset{ firstHandleRegion_.Center().GetX(), firstHandleRegion_.Center().GetY() };
490 auto secondHandleCenter = Offset{ secondHandleRegion_.Center().GetX(), secondHandleRegion_.Center().GetY() };
491 auto distanceToFirstHandle = (firstHandleCenter - touchOffset).GetDistance();
492 auto distanceToSecondHandle = (secondHandleCenter - touchOffset).GetDistance();
493 return GreatNotEqual(distanceToSecondHandle, distanceToFirstHandle);
494 }
495 return isFirstHandleTouchDown_;
496 }
497
SetHandleReverse(bool reverse)498 void SelectOverlayPattern::SetHandleReverse(bool reverse)
499 {
500 info_->handleReverse = reverse;
501 UpdateHandleHotZone();
502 auto host = DynamicCast<SelectOverlayNode>(GetHost());
503 CHECK_NULL_VOID(host);
504 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
505 }
506
SetSelectRegionVisible(bool isSelectRegionVisible)507 void SelectOverlayPattern::SetSelectRegionVisible(bool isSelectRegionVisible)
508 {
509 if (info_->isSelectRegionVisible != isSelectRegionVisible) {
510 info_->isSelectRegionVisible = isSelectRegionVisible;
511 auto host = DynamicCast<SelectOverlayNode>(GetHost());
512 CHECK_NULL_VOID(host);
513 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
514 }
515 }
516
UpdateFirstSelectHandleInfo(const SelectHandleInfo & info)517 void SelectOverlayPattern::UpdateFirstSelectHandleInfo(const SelectHandleInfo& info)
518 {
519 if (info_->firstHandle == info) {
520 return;
521 }
522 info_->firstHandle = info;
523 CheckHandleReverse();
524 UpdateHandleHotZone();
525 auto host = DynamicCast<SelectOverlayNode>(GetHost());
526 CHECK_NULL_VOID(host);
527 if (info.needLayout) {
528 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
529 } else {
530 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
531 }
532 }
533
UpdateSecondSelectHandleInfo(const SelectHandleInfo & info)534 void SelectOverlayPattern::UpdateSecondSelectHandleInfo(const SelectHandleInfo& info)
535 {
536 if (info_->secondHandle == info) {
537 return;
538 }
539 info_->secondHandle = info;
540 CheckHandleReverse();
541 UpdateHandleHotZone();
542 auto host = DynamicCast<SelectOverlayNode>(GetHost());
543 CHECK_NULL_VOID(host);
544 if (info.needLayout) {
545 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
546 } else {
547 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
548 }
549 }
550
UpdateFirstAndSecondHandleInfo(const SelectHandleInfo & firstInfo,const SelectHandleInfo & secondInfo)551 void SelectOverlayPattern::UpdateFirstAndSecondHandleInfo(
552 const SelectHandleInfo& firstInfo, const SelectHandleInfo& secondInfo)
553 {
554 if (info_->firstHandle == firstInfo && info_->secondHandle == secondInfo) {
555 return;
556 }
557 if (info_->firstHandle != firstInfo && !firstHandleDrag_) {
558 info_->firstHandle = firstInfo;
559 }
560 if (info_->secondHandle != secondInfo && !secondHandleDrag_) {
561 info_->secondHandle = secondInfo;
562 }
563 CheckHandleReverse();
564 UpdateHandleHotZone();
565 auto host = DynamicCast<SelectOverlayNode>(GetHost());
566 CHECK_NULL_VOID(host);
567 host->UpdateToolBar(false);
568 }
569
UpdateSelectMenuInfo(const SelectMenuInfo & info)570 void SelectOverlayPattern::UpdateSelectMenuInfo(const SelectMenuInfo& info)
571 {
572 auto host = DynamicCast<SelectOverlayNode>(GetHost());
573 CHECK_NULL_VOID(host);
574 auto itemChanged = info_->menuInfo.IsIconChanged(info);
575 info_->menuInfo = info;
576 host->UpdateToolBar(itemChanged);
577 }
578
UpdateShowArea(const RectF & area)579 void SelectOverlayPattern::UpdateShowArea(const RectF& area)
580 {
581 if (info_->showArea != area) {
582 info_->showArea = area;
583 }
584 auto host = GetHost();
585 CHECK_NULL_VOID(host);
586 host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
587 }
588
UpdateSelectMenuInfo(std::function<void (SelectMenuInfo & menuInfo)> updateAction)589 void SelectOverlayPattern::UpdateSelectMenuInfo(std::function<void(SelectMenuInfo& menuInfo)> updateAction)
590 {
591 if (updateAction) {
592 SelectMenuInfo shadowMenuInfo = info_->menuInfo;
593 updateAction(shadowMenuInfo);
594 UpdateSelectMenuInfo(shadowMenuInfo);
595 }
596 }
597
ShowOrHiddenMenu(bool isHidden,bool noAnimation)598 void SelectOverlayPattern::ShowOrHiddenMenu(bool isHidden, bool noAnimation)
599 {
600 auto host = DynamicCast<SelectOverlayNode>(GetHost());
601 CHECK_NULL_VOID(host);
602 if (info_->menuInfo.menuIsShow && isHidden) {
603 info_->menuInfo.menuIsShow = false;
604 host->UpdateToolBar(false, noAnimation);
605 } else if (!info_->menuInfo.menuIsShow && !isHidden &&
606 (info_->firstHandle.isShow || info_->secondHandle.isShow || info_->isSelectRegionVisible ||
607 (info_->isNewAvoid && !info_->isSingleHandle))) {
608 info_->menuInfo.menuIsShow = true;
609 host->UpdateToolBar(false, noAnimation);
610 }
611 }
612
DisableMenu(bool isDisabled)613 void SelectOverlayPattern::DisableMenu(bool isDisabled)
614 {
615 info_->menuInfo.menuDisable = isDisabled;
616 auto host = DynamicCast<SelectOverlayNode>(GetHost());
617 CHECK_NULL_VOID(host);
618 host->UpdateToolBar(false);
619 }
620
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)621 bool SelectOverlayPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
622 {
623 UpdateHandleHotZone();
624 if (config.skipMeasure || dirty->SkipMeasureContent()) {
625 return false;
626 }
627 auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
628 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
629 auto selectOverlayLayoutAlgorithm =
630 DynamicCast<SelectOverlayLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
631 CHECK_NULL_RETURN(selectOverlayLayoutAlgorithm, false);
632 defaultMenuStartOffset_ = selectOverlayLayoutAlgorithm->GetDefaultMenuStartOffset();
633 defaultMenuEndOffset_ = selectOverlayLayoutAlgorithm->GetDefaultMenuEndOffset();
634 menuWidth_ = selectOverlayLayoutAlgorithm->GetMenuWidth();
635 menuHeight_ = selectOverlayLayoutAlgorithm->GetMenuHeight();
636 hasExtensionMenu_ =
637 selectOverlayLayoutAlgorithm->GetHasExtensionMenu() && !selectOverlayLayoutAlgorithm->GetHideMoreOrBack();
638 if (IsCustomMenu()) {
639 MenuWrapperPattern::CheckAndShowAnimation();
640 }
641 return true;
642 }
643
IsMenuShow()644 bool SelectOverlayPattern::IsMenuShow()
645 {
646 CHECK_NULL_RETURN(info_, false);
647 return info_->menuInfo.menuIsShow;
648 }
649
IsSingleHandleMenuShow()650 bool SelectOverlayPattern::IsSingleHandleMenuShow()
651 {
652 CHECK_NULL_RETURN(info_, false);
653 return info_->menuInfo.singleHandleMenuIsShow;
654 }
655
IsHandleShow()656 bool SelectOverlayPattern::IsHandleShow()
657 {
658 CHECK_NULL_RETURN(info_, false);
659 return info_->firstHandle.isShow || info_->secondHandle.isShow;
660 }
661
IsSingleHandle()662 bool SelectOverlayPattern::IsSingleHandle()
663 {
664 CHECK_NULL_RETURN(info_, false);
665 return info_->isSingleHandle;
666 }
667
StartHiddenHandleTask(bool isDelay)668 void SelectOverlayPattern::StartHiddenHandleTask(bool isDelay)
669 {
670 auto host = GetHost();
671 CHECK_NULL_VOID(host);
672 auto context = host->GetContext();
673 CHECK_NULL_VOID(context);
674 auto taskExecutor = context->GetTaskExecutor();
675 CHECK_NULL_VOID(taskExecutor);
676 auto weak = WeakClaim(this);
677 hiddenHandleTask_.Reset([weak] {
678 auto client = weak.Upgrade();
679 CHECK_NULL_VOID(client);
680 client->HiddenHandle();
681 });
682 if (isDelay) {
683 taskExecutor->PostDelayedTask(hiddenHandleTask_, TaskExecutor::TaskType::UI, HIDDEN_HANDLE_TIMER_MS,
684 "ArkUISelectOverlayHiddenHandle");
685 } else {
686 taskExecutor->PostTask(hiddenHandleTask_, TaskExecutor::TaskType::UI, "ArkUISelectOverlayHiddenHandle");
687 }
688 }
689
HiddenHandle()690 void SelectOverlayPattern::HiddenHandle()
691 {
692 hiddenHandleTask_.Cancel();
693 isHiddenHandle_ = true;
694 if (info_->onHandleIsHidden) {
695 info_->onHandleIsHidden();
696 }
697 auto host = DynamicCast<SelectOverlayNode>(GetHost());
698 CHECK_NULL_VOID(host);
699 firstHandleRegion_.Reset();
700 secondHandleRegion_.Reset();
701 std::vector<DimensionRect> responseRegion;
702 host->GetOrCreateGestureEventHub()->SetResponseRegion(responseRegion);
703 host->GetOrCreateGestureEventHub()->SetHitTestMode(HitTestMode::HTMNONE);
704 host->GetOrCreateGestureEventHub()->RemoveClickEvent(clickEvent_);
705 host->GetOrCreateGestureEventHub()->RemovePanEvent(panEvent_);
706 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
707 }
708
StopHiddenHandleTask()709 void SelectOverlayPattern::StopHiddenHandleTask()
710 {
711 hiddenHandleTask_.Cancel();
712 }
713
UpdateSelectArea(const RectF & selectArea)714 void SelectOverlayPattern::UpdateSelectArea(const RectF& selectArea)
715 {
716 info_->selectArea = selectArea;
717 }
718
SetIsNewAvoid(bool isNewAvoid)719 void SelectOverlayPattern::SetIsNewAvoid(bool isNewAvoid)
720 {
721 info_->isNewAvoid = isNewAvoid;
722 }
723
SetSelectMenuHeight()724 void SelectOverlayPattern::SetSelectMenuHeight()
725 {
726 auto host = DynamicCast<SelectOverlayNode>(GetHost());
727 CHECK_NULL_VOID(host);
728 auto selectMenu = AceType::DynamicCast<FrameNode>(host->GetFirstChild());
729 CHECK_NULL_VOID(selectMenu);
730 auto geometryNode = selectMenu->GetGeometryNode();
731 CHECK_NULL_VOID(geometryNode);
732 selectMenuHeight_ = geometryNode->GetFrameSize().Height();
733 }
734
CheckIfNeedMenu()735 bool SelectOverlayPattern::CheckIfNeedMenu()
736 {
737 return (overlayMode_ == SelectOverlayMode::ALL || overlayMode_ == SelectOverlayMode::MENU_ONLY);
738 }
739
CheckIfNeedHandle()740 bool SelectOverlayPattern::CheckIfNeedHandle()
741 {
742 return (overlayMode_ == SelectOverlayMode::ALL || overlayMode_ == SelectOverlayMode::HANDLE_ONLY);
743 }
744
GetHandleDiameter()745 float SelectOverlayPattern::GetHandleDiameter()
746 {
747 auto pipleline = PipelineContext::GetCurrentContextSafely();
748 CHECK_NULL_RETURN(pipleline, 0.0f);
749 auto textOverlayTheme = pipleline->GetTheme<TextOverlayTheme>();
750 CHECK_NULL_RETURN(textOverlayTheme, 0.0f);
751 return textOverlayTheme->GetHandleDiameter().ConvertToPx();
752 }
753
SetContentModifierBounds(const RefPtr<SelectOverlayContentModifier> & modifier)754 void SelectOverlayPattern::SetContentModifierBounds(const RefPtr<SelectOverlayContentModifier>& modifier)
755 {
756 CHECK_NULL_VOID(modifier);
757 auto host = GetHost();
758 CHECK_NULL_VOID(host);
759 auto geometryNode = host->GetGeometryNode();
760 CHECK_NULL_VOID(geometryNode);
761 auto frameRect = geometryNode->GetFrameRect();
762 auto handleDiameter = GetHandleDiameter();
763 RectF boundsRect;
764 boundsRect.SetLeft(frameRect.Left() - handleDiameter * 1.5f);
765 boundsRect.SetTop(frameRect.Top() - handleDiameter * 1.5f);
766 boundsRect.SetWidth(frameRect.Width() + handleDiameter * 3.0f);
767 boundsRect.SetHeight(frameRect.Height() + handleDiameter * 3.0f);
768 modifier->SetBoundsRect(boundsRect);
769 }
770
OnDpiConfigurationUpdate()771 void SelectOverlayPattern::OnDpiConfigurationUpdate()
772 {
773 auto host = DynamicCast<SelectOverlayNode>(GetHost());
774 CHECK_NULL_VOID(host);
775 host->UpdateToolBar(true, true);
776 }
777
SwitchHandleToOverlayMode(bool afterRender)778 void SelectOverlayPattern::SwitchHandleToOverlayMode(bool afterRender)
779 {
780 if (!info_->enableHandleLevel || info_->handleLevelMode != HandleLevelMode::EMBED) {
781 return;
782 }
783 auto host = GetHost();
784 CHECK_NULL_VOID(host);
785 auto overlayNode = DynamicCast<SelectOverlayNode>(host);
786 CHECK_NULL_VOID(overlayNode);
787 auto switchTask = [weak = WeakClaim(AceType::RawPtr(overlayNode))]() {
788 auto overlayNode = weak.Upgrade();
789 CHECK_NULL_VOID(overlayNode);
790 if (overlayNode) {
791 overlayNode->SwitchToOverlayMode();
792 }
793 };
794 if (afterRender) {
795 auto pipeline = host->GetContext();
796 CHECK_NULL_VOID(pipeline);
797 pipeline->AddAfterRenderTask(switchTask);
798 } else {
799 switchTask();
800 }
801 }
802 } // namespace OHOS::Ace::NG
803