1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components_ng/pattern/grid/grid_scroll/grid_scroll_with_options_layout_algorithm.h"
17
18 namespace OHOS::Ace::NG {
AdjustRowColSpan(const RefPtr<LayoutWrapper> &,LayoutWrapper * layoutWrapper,int32_t itemIndex)19 void GridScrollWithOptionsLayoutAlgorithm::AdjustRowColSpan(
20 const RefPtr<LayoutWrapper>& /* itemLayoutWrapper */, LayoutWrapper* layoutWrapper, int32_t itemIndex)
21 {
22 auto result = GetCrossStartAndSpan(layoutWrapper, itemIndex);
23 if (gridLayoutInfo_.axis_ == Axis::VERTICAL) {
24 currentItemColStart_ = result.first;
25 currentItemColSpan_ = result.second;
26 currentItemColEnd_ = currentItemColStart_ + currentItemColSpan_ - 1;
27 currentItemRowStart_ = -1;
28 currentItemRowEnd_ = -1;
29 currentItemRowSpan_ = 1;
30 } else {
31 currentItemRowStart_ = result.first;
32 currentItemRowSpan_ = result.second;
33 currentItemRowEnd_ = currentItemColStart_ + currentItemColSpan_ - 1;
34 currentItemColStart_ = -1;
35 currentItemColEnd_ = -1;
36 currentItemColSpan_ = 1;
37 }
38 }
39
LargeItemLineHeight(const RefPtr<LayoutWrapper> & itemWrapper,bool &)40 void GridScrollWithOptionsLayoutAlgorithm::LargeItemLineHeight(
41 const RefPtr<LayoutWrapper>& itemWrapper, bool& /* hasNormalItem */)
42 {
43 auto itemSize = itemWrapper->GetGeometryNode()->GetMarginFrameSize();
44 cellAveLength_ = std::max(GetMainAxisSize(itemSize, gridLayoutInfo_.axis_), cellAveLength_);
45 }
46
GetTargetIndexInfoWithBenchMark(LayoutWrapper * layoutWrapper,bool isTargetBackward,int32_t targetIndex)47 void GridScrollWithOptionsLayoutAlgorithm::GetTargetIndexInfoWithBenchMark(
48 LayoutWrapper* layoutWrapper, bool isTargetBackward, int32_t targetIndex)
49 {
50 int32_t benchmarkIndex = isTargetBackward ? gridLayoutInfo_.gridMatrix_.rbegin()->second.rbegin()->second + 1 : 0;
51 int32_t mainStartIndex = isTargetBackward ? gridLayoutInfo_.gridMatrix_.rbegin()->first + 1 : 0;
52 int32_t currentIndex = benchmarkIndex;
53 int32_t headOfMainStartLine = currentIndex;
54
55 while (currentIndex < targetIndex) {
56 int32_t crossGridReserve = gridLayoutInfo_.crossCount_;
57 /* go through a new line */
58 while ((crossGridReserve > 0) && (currentIndex <= targetIndex)) {
59 auto crossPos = GetCrossStartAndSpan(layoutWrapper, targetIndex);
60 auto gridSpan = crossPos.second;
61 if (crossGridReserve >= gridSpan) {
62 crossGridReserve -= gridSpan;
63 } else if (gridLayoutInfo_.crossCount_ >= gridSpan) {
64 ++mainStartIndex;
65 headOfMainStartLine = currentIndex;
66 crossGridReserve = gridLayoutInfo_.crossCount_ - gridSpan;
67 }
68 ++currentIndex;
69 }
70 if (currentIndex > targetIndex) {
71 break;
72 }
73 ++mainStartIndex;
74 headOfMainStartLine = currentIndex;
75 }
76 gridLayoutInfo_.startMainLineIndex_ = mainStartIndex;
77 gridLayoutInfo_.startIndex_ = headOfMainStartLine;
78 gridLayoutInfo_.endIndex_ = headOfMainStartLine - 1;
79 gridLayoutInfo_.prevOffset_ = 0;
80 gridLayoutInfo_.currentOffset_ = 0;
81 gridLayoutInfo_.ResetPositionFlags();
82 gridLayoutInfo_.gridMatrix_.clear();
83 gridLayoutInfo_.lineHeightMap_.clear();
84 gridLayoutInfo_.irregularItemsPosition_.clear();
85 }
86
GetCrossStartAndSpan(LayoutWrapper * layoutWrapper,int32_t itemIndex)87 std::pair<int32_t, int32_t> GridScrollWithOptionsLayoutAlgorithm::GetCrossStartAndSpan(
88 LayoutWrapper* layoutWrapper, int32_t itemIndex)
89 {
90 auto layoutProperty = DynamicCast<GridLayoutProperty>(layoutWrapper->GetLayoutProperty());
91 CHECK_NULL_RETURN(layoutProperty, std::make_pair(-1, 1));
92 auto options = layoutProperty->GetLayoutOptions().value();
93 if (options.irregularIndexes.empty()) {
94 return std::make_pair(itemIndex % crossCount_, 1);
95 }
96
97 auto firstIrregularIndex = *(options.irregularIndexes.begin());
98 if (itemIndex < firstIrregularIndex) {
99 return std::make_pair(itemIndex % crossCount_, 1);
100 }
101
102 // without function
103 if (!options.getSizeByIndex) {
104 if (options.irregularIndexes.find(itemIndex) != options.irregularIndexes.end()) {
105 return std::make_pair(0, crossCount_);
106 }
107 int32_t crossStart = -1;
108 auto iter = std::find_if(options.irregularIndexes.begin(), options.irregularIndexes.end(),
109 [itemIndex](int32_t index) { return index > itemIndex; });
110 if (iter == options.irregularIndexes.end()) {
111 crossStart = (itemIndex - (*(options.irregularIndexes.rbegin()) + 1)) % crossCount_;
112 } else {
113 if (iter != options.irregularIndexes.begin()) {
114 crossStart = (itemIndex - (*(--iter) + 1)) % crossCount_;
115 } else {
116 crossStart = itemIndex % crossCount_;
117 }
118 }
119 return std::make_pair(crossStart, 1);
120 }
121
122 return GetCrossStartAndSpanWithUserFunction(itemIndex, options, firstIrregularIndex);
123 }
124
JumpToLastIrregularItem(const std::map<int32_t,int32_t> & irregularItemsPosition,int32_t & sum,int32_t & lastIndex,int32_t targetIndex)125 static void JumpToLastIrregularItem(
126 const std::map<int32_t, int32_t>& irregularItemsPosition, int32_t& sum, int32_t& lastIndex, int32_t targetIndex)
127 {
128 if (irregularItemsPosition.empty()) {
129 return;
130 }
131
132 auto iter = std::find_if(irregularItemsPosition.begin(), irregularItemsPosition.end(),
133 [targetIndex](const std::pair<int32_t, int32_t>& item) { return item.first >= targetIndex; });
134 if (iter == irregularItemsPosition.begin()) {
135 return;
136 }
137 if (iter != irregularItemsPosition.end()) {
138 --iter;
139 sum = iter->second - 1;
140 lastIndex = iter->first;
141 } else {
142 auto lastIter = irregularItemsPosition.rbegin();
143 sum = lastIter->second - 1;
144 lastIndex = lastIter->first;
145 }
146 }
147
GetCrossStartAndSpanWithUserFunction(int32_t itemIndex,const GridLayoutOptions & options,int32_t firstIrregularIndex)148 std::pair<int32_t, int32_t> GridScrollWithOptionsLayoutAlgorithm::GetCrossStartAndSpanWithUserFunction(
149 int32_t itemIndex, const GridLayoutOptions& options, int32_t firstIrregularIndex)
150 {
151 auto sum = firstIrregularIndex;
152 auto lastIndex = firstIrregularIndex;
153 JumpToLastIrregularItem(gridLayoutInfo_.irregularItemsPosition_, sum, lastIndex, itemIndex);
154 auto iter = options.irregularIndexes.find(lastIndex);
155 if (iter == options.irregularIndexes.end()) {
156 iter = options.irregularIndexes.begin();
157 }
158 for (; iter != options.irregularIndexes.end(); ++iter) {
159 auto index = *iter;
160 if (index >= itemIndex) {
161 break;
162 }
163
164 if (index >= lastIndex) {
165 continue;
166 }
167
168 auto crossSpan = options.getSizeByIndex(index).GetCorssSize(gridLayoutInfo_.axis_);
169 if (crossSpan > static_cast<int32_t>(crossCount_) || crossSpan <= 0) {
170 LOGI("crossSpan invalid, use 1");
171 crossSpan = 1;
172 }
173 auto irregularStart = (sum + index - lastIndex) % crossCount_;
174 // put it into next line
175 if (irregularStart + crossSpan > crossCount_) {
176 sum += (crossCount_ - irregularStart);
177 }
178 sum += (index - lastIndex - 1);
179 sum += crossSpan;
180 lastIndex = index;
181 }
182 sum += (itemIndex - lastIndex);
183 auto crossStart = sum % crossCount_;
184 bool isRegularItem = (options.irregularIndexes.find(itemIndex) == options.irregularIndexes.end());
185 auto crossSpan = isRegularItem ? 1 : options.getSizeByIndex(itemIndex).GetCorssSize(gridLayoutInfo_.axis_);
186 if (crossSpan > static_cast<int32_t>(crossCount_) || crossSpan <= 0) {
187 LOGI("crossSpan invalid, use 1");
188 crossSpan = 1;
189 }
190 if (crossStart + crossSpan > crossCount_) {
191 sum += (crossCount_ - crossStart);
192 crossStart = 0;
193 }
194 if (!isRegularItem) {
195 sum += crossSpan;
196 gridLayoutInfo_.irregularItemsPosition_.emplace(itemIndex, sum);
197 }
198 return std::make_pair(crossStart, crossSpan);
199 }
200
SkipLargeOffset(float mainSize,LayoutWrapper * layoutWrapper)201 void GridScrollWithOptionsLayoutAlgorithm::SkipLargeOffset(float mainSize, LayoutWrapper* layoutWrapper)
202 {
203 SkipForwardLines(mainSize, layoutWrapper);
204 SkipBackwardLines(mainSize, layoutWrapper);
205 }
206 } // namespace OHOS::Ace::NG
207