1 /*
2 * Copyright (c) 2023 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/overlay/sheet_presentation_layout_algorithm.h"
17
18 #include "base/geometry/axis.h"
19 #include "base/geometry/ng/offset_t.h"
20 #include "base/geometry/ng/size_t.h"
21 #include "base/log/ace_trace.h"
22 #include "base/memory/ace_type.h"
23 #include "base/utils/utils.h"
24 #include "base/window/foldable_window.h"
25 #include "core/components/common/layout/grid_system_manager.h"
26 #include "core/components_ng/base/frame_node.h"
27 #include "core/components_ng/layout/layout_algorithm.h"
28 #include "core/components_ng/pattern/overlay/sheet_presentation_pattern.h"
29 #include "core/components_ng/property/layout_constraint.h"
30 #include "core/components_ng/property/measure_property.h"
31 #include "core/components_ng/property/measure_utils.h"
32 #include "core/components_v2/inspector/inspector_constants.h"
33 #include "core/pipeline_ng/pipeline_context.h"
34
35 namespace OHOS::Ace::NG {
36 namespace {
37 constexpr int32_t SHEET_HALF_SIZE = 2;
38 constexpr Dimension WINDOW_EDGE_SPACE = 6.0_vp;
39 constexpr Dimension ARROW_VERTICAL_P1_OFFSET_X = 8.0_vp;
40 constexpr Dimension ARROW_VERTICAL_P5_OFFSET_X = 8.0_vp;
41 std::map<Placement, std::vector<Placement>> DIRECTIONS_STATES = {
42 { Placement::BOTTOM,
43 {
44 Placement::BOTTOM,
45 } },
46 };
47 std::map<Placement, std::vector<Placement>> PLACEMENT_STATES = {
48 { Placement::BOTTOM,
49 {
50 Placement::BOTTOM,
51 Placement::BOTTOM_RIGHT,
52 Placement::BOTTOM_LEFT,
53 } },
54 };
55 } // namespace
56
InitParameter()57 void SheetPresentationLayoutAlgorithm::InitParameter()
58 {
59 auto pipeline = PipelineContext::GetCurrentContext();
60 CHECK_NULL_VOID(pipeline);
61 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
62 CHECK_NULL_VOID(sheetTheme);
63 sheetRadius_ = sheetTheme->GetSheetRadius().ConvertToPx();
64 // if 2in1, enableHoverMode is true by default.
65 auto enableHoverMode = sheetStyle_.enableHoverMode.value_or(false);
66 hoverModeArea_ = sheetStyle_.hoverModeArea.value_or(HoverModeAreaType::BOTTOM_SCREEN);
67 auto safeAreaManager = pipeline->GetSafeAreaManager();
68 CHECK_NULL_VOID(safeAreaManager);
69 auto keyboardInsert = safeAreaManager->GetKeyboardInset();
70 isKeyBoardShow_ = keyboardInsert.IsValid();
71 isHoverMode_ = enableHoverMode ? pipeline->IsHalfFoldHoverStatus() : false;
72 }
73
CalculateSheetHeightInOtherScenes(LayoutWrapper * layoutWrapper)74 void SheetPresentationLayoutAlgorithm::CalculateSheetHeightInOtherScenes(LayoutWrapper* layoutWrapper)
75 {
76 CHECK_NULL_VOID(layoutWrapper);
77 auto host = layoutWrapper->GetHostNode();
78 CHECK_NULL_VOID(host);
79 auto sheetPattern = host->GetPattern<SheetPresentationPattern>();
80 CHECK_NULL_VOID(sheetPattern);
81 auto foldCreaseRect = sheetPattern->GetFoldScreenRect();
82 if (sheetType_ == SheetType::SHEET_CENTER && isHoverMode_) {
83 float upScreenHeight = foldCreaseRect.Top() - SHEET_HOVERMODE_UP_HEIGHT.ConvertToPx();
84 float downScreenHeight = sheetMaxHeight_ - SHEET_HOVERMODE_DOWN_HEIGHT.ConvertToPx() - foldCreaseRect.Bottom();
85 TAG_LOGD(AceLogTag::ACE_SHEET, "upScreenHeight: %{public}f, downScreenHeight: %{public}f.", upScreenHeight,
86 downScreenHeight);
87 sheetHeight_ = std::min(sheetHeight_,
88 (hoverModeArea_ == HoverModeAreaType::TOP_SCREEN || isKeyBoardShow_) ? upScreenHeight : downScreenHeight);
89 }
90 }
91
CalculateSheetOffsetInOtherScenes(LayoutWrapper * layoutWrapper)92 void SheetPresentationLayoutAlgorithm::CalculateSheetOffsetInOtherScenes(LayoutWrapper* layoutWrapper)
93 {
94 CHECK_NULL_VOID(layoutWrapper);
95 auto host = layoutWrapper->GetHostNode();
96 CHECK_NULL_VOID(host);
97 auto sheetPattern = host->GetPattern<SheetPresentationPattern>();
98 CHECK_NULL_VOID(sheetPattern);
99 auto geometryNode = layoutWrapper->GetGeometryNode();
100 CHECK_NULL_VOID(geometryNode);
101 auto foldCreaseRect = sheetPattern->GetFoldScreenRect();
102 auto frameSizeHeight = geometryNode->GetFrameSize().Height();
103 if (sheetType_ == SheetType::SHEET_CENTER && isHoverMode_) {
104 float upScreenHeight = foldCreaseRect.Top() - SHEET_HOVERMODE_UP_HEIGHT.ConvertToPx();
105 float downScreenHeight = sheetMaxHeight_ - SHEET_HOVERMODE_DOWN_HEIGHT.ConvertToPx() - foldCreaseRect.Bottom();
106 sheetOffsetY_ = (hoverModeArea_ == HoverModeAreaType::TOP_SCREEN || isKeyBoardShow_)
107 ? (SHEET_HOVERMODE_UP_HEIGHT.ConvertToPx() +
108 (upScreenHeight - frameSizeHeight) / SHEET_HALF_SIZE)
109 : (foldCreaseRect.Bottom() + (downScreenHeight - frameSizeHeight) / SHEET_HALF_SIZE);
110 }
111 }
112
Measure(LayoutWrapper * layoutWrapper)113 void SheetPresentationLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
114 {
115 CHECK_NULL_VOID(layoutWrapper);
116 auto layoutProperty = AceType::DynamicCast<SheetPresentationProperty>(layoutWrapper->GetLayoutProperty());
117 CHECK_NULL_VOID(layoutProperty);
118 sheetStyle_ = layoutProperty->GetSheetStyleValue();
119 auto layoutConstraint = layoutProperty->GetLayoutConstraint();
120 if (!layoutConstraint) {
121 TAG_LOGE(AceLogTag::ACE_SHEET, "fail to measure sheet due to layoutConstraint is nullptr");
122 return;
123 }
124 InitParameter();
125 auto maxSize = layoutConstraint->maxSize;
126 if (layoutWrapper->GetGeometryNode() && layoutWrapper->GetGeometryNode()->GetParentLayoutConstraint()) {
127 auto parentConstraint = layoutWrapper->GetGeometryNode()->GetParentLayoutConstraint();
128 layoutConstraint = parentConstraint.value();
129 layoutProperty->UpdateLayoutConstraint(layoutConstraint.value());
130 maxSize = layoutConstraint->maxSize;
131 sheetMaxHeight_ = maxSize.Height();
132 sheetMaxWidth_ = maxSize.Width();
133 sheetWidth_ = GetWidthByScreenSizeType(maxSize, layoutWrapper);
134 sheetHeight_ = GetHeightByScreenSizeType(maxSize);
135 if (sheetStyle_.width.has_value()) {
136 float width = 0.0f;
137 if (sheetStyle_.width->Unit() == DimensionUnit::PERCENT) {
138 width = sheetStyle_.width->ConvertToPxWithSize(maxSize.Width());
139 } else {
140 width = sheetStyle_.width->ConvertToPx();
141 }
142 if (width > maxSize.Width() || width < 0.0f) {
143 width = sheetWidth_;
144 }
145 sheetWidth_ = width;
146 }
147 CalculateSheetHeightInOtherScenes(layoutWrapper);
148 SizeF idealSize(sheetWidth_, sheetHeight_);
149 layoutWrapper->GetGeometryNode()->SetFrameSize(idealSize);
150 layoutWrapper->GetGeometryNode()->SetContentSize(idealSize);
151 auto childConstraint = CreateSheetChildConstraint(layoutProperty, layoutWrapper);
152 layoutConstraint->percentReference = SizeF(sheetWidth_, sheetHeight_);
153 for (auto&& child : layoutWrapper->GetAllChildrenWithBuild()) {
154 child->Measure(childConstraint);
155 }
156 auto scrollNode = layoutWrapper->GetChildByIndex(1);
157 CHECK_NULL_VOID(scrollNode);
158 childConstraint.selfIdealSize.SetWidth(childConstraint.maxSize.Width());
159 scrollNode->Measure(childConstraint);
160 if ((sheetType_ == SheetType::SHEET_CENTER || sheetType_ == SheetType::SHEET_POPUP)
161 && (sheetStyle_.sheetHeight.sheetMode.value_or(SheetMode::LARGE) == SheetMode::AUTO)) {
162 auto&& children = layoutWrapper->GetAllChildrenWithBuild();
163 auto secondIter = std::next(children.begin(), 1);
164 auto secondChild = *secondIter;
165 CHECK_NULL_VOID(secondChild);
166 auto&& scrollChild = secondChild->GetAllChildrenWithBuild();
167 auto builder = scrollChild.front();
168 CHECK_NULL_VOID(builder);
169 auto operatoration = children.front();
170 CHECK_NULL_VOID(operatoration);
171 auto operatorGeometryNode = operatoration->GetGeometryNode();
172 CHECK_NULL_VOID(operatorGeometryNode);
173 auto builderGeometryNode = builder->GetGeometryNode();
174 CHECK_NULL_VOID(builderGeometryNode);
175 sheetHeight_ =
176 operatorGeometryNode->GetFrameSize().Height() + builderGeometryNode->GetFrameSize().Height();
177 float sheetMaxHeight = sheetMaxHeight_;
178 if (SheetInSplitWindow()) {
179 auto pipelineContext = PipelineContext::GetCurrentContext();
180 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
181 sheetMaxHeight = windowGlobalRect.Height() - SHEET_SPLIT_STATUS_BAR.ConvertToPx()-
182 SHEET_SPLIT_AI_BAR.ConvertToPx();
183 }
184 auto maxHeight = std::min(sheetMaxHeight, sheetMaxWidth_) * POPUP_LARGE_SIZE;
185 maxHeight = SheetInSplitWindow()
186 ? maxHeight : std::max(maxHeight, static_cast<float>(SHEET_BIG_WINDOW_MIN_HEIGHT.ConvertToPx()));
187 if (LessNotEqual(sheetHeight_, 0.0f)) {
188 sheetHeight_ = SHEET_BIG_WINDOW_HEIGHT.ConvertToPx();
189 } else if (LessOrEqual(sheetHeight_, SHEET_BIG_WINDOW_MIN_HEIGHT.ConvertToPx()) && !SheetInSplitWindow()) {
190 sheetHeight_ = SHEET_BIG_WINDOW_MIN_HEIGHT.ConvertToPx();
191 } else if (GreatOrEqual(sheetHeight_, maxHeight)) {
192 sheetHeight_ = maxHeight;
193 }
194 SizeF idealSize(sheetWidth_, sheetHeight_);
195 layoutWrapper->GetGeometryNode()->SetFrameSize(idealSize);
196 childConstraint = CreateSheetChildConstraint(layoutProperty, layoutWrapper);
197 secondChild->Measure(childConstraint);
198 }
199 }
200 }
201
Layout(LayoutWrapper * layoutWrapper)202 void SheetPresentationLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
203 {
204 CHECK_NULL_VOID(layoutWrapper);
205 const auto& pipeline = PipelineContext::GetCurrentContext();
206 CHECK_NULL_VOID(pipeline);
207 sheetOffsetX_ = (sheetMaxWidth_ - sheetWidth_) / SHEET_HALF_SIZE;
208 if (sheetType_ == SheetType::SHEET_BOTTOMLANDSPACE) {
209 sheetOffsetX_ = (sheetMaxWidth_ - sheetWidth_) / SHEET_HALF_SIZE;
210 } else if (sheetType_ == SheetType::SHEET_CENTER) {
211 sheetOffsetX_ = (sheetMaxWidth_ - sheetWidth_) / SHEET_HALF_SIZE;
212 } else if (sheetType_ == SheetType::SHEET_POPUP) {
213 auto frameNode = layoutWrapper->GetHostNode();
214 CHECK_NULL_VOID(frameNode);
215 auto parent = DynamicCast<FrameNode>(frameNode->GetParent());
216 CHECK_NULL_VOID(parent);
217 auto parentOffset = parent->GetPaintRectOffset();
218 OffsetF popupStyleSheetOffset = GetPopupStyleSheetOffset();
219 // need to subtract the SheetWrapper relative to the upper left corner of the window,
220 // which is the offset of the upper left corner of the bubble relative to the SheetWrapper
221 sheetOffsetX_ = popupStyleSheetOffset.GetX() - parentOffset.GetX();
222 sheetOffsetY_ = popupStyleSheetOffset.GetY() - parentOffset.GetY();
223 }
224 CalculateSheetOffsetInOtherScenes(layoutWrapper);
225 TAG_LOGD(AceLogTag::ACE_SHEET, "Sheet layout info, sheetOffsetX_ is: %{public}f, sheetOffsetY_ is: %{public}f",
226 sheetOffsetX_, sheetOffsetY_);
227 OffsetF positionOffset;
228 positionOffset.SetX(sheetOffsetX_);
229 positionOffset.SetY(0.0f);
230 auto geometryNode = layoutWrapper->GetGeometryNode();
231 CHECK_NULL_VOID(geometryNode);
232 // This step is only to determine the position of x, because y is to be done by the bit movement effect
233 geometryNode->SetMarginFrameOffset(positionOffset);
234 OffsetF translate(0.0f, 0.0f);
235 if (sheetType_ == SheetType::SHEET_POPUP) {
236 translate += OffsetF(0, SHEET_ARROW_HEIGHT.ConvertToPx());
237 }
238 for (const auto& child : layoutWrapper->GetAllChildrenWithBuild()) {
239 child->GetGeometryNode()->SetMarginFrameOffset(translate);
240 child->Layout();
241 translate += OffsetF(0, child->GetGeometryNode()->GetFrameSize().Height());
242 }
243 }
244
245 // Get the offset of the popupSheet relative to the upper left corner of the window
GetPopupStyleSheetOffset()246 OffsetF SheetPresentationLayoutAlgorithm::GetPopupStyleSheetOffset()
247 {
248 auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
249 CHECK_NULL_RETURN(targetNode, OffsetF());
250 auto geometryNode = targetNode->GetGeometryNode();
251 CHECK_NULL_RETURN(geometryNode, OffsetF());
252 auto targetSize = geometryNode->GetFrameSize();
253 auto targetOffset = targetNode->GetPaintRectOffset();
254 return GetOffsetInAvoidanceRule(targetSize, targetOffset);
255 }
256
GetOffsetInAvoidanceRule(const SizeF & targetSize,const OffsetF & targetOffset)257 OffsetF SheetPresentationLayoutAlgorithm::GetOffsetInAvoidanceRule(const SizeF& targetSize, const OffsetF& targetOffset)
258 {
259 // The current default Placement is Placement::BOTTOM
260 auto placement = Placement::BOTTOM;
261 auto targetPlacement = AvoidanceRuleOfPlacement(placement, targetSize, targetOffset);
262 if (getOffsetFunc_.find(targetPlacement) == getOffsetFunc_.end()) {
263 TAG_LOGW(AceLogTag::ACE_SHEET, "It is an invalid Placement for current PopSheet.");
264 return {};
265 }
266 auto offsetFunc = getOffsetFunc_[targetPlacement];
267 CHECK_NULL_RETURN(offsetFunc, OffsetF());
268 return (this->*offsetFunc)(targetSize, targetOffset);
269 }
270
AvoidanceRuleOfPlacement(const Placement & currentPlacement,const SizeF & targetSize,const OffsetF & targetOffset)271 Placement SheetPresentationLayoutAlgorithm::AvoidanceRuleOfPlacement(
272 const Placement& currentPlacement, const SizeF& targetSize, const OffsetF& targetOffset)
273 {
274 Placement targetPlacement = currentPlacement;
275 TAG_LOGD(AceLogTag::ACE_SHEET, "Init PopupSheet placement: %{public}s",
276 PlacementUtils::ConvertPlacementToString(targetPlacement).c_str());
277 // Step1: Determine the direction
278 auto& directionVec = DIRECTIONS_STATES[targetPlacement];
279 for (auto placement : directionVec) {
280 auto& placementFunc = directionCheckFunc_[placement];
281 if (placementFunc == nullptr) {
282 continue;
283 }
284 if ((this->*placementFunc)(targetSize, targetOffset)) {
285 targetPlacement = placement;
286 break;
287 }
288 }
289 TAG_LOGD(AceLogTag::ACE_SHEET, "After step1, placement: %{public}s",
290 PlacementUtils::ConvertPlacementToString(targetPlacement).c_str());
291 // Step2: Determine the Placement in that direction
292 auto& placementVec = PLACEMENT_STATES[targetPlacement];
293 for (auto placement : placementVec) {
294 auto& placementFunc = placementCheckFunc_[placement];
295 if (placementFunc == nullptr) {
296 continue;
297 }
298 if ((this->*placementFunc)(targetSize, targetOffset)) {
299 targetPlacement = placement;
300 break;
301 }
302 }
303 TAG_LOGD(AceLogTag::ACE_SHEET, "After step2, placement: %{public}s",
304 PlacementUtils::ConvertPlacementToString(targetPlacement).c_str());
305 return targetPlacement;
306 }
307
CheckDirectionBottom(const SizeF & targetSize,const OffsetF & targetOffset)308 bool SheetPresentationLayoutAlgorithm::CheckDirectionBottom(const SizeF& targetSize, const OffsetF& targetOffset)
309 {
310 // Generalized bottom direction,
311 // determine whether the space below the component is enough to place the sheet of size
312 return true;
313 }
314
CheckPlacementBottom(const SizeF & targetSize,const OffsetF & targetOffset)315 bool SheetPresentationLayoutAlgorithm::CheckPlacementBottom(const SizeF& targetSize, const OffsetF& targetOffset)
316 {
317 auto pipelineContext = PipelineContext::GetCurrentContext();
318 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
319 return GreatOrEqual(
320 windowGlobalRect.Width() - WINDOW_EDGE_SPACE.ConvertToPx(),
321 targetOffset.GetX() + targetSize.Width() / SHEET_HALF_SIZE + sheetWidth_ / SHEET_HALF_SIZE) &&
322 LessOrEqual(
323 WINDOW_EDGE_SPACE.ConvertToPx(),
324 targetOffset.GetX() + targetSize.Width() / SHEET_HALF_SIZE - sheetWidth_ / SHEET_HALF_SIZE);
325 }
326
CheckPlacementBottomLeft(const SizeF & targetSize,const OffsetF & targetOffset)327 bool SheetPresentationLayoutAlgorithm::CheckPlacementBottomLeft(const SizeF& targetSize, const OffsetF& targetOffset)
328 {
329 auto pipelineContext = PipelineContext::GetCurrentContext();
330 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
331 return LessOrEqual(WINDOW_EDGE_SPACE.ConvertToPx(), targetOffset.GetX()) &&
332 GreatOrEqual(windowGlobalRect.Width() - WINDOW_EDGE_SPACE.ConvertToPx(), targetOffset.GetX() + sheetWidth_);
333 }
334
CheckPlacementBottomRight(const SizeF & targetSize,const OffsetF & targetOffset)335 bool SheetPresentationLayoutAlgorithm::CheckPlacementBottomRight(const SizeF& targetSize, const OffsetF& targetOffset)
336 {
337 auto pipelineContext = PipelineContext::GetCurrentContext();
338 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
339 return LessOrEqual(WINDOW_EDGE_SPACE.ConvertToPx(), targetOffset.GetX() + targetSize.Width() - sheetWidth_) &&
340 GreatOrEqual(
341 windowGlobalRect.Width() - WINDOW_EDGE_SPACE.ConvertToPx(), targetOffset.GetX() + targetSize.Width());
342 }
343
GetOffsetWithBottom(const SizeF & targetSize,const OffsetF & targetOffset)344 OffsetF SheetPresentationLayoutAlgorithm::GetOffsetWithBottom(const SizeF& targetSize, const OffsetF& targetOffset)
345 {
346 arrowOffsetX_ = sheetWidth_ / SHEET_HALF_SIZE;
347 return OffsetF(targetOffset.GetX() + (targetSize.Width() - sheetWidth_) / SHEET_HALF_SIZE,
348 targetOffset.GetY() + targetSize.Height() + SHEET_TARGET_SPACE.ConvertToPx());
349 }
350
GetOffsetWithBottomLeft(const SizeF & targetSize,const OffsetF & targetOffset)351 OffsetF SheetPresentationLayoutAlgorithm::GetOffsetWithBottomLeft(const SizeF& targetSize, const OffsetF& targetOffset)
352 {
353 arrowOffsetX_ = targetSize.Width() / SHEET_HALF_SIZE;
354 auto sheetOffset =
355 OffsetF(targetOffset.GetX(), targetOffset.GetY() + targetSize.Height() + SHEET_TARGET_SPACE.ConvertToPx());
356
357 // if the arrow overlaps the sheet left corner, move sheet to the 6vp from the left edge
358 if (LessNotEqual(arrowOffsetX_ - ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(), sheetRadius_)) {
359 sheetOffset.SetX(WINDOW_EDGE_SPACE.ConvertToPx());
360 arrowOffsetX_ = targetOffset.GetX() + targetSize.Width() / SHEET_HALF_SIZE - sheetOffset.GetX();
361 TAG_LOGD(AceLogTag::ACE_SHEET, "Adjust sheet to the left boundary of the screen");
362 }
363
364 // if the arrow still overlaps the sheet left corner, the arrow will become a right angle.
365 if (LessNotEqual(arrowOffsetX_ - ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(), sheetRadius_)) {
366 isRightAngleArrow_ = true;
367 TAG_LOGD(AceLogTag::ACE_SHEET, "Need to switch the arrow into the right-angle arrow");
368 }
369 return sheetOffset;
370 }
371
GetOffsetWithBottomRight(const SizeF & targetSize,const OffsetF & targetOffset)372 OffsetF SheetPresentationLayoutAlgorithm::GetOffsetWithBottomRight(const SizeF& targetSize, const OffsetF& targetOffset)
373 {
374 auto pipelineContext = PipelineContext::GetCurrentContext();
375 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
376 arrowOffsetX_ = sheetWidth_ - targetSize.Width() / SHEET_HALF_SIZE;
377 auto sheetOffset = OffsetF(targetOffset.GetX() + targetSize.Width() - sheetWidth_,
378 targetOffset.GetY() + targetSize.Height() + SHEET_TARGET_SPACE.ConvertToPx());
379
380 // if the arrow overlaps the sheet right corner, move sheet to the 6vp from the right edge
381 if (GreatNotEqual(arrowOffsetX_ + sheetRadius_ + ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(), sheetWidth_)) {
382 sheetOffset.SetX(windowGlobalRect.Width() - WINDOW_EDGE_SPACE.ConvertToPx() - sheetWidth_);
383 arrowOffsetX_ = targetOffset.GetX() + targetSize.Width() / SHEET_HALF_SIZE - sheetOffset.GetX();
384 TAG_LOGD(AceLogTag::ACE_SHEET, "Adjust sheet to the right boundary of the screen");
385 }
386
387 // if the arrow still overlaps the sheet right corner, the arrow will become a right angle.
388 if (GreatNotEqual(arrowOffsetX_ + sheetRadius_ + ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(), sheetWidth_)) {
389 isRightAngleArrow_ = true;
390 TAG_LOGD(AceLogTag::ACE_SHEET, "Need to switch the arrow into the right angle arrow");
391 }
392 return sheetOffset;
393 }
394
GetHeightByScreenSizeType(const SizeF & maxSize) const395 float SheetPresentationLayoutAlgorithm::GetHeightByScreenSizeType(const SizeF& maxSize) const
396 {
397 float height = maxSize.Height();
398 switch (sheetType_) {
399 case SheetType::SHEET_BOTTOM:
400 case SheetType::SHEET_BOTTOM_FREE_WINDOW:
401 case SheetType::SHEET_BOTTOMLANDSPACE:
402 height = maxSize.Height();
403 break;
404 case SheetType::SHEET_CENTER:
405 height = GetHeightBySheetStyle();
406 break;
407 case SheetType::SHEET_POPUP:
408 height = GetHeightBySheetStyle() + SHEET_ARROW_HEIGHT.ConvertToPx();
409 break;
410 default:
411 break;
412 }
413
414 return height;
415 }
416
GetWidthByScreenSizeType(const SizeF & maxSize,LayoutWrapper * layoutWrapper) const417 float SheetPresentationLayoutAlgorithm::GetWidthByScreenSizeType(const SizeF& maxSize,
418 LayoutWrapper* layoutWrapper) const
419 {
420 float width = maxSize.Width();
421 auto host = layoutWrapper->GetHostNode();
422 CHECK_NULL_RETURN(host, width);
423 auto sheetPattern = host->GetPattern<SheetPresentationPattern>();
424 CHECK_NULL_RETURN(sheetPattern, width);
425 switch (sheetType_) {
426 case SheetType::SHEET_BOTTOM:
427 if (sheetPattern->IsPhoneInLandScape()) {
428 width = std::min(static_cast<float>(SHEET_LANDSCAPE_WIDTH.ConvertToPx()), maxSize.Width());
429 break;
430 }
431 [[fallthrough]];
432 case SheetType::SHEET_BOTTOM_FREE_WINDOW:
433 width = maxSize.Width();
434 break;
435 case SheetType::SHEET_BOTTOMLANDSPACE:
436 [[fallthrough]];
437 case SheetType::SHEET_CENTER:
438 width = SHEET_LANDSCAPE_WIDTH.ConvertToPx();
439 break;
440 case SheetType::SHEET_POPUP:
441 width = SHEET_POPUP_WIDTH.ConvertToPx();
442 break;
443 default:
444 break;
445 }
446 return width;
447 }
448
GetHeightBySheetStyle() const449 float SheetPresentationLayoutAlgorithm::GetHeightBySheetStyle() const
450 {
451 float height = 0.0f;
452 bool isMediumOrLargeMode = false;
453 if (sheetStyle_.sheetHeight.sheetMode == SheetMode::MEDIUM ||
454 sheetStyle_.sheetHeight.sheetMode == SheetMode::LARGE) {
455 isMediumOrLargeMode = true;
456 }
457 if (sheetStyle_.sheetHeight.height.has_value() || isMediumOrLargeMode) {
458 float sheetMaxHeight = sheetMaxHeight_;
459 if (SheetInSplitWindow()) {
460 sheetMaxHeight = sheetMaxHeight_ - SHEET_SPLIT_STATUS_BAR.ConvertToPx()-
461 SHEET_SPLIT_AI_BAR.ConvertToPx();
462 }
463 auto maxHeight = std::min(sheetMaxHeight, sheetMaxWidth_) * POPUP_LARGE_SIZE;
464 if (sheetStyle_.sheetHeight.height->Unit() == DimensionUnit::PERCENT) {
465 height = sheetStyle_.sheetHeight.height->ConvertToPxWithSize(maxHeight);
466 } else if (isMediumOrLargeMode) {
467 height = SHEET_BIG_WINDOW_HEIGHT.ConvertToPx();
468 } else {
469 height = sheetStyle_.sheetHeight.height->ConvertToPx();
470 }
471
472 maxHeight = SheetInSplitWindow()
473 ? maxHeight : std::max(maxHeight, static_cast<float>(SHEET_BIG_WINDOW_MIN_HEIGHT.ConvertToPx()));
474 if (LessNotEqual(height, 0.0f)) {
475 height = SHEET_BIG_WINDOW_HEIGHT.ConvertToPx();
476 } else if (LessOrEqual(height, SHEET_BIG_WINDOW_MIN_HEIGHT.ConvertToPx()) && !SheetInSplitWindow()) {
477 height = SHEET_BIG_WINDOW_MIN_HEIGHT.ConvertToPx();
478 } else if (GreatOrEqual(height, maxHeight)) {
479 height = maxHeight;
480 }
481 } else {
482 height = SHEET_BIG_WINDOW_HEIGHT.ConvertToPx();
483 }
484 return height;
485 }
486
CreateSheetChildConstraint(RefPtr<SheetPresentationProperty> layoutprop,LayoutWrapper * layoutWrapper)487 LayoutConstraintF SheetPresentationLayoutAlgorithm::CreateSheetChildConstraint(
488 RefPtr<SheetPresentationProperty> layoutprop, LayoutWrapper* layoutWrapper)
489 {
490 auto childConstraint = layoutprop->CreateChildConstraint();
491 auto pipeline = PipelineContext::GetCurrentContext();
492 CHECK_NULL_RETURN(pipeline, childConstraint);
493 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
494 CHECK_NULL_RETURN(sheetTheme, childConstraint);
495
496 childConstraint.maxSize.SetWidth(sheetWidth_);
497 auto maxHeight = sheetHeight_;
498 if ((sheetStyle_.isTitleBuilder.has_value()) &&
499 ((sheetType_ == SheetType::SHEET_CENTER) || (sheetType_ == SheetType::SHEET_POPUP))) {
500 auto host = layoutWrapper->GetHostNode();
501 CHECK_NULL_RETURN(host, childConstraint);
502 auto operationNode = DynamicCast<FrameNode>(host->GetChildAtIndex(0));
503 CHECK_NULL_RETURN(operationNode, childConstraint);
504 auto titleGeometryNode = operationNode->GetGeometryNode();
505 CHECK_NULL_RETURN(titleGeometryNode, childConstraint);
506 auto titleHeiht = titleGeometryNode->GetFrameSize().Height();
507 maxHeight -= titleHeiht;
508 }
509 if (sheetType_ == SheetType::SHEET_POPUP) {
510 maxHeight -= SHEET_ARROW_HEIGHT.ConvertToPx();
511 }
512 childConstraint.maxSize.SetHeight(maxHeight);
513 childConstraint.parentIdealSize = OptionalSizeF(sheetWidth_, sheetHeight_);
514 childConstraint.percentReference = SizeF(sheetWidth_, sheetHeight_);
515 return childConstraint;
516 }
517
SheetInSplitWindow() const518 bool SheetPresentationLayoutAlgorithm::SheetInSplitWindow() const
519 {
520 //whether window in up and down split mode
521 auto pipelineContext = PipelineContext::GetCurrentContext();
522 auto windowManager = pipelineContext->GetWindowManager();
523 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
524 int32_t deviceHeight = SystemProperties::GetDeviceHeight();
525 if (sheetType_ == SheetType::SHEET_CENTER && windowManager && windowGlobalRect.Height() < deviceHeight &&
526 (windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY ||
527 windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY)) {
528 return true;
529 }
530 return false;
531 }
532 } // namespace OHOS::Ace::NG