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