1 /*
2 * Copyright (c) 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/layout/box_layout_algorithm.h"
17 #include "core/components_ng/layout/layout_wrapper.h"
18 #include "core/components_ng/pattern/overlay/sheet_presentation_layout_algorithm.h"
19 #include "core/components_ng/pattern/overlay/sheet_presentation_pattern.h"
20 #include "core/components_ng/pattern/sheet/sheet_mask_pattern.h"
21 #include "core/components_ng/pattern/overlay/sheet_presentation_property.h"
22 #include "core/components_ng/pattern/overlay/sheet_wrapper_layout_algorithm.h"
23 #include "core/components_ng/pattern/overlay/sheet_wrapper_pattern.h"
24 #include "core/pipeline_ng/pipeline_context.h"
25
26 namespace OHOS::Ace::NG {
27 namespace {
28 constexpr int32_t DOUBLE_SIZE = 2;
29 constexpr Dimension WINDOW_EDGE_SPACE = 6.0_vp;
30 constexpr Dimension ARROW_VERTICAL_P1_OFFSET_X = 8.0_vp;
31 constexpr Dimension ARROW_VERTICAL_P5_OFFSET_X = 8.0_vp;
32 std::map<Placement, std::vector<Placement>> PLACEMENT_STATES = {
33 { Placement::BOTTOM_LEFT,
34 {
35 Placement::BOTTOM_LEFT,
36 Placement::TOP_LEFT,
37 Placement::RIGHT_TOP,
38 Placement::LEFT_TOP,
39 Placement::NONE,
40 } },
41 { Placement::BOTTOM,
42 {
43 Placement::BOTTOM,
44 Placement::TOP,
45 Placement::RIGHT,
46 Placement::LEFT,
47 Placement::NONE,
48 } },
49 { Placement::BOTTOM_RIGHT,
50 {
51 Placement::BOTTOM_RIGHT,
52 Placement::TOP_RIGHT,
53 Placement::RIGHT_BOTTOM,
54 Placement::LEFT_BOTTOM,
55 Placement::NONE,
56 } },
57 { Placement::TOP_LEFT,
58 {
59 Placement::TOP_LEFT,
60 Placement::BOTTOM_LEFT,
61 Placement::RIGHT_TOP,
62 Placement::LEFT_TOP,
63 Placement::NONE,
64 } },
65 { Placement::TOP,
66 {
67 Placement::TOP,
68 Placement::BOTTOM,
69 Placement::RIGHT,
70 Placement::LEFT,
71 Placement::NONE,
72 } },
73 { Placement::TOP_RIGHT,
74 {
75 Placement::TOP_RIGHT,
76 Placement::BOTTOM_RIGHT,
77 Placement::RIGHT_BOTTOM,
78 Placement::LEFT_BOTTOM,
79 Placement::NONE,
80 } },
81 { Placement::LEFT_TOP,
82 {
83 Placement::LEFT_TOP,
84 Placement::RIGHT_TOP,
85 Placement::BOTTOM_LEFT,
86 Placement::TOP_LEFT,
87 Placement::NONE,
88 } },
89 { Placement::LEFT,
90 {
91 Placement::LEFT,
92 Placement::RIGHT,
93 Placement::BOTTOM,
94 Placement::TOP,
95 Placement::NONE,
96 } },
97 { Placement::LEFT_BOTTOM,
98 {
99 Placement::LEFT_BOTTOM,
100 Placement::RIGHT_BOTTOM,
101 Placement::BOTTOM_RIGHT,
102 Placement::TOP_RIGHT,
103 Placement::NONE,
104 } },
105 { Placement::RIGHT_TOP,
106 {
107 Placement::RIGHT_TOP,
108 Placement::LEFT_TOP,
109 Placement::BOTTOM_LEFT,
110 Placement::TOP_LEFT,
111 Placement::NONE,
112 } },
113 { Placement::RIGHT,
114 {
115 Placement::RIGHT,
116 Placement::LEFT,
117 Placement::BOTTOM,
118 Placement::TOP,
119 Placement::NONE,
120 } },
121 { Placement::RIGHT_BOTTOM,
122 {
123 Placement::RIGHT_BOTTOM,
124 Placement::LEFT_BOTTOM,
125 Placement::BOTTOM_RIGHT,
126 Placement::TOP_RIGHT,
127 Placement::NONE,
128 } },
129 };
130 } // namespace
131
Measure(LayoutWrapper * layoutWrapper)132 void SheetWrapperLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
133 {
134 CHECK_NULL_VOID(layoutWrapper);
135 InitParameter(layoutWrapper);
136 BoxLayoutAlgorithm::PerformMeasureSelf(layoutWrapper);
137 auto host = layoutWrapper->GetHostNode();
138 CHECK_NULL_VOID(host);
139 auto sheetWrapperPattern = host->GetPattern<SheetWrapperPattern>();
140 CHECK_NULL_VOID(sheetWrapperPattern);
141 auto child = sheetWrapperPattern->GetSheetPageNode();
142 CHECK_NULL_VOID(child);
143 auto sheetLayoutProperty = child->GetLayoutProperty();
144 CHECK_NULL_VOID(sheetLayoutProperty);
145 sheetLayoutProperty->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
146 auto layoutProp = layoutWrapper->GetLayoutProperty();
147 CHECK_NULL_VOID(layoutProp);
148 auto childConstraint = layoutProp->CreateChildConstraint();
149 child->Measure(childConstraint);
150 GetSheetPageSize(layoutWrapper);
151 MeasureSheetMask(layoutWrapper);
152 }
153
MeasureSheetMask(LayoutWrapper * layoutWrapper)154 void SheetWrapperLayoutAlgorithm::MeasureSheetMask(LayoutWrapper* layoutWrapper)
155 {
156 auto host = layoutWrapper->GetHostNode();
157 CHECK_NULL_VOID(host);
158 auto sheetWrapperPattern = host->GetPattern<SheetWrapperPattern>();
159 CHECK_NULL_VOID(sheetWrapperPattern);
160
161 if (!sheetWrapperPattern->ShowInUEC()) {
162 return;
163 }
164 auto maskNode = sheetWrapperPattern->GetSheetMaskNode();
165 CHECK_NULL_VOID(maskNode);
166 auto index = host->GetChildIndexById(maskNode->GetId());
167 auto maskWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
168 CHECK_NULL_VOID(maskWrapper);
169 auto rect = sheetWrapperPattern->GetMainWindowRect();
170 auto layoutProp = layoutWrapper->GetLayoutProperty();
171 CHECK_NULL_VOID(layoutProp);
172 auto constraint = layoutProp->CreateChildConstraint();
173 constraint.selfIdealSize = OptionalSizeF(rect.Width(), rect.Height());
174 maskWrapper->Measure(constraint);
175 }
176
InitParameter(LayoutWrapper * layoutWrapper)177 void SheetWrapperLayoutAlgorithm::InitParameter(LayoutWrapper* layoutWrapper)
178 {
179 auto host = layoutWrapper->GetHostNode();
180 CHECK_NULL_VOID(host);
181 auto pipeline = host->GetContext();
182 CHECK_NULL_VOID(pipeline);
183 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
184 CHECK_NULL_VOID(sheetTheme);
185
186 auto sheetWrapperPattern = host->GetPattern<SheetWrapperPattern>();
187 CHECK_NULL_VOID(sheetWrapperPattern);
188 auto sheetPage = sheetWrapperPattern->GetSheetPageNode();
189 CHECK_NULL_VOID(sheetPage);
190 auto sheetPattern = DynamicCast<SheetPresentationPattern>(sheetPage->GetPattern());
191 CHECK_NULL_VOID(sheetPattern);
192 sheetRadius_ = BorderRadiusProperty(sheetTheme->GetSheetRadius());
193 sheetPattern->CalculateSheetRadius(sheetRadius_);
194 auto layoutProperty = sheetPage->GetLayoutProperty<SheetPresentationProperty>();
195 CHECK_NULL_VOID(layoutProperty);
196 auto sheetStyle = layoutProperty->GetSheetStyleValue();
197 placement_ = sheetStyle.placement.value_or(Placement::BOTTOM);
198 sheetPopupInfo_.finalPlacement = placement_;
199 sheetPopupInfo_.placementOnTarget = sheetStyle.placementOnTarget.value_or(true);
200 windowGlobalRect_ = pipeline->GetDisplayWindowRectInfo();
201 windowEdgeWidth_ = WINDOW_EDGE_SPACE.ConvertToPx();
202 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
203 // global rect need to reduce the top and bottom safe area
204 windowGlobalRect_ = pipeline->GetCurrentWindowRect();
205 auto safeArea = pipeline->GetSafeArea();
206 RectF floatContainerModal;
207 RectF titleRect;
208 // get window rect title height
209 pipeline->GetContainerModalButtonsRect(floatContainerModal, titleRect);
210 auto offsetY = safeArea.top_.Length() + titleRect.Height();
211 auto height = windowGlobalRect_.Height() - offsetY - safeArea.bottom_.Length();
212 // windowRect neet to set as origin point, because sheet offset is relative to window rect
213 windowGlobalRect_ = Rect(0.f, offsetY, windowGlobalRect_.Width(), height);
214 }
215 }
216
GetSheetPageSize(LayoutWrapper * layoutWrapper)217 void SheetWrapperLayoutAlgorithm::GetSheetPageSize(LayoutWrapper* layoutWrapper)
218 {
219 CHECK_NULL_VOID(layoutWrapper);
220 auto host = layoutWrapper->GetHostNode();
221 CHECK_NULL_VOID(host);
222 auto sheetWrapperPattern = host->GetPattern<SheetWrapperPattern>();
223 CHECK_NULL_VOID(sheetWrapperPattern);
224 auto sheetPage = sheetWrapperPattern->GetSheetPageNode();
225 CHECK_NULL_VOID(sheetPage);
226 auto sheetGeometryNode = sheetPage->GetGeometryNode();
227 CHECK_NULL_VOID(sheetGeometryNode);
228 sheetWidth_ = sheetGeometryNode->GetFrameSize().Width();
229 sheetHeight_ = sheetGeometryNode->GetFrameSize().Height();
230 DecreaseArrowHeightWhenArrowIsShown(sheetPage);
231 // when sheetWidth > global rect - 2 * windowEdgeSpace, windowEdgeSpace is set to the half of left space
232 if (GreatNotEqual(sheetWidth_, windowGlobalRect_.Width() - DOUBLE_SIZE * WINDOW_EDGE_SPACE.ConvertToPx())) {
233 windowEdgeWidth_ = (windowGlobalRect_.Width() - sheetWidth_) / DOUBLE_SIZE;
234 }
235 }
236
DecreaseArrowHeightWhenArrowIsShown(const RefPtr<FrameNode> & sheetNode)237 void SheetWrapperLayoutAlgorithm::DecreaseArrowHeightWhenArrowIsShown(const RefPtr<FrameNode>& sheetNode)
238 {
239 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
240 return;
241 }
242
243 auto sheetPattern = sheetNode->GetPattern<SheetPresentationPattern>();
244 CHECK_NULL_VOID(sheetPattern);
245 auto prePopupInfo = sheetPattern->GetSheetPopupInfo();
246 if (!prePopupInfo.showArrow) {
247 return;
248 }
249
250 switch (prePopupInfo.finalPlacement) {
251 case Placement::BOTTOM_LEFT:
252 [[fallthrough]];
253 case Placement::BOTTOM_RIGHT:
254 [[fallthrough]];
255 case Placement::BOTTOM:
256 [[fallthrough]];
257 case Placement::TOP_LEFT:
258 [[fallthrough]];
259 case Placement::TOP_RIGHT:
260 [[fallthrough]];
261 case Placement::TOP: {
262 sheetHeight_ -= SHEET_ARROW_HEIGHT.ConvertToPx();
263 break;
264 }
265 case Placement::RIGHT_TOP:
266 [[fallthrough]];
267 case Placement::RIGHT_BOTTOM:
268 [[fallthrough]];
269 case Placement::RIGHT:
270 [[fallthrough]];
271 case Placement::LEFT_TOP:
272 [[fallthrough]];
273 case Placement::LEFT_BOTTOM:
274 [[fallthrough]];
275 case Placement::LEFT: {
276 sheetWidth_ -= SHEET_ARROW_HEIGHT.ConvertToPx();
277 break;
278 }
279 default:
280 break;
281 }
282 }
283
GetPopupStyleSheetOffset(LayoutWrapper * layoutWrapper)284 OffsetF SheetWrapperLayoutAlgorithm::GetPopupStyleSheetOffset(LayoutWrapper* layoutWrapper)
285 {
286 auto host = layoutWrapper->GetHostNode();
287 CHECK_NULL_RETURN(host, OffsetF());
288 auto sheetWrapperPattern = host->GetPattern<SheetWrapperPattern>();
289 CHECK_NULL_RETURN(sheetWrapperPattern, OffsetF());
290 auto targetNode = sheetWrapperPattern->GetTargetNode();
291 CHECK_NULL_RETURN(targetNode, OffsetF());
292 auto geometryNode = targetNode->GetGeometryNode();
293 CHECK_NULL_RETURN(geometryNode, OffsetF());
294 auto targetSize = geometryNode->GetFrameSize();
295 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
296 targetSize = targetNode->GetPaintRectWithTransform().GetSize();
297 }
298 auto targetOffset = targetNode->GetPaintRectOffset();
299 return GetOffsetInAvoidanceRule(layoutWrapper, targetSize, targetOffset);
300 }
301
GetOffsetInAvoidanceRule(LayoutWrapper * layoutWrapper,const SizeF & targetSize,const OffsetF & targetOffset)302 OffsetF SheetWrapperLayoutAlgorithm::GetOffsetInAvoidanceRule(
303 LayoutWrapper* layoutWrapper, const SizeF& targetSize, const OffsetF& targetOffset)
304 {
305 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
306 sheetPopupInfo_.finalPlacement = AvoidanceRuleOfPlacement(layoutWrapper, targetSize, targetOffset);
307 } else {
308 // before api 16, only placement bottom is used
309 sheetPopupInfo_.finalPlacement = AvoidanceRuleBottom(Placement::BOTTOM, targetSize, targetOffset);
310 }
311 TAG_LOGI(AceLogTag::ACE_SHEET, "finalPlacement %{public}s",
312 PlacementUtils::ConvertPlacementToString(sheetPopupInfo_.finalPlacement).c_str());
313 if (getOffsetFunc_.find(sheetPopupInfo_.finalPlacement) == getOffsetFunc_.end()) {
314 TAG_LOGW(AceLogTag::ACE_SHEET, "It is an invalid Placement for current PopSheet.");
315 return OffsetF(0.f, 0.f);
316 }
317 auto offsetFunc = getOffsetFunc_[sheetPopupInfo_.finalPlacement];
318 CHECK_NULL_RETURN(offsetFunc, OffsetF());
319 /*
320 * steps 1. get sheet offset and restrict in window global rect
321 * steps 2. check whether need to show arrow
322 * steps 3. get arrow offset and check whether it is overlap sheet radius
323 */
324 return (this->*offsetFunc)(targetSize, targetOffset);
325 }
326
AvoidanceRuleBottom(const Placement & currentPlacement,const SizeF & targetSize,const OffsetF & targetOffset)327 Placement SheetWrapperLayoutAlgorithm::AvoidanceRuleBottom(
328 const Placement& currentPlacement, const SizeF& targetSize, const OffsetF& targetOffset)
329 {
330 static std::map<Placement, std::vector<Placement>> PLACEMENT_STATES_BOTTOM = {
331 { Placement::BOTTOM,
332 {
333 Placement::BOTTOM,
334 Placement::BOTTOM_RIGHT,
335 Placement::BOTTOM_LEFT,
336 } },
337 };
338 Placement targetPlacement = currentPlacement;
339 TAG_LOGD(AceLogTag::ACE_SHEET, "Init PopupSheet placement: %{public}s",
340 PlacementUtils::ConvertPlacementToString(targetPlacement).c_str());
341 // Step1: Determine the Placement in direction Bottom
342 auto& placementVec = PLACEMENT_STATES_BOTTOM[targetPlacement];
343 for (auto placement : placementVec) {
344 auto& placementFunc = placementCheckFunc_[placement];
345 if (placementFunc == nullptr) {
346 continue;
347 }
348 if ((this->*placementFunc)(targetSize, targetOffset)) {
349 targetPlacement = placement;
350 break;
351 }
352 }
353 TAG_LOGD(AceLogTag::ACE_SHEET, "After placementCheck, placement: %{public}s",
354 PlacementUtils::ConvertPlacementToString(targetPlacement).c_str());
355 return targetPlacement;
356 }
357
AvoidanceRuleOfPlacement(LayoutWrapper * layoutWrapper,const SizeF & targetSize,const OffsetF & targetOffset)358 Placement SheetWrapperLayoutAlgorithm::AvoidanceRuleOfPlacement(
359 LayoutWrapper* layoutWrapper, const SizeF& targetSize, const OffsetF& targetOffset)
360 {
361 auto finalPlacement = placement_;
362 // step1: confirm the direction to place popup
363 TAG_LOGD(AceLogTag::ACE_SHEET, "Init PopupSheet placement: %{public}s",
364 PlacementUtils::ConvertPlacementToString(finalPlacement).c_str());
365 auto& placementStateVec = PLACEMENT_STATES[finalPlacement];
366 for (auto placement : placementStateVec) {
367 finalPlacement = placement;
368 auto& directionFunc = directionCheckFunc_[placement];
369 if (directionFunc == nullptr) {
370 continue;
371 }
372 if ((this->*directionFunc)(targetSize, targetOffset)) {
373 break;
374 }
375 }
376 TAG_LOGD(AceLogTag::ACE_SHEET, "After directionCheck, placement: %{public}s",
377 PlacementUtils::ConvertPlacementToString(finalPlacement).c_str());
378 // step2: check whether placement direction is NONE;
379 if (finalPlacement == Placement::NONE) {
380 sheetPopupInfo_.placementRechecked = true;
381 if (sheetPopupInfo_.placementOnTarget) {
382 finalPlacement = placement_;
383 } else {
384 SizeF bestSize = SizeF(0.f, 0.f);
385 finalPlacement = RecheckBestPlacementWithInsufficientSpace(targetSize, targetOffset, bestSize);
386 sheetHeight_ = bestSize.Height();
387 }
388 } else {
389 sheetPopupInfo_.placementRechecked = false;
390 }
391 return finalPlacement;
392 }
393
CheckDirectionBottom(const SizeF & targetSize,const OffsetF & targetOffset)394 bool SheetWrapperLayoutAlgorithm::CheckDirectionBottom(const SizeF& targetSize, const OffsetF& targetOffset)
395 {
396 float sheetPageAvoidHeight = (SHEET_TARGET_SPACE + WINDOW_EDGE_SPACE).ConvertToPx();
397 /* if sheetWidth < sheetRadius * 2 + sheetArrowWidth, arrow is no need to show,
398 * so that arrowHeight is no need to avoid.
399 */
400 if (GreatOrEqual(sheetWidth_, sheetRadius_.radiusTopLeft->ConvertToPx() +
401 sheetRadius_.radiusTopRight->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
402 sheetPageAvoidHeight += SHEET_ARROW_HEIGHT.ConvertToPx();
403 }
404 return GreatOrEqual(windowGlobalRect_.Width(), sheetWidth_ + DOUBLE_SIZE * windowEdgeWidth_) &&
405 GreatOrEqual(windowGlobalRect_.Height() + windowGlobalRect_.Top() - targetOffset.GetY() - targetSize.Height(),
406 sheetHeight_ + sheetPageAvoidHeight);
407 }
408
CheckDirectionTop(const SizeF & targetSize,const OffsetF & targetOffset)409 bool SheetWrapperLayoutAlgorithm::CheckDirectionTop(const SizeF& targetSize, const OffsetF& targetOffset)
410 {
411 float sheetPageAvoidHeight = (SHEET_TARGET_SPACE + WINDOW_EDGE_SPACE).ConvertToPx();
412 /* if sheetWidth < sheetRadius * 2 + sheetArrowWidth, arrow is no need to show,
413 * so that arrowHeight is no need to avoid.
414 */
415 if (GreatOrEqual(sheetWidth_, sheetRadius_.radiusBottomLeft->ConvertToPx() +
416 sheetRadius_.radiusBottomRight->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
417 sheetPageAvoidHeight += SHEET_ARROW_HEIGHT.ConvertToPx();
418 }
419 return GreatOrEqual(windowGlobalRect_.Width(), sheetWidth_ + DOUBLE_SIZE * windowEdgeWidth_) &&
420 GreatOrEqual(targetOffset.GetY() - windowGlobalRect_.Top(),
421 sheetHeight_ + sheetPageAvoidHeight);
422 }
423
CheckDirectionRight(const SizeF & targetSize,const OffsetF & targetOffset)424 bool SheetWrapperLayoutAlgorithm::CheckDirectionRight(const SizeF& targetSize, const OffsetF& targetOffset)
425 {
426 float sheetPageAvoidWidth = (SHEET_TARGET_SPACE + WINDOW_EDGE_SPACE).ConvertToPx();
427 /* if sheetHeight < sheetRadius * 2 + sheetArrowWidth, arrow is no need to show,
428 * so that arrowHeight is no need to avoid.
429 */
430 if (GreatOrEqual(sheetHeight_, sheetRadius_.radiusTopLeft->ConvertToPx() +
431 sheetRadius_.radiusBottomLeft->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
432 sheetPageAvoidWidth += SHEET_ARROW_HEIGHT.ConvertToPx();
433 }
434 return GreatOrEqual(windowGlobalRect_.Width() - targetOffset.GetX() - targetSize.Width(),
435 sheetWidth_ + sheetPageAvoidWidth) &&
436 GreatOrEqual(windowGlobalRect_.Height(), sheetHeight_ + DOUBLE_SIZE * WINDOW_EDGE_SPACE.ConvertToPx());
437 }
438
CheckDirectionLeft(const SizeF & targetSize,const OffsetF & targetOffset)439 bool SheetWrapperLayoutAlgorithm::CheckDirectionLeft(const SizeF& targetSize, const OffsetF& targetOffset)
440 {
441 float sheetPageAvoidWidth = (SHEET_TARGET_SPACE + WINDOW_EDGE_SPACE).ConvertToPx();
442 /* if sheetHeight < sheetRadius * 2 + sheetArrowWidth, arrow is no need to show,
443 * so that arrowHeight is no need to avoid.
444 */
445 if (GreatOrEqual(sheetHeight_, sheetRadius_.radiusTopRight->ConvertToPx() +
446 sheetRadius_.radiusBottomRight->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
447 sheetPageAvoidWidth += SHEET_ARROW_HEIGHT.ConvertToPx();
448 }
449 return GreatOrEqual(targetOffset.GetX(), sheetWidth_ + sheetPageAvoidWidth) &&
450 GreatOrEqual(windowGlobalRect_.Height(),
451 sheetHeight_ + DOUBLE_SIZE * WINDOW_EDGE_SPACE.ConvertToPx());
452 }
453
RecheckBestPlacementWithInsufficientSpace(const SizeF & targetSize,const OffsetF & targetOffset,SizeF & bestSize)454 Placement SheetWrapperLayoutAlgorithm::RecheckBestPlacementWithInsufficientSpace(
455 const SizeF& targetSize, const OffsetF& targetOffset, SizeF& bestSize)
456 {
457 auto expectedPlacement = Placement::NONE;
458 auto& recheckPlacementVec = PLACEMENT_STATES[placement_];
459 for (auto placement : recheckPlacementVec) {
460 auto curLeftSpace = GetLeftSpaceWithPlacement(placement, targetSize, targetOffset);
461 /* best placement need to meet the following conditions:
462 * 1.space width >= sheetWidth
463 * 2.space height is the biggest in every placement
464 */
465 if (curLeftSpace.Width() >= sheetWidth_ && curLeftSpace.Height() < sheetHeight_) {
466 if (curLeftSpace.Height() > bestSize.Height()) {
467 bestSize = curLeftSpace;
468 expectedPlacement = placement;
469 }
470 }
471 }
472 TAG_LOGI(AceLogTag::ACE_SHEET, "get best size in insufficient space: %{public}s", bestSize.ToString().c_str());
473 return expectedPlacement;
474 }
475
CheckPlacementBottom(const SizeF & targetSize,const OffsetF & targetOffset)476 bool SheetWrapperLayoutAlgorithm::CheckPlacementBottom(const SizeF& targetSize, const OffsetF& targetOffset)
477 {
478 return GreatOrEqual(
479 windowGlobalRect_.Width() - WINDOW_EDGE_SPACE.ConvertToPx(),
480 targetOffset.GetX() + targetSize.Width() / DOUBLE_SIZE + sheetWidth_ / DOUBLE_SIZE) &&
481 LessOrEqual(
482 WINDOW_EDGE_SPACE.ConvertToPx(),
483 targetOffset.GetX() + targetSize.Width() / DOUBLE_SIZE - sheetWidth_ / DOUBLE_SIZE);
484 }
485
CheckPlacementBottomLeft(const SizeF & targetSize,const OffsetF & targetOffset)486 bool SheetWrapperLayoutAlgorithm::CheckPlacementBottomLeft(const SizeF& targetSize, const OffsetF& targetOffset)
487 {
488 return LessOrEqual(WINDOW_EDGE_SPACE.ConvertToPx(), targetOffset.GetX()) &&
489 GreatOrEqual(windowGlobalRect_.Width() - WINDOW_EDGE_SPACE.ConvertToPx(), targetOffset.GetX() + sheetWidth_);
490 }
491
CheckPlacementBottomRight(const SizeF & targetSize,const OffsetF & targetOffset)492 bool SheetWrapperLayoutAlgorithm::CheckPlacementBottomRight(const SizeF& targetSize, const OffsetF& targetOffset)
493 {
494 return LessOrEqual(WINDOW_EDGE_SPACE.ConvertToPx(), targetOffset.GetX() + targetSize.Width() - sheetWidth_) &&
495 GreatOrEqual(
496 windowGlobalRect_.Width() - WINDOW_EDGE_SPACE.ConvertToPx(), targetOffset.GetX() + targetSize.Width());
497 }
498
GetLeftSpaceWithPlacement(const Placement & placement,const SizeF & targetSize,const OffsetF & targetOffset)499 SizeF SheetWrapperLayoutAlgorithm::GetLeftSpaceWithPlacement(
500 const Placement& placement, const SizeF& targetSize, const OffsetF& targetOffset)
501 {
502 float width = 0.f;
503 float height = 0.f;
504 float sheetPageAvoidHeight = (SHEET_TARGET_SPACE + WINDOW_EDGE_SPACE).ConvertToPx();
505 float sheetPageAvoidWidth = (SHEET_TARGET_SPACE + WINDOW_EDGE_SPACE).ConvertToPx();
506 switch (placement) {
507 case Placement::BOTTOM_LEFT:
508 [[fallthrough]];
509 case Placement::BOTTOM_RIGHT:
510 [[fallthrough]];
511 case Placement::BOTTOM: {
512 if (GreatOrEqual(sheetWidth_, sheetRadius_.radiusTopLeft->ConvertToPx() +
513 sheetRadius_.radiusTopRight->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
514 sheetPageAvoidHeight += SHEET_ARROW_HEIGHT.ConvertToPx();
515 }
516 width = windowGlobalRect_.Width() - DOUBLE_SIZE * windowEdgeWidth_;
517 height = windowGlobalRect_.Height() + windowGlobalRect_.Top() -
518 targetOffset.GetY() - targetSize.Height() - sheetPageAvoidHeight;
519 break;
520 }
521 case Placement::TOP_LEFT:
522 [[fallthrough]];
523 case Placement::TOP_RIGHT:
524 [[fallthrough]];
525 case Placement::TOP: {
526 if (GreatOrEqual(sheetWidth_, sheetRadius_.radiusBottomLeft->ConvertToPx() +
527 sheetRadius_.radiusBottomRight->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
528 sheetPageAvoidHeight += SHEET_ARROW_HEIGHT.ConvertToPx();
529 }
530 width = windowGlobalRect_.Width() - DOUBLE_SIZE * windowEdgeWidth_;
531 height = targetOffset.GetY() - windowGlobalRect_.Top() - sheetPageAvoidHeight;
532 break;
533 }
534 case Placement::RIGHT_TOP:
535 [[fallthrough]];
536 case Placement::RIGHT_BOTTOM:
537 [[fallthrough]];
538 case Placement::RIGHT: {
539 if (GreatOrEqual(sheetHeight_, sheetRadius_.radiusTopLeft->ConvertToPx() +
540 sheetRadius_.radiusBottomLeft->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
541 sheetPageAvoidWidth += SHEET_ARROW_HEIGHT.ConvertToPx();
542 }
543 width = windowGlobalRect_.Width() - targetOffset.GetX() - targetSize.Width() - sheetPageAvoidWidth;
544 height = windowGlobalRect_.Height() - DOUBLE_SIZE * WINDOW_EDGE_SPACE.ConvertToPx();
545 break;
546 }
547 case Placement::LEFT_TOP:
548 [[fallthrough]];
549 case Placement::LEFT_BOTTOM:
550 [[fallthrough]];
551 case Placement::LEFT: {
552 if (GreatOrEqual(sheetHeight_, sheetRadius_.radiusTopRight->ConvertToPx() +
553 sheetRadius_.radiusBottomRight->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
554 sheetPageAvoidWidth += SHEET_ARROW_HEIGHT.ConvertToPx();
555 }
556 width = targetOffset.GetX() - sheetPageAvoidWidth;
557 height = windowGlobalRect_.Height() - DOUBLE_SIZE * WINDOW_EDGE_SPACE.ConvertToPx();
558 break;
559 }
560 default:
561 break;
562 }
563 return SizeF(width, height);
564 }
565
GetOffsetWithBottom(const SizeF & targetSize,const OffsetF & targetOffset)566 OffsetF SheetWrapperLayoutAlgorithm::GetOffsetWithBottom(
567 const SizeF& targetSize, const OffsetF& targetOffset)
568 {
569 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
570 sheetPopupInfo_.arrowOffsetX = sheetWidth_ / DOUBLE_SIZE;
571 return OffsetF(targetOffset.GetX() + (targetSize.Width() - sheetWidth_) / DOUBLE_SIZE,
572 targetOffset.GetY() + targetSize.Height() + SHEET_TARGET_SPACE.ConvertToPx());
573 }
574
575 float finalOffsetX = targetOffset.GetX() + (targetSize.Width() - sheetWidth_) / DOUBLE_SIZE;
576 float finalOffsetY = targetOffset.GetY() + targetSize.Height() + SHEET_TARGET_SPACE.ConvertToPx();
577 RestrictOffsetInSpaceBottom(finalOffsetX, finalOffsetY);
578 if (!sheetPopupInfo_.showArrow) {
579 return OffsetF(finalOffsetX, finalOffsetY);
580 }
581 // if sheetWidth < sheetRadius * 2 + sheetArrowWidth, arrow is no need to show
582 if (LessNotEqual(sheetWidth_, sheetRadius_.radiusTopLeft->ConvertToPx() +
583 sheetRadius_.radiusTopRight->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
584 sheetPopupInfo_.showArrow = false;
585 return OffsetF(finalOffsetX, finalOffsetY);
586 }
587 SetArrowOffsetInBottomOrTop(targetSize, targetOffset, finalOffsetX);
588 CheckIsArrowOverlapSheetRadius();
589 return OffsetF(finalOffsetX, finalOffsetY);
590 }
591
GetOffsetWithBottomLeft(const SizeF & targetSize,const OffsetF & targetOffset)592 OffsetF SheetWrapperLayoutAlgorithm::GetOffsetWithBottomLeft(
593 const SizeF& targetSize, const OffsetF& targetOffset)
594 {
595 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
596 sheetPopupInfo_.arrowOffsetX = targetSize.Width() / DOUBLE_SIZE;
597 auto sheetOffset =
598 OffsetF(targetOffset.GetX(), targetOffset.GetY() + targetSize.Height() + SHEET_TARGET_SPACE.ConvertToPx());
599
600 // if the arrow overlaps the sheet left corner, move sheet to the 6vp from the left edge
601 if (LessNotEqual(sheetPopupInfo_.arrowOffsetX - ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(),
602 sheetRadius_.radiusTopLeft->ConvertToPx())) {
603 sheetOffset.SetX(WINDOW_EDGE_SPACE.ConvertToPx());
604 sheetPopupInfo_.arrowOffsetX = targetOffset.GetX() + targetSize.Width() / DOUBLE_SIZE - sheetOffset.GetX();
605 TAG_LOGD(AceLogTag::ACE_SHEET, "Adjust sheet to the left boundary of the screen");
606 }
607
608 // if the arrow still overlaps the sheet left corner, the arrow will become a right angle.
609 if (LessNotEqual(sheetPopupInfo_.arrowOffsetX - ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(),
610 sheetRadius_.radiusTopLeft->ConvertToPx())) {
611 TAG_LOGD(AceLogTag::ACE_SHEET, "Need to switch the arrow into the right-angle arrow");
612 }
613 return sheetOffset;
614 }
615
616 float finalOffsetX = targetOffset.GetX();
617 float finalOffsetY = targetOffset.GetY() + targetSize.Height() + SHEET_TARGET_SPACE.ConvertToPx();
618 RestrictOffsetInSpaceBottom(finalOffsetX, finalOffsetY);
619 if (!sheetPopupInfo_.showArrow) {
620 return OffsetF(finalOffsetX, finalOffsetY);
621 }
622 // if sheetWidth < sheetRadius * 2 + sheetArrowWidth, arrow is no need to show
623 if (LessNotEqual(sheetWidth_, sheetRadius_.radiusTopLeft->ConvertToPx() +
624 sheetRadius_.radiusTopRight->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
625 sheetPopupInfo_.showArrow = false;
626 return OffsetF(finalOffsetX, finalOffsetY);
627 }
628 SetArrowOffsetInBottomOrTop(targetSize, targetOffset, finalOffsetX);
629 CheckIsArrowOverlapSheetRadius();
630 return OffsetF(finalOffsetX, finalOffsetY);
631 }
632
GetOffsetWithBottomRight(const SizeF & targetSize,const OffsetF & targetOffset)633 OffsetF SheetWrapperLayoutAlgorithm::GetOffsetWithBottomRight(
634 const SizeF& targetSize, const OffsetF& targetOffset)
635 {
636 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
637 sheetPopupInfo_.arrowOffsetX = sheetWidth_ - targetSize.Width() / DOUBLE_SIZE;
638 auto sheetOffset = OffsetF(targetOffset.GetX() + targetSize.Width() - sheetWidth_,
639 targetOffset.GetY() + targetSize.Height() + SHEET_TARGET_SPACE.ConvertToPx());
640
641 // if the arrow overlaps the sheet right corner, move sheet to the 6vp from the right edge
642 if (GreatNotEqual(sheetPopupInfo_.arrowOffsetX + sheetRadius_.radiusTopRight->ConvertToPx() +
643 ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(), sheetWidth_)) {
644 sheetOffset.SetX(windowGlobalRect_.Width() - WINDOW_EDGE_SPACE.ConvertToPx() - sheetWidth_);
645 sheetPopupInfo_.arrowOffsetX = targetOffset.GetX() + targetSize.Width() / DOUBLE_SIZE - sheetOffset.GetX();
646 TAG_LOGD(AceLogTag::ACE_SHEET, "Adjust sheet to the right boundary of the screen");
647 }
648
649 // if the arrow still overlaps the sheet right corner, the arrow will become a right angle.
650 if (GreatNotEqual(sheetPopupInfo_.arrowOffsetX + sheetRadius_.radiusTopRight->ConvertToPx() +
651 ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(), sheetWidth_)) {
652 TAG_LOGD(AceLogTag::ACE_SHEET, "Need to switch the arrow into the right angle arrow");
653 }
654 return sheetOffset;
655 }
656
657 float finalOffsetX = targetOffset.GetX() + targetSize.Width() - sheetWidth_;
658 float finalOffsetY = targetOffset.GetY() + targetSize.Height() + SHEET_TARGET_SPACE.ConvertToPx();
659 RestrictOffsetInSpaceBottom(finalOffsetX, finalOffsetY);
660 if (!sheetPopupInfo_.showArrow) {
661 return OffsetF(finalOffsetX, finalOffsetY);
662 }
663 // if sheetWidth < sheetRadius * 2 + sheetArrowWidth, arrow is no need to show
664 if (LessNotEqual(sheetWidth_, sheetRadius_.radiusTopLeft->ConvertToPx() +
665 sheetRadius_.radiusTopRight->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
666 sheetPopupInfo_.showArrow = false;
667 return OffsetF(finalOffsetX, finalOffsetY);
668 }
669 SetArrowOffsetInBottomOrTop(targetSize, targetOffset, finalOffsetX);
670 CheckIsArrowOverlapSheetRadius();
671 return OffsetF(finalOffsetX, finalOffsetY);
672 }
673
GetOffsetWithTop(const SizeF & targetSize,const OffsetF & targetOffset)674 OffsetF SheetWrapperLayoutAlgorithm::GetOffsetWithTop(const SizeF& targetSize, const OffsetF& targetOffset)
675 {
676 float finalOffsetX = targetOffset.GetX() + (targetSize.Width() - sheetWidth_) / DOUBLE_SIZE;
677 float finalOffsetY = targetOffset.GetY() -
678 SHEET_TARGET_SPACE.ConvertToPx() - sheetHeight_ - SHEET_ARROW_HEIGHT.ConvertToPx();
679 RestrictOffsetInSpaceTop(finalOffsetX, finalOffsetY);
680 if (!sheetPopupInfo_.showArrow) {
681 return OffsetF(finalOffsetX, finalOffsetY);
682 }
683 // if sheetWidth < sheetRadius * 2 + sheetArrowWidth, arrow is no need to show
684 if (LessNotEqual(sheetWidth_, sheetRadius_.radiusBottomLeft->ConvertToPx() +
685 sheetRadius_.radiusBottomRight->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
686 sheetPopupInfo_.showArrow = false;
687 return OffsetF(finalOffsetX, finalOffsetY);
688 }
689 SetArrowOffsetInBottomOrTop(targetSize, targetOffset, finalOffsetX);
690 CheckIsArrowOverlapSheetRadius();
691 return OffsetF(finalOffsetX, finalOffsetY);
692 }
693
GetOffsetWithTopLeft(const SizeF & targetSize,const OffsetF & targetOffset)694 OffsetF SheetWrapperLayoutAlgorithm::GetOffsetWithTopLeft(const SizeF& targetSize, const OffsetF& targetOffset)
695 {
696 float finalOffsetX = targetOffset.GetX();
697 float finalOffsetY = targetOffset.GetY() -
698 SHEET_TARGET_SPACE.ConvertToPx() - sheetHeight_ - SHEET_ARROW_HEIGHT.ConvertToPx();
699 RestrictOffsetInSpaceTop(finalOffsetX, finalOffsetY);
700 if (!sheetPopupInfo_.showArrow) {
701 return OffsetF(finalOffsetX, finalOffsetY);
702 }
703 // if sheetWidth < sheetRadius * 2 + sheetArrowWidth, arrow is no need to show
704 if (LessNotEqual(sheetWidth_, sheetRadius_.radiusBottomLeft->ConvertToPx() +
705 sheetRadius_.radiusBottomRight->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
706 sheetPopupInfo_.showArrow = false;
707 return OffsetF(finalOffsetX, finalOffsetY);
708 }
709 SetArrowOffsetInBottomOrTop(targetSize, targetOffset, finalOffsetX);
710 CheckIsArrowOverlapSheetRadius();
711 return OffsetF(finalOffsetX, finalOffsetY);
712 }
713
GetOffsetWithTopRight(const SizeF & targetSize,const OffsetF & targetOffset)714 OffsetF SheetWrapperLayoutAlgorithm::GetOffsetWithTopRight(
715 const SizeF& targetSize, const OffsetF& targetOffset)
716 {
717 float finalOffsetX = targetOffset.GetX() + targetSize.Width() - sheetWidth_;
718 float finalOffsetY = targetOffset.GetY() -
719 SHEET_TARGET_SPACE.ConvertToPx() - sheetHeight_ - SHEET_ARROW_HEIGHT.ConvertToPx();
720 RestrictOffsetInSpaceTop(finalOffsetX, finalOffsetY);
721 if (!sheetPopupInfo_.showArrow) {
722 return OffsetF(finalOffsetX, finalOffsetY);
723 }
724 // if sheetWidth < sheetRadius * 2 + sheetArrowWidth, arrow is no need to show
725 if (LessNotEqual(sheetWidth_, sheetRadius_.radiusBottomLeft->ConvertToPx() +
726 sheetRadius_.radiusBottomRight->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
727 sheetPopupInfo_.showArrow = false;
728 return OffsetF(finalOffsetX, finalOffsetY);
729 }
730 SetArrowOffsetInBottomOrTop(targetSize, targetOffset, finalOffsetX);
731 CheckIsArrowOverlapSheetRadius();
732 return OffsetF(finalOffsetX, finalOffsetY);
733 }
734
GetOffsetWithLeft(const SizeF & targetSize,const OffsetF & targetOffset)735 OffsetF SheetWrapperLayoutAlgorithm::GetOffsetWithLeft(const SizeF& targetSize, const OffsetF& targetOffset)
736 {
737 float finalOffsetX = targetOffset.GetX() -
738 sheetWidth_ - SHEET_TARGET_SPACE.ConvertToPx() - SHEET_ARROW_HEIGHT.ConvertToPx();
739 float finalOffsetY = targetOffset.GetY() + (targetSize.Height() - sheetHeight_) / DOUBLE_SIZE;
740 RestrictOffsetInSpaceLeft(finalOffsetX, finalOffsetY);
741 if (!sheetPopupInfo_.showArrow) {
742 return OffsetF(finalOffsetX, finalOffsetY);
743 }
744 // if sheetHeight < sheetRadius * 2 + sheetArrowWidth, arrow is no need to show
745 if (LessNotEqual(sheetHeight_, sheetRadius_.radiusTopRight->ConvertToPx() +
746 sheetRadius_.radiusBottomRight->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
747 sheetPopupInfo_.showArrow = false;
748 return OffsetF(finalOffsetX, finalOffsetY);
749 }
750 SetArrowOffsetInRightOrLeft(targetSize, targetOffset, finalOffsetY);
751 CheckIsArrowOverlapSheetRadius();
752 return OffsetF(finalOffsetX, finalOffsetY);
753 }
754
GetOffsetWithLeftTop(const SizeF & targetSize,const OffsetF & targetOffset)755 OffsetF SheetWrapperLayoutAlgorithm::GetOffsetWithLeftTop(const SizeF& targetSize, const OffsetF& targetOffset)
756 {
757 float finalOffsetX = targetOffset.GetX() -
758 sheetWidth_ - SHEET_TARGET_SPACE.ConvertToPx() - SHEET_ARROW_HEIGHT.ConvertToPx();
759 float finalOffsetY = targetOffset.GetY();
760 RestrictOffsetInSpaceLeft(finalOffsetX, finalOffsetY);
761 if (!sheetPopupInfo_.showArrow) {
762 return OffsetF(finalOffsetX, finalOffsetY);
763 }
764 // if sheetHeight < sheetRadius * 2 + sheetArrowWidth, arrow is no need to show
765 if (LessNotEqual(sheetHeight_, sheetRadius_.radiusTopRight->ConvertToPx() +
766 sheetRadius_.radiusBottomRight->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
767 sheetPopupInfo_.showArrow = false;
768 return OffsetF(finalOffsetX, finalOffsetY);
769 }
770 SetArrowOffsetInRightOrLeft(targetSize, targetOffset, finalOffsetY);
771 CheckIsArrowOverlapSheetRadius();
772 return OffsetF(finalOffsetX, finalOffsetY);
773 }
774
GetOffsetWithLeftBottom(const SizeF & targetSize,const OffsetF & targetOffset)775 OffsetF SheetWrapperLayoutAlgorithm::GetOffsetWithLeftBottom(
776 const SizeF& targetSize, const OffsetF& targetOffset)
777 {
778 float finalOffsetX = targetOffset.GetX() -
779 sheetWidth_ - SHEET_TARGET_SPACE.ConvertToPx() - SHEET_ARROW_HEIGHT.ConvertToPx();
780 float finalOffsetY = targetOffset.GetY() + targetSize.Height() - sheetHeight_;
781 RestrictOffsetInSpaceLeft(finalOffsetX, finalOffsetY);
782 if (!sheetPopupInfo_.showArrow) {
783 return OffsetF(finalOffsetX, finalOffsetY);
784 }
785 // if sheetHeight < sheetRadius * 2 + sheetArrowWidth, arrow is no need to show
786 if (LessNotEqual(sheetHeight_, sheetRadius_.radiusTopRight->ConvertToPx() +
787 sheetRadius_.radiusBottomRight->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
788 sheetPopupInfo_.showArrow = false;
789 return OffsetF(finalOffsetX, finalOffsetY);
790 }
791 SetArrowOffsetInRightOrLeft(targetSize, targetOffset, finalOffsetY);
792 CheckIsArrowOverlapSheetRadius();
793 return OffsetF(finalOffsetX, finalOffsetY);
794 }
795
GetOffsetWithRight(const SizeF & targetSize,const OffsetF & targetOffset)796 OffsetF SheetWrapperLayoutAlgorithm::GetOffsetWithRight(const SizeF& targetSize, const OffsetF& targetOffset)
797 {
798 float finalOffsetX = targetOffset.GetX() + targetSize.Width() + SHEET_TARGET_SPACE.ConvertToPx();
799 float finalOffsetY = targetOffset.GetY() + (targetSize.Height() - sheetHeight_) / DOUBLE_SIZE;
800 RestrictOffsetInSpaceRight(finalOffsetX, finalOffsetY);
801 if (!sheetPopupInfo_.showArrow) {
802 return OffsetF(finalOffsetX, finalOffsetY);
803 }
804 // if sheetHeight < sheetRadius * 2 + sheetArrowWidth, arrow is no need to show
805 if (LessNotEqual(sheetHeight_, sheetRadius_.radiusTopLeft->ConvertToPx() +
806 sheetRadius_.radiusBottomLeft->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
807 sheetPopupInfo_.showArrow = false;
808 return OffsetF(finalOffsetX, finalOffsetY);
809 }
810 SetArrowOffsetInRightOrLeft(targetSize, targetOffset, finalOffsetY);
811 CheckIsArrowOverlapSheetRadius();
812 return OffsetF(finalOffsetX, finalOffsetY);
813 }
814
GetOffsetWithRightTop(const SizeF & targetSize,const OffsetF & targetOffset)815 OffsetF SheetWrapperLayoutAlgorithm::GetOffsetWithRightTop(const SizeF& targetSize, const OffsetF& targetOffset)
816 {
817 float finalOffsetX = targetOffset.GetX() + targetSize.Width() + SHEET_TARGET_SPACE.ConvertToPx();
818 float finalOffsetY = targetOffset.GetY();
819 RestrictOffsetInSpaceRight(finalOffsetX, finalOffsetY);
820 if (!sheetPopupInfo_.showArrow) {
821 return OffsetF(finalOffsetX, finalOffsetY);
822 }
823 // if sheetHeight < sheetRadius * 2 + sheetArrowWidth, arrow is no need to show
824 if (LessNotEqual(sheetHeight_, sheetRadius_.radiusTopLeft->ConvertToPx() +
825 sheetRadius_.radiusBottomLeft->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
826 sheetPopupInfo_.showArrow = false;
827 return OffsetF(finalOffsetX, finalOffsetY);
828 }
829 SetArrowOffsetInRightOrLeft(targetSize, targetOffset, finalOffsetY);
830 CheckIsArrowOverlapSheetRadius();
831 return OffsetF(finalOffsetX, finalOffsetY);
832 }
833
GetOffsetWithRightBottom(const SizeF & targetSize,const OffsetF & targetOffset)834 OffsetF SheetWrapperLayoutAlgorithm::GetOffsetWithRightBottom(
835 const SizeF& targetSize, const OffsetF& targetOffset)
836 {
837 float finalOffsetX = targetOffset.GetX() + targetSize.Width() + SHEET_TARGET_SPACE.ConvertToPx();
838 float finalOffsetY = targetOffset.GetY() + targetSize.Height() - sheetHeight_;
839 RestrictOffsetInSpaceRight(finalOffsetX, finalOffsetY);
840 if (!sheetPopupInfo_.showArrow) {
841 return OffsetF(finalOffsetX, finalOffsetY);
842 }
843 // if sheetHeight < sheetRadius * 2 + sheetArrowWidth, arrow is no need to show
844 if (LessNotEqual(sheetHeight_, sheetRadius_.radiusTopLeft->ConvertToPx() +
845 sheetRadius_.radiusBottomLeft->ConvertToPx() + SHEET_ARROW_WIDTH.ConvertToPx())) {
846 sheetPopupInfo_.showArrow = false;
847 return OffsetF(finalOffsetX, finalOffsetY);
848 }
849 SetArrowOffsetInRightOrLeft(targetSize, targetOffset, finalOffsetY);
850 CheckIsArrowOverlapSheetRadius();
851 return OffsetF(finalOffsetX, finalOffsetY);
852 }
853
SetArrowOffsetInBottomOrTop(const SizeF & targetSize,const OffsetF & targetOffset,float sheetOffset)854 void SheetWrapperLayoutAlgorithm::SetArrowOffsetInBottomOrTop(
855 const SizeF& targetSize, const OffsetF& targetOffset, float sheetOffset)
856 {
857 sheetPopupInfo_.arrowOffsetX = targetOffset.GetX() + targetSize.Width() / DOUBLE_SIZE - sheetOffset;
858
859 sheetPopupInfo_.arrowOffsetX = std::clamp(static_cast<double>(sheetPopupInfo_.arrowOffsetX),
860 ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(),
861 sheetWidth_ - ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx());
862 }
863
SetArrowOffsetInRightOrLeft(const SizeF & targetSize,const OffsetF & targetOffset,float sheetOffset)864 void SheetWrapperLayoutAlgorithm::SetArrowOffsetInRightOrLeft(
865 const SizeF& targetSize, const OffsetF& targetOffset, float sheetOffset)
866 {
867 sheetPopupInfo_.arrowOffsetY = targetOffset.GetY() + targetSize.Height() / DOUBLE_SIZE - sheetOffset;
868
869 sheetPopupInfo_.arrowOffsetY = std::clamp(static_cast<double>(sheetPopupInfo_.arrowOffsetY),
870 ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(),
871 sheetHeight_ - ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx());
872 }
873
RestrictOffsetInSpaceBottom(float & offsetX,float & offsetY)874 void SheetWrapperLayoutAlgorithm::RestrictOffsetInSpaceBottom(float& offsetX, float& offsetY)
875 {
876 offsetX = std::clamp(static_cast<double>(offsetX), static_cast<double>(windowEdgeWidth_),
877 windowGlobalRect_.Width() - sheetWidth_ - windowEdgeWidth_);
878
879 offsetY = std::clamp(static_cast<double>(offsetY), windowGlobalRect_.Top() + WINDOW_EDGE_SPACE.ConvertToPx(),
880 windowGlobalRect_.Height() + windowGlobalRect_.Top() - sheetHeight_ - WINDOW_EDGE_SPACE.ConvertToPx());
881
882 if (sheetPopupInfo_.placementRechecked && sheetPopupInfo_.placementOnTarget) {
883 sheetPopupInfo_.showArrow = false;
884 offsetY =
885 windowGlobalRect_.Height() + windowGlobalRect_.Top() - sheetHeight_ - WINDOW_EDGE_SPACE.ConvertToPx();
886 }
887 }
888
RestrictOffsetInSpaceTop(float & offsetX,float & offsetY)889 void SheetWrapperLayoutAlgorithm::RestrictOffsetInSpaceTop(float& offsetX, float& offsetY)
890 {
891 offsetX = std::clamp(static_cast<double>(offsetX), static_cast<double>(windowEdgeWidth_),
892 windowGlobalRect_.Width() - sheetWidth_ - windowEdgeWidth_);
893
894 offsetY = std::clamp(static_cast<double>(offsetY), windowGlobalRect_.Top() + WINDOW_EDGE_SPACE.ConvertToPx(),
895 windowGlobalRect_.Height() + windowGlobalRect_.Top() - sheetHeight_ - WINDOW_EDGE_SPACE.ConvertToPx());
896
897 if (sheetPopupInfo_.placementRechecked && sheetPopupInfo_.placementOnTarget) {
898 sheetPopupInfo_.showArrow = false;
899 offsetY = windowGlobalRect_.Top() + WINDOW_EDGE_SPACE.ConvertToPx();
900 }
901 }
902
RestrictOffsetInSpaceLeft(float & offsetX,float & offsetY)903 void SheetWrapperLayoutAlgorithm::RestrictOffsetInSpaceLeft(float& offsetX, float& offsetY)
904 {
905 offsetX = std::clamp(static_cast<double>(offsetX), static_cast<double>(windowEdgeWidth_),
906 windowGlobalRect_.Width() - sheetWidth_ - windowEdgeWidth_);
907
908 offsetY = std::clamp(static_cast<double>(offsetY), windowGlobalRect_.Top() + WINDOW_EDGE_SPACE.ConvertToPx(),
909 windowGlobalRect_.Height() + windowGlobalRect_.Top() - sheetHeight_ - WINDOW_EDGE_SPACE.ConvertToPx());
910
911 if (sheetPopupInfo_.placementRechecked && sheetPopupInfo_.placementOnTarget) {
912 sheetPopupInfo_.showArrow = false;
913 offsetX = windowEdgeWidth_;
914 }
915 }
916
RestrictOffsetInSpaceRight(float & offsetX,float & offsetY)917 void SheetWrapperLayoutAlgorithm::RestrictOffsetInSpaceRight(float& offsetX, float& offsetY)
918 {
919 offsetX = std::clamp(static_cast<double>(offsetX), static_cast<double>(windowEdgeWidth_),
920 windowGlobalRect_.Width() - sheetWidth_ - windowEdgeWidth_);
921
922 offsetY = std::clamp(static_cast<double>(offsetY), windowGlobalRect_.Top() + WINDOW_EDGE_SPACE.ConvertToPx(),
923 windowGlobalRect_.Height() + windowGlobalRect_.Top() - sheetHeight_ - WINDOW_EDGE_SPACE.ConvertToPx());
924
925 if (sheetPopupInfo_.placementRechecked && sheetPopupInfo_.placementOnTarget) {
926 sheetPopupInfo_.showArrow = false;
927 offsetX = windowGlobalRect_.Width() - windowEdgeWidth_ - sheetWidth_;
928 }
929 }
930
CheckIsArrowOverlapSheetRadius()931 void SheetWrapperLayoutAlgorithm::CheckIsArrowOverlapSheetRadius()
932 {
933 sheetPopupInfo_.arrowPosition = SheetArrowPosition::NONE;
934 switch (sheetPopupInfo_.finalPlacement) {
935 case Placement::BOTTOM_LEFT:
936 [[fallthrough]];
937 case Placement::BOTTOM_RIGHT:
938 [[fallthrough]];
939 case Placement::BOTTOM: {
940 if (LessNotEqual(sheetPopupInfo_.arrowOffsetX - ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(),
941 sheetRadius_.radiusTopLeft->ConvertToPx())) {
942 sheetPopupInfo_.arrowPosition = SheetArrowPosition::BOTTOM_LEFT;
943 } else if (GreatNotEqual(sheetPopupInfo_.arrowOffsetX + ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(),
944 sheetWidth_ - sheetRadius_.radiusTopRight->ConvertToPx())) {
945 sheetPopupInfo_.arrowPosition = SheetArrowPosition::BOTTOM_RIGHT;
946 }
947 break;
948 }
949 case Placement::TOP_LEFT:
950 [[fallthrough]];
951 case Placement::TOP_RIGHT:
952 [[fallthrough]];
953 case Placement::TOP: {
954 if (LessNotEqual(sheetPopupInfo_.arrowOffsetX - ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(),
955 sheetRadius_.radiusBottomLeft->ConvertToPx())) {
956 sheetPopupInfo_.arrowPosition = SheetArrowPosition::TOP_LEFT;
957 } else if (GreatNotEqual(sheetPopupInfo_.arrowOffsetX + ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(),
958 sheetWidth_ - sheetRadius_.radiusBottomRight->ConvertToPx())) {
959 sheetPopupInfo_.arrowPosition = SheetArrowPosition::TOP_RIGHT;
960 }
961 break;
962 }
963 case Placement::RIGHT_TOP:
964 [[fallthrough]];
965 case Placement::RIGHT_BOTTOM:
966 [[fallthrough]];
967 case Placement::RIGHT: {
968 if (LessNotEqual(sheetPopupInfo_.arrowOffsetY - ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(),
969 sheetRadius_.radiusTopLeft->ConvertToPx())) {
970 sheetPopupInfo_.arrowPosition = SheetArrowPosition::RIGHT_TOP;
971 } else if (GreatNotEqual(sheetPopupInfo_.arrowOffsetY + ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(),
972 sheetHeight_ - sheetRadius_.radiusBottomLeft->ConvertToPx())) {
973 sheetPopupInfo_.arrowPosition = SheetArrowPosition::RIGHT_BOTTOM;
974 }
975 break;
976 }
977 case Placement::LEFT_TOP:
978 [[fallthrough]];
979 case Placement::LEFT_BOTTOM:
980 [[fallthrough]];
981 case Placement::LEFT: {
982 if (LessNotEqual(sheetPopupInfo_.arrowOffsetY - ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(),
983 sheetRadius_.radiusTopRight->ConvertToPx())) {
984 sheetPopupInfo_.arrowPosition = SheetArrowPosition::LEFT_TOP;
985 } else if (GreatNotEqual(sheetPopupInfo_.arrowOffsetY + ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(),
986 sheetHeight_ - sheetRadius_.radiusBottomRight->ConvertToPx())) {
987 sheetPopupInfo_.arrowPosition = SheetArrowPosition::LEFT_BOTTOM;
988 }
989 break;
990 }
991 default:
992 sheetPopupInfo_.arrowPosition = SheetArrowPosition::NONE;
993 break;
994 }
995 }
996
Layout(LayoutWrapper * layoutWrapper)997 void SheetWrapperLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
998 {
999 BoxLayoutAlgorithm::PerformLayout(layoutWrapper);
1000 auto host = layoutWrapper->GetHostNode();
1001 CHECK_NULL_VOID(host);
1002 auto sheetWrapperPattern = host->GetPattern<SheetWrapperPattern>();
1003 CHECK_NULL_VOID(sheetWrapperPattern);
1004 auto sheetPageNode = sheetWrapperPattern->GetSheetPageNode();
1005 CHECK_NULL_VOID(sheetPageNode);
1006 auto sheetPagePattern = sheetPageNode->GetPattern<SheetPresentationPattern>();
1007 CHECK_NULL_VOID(sheetPagePattern);
1008 auto sheetType = sheetPagePattern->GetSheetType();
1009 if (sheetType == SheetType::SHEET_POPUP) {
1010 TAG_LOGI(AceLogTag::ACE_SHEET, "before popup sheet page, origin size [%{public}f, %{public}f]",
1011 sheetWidth_, sheetHeight_);
1012 OffsetF popupOffset = GetPopupStyleSheetOffset(layoutWrapper);
1013 auto hostNode = layoutWrapper->GetHostNode();
1014 CHECK_NULL_VOID(hostNode);
1015 auto wrapperOffset = hostNode->GetPaintRectOffset();
1016 sheetPopupInfo_.sheetOffsetX = popupOffset.GetX() - wrapperOffset.GetX();
1017 sheetPopupInfo_.sheetOffsetY = popupOffset.GetY() - wrapperOffset.GetY();
1018 TAG_LOGI(AceLogTag::ACE_SHEET, "checked offset (%{public}f, %{public}f), checked size [%{public}f, %{public}f]",
1019 sheetPopupInfo_.sheetOffsetX, sheetPopupInfo_.sheetOffsetY, sheetWidth_, sheetHeight_);
1020 RemeasureForPopup(layoutWrapper);
1021 }
1022 auto index = host->GetChildIndexById(sheetPageNode->GetId());
1023 auto sheetPageWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
1024 CHECK_NULL_VOID(sheetPageWrapper);
1025 sheetPageWrapper->Layout();
1026 LayoutMaskNode(layoutWrapper);
1027 }
1028
LayoutMaskNode(LayoutWrapper * layoutWrapper)1029 void SheetWrapperLayoutAlgorithm::LayoutMaskNode(LayoutWrapper* layoutWrapper)
1030 {
1031 auto host = layoutWrapper->GetHostNode();
1032 CHECK_NULL_VOID(host);
1033 auto sheetWrapperPattern = host->GetPattern<SheetWrapperPattern>();
1034 CHECK_NULL_VOID(sheetWrapperPattern);
1035 if (!sheetWrapperPattern->ShowInUEC()) {
1036 return;
1037 }
1038 auto maskNode = sheetWrapperPattern->GetSheetMaskNode();
1039 CHECK_NULL_VOID(maskNode);
1040 auto maskPattern = maskNode->GetPattern<SheetMaskPattern>();
1041 CHECK_NULL_VOID(maskPattern);
1042 auto index = host->GetChildIndexById(maskNode->GetId());
1043 auto maskWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
1044 CHECK_NULL_VOID(maskWrapper);
1045 auto rect = sheetWrapperPattern->GetMainWindowRect();
1046 auto contentOffset = OffsetF(rect.GetX(), rect.GetY());
1047 auto geometryNode = maskWrapper->GetGeometryNode();
1048 CHECK_NULL_VOID(geometryNode);
1049 geometryNode->SetMarginFrameOffset(contentOffset);
1050
1051 auto currentId = Container::CurrentId();
1052 SubwindowManager::GetInstance()->DeleteHotAreas(currentId, maskNode->GetId(), SubwindowType::TYPE_SHEET);
1053 if (maskPattern->GetIsMaskInteractive()) {
1054 std::vector<Rect> rects;
1055 auto maskHotRect = Rect(rect.GetX(), rect.GetY(),
1056 maskNode->GetGeometryNode()->GetFrameSize().Width(), maskNode->GetGeometryNode()->GetFrameSize().Height());
1057 rects.emplace_back(maskHotRect);
1058 auto subWindowMgr = SubwindowManager::GetInstance();
1059 subWindowMgr->SetHotAreas(rects, SubwindowType::TYPE_SHEET, maskNode->GetId(), currentId);
1060 }
1061 maskWrapper->Layout();
1062 }
1063
RemeasureForPopup(LayoutWrapper * layoutWrapper)1064 void SheetWrapperLayoutAlgorithm::RemeasureForPopup(LayoutWrapper* layoutWrapper)
1065 {
1066 UpdateSheetNodePopupInfo(layoutWrapper);
1067 }
1068
UpdateSheetNodePopupInfo(LayoutWrapper * layoutWrapper)1069 void SheetWrapperLayoutAlgorithm::UpdateSheetNodePopupInfo(LayoutWrapper* layoutWrapper)
1070 {
1071 auto host = layoutWrapper->GetHostNode();
1072 CHECK_NULL_VOID(host);
1073 auto sheetWrapperPattern = host->GetPattern<SheetWrapperPattern>();
1074 CHECK_NULL_VOID(sheetWrapperPattern);
1075 auto sheetNode = sheetWrapperPattern->GetSheetPageNode();
1076 CHECK_NULL_VOID(sheetNode);
1077 auto index = host->GetChildIndexById(sheetNode->GetId());
1078 auto sheetPageWrapper = layoutWrapper->GetOrCreateChildByIndex(index);
1079 CHECK_NULL_VOID(sheetPageWrapper);
1080 auto sheetPageNode = sheetPageWrapper->GetHostNode();
1081 CHECK_NULL_VOID(sheetPageNode);
1082 auto sheetPagePattern = sheetPageNode->GetPattern<SheetPresentationPattern>();
1083 CHECK_NULL_VOID(sheetPagePattern);
1084 sheetPagePattern->UpdateSheetPopupInfo(sheetPopupInfo_);
1085 auto sheetPageLayoutAlgorithmWrapper = sheetPageWrapper->GetLayoutAlgorithm();
1086 CHECK_NULL_VOID(sheetPageLayoutAlgorithmWrapper);
1087 auto sheetPageLayoutAlgorithm =
1088 DynamicCast<SheetPresentationLayoutAlgorithm>(sheetPageLayoutAlgorithmWrapper->GetLayoutAlgorithm());
1089 CHECK_NULL_VOID(sheetPageLayoutAlgorithm);
1090 sheetPageLayoutAlgorithm->UpdatePopupInfoAndRemeasure(layoutWrapper, sheetPopupInfo_, sheetWidth_, sheetHeight_);
1091 }
1092 } // namespace OHOS::Ace::NG
1093