• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     AddOrRemovePanEvent(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 
AddOrRemovePanEvent(const RefPtr<FrameNode> & controlButtonsNode)283 void ContainerModalPattern::AddOrRemovePanEvent(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 
OnWindowFocused()310 void ContainerModalPattern::OnWindowFocused()
311 {
312     WindowFocus(true);
313 }
314 
OnWindowUnfocused()315 void ContainerModalPattern::OnWindowUnfocused()
316 {
317     WindowFocus(false);
318 }
319 
OnWindowForceUnfocused()320 void ContainerModalPattern::OnWindowForceUnfocused() {}
321 
WindowFocus(bool isFocus)322 void ContainerModalPattern::WindowFocus(bool isFocus)
323 {
324     auto theme = PipelineContext::GetCurrentContext()->GetTheme<ContainerModalTheme>();
325     isFocus_ = isFocus;
326     auto containerNode = GetHost();
327     CHECK_NULL_VOID(containerNode);
328 
329     // update container modal background
330     auto renderContext = containerNode->GetRenderContext();
331     CHECK_NULL_VOID(renderContext);
332     renderContext->UpdateBackgroundColor(theme->GetBackGroundColor(isFocus));
333     BorderColorProperty borderColor;
334     borderColor.SetColor(isFocus ? CONTAINER_BORDER_COLOR : CONTAINER_BORDER_COLOR_LOST_FOCUS);
335     renderContext->UpdateBorderColor(borderColor);
336 
337     ChangeCustomTitle(isFocus);
338     ChangeFloatingTitle(isFocus);
339     ChangeControlButtons(isFocus);
340 }
341 
ChangeCustomTitle(bool isFocus)342 void ContainerModalPattern::ChangeCustomTitle(bool isFocus)
343 {
344     // update custom title label
345     auto customTitleNode = GetCustomTitleNode();
346     CHECK_NULL_VOID(customTitleNode);
347     isFocus ? customTitleNode->FireOnWindowFocusedCallback() : customTitleNode->FireOnWindowUnfocusedCallback();
348 }
349 
ChangeControlButtons(bool isFocus)350 void ContainerModalPattern::ChangeControlButtons(bool isFocus)
351 {
352     auto containerNode = GetHost();
353     CHECK_NULL_VOID(containerNode);
354     auto controlButtonsNode = GetControlButtonRow();
355     CHECK_NULL_VOID(controlButtonsNode);
356 
357     // update leftSplit button
358     auto leftSplitButton =
359         AceType::DynamicCast<FrameNode>(GetTitleItemByIndex(controlButtonsNode, LEFT_SPLIT_BUTTON_INDEX));
360     ChangeTitleButtonIcon(leftSplitButton,
361         isFocus ? InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_SPLIT_LEFT
362                 : InternalResource::ResourceId::CONTAINER_MODAL_WINDOW_DEFOCUS_SPLIT_LEFT,
363         isFocus, false);
364 
365     // hide leftSplit button when window mode is WINDOW_MODE_SPLIT_PRIMARY type or split button can not show
366     bool hideLeftSplit = hideSplitButton_ || windowMode_ == WindowMode::WINDOW_MODE_SPLIT_PRIMARY;
367     leftSplitButton->GetLayoutProperty()->UpdateVisibility(hideLeftSplit ? VisibleType::GONE : VisibleType::VISIBLE);
368 
369     // update maximize button
370     auto maximizeButton =
371         AceType::DynamicCast<FrameNode>(GetTitleItemByIndex(controlButtonsNode, MAX_RECOVER_BUTTON_INDEX));
372     auto pipeline = PipelineContext::GetCurrentContext();
373     auto windowManager = pipeline->GetWindowManager();
374     MaximizeMode mode = windowManager->GetCurrentWindowMaximizeMode();
375     InternalResource::ResourceId maxId;
376     if (mode == MaximizeMode::MODE_AVOID_SYSTEM_BAR || windowMode_ == WindowMode::WINDOW_MODE_FULLSCREEN) {
377         maxId = InternalResource::ResourceId::IC_WINDOW_RESTORES;
378     } else {
379         maxId = InternalResource::ResourceId::IC_WINDOW_MAX;
380     }
381 
382     ChangeTitleButtonIcon(maximizeButton, maxId, isFocus, false);
383     // update minimize button
384     auto minimizeButton =
385         AceType::DynamicCast<FrameNode>(GetTitleItemByIndex(controlButtonsNode, MINIMIZE_BUTTON_INDEX));
386     ChangeTitleButtonIcon(minimizeButton,
387         InternalResource::ResourceId::IC_WINDOW_MIN, isFocus, false);
388 
389     // update close button
390     auto closeButton = AceType::DynamicCast<FrameNode>(GetTitleItemByIndex(controlButtonsNode, CLOSE_BUTTON_INDEX));
391     ChangeTitleButtonIcon(closeButton,
392         InternalResource::ResourceId::IC_WINDOW_CLOSE, isFocus, true);
393 }
394 
ChangeFloatingTitle(bool isFocus)395 void ContainerModalPattern::ChangeFloatingTitle(bool isFocus)
396 {
397     // update floating custom title label
398     auto customFloatingTitleNode = GetFloatingTitleNode();
399     CHECK_NULL_VOID(customFloatingTitleNode);
400     isFocus ? customFloatingTitleNode->FireOnWindowFocusedCallback()
401             : customFloatingTitleNode->FireOnWindowUnfocusedCallback();
402 }
403 
ChangeTitleButtonIcon(const RefPtr<FrameNode> & buttonNode,InternalResource::ResourceId icon,bool isFocus,bool isCloseBtn)404 void ContainerModalPattern::ChangeTitleButtonIcon(
405     const RefPtr<FrameNode>& buttonNode, InternalResource::ResourceId icon, bool isFocus, bool isCloseBtn)
406 {
407     auto theme = PipelineContext::GetCurrentContext()->GetTheme<ContainerModalTheme>();
408     auto renderContext = buttonNode->GetRenderContext();
409     CHECK_NULL_VOID(renderContext);
410     auto colorType = isFocus ? ControlBtnColorType::NORMAL : ControlBtnColorType::UNFOCUS;
411     auto color = theme->GetControlBtnColor(isCloseBtn, colorType);
412     renderContext->UpdateBackgroundColor(color);
413     auto buttonIcon = AceType::DynamicCast<FrameNode>(buttonNode->GetChildren().front());
414     CHECK_NULL_VOID(buttonIcon);
415     ImageSourceInfo imageSourceInfo;
416     imageSourceInfo.SetResourceId(icon);
417     colorType = isFocus ? ControlBtnColorType::NORMAL_FILL : ControlBtnColorType::UNFOCUS_FILL;
418     color = theme->GetControlBtnColor(isCloseBtn,  colorType);
419     imageSourceInfo.SetFillColor(color);
420     auto imageLayoutProperty = buttonIcon->GetLayoutProperty<ImageLayoutProperty>();
421     imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
422     buttonIcon->MarkModifyDone();
423     buttonNode->MarkModifyDone();
424 }
425 
CanShowFloatingTitle()426 bool ContainerModalPattern::CanShowFloatingTitle()
427 {
428     auto floatingTitleRow = GetFloatingTitleRow();
429     CHECK_NULL_RETURN(floatingTitleRow, false);
430     auto floatingLayoutProperty = floatingTitleRow->GetLayoutProperty();
431     CHECK_NULL_RETURN(floatingLayoutProperty, false);
432 
433     if (windowMode_ != WindowMode::WINDOW_MODE_FULLSCREEN && windowMode_ != WindowMode::WINDOW_MODE_SPLIT_PRIMARY &&
434         windowMode_ != WindowMode::WINDOW_MODE_SPLIT_SECONDARY) {
435         LOGI("Window is not full screen or split screen, can not show floating title.");
436         return false;
437     }
438 
439     if (floatingLayoutProperty->GetVisibilityValue(VisibleType::GONE) == VisibleType::VISIBLE) {
440         LOGI("Floating tittle is visible now, no need to show again.");
441         return false;
442     }
443     return true;
444 }
445 
SetAppTitle(const std::string & title)446 void ContainerModalPattern::SetAppTitle(const std::string& title)
447 {
448     LOGI("SetAppTitle successfully, title is %{public}s", title.c_str());
449     auto customTitleNode = GetCustomTitleNode();
450     CHECK_NULL_VOID(customTitleNode);
451     customTitleNode->FireAppTitleCallback(title);
452 
453     auto customFloatingTitleNode = GetFloatingTitleNode();
454     CHECK_NULL_VOID(customFloatingTitleNode);
455     customFloatingTitleNode->FireAppTitleCallback(title);
456 }
457 
SetAppIcon(const RefPtr<PixelMap> & icon)458 void ContainerModalPattern::SetAppIcon(const RefPtr<PixelMap>& icon)
459 {
460     CHECK_NULL_VOID(icon);
461     LOGI("SetAppIcon successfully");
462     auto customTitleNode = GetCustomTitleNode();
463     CHECK_NULL_VOID(customTitleNode);
464     customTitleNode->FireAppIconCallback(icon);
465 
466     auto customFloatingTitleNode = GetFloatingTitleNode();
467     CHECK_NULL_VOID(customFloatingTitleNode);
468     customFloatingTitleNode->FireAppIconCallback(icon);
469 }
470 
SetTitleButtonHide(const RefPtr<FrameNode> & controlButtonsNode,bool hideSplit,bool hideMaximize,bool hideMinimize)471 void ContainerModalPattern::SetTitleButtonHide(
472     const RefPtr<FrameNode>& controlButtonsNode, bool hideSplit, bool hideMaximize, bool hideMinimize)
473 {
474     auto leftSplitButton =
475         AceType::DynamicCast<FrameNode>(GetTitleItemByIndex(controlButtonsNode, LEFT_SPLIT_BUTTON_INDEX));
476     CHECK_NULL_VOID(leftSplitButton);
477     leftSplitButton->GetLayoutProperty()->UpdateVisibility(hideSplit ? VisibleType::GONE : VisibleType::VISIBLE);
478     leftSplitButton->MarkDirtyNode();
479 
480     auto maximizeButton =
481         AceType::DynamicCast<FrameNode>(GetTitleItemByIndex(controlButtonsNode, MAX_RECOVER_BUTTON_INDEX));
482     CHECK_NULL_VOID(maximizeButton);
483     maximizeButton->GetLayoutProperty()->UpdateVisibility(hideMaximize ? VisibleType::GONE : VisibleType::VISIBLE);
484     maximizeButton->MarkDirtyNode();
485 
486     auto minimizeButton = AceType::DynamicCast<FrameNode>(
487         GetTitleItemByIndex(controlButtonsNode, MINIMIZE_BUTTON_INDEX));
488     CHECK_NULL_VOID(minimizeButton);
489     minimizeButton->GetLayoutProperty()->UpdateVisibility(hideMinimize ? VisibleType::GONE : VisibleType::VISIBLE);
490     minimizeButton->MarkDirtyNode();
491 }
492 
SetContainerButtonHide(bool hideSplit,bool hideMaximize,bool hideMinimize)493 void ContainerModalPattern::SetContainerButtonHide(bool hideSplit, bool hideMaximize, bool hideMinimize)
494 {
495     auto controlButtonsRow = GetControlButtonRow();
496     CHECK_NULL_VOID(controlButtonsRow);
497     SetTitleButtonHide(controlButtonsRow, hideSplit, hideMaximize, hideMinimize);
498     hideSplitButton_ = hideSplit;
499     LOGI("Set containerModal button status successfully, hideSplit: %{public}d, hideMaximize: %{public}d, "
500          "hideMinimize: %{public}d",
501         hideSplit, hideMaximize, hideMinimize);
502 }
503 
SetCloseButtonStatus(bool isEnabled)504 void ContainerModalPattern::SetCloseButtonStatus(bool isEnabled)
505 {
506     auto controlButtonsRow = GetControlButtonRow();
507     CHECK_NULL_VOID(controlButtonsRow);
508 
509     // set closeButton enable or disable
510     auto closeButton = AceType::DynamicCast<FrameNode>(GetTitleItemByIndex(controlButtonsRow, CLOSE_BUTTON_INDEX));
511     CHECK_NULL_VOID(closeButton);
512     auto buttonEvent = closeButton->GetEventHub<ButtonEventHub>();
513     CHECK_NULL_VOID(buttonEvent);
514     buttonEvent->SetEnabled(isEnabled);
515     LOGI("Set close button status %{public}s", isEnabled ? "enable" : "disable");
516 }
517 
UpdateGestureRowVisible()518 void ContainerModalPattern::UpdateGestureRowVisible()
519 {
520     auto gestureRow = GetGestureRow();
521     CHECK_NULL_VOID(gestureRow);
522     auto customTitleRow = GetCustomTitleRow();
523     CHECK_NULL_VOID(customTitleRow);
524     auto buttonsRow = GetControlButtonRow();
525     CHECK_NULL_VOID(buttonsRow);
526     auto gestureRowProp = gestureRow->GetLayoutProperty();
527     auto customTitleRowProp = customTitleRow->GetLayoutProperty();
528     auto buttonsRowProp = buttonsRow->GetLayoutProperty();
529     if (customTitleRowProp->GetVisibilityValue(VisibleType::VISIBLE) == VisibleType::GONE &&
530         buttonsRowProp->GetVisibilityValue(VisibleType::VISIBLE) == VisibleType::VISIBLE) {
531         gestureRowProp->UpdateVisibility(VisibleType::VISIBLE);
532     } else {
533         gestureRowProp->UpdateVisibility(VisibleType::GONE);
534     }
535 }
536 
SetContainerModalTitleVisible(bool customTitleSettedShow,bool floatingTitleSettedShow)537 void ContainerModalPattern::SetContainerModalTitleVisible(bool customTitleSettedShow, bool floatingTitleSettedShow)
538 {
539     LOGI("ContainerModal customTitleSettedShow=%{public}d, floatingTitleSettedShow=%{public}d", customTitleSettedShow,
540         floatingTitleSettedShow);
541     customTitleSettedShow_ = customTitleSettedShow;
542     auto customTitleRow = GetCustomTitleRow();
543     CHECK_NULL_VOID(customTitleRow);
544     auto customTitleRowProp = customTitleRow->GetLayoutProperty();
545     if (!customTitleSettedShow) {
546         customTitleRowProp->UpdateVisibility(VisibleType::GONE);
547     } else if (CanShowCustomTitle()) {
548         customTitleRowProp->UpdateVisibility(VisibleType::VISIBLE);
549     }
550     floatingTitleSettedShow_ = floatingTitleSettedShow;
551     auto floatingTitleRow = GetFloatingTitleRow();
552     CHECK_NULL_VOID(floatingTitleRow);
553     auto floatingTitleRowProp = floatingTitleRow->GetLayoutProperty();
554     if (!floatingTitleSettedShow) {
555         floatingTitleRowProp->UpdateVisibility(VisibleType::GONE);
556     }
557 
558     auto buttonsRow = GetControlButtonRow();
559     CHECK_NULL_VOID(buttonsRow);
560     buttonsRow->SetHitTestMode(HitTestMode::HTMTRANSPARENT_SELF);
561     UpdateGestureRowVisible();
562     TrimFloatingWindowLayout();
563 }
564 
SetContainerModalTitleHeight(int32_t height)565 void ContainerModalPattern::SetContainerModalTitleHeight(int32_t height)
566 {
567     LOGI("ContainerModal SetContainerModalTitleHeight height=%{public}d", height);
568     if (height < 0) {
569         height = 0;
570     }
571     titleHeight_ = Dimension(Dimension(height, DimensionUnit::PX).ConvertToVp(), DimensionUnit::VP);
572     auto customTitleRow = GetCustomTitleRow();
573     UpdateRowHeight(customTitleRow, titleHeight_);
574     auto controlButtonsRow = GetControlButtonRow();
575     UpdateRowHeight(controlButtonsRow, titleHeight_);
576     auto gestureRow = GetGestureRow();
577     UpdateRowHeight(gestureRow, titleHeight_);
578     CallButtonsRectChange();
579 }
580 
GetContainerModalTitleHeight()581 int32_t ContainerModalPattern::GetContainerModalTitleHeight()
582 {
583     return static_cast<int32_t>(ceil(titleHeight_.ConvertToPx()));
584 }
585 
GetContainerModalButtonsRect(RectF & containerModal,RectF & buttons)586 bool ContainerModalPattern::GetContainerModalButtonsRect(RectF& containerModal, RectF& buttons)
587 {
588     auto column = GetColumnNode();
589     CHECK_NULL_RETURN(column, false);
590     auto columnRect = column->GetGeometryNode()->GetFrameRect();
591     containerModal = columnRect;
592     if (columnRect.Width() == 0) {
593         LOGW("Get rect of buttons failed, the rect is measuring.");
594         return false;
595     }
596 
597     auto controlButtonsRow = GetControlButtonRow();
598     CHECK_NULL_RETURN(controlButtonsRow, false);
599     auto children = controlButtonsRow->GetChildren();
600     RectF firstButtonRect;
601     RectF lastButtonRect;
602     for (auto& child : children) {
603         auto node = AceType::DynamicCast<FrameNode>(child);
604         if (node->GetLayoutProperty()->GetVisibilityValue(VisibleType::VISIBLE) != VisibleType::VISIBLE) {
605             continue;
606         }
607         auto rect = node->GetGeometryNode()->GetFrameRect();
608         if (firstButtonRect.Width() == 0) {
609             firstButtonRect = rect;
610         }
611         lastButtonRect = rect;
612     }
613     buttons = firstButtonRect.CombineRectT(lastButtonRect);
614     if (buttons.Width() == 0) {
615         LOGW("Get rect of buttons failed, buttons are hidden");
616         return false;
617     }
618 
619     auto widthByPx = (TITLE_PADDING_START + TITLE_PADDING_END).ConvertToPx() + buttons.Width();
620     auto isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
621     if (isRtl) {
622         buttons.SetLeft(0);
623     } else {
624         buttons.SetLeft(containerModal.Width() - widthByPx);
625     }
626     buttons.SetTop(0);
627     buttons.SetWidth(widthByPx);
628     buttons.SetHeight(titleHeight_.ConvertToPx());
629     return true;
630 }
631 
SubscribeContainerModalButtonsRectChange(std::function<void (RectF & containerModal,RectF & buttons)> && callback)632 void ContainerModalPattern::SubscribeContainerModalButtonsRectChange(
633     std::function<void(RectF& containerModal, RectF& buttons)>&& callback)
634 {
635     controlButtonsRectChangeCallback_ = std::move(callback);
636 }
637 
GetWindowPaintRectWithoutMeasureAndLayout(RectInt & rect)638 void ContainerModalPattern::GetWindowPaintRectWithoutMeasureAndLayout(RectInt& rect)
639 {
640     auto host = GetHost();
641     CHECK_NULL_VOID(host);
642     auto layoutProperty = host->GetLayoutProperty();
643     CHECK_NULL_VOID(layoutProperty);
644     auto titleHeight = round(GetCustomTitleHeight().ConvertToPx());
645     auto padding = layoutProperty->CreatePaddingAndBorder();
646     rect.SetRect(padding.Offset().GetX(), padding.Offset().GetY() + titleHeight, rect.Width() - padding.Width(),
647         rect.Height() - padding.Height() - titleHeight);
648 }
649 
CallButtonsRectChange()650 void ContainerModalPattern::CallButtonsRectChange()
651 {
652     CHECK_NULL_VOID(controlButtonsRectChangeCallback_);
653     RectF containerModal;
654     RectF buttons;
655     GetContainerModalButtonsRect(containerModal, buttons);
656     if (buttonsRect_ == buttons) {
657         return;
658     }
659     buttonsRect_ = buttons;
660     auto taskExecutor = Container::CurrentTaskExecutor();
661     CHECK_NULL_VOID(taskExecutor);
662     taskExecutor->PostTask(
663         [containerModal, buttons, cb = controlButtonsRectChangeCallback_]() mutable {
664             if (cb) {
665                 cb(containerModal, buttons);
666             }
667         },
668         TaskExecutor::TaskType::JS, "ArkUIContainerModalButtonsRectChange");
669 }
670 
InitTitle()671 void ContainerModalPattern::InitTitle()
672 {
673     auto pipeline = PipelineContext::GetCurrentContext();
674     CHECK_NULL_VOID(pipeline);
675     auto themeManager = pipeline->GetThemeManager();
676     CHECK_NULL_VOID(themeManager);
677     auto themeConstants = themeManager->GetThemeConstants();
678     CHECK_NULL_VOID(themeConstants);
679     auto id = pipeline->GetWindowManager()->GetAppIconId();
680     auto pixelMap = themeConstants->GetPixelMap(id);
681     if (pixelMap) {
682         RefPtr<PixelMap> icon = PixelMap::CreatePixelMap(&pixelMap);
683         SetAppIcon(icon);
684     } else {
685         LOGW("Cannot get pixelmap, try media path."); // use themeConstants GetMediaPath
686     }
687     SetAppTitle(themeConstants->GetString(pipeline->GetWindowManager()->GetAppLabelId()));
688 }
689 
Init()690 void ContainerModalPattern::Init()
691 {
692     InitContainerEvent();
693     InitTitle();
694     InitLayoutProperty();
695 }
696 
OnColorConfigurationUpdate()697 void ContainerModalPattern::OnColorConfigurationUpdate()
698 {
699     WindowFocus(isFocus_);
700 }
701 
InitLayoutProperty()702 void ContainerModalPattern::InitLayoutProperty()
703 {
704     auto containerModal = GetHost();
705     auto column = GetColumnNode();
706     auto stack = GetStackNode();
707     auto content = GetContentNode();
708     CHECK_NULL_VOID(content);
709     auto buttonsRow = GetControlButtonRow();
710     CHECK_NULL_VOID(buttonsRow);
711     auto contentProperty = content->GetLayoutProperty();
712     auto buttonsRowProperty = buttonsRow->GetLayoutProperty<LinearLayoutProperty>();
713 
714     containerModal->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT);
715     column->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT);
716     stack->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT);
717     contentProperty->UpdateMeasureType(MeasureType::MATCH_CONTENT);
718     contentProperty->UpdateUserDefinedIdealSize(
719         CalcSize(CalcLength(1.0, DimensionUnit::PERCENT), CalcLength(1.0, DimensionUnit::PERCENT)));
720     buttonsRowProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
721     auto buttonHeight = (CONTAINER_TITLE_HEIGHT == titleHeight_) ? CONTAINER_TITLE_HEIGHT : titleHeight_;
722     buttonsRowProperty->UpdateUserDefinedIdealSize(
723         CalcSize(CalcLength(1.0, DimensionUnit::PERCENT), CalcLength(buttonHeight)));
724     buttonsRowProperty->UpdateMainAxisAlign(FlexAlign::FLEX_END);
725     buttonsRowProperty->UpdateCrossAxisAlign(FlexAlign::CENTER);
726 
727     InitTitleRowLayoutProperty(GetCustomTitleRow());
728     InitTitleRowLayoutProperty(GetFloatingTitleRow());
729     InitButtonsLayoutProperty();
730 
731     containerModal->MarkModifyDone();
732 }
733 
InitTitleRowLayoutProperty(RefPtr<FrameNode> titleRow)734 void ContainerModalPattern::InitTitleRowLayoutProperty(RefPtr<FrameNode> titleRow)
735 {
736     CHECK_NULL_VOID(titleRow);
737     auto titleRowProperty = titleRow->GetLayoutProperty<LinearLayoutProperty>();
738     CHECK_NULL_VOID(titleRowProperty);
739     titleRowProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
740     titleRowProperty->UpdateUserDefinedIdealSize(
741         CalcSize(CalcLength(1.0, DimensionUnit::PERCENT), CalcLength(CONTAINER_TITLE_HEIGHT)));
742     titleRowProperty->UpdateMainAxisAlign(FlexAlign::FLEX_START);
743     titleRowProperty->UpdateCrossAxisAlign(FlexAlign::CENTER);
744     auto isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
745     PaddingProperty padding;
746     auto sidePadding = isRtl ? &padding.left : & padding.right;
747     *sidePadding = GetControlButtonRowWidth();
748     titleRowProperty->UpdatePadding(padding);
749 }
750 
GetControlButtonRowWidth()751 CalcLength ContainerModalPattern::GetControlButtonRowWidth()
752 {
753     auto row = GetControlButtonRow();
754     // default
755     int32_t buttonNum = 0;
756     const auto& children = row->GetChildren();
757     for (const auto& child : children) {
758         auto childButton = AceType::DynamicCast<FrameNode>(child);
759         if (childButton && childButton->IsVisible()) {
760             buttonNum++;
761         }
762     }
763     return CalcLength(TITLE_ELEMENT_MARGIN_HORIZONTAL * (buttonNum - 1) + TITLE_BUTTON_SIZE * buttonNum +
764                       TITLE_PADDING_START + TITLE_PADDING_END);
765 }
766 
InitColumnTouchTestFunc()767 void ContainerModalPattern::InitColumnTouchTestFunc()
768 {
769     auto column = GetColumnNode();
770     CHECK_NULL_VOID(column);
771     auto eventHub = column->GetOrCreateGestureEventHub();
772     auto func = [](const std::vector<TouchTestInfo>& touchInfo) -> TouchResult {
773         TouchResult touchRes;
774         TouchResult defaultRes;
775         touchRes.strategy = TouchTestStrategy::FORWARD_COMPETITION;
776         defaultRes.strategy = TouchTestStrategy::DEFAULT;
777         defaultRes.id = "";
778         for (auto info : touchInfo) {
779             if (info.id.compare(CONTAINER_MODAL_STACK_ID) == 0) {
780                 touchRes.id = info.id;
781                 return touchRes;
782             }
783         }
784         return defaultRes;
785     };
786     eventHub->SetOnTouchTestFunc(func);
787 }
788 
InitButtonsLayoutProperty()789 void ContainerModalPattern::InitButtonsLayoutProperty()
790 {
791     auto buttonsRow = GetControlButtonRow();
792     CHECK_NULL_VOID(buttonsRow);
793     auto isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
794     auto buttons = buttonsRow->GetChildren();
795     for (uint64_t index = 0; index < buttons.size(); index++) {
796         auto space = (index == buttons.size() - 1) ? TITLE_PADDING_END : TITLE_ELEMENT_MARGIN_HORIZONTAL;
797         MarginProperty margin;
798         if (isRtl) {
799             margin.left = CalcLength(space);
800             margin.right = CalcLength();
801         } else {
802             margin.left = CalcLength();
803             margin.right = CalcLength(space);
804         }
805         auto button = AceType::DynamicCast<FrameNode>(buttonsRow->GetChildAtIndex(index));
806         CHECK_NULL_VOID(button);
807         auto layoutProp = button->GetLayoutProperty<ButtonLayoutProperty>();
808         layoutProp->UpdateMargin(margin);
809         button->MarkModifyDone();
810         button->MarkDirtyNode();
811     }
812 }
813 
OnLanguageConfigurationUpdate()814 void ContainerModalPattern::OnLanguageConfigurationUpdate()
815 {
816     InitTitle();
817     InitLayoutProperty();
818 }
819 
GetCustomTitleHeight()820 Dimension ContainerModalPattern::GetCustomTitleHeight()
821 {
822     auto customTitleRow = GetCustomTitleRow();
823     Dimension zeroHeight;
824     CHECK_NULL_RETURN(customTitleRow, zeroHeight);
825     auto property = customTitleRow->GetLayoutProperty();
826     if (property->GetVisibilityValue(VisibleType::VISIBLE) != VisibleType::VISIBLE) {
827         return zeroHeight;
828     }
829     return titleHeight_;
830 }
831 
GetStackNodeRadius()832 Dimension ContainerModalPattern::GetStackNodeRadius()
833 {
834     Dimension radius = customTitleSettedShow_ ? CONTAINER_INNER_RADIUS : CONTAINER_OUTER_RADIUS;
835     auto trimRadiusPx = Dimension(round(radius.ConvertToPx() * 2) / 2.0);
836     auto trimRadiusVp = Dimension(trimRadiusPx.ConvertToVp(), DimensionUnit::VP);
837     return trimRadiusVp;
838 }
839 
CanShowCustomTitle()840 bool ContainerModalPattern::CanShowCustomTitle()
841 {
842     auto buttonsRow = GetControlButtonRow();
843     CHECK_NULL_RETURN(buttonsRow, false);
844     auto visibility = buttonsRow->GetLayoutProperty()->GetVisibilityValue(VisibleType::GONE);
845     return visibility == VisibleType::VISIBLE;
846 }
847 
TrimFloatingWindowLayout()848 void ContainerModalPattern::TrimFloatingWindowLayout()
849 {
850     if (windowMode_ != WindowMode::WINDOW_MODE_FLOATING) {
851         return;
852     }
853     auto stack = GetStackNode();
854     CHECK_NULL_VOID(stack);
855     auto stackRender = stack->GetRenderContext();
856     BorderRadiusProperty borderRadius;
857     borderRadius.SetRadius(GetStackNodeRadius());
858     stackRender->UpdateBorderRadius(borderRadius);
859     auto host = GetHost();
860     CHECK_NULL_VOID(host);
861     auto hostProp = host->GetLayoutProperty();
862     PaddingProperty padding;
863     auto customtitleRow = GetCustomTitleRow();
864     CHECK_NULL_VOID(customtitleRow);
865     auto customTitleRowProp = customtitleRow->GetLayoutProperty();
866     if (customTitleRowProp->GetVisibilityValue(VisibleType::GONE) == VisibleType::VISIBLE) {
867         padding = { CalcLength(CONTENT_PADDING), CalcLength(CONTENT_PADDING), std::nullopt,
868             CalcLength(CONTENT_PADDING) };
869     }
870     hostProp->UpdatePadding(padding);
871 }
872 } // namespace OHOS::Ace::NG