1 /*
2  * Copyright (c) 2023-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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_GRID_GRID_IRREGULAR_FILLER_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_GRID_GRID_IRREGULAR_FILLER_H
18 
19 #include "base/utils/noncopyable.h"
20 #include "core/components_ng/layout/layout_wrapper.h"
21 #include "core/components_ng/pattern/grid/grid_layout_info.h"
22 #include "core/components_ng/pattern/grid/grid_layout_options.h"
23 
24 namespace OHOS::Ace::NG {
25 /**
26  * @brief The GridIrregularFiller class is responsible for filling an irregular grid layout with items.
27  *
28  * It calculates the positions and sizes of the items based on the provided layout information.
29  * The GridItems can have varying row and column lengths.
30  */
31 class GridIrregularFiller {
32     ACE_DISALLOW_COPY_AND_MOVE(GridIrregularFiller);
33 
34 public:
35     /**
36      * @brief Constructs a GridIrregularFiller object.
37      * REQUIRES: All indices prior to GridLayoutInfo::startIndex_ should already be in the GridMatrix.
38      */
39     GridIrregularFiller(GridLayoutInfo* info, LayoutWrapper* wrapper);
40     ~GridIrregularFiller() = default;
41 
42     struct FillParameters {
43         std::vector<float> crossLens; /**< The column widths of items. */
44         float crossGap = 0.0f;        /**< The cross-axis gap between items. */
45         float mainGap = 0.0f;         /**< The main-axis gap between items. */
46     };
47 
48     struct FillResult {
49         float length = 0.0f;           /**< The total length filled on the main axis. */
50         int32_t endMainLineIndex = -1; /**< The last line filled to reach target length. */
51         int32_t endIndex = -1;         /**< The index of the last item measured. */
52     };
53 
54     /**
55      * @brief Fills the grid with items in the forward direction.
56      *
57      * @param params The FillParameters object containing the fill parameters.
58      * @param targetLen The target length of the main axis (total row height to fill).
59      * @param startingLine The line index to start filling from.
60      */
61     FillResult Fill(const FillParameters& params, float targetLen, int32_t startingLine);
62 
63     /**
64      * @brief Fills the grid with items in the forward direction until targetIdx is measured.
65      *
66      * @param params The FillParameters object containing the fill parameters.
67      * @param targetIdx The target index to fill up to.
68      * @param startingLine The line index to start filling from.
69      */
70     void FillToTarget(const FillParameters& params, int32_t targetIdx, int32_t startingLine);
71 
72     /**
73      * @brief Fills the gridMatrix in forward direction until the target GridItem is included. Measure isn't performed,
74      * and lineHeightMap_ isn't updated.
75      *
76      * @param targetIdx The target GridItem index to fill.
77      *
78      * @return Line index in which Item [targetIdx] resides.
79      */
80     int32_t FillMatrixOnly(int32_t targetIdx);
81 
82     /**
83      * @brief Fills the gridMatrix in forward direction until lines prior to [targetLine] are all filled.
84      * Measure isn't performed, and lineHeightMap_ isn't updated.
85      *
86      * @param startingLine The starting line index.
87      * @param targetLine The target GridItem index to fill up to.
88      *
89      * @return Last item index filled to reach [targetLine].
90      */
91     int32_t FillMatrixByLine(int32_t startingLine, int32_t targetLine);
92 
93     /**
94      * @brief Measures the GridItems in the backward direction until the target length is filled.
95      *
96      * REQUIRES: GridMatrix prior to startingLine is already filled.
97      *
98      * @param params The fill parameters for measuring GridItems.
99      * @param targetLen The target length of the main axis (total row height to fill).
100      * @param startingLine The line index to start measuring backward.
101      * @return The total length filled on the main axis.
102      */
103     float MeasureBackward(const FillParameters& params, float targetLen, int32_t startingLine);
104 
105     /**
106      * @brief Measures the GridItems in the backward direction until the target line is measured.
107      *
108      * REQUIRES: GridMatrix prior to startingLine is already filled.
109      *
110      * @param params The fill parameters for measuring GridItems.
111      * @param targetLine The target line index to fill backward to.
112      * @param startingLine The line index to start measuring backward.
113      */
114     void MeasureBackwardToTarget(const FillParameters& params, int32_t targetLine, int32_t startingLine);
115 
116     /**
117      * @brief Check if the line contains non-top-left tiles of irregular items (represented by idx < 0 in the matrix).
118      * These items would be skipped in a a regular forward Fill, so we need to use a backward traversal to measure them.
119      * If the line doesn't contain any irregulars, no measure is performed in this function.
120      *
121      * REQUIRES: GridMatrix prior to [line] is already filled.
122      *
123      * @param params FillParameters
124      * @param line index to prepare and measure.
125      */
126     void MeasureLineWithIrregulars(const FillParameters& params, int32_t line);
127 
128     /**
129      * @brief Measures a GridItem and updates the grid layout information.
130      *
131      * @param params The FillParameters object containing the fill parameters.
132      * @param itemIdx The index of the GridItem.
133      * @param col The column index where the item is being added.
134      * @param row The row index where the item is being added.
135      */
136     std::pair<float, LayoutConstraintF> MeasureItem(
137         const FillParameters& params, int32_t itemIdx, int32_t col, int32_t row, bool isCache);
138 
139 private:
140     /**
141      * @brief Fills one GridItem into the Grid.
142      *
143      * @param idx Item index to fill in the matrix.
144      */
145     void FillOne(int32_t idx);
146 
147     /**
148      * @brief Updates the length of the main axis. Add heights in range [row, rowBound).
149      * Return immediately when [targetLen] is reached.
150      *
151      * @param len A reference to the filled length on the main axis.
152      * @param row A reference to the current row index.
153      * @param rowBound Upper bound of row index to add heights.
154      * @return true if len >= targetLen after adding height of [row]. At this point, row = last
155      */
156     bool UpdateLength(float& len, float targetLen, int32_t& row, int32_t rowBound, float mainGap) const;
157 
158     /**
159      * @brief Initializes the position of the filler in the grid to GridLayoutInfo::startIndex_.
160      *
161      * @param lineIdx The line index of the starting position.
162      * REQUIRES: lineIdx is a valid startMainLineIndex_,
163      * i.e. the top-left corner of an item resides in the first column.
164      * @return startIndex_ - 1
165      */
166     int32_t InitPos(int32_t lineIdx);
167 
168     /**
169      * @brief Initializes the position of the filler to the last item above [lineIdx] in gridMatrix_.
170      *
171      * @param lineIdx The line index to start traversing backwards (inclusive).
172      * @return index of the last item.
173      */
174     int32_t InitPosToLastItem(int32_t lineIdx);
175 
176     /**
177      * @brief Try to find the GridItem with target index in the grid matrix.
178      *
179      * @param target The target index of the GridItem.
180      * @return True if target index is already recorded in the matrix.
181      */
182     bool FindNextItem(int32_t target);
183 
184     /**
185      * @brief Advances the position of the filler in the grid.
186      *
187      * @return True if the position is successfully advanced, false if the end of the grid is reached.
188      */
189     bool AdvancePos();
190 
191     /**
192      * @brief Checks if an item can fit in the grid based on its width and the available space in the current row or
193      * column.
194      *
195      * @param it An iterator pointing to the current row or column in the grid layout information.
196      * @param itemWidth The width of the item.
197      * @return The cross-axis index where the item can fit. Returns -1 if it can't fit on the current row.
198      */
199     int32_t FitItem(const decltype(GridLayoutInfo::gridMatrix_)::iterator& it, int32_t itemWidth);
200 
201     /**
202      * @brief Implementation of MeasureBackward algorithm on each row.
203      *
204      * @param measured unordered_set to record items that are already measured.
205      * @param params Fill Parameters needed for measure.
206      */
207     void BackwardImpl(std::unordered_set<int32_t>& measured, const FillParameters& params);
208 
209     /**
210      * @brief Finds the top row index of an item in the grid.
211      *
212      * @param row The row index of the item's bottom-left tile.
213      * @param col The column index of the item's bottom-left tile.
214      * @return The top row index of the GridItem.
215      */
216     int32_t FindItemTopRow(int32_t row, int32_t col) const;
217 
218     /**
219      * @brief Update item info to the newly filled GridItem.
220      *
221      * @param idx item index
222      * @param row row index of item's top-left corner
223      * @param col column index of item's top-left corner
224      * @param size size of the item.
225      */
226     void SetItemInfo(int32_t idx, int32_t row, int32_t col, GridItemSize size);
227 
228     int32_t posY_ = 0;  /**< The current row index in the grid. */
229     int32_t posX_ = -1; /**< The current column index in the grid. */
230 
231     GridLayoutInfo* info_;
232     LayoutWrapper* wrapper_;
233 };
234 
235 } // namespace OHOS::Ace::NG
236 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_GRID_GRID_IRREGULAR_FILLER_H
237