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