1 /*
2  * Copyright (c) 2022-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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_LIST_LIST_ITEM_GROUP_LAYOUT_ALGORITHM_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_LIST_LIST_ITEM_GROUP_LAYOUT_ALGORITHM_H
18 
19 #include <optional>
20 #include "base/geometry/axis.h"
21 #include "core/components_ng/layout/layout_algorithm.h"
22 #include "core/components_ng/layout/layout_wrapper.h"
23 #include "core/components_ng/pattern/list/list_layout_property.h"
24 #include "core/components_v2/list/list_properties.h"
25 
26 namespace OHOS::Ace::NG {
27 class ListPositionMap;
28 class ListChildrenMainSize;
29 struct ListItemGroupLayoutInfo;
30 struct LayoutedItemInfo {
31     int32_t startIndex = 0;
32     float startPos = 0.0f;
33     int32_t endIndex = 0;
34     float endPos = 0.0f;
35 };
36 
37 struct ListItemGroupInfo {
38     int32_t id = -1;
39     float startPos = 0.0f;
40     float endPos = 0.0f;
41     bool isPressed = false;
42 };
43 
44 struct ListItemGroupCacheParam {
45     bool forward = true;
46     bool backward = false;
47     bool show = false;
48     int32_t cacheCountForward = 0;
49     int32_t cacheCountBackward = 0;
50     int32_t forwardCachedIndex = -1;
51     int32_t backwardCachedIndex = INT_MAX;
52     int64_t deadline = 0;
53 };
54 
55 struct CachedIndexInfo {
56     int32_t forwardCachedCount = 0;
57     int32_t backwardCachedCount = 0;
58     int32_t forwardCacheMax = 0;
59     int32_t backwardCacheMax = 0;
60 };
61 
62 // TextLayoutAlgorithm acts as the underlying text layout.
63 class ACE_EXPORT ListItemGroupLayoutAlgorithm : public LayoutAlgorithm {
64     DECLARE_ACE_TYPE(ListItemGroupLayoutAlgorithm, LayoutAlgorithm);
65 public:
66     using PositionMap = std::map<int32_t, ListItemGroupInfo>;
67 
68     static const int32_t LAST_ITEM = -1;
69 
ListItemGroupLayoutAlgorithm(int32_t headerIndex,int32_t footerIndex,int32_t itemStartIndex)70     ListItemGroupLayoutAlgorithm(int32_t headerIndex, int32_t footerIndex, int32_t itemStartIndex)
71         :headerIndex_(headerIndex), footerIndex_(footerIndex), itemStartIndex_(itemStartIndex) {}
72 
73     void Measure(LayoutWrapper* layoutWrapper) override;
74 
75     void Layout(LayoutWrapper* layoutWrapper) override;
76 
GetItemPosition()77     const PositionMap& GetItemPosition() const
78     {
79         return itemPosition_;
80     }
81 
GetCachedItemPosition()82     const PositionMap& GetCachedItemPosition() const
83     {
84         return cachedItemPosition_;
85     }
86 
ResetCachedItemPosition()87     void ResetCachedItemPosition()
88     {
89         cachedItemPosition_.clear();
90     }
91 
ResetCachedIndex()92     void ResetCachedIndex()
93     {
94         forwardCachedIndex_ = -1;
95         backwardCachedIndex_ = INT_MAX;
96     }
97 
SetItemsPosition(const PositionMap & itemPosition)98     void SetItemsPosition(const PositionMap& itemPosition)
99     {
100         itemPosition_ = itemPosition;
101     }
102 
SetCachedItemsPosition(const PositionMap & itemPosition)103     void SetCachedItemsPosition(const PositionMap& itemPosition)
104     {
105         cachedItemPosition_ = itemPosition;
106     }
107 
108     void ClearItemPosition();
109 
GetSpaceWidth()110     float GetSpaceWidth() const
111     {
112         return spaceWidth_;
113     }
114 
GetAxis()115     Axis GetAxis() const
116     {
117         return axis_;
118     }
119 
GetLayoutDirection()120     TextDirection GetLayoutDirection() const
121     {
122         return layoutDirection_;
123     }
124 
GetMainSize()125     float GetMainSize() const
126     {
127         return totalMainSize_;
128     }
129 
GetLanes()130     int32_t GetLanes() const
131     {
132         return lanes_;
133     }
134 
GetLaneGutter()135     float GetLaneGutter() const
136     {
137         return laneGutter_;
138     }
139 
GetLanesFloor(int32_t index)140     int32_t GetLanesFloor(int32_t index) const
141     {
142         if (lanes_ <= 1) {
143             return index;
144         }
145         return index - index % lanes_;
146     }
147 
GetLanesCeil(int32_t index)148     int32_t GetLanesCeil(int32_t index) const
149     {
150         int32_t tmpIndex = (lanes_ <= 1) ? index : (index - index % lanes_ + lanes_ - 1);
151         tmpIndex = tmpIndex >= totalItemCount_ ? totalItemCount_ - 1 : tmpIndex;
152         return tmpIndex;
153     }
154 
SetListMainSize(float startPos,float endPos,float referencePos,float prevContentSize,bool forwardLayout)155     void SetListMainSize(float startPos, float endPos, float referencePos, float prevContentSize, bool forwardLayout)
156     {
157         startPos_ = startPos;
158         endPos_ = endPos;
159         referencePos_ = referencePos;
160         forwardLayout_ = forwardLayout;
161         refPos_ = referencePos;
162         prevContentMainSize_ = prevContentSize;
163     }
164 
165     void ModifyReferencePos(int32_t index, float pos);
166 
SetNeedAdjustRefPos(bool needAdjust)167     void SetNeedAdjustRefPos(bool needAdjust)
168     {
169         needAdjustRefPos_ = needAdjust;
170     }
171 
SetNeedCheckOffset(bool needCheckOffset)172     void SetNeedCheckOffset(bool needCheckOffset)
173     {
174         isNeedCheckOffset_ = needCheckOffset;
175     }
176 
GetRefPos()177     float GetRefPos() const
178     {
179         return refPos_;
180     }
181 
SetContentOffset(float contentStartOffset,float contentEndOffset)182     void SetContentOffset(float contentStartOffset, float contentEndOffset)
183     {
184         contentStartOffset_ = contentStartOffset;
185         contentEndOffset_ = contentEndOffset;
186     }
187 
SetListLayoutProperty(RefPtr<ListLayoutProperty> layoutProperty)188     void SetListLayoutProperty(RefPtr<ListLayoutProperty> layoutProperty)
189     {
190         listLayoutProperty_ = std::move(layoutProperty);
191     }
192 
SetJumpIndex(int32_t index)193     void SetJumpIndex(int32_t index)
194     {
195         jumpIndex_ = index;
196     }
197 
SetTargetIndex(int32_t index)198     void SetTargetIndex(int32_t index)
199     {
200         targetIndex_ = index;
201     }
202 
GetStartIndex()203     int32_t GetStartIndex() const
204     {
205         return itemPosition_.empty() ? 0 : itemPosition_.begin()->first;
206     }
207 
GetEndIndex()208     int32_t GetEndIndex() const
209     {
210         return itemPosition_.empty() ? 0 : itemPosition_.rbegin()->first;
211     }
212 
GetCacheStartIndex()213     int32_t GetCacheStartIndex() const
214     {
215         return cachedItemPosition_.empty() ? -1 : cachedItemPosition_.begin()->first;
216     }
217 
GetCacheEndIndex()218     int32_t GetCacheEndIndex() const
219     {
220         return cachedItemPosition_.empty() ? -1 : cachedItemPosition_.rbegin()->first;
221     }
222 
GetStartPosition()223     float GetStartPosition() const
224     {
225         if (itemPosition_.empty()) {
226             return 0.0f;
227         }
228         if (GetStartIndex() == 0) {
229             return itemPosition_.begin()->second.startPos;
230         }
231         return itemPosition_.begin()->second.startPos - spaceWidth_;
232     }
233 
GetEndPosition()234     float GetEndPosition() const
235     {
236         if (itemPosition_.empty()) {
237             return 0.0f;
238         }
239         if (GetEndIndex() == totalItemCount_ - 1) {
240             return itemPosition_.rbegin()->second.endPos;
241         }
242         return itemPosition_.rbegin()->second.endPos + spaceWidth_;
243     }
244 
GetCacheStartPosition()245     float GetCacheStartPosition() const
246     {
247         if (cachedItemPosition_.empty()) {
248             return 0.0f;
249         }
250         if (GetCacheStartIndex() == 0) {
251             return cachedItemPosition_.begin()->second.startPos;
252         }
253         return cachedItemPosition_.begin()->second.startPos - spaceWidth_;
254     }
255 
GetCacheEndPosition()256     float GetCacheEndPosition() const
257     {
258         if (cachedItemPosition_.empty()) {
259             return 0.0f;
260         }
261         if (GetCacheEndIndex() == totalItemCount_ - 1) {
262             return cachedItemPosition_.rbegin()->second.endPos;
263         }
264         return cachedItemPosition_.rbegin()->second.endPos + spaceWidth_;
265     }
266 
GetTotalItemCount()267     int32_t GetTotalItemCount() const
268     {
269         return totalItemCount_;
270     }
271 
272     float GetChildMaxCrossSize(LayoutWrapper* layoutWrapper, Axis axis);
273 
274     void CheckRecycle(const RefPtr<LayoutWrapper>& layoutWrapper, float startPos, float endPos, float referencePos,
275         bool forwardLayout);
276 
SetNeedAllLayout()277     void SetNeedAllLayout()
278     {
279         needAllLayout_ = true;
280     }
281 
282     void CheckNeedAllLayout(const RefPtr<LayoutWrapper>& layoutWrapper, bool forwardLayout);
283 
SetScrollAlign(ScrollAlign align)284     void SetScrollAlign(ScrollAlign align)
285     {
286         scrollAlign_ = align;
287     }
288 
289     std::pair<float, float> GetItemGroupPosition(int32_t index);
290 
GetHeaderMainSize()291     float GetHeaderMainSize() const
292     {
293         return headerMainSize_;
294     }
295 
GetFooterMainSize()296     float GetFooterMainSize() const
297     {
298         return footerMainSize_;
299     }
300 
301     float GetItemHeight(int32_t index);
302 
GetItemStartIndex()303     int32_t GetItemStartIndex()
304     {
305         return itemStartIndex_;
306     }
307 
SetLayoutedItemInfo(const std::optional<LayoutedItemInfo> & itemInfo)308     void SetLayoutedItemInfo(const std::optional<LayoutedItemInfo>& itemInfo)
309     {
310         layoutedItemInfo_ = itemInfo;
311     }
312 
GetLayoutedItemInfo()313     std::optional<LayoutedItemInfo> GetLayoutedItemInfo() const
314     {
315         return layoutedItemInfo_;
316     }
317 
SetListChildrenMainSize(const RefPtr<ListChildrenMainSize> & childrenMainSize)318     void SetListChildrenMainSize(const RefPtr<ListChildrenMainSize>& childrenMainSize)
319     {
320         childrenSize_ = childrenMainSize;
321     }
322 
SetListPositionMap(const RefPtr<ListPositionMap> & posMap)323     void SetListPositionMap(const RefPtr<ListPositionMap>& posMap)
324     {
325         posMap_ = posMap;
326     }
327 
328     void AdjustByPosMap();
329 
330     static void SyncGeometry(RefPtr<LayoutWrapper>& wrapper);
331 
GetStartHeaderPos()332     float GetStartHeaderPos() const
333     {
334         return startHeaderPos_;
335     }
336 
GetEndFooterPos()337     float GetEndFooterPos() const
338     {
339         return endFooterPos_;
340     }
341 
SetCacheParam(std::optional<ListItemGroupCacheParam> param)342     void SetCacheParam(std::optional<ListItemGroupCacheParam> param)
343     {
344         cacheParam_ = param;
345     }
346 
GetCacheParam()347     std::optional<ListItemGroupCacheParam> GetCacheParam() const
348     {
349         return cacheParam_;
350     }
351 
SetNeedMeasureFormLastItem(bool needMeasureFormLastItem)352     void SetNeedMeasureFormLastItem(bool needMeasureFormLastItem)
353     {
354         isNeedMeasureFormLastItem_ = needMeasureFormLastItem;
355     }
356 
357     ListItemGroupLayoutInfo GetLayoutInfo() const;
358 
GetAdjustReferenceDelta()359     float GetAdjustReferenceDelta() const
360     {
361         return adjustReferenceDelta_;
362     }
363 
GetAdjustTotalSize()364     float GetAdjustTotalSize() const
365     {
366         return adjustTotalSize_;
367     }
368 
SetCachedIndex(int32_t forwardIndex,int32_t backwardIndex)369     void SetCachedIndex(int32_t forwardIndex, int32_t backwardIndex)
370     {
371         forwardCachedIndex_ = forwardIndex;
372         backwardCachedIndex_ = backwardIndex;
373     }
374 
GetCachedIndex()375     std::pair<int32_t, int32_t> GetCachedIndex() const
376     {
377         return { forwardCachedIndex_, backwardCachedIndex_ };
378     }
379 
GetListItemCount()380     int32_t GetListItemCount() const
381     {
382         return static_cast<int32_t>(itemPosition_.size());
383     }
384 
385 private:
386     float CalculateLaneCrossOffset(float crossSize, float childCrossSize);
387     void UpdateListItemConstraint(const OptionalSizeF& selfIdealSize, LayoutConstraintF& contentConstraint);
388     void LayoutListItem(LayoutWrapper* layoutWrapper, const OffsetF& paddingOffset, float crossSize);
389     void LayoutListItemAll(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, float startPos);
390     void LayoutHeaderFooterRTL(LayoutWrapper* layoutWrapper, const OffsetF& paddingOffset, float crossSize);
391     void LayoutHeaderFooterLTR(LayoutWrapper* layoutWrapper, const OffsetF& paddingOffset, float crossSize);
392     void UpdateZIndex(const RefPtr<LayoutWrapper>& layoutWrapper);
393     void LayoutIndex(const RefPtr<LayoutWrapper>& wrapper, const OffsetF& paddingOffset,
394         float crossSize, float startPos);
GetListItem(LayoutWrapper * layoutWrapper,int32_t index)395     inline RefPtr<LayoutWrapper> GetListItem(LayoutWrapper* layoutWrapper, int32_t index) const
396     {
397         return layoutWrapper->GetOrCreateChildByIndex(index + itemStartIndex_);
398     }
399     void CalculateLanes(const RefPtr<ListLayoutProperty>& layoutProperty,
400         const LayoutConstraintF& layoutConstraint, std::optional<float> crossSizeOptional, Axis axis);
401 
402     void MeasureListItem(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint);
403     int32_t MeasureALineForward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
404         int32_t& currentIndex, float startPos, float& endPos);
405     int32_t MeasureALineBackward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
406         int32_t& currentIndex, float endPos, float& startPos);
407     int32_t MeasureALineCenter(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
408         int32_t currentIndex);
409     int32_t MeasureALineAuto(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
410         int32_t currentIndex);
411     void CheckJumpForwardForBigOffset(int32_t& startIndex, float& startPos);
412     void CheckJumpBackwardForBigOffset(int32_t& endIndex, float& endPos);
413     void MeasureForward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
414         int32_t startIndex, float startPos);
415     void MeasureBackward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint,
416         int32_t endIndex, float endPos);
417     void MeasureJumpToItemForward(LayoutWrapper* layoutWrapper,
418         const LayoutConstraintF& layoutConstraint, int32_t startIndex, float startPos);
419     void MeasureJumpToItemBackward(LayoutWrapper* layoutWrapper,
420         const LayoutConstraintF& layoutConstraint, int32_t endIndex, float endPos);
421     void MeasureCenter(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, int32_t startIndex);
422     void MeasureStart(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, int32_t startIndex);
423     void MeasureEnd(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, int32_t startIndex);
424     void MeasureAuto(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, int32_t startIndex);
425     void MeasureHeaderFooter(LayoutWrapper* layoutWrapper);
426     void SetActiveChildRange(LayoutWrapper* layoutWrapper, int32_t cacheCount, bool show);
427     float UpdateReferencePos(RefPtr<LayoutProperty> layoutProperty, bool forwardLayout, float referencePos);
428     bool NeedMeasureItem(LayoutWrapper* layoutWrapper);
429     static void SetListItemIndex(const LayoutWrapper* groupLayoutWrapper,
430         const RefPtr<LayoutWrapper>& itemLayoutWrapper, int32_t indexInGroup);
431     bool IsCardStyleForListItemGroup(const LayoutWrapper* groupLayoutWrapper);
432     float GetListItemGroupMaxWidth(const OptionalSizeF& parentIdealSize, RefPtr<LayoutProperty> layoutProperty);
433     void AdjustItemPosition();
434     bool CheckNeedMeasure(const RefPtr<LayoutWrapper>& layoutWrapper) const;
435     void MeasureCacheItem(LayoutWrapper* layoutWrapper);
436     void MeasureCacheForward(LayoutWrapper* layoutWrapper, ListItemGroupCacheParam& param);
437     void MeasureCacheBackward(LayoutWrapper* layoutWrapper, ListItemGroupCacheParam& param);
438     void LayoutCacheItem(LayoutWrapper* layoutWrapper, const OffsetF& paddingOffset, float crossSize, bool show);
439     void CheckUpdateGroupAndItemPos(LayoutWrapper* layoutWrapper, const OffsetF& paddingOffset, float crossSize);
440     void UpdateCachedItemPosition(int32_t cacheCount);
441     void UpdateLayoutedItemInfo();
442 
443     bool isCardStyle_ = false;
444     int32_t headerIndex_;
445     int32_t footerIndex_;
446     int32_t itemStartIndex_;
447     RefPtr<ListLayoutProperty> listLayoutProperty_;
448     float paddingBeforeContent_ = 0.0f;
449     float paddingAfterContent_ = 0.0f;
450 
451     PositionMap itemPosition_;
452     RefPtr<ListChildrenMainSize> childrenSize_;
453     RefPtr<ListPositionMap> posMap_;
454     Axis axis_ = Axis::VERTICAL;
455     int32_t lanes_ = 1;
456     float laneGutter_ = 0.0f;
457     std::optional<float> minLaneLength_;
458     std::optional<float> maxLaneLength_;
459     V2::ListItemAlign itemAlign_ = V2::ListItemAlign::START;
460     float spaceWidth_ = 0.0f;
461 
462     std::optional<int32_t> jumpIndex_;
463     std::optional<int32_t> targetIndex_;
464     ScrollAlign scrollAlign_ = ScrollAlign::NONE;
465     int32_t totalItemCount_ = 0;
466     int32_t forwardCachedIndex_ = -1;
467     int32_t backwardCachedIndex_ = INT_MAX;
468     float totalMainSize_ = 0.0f;
469     float headerMainSize_ = 0.0f;
470     float footerMainSize_ = 0.0f;
471     float startPos_ = 0.0f;
472     float startHeaderPos_ = 0.0f;
473     float endFooterPos_ = 0.0f;
474     float prevStartPos_ = 0.0f;
475     float prevEndPos_ = 0.0f;
476     float endPos_ = 0.0f;
477     float referencePos_ = 0.0f;
478     float adjustReferenceDelta_ = 0.0f;
479     float adjustTotalSize_ = 0.0f;
480     float refPos_ = 0.0f;
481     float prevContentMainSize_ = 0.0f;
482     float contentStartOffset_ = 0.0f;
483     float contentEndOffset_ = 0.0f;
484     bool forwardLayout_ = true;
485     bool needAllLayout_ = false;
486     bool needAdjustRefPos_ = false;
487     bool isNeedCheckOffset_ = false;
488     bool isNeedMeasureFormLastItem_ = false;
489 
490     std::optional<LayoutedItemInfo> layoutedItemInfo_;
491     LayoutConstraintF childLayoutConstraint_;
492     TextDirection layoutDirection_ = TextDirection::LTR;
493 
494     std::optional<ListItemGroupCacheParam> cacheParam_;
495     PositionMap cachedItemPosition_;
496 };
497 } // namespace OHOS::Ace::NG
498 
499 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_LIST_LIST_LAYOUT_ALGORITHM_H
500