1 /*
2 * Copyright (c) 2022-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/side_bar/side_bar_container_layout_algorithm.h"
17
18 #include "base/geometry/dimension.h"
19 #include "base/geometry/ng/offset_t.h"
20 #include "base/utils/utils.h"
21 #include "core/common/ace_application_info.h"
22 #include "core/common/container.h"
23 #include "core/components/common/layout/constants.h"
24 #include "core/components_ng/base/frame_node.h"
25 #include "core/components_ng/pattern/side_bar/side_bar_container_pattern.h"
26 #include "core/components_ng/property/calc_length.h"
27 #include "core/components_ng/property/measure_utils.h"
28 #include "core/pipeline_ng/pipeline_context.h"
29
30 namespace OHOS::Ace::NG {
31
32 namespace {
33 constexpr int32_t DEFAULT_MIN_CHILDREN_SIZE = 3;
34 constexpr Dimension DEFAULT_CONTROL_BUTTON_LEFT = 16.0_vp;
35 constexpr Dimension DEFAULT_CONTROL_BUTTON_TOP = 48.0_vp;
36 constexpr Dimension DEFAULT_MAX_SIDE_BAR_WIDTH = 280.0_vp;
37 constexpr Dimension DEFAULT_DIVIDER_STROKE_WIDTH = 1.0_vp;
38 constexpr Dimension DEFAULT_DIVIDER_START_MARGIN = 0.0_vp;
39 constexpr Dimension DEFAULT_DIVIDER_END_MARGIN = 0.0_vp;
40
41 constexpr static int INDEX_CONTRON_BUTTON = 1;
42 constexpr static int INDEX_DIVIDER = 2;
43 constexpr static int INDEX_SIDE_BAR = 3;
44 constexpr static int32_t PLATFORM_VERSION_TEN = 10;
45 static Dimension DEFAULT_SIDE_BAR_WIDTH = 200.0_vp;
46 static Dimension DEFAULT_MIN_SIDE_BAR_WIDTH = 200.0_vp;
47 static Dimension DEFAULT_MIN_CONTENT_WIDTH = 0.0_vp;
48 constexpr Dimension CONTROL_BUTTON_PADDING = 12.0_vp;
49 } // namespace
50
Measure(LayoutWrapper * layoutWrapper)51 void SideBarContainerLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
52 {
53 autoHide_ = false;
54 UpdateDefaultValueByVersion();
55 const auto& children = layoutWrapper->GetAllChildrenWithBuild(layoutWrapper->IsActive());
56 if (children.size() < DEFAULT_MIN_CHILDREN_SIZE) {
57 return;
58 }
59 auto layoutProperty = AceType::DynamicCast<SideBarContainerLayoutProperty>(layoutWrapper->GetLayoutProperty());
60 CHECK_NULL_VOID(layoutProperty);
61 const auto& constraint = layoutProperty->GetLayoutConstraint();
62 auto idealSize = PipelineContext::GetCurrentContext()->GetMinPlatformVersion() >= PLATFORM_VERSION_TEN ?
63 CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL,
64 layoutProperty->GetMeasureType(MeasureType::MATCH_PARENT)).ConvertToSizeT() :
65 CreateIdealSize(
66 constraint.value(), Axis::HORIZONTAL, layoutProperty->GetMeasureType(MeasureType::MATCH_PARENT), true);
67 layoutWrapper->GetGeometryNode()->SetFrameSize(idealSize);
68
69 AdjustMinAndMaxSideBarWidth(layoutWrapper);
70
71 auto parentWidth = idealSize.Width();
72 realSideBarWidth_ = ConvertToPx(realSideBarWidthDimension_, constraint->scaleProperty, parentWidth).value_or(-1.0f);
73 if (needInitRealSideBarWidth_ || NearZero(realSideBarWidth_)) {
74 auto pipeline = PipelineContext::GetCurrentContext();
75 if (pipeline->GetMinPlatformVersion() >= PLATFORM_VERSION_TEN) {
76 GetAllPropertyValue(layoutProperty, parentWidth);
77 } else {
78 InitRealSideBarWidth(layoutWrapper, parentWidth);
79 }
80 }
81
82 if (parentWidth >= typeUpdateWidth_) {
83 type_ = layoutProperty->GetSideBarContainerType().value_or(SideBarContainerType::EMBED);
84 }
85
86 auto type = layoutProperty->GetSideBarContainerType().value_or(SideBarContainerType::EMBED);
87 if (type == SideBarContainerType::AUTO) {
88 AutoMode(layoutProperty, parentWidth);
89 }
90
91 if ((parentWidth < typeUpdateWidth_) && (!layoutProperty->GetShowSideBar().has_value()) &&
92 (type_ != SideBarContainerType::OVERLAY)) {
93 if (isControlButtonClick_) {
94 type_ = SideBarContainerType::OVERLAY;
95 } else if (layoutProperty->GetAutoHide().value_or(true)) {
96 sideBarStatus_ = SideBarStatus::HIDDEN;
97 autoHide_ = true;
98 }
99 }
100 if (type_ != SideBarContainerType::OVERLAY) {
101 AutoChangeSideBarWidth(layoutProperty, parentWidth);
102 }
103
104 /*
105 * child inverted order is: controlbutton, divider, sidebar, contentxxx, ..., content2, content1
106 * content only display the first one, use itor from end
107 */
108 int index = 0;
109 RefPtr<LayoutWrapper> dividerLayoutWrapper = nullptr;
110 for (auto it = children.rbegin(); it != children.rend(); ++it) {
111 index++;
112 if (index == INDEX_CONTRON_BUTTON) {
113 auto imgLayoutWrapper = (*it);
114 MeasureControlButton(layoutProperty, imgLayoutWrapper, parentWidth);
115 } else if (index == INDEX_DIVIDER) {
116 dividerLayoutWrapper = (*it);
117 } else if (index == INDEX_SIDE_BAR) {
118 auto sideBarLayoutWrapper = (*it);
119 MeasureSideBar(layoutProperty, sideBarLayoutWrapper);
120 } else { // other break
121 continue;
122 }
123 }
124
125 if (dividerLayoutWrapper) {
126 MeasureDivider(layoutProperty, dividerLayoutWrapper, parentWidth);
127 }
128
129 if (children.size() > DEFAULT_MIN_CHILDREN_SIZE) { // when sidebar only add one component, content is not display
130 auto contentLayoutWrapper = children.front();
131 MeasureSideBarContent(layoutProperty, contentLayoutWrapper, parentWidth);
132 }
133
134 if (realSideBarWidthDimension_.Unit() == DimensionUnit::PERCENT) {
135 realSideBarWidthDimension_ = NearZero(parentWidth)
136 ? Dimension(0.0, DimensionUnit::PERCENT)
137 : Dimension(realSideBarWidth_ / parentWidth, DimensionUnit::PERCENT);
138 } else {
139 realSideBarWidthDimension_ = Dimension(realSideBarWidth_, DimensionUnit::PX);
140 }
141 }
142
UpdateDefaultValueByVersion()143 void SideBarContainerLayoutAlgorithm::UpdateDefaultValueByVersion()
144 {
145 auto pipeline = PipelineContext::GetCurrentContext();
146 CHECK_NULL_VOID(pipeline);
147 if (pipeline->GetMinPlatformVersion() >= PLATFORM_VERSION_TEN) {
148 DEFAULT_SIDE_BAR_WIDTH = 240.0_vp;
149 DEFAULT_MIN_SIDE_BAR_WIDTH = 240.0_vp;
150 DEFAULT_MIN_CONTENT_WIDTH = 360.0_vp;
151 }
152 }
153
GetSideBarLayoutWrapper(LayoutWrapper * layoutWrapper) const154 RefPtr<LayoutWrapper> SideBarContainerLayoutAlgorithm::GetSideBarLayoutWrapper(LayoutWrapper* layoutWrapper) const
155 {
156 CHECK_NULL_RETURN(layoutWrapper, nullptr);
157 const auto& children = layoutWrapper->GetAllChildrenWithBuild(layoutWrapper->IsActive());
158 if (children.size() < DEFAULT_MIN_CHILDREN_SIZE) {
159 return nullptr;
160 }
161
162 int index = 0;
163 for (auto it = children.rbegin(); it != children.rend(); ++it) {
164 index++;
165 if (index == INDEX_SIDE_BAR) {
166 return (*it);
167 }
168 }
169
170 return nullptr;
171 }
172
AdjustMinAndMaxSideBarWidth(LayoutWrapper * layoutWrapper)173 void SideBarContainerLayoutAlgorithm::AdjustMinAndMaxSideBarWidth(LayoutWrapper* layoutWrapper)
174 {
175 adjustMinSideBarWidth_ = DEFAULT_MIN_SIDE_BAR_WIDTH;
176 adjustMaxSideBarWidth_ = DEFAULT_MAX_SIDE_BAR_WIDTH;
177 auto layoutProperty = AceType::DynamicCast<SideBarContainerLayoutProperty>(layoutWrapper->GetLayoutProperty());
178 CHECK_NULL_VOID(layoutProperty);
179
180 auto pipeline = PipelineContext::GetCurrentContext();
181 CHECK_NULL_VOID(pipeline);
182
183 if (pipeline->GetMinPlatformVersion() < PLATFORM_VERSION_TEN) {
184 adjustMinSideBarWidth_ = layoutProperty->GetMinSideBarWidth().value_or(DEFAULT_MIN_SIDE_BAR_WIDTH);
185 adjustMaxSideBarWidth_ = layoutProperty->GetMaxSideBarWidth().value_or(DEFAULT_MAX_SIDE_BAR_WIDTH);
186 if (adjustMinSideBarWidth_ > adjustMaxSideBarWidth_) {
187 adjustMinSideBarWidth_ = DEFAULT_MIN_SIDE_BAR_WIDTH;
188 adjustMaxSideBarWidth_ = DEFAULT_MAX_SIDE_BAR_WIDTH;
189 }
190 return;
191 }
192
193 auto sideBarLayoutWrapper = GetSideBarLayoutWrapper(layoutWrapper);
194 CHECK_NULL_VOID(sideBarLayoutWrapper);
195
196 auto sideBarLayoutProperty = sideBarLayoutWrapper->GetLayoutProperty();
197 CHECK_NULL_VOID(sideBarLayoutProperty);
198
199 auto&& calcConstraint = sideBarLayoutProperty->GetCalcLayoutConstraint();
200 if (layoutProperty->GetMinSideBarWidth().has_value()) {
201 adjustMinSideBarWidth_ = layoutProperty->GetMinSideBarWidthValue();
202 } else if (calcConstraint && calcConstraint->minSize.has_value() &&
203 calcConstraint->minSize.value().Width().has_value()) {
204 adjustMinSideBarWidth_ = calcConstraint->minSize->Width()->GetDimension();
205 }
206
207 if (layoutProperty->GetMaxSideBarWidth().has_value()) {
208 adjustMaxSideBarWidth_ = layoutProperty->GetMaxSideBarWidthValue();
209 } else if (calcConstraint && calcConstraint->maxSize.has_value() && calcConstraint->maxSize->Width().has_value()) {
210 adjustMaxSideBarWidth_ = calcConstraint->maxSize->Width()->GetDimension();
211 }
212
213 if (adjustMinSideBarWidth_ > adjustMaxSideBarWidth_) {
214 adjustMinSideBarWidth_ = DEFAULT_MIN_SIDE_BAR_WIDTH;
215 adjustMaxSideBarWidth_ = DEFAULT_MAX_SIDE_BAR_WIDTH;
216 }
217 }
218
GetAllPropertyValue(const RefPtr<SideBarContainerLayoutProperty> & layoutProperty,float parentWidth)219 void SideBarContainerLayoutAlgorithm::GetAllPropertyValue(
220 const RefPtr<SideBarContainerLayoutProperty>& layoutProperty, float parentWidth)
221 {
222 const auto& constraint = layoutProperty->GetLayoutConstraint();
223 const auto& scaleProperty = constraint->scaleProperty;
224 auto realSideBarWidth = layoutProperty->GetSideBarWidth().value_or(-1.0_vp);
225 auto minSideBarWidth = layoutProperty->GetMinSideBarWidth().value_or(-1.0_vp);
226 auto minContentWidth = layoutProperty->GetMinContentWidth().value_or(-1.0_vp);
227 auto maxSideBarWidth = layoutProperty->GetMaxSideBarWidth().value_or(-1.0_vp);
228
229 realSideBarWidth_ = ConvertToPx(realSideBarWidth, scaleProperty, parentWidth).value_or(-1.0f);
230 if (preSideBarWidth_.IsValid()) {
231 realSideBarWidth_ = ConvertToPx(preSideBarWidth_, scaleProperty, parentWidth).value_or(-1.0f);
232 }
233
234 minSideBarWidth_ = ConvertToPx(minSideBarWidth, scaleProperty, parentWidth).value_or(-1.0f);
235 minContentWidth_ = ConvertToPx(minContentWidth, scaleProperty, parentWidth).value_or(-1.0f);
236 maxSideBarWidth_ = ConvertToPx(maxSideBarWidth, scaleProperty, parentWidth).value_or(-1.0f);
237
238 defaultRealSideBarWidth_ = ConvertToPx(DEFAULT_SIDE_BAR_WIDTH, scaleProperty, parentWidth).value_or(-1.0f);
239 defaultMinSideBarWidth_ = ConvertToPx(DEFAULT_MIN_SIDE_BAR_WIDTH, scaleProperty, parentWidth).value_or(-1.0f);
240 defaultMaxSideBarWidth_ = ConvertToPx(DEFAULT_MAX_SIDE_BAR_WIDTH, scaleProperty, parentWidth).value_or(-1.0f);
241 defaultMinContentWidth_ = ConvertToPx(DEFAULT_MIN_CONTENT_WIDTH, scaleProperty, parentWidth).value_or(-1.0f);
242
243 MeasureTypeUpdateWidth();
244 minContentWidth_ = std::max(0.0f, minContentWidth_);
245 InitSideBarWidth(parentWidth);
246 MeasureRealSideBarWidth(parentWidth);
247
248 auto sideBarContainerPattern = AceType::DynamicCast<SideBarContainerPattern>(pattern_.Upgrade());
249 sideBarContainerPattern->SetMinSideBarWidth(minSideBarWidth_);
250 sideBarContainerPattern->SetMaxSideBarWidth(maxSideBarWidth_);
251 sideBarContainerPattern->SetMinContentWidth(minContentWidth_);
252 sideBarContainerPattern->SetTypeUpdateWidth(typeUpdateWidth_);
253 }
254
MeasureTypeUpdateWidth()255 void SideBarContainerLayoutAlgorithm::MeasureTypeUpdateWidth()
256 {
257 if (minSideBarWidth_ >= 0.0f && minContentWidth_ >= 0.0f) {
258 typeUpdateWidth_ = minSideBarWidth_ + minContentWidth_;
259 return;
260 } else if (minSideBarWidth_ >= 0.0f) {
261 typeUpdateWidth_ = minSideBarWidth_ + defaultMinContentWidth_;
262 } else if (minContentWidth_ >= 0.0f) {
263 typeUpdateWidth_ = minContentWidth_ + defaultMinSideBarWidth_;
264 } else {
265 typeUpdateWidth_ = defaultMinSideBarWidth_ + defaultMinContentWidth_;
266 }
267 if (typeUpdateWidth_ < defaultMinSideBarWidth_ + defaultMinContentWidth_) {
268 typeUpdateWidth_ = defaultMinSideBarWidth_ + defaultMinContentWidth_;
269 }
270 }
271
InitSideBarWidth(float parentWidth)272 void SideBarContainerLayoutAlgorithm::InitSideBarWidth(float parentWidth)
273 {
274 if (minSideBarWidth_ >= parentWidth) {
275 minSideBarWidth_ = parentWidth;
276 maxSideBarWidth_ = parentWidth;
277 realSideBarWidth_ = parentWidth;
278 minContentWidth_ = 0.0f;
279 return;
280 }
281
282 if (maxSideBarWidth_ >= parentWidth) {
283 maxSideBarWidth_ = parentWidth;
284 if (realSideBarWidth_ <= minSideBarWidth_) {
285 realSideBarWidth_ = minSideBarWidth_;
286 } else if (realSideBarWidth_ >= maxSideBarWidth_) {
287 realSideBarWidth_ = maxSideBarWidth_;
288 }
289 return;
290 }
291 if (minSideBarWidth_ >= 0.0f && maxSideBarWidth_ >= 0.0f) {
292 if (minSideBarWidth_ >= maxSideBarWidth_) {
293 maxSideBarWidth_ = minSideBarWidth_;
294 realSideBarWidth_ = minSideBarWidth_;
295 return;
296 }
297 }
298
299 if (realSideBarWidth_ < 0.0f) {
300 return;
301 }
302 if (realSideBarWidth_ <= minSideBarWidth_) {
303 realSideBarWidth_ = minSideBarWidth_;
304 return;
305 } else if (realSideBarWidth_ >= maxSideBarWidth_ && maxSideBarWidth_ >= 0) {
306 realSideBarWidth_ = maxSideBarWidth_;
307 return;
308 } else if (realSideBarWidth_ >= parentWidth) {
309 realSideBarWidth_ = parentWidth;
310 }
311 }
312
MeasureRealSideBarWidth(float parentWidth)313 void SideBarContainerLayoutAlgorithm::MeasureRealSideBarWidth(float parentWidth)
314 {
315 if (minSideBarWidth_ < 0.0f) {
316 if (realSideBarWidth_ >= 0.0f) {
317 minSideBarWidth_ = realSideBarWidth_;
318 } else if (maxSideBarWidth_ >= 0.0f) {
319 minSideBarWidth_ = maxSideBarWidth_;
320 } else {
321 minSideBarWidth_ = defaultMinSideBarWidth_;
322 }
323 if (minSideBarWidth_ >= defaultMinSideBarWidth_) {
324 minSideBarWidth_ = defaultMinSideBarWidth_;
325 }
326 if (minSideBarWidth_ >= parentWidth) {
327 minSideBarWidth_ = parentWidth;
328 maxSideBarWidth_ = parentWidth;
329 realSideBarWidth_ = parentWidth;
330 return;
331 }
332 }
333
334 if (maxSideBarWidth_ < 0.0f) {
335 maxSideBarWidth_ = defaultMaxSideBarWidth_;
336 if (maxSideBarWidth_ <= realSideBarWidth_) {
337 maxSideBarWidth_ = realSideBarWidth_;
338 } else if (maxSideBarWidth_ <= minSideBarWidth_) {
339 maxSideBarWidth_ = minSideBarWidth_;
340 realSideBarWidth_ = minSideBarWidth_;
341 return;
342 }
343 }
344
345 if (realSideBarWidth_ < 0.0f) {
346 realSideBarWidth_ = defaultRealSideBarWidth_;
347 if (realSideBarWidth_ <= minSideBarWidth_) {
348 realSideBarWidth_ = minSideBarWidth_;
349 } else if (realSideBarWidth_ >= maxSideBarWidth_) {
350 realSideBarWidth_ = maxSideBarWidth_;
351 }
352 }
353 }
354
InitRealSideBarWidth(LayoutWrapper * layoutWrapper,float parentWidth)355 void SideBarContainerLayoutAlgorithm::InitRealSideBarWidth(LayoutWrapper* layoutWrapper, float parentWidth)
356 {
357 auto layoutProperty = AceType::DynamicCast<SideBarContainerLayoutProperty>(layoutWrapper->GetLayoutProperty());
358 CHECK_NULL_VOID(layoutProperty);
359 auto constraint = layoutProperty->GetLayoutConstraint();
360 auto scaleProperty = constraint->scaleProperty;
361 auto sideBarWidth = layoutProperty->GetSideBarWidth().value_or(DEFAULT_SIDE_BAR_WIDTH);
362 auto sideBarWidthPx = ConvertToPx(sideBarWidth, scaleProperty, parentWidth).value_or(0);
363 auto minSideBarWidthPx = ConvertToPx(adjustMinSideBarWidth_, scaleProperty, parentWidth).value_or(0);
364 auto maxSideBarWidthPx = ConvertToPx(adjustMaxSideBarWidth_, scaleProperty, parentWidth).value_or(0);
365 if (minSideBarWidthPx > maxSideBarWidthPx) {
366 minSideBarWidthPx = ConvertToPx(DEFAULT_MIN_SIDE_BAR_WIDTH, scaleProperty, parentWidth).value_or(0);
367 maxSideBarWidthPx = ConvertToPx(DEFAULT_MAX_SIDE_BAR_WIDTH, scaleProperty, parentWidth).value_or(0);
368 }
369
370 if (sideBarWidthPx <= minSideBarWidthPx) {
371 realSideBarWidth_ = minSideBarWidthPx;
372 } else if (sideBarWidthPx >= maxSideBarWidthPx) {
373 realSideBarWidth_ = maxSideBarWidthPx;
374 } else {
375 realSideBarWidth_ = sideBarWidthPx;
376 }
377 }
378
AutoChangeSideBarWidth(const RefPtr<SideBarContainerLayoutProperty> & layoutProperty,float parentWidth)379 void SideBarContainerLayoutAlgorithm::AutoChangeSideBarWidth(
380 const RefPtr<SideBarContainerLayoutProperty>& layoutProperty, float parentWidth)
381 {
382 /*
383 * When reducing component width, first reduce the width of the content to minContentWidth,
384 * and then reduce the width of the sidebar
385 */
386 const auto& constraint = layoutProperty->GetLayoutConstraint();
387 const auto& scaleProperty = constraint->scaleProperty;
388 auto dividerStrokeWidth = layoutProperty->GetDividerStrokeWidth().value_or(DEFAULT_DIVIDER_STROKE_WIDTH);
389 auto dividerStrokeWidthPx = ConvertToPx(dividerStrokeWidth, scaleProperty, parentWidth).value_or(1);
390 if ((realSideBarWidth_ + minContentWidth_ + dividerStrokeWidthPx) >= parentWidth) {
391 realSideBarWidth_ = parentWidth - minContentWidth_ - dividerStrokeWidthPx;
392 }
393 if (realSideBarWidth_ <= minSideBarWidth_) {
394 realSideBarWidth_ = minSideBarWidth_;
395 }
396 }
397
AutoMode(const RefPtr<SideBarContainerLayoutProperty> & layoutProperty,float parentWidth)398 void SideBarContainerLayoutAlgorithm::AutoMode(
399 const RefPtr<SideBarContainerLayoutProperty>& layoutProperty, float parentWidth)
400 {
401 /*
402 * SideBarContainer AUTO mode:
403 * When the component width is greater or equal to minNavBarWidth+minContentWidth,
404 * it is displayed in Embed mode;
405 * When the component width is smaller than minNavBarWidth+minContentWidth,
406 * it is displayed in Overlay mode.
407 */
408 if (parentWidth < typeUpdateWidth_) {
409 type_ = SideBarContainerType::OVERLAY;
410 } else {
411 type_ = SideBarContainerType::EMBED;
412 }
413 }
414
MeasureSideBar(const RefPtr<SideBarContainerLayoutProperty> & layoutProperty,const RefPtr<LayoutWrapper> & sideBarLayoutWrapper)415 void SideBarContainerLayoutAlgorithm::MeasureSideBar(
416 const RefPtr<SideBarContainerLayoutProperty>& layoutProperty, const RefPtr<LayoutWrapper>& sideBarLayoutWrapper)
417 {
418 auto constraint = layoutProperty->GetLayoutConstraint();
419 auto sideBarIdealSize = PipelineContext::GetCurrentContext()->GetMinPlatformVersion() >= PLATFORM_VERSION_TEN ?
420 CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL,
421 layoutProperty->GetMeasureType(MeasureType::MATCH_PARENT)).ConvertToSizeT():
422 CreateIdealSize(constraint.value(), Axis::HORIZONTAL,
423 layoutProperty->GetMeasureType(MeasureType::MATCH_PARENT), true);
424 const auto& padding = layoutProperty->CreatePaddingAndBorder();
425 realSideBarHeight_ = sideBarIdealSize.Height() - padding.top.value_or(0) - padding.bottom.value_or(0);
426 if (LessNotEqual(realSideBarHeight_, 0.0f)) {
427 realSideBarHeight_ = 0.0f;
428 }
429 sideBarIdealSize.SetWidth(realSideBarWidth_);
430 sideBarIdealSize.SetHeight(realSideBarHeight_);
431
432 auto pipeline = PipelineContext::GetCurrentContext();
433 CHECK_NULL_VOID(pipeline);
434 if (pipeline->GetMinPlatformVersion() >= PLATFORM_VERSION_TEN) {
435 auto sideBarLayoutProperty = sideBarLayoutWrapper->GetLayoutProperty();
436 CHECK_NULL_VOID(sideBarLayoutProperty);
437 auto&& calcConstraint = sideBarLayoutProperty->GetCalcLayoutConstraint();
438 if (calcConstraint) {
439 if (calcConstraint->maxSize.has_value()) {
440 auto maxWidth = CalcLength(realSideBarWidth_);
441 auto maxHeight = CalcLength(realSideBarHeight_);
442 calcConstraint->UpdateMaxSizeWithCheck(CalcSize(maxWidth, maxHeight));
443 }
444
445 if (calcConstraint->minSize.has_value()) {
446 auto minWidth = CalcLength(realSideBarWidth_);
447 auto minHeight = CalcLength(realSideBarHeight_);
448 calcConstraint->UpdateMinSizeWithCheck(CalcSize(minWidth, minHeight));
449 }
450 }
451 }
452
453 auto sideBarConstraint = layoutProperty->CreateChildConstraint();
454 sideBarConstraint.selfIdealSize = OptionalSizeF(sideBarIdealSize);
455
456 sideBarLayoutWrapper->Measure(sideBarConstraint);
457 }
458
MeasureDivider(const RefPtr<SideBarContainerLayoutProperty> & layoutProperty,const RefPtr<LayoutWrapper> & dividerLayoutWrapper,float parentWidth)459 void SideBarContainerLayoutAlgorithm::MeasureDivider(const RefPtr<SideBarContainerLayoutProperty>& layoutProperty,
460 const RefPtr<LayoutWrapper>& dividerLayoutWrapper, float parentWidth)
461 {
462 CHECK_NULL_VOID(layoutProperty);
463 CHECK_NULL_VOID(dividerLayoutWrapper);
464 auto constraint = layoutProperty->GetLayoutConstraint();
465 CHECK_NULL_VOID(constraint);
466 auto scaleProperty = constraint->scaleProperty;
467 auto dividerIdealSize = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN) ?
468 CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL,
469 layoutProperty->GetMeasureType(MeasureType::MATCH_PARENT)).ConvertToSizeT() :
470 CreateIdealSize(
471 constraint.value(), Axis::HORIZONTAL, layoutProperty->GetMeasureType(MeasureType::MATCH_PARENT), true);
472
473 auto dividerStrokeWidth = layoutProperty->GetDividerStrokeWidth().value_or(DEFAULT_DIVIDER_STROKE_WIDTH);
474 auto dividerStartMargin = layoutProperty->GetDividerStartMargin().value_or(DEFAULT_DIVIDER_START_MARGIN);
475 auto dividerEndMargin = layoutProperty->GetDividerEndMargin().value_or(DEFAULT_DIVIDER_END_MARGIN);
476
477 auto dividerStrokeWidthPx = ConvertToPx(dividerStrokeWidth, scaleProperty, parentWidth).value_or(1);
478 auto dividerStartMarginPx = ConvertToPx(dividerStartMargin, scaleProperty, parentWidth).value_or(0);
479 auto dividerEndMarginPx = ConvertToPx(dividerEndMargin, scaleProperty, parentWidth).value_or(0);
480
481 dividerIdealSize.SetWidth(dividerStrokeWidthPx);
482 dividerIdealSize.SetHeight(realSideBarHeight_ - dividerStartMarginPx - dividerEndMarginPx);
483 realDividerWidth_ = dividerStrokeWidthPx;
484
485 auto dividerLayoutConstraint = layoutProperty->CreateChildConstraint();
486 dividerLayoutConstraint.selfIdealSize = OptionalSizeF(dividerIdealSize);
487 dividerLayoutWrapper->Measure(dividerLayoutConstraint);
488 }
489
MeasureSideBarContent(const RefPtr<SideBarContainerLayoutProperty> & layoutProperty,const RefPtr<LayoutWrapper> & contentLayoutWrapper,float parentWidth)490 void SideBarContainerLayoutAlgorithm::MeasureSideBarContent(
491 const RefPtr<SideBarContainerLayoutProperty>& layoutProperty, const RefPtr<LayoutWrapper>& contentLayoutWrapper,
492 float parentWidth)
493 {
494 auto sideBarPosition = GetSideBarPositionWithRtl(layoutProperty);
495 auto constraint = layoutProperty->GetLayoutConstraint();
496 const auto& padding = layoutProperty->CreatePaddingAndBorder();
497 auto contentWidth = parentWidth - padding.left.value_or(0) - padding.right.value_or(0);
498
499 if (type_ == SideBarContainerType::EMBED) {
500 if (sideBarStatus_ == SideBarStatus::SHOW) {
501 contentWidth -= (realSideBarWidth_ + realDividerWidth_);
502 } else if (sideBarStatus_ == SideBarStatus::CHANGING) {
503 contentWidth = (sideBarPosition == SideBarPosition::START)
504 ? (contentWidth - realSideBarWidth_ - realDividerWidth_ - currentOffset_)
505 : (contentWidth - realDividerWidth_ + currentOffset_);
506 }
507 }
508 contentWidth = std::max(contentWidth, minContentWidth_);
509
510 auto contentIdealSize = PipelineContext::GetCurrentContext()->GetMinPlatformVersion() >= PLATFORM_VERSION_TEN ?
511 CreateIdealSizeByPercentRef(constraint.value(), Axis::HORIZONTAL,
512 layoutProperty->GetMeasureType(MeasureType::MATCH_PARENT)).ConvertToSizeT() :
513 CreateIdealSize(
514 constraint.value(), Axis::HORIZONTAL, layoutProperty->GetMeasureType(MeasureType::MATCH_PARENT), true);
515 contentIdealSize.SetWidth(contentWidth);
516 contentIdealSize.SetHeight(realSideBarHeight_);
517 auto contentConstraint = layoutProperty->CreateChildConstraint();
518 contentConstraint.selfIdealSize = OptionalSizeF(contentIdealSize);
519 contentLayoutWrapper->Measure(contentConstraint);
520 }
521
MeasureControlButton(const RefPtr<SideBarContainerLayoutProperty> & layoutProperty,const RefPtr<LayoutWrapper> & buttonLayoutWrapper,float parentWidth)522 void SideBarContainerLayoutAlgorithm::MeasureControlButton(const RefPtr<SideBarContainerLayoutProperty>& layoutProperty,
523 const RefPtr<LayoutWrapper>& buttonLayoutWrapper, float parentWidth)
524 {
525 auto constraint = layoutProperty->GetLayoutConstraint();
526 auto scaleProperty = constraint->scaleProperty;
527
528 auto controlButtonWidth = controlImageWidth_ + CONTROL_BUTTON_PADDING * 2;
529 auto controlButtonHeight = controlImageHeight_ + CONTROL_BUTTON_PADDING * 2;
530 auto controlButtonWidthPx = ConvertToPx(controlButtonWidth, scaleProperty, parentWidth).value_or(0);
531 auto controlButtonHeightPx = ConvertToPx(controlButtonHeight, scaleProperty, parentWidth).value_or(0);
532
533 auto controlButtonLayoutConstraint = layoutProperty->CreateChildConstraint();
534 controlButtonLayoutConstraint.selfIdealSize.SetWidth(controlButtonWidthPx);
535 controlButtonLayoutConstraint.selfIdealSize.SetHeight(controlButtonHeightPx);
536 buttonLayoutWrapper->Measure(controlButtonLayoutConstraint);
537 }
538
Layout(LayoutWrapper * layoutWrapper)539 void SideBarContainerLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
540 {
541 const auto& children = layoutWrapper->GetAllChildrenWithBuild(layoutWrapper->IsActive());
542 if (children.size() < DEFAULT_MIN_CHILDREN_SIZE) {
543 return;
544 }
545
546 int index = 0;
547 for (auto it = children.rbegin(); it != children.rend(); ++it) {
548 index++;
549 if (index == INDEX_CONTRON_BUTTON) {
550 auto controlButtonLayoutWrapper = (*it);
551 LayoutControlButton(layoutWrapper, controlButtonLayoutWrapper);
552 } else if (index == INDEX_DIVIDER) {
553 auto dividerLayoutWrapper = (*it);
554 LayoutDivider(layoutWrapper, dividerLayoutWrapper);
555 } else if (index == INDEX_SIDE_BAR) {
556 auto sideBarLayoutWrapper = (*it);
557 LayoutSideBar(layoutWrapper, sideBarLayoutWrapper);
558 } else { // other break
559 break;
560 }
561 }
562
563 if (children.size() > DEFAULT_MIN_CHILDREN_SIZE) { // when sidebar only add one component, content is not display
564 auto contentLayoutWrapper = children.front();
565 LayoutSideBarContent(layoutWrapper, contentLayoutWrapper);
566 }
567 }
568
LayoutControlButton(LayoutWrapper * layoutWrapper,const RefPtr<LayoutWrapper> & buttonLayoutWrapper)569 void SideBarContainerLayoutAlgorithm::LayoutControlButton(
570 LayoutWrapper* layoutWrapper, const RefPtr<LayoutWrapper>& buttonLayoutWrapper)
571 {
572 auto layoutProperty = AceType::DynamicCast<SideBarContainerLayoutProperty>(layoutWrapper->GetLayoutProperty());
573 CHECK_NULL_VOID(layoutProperty);
574
575 CHECK_NULL_VOID(layoutWrapper->GetGeometryNode());
576 auto parentWidth = layoutWrapper->GetGeometryNode()->GetFrameSize().Width();
577 auto constraint = layoutProperty->GetLayoutConstraint();
578 auto scaleProperty = constraint->scaleProperty;
579 const auto& padding = layoutProperty->CreatePaddingAndBorder();
580 auto controlImageLeft = layoutProperty->GetControlButtonLeft().value_or(DEFAULT_CONTROL_BUTTON_LEFT);
581 auto controlImageTop = layoutProperty->GetControlButtonTop().value_or(DEFAULT_CONTROL_BUTTON_TOP);
582
583 if (LessNotEqual(controlImageLeft.Value(), 0.0)) {
584 controlImageLeft = DEFAULT_CONTROL_BUTTON_LEFT;
585 }
586
587 if (LessNotEqual(controlImageTop.Value(), 0.0)) {
588 controlImageTop = DEFAULT_CONTROL_BUTTON_TOP;
589 }
590 auto controlButtonLeft = controlImageLeft - CONTROL_BUTTON_PADDING;
591 auto controlButtonTop = controlImageTop - CONTROL_BUTTON_PADDING;
592
593 auto controlButtonLeftPx = ConvertToPx(controlButtonLeft, scaleProperty, parentWidth).value_or(0);
594 auto controlButtonTopPx = ConvertToPx(controlButtonTop, scaleProperty, parentWidth).value_or(0);
595 controlButtonLeftPx += padding.left.value_or(0);
596 controlButtonTopPx += padding.top.value_or(0);
597 /*
598 * Control buttion left position need to special handle:
599 * 1. when sideBarPosition set to END and controlButtonLeft do not set in ButtonStyle
600 * control button need to move follow the sidebar to the right
601 * 2. when sideBarPosition set to START or controlButtonLeft has set by user
602 * control button keep before handle
603 * 3. if the controlButtonLeft has set, whether sideBarPosition set to START or END
604 * control button offset the left, if value invalid set to default 16vp
605 */
606 auto sideBarPosition = GetSideBarPositionWithRtl(layoutProperty);
607 auto controlButtonWidth = controlImageWidth_ + CONTROL_BUTTON_PADDING * 2;
608
609 if ((sideBarPosition == SideBarPosition::END) && // sideBarPosition is End, other pass
610 (!layoutProperty->GetControlButtonLeft().has_value())) { // origin value has not set
611 auto defaultControlButtonLeft = DEFAULT_CONTROL_BUTTON_LEFT - CONTROL_BUTTON_PADDING;
612 auto defaultControlButtonLeftPx = ConvertToPx(defaultControlButtonLeft, scaleProperty, parentWidth).value_or(0)
613 + padding.right.value_or(0);
614 auto controlButtonWidthPx = ConvertToPx(controlButtonWidth, scaleProperty, parentWidth).value_or(0);
615 controlButtonLeftPx = parentWidth - defaultControlButtonLeftPx - controlButtonWidthPx;
616 }
617
618 auto imgOffset = OffsetF(controlButtonLeftPx, controlButtonTopPx);
619 buttonLayoutWrapper->GetGeometryNode()->SetMarginFrameOffset(imgOffset);
620 buttonLayoutWrapper->Layout();
621 }
622
LayoutSideBar(LayoutWrapper * layoutWrapper,const RefPtr<LayoutWrapper> & sideBarLayoutWrapper)623 void SideBarContainerLayoutAlgorithm::LayoutSideBar(
624 LayoutWrapper* layoutWrapper, const RefPtr<LayoutWrapper>& sideBarLayoutWrapper)
625 {
626 auto layoutProperty = AceType::DynamicCast<SideBarContainerLayoutProperty>(layoutWrapper->GetLayoutProperty());
627 CHECK_NULL_VOID(layoutProperty);
628
629 CHECK_NULL_VOID(layoutWrapper->GetGeometryNode());
630 auto parentWidth = layoutWrapper->GetGeometryNode()->GetFrameSize().Width();
631 auto sideBarPosition = GetSideBarPositionWithRtl(layoutProperty);
632 const auto& padding = layoutProperty->CreatePaddingAndBorder();
633 float sideBarOffsetX = padding.left.value_or(0);
634 float sideBarOffsetY = padding.top.value_or(0);
635
636 switch (sideBarStatus_) {
637 case SideBarStatus::SHOW:
638 if (sideBarPosition == SideBarPosition::END) {
639 sideBarOffsetX = parentWidth - realSideBarWidth_ - padding.right.value_or(0);
640 }
641 break;
642 case SideBarStatus::HIDDEN:
643 if (sideBarPosition == SideBarPosition::START) {
644 sideBarOffsetX = -(realSideBarWidth_ + realDividerWidth_ - padding.left.value_or(0));
645 } else {
646 sideBarOffsetX = parentWidth + realDividerWidth_ - padding.right.value_or(0);
647 }
648 break;
649 case SideBarStatus::CHANGING:
650 if (sideBarPosition == SideBarPosition::START) {
651 sideBarOffsetX = currentOffset_ + padding.left.value_or(0);
652 } else {
653 sideBarOffsetX = parentWidth - padding.right.value_or(0) + currentOffset_;
654 }
655 break;
656 default:
657 break;
658 }
659
660 sideBarOffset_ = OffsetF(sideBarOffsetX, sideBarOffsetY);
661 sideBarLayoutWrapper->GetGeometryNode()->SetMarginFrameOffset(sideBarOffset_);
662 sideBarLayoutWrapper->Layout();
663 }
664
LayoutSideBarContent(LayoutWrapper * layoutWrapper,const RefPtr<LayoutWrapper> & contentLayoutWrapper)665 void SideBarContainerLayoutAlgorithm::LayoutSideBarContent(
666 LayoutWrapper* layoutWrapper, const RefPtr<LayoutWrapper>& contentLayoutWrapper)
667 {
668 auto layoutProperty = AceType::DynamicCast<SideBarContainerLayoutProperty>(layoutWrapper->GetLayoutProperty());
669 CHECK_NULL_VOID(layoutProperty);
670
671 auto sideBarPosition = GetSideBarPositionWithRtl(layoutProperty);
672 const auto& padding = layoutProperty->CreatePaddingAndBorder();
673 float contentOffsetX = padding.left.value_or(0);
674 float contentOffsetY = padding.top.value_or(0);
675
676 if (type_ == SideBarContainerType::EMBED && sideBarPosition == SideBarPosition::START) {
677 if (sideBarStatus_ == SideBarStatus::SHOW) {
678 contentOffsetX = realSideBarWidth_ + realDividerWidth_ + padding.left.value_or(0);
679 } else if (sideBarStatus_ == SideBarStatus::CHANGING) {
680 contentOffsetX = realSideBarWidth_ + realDividerWidth_ + currentOffset_ + padding.left.value_or(0);
681 }
682 }
683
684 auto contentOffset = OffsetF(contentOffsetX, contentOffsetY);
685 contentLayoutWrapper->GetGeometryNode()->SetMarginFrameOffset(contentOffset);
686 contentLayoutWrapper->Layout();
687 }
688
LayoutDivider(LayoutWrapper * layoutWrapper,const RefPtr<LayoutWrapper> & dividerLayoutWrapper)689 void SideBarContainerLayoutAlgorithm::LayoutDivider(
690 LayoutWrapper* layoutWrapper, const RefPtr<LayoutWrapper>& dividerLayoutWrapper)
691 {
692 CHECK_NULL_VOID(layoutWrapper);
693 CHECK_NULL_VOID(dividerLayoutWrapper);
694 auto layoutProperty = AceType::DynamicCast<SideBarContainerLayoutProperty>(layoutWrapper->GetLayoutProperty());
695 CHECK_NULL_VOID(layoutProperty);
696
697 auto sideBarPosition = GetSideBarPositionWithRtl(layoutProperty);
698
699 CHECK_NULL_VOID(layoutWrapper->GetGeometryNode());
700 auto parentWidth = layoutWrapper->GetGeometryNode()->GetFrameSize().Width();
701 auto constraint = layoutProperty->GetLayoutConstraint();
702 CHECK_NULL_VOID(constraint);
703 auto scaleProperty = constraint->scaleProperty;
704
705 auto dividerStartMargin = layoutProperty->GetDividerStartMargin().value_or(DEFAULT_DIVIDER_START_MARGIN);
706 auto dividerStartMarginPx = ConvertToPx(dividerStartMargin, scaleProperty, parentWidth).value_or(0);
707 const auto& padding = layoutProperty->CreatePaddingAndBorder();
708 float dividerOffsetX = padding.left.value_or(0);
709 float dividerOffsetY = padding.top.value_or(0);
710
711 switch (sideBarStatus_) {
712 case SideBarStatus::SHOW:
713 if (sideBarPosition == SideBarPosition::START) {
714 dividerOffsetX = realSideBarWidth_ + padding.left.value_or(0);
715 } else {
716 dividerOffsetX = parentWidth - realSideBarWidth_ - realDividerWidth_ - padding.right.value_or(0);
717 }
718 break;
719 case SideBarStatus::HIDDEN:
720 if (sideBarPosition == SideBarPosition::START) {
721 dividerOffsetX = -realDividerWidth_ + padding.left.value_or(0);
722 } else {
723 dividerOffsetX = parentWidth - padding.right.value_or(0);
724 }
725 break;
726 case SideBarStatus::CHANGING:
727 if (sideBarPosition == SideBarPosition::START) {
728 dividerOffsetX = realSideBarWidth_ + currentOffset_ + padding.left.value_or(0);
729 } else {
730 dividerOffsetX = parentWidth - realDividerWidth_ + currentOffset_ - padding.right.value_or(0);
731 }
732 break;
733 default:
734 break;
735 }
736
737 auto dividerOffset = OffsetF(dividerOffsetX, dividerStartMarginPx + dividerOffsetY);
738 CHECK_NULL_VOID(dividerLayoutWrapper->GetGeometryNode());
739 dividerLayoutWrapper->GetGeometryNode()->SetMarginFrameOffset(dividerOffset);
740 dividerLayoutWrapper->Layout();
741 }
742
GetSideBarPositionWithRtl(const RefPtr<SideBarContainerLayoutProperty> & layoutProperty)743 SideBarPosition SideBarContainerLayoutAlgorithm::GetSideBarPositionWithRtl(
744 const RefPtr<SideBarContainerLayoutProperty>& layoutProperty)
745 {
746 auto sideBarPosition = layoutProperty->GetSideBarPosition().value_or(SideBarPosition::START);
747 if (layoutProperty->GetLayoutDirection() == TextDirection::RTL ||
748 AceApplicationInfo::GetInstance().IsRightToLeft()) {
749 sideBarPosition = (sideBarPosition == SideBarPosition::START) ? SideBarPosition::END : SideBarPosition::START;
750 }
751 return sideBarPosition;
752 }
753 } // namespace OHOS::Ace::NG
754