1 /* 2 * Copyright (c) 2022-2024 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/container_modal/container_modal_pattern.h" 17 18 #include "base/resource/internal_resource.h" 19 #include "base/subwindow/subwindow_manager.h" 20 #include "base/utils/utils.h" 21 #include "core/common/container.h" 22 #include "core/common/container_scope.h" 23 #include "core/components_ng/pattern/button/button_event_hub.h" 24 #include "core/components_ng/pattern/container_modal/container_modal_theme.h" 25 #include "core/components_ng/pattern/button/button_layout_property.h" 26 #include "core/components_ng/pattern/image/image_layout_property.h" 27 #include "core/components_ng/pattern/linear_layout/linear_layout_property.h" 28 #include "core/components_ng/pattern/text/text_layout_property.h" 29 #include "core/image/image_source_info.h" 30 31 namespace OHOS::Ace::NG { 32 33 namespace { 34 constexpr int32_t LEFT_SPLIT_BUTTON_INDEX = 0; 35 constexpr int32_t MAX_RECOVER_BUTTON_INDEX = 1; 36 constexpr int32_t MINIMIZE_BUTTON_INDEX = 2; 37 constexpr int32_t CLOSE_BUTTON_INDEX = 3; 38 constexpr int32_t TITLE_POPUP_DURATION = 200; 39 constexpr double MOUSE_MOVE_POPUP_DISTANCE = 5.0; // 5.0px 40 constexpr double MOVE_POPUP_DISTANCE_X = 40.0; // 40.0px 41 constexpr double MOVE_POPUP_DISTANCE_Y = 20.0; // 20.0px 42 constexpr double TITLE_POPUP_DISTANCE = 37.0; // 37vp height of title 43 } // namespace 44 UpdateRowHeight(const RefPtr<FrameNode> & row,Dimension height)45 void UpdateRowHeight(const RefPtr<FrameNode>& row, Dimension height) 46 { 47 CHECK_NULL_VOID(row); 48 auto layoutProperty = row->GetLayoutProperty<LinearLayoutProperty>(); 49 CHECK_NULL_VOID(layoutProperty); 50 layoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(1.0, DimensionUnit::PERCENT), CalcLength(height))); 51 row->MarkModifyDone(); 52 row->MarkDirtyNode(); 53 } 54 ShowTitle(bool isShow,bool hasDeco,bool needUpdate)55 void ContainerModalPattern::ShowTitle(bool isShow, bool hasDeco, bool needUpdate) 56 { 57 auto containerNode = GetHost(); 58 CHECK_NULL_VOID(containerNode); 59 auto customTitleRow = GetCustomTitleRow(); 60 CHECK_NULL_VOID(customTitleRow); 61 auto floatingTitleRow = GetFloatingTitleRow(); 62 CHECK_NULL_VOID(floatingTitleRow); 63 if (needUpdate) { 64 LOGI("title is need update, isFocus_: %{public}d", isFocus_); 65 ChangeCustomTitle(isFocus_); 66 ChangeControlButtons(isFocus_); 67 return; 68 } 69 70 auto pipelineContext = PipelineContext::GetCurrentContext(); 71 CHECK_NULL_VOID(pipelineContext); 72 auto theme = pipelineContext->GetTheme<ContainerModalTheme>(); 73 auto stackNode = GetStackNode(); 74 CHECK_NULL_VOID(stackNode); 75 auto windowManager = pipelineContext->GetWindowManager(); 76 CHECK_NULL_VOID(windowManager); 77 windowMode_ = windowManager->GetWindowMode(); 78 hasDeco_ = hasDeco; 79 LOGI("ShowTitle isShow: %{public}d, windowMode: %{public}d, hasDeco: %{public}d", isShow, windowMode_, hasDeco_); 80 if (!hasDeco_) { 81 isShow = false; 82 } 83 84 // set container window show state to RS 85 pipelineContext->SetContainerWindow(isShow); 86 87 // update container modal padding and border 88 auto layoutProperty = containerNode->GetLayoutProperty(); 89 CHECK_NULL_VOID(layoutProperty); 90 layoutProperty->UpdateAlignment(Alignment::TOP_LEFT); 91 PaddingProperty padding; 92 if (isShow && customTitleSettedShow_) { 93 padding = { CalcLength(CONTENT_PADDING), CalcLength(CONTENT_PADDING), std::nullopt, 94 CalcLength(CONTENT_PADDING) }; 95 } 96 layoutProperty->UpdatePadding(padding); 97 BorderWidthProperty borderWidth; 98 borderWidth.SetBorderWidth(isShow ? CONTAINER_BORDER_WIDTH : 0.0_vp); 99 layoutProperty->UpdateBorderWidth(borderWidth); 100 101 auto renderContext = containerNode->GetRenderContext(); 102 CHECK_NULL_VOID(renderContext); 103 renderContext->UpdateBackgroundColor(theme->GetBackGroundColor(isFocus_)); 104 BorderRadiusProperty borderRadius; 105 borderRadius.SetRadius(isShow ? CONTAINER_OUTER_RADIUS : 0.0_vp); 106 renderContext->UpdateBorderRadius(borderRadius); 107 BorderColorProperty borderColor; 108 borderColor.SetColor(isShow ? CONTAINER_BORDER_COLOR : Color::TRANSPARENT); 109 renderContext->UpdateBorderColor(borderColor); 110 111 // update stack content border 112 auto stackLayoutProperty = stackNode->GetLayoutProperty(); 113 CHECK_NULL_VOID(stackLayoutProperty); 114 stackLayoutProperty->UpdateLayoutWeight(1.0f); 115 116 auto stackRenderContext = stackNode->GetRenderContext(); 117 CHECK_NULL_VOID(stackRenderContext); 118 BorderRadiusProperty stageBorderRadius; 119 stageBorderRadius.SetRadius(isShow ? GetStackNodeRadius() : 0.0_vp); 120 stackRenderContext->UpdateBorderRadius(stageBorderRadius); 121 stackRenderContext->SetClipToBounds(true); 122 123 auto customTitleLayoutProperty = customTitleRow->GetLayoutProperty(); 124 CHECK_NULL_VOID(customTitleLayoutProperty); 125 customTitleLayoutProperty->UpdateVisibility( 126 (isShow && customTitleSettedShow_) ? VisibleType::VISIBLE : VisibleType::GONE); 127 auto floatingLayoutProperty = floatingTitleRow->GetLayoutProperty(); 128 CHECK_NULL_VOID(floatingLayoutProperty); 129 floatingLayoutProperty->UpdateVisibility(VisibleType::GONE); 130 131 auto controlButtonsNode = GetControlButtonRow(); 132 CHECK_NULL_VOID(controlButtonsNode); 133 auto controlButtonsLayoutProperty = controlButtonsNode->GetLayoutProperty(); 134 CHECK_NULL_VOID(controlButtonsLayoutProperty); 135 AddPanEvent(controlButtonsNode); 136 ChangeFloatingTitle(isFocus_); 137 ChangeControlButtons(isFocus_); 138 139 auto controlButtonsContext = controlButtonsNode->GetRenderContext(); 140 CHECK_NULL_VOID(controlButtonsContext); 141 controlButtonsLayoutProperty->UpdateVisibility(isShow ? VisibleType::VISIBLE : VisibleType::GONE); 142 } 143 InitContainerEvent()144 void ContainerModalPattern::InitContainerEvent() 145 { 146 bool isChangeTitleStyle = SystemProperties::GetTitleStyleEnabled(); 147 if (isChangeTitleStyle) { 148 return; 149 } 150 auto containerNode = GetHost(); 151 CHECK_NULL_VOID(containerNode); 152 auto touchEventHub = containerNode->GetOrCreateGestureEventHub(); 153 CHECK_NULL_VOID(touchEventHub); 154 auto controlButtonsNode = GetControlButtonRow(); 155 CHECK_NULL_VOID(controlButtonsNode); 156 auto controlButtonsLayoutProperty = controlButtonsNode->GetLayoutProperty(); 157 CHECK_NULL_VOID(controlButtonsLayoutProperty); 158 auto controlButtonsContext = controlButtonsNode->GetRenderContext(); 159 CHECK_NULL_VOID(controlButtonsContext); 160 161 auto floatingTitleRow = GetFloatingTitleRow(); 162 CHECK_NULL_VOID(floatingTitleRow); 163 auto floatingLayoutProperty = floatingTitleRow->GetLayoutProperty(); 164 CHECK_NULL_VOID(floatingLayoutProperty); 165 auto floatingContext = floatingTitleRow->GetRenderContext(); 166 CHECK_NULL_VOID(floatingContext); 167 168 auto containerNodeContext = containerNode->GetContext(); 169 CHECK_NULL_VOID(containerNodeContext); 170 auto titlePopupDistance = TITLE_POPUP_DISTANCE * containerNodeContext->GetDensity(); 171 AnimationOption option; 172 option.SetDuration(TITLE_POPUP_DURATION); 173 option.SetCurve(Curves::EASE_IN_OUT); 174 175 // init touch event 176 touchEventHub->SetTouchEvent([controlButtonsLayoutProperty, floatingLayoutProperty, controlButtonsContext, 177 floatingContext, option, titlePopupDistance, 178 weak = WeakClaim(this)](TouchEventInfo& info) { 179 auto container = weak.Upgrade(); 180 CHECK_NULL_VOID(container); 181 if (!container->hasDeco_) { 182 return; 183 } 184 if (info.GetChangedTouches().begin()->GetGlobalLocation().GetY() <= titlePopupDistance) { 185 // step1. Record the coordinates of the start of the touch. 186 if (info.GetChangedTouches().begin()->GetTouchType() == TouchType::DOWN) { 187 container->moveX_ = static_cast<float>(info.GetChangedTouches().begin()->GetGlobalLocation().GetX()); 188 container->moveY_ = static_cast<float>(info.GetChangedTouches().begin()->GetGlobalLocation().GetY()); 189 return; 190 } 191 if (info.GetChangedTouches().begin()->GetTouchType() != TouchType::MOVE || 192 !container->CanShowFloatingTitle()) { 193 return; 194 } 195 196 // step2. Calculate the coordinates of touch move relative to touch down. 197 auto deltaMoveX = fabs(info.GetChangedTouches().begin()->GetGlobalLocation().GetX() - container->moveX_); 198 auto deltaMoveY = info.GetChangedTouches().begin()->GetGlobalLocation().GetY() - container->moveY_; 199 // step3. If the horizontal distance of the touch move does not exceed 10px and the vertical distance 200 // exceeds 20px, the floating title will be displayed. 201 if (deltaMoveX <= MOVE_POPUP_DISTANCE_X && deltaMoveY >= MOVE_POPUP_DISTANCE_Y) { 202 controlButtonsContext->OnTransformTranslateUpdate( 203 { 0.0f, static_cast<float>(-titlePopupDistance), 0.0f }); 204 controlButtonsLayoutProperty->UpdateVisibility(VisibleType::VISIBLE); 205 AnimationUtils::Animate(option, [controlButtonsContext]() { 206 controlButtonsContext->OnTransformTranslateUpdate({ 0.0f, 0.0f, 0.0f }); 207 }); 208 floatingContext->OnTransformTranslateUpdate({ 0.0f, static_cast<float>(-titlePopupDistance), 0.0f }); 209 floatingLayoutProperty->UpdateVisibility( 210 container->floatingTitleSettedShow_ ? VisibleType::VISIBLE : VisibleType::GONE); 211 AnimationUtils::Animate(option, [floatingContext]() { 212 floatingContext->OnTransformTranslateUpdate({ 0.0f, 0.0f, 0.0f }); 213 }); 214 } 215 return; 216 } 217 if (info.GetChangedTouches().begin()->GetTouchType() != TouchType::DOWN) { 218 return; 219 } 220 if (floatingLayoutProperty->GetVisibilityValue(VisibleType::GONE) != VisibleType::VISIBLE) { 221 return; 222 } 223 // step4. Touch other area to hide floating title. 224 AnimationUtils::Animate( 225 option, 226 [controlButtonsContext, floatingContext, titlePopupDistance]() { 227 controlButtonsContext->OnTransformTranslateUpdate( 228 { 0.0f, static_cast<float>(-titlePopupDistance), 0.0f }); 229 floatingContext->OnTransformTranslateUpdate({ 0.0f, static_cast<float>(-titlePopupDistance), 0.0f }); 230 }, 231 [floatingLayoutProperty, id = Container::CurrentId()]() { 232 ContainerScope scope(id); 233 floatingLayoutProperty->UpdateVisibility(VisibleType::GONE); 234 }); 235 }); 236 237 // init mouse event 238 auto mouseEventHub = containerNode->GetOrCreateInputEventHub(); 239 CHECK_NULL_VOID(mouseEventHub); 240 mouseEventHub->SetMouseEvent([controlButtonsLayoutProperty, floatingLayoutProperty, controlButtonsContext, 241 floatingContext, option, titlePopupDistance, 242 weak = WeakClaim(this)](MouseInfo& info) { 243 auto container = weak.Upgrade(); 244 CHECK_NULL_VOID(container); 245 auto action = info.GetAction(); 246 if ((action != MouseAction::MOVE && action != MouseAction::WINDOW_LEAVE) || !container->hasDeco_) { 247 return; 248 } 249 if (info.GetLocalLocation().GetY() <= MOUSE_MOVE_POPUP_DISTANCE && container->CanShowFloatingTitle()) { 250 controlButtonsContext->OnTransformTranslateUpdate({ 0.0f, static_cast<float>(-titlePopupDistance), 0.0f }); 251 controlButtonsLayoutProperty->UpdateVisibility(VisibleType::VISIBLE); 252 AnimationUtils::Animate(option, [controlButtonsContext]() { 253 controlButtonsContext->OnTransformTranslateUpdate({ 0.0f, 0.0f, 0.0f }); 254 }); 255 floatingContext->OnTransformTranslateUpdate({ 0.0f, static_cast<float>(-titlePopupDistance), 0.0f }); 256 floatingLayoutProperty->UpdateVisibility( 257 container->floatingTitleSettedShow_ ? VisibleType::VISIBLE : VisibleType::GONE); 258 AnimationUtils::Animate(option, [floatingContext]() { 259 floatingContext->OnTransformTranslateUpdate({ 0.0f, 0.0f, 0.0f }); 260 }); 261 } 262 263 if (!container->CanHideFloatingTitle()) { 264 return; 265 } 266 if ((info.GetLocalLocation().GetY() >= titlePopupDistance || action == MouseAction::WINDOW_LEAVE) && 267 floatingLayoutProperty->GetVisibilityValue(VisibleType::GONE) == VisibleType::VISIBLE) { 268 AnimationUtils::Animate( 269 option, 270 [controlButtonsContext, floatingContext, titlePopupDistance]() { 271 controlButtonsContext->OnTransformTranslateUpdate( 272 { 0.0f, static_cast<float>(-titlePopupDistance), 0.0f }); 273 floatingContext->OnTransformTranslateUpdate( 274 { 0.0f, static_cast<float>(-titlePopupDistance), 0.0f }); 275 }, 276 [floatingLayoutProperty]() { 277 floatingLayoutProperty->UpdateVisibility(VisibleType::GONE); 278 }); 279 } 280 }); 281 } 282 AddPanEvent(const RefPtr<FrameNode> & controlButtonsNode)283 void ContainerModalPattern::AddPanEvent(const RefPtr<FrameNode>& controlButtonsNode) 284 { 285 auto eventHub = controlButtonsNode->GetOrCreateGestureEventHub(); 286 CHECK_NULL_VOID(eventHub); 287 PanDirection panDirection; 288 panDirection.type = PanDirection::ALL; 289 290 if (!panEvent_) { 291 auto pipeline = PipelineContext::GetCurrentContext(); 292 CHECK_NULL_VOID(pipeline); 293 auto windowManager = pipeline->GetWindowManager(); 294 CHECK_NULL_VOID(windowManager); 295 // touch the title to move the floating window 296 auto panActionStart = [wk = WeakClaim(RawPtr(windowManager))](const GestureEvent& event) { 297 auto windowManager = wk.Upgrade(); 298 CHECK_NULL_VOID(windowManager); 299 if ((windowManager->GetCurrentWindowMaximizeMode() != MaximizeMode::MODE_AVOID_SYSTEM_BAR) && 300 (event.GetSourceTool() != SourceTool::TOUCHPAD)) { 301 windowManager->WindowStartMove(); 302 SubwindowManager::GetInstance()->ClearToastInSubwindow(); 303 } 304 }; 305 panEvent_ = MakeRefPtr<PanEvent>(std::move(panActionStart), nullptr, nullptr, nullptr); 306 } 307 eventHub->AddPanEvent(panEvent_, panDirection, DEFAULT_PAN_FINGER, DEFAULT_PAN_DISTANCE); 308 } 309 RemovePanEvent(const RefPtr<FrameNode> & controlButtonsNode)310 void ContainerModalPattern::RemovePanEvent(const RefPtr<FrameNode>& controlButtonsNode) 311 { 312 auto eventHub = controlButtonsNode->GetOrCreateGestureEventHub(); 313 CHECK_NULL_VOID(eventHub); 314 315 if (!panEvent_) { 316 return; 317 } 318 eventHub->RemovePanEvent(panEvent_); 319 } 320 OnWindowFocused()321 void ContainerModalPattern::OnWindowFocused() 322 { 323 WindowFocus(true); 324 } 325 OnWindowUnfocused()326 void ContainerModalPattern::OnWindowUnfocused() 327 { 328 WindowFocus(false); 329 } 330 OnWindowForceUnfocused()331 void ContainerModalPattern::OnWindowForceUnfocused() {} 332 WindowFocus(bool isFocus)333 void ContainerModalPattern::WindowFocus(bool isFocus) 334 { 335 auto theme = PipelineContext::GetCurrentContext()->GetTheme<ContainerModalTheme>(); 336 isFocus_ = isFocus; 337 auto containerNode = GetHost(); 338 CHECK_NULL_VOID(containerNode); 339 340 // update container modal background 341 auto renderContext = containerNode->GetRenderContext(); 342 CHECK_NULL_VOID(renderContext); 343 renderContext->UpdateBackgroundColor(theme->GetBackGroundColor(isFocus)); 344 BorderColorProperty borderColor; 345 borderColor.SetColor(isFocus ? CONTAINER_BORDER_COLOR : CONTAINER_BORDER_COLOR_LOST_FOCUS); 346 renderContext->UpdateBorderColor(borderColor); 347 348 ChangeCustomTitle(isFocus); 349 ChangeFloatingTitle(isFocus); 350 ChangeControlButtons(isFocus); 351 } 352 ChangeCustomTitle(bool isFocus)353 void ContainerModalPattern::ChangeCustomTitle(bool isFocus) 354 { 355 // update custom title label 356 auto customTitleNode = GetCustomTitleNode(); 357 CHECK_NULL_VOID(customTitleNode); 358 isFocus ? customTitleNode->FireOnWindowFocusedCallback() : customTitleNode->FireOnWindowUnfocusedCallback(); 359 } 360 ChangeControlButtons(bool isFocus)361 void ContainerModalPattern::ChangeControlButtons(bool isFocus) 362 { 363 auto containerNode = GetHost(); 364 CHECK_NULL_VOID(containerNode); 365 auto controlButtonsNode = GetControlButtonRow(); 366 CHECK_NULL_VOID(controlButtonsNode); 367 368 // update leftSplit button 369 auto leftSplitButton = 370 AceType::DynamicCast<FrameNode>(GetTitleItemByIndex(controlButtonsNode, LEFT_SPLIT_BUTTON_INDEX)); 371 ChangeTitleButtonIcon(leftSplitButton, 372 isFocus ? InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_SPLIT_LEFT 373 : InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_SPLIT_LEFT, 374 isFocus, false); 375 376 // hide leftSplit button when window mode is WINDOW_MODE_SPLIT_PRIMARY type or split button can not show 377 bool hideLeftSplit = hideSplitButton_ || windowMode_ == WindowMode::WINDOW_MODE_SPLIT_PRIMARY; 378 leftSplitButton->GetLayoutProperty()->UpdateVisibility(hideLeftSplit ? VisibleType::GONE : VisibleType::VISIBLE); 379 380 // update maximize button 381 auto maximizeButton = 382 AceType::DynamicCast<FrameNode>(GetTitleItemByIndex(controlButtonsNode, MAX_RECOVER_BUTTON_INDEX)); 383 auto pipeline = PipelineContext::GetCurrentContext(); 384 auto windowManager = pipeline->GetWindowManager(); 385 MaximizeMode mode = windowManager->GetCurrentWindowMaximizeMode(); 386 InternalResource::ResourceId maxId; 387 if (mode == MaximizeMode::MODE_AVOID_SYSTEM_BAR || windowMode_ == WindowMode::WINDOW_MODE_FULLSCREEN) { 388 maxId = InternalResource::ResourceId::IC_WINDOW_RESTORES; 389 } else { 390 maxId = InternalResource::ResourceId::IC_WINDOW_MAX; 391 } 392 393 ChangeTitleButtonIcon(maximizeButton, maxId, isFocus, false); 394 // update minimize button 395 auto minimizeButton = 396 AceType::DynamicCast<FrameNode>(GetTitleItemByIndex(controlButtonsNode, MINIMIZE_BUTTON_INDEX)); 397 ChangeTitleButtonIcon(minimizeButton, 398 InternalResource::ResourceId::IC_WINDOW_MIN, isFocus, false); 399 400 // update close button 401 auto closeButton = AceType::DynamicCast<FrameNode>(GetTitleItemByIndex(controlButtonsNode, CLOSE_BUTTON_INDEX)); 402 ChangeTitleButtonIcon(closeButton, 403 InternalResource::ResourceId::IC_WINDOW_CLOSE, isFocus, true); 404 } 405 ChangeFloatingTitle(bool isFocus)406 void ContainerModalPattern::ChangeFloatingTitle(bool isFocus) 407 { 408 // update floating custom title label 409 auto customFloatingTitleNode = GetFloatingTitleNode(); 410 CHECK_NULL_VOID(customFloatingTitleNode); 411 isFocus ? customFloatingTitleNode->FireOnWindowFocusedCallback() 412 : customFloatingTitleNode->FireOnWindowUnfocusedCallback(); 413 } 414 ChangeTitleButtonIcon(const RefPtr<FrameNode> & buttonNode,InternalResource::ResourceId icon,bool isFocus,bool isCloseBtn)415 void ContainerModalPattern::ChangeTitleButtonIcon( 416 const RefPtr<FrameNode>& buttonNode, InternalResource::ResourceId icon, bool isFocus, bool isCloseBtn) 417 { 418 auto theme = PipelineContext::GetCurrentContext()->GetTheme<ContainerModalTheme>(); 419 auto renderContext = buttonNode->GetRenderContext(); 420 CHECK_NULL_VOID(renderContext); 421 auto colorType = isFocus ? ControlBtnColorType::NORMAL : ControlBtnColorType::UNFOCUS; 422 auto color = theme->GetControlBtnColor(isCloseBtn, colorType); 423 renderContext->UpdateBackgroundColor(color); 424 auto buttonIcon = AceType::DynamicCast<FrameNode>(buttonNode->GetChildren().front()); 425 CHECK_NULL_VOID(buttonIcon); 426 ImageSourceInfo imageSourceInfo; 427 imageSourceInfo.SetResourceId(icon); 428 colorType = isFocus ? ControlBtnColorType::NORMAL_FILL : ControlBtnColorType::UNFOCUS_FILL; 429 color = theme->GetControlBtnColor(isCloseBtn, colorType); 430 imageSourceInfo.SetFillColor(color); 431 auto imageLayoutProperty = buttonIcon->GetLayoutProperty<ImageLayoutProperty>(); 432 imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo); 433 buttonIcon->MarkModifyDone(); 434 buttonNode->MarkModifyDone(); 435 } 436 CanShowFloatingTitle()437 bool ContainerModalPattern::CanShowFloatingTitle() 438 { 439 auto floatingTitleRow = GetFloatingTitleRow(); 440 CHECK_NULL_RETURN(floatingTitleRow, false); 441 auto floatingLayoutProperty = floatingTitleRow->GetLayoutProperty(); 442 CHECK_NULL_RETURN(floatingLayoutProperty, false); 443 444 if (windowMode_ != WindowMode::WINDOW_MODE_FULLSCREEN && windowMode_ != WindowMode::WINDOW_MODE_SPLIT_PRIMARY && 445 windowMode_ != WindowMode::WINDOW_MODE_SPLIT_SECONDARY) { 446 LOGI("Window is not full screen or split screen, can not show floating title."); 447 return false; 448 } 449 450 if (floatingLayoutProperty->GetVisibilityValue(VisibleType::GONE) == VisibleType::VISIBLE) { 451 LOGI("Floating tittle is visible now, no need to show again."); 452 return false; 453 } 454 return true; 455 } 456 SetAppTitle(const std::string & title)457 void ContainerModalPattern::SetAppTitle(const std::string& title) 458 { 459 TAG_LOGI(AceLogTag::ACE_APPBAR, "SetAppTitle successfully"); 460 auto customTitleNode = GetCustomTitleNode(); 461 CHECK_NULL_VOID(customTitleNode); 462 customTitleNode->FireAppTitleCallback(title); 463 464 auto customFloatingTitleNode = GetFloatingTitleNode(); 465 CHECK_NULL_VOID(customFloatingTitleNode); 466 customFloatingTitleNode->FireAppTitleCallback(title); 467 } 468 SetAppIcon(const RefPtr<PixelMap> & icon)469 void ContainerModalPattern::SetAppIcon(const RefPtr<PixelMap>& icon) 470 { 471 CHECK_NULL_VOID(icon); 472 LOGI("SetAppIcon successfully"); 473 auto customTitleNode = GetCustomTitleNode(); 474 CHECK_NULL_VOID(customTitleNode); 475 customTitleNode->FireAppIconCallback(icon); 476 477 auto customFloatingTitleNode = GetFloatingTitleNode(); 478 CHECK_NULL_VOID(customFloatingTitleNode); 479 customFloatingTitleNode->FireAppIconCallback(icon); 480 } 481 SetTitleButtonHide(const RefPtr<FrameNode> & controlButtonsNode,bool hideSplit,bool hideMaximize,bool hideMinimize,bool hideClose)482 void ContainerModalPattern::SetTitleButtonHide( 483 const RefPtr<FrameNode>& controlButtonsNode, bool hideSplit, bool hideMaximize, bool hideMinimize, bool hideClose) 484 { 485 auto leftSplitButton = 486 AceType::DynamicCast<FrameNode>(GetTitleItemByIndex(controlButtonsNode, LEFT_SPLIT_BUTTON_INDEX)); 487 CHECK_NULL_VOID(leftSplitButton); 488 leftSplitButton->GetLayoutProperty()->UpdateVisibility(hideSplit ? VisibleType::GONE : VisibleType::VISIBLE); 489 leftSplitButton->MarkDirtyNode(); 490 491 auto maximizeButton = 492 AceType::DynamicCast<FrameNode>(GetTitleItemByIndex(controlButtonsNode, MAX_RECOVER_BUTTON_INDEX)); 493 CHECK_NULL_VOID(maximizeButton); 494 maximizeButton->GetLayoutProperty()->UpdateVisibility(hideMaximize ? VisibleType::GONE : VisibleType::VISIBLE); 495 maximizeButton->MarkDirtyNode(); 496 497 auto minimizeButton = AceType::DynamicCast<FrameNode>( 498 GetTitleItemByIndex(controlButtonsNode, MINIMIZE_BUTTON_INDEX)); 499 CHECK_NULL_VOID(minimizeButton); 500 minimizeButton->GetLayoutProperty()->UpdateVisibility(hideMinimize ? VisibleType::GONE : VisibleType::VISIBLE); 501 minimizeButton->MarkDirtyNode(); 502 503 auto closeButton = AceType::DynamicCast<FrameNode>(GetTitleItemByIndex(controlButtonsNode, CLOSE_BUTTON_INDEX)); 504 CHECK_NULL_VOID(closeButton); 505 closeButton->GetLayoutProperty()->UpdateVisibility(hideClose ? VisibleType::GONE : VisibleType::VISIBLE); 506 closeButton->MarkDirtyNode(); 507 } 508 SetContainerButtonHide(bool hideSplit,bool hideMaximize,bool hideMinimize,bool hideClose)509 void ContainerModalPattern::SetContainerButtonHide(bool hideSplit, bool hideMaximize, bool hideMinimize, bool hideClose) 510 { 511 auto controlButtonsRow = GetControlButtonRow(); 512 CHECK_NULL_VOID(controlButtonsRow); 513 SetTitleButtonHide(controlButtonsRow, hideSplit, hideMaximize, hideMinimize, hideClose); 514 hideSplitButton_ = hideSplit; 515 TAG_LOGI(AceLogTag::ACE_APPBAR, 516 "Set containerModal button status successfully, " 517 "hideSplit: %{public}d, hideMaximize: %{public}d, " 518 "hideMinimize: %{public}d, hideClose: %{public}d", 519 hideSplit, hideMaximize, hideMinimize, hideClose); 520 } 521 SetCloseButtonStatus(bool isEnabled)522 void ContainerModalPattern::SetCloseButtonStatus(bool isEnabled) 523 { 524 auto controlButtonsRow = GetControlButtonRow(); 525 CHECK_NULL_VOID(controlButtonsRow); 526 527 // set closeButton enable or disable 528 auto closeButton = AceType::DynamicCast<FrameNode>(GetTitleItemByIndex(controlButtonsRow, CLOSE_BUTTON_INDEX)); 529 CHECK_NULL_VOID(closeButton); 530 auto buttonEvent = closeButton->GetEventHub<ButtonEventHub>(); 531 CHECK_NULL_VOID(buttonEvent); 532 buttonEvent->SetEnabled(isEnabled); 533 LOGI("Set close button status %{public}s", isEnabled ? "enable" : "disable"); 534 } 535 UpdateGestureRowVisible()536 void ContainerModalPattern::UpdateGestureRowVisible() 537 { 538 auto gestureRow = GetGestureRow(); 539 CHECK_NULL_VOID(gestureRow); 540 auto customTitleRow = GetCustomTitleRow(); 541 CHECK_NULL_VOID(customTitleRow); 542 auto buttonsRow = GetControlButtonRow(); 543 CHECK_NULL_VOID(buttonsRow); 544 auto gestureRowProp = gestureRow->GetLayoutProperty(); 545 auto customTitleRowProp = customTitleRow->GetLayoutProperty(); 546 auto buttonsRowProp = buttonsRow->GetLayoutProperty(); 547 if (customTitleRowProp->GetVisibilityValue(VisibleType::VISIBLE) == VisibleType::GONE && 548 buttonsRowProp->GetVisibilityValue(VisibleType::VISIBLE) == VisibleType::VISIBLE) { 549 gestureRowProp->UpdateVisibility(VisibleType::VISIBLE); 550 } else { 551 gestureRowProp->UpdateVisibility(VisibleType::GONE); 552 } 553 } 554 SetContainerModalTitleVisible(bool customTitleSettedShow,bool floatingTitleSettedShow)555 void ContainerModalPattern::SetContainerModalTitleVisible(bool customTitleSettedShow, bool floatingTitleSettedShow) 556 { 557 LOGI("ContainerModal customTitleSettedShow=%{public}d, floatingTitleSettedShow=%{public}d", customTitleSettedShow, 558 floatingTitleSettedShow); 559 customTitleSettedShow_ = customTitleSettedShow; 560 auto customTitleRow = GetCustomTitleRow(); 561 CHECK_NULL_VOID(customTitleRow); 562 auto customTitleRowProp = customTitleRow->GetLayoutProperty(); 563 if (!customTitleSettedShow) { 564 customTitleRowProp->UpdateVisibility(VisibleType::GONE); 565 } else if (CanShowCustomTitle()) { 566 customTitleRowProp->UpdateVisibility(VisibleType::VISIBLE); 567 } 568 floatingTitleSettedShow_ = floatingTitleSettedShow; 569 auto floatingTitleRow = GetFloatingTitleRow(); 570 CHECK_NULL_VOID(floatingTitleRow); 571 auto floatingTitleRowProp = floatingTitleRow->GetLayoutProperty(); 572 if (!floatingTitleSettedShow) { 573 floatingTitleRowProp->UpdateVisibility(VisibleType::GONE); 574 } 575 576 auto buttonsRow = GetControlButtonRow(); 577 CHECK_NULL_VOID(buttonsRow); 578 buttonsRow->SetHitTestMode(HitTestMode::HTMTRANSPARENT_SELF); 579 UpdateGestureRowVisible(); 580 TrimFloatingWindowLayout(); 581 } 582 SetContainerModalTitleHeight(int32_t height)583 void ContainerModalPattern::SetContainerModalTitleHeight(int32_t height) 584 { 585 LOGI("ContainerModal SetContainerModalTitleHeight height=%{public}d", height); 586 if (height < 0) { 587 height = 0; 588 } 589 titleHeight_ = Dimension(Dimension(height, DimensionUnit::PX).ConvertToVp(), DimensionUnit::VP); 590 auto customTitleRow = GetCustomTitleRow(); 591 UpdateRowHeight(customTitleRow, titleHeight_); 592 auto controlButtonsRow = GetControlButtonRow(); 593 UpdateRowHeight(controlButtonsRow, titleHeight_); 594 auto gestureRow = GetGestureRow(); 595 UpdateRowHeight(gestureRow, titleHeight_); 596 CallButtonsRectChange(); 597 } 598 GetContainerModalTitleHeight()599 int32_t ContainerModalPattern::GetContainerModalTitleHeight() 600 { 601 return static_cast<int32_t>(ceil(titleHeight_.ConvertToPx())); 602 } 603 GetContainerModalButtonsRect(RectF & containerModal,RectF & buttons)604 bool ContainerModalPattern::GetContainerModalButtonsRect(RectF& containerModal, RectF& buttons) 605 { 606 auto column = GetColumnNode(); 607 CHECK_NULL_RETURN(column, false); 608 auto columnRect = column->GetGeometryNode()->GetFrameRect(); 609 containerModal = columnRect; 610 if (columnRect.Width() == 0) { 611 LOGW("Get rect of buttons failed, the rect is measuring."); 612 return false; 613 } 614 615 auto controlButtonsRow = GetControlButtonRow(); 616 CHECK_NULL_RETURN(controlButtonsRow, false); 617 auto children = controlButtonsRow->GetChildren(); 618 RectF firstButtonRect; 619 RectF lastButtonRect; 620 for (auto& child : children) { 621 auto node = AceType::DynamicCast<FrameNode>(child); 622 if (node->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) != VisibleType::VISIBLE) { 623 continue; 624 } 625 auto rect = node->GetGeometryNode()->GetFrameRect(); 626 if (firstButtonRect.Width() == 0) { 627 firstButtonRect = rect; 628 } 629 lastButtonRect = rect; 630 } 631 buttons = firstButtonRect.CombineRectT(lastButtonRect); 632 if (buttons.Width() == 0) { 633 LOGW("Get rect of buttons failed, buttons are hidden"); 634 return false; 635 } 636 637 auto widthByPx = (TITLE_PADDING_START + TITLE_PADDING_END).ConvertToPx() + buttons.Width(); 638 auto isRtl = AceApplicationInfo::GetInstance().IsRightToLeft(); 639 if (isRtl) { 640 buttons.SetLeft(0); 641 } else { 642 buttons.SetLeft(containerModal.Width() - widthByPx); 643 } 644 buttons.SetTop(0); 645 buttons.SetWidth(widthByPx); 646 buttons.SetHeight(titleHeight_.ConvertToPx()); 647 return true; 648 } 649 SubscribeContainerModalButtonsRectChange(std::function<void (RectF & containerModal,RectF & buttons)> && callback)650 void ContainerModalPattern::SubscribeContainerModalButtonsRectChange( 651 std::function<void(RectF& containerModal, RectF& buttons)>&& callback) 652 { 653 controlButtonsRectChangeCallback_ = std::move(callback); 654 } 655 GetWindowPaintRectWithoutMeasureAndLayout(RectInt & rect)656 void ContainerModalPattern::GetWindowPaintRectWithoutMeasureAndLayout(RectInt& rect) 657 { 658 auto host = GetHost(); 659 CHECK_NULL_VOID(host); 660 auto layoutProperty = host->GetLayoutProperty(); 661 CHECK_NULL_VOID(layoutProperty); 662 auto titleHeight = round(GetCustomTitleHeight().ConvertToPx()); 663 auto padding = layoutProperty->CreatePaddingAndBorder(); 664 rect.SetRect(padding.Offset().GetX(), padding.Offset().GetY() + titleHeight, rect.Width() - padding.Width(), 665 rect.Height() - padding.Height() - titleHeight); 666 } 667 CallButtonsRectChange()668 void ContainerModalPattern::CallButtonsRectChange() 669 { 670 CHECK_NULL_VOID(controlButtonsRectChangeCallback_); 671 RectF containerModal; 672 RectF buttons; 673 GetContainerModalButtonsRect(containerModal, buttons); 674 if (buttonsRect_ == buttons) { 675 return; 676 } 677 buttonsRect_ = buttons; 678 auto taskExecutor = Container::CurrentTaskExecutor(); 679 CHECK_NULL_VOID(taskExecutor); 680 taskExecutor->PostTask( 681 [containerModal, buttons, cb = controlButtonsRectChangeCallback_]() mutable { 682 if (cb) { 683 cb(containerModal, buttons); 684 } 685 }, 686 TaskExecutor::TaskType::JS, "ArkUIContainerModalButtonsRectChange"); 687 } 688 InitTitle()689 void ContainerModalPattern::InitTitle() 690 { 691 auto pipeline = PipelineContext::GetCurrentContext(); 692 CHECK_NULL_VOID(pipeline); 693 auto themeManager = pipeline->GetThemeManager(); 694 CHECK_NULL_VOID(themeManager); 695 auto themeConstants = themeManager->GetThemeConstants(); 696 CHECK_NULL_VOID(themeConstants); 697 auto id = pipeline->GetWindowManager()->GetAppIconId(); 698 auto pixelMap = themeConstants->GetPixelMap(id); 699 if (pixelMap) { 700 RefPtr<PixelMap> icon = PixelMap::CreatePixelMap(&pixelMap); 701 SetAppIcon(icon); 702 } else { 703 LOGW("Cannot get pixelmap, try media path."); // use themeConstants GetMediaPath 704 } 705 SetAppTitle(themeConstants->GetString(pipeline->GetWindowManager()->GetAppLabelId())); 706 } 707 Init()708 void ContainerModalPattern::Init() 709 { 710 InitContainerEvent(); 711 InitTitle(); 712 InitLayoutProperty(); 713 } 714 OnColorConfigurationUpdate()715 void ContainerModalPattern::OnColorConfigurationUpdate() 716 { 717 WindowFocus(isFocus_); 718 } 719 InitLayoutProperty()720 void ContainerModalPattern::InitLayoutProperty() 721 { 722 auto containerModal = GetHost(); 723 auto column = GetColumnNode(); 724 auto stack = GetStackNode(); 725 auto content = GetContentNode(); 726 CHECK_NULL_VOID(content); 727 auto buttonsRow = GetControlButtonRow(); 728 CHECK_NULL_VOID(buttonsRow); 729 auto contentProperty = content->GetLayoutProperty(); 730 auto buttonsRowProperty = buttonsRow->GetLayoutProperty<LinearLayoutProperty>(); 731 732 containerModal->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT); 733 column->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT); 734 stack->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT); 735 contentProperty->UpdateMeasureType(MeasureType::MATCH_CONTENT); 736 contentProperty->UpdateUserDefinedIdealSize( 737 CalcSize(CalcLength(1.0, DimensionUnit::PERCENT), CalcLength(1.0, DimensionUnit::PERCENT))); 738 buttonsRowProperty->UpdateMeasureType(MeasureType::MATCH_PARENT); 739 auto buttonHeight = (CONTAINER_TITLE_HEIGHT == titleHeight_) ? CONTAINER_TITLE_HEIGHT : titleHeight_; 740 buttonsRowProperty->UpdateUserDefinedIdealSize( 741 CalcSize(CalcLength(1.0, DimensionUnit::PERCENT), CalcLength(buttonHeight))); 742 buttonsRowProperty->UpdateMainAxisAlign(FlexAlign::FLEX_END); 743 buttonsRowProperty->UpdateCrossAxisAlign(FlexAlign::CENTER); 744 745 InitTitleRowLayoutProperty(GetCustomTitleRow()); 746 InitTitleRowLayoutProperty(GetFloatingTitleRow()); 747 InitButtonsLayoutProperty(); 748 749 containerModal->MarkModifyDone(); 750 } 751 InitTitleRowLayoutProperty(RefPtr<FrameNode> titleRow)752 void ContainerModalPattern::InitTitleRowLayoutProperty(RefPtr<FrameNode> titleRow) 753 { 754 CHECK_NULL_VOID(titleRow); 755 auto titleRowProperty = titleRow->GetLayoutProperty<LinearLayoutProperty>(); 756 CHECK_NULL_VOID(titleRowProperty); 757 titleRowProperty->UpdateMeasureType(MeasureType::MATCH_PARENT); 758 titleRowProperty->UpdateUserDefinedIdealSize( 759 CalcSize(CalcLength(1.0, DimensionUnit::PERCENT), CalcLength(CONTAINER_TITLE_HEIGHT))); 760 titleRowProperty->UpdateMainAxisAlign(FlexAlign::FLEX_START); 761 titleRowProperty->UpdateCrossAxisAlign(FlexAlign::CENTER); 762 auto isRtl = AceApplicationInfo::GetInstance().IsRightToLeft(); 763 PaddingProperty padding; 764 auto sidePadding = isRtl ? &padding.left : & padding.right; 765 *sidePadding = GetControlButtonRowWidth(); 766 titleRowProperty->UpdatePadding(padding); 767 } 768 GetControlButtonRowWidth()769 CalcLength ContainerModalPattern::GetControlButtonRowWidth() 770 { 771 auto row = GetControlButtonRow(); 772 // default 773 int32_t buttonNum = 0; 774 const auto& children = row->GetChildren(); 775 for (const auto& child : children) { 776 auto childButton = AceType::DynamicCast<FrameNode>(child); 777 if (childButton && childButton->IsVisible()) { 778 buttonNum++; 779 } 780 } 781 return CalcLength(TITLE_ELEMENT_MARGIN_HORIZONTAL * (buttonNum - 1) + TITLE_BUTTON_SIZE * buttonNum + 782 TITLE_PADDING_START + TITLE_PADDING_END); 783 } 784 InitColumnTouchTestFunc()785 void ContainerModalPattern::InitColumnTouchTestFunc() 786 { 787 auto column = GetColumnNode(); 788 CHECK_NULL_VOID(column); 789 auto eventHub = column->GetOrCreateGestureEventHub(); 790 auto func = [](const std::vector<TouchTestInfo>& touchInfo) -> TouchResult { 791 TouchResult touchRes; 792 TouchResult defaultRes; 793 touchRes.strategy = TouchTestStrategy::FORWARD_COMPETITION; 794 defaultRes.strategy = TouchTestStrategy::DEFAULT; 795 defaultRes.id = ""; 796 for (auto info : touchInfo) { 797 if (info.id.compare(CONTAINER_MODAL_STACK_ID) == 0) { 798 touchRes.id = info.id; 799 return touchRes; 800 } 801 } 802 return defaultRes; 803 }; 804 eventHub->SetOnTouchTestFunc(func); 805 } 806 InitButtonsLayoutProperty()807 void ContainerModalPattern::InitButtonsLayoutProperty() 808 { 809 auto buttonsRow = GetControlButtonRow(); 810 CHECK_NULL_VOID(buttonsRow); 811 auto isRtl = AceApplicationInfo::GetInstance().IsRightToLeft(); 812 auto buttons = buttonsRow->GetChildren(); 813 for (uint64_t index = 0; index < buttons.size(); index++) { 814 auto space = (index == buttons.size() - 1) ? TITLE_PADDING_END : TITLE_ELEMENT_MARGIN_HORIZONTAL; 815 MarginProperty margin; 816 if (isRtl) { 817 margin.left = CalcLength(space); 818 margin.right = CalcLength(); 819 } else { 820 margin.left = CalcLength(); 821 margin.right = CalcLength(space); 822 } 823 auto button = AceType::DynamicCast<FrameNode>(buttonsRow->GetChildAtIndex(index)); 824 CHECK_NULL_VOID(button); 825 auto layoutProp = button->GetLayoutProperty<ButtonLayoutProperty>(); 826 layoutProp->UpdateMargin(margin); 827 button->MarkModifyDone(); 828 button->MarkDirtyNode(); 829 } 830 } 831 OnLanguageConfigurationUpdate()832 void ContainerModalPattern::OnLanguageConfigurationUpdate() 833 { 834 InitTitle(); 835 InitLayoutProperty(); 836 } 837 GetCustomTitleHeight()838 Dimension ContainerModalPattern::GetCustomTitleHeight() 839 { 840 auto customTitleRow = GetCustomTitleRow(); 841 Dimension zeroHeight; 842 CHECK_NULL_RETURN(customTitleRow, zeroHeight); 843 auto property = customTitleRow->GetLayoutProperty(); 844 if (property->GetVisibilityValue(VisibleType::VISIBLE) != VisibleType::VISIBLE) { 845 return zeroHeight; 846 } 847 return titleHeight_; 848 } 849 GetStackNodeRadius()850 Dimension ContainerModalPattern::GetStackNodeRadius() 851 { 852 Dimension radius = customTitleSettedShow_ ? CONTAINER_INNER_RADIUS : CONTAINER_OUTER_RADIUS; 853 auto trimRadiusPx = Dimension(round(radius.ConvertToPx() * 2) / 2.0); 854 auto trimRadiusVp = Dimension(trimRadiusPx.ConvertToVp(), DimensionUnit::VP); 855 return trimRadiusVp; 856 } 857 CanShowCustomTitle()858 bool ContainerModalPattern::CanShowCustomTitle() 859 { 860 auto buttonsRow = GetControlButtonRow(); 861 CHECK_NULL_RETURN(buttonsRow, false); 862 auto visibility = buttonsRow->GetLayoutProperty()->GetVisibilityValue(VisibleType::GONE); 863 return visibility == VisibleType::VISIBLE; 864 } 865 TrimFloatingWindowLayout()866 void ContainerModalPattern::TrimFloatingWindowLayout() 867 { 868 if (windowMode_ != WindowMode::WINDOW_MODE_FLOATING) { 869 return; 870 } 871 auto stack = GetStackNode(); 872 CHECK_NULL_VOID(stack); 873 auto stackRender = stack->GetRenderContext(); 874 BorderRadiusProperty borderRadius; 875 borderRadius.SetRadius(GetStackNodeRadius()); 876 stackRender->UpdateBorderRadius(borderRadius); 877 auto host = GetHost(); 878 CHECK_NULL_VOID(host); 879 auto hostProp = host->GetLayoutProperty(); 880 PaddingProperty padding; 881 auto customtitleRow = GetCustomTitleRow(); 882 CHECK_NULL_VOID(customtitleRow); 883 auto customTitleRowProp = customtitleRow->GetLayoutProperty(); 884 if (customTitleRowProp->GetVisibilityValue(VisibleType::GONE) == VisibleType::VISIBLE) { 885 padding = { CalcLength(CONTENT_PADDING), CalcLength(CONTENT_PADDING), std::nullopt, 886 CalcLength(CONTENT_PADDING) }; 887 } 888 hostProp->UpdatePadding(padding); 889 } 890 } // namespace OHOS::Ace::NG