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