• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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