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