• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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