1 /*
2 * Copyright (c) 2022 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/list/list_item_layout_algorithm.h"
17
18 #include "base/geometry/ng/offset_t.h"
19 #include "base/utils/utils.h"
20 #include "core/components_ng/layout/box_layout_algorithm.h"
21 #include "core/components_ng/pattern/list/list_item_layout_property.h"
22 #include "core/components_ng/property/measure_utils.h"
23
24 namespace OHOS::Ace::NG {
25
IsRTLAndVertical(LayoutWrapper * layoutWrapper) const26 bool ListItemLayoutAlgorithm::IsRTLAndVertical(LayoutWrapper* layoutWrapper) const
27 {
28 auto layoutDirection = layoutWrapper->GetLayoutProperty()->GetNonAutoLayoutDirection();
29 if (layoutDirection == TextDirection::RTL && axis_ == Axis::VERTICAL) {
30 return true;
31 } else {
32 return false;
33 }
34 }
35
SetReverseValue(LayoutWrapper * layoutWrapper,float offset)36 float ListItemLayoutAlgorithm::SetReverseValue(LayoutWrapper* layoutWrapper, float offset)
37 {
38 if (IsRTLAndVertical(layoutWrapper)) {
39 return -offset;
40 } else {
41 return offset;
42 }
43 }
44
Measure(LayoutWrapper * layoutWrapper)45 void ListItemLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
46 {
47 layoutWrapper->RemoveAllChildInRenderTree();
48
49 std::list<RefPtr<LayoutWrapper>> childList;
50 auto layoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
51 auto child = layoutWrapper->GetOrCreateChildByIndex(childNodeIndex_);
52 if (child) {
53 child->Measure(layoutConstraint);
54 childList.push_back(child);
55 }
56 PerformMeasureSelfWithChildList(layoutWrapper, childList);
57 auto mainSize = layoutWrapper->GetGeometryNode()->GetPaddingSize().MainSize(axis_);
58 if (NonPositive(mainSize)) {
59 curOffset_ = 0.0f;
60 return;
61 }
62 if (Positive(curOffset_) && startNodeIndex_ >= 0) {
63 auto startLayoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
64 if (!NearZero(startNodeSize_) && curOffset_ > startNodeSize_) {
65 startLayoutConstraint.maxSize.SetCrossSize(curOffset_, axis_);
66 startLayoutConstraint.minSize.SetCrossSize(curOffset_, axis_);
67 }
68 startLayoutConstraint.maxSize.SetMainSize(mainSize, axis_);
69 startLayoutConstraint.percentReference.SetMainSize(mainSize, axis_);
70 auto startNode = layoutWrapper->GetOrCreateChildByIndex(startNodeIndex_);
71 CHECK_NULL_VOID(startNode);
72 startNode->Measure(startLayoutConstraint);
73 if (NearZero(startNodeSize_) || curOffset_ < endNodeSize_) {
74 startNodeSize_ = startNode->GetGeometryNode()->GetMarginFrameSize().CrossSize(axis_);
75 }
76 curOffset_ = NearZero(startNodeSize_) && !hasStartDeleteArea_ ? 0.0f : curOffset_;
77 } else if (Negative(curOffset_) && endNodeIndex_ >= 0) {
78 auto endLayoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
79 if (!NearZero(endNodeSize_) && -curOffset_ > endNodeSize_) {
80 endLayoutConstraint.maxSize.SetCrossSize(-curOffset_, axis_);
81 endLayoutConstraint.minSize.SetCrossSize(-curOffset_, axis_);
82 }
83 endLayoutConstraint.maxSize.SetMainSize(mainSize, axis_);
84 endLayoutConstraint.percentReference.SetMainSize(mainSize, axis_);
85 auto endNode = layoutWrapper->GetOrCreateChildByIndex(endNodeIndex_);
86 CHECK_NULL_VOID(endNode);
87 endNode->Measure(endLayoutConstraint);
88 if (NearZero(endNodeSize_) || -curOffset_ < endNodeSize_) {
89 endNodeSize_ = endNode->GetGeometryNode()->GetMarginFrameSize().CrossSize(axis_);
90 }
91 curOffset_ = NearZero(endNodeSize_) && !hasEndDeleteArea_ ? 0.0f : curOffset_;
92 }
93 }
94
Layout(LayoutWrapper * layoutWrapper)95 void ListItemLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
96 {
97 // update child position.
98 auto size = layoutWrapper->GetGeometryNode()->GetFrameSize();
99 const auto& padding = layoutWrapper->GetLayoutProperty()->CreatePaddingAndBorder();
100 MinusPaddingToSize(padding, size);
101 auto paddingOffset = padding.Offset();
102 auto align = Alignment::CENTER;
103 if (layoutWrapper->GetLayoutProperty()->GetPositionProperty()) {
104 align = layoutWrapper->GetLayoutProperty()->GetPositionProperty()->GetAlignment().value_or(align);
105 }
106 // Update child position.
107 if (Positive(curOffset_) && startNodeIndex_ >= 0) {
108 auto child = layoutWrapper->GetOrCreateChildByIndex(startNodeIndex_);
109 CHECK_NULL_VOID(child);
110 auto childSize = child->GetGeometryNode()->GetMarginFrameSize();
111 float crossOffset = IsRTLAndVertical(layoutWrapper) ?
112 (size.CrossSize(axis_) - curOffset_) : (curOffset_ - childSize.CrossSize(axis_));
113 float mainOffset = (size.MainSize(axis_) - childSize.MainSize(axis_)) / 2;
114 OffsetF offset = axis_ == Axis::VERTICAL ? OffsetF(crossOffset, mainOffset) : OffsetF(mainOffset, crossOffset);
115 child->GetGeometryNode()->SetMarginFrameOffset(paddingOffset + offset);
116 child->Layout();
117 } else if (Negative(curOffset_) && endNodeIndex_ >= 0) {
118 auto child = layoutWrapper->GetOrCreateChildByIndex(endNodeIndex_);
119 CHECK_NULL_VOID(child);
120 auto childSize = child->GetGeometryNode()->GetMarginFrameSize();
121 float crossOffset = IsRTLAndVertical(layoutWrapper) ?
122 (-curOffset_ - childSize.CrossSize(axis_)) : (size.CrossSize(axis_) + curOffset_);
123 float mainOffset = (size.MainSize(axis_) - childSize.MainSize(axis_)) / 2;
124 OffsetF offset = axis_ == Axis::VERTICAL ? OffsetF(crossOffset, mainOffset) : OffsetF(mainOffset, crossOffset);
125 child->GetGeometryNode()->SetMarginFrameOffset(paddingOffset + offset);
126 child->Layout();
127 }
128 auto child = layoutWrapper->GetOrCreateChildByIndex(childNodeIndex_);
129 if (child) {
130 auto translate =
131 Alignment::GetAlignPosition(size, child->GetGeometryNode()->GetMarginFrameSize(), align) + paddingOffset;
132 OffsetF offset = axis_ == Axis::VERTICAL ? OffsetF(SetReverseValue(layoutWrapper, curOffset_), 0.0f) :
133 OffsetF(0.0f, curOffset_);
134 child->GetGeometryNode()->SetMarginFrameOffset(translate + offset);
135 child->Layout();
136 }
137 // Update content position.
138 const auto& content = layoutWrapper->GetGeometryNode()->GetContent();
139 if (content) {
140 auto translate = Alignment::GetAlignPosition(size, content->GetRect().GetSize(), align) + paddingOffset;
141 content->SetOffset(translate);
142 }
143 }
144 } // namespace OHOS::Ace::NG