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);
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_.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.maxSize.SetWidth(sheetWidth_);
197 childConstraint.maxSize.SetHeight(sheetHeight_);
198 secondChild->Measure(childConstraint);
199 }
200 }
201 }
202
Layout(LayoutWrapper * layoutWrapper)203 void SheetPresentationLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
204 {
205 CHECK_NULL_VOID(layoutWrapper);
206 const auto& pipeline = PipelineContext::GetCurrentContext();
207 CHECK_NULL_VOID(pipeline);
208 sheetOffsetX_ = (sheetMaxWidth_ - sheetWidth_) / SHEET_HALF_SIZE;
209 if (sheetType_ == SheetType::SHEET_BOTTOMLANDSPACE) {
210 sheetOffsetX_ = (sheetMaxWidth_ - sheetWidth_) / SHEET_HALF_SIZE;
211 } else if (sheetType_ == SheetType::SHEET_CENTER) {
212 sheetOffsetX_ = (sheetMaxWidth_ - sheetWidth_) / SHEET_HALF_SIZE;
213 } else if (sheetType_ == SheetType::SHEET_POPUP) {
214 auto frameNode = layoutWrapper->GetHostNode();
215 CHECK_NULL_VOID(frameNode);
216 auto parent = DynamicCast<FrameNode>(frameNode->GetParent());
217 CHECK_NULL_VOID(parent);
218 auto parentOffset = parent->GetPaintRectOffset();
219 OffsetF popupStyleSheetOffset = GetPopupStyleSheetOffset();
220 // need to subtract the SheetWrapper relative to the upper left corner of the window,
221 // which is the offset of the upper left corner of the bubble relative to the SheetWrapper
222 sheetOffsetX_ = popupStyleSheetOffset.GetX() - parentOffset.GetX();
223 sheetOffsetY_ = popupStyleSheetOffset.GetY() - parentOffset.GetY();
224 }
225 CalculateSheetOffsetInOtherScenes(layoutWrapper);
226 TAG_LOGD(AceLogTag::ACE_SHEET, "Sheet layout info, sheetOffsetX_ is: %{public}f, sheetOffsetY_ is: %{public}f",
227 sheetOffsetX_, sheetOffsetY_);
228 OffsetF positionOffset;
229 positionOffset.SetX(sheetOffsetX_);
230 positionOffset.SetY(0.0f);
231 auto geometryNode = layoutWrapper->GetGeometryNode();
232 CHECK_NULL_VOID(geometryNode);
233 // This step is only to determine the position of x, because y is to be done by the bit movement effect
234 geometryNode->SetMarginFrameOffset(positionOffset);
235 OffsetF translate(0.0f, 0.0f);
236 if (sheetType_ == SheetType::SHEET_POPUP) {
237 translate += OffsetF(0, SHEET_ARROW_HEIGHT.ConvertToPx());
238 }
239 for (const auto& child : layoutWrapper->GetAllChildrenWithBuild()) {
240 child->GetGeometryNode()->SetMarginFrameOffset(translate);
241 child->Layout();
242 translate += OffsetF(0, child->GetGeometryNode()->GetFrameSize().Height());
243 }
244 }
245
246 // Get the offset of the popupSheet relative to the upper left corner of the window
GetPopupStyleSheetOffset()247 OffsetF SheetPresentationLayoutAlgorithm::GetPopupStyleSheetOffset()
248 {
249 auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
250 CHECK_NULL_RETURN(targetNode, OffsetF());
251 auto geometryNode = targetNode->GetGeometryNode();
252 CHECK_NULL_RETURN(geometryNode, OffsetF());
253 auto targetSize = geometryNode->GetFrameSize();
254 auto targetOffset = targetNode->GetPaintRectOffset();
255 return GetOffsetInAvoidanceRule(targetSize, targetOffset);
256 }
257
GetOffsetInAvoidanceRule(const SizeF & targetSize,const OffsetF & targetOffset)258 OffsetF SheetPresentationLayoutAlgorithm::GetOffsetInAvoidanceRule(const SizeF& targetSize, const OffsetF& targetOffset)
259 {
260 // The current default Placement is Placement::BOTTOM
261 auto placement = Placement::BOTTOM;
262 auto targetPlacement = AvoidanceRuleOfPlacement(placement, targetSize, targetOffset);
263 if (getOffsetFunc_.find(targetPlacement) == getOffsetFunc_.end()) {
264 TAG_LOGW(AceLogTag::ACE_SHEET, "It is an invalid Placement for current PopSheet.");
265 return {};
266 }
267 auto offsetFunc = getOffsetFunc_[targetPlacement];
268 CHECK_NULL_RETURN(offsetFunc, OffsetF());
269 return (this->*offsetFunc)(targetSize, targetOffset);
270 }
271
AvoidanceRuleOfPlacement(const Placement & currentPlacement,const SizeF & targetSize,const OffsetF & targetOffset)272 Placement SheetPresentationLayoutAlgorithm::AvoidanceRuleOfPlacement(
273 const Placement& currentPlacement, const SizeF& targetSize, const OffsetF& targetOffset)
274 {
275 Placement targetPlacement = currentPlacement;
276 TAG_LOGD(AceLogTag::ACE_SHEET, "Init PopupSheet placement: %{public}s",
277 PlacementUtils::ConvertPlacementToString(targetPlacement).c_str());
278 // Step1: Determine the direction
279 auto& directionVec = DIRECTIONS_STATES[targetPlacement];
280 for (auto placement : directionVec) {
281 auto& placementFunc = directionCheckFunc_[placement];
282 if (placementFunc == nullptr) {
283 continue;
284 }
285 if ((this->*placementFunc)(targetSize, targetOffset)) {
286 targetPlacement = placement;
287 break;
288 }
289 }
290 TAG_LOGD(AceLogTag::ACE_SHEET, "After step1, placement: %{public}s",
291 PlacementUtils::ConvertPlacementToString(targetPlacement).c_str());
292 // Step2: Determine the Placement in that direction
293 auto& placementVec = PLACEMENT_STATES[targetPlacement];
294 for (auto placement : placementVec) {
295 auto& placementFunc = placementCheckFunc_[placement];
296 if (placementFunc == nullptr) {
297 continue;
298 }
299 if ((this->*placementFunc)(targetSize, targetOffset)) {
300 targetPlacement = placement;
301 break;
302 }
303 }
304 TAG_LOGD(AceLogTag::ACE_SHEET, "After step2, placement: %{public}s",
305 PlacementUtils::ConvertPlacementToString(targetPlacement).c_str());
306 return targetPlacement;
307 }
308
CheckDirectionBottom(const SizeF & targetSize,const OffsetF & targetOffset)309 bool SheetPresentationLayoutAlgorithm::CheckDirectionBottom(const SizeF& targetSize, const OffsetF& targetOffset)
310 {
311 // Generalized bottom direction,
312 // determine whether the space below the component is enough to place the sheet of size
313 return true;
314 }
315
CheckPlacementBottom(const SizeF & targetSize,const OffsetF & targetOffset)316 bool SheetPresentationLayoutAlgorithm::CheckPlacementBottom(const SizeF& targetSize, const OffsetF& targetOffset)
317 {
318 auto pipelineContext = PipelineContext::GetCurrentContext();
319 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
320 return GreatOrEqual(
321 windowGlobalRect.Width() - WINDOW_EDGE_SPACE.ConvertToPx(),
322 targetOffset.GetX() + targetSize.Width() / SHEET_HALF_SIZE + sheetWidth_ / SHEET_HALF_SIZE) &&
323 LessOrEqual(
324 WINDOW_EDGE_SPACE.ConvertToPx(),
325 targetOffset.GetX() + targetSize.Width() / SHEET_HALF_SIZE - sheetWidth_ / SHEET_HALF_SIZE);
326 }
327
CheckPlacementBottomLeft(const SizeF & targetSize,const OffsetF & targetOffset)328 bool SheetPresentationLayoutAlgorithm::CheckPlacementBottomLeft(const SizeF& targetSize, const OffsetF& targetOffset)
329 {
330 auto pipelineContext = PipelineContext::GetCurrentContext();
331 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
332 return LessOrEqual(WINDOW_EDGE_SPACE.ConvertToPx(), targetOffset.GetX()) &&
333 GreatOrEqual(windowGlobalRect.Width() - WINDOW_EDGE_SPACE.ConvertToPx(), targetOffset.GetX() + sheetWidth_);
334 }
335
CheckPlacementBottomRight(const SizeF & targetSize,const OffsetF & targetOffset)336 bool SheetPresentationLayoutAlgorithm::CheckPlacementBottomRight(const SizeF& targetSize, const OffsetF& targetOffset)
337 {
338 auto pipelineContext = PipelineContext::GetCurrentContext();
339 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
340 return LessOrEqual(WINDOW_EDGE_SPACE.ConvertToPx(), targetOffset.GetX() + targetSize.Width() - sheetWidth_) &&
341 GreatOrEqual(
342 windowGlobalRect.Width() - WINDOW_EDGE_SPACE.ConvertToPx(), targetOffset.GetX() + targetSize.Width());
343 }
344
GetOffsetWithBottom(const SizeF & targetSize,const OffsetF & targetOffset)345 OffsetF SheetPresentationLayoutAlgorithm::GetOffsetWithBottom(const SizeF& targetSize, const OffsetF& targetOffset)
346 {
347 arrowOffsetX_ = sheetWidth_ / SHEET_HALF_SIZE;
348 return OffsetF(targetOffset.GetX() + (targetSize.Width() - sheetWidth_) / SHEET_HALF_SIZE,
349 targetOffset.GetY() + targetSize.Height() + SHEET_TARGET_SPACE.ConvertToPx());
350 }
351
GetOffsetWithBottomLeft(const SizeF & targetSize,const OffsetF & targetOffset)352 OffsetF SheetPresentationLayoutAlgorithm::GetOffsetWithBottomLeft(const SizeF& targetSize, const OffsetF& targetOffset)
353 {
354 arrowOffsetX_ = targetSize.Width() / SHEET_HALF_SIZE;
355 auto sheetOffset =
356 OffsetF(targetOffset.GetX(), targetOffset.GetY() + targetSize.Height() + SHEET_TARGET_SPACE.ConvertToPx());
357
358 // if the arrow overlaps the sheet left corner, move sheet to the 6vp from the left edge
359 if (LessNotEqual(arrowOffsetX_ - ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(), sheetRadius_)) {
360 sheetOffset.SetX(WINDOW_EDGE_SPACE.ConvertToPx());
361 arrowOffsetX_ = targetOffset.GetX() + targetSize.Width() / SHEET_HALF_SIZE - sheetOffset.GetX();
362 TAG_LOGD(AceLogTag::ACE_SHEET, "Adjust sheet to the left boundary of the screen");
363 }
364
365 // if the arrow still overlaps the sheet left corner, the arrow will become a right angle.
366 if (LessNotEqual(arrowOffsetX_ - ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(), sheetRadius_)) {
367 isRightAngleArrow_ = true;
368 TAG_LOGD(AceLogTag::ACE_SHEET, "Need to switch the arrow into the right-angle arrow");
369 }
370 return sheetOffset;
371 }
372
GetOffsetWithBottomRight(const SizeF & targetSize,const OffsetF & targetOffset)373 OffsetF SheetPresentationLayoutAlgorithm::GetOffsetWithBottomRight(const SizeF& targetSize, const OffsetF& targetOffset)
374 {
375 auto pipelineContext = PipelineContext::GetCurrentContext();
376 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
377 arrowOffsetX_ = sheetWidth_ - targetSize.Width() / SHEET_HALF_SIZE;
378 auto sheetOffset = OffsetF(targetOffset.GetX() + targetSize.Width() - sheetWidth_,
379 targetOffset.GetY() + targetSize.Height() + SHEET_TARGET_SPACE.ConvertToPx());
380
381 // if the arrow overlaps the sheet right corner, move sheet to the 6vp from the right edge
382 if (GreatNotEqual(arrowOffsetX_ + sheetRadius_ + ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(), sheetWidth_)) {
383 sheetOffset.SetX(windowGlobalRect.Width() - WINDOW_EDGE_SPACE.ConvertToPx() - sheetWidth_);
384 arrowOffsetX_ = targetOffset.GetX() + targetSize.Width() / SHEET_HALF_SIZE - sheetOffset.GetX();
385 TAG_LOGD(AceLogTag::ACE_SHEET, "Adjust sheet to the right boundary of the screen");
386 }
387
388 // if the arrow still overlaps the sheet right corner, the arrow will become a right angle.
389 if (GreatNotEqual(arrowOffsetX_ + sheetRadius_ + ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(), sheetWidth_)) {
390 isRightAngleArrow_ = true;
391 TAG_LOGD(AceLogTag::ACE_SHEET, "Need to switch the arrow into the right angle arrow");
392 }
393 return sheetOffset;
394 }
395
GetHeightByScreenSizeType(const SizeF & maxSize) const396 float SheetPresentationLayoutAlgorithm::GetHeightByScreenSizeType(const SizeF& maxSize) const
397 {
398 float height = maxSize.Height();
399 switch (sheetType_) {
400 case SheetType::SHEET_BOTTOM:
401 case SheetType::SHEET_BOTTOM_FREE_WINDOW:
402 case SheetType::SHEET_BOTTOMLANDSPACE:
403 height = maxSize.Height();
404 break;
405 case SheetType::SHEET_CENTER:
406 height = GetHeightBySheetStyle();
407 break;
408 case SheetType::SHEET_POPUP:
409 height = GetHeightBySheetStyle() + SHEET_ARROW_HEIGHT.ConvertToPx();
410 break;
411 default:
412 break;
413 }
414
415 return height;
416 }
417
GetWidthByScreenSizeType(const SizeF & maxSize,LayoutWrapper * layoutWrapper) const418 float SheetPresentationLayoutAlgorithm::GetWidthByScreenSizeType(const SizeF& maxSize,
419 LayoutWrapper* layoutWrapper) const
420 {
421 float width = maxSize.Width();
422 auto host = layoutWrapper->GetHostNode();
423 CHECK_NULL_RETURN(host, width);
424 auto sheetPattern = host->GetPattern<SheetPresentationPattern>();
425 CHECK_NULL_RETURN(sheetPattern, width);
426 switch (sheetType_) {
427 case SheetType::SHEET_BOTTOM:
428 if (sheetPattern->IsPhoneInLandScape()) {
429 width = std::min(static_cast<float>(SHEET_LANDSCAPE_WIDTH.ConvertToPx()), maxSize.Width());
430 break;
431 }
432 case SheetType::SHEET_BOTTOM_FREE_WINDOW:
433 width = maxSize.Width();
434 break;
435 case SheetType::SHEET_BOTTOMLANDSPACE:
436 case SheetType::SHEET_CENTER:
437 width = SHEET_LANDSCAPE_WIDTH.ConvertToPx();
438 break;
439 case SheetType::SHEET_POPUP:
440 width = SHEET_POPUP_WIDTH.ConvertToPx();
441 break;
442 default:
443 break;
444 }
445 return width;
446 }
447
GetHeightBySheetStyle() const448 float SheetPresentationLayoutAlgorithm::GetHeightBySheetStyle() const
449 {
450 float height = 0.0f;
451 bool isMediumOrLargeMode = false;
452 if (sheetStyle_.sheetMode == SheetMode::MEDIUM || sheetStyle_.sheetMode == SheetMode::LARGE) {
453 isMediumOrLargeMode = true;
454 }
455 if (sheetStyle_.height.has_value() || isMediumOrLargeMode) {
456 float sheetMaxHeight = sheetMaxHeight_;
457 if (SheetInSplitWindow()) {
458 sheetMaxHeight = sheetMaxHeight_ - SHEET_SPLIT_STATUS_BAR.ConvertToPx()-
459 SHEET_SPLIT_AI_BAR.ConvertToPx();
460 }
461 auto maxHeight = std::min(sheetMaxHeight, sheetMaxWidth_) * POPUP_LARGE_SIZE;
462 if (sheetStyle_.height->Unit() == DimensionUnit::PERCENT) {
463 height = sheetStyle_.height->ConvertToPxWithSize(maxHeight);
464 } else if (isMediumOrLargeMode) {
465 height = SHEET_BIG_WINDOW_HEIGHT.ConvertToPx();
466 } else {
467 height = sheetStyle_.height->ConvertToPx();
468 }
469
470 maxHeight = SheetInSplitWindow()
471 ? maxHeight : std::max(maxHeight, static_cast<float>(SHEET_BIG_WINDOW_MIN_HEIGHT.ConvertToPx()));
472 if (LessNotEqual(height, 0.0f)) {
473 height = SHEET_BIG_WINDOW_HEIGHT.ConvertToPx();
474 } else if (LessOrEqual(height, SHEET_BIG_WINDOW_MIN_HEIGHT.ConvertToPx()) && !SheetInSplitWindow()) {
475 height = SHEET_BIG_WINDOW_MIN_HEIGHT.ConvertToPx();
476 } else if (GreatOrEqual(height, maxHeight)) {
477 height = maxHeight;
478 }
479 } else {
480 height = SHEET_BIG_WINDOW_HEIGHT.ConvertToPx();
481 }
482 return height;
483 }
484
CreateSheetChildConstraint(RefPtr<SheetPresentationProperty> layoutprop)485 LayoutConstraintF SheetPresentationLayoutAlgorithm::CreateSheetChildConstraint(
486 RefPtr<SheetPresentationProperty> layoutprop)
487 {
488 auto childConstraint = layoutprop->CreateChildConstraint();
489 auto pipeline = PipelineContext::GetCurrentContext();
490 CHECK_NULL_RETURN(pipeline, childConstraint);
491 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
492 CHECK_NULL_RETURN(sheetTheme, childConstraint);
493
494 childConstraint.maxSize.SetWidth(sheetWidth_);
495 auto maxHeight = sheetHeight_;
496 if ((sheetStyle_.isTitleBuilder.has_value()) &&
497 ((sheetType_ == SheetType::SHEET_CENTER) || (sheetType_ == SheetType::SHEET_POPUP))) {
498 maxHeight -= SHEET_OPERATION_AREA_HEIGHT.ConvertToPx();
499 }
500 childConstraint.maxSize.SetHeight(maxHeight);
501 childConstraint.parentIdealSize = OptionalSizeF(sheetWidth_, sheetHeight_);
502 childConstraint.percentReference = SizeF(sheetWidth_, sheetHeight_);
503 return childConstraint;
504 }
505
SheetInSplitWindow() const506 bool SheetPresentationLayoutAlgorithm::SheetInSplitWindow() const
507 {
508 //whether window in up and down split mode
509 auto pipelineContext = PipelineContext::GetCurrentContext();
510 auto windowManager = pipelineContext->GetWindowManager();
511 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
512 int32_t deviceHeight = SystemProperties::GetDeviceHeight();
513 if (sheetType_ == SheetType::SHEET_CENTER && windowManager && windowGlobalRect.Height() < deviceHeight &&
514 (windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY ||
515 windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_SECONDARY)) {
516 return true;
517 }
518 return false;
519 }
520 } // namespace OHOS::Ace::NG