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