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