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