1 /*
2  * Copyright (c) 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_WATERFLOW_WATER_FLOW_LAYOUT_INFO_SW_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_WATERFLOW_WATER_FLOW_LAYOUT_INFO_SW_H
18 
19 #include <algorithm>
20 #include <deque>
21 #include <vector>
22 
23 #include "core/components_ng/pattern/waterflow/layout/water_flow_layout_algorithm_base.h"
24 #include "core/components_ng/pattern/waterflow/layout/water_flow_layout_info_base.h"
25 
26 namespace OHOS::Ace::NG {
27 constexpr int32_t EMPTY_NEW_START_INDEX = -1;
28 constexpr int32_t INVALID_NEW_START_INDEX = -2;
29 /**
30  * @brief Layout data structure for Sliding Window version of WaterFlowLayout
31  */
32 class WaterFlowLayoutInfoSW : public WaterFlowLayoutInfoBase {
33     DECLARE_ACE_TYPE(WaterFlowLayoutInfoSW, WaterFlowLayoutInfoBase);
34 
35 public:
Mode()36     WaterFlowLayoutMode Mode() const override
37     {
38         return WaterFlowLayoutMode::SLIDING_WINDOW;
39     }
40 
Offset()41     float Offset() const override
42     {
43         return totalOffset_;
44     }
FirstIdx()45     int32_t FirstIdx() const override
46     {
47         return startIndex_;
48     }
49 
UpdateOffset(float delta)50     void UpdateOffset(float delta) override
51     {
52         delta_ += delta;
53         synced_ = false;
54     }
55 
56     float CalibrateOffset() override;
57 
58     int32_t GetCrossIndex(int32_t itemIndex) const override;
59 
60     OverScrollOffset GetOverScrolledDelta(float delta) const override;
61 
62     float CalcOverScroll(float mainSize, float delta) const override;
63 
64     bool ReachStart(float prevPos, bool firstLayout) const override;
65 
66     bool ReachEnd(float prevPos, bool firstLayout) const override;
67 
68     bool OutOfBounds() const override;
69 
70     float GetContentHeight() const override;
71 
72     float CalcTargetPosition(int32_t idx, int32_t crossIdx) const override;
73 
GetDelta(float prevPos)74     float GetDelta(float prevPos) const override
75     {
76         return prevPos - totalOffset_;
77     }
78 
79     int32_t GetMainCount() const override;
GetCrossCount()80     int32_t GetCrossCount() const override
81     {
82         if (lanes_.empty()) {
83             return 0;
84         }
85         return lanes_[0].size();
86     }
87 
CurrentPos()88     float CurrentPos() const override
89     {
90         return 0.0f;
91     }
92     float TopFinalPos() const override;
93     float BottomFinalPos(float viewHeight) const override;
94 
95     void Reset() override;
96 
97     bool IsMisaligned() const override;
98 
99     void InitSegments(const std::vector<WaterFlowSections::Section>& sections, int32_t start) override;
100 
101     /**
102      * @brief reset layout data and setting up a base position for each lane.
103      *
104      * @param laneBasePos base value for lane's start&end position.
105      * When not provided, lane positions are not modified.
106      */
107     void ResetWithLaneOffset(std::optional<float> laneBasePos);
108 
BeginUpdate()109     void BeginUpdate()
110     {
111         synced_ = false;
112     }
113     /**
114      * @brief synchronize data after update is completed.
115      *
116      * @param itemCnt number of FlowItems.
117      * @param mainSize main-axis length of the viewport.
118      * @param mainGap main-axis gap between items.
119      */
120     void Sync(int32_t itemCnt, float mainSize, const std::vector<float>& mainGap);
121 
122     /**
123      * @brief Mark beginning of cache item layout and save current lanes_ state.
124      *
125      */
126     void BeginCacheUpdate();
127     /**
128      * @brief mark synced and restore lanes_ after cache item layout
129      */
130     void EndCacheUpdate();
131 
132     /**
133      * @brief Calculates distance from the item's top edge to the top of the viewport.
134      *
135      * @param item index
136      * @return positive result when item's top edge is below viewport.
137      */
138     float DistanceToTop(int32_t item, float mainGap) const;
139 
140     /**
141      * @brief Calculates distance from the item's bottom edge to the bottom of the viewport.
142      *
143      * @param item index
144      * @param mainSize of the viewport
145      * @return positive result when item's bottom edge is above viewport.
146      */
147     float DistanceToBottom(int32_t item, float mainSize, float mainGap) const;
148 
149     int32_t StartIndex() const;
150     int32_t EndIndex() const;
ItemInView(int32_t idx)151     inline bool ItemInView(int32_t idx) const
152     {
153         return !lanes_.empty() && idx >= StartIndex() && idx <= EndIndex();
154     }
155     /**
156      * @param idx of the item.
157      * @return true the item is approximately within 1 full-viewport distance.
158      */
159     bool ItemCloseToView(int32_t idx) const;
160 
161     /**
162      * @return maximum end position of items in lanes_.
163      */
164     float EndPos() const;
EndPosWithMargin()165     inline float EndPosWithMargin() const
166     {
167         return EndPos() + BotMargin();
168     }
169     /**
170      * @return minimum start position of items in lanes_.
171      */
172     float StartPos() const;
StartPosWithMargin()173     inline float StartPosWithMargin() const
174     {
175         return StartPos() - TopMargin();
176     }
177 
178     void ClearDataFrom(int32_t idx, const std::vector<float>& mainGap);
179 
TopMargin()180     inline float TopMargin() const
181     {
182         if (margins_.empty()) {
183             return 0.0f;
184         }
185         return (axis_ == Axis::VERTICAL ? margins_.front().top : margins_.front().left).value_or(0.0f);
186     }
BotMargin()187     inline float BotMargin() const
188     {
189         if (margins_.empty()) {
190             return 0.0f;
191         }
192         return (axis_ == Axis::VERTICAL ? margins_.back().bottom : margins_.back().right).value_or(0.0f);
193     }
194 
195     /**
196      * @brief prepare lanes in the current section.
197      *
198      * @param idx current item index
199      * @param fillBack true if preparing in the forward direction (prevIdx < curIdx).
200      */
201     void PrepareSectionPos(int32_t idx, bool fillBack);
202 
203     void NotifyDataChange(int32_t index, int32_t count) override;
204     void UpdateLanesIndex(int32_t updateIdx);
205     void InitSegmentsForKeepPositionMode(const std::vector<WaterFlowSections::Section>& sections,
206         const std::vector<WaterFlowSections::Section>& prevSections, int32_t start) override;
207 
208     struct Lane;
209     /**
210      * @brief Find item's corresponding Lane
211      */
212     const Lane* GetLane(int32_t itemIdx) const;
213     Lane* GetMutableLane(int32_t itemIdx);
214 
215     bool LaneOutOfBounds(size_t laneIdx, int32_t section) const;
216 
217     /**
218      * @brief lanes in multiple sections.
219      * REQUIRES: In stable state (outside update phase), only items inside viewport are in lanes_.
220      */
221     std::vector<std::vector<Lane>> lanes_;
222     /**
223      * @brief mapping of all items previously or currently in lanes_.
224      * REQUIRES: All items in lanes_ are in idxToLane_.
225      */
226     std::unordered_map<int32_t, size_t> idxToLane_;
227 
228     float delta_ = 0.0f;
229     /* Record total offset when continuously scrolling. No longer accurate after jump. Reset when reach top */
230     float totalOffset_ = 0.0f;
231 
232     std::vector<float> mainGap_; // update this at the end of a layout
233 
234     // maximum content height encountered so far, mainly for comparing content and viewport height
235     float maxHeight_ = 0.0f;
236     float footerHeight_ = 0.0f;
237 
238     // record the new startIndex_ after changing the datasource, corresponding to the old startIndex_.
239     int32_t newStartIndex_ = EMPTY_NEW_START_INDEX;
240 
241 private:
242     inline void PrepareJump();
243 
244     void InitSegmentTails(const std::vector<WaterFlowSections::Section>& sections);
245     void InitLanes(const std::vector<WaterFlowSections::Section>& sections, int32_t start);
246 
247     /**
248      * @brief prepare newStartIndex_
249      *
250      * @return false if the value of newStartIndex_ is INVALID.
251      */
252     bool PrepareNewStartIndex();
253 
254     /**
255      * @brief Adjust Lanes_ when the change happens in front of lane.
256      *
257      * @param sections the new sections after change.
258      * @param start segment index of the first change section.
259      * @param prevSegIdx segment index of original startIndex_ belongs to.
260      *
261      * @return true if adjust successfully.
262      */
263     bool AdjustLanes(const std::vector<WaterFlowSections::Section>& sections,
264         const WaterFlowSections::Section& prevSection, int32_t start, int32_t prevSegIdx);
265 
266     void ClearData();
267 
268     /**
269      * @brief Sync state when there has no items in lanes.
270      */
271     void SyncOnEmptyLanes();
272 
273     std::unique_ptr<decltype(lanes_)> savedLanes_; // temporarily store current lanes_ state in Cache Item operations.
274 
275     /* cache */
276     float startPos_ = 0.0f;
277     float endPos_ = 0.0f;
278 
279     bool synced_ = false;
280 
281     struct ItemInfo;
282 };
283 
284 struct WaterFlowLayoutInfoSW::ItemInfo {
285     int32_t idx = -1;
286     float mainSize = 0.0f;
287 };
288 
289 struct WaterFlowLayoutInfoSW::Lane {
290     std::string ToString() const;
291 
292     float startPos = 0.0f;
293     float endPos = 0.0f;
294     std::deque<ItemInfo> items_;
295 };
296 } // namespace OHOS::Ace::NG
297 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_WATERFLOW_WATER_FLOW_LAYOUT_INFO_SW_H
298