1 /*
2  * Copyright (c) 2022 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_SWIPER_SWIPER_LAYOUT_ALGORITHM_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_SWIPER_SWIPER_LAYOUT_ALGORITHM_H
18 
19 #include <cstdint>
20 #include <optional>
21 
22 #include "base/geometry/axis.h"
23 #include "base/geometry/ng/offset_t.h"
24 #include "base/memory/referenced.h"
25 #include "core/components_ng/layout/layout_algorithm.h"
26 #include "core/components_ng/layout/layout_wrapper.h"
27 #include "core/components_ng/pattern/swiper/swiper_layout_property.h"
28 
29 namespace OHOS::Ace::NG {
30 
31 struct SwiperItemInfo {
32     float startPos = 0.0f;
33     float endPos = 0.0f;
34     RefPtr<FrameNode> node;
35     OffsetF finalOffset;
36     CancelableCallback<void()> task;
37     bool isFinishAnimation = false;
38 };
39 
40 class ACE_EXPORT SwiperLayoutAlgorithm : public LayoutAlgorithm {
41     DECLARE_ACE_TYPE(SwiperLayoutAlgorithm, LayoutAlgorithm);
42 
43 public:
44     using PositionMap = std::map<int32_t, SwiperItemInfo>;
45 
46     SwiperLayoutAlgorithm() = default;
~SwiperLayoutAlgorithm()47     ~SwiperLayoutAlgorithm() override
48     {
49         std::lock_guard<std::mutex> lock(swiperMutex_);
50     }
51 
OnReset()52     void OnReset() override {}
53     void Measure(LayoutWrapper* layoutWrapper) override;
54     void Layout(LayoutWrapper* layoutWrapper) override;
55 
56     void LayoutForward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, Axis axis,
57         int32_t startIndex, float startPos);
58     void LayoutBackward(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, Axis axis,
59         int32_t endIndex, float endPos);
60     bool LayoutForwardItem(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, Axis axis,
61         int32_t& currentIndex, float startPos, float& endPos);
62     bool LayoutBackwardItem(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, Axis axis,
63         int32_t& currentIndex, float endPos, float& startPos);
64     float GetChildMaxSize(LayoutWrapper* layoutWrapper, Axis axis, bool isMainAxis) const;
65     int32_t GetLoopIndex(int32_t originalIndex) const;
66 
SetItemsPosition(const PositionMap & itemPosition)67     void SetItemsPosition(const PositionMap& itemPosition)
68     {
69         itemPosition_ = itemPosition;
70     }
71 
GetItemPosition()72     PositionMap&& GetItemPosition()
73     {
74         return std::move(itemPosition_);
75     }
76 
SetJumpIndex(int32_t index)77     void SetJumpIndex(int32_t index)
78     {
79         jumpIndex_ = index;
80     }
81 
SetCurrentDelta(float offset)82     void SetCurrentDelta(float offset)
83     {
84         currentDelta_ = offset;
85         currentOffset_ = offset;
86     }
87 
SetOverScrollFeature()88     void SetOverScrollFeature()
89     {
90         overScrollFeature_ = true;
91     }
92 
SetCanOverScroll(bool canOverScroll)93     void SetCanOverScroll(bool canOverScroll)
94     {
95         canOverScroll_ = canOverScroll;
96     }
97 
SetTotalItemCount(int32_t totalItemCount)98     void SetTotalItemCount(int32_t totalItemCount)
99     {
100         totalItemCount_ = totalItemCount;
101     }
102 
GetContentMainSize()103     float GetContentMainSize() const
104     {
105         return contentMainSize_;
106     }
107 
SetContentMainSize(float contentMainSize)108     void SetContentMainSize(float contentMainSize)
109     {
110         contentMainSize_ = contentMainSize;
111         oldContentMainSize_ = contentMainSize;
112     }
113 
GetContentCrossSize()114     float GetContentCrossSize() const
115     {
116         return contentCrossSize_;
117     }
118 
SetContentCrossSize(float contentCrossSize)119     void SetContentCrossSize(float contentCrossSize)
120     {
121         contentCrossSize_ = contentCrossSize;
122     }
123 
SetCurrentOffset(float offset)124     void SetCurrentOffset(float offset)
125     {
126         currentOffset_ = offset;
127     }
128 
GetCurrentOffset()129     float GetCurrentOffset() const
130     {
131         return currentOffset_;
132     }
133 
SetTargetIndex(std::optional<int32_t> targetIndex)134     void SetTargetIndex(std::optional<int32_t> targetIndex)
135     {
136         targetIndex_ = targetIndex;
137     }
138 
SetIsLoop(bool isLoop)139     void SetIsLoop(bool isLoop)
140     {
141         isLoop_ = isLoop;
142     }
143 
GetStartIndex()144     int32_t GetStartIndex() const
145     {
146         return itemPosition_.empty() ? 0 : itemPosition_.begin()->first;
147     }
148 
GetEndIndex()149     int32_t GetEndIndex() const
150     {
151         return itemPosition_.empty() ? 0 : itemPosition_.rbegin()->first;
152     }
153 
GetStartPosition()154     float GetStartPosition() const
155     {
156         if (itemPosition_.empty()) {
157             return 0.0f;
158         }
159         if (GetStartIndex() == 0 && !isLoop_) {
160             return itemPosition_.begin()->second.startPos;
161         }
162         return itemPosition_.begin()->second.startPos - spaceWidth_;
163     }
164 
GetEndPosition()165     float GetEndPosition() const
166     {
167         if (itemPosition_.empty()) {
168             return 0.0f;
169         }
170         if (GetEndIndex() == totalItemCount_ - 1 && !isLoop_) {
171             return itemPosition_.rbegin()->second.endPos;
172         }
173         return itemPosition_.rbegin()->second.endPos + spaceWidth_;
174     }
175 
SetMainSizeIsMeasured(bool mainSizeIsMeasured)176     void SetMainSizeIsMeasured(bool mainSizeIsMeasured)
177     {
178         mainSizeIsMeasured_ = mainSizeIsMeasured;
179     }
180 
GetMainSizeIsMeasured()181     bool GetMainSizeIsMeasured() const
182     {
183         return mainSizeIsMeasured_;
184     }
185 
SetCurrentIndex(int32_t currentIndex)186     void SetCurrentIndex(int32_t currentIndex)
187     {
188         currentIndex_ = currentIndex;
189     }
190 
GetCurrentIndex()191     int32_t GetCurrentIndex() const
192     {
193         return currentIndex_;
194     }
195 
IsCrossMatchChild()196     bool IsCrossMatchChild() const
197     {
198         return crossMatchChild_;
199     }
200 
SetUseCustomAnimation(bool useCustomAnimation)201     void SetUseCustomAnimation(bool useCustomAnimation)
202     {
203         useCustomAnimation_ = useCustomAnimation;
204     }
205 
SetCustomAnimationToIndex(std::optional<int32_t> customAnimationToIndex)206     void SetCustomAnimationToIndex(std::optional<int32_t> customAnimationToIndex)
207     {
208         customAnimationToIndex_ = customAnimationToIndex;
209     }
210 
SetRemoveFromRSTreeIndex(std::optional<int32_t> removeFromRSTreeIndex)211     void SetRemoveFromRSTreeIndex(std::optional<int32_t> removeFromRSTreeIndex)
212     {
213         removeFromRSTreeIndex_ = removeFromRSTreeIndex;
214     }
215 
SetIndexsInAnimation(const std::set<int32_t> & indexsInAnimation)216     void SetIndexsInAnimation(const std::set<int32_t>& indexsInAnimation)
217     {
218         indexsInAnimation_ = indexsInAnimation;
219     }
220 
SetNeedUnmountIndexs(const std::set<int32_t> & needUnmountIndexs)221     void SetNeedUnmountIndexs(const std::set<int32_t>& needUnmountIndexs)
222     {
223         needUnmountIndexs_ = needUnmountIndexs;
224     }
225 
GetNeedUnmountIndexs()226     std::set<int32_t> GetNeedUnmountIndexs() const
227     {
228         return needUnmountIndexs_;
229     }
230 
SetSwipeByGroup(bool swipeByGroup)231     void SetSwipeByGroup(bool swipeByGroup)
232     {
233         swipeByGroup_ = swipeByGroup;
234     }
235 
SetRealTotalCount(int32_t realTotalCount)236     void SetRealTotalCount(int32_t realTotalCount)
237     {
238         realTotalCount_ = realTotalCount;
239     }
240 
SetPlaceItemWidth(std::optional<float> placeItemWidth)241     void SetPlaceItemWidth(std::optional<float> placeItemWidth)
242     {
243         placeItemWidth_ = placeItemWidth;
244     }
245 
SetHasCachedCapture(bool hasCachedCapture)246     void SetHasCachedCapture(bool hasCachedCapture)
247     {
248         hasCachedCapture_ = hasCachedCapture;
249     }
250 
SetIsCaptureReverse(bool isCaptureReverse)251     void SetIsCaptureReverse(bool isCaptureReverse)
252     {
253         isCaptureReverse_ = isCaptureReverse;
254     }
255 
GetIsCaptureReverse()256     bool GetIsCaptureReverse() const
257     {
258         return isCaptureReverse_;
259     }
260 
GetIsNeedUpdateCapture()261     bool GetIsNeedUpdateCapture() const
262     {
263         return isNeedUpdateCapture_;
264     }
265 
SetItemsPositionInAnimation(const PositionMap & itemPositionInAnimation)266     void SetItemsPositionInAnimation(const PositionMap& itemPositionInAnimation)
267     {
268         itemPositionInAnimation_ = itemPositionInAnimation;
269     }
270 
GetItemsPositionInAnimation()271     PositionMap&& GetItemsPositionInAnimation()
272     {
273         return std::move(itemPositionInAnimation_);
274     }
275 
SetIsMeasureOneMoreItem(bool isMeasureOneMoreItem)276     void SetIsMeasureOneMoreItem(bool isMeasureOneMoreItem)
277     {
278         isMeasureOneMoreItem_ = isMeasureOneMoreItem;
279     }
280 
SetIsFrameAnimation(bool isFrameAnimation)281     void SetIsFrameAnimation(bool isFrameAnimation)
282     {
283         isFrameAnimation_ = isFrameAnimation;
284     }
285 
GetTargetStartPos()286     float GetTargetStartPos() const
287     {
288         return targetStartPos_;
289     }
290 
SetCachedCount(int32_t cachedCount)291     void SetCachedCount(int32_t cachedCount)
292     {
293         cachedCount_ = cachedCount > realTotalCount_ ? realTotalCount_ : cachedCount;
294     }
295 
GetCachedItems()296     const std::set<int32_t>& GetCachedItems() const
297     {
298         return cachedItems_;
299     }
300 
GetLayoutConstraint()301     const LayoutConstraintF& GetLayoutConstraint() const
302     {
303         return childLayoutConstraint_;
304     }
305 
GetIgnoreBlankOffset()306     float GetIgnoreBlankOffset() const
307     {
308         return ignoreBlankOffset_;
309     }
310 
SetIgnoreBlankOffset(float ignoreBlankOffset)311     void SetIgnoreBlankOffset(float ignoreBlankOffset)
312     {
313         ignoreBlankOffset_ = ignoreBlankOffset;
314     }
315 
SetDuringInteraction(bool duringInteraction)316     void SetDuringInteraction(bool duringInteraction)
317     {
318         duringInteraction_ = duringInteraction;
319     }
320 
321 private:
322     void LayoutSwiperIndicator(
323         LayoutWrapper* layoutWrapper, const RefPtr<SwiperLayoutProperty>& swiperLayoutProperty,
324         const PaddingPropertyF& padding);
325     void MeasureSwiper(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint, Axis axis);
326     void MeasureTabsCustomAnimation(LayoutWrapper* layoutWrapper);
327     void MeasureSwiperCustomAnimation(LayoutWrapper* layoutWrapper, const LayoutConstraintF& layoutConstraint);
328     void LayoutCustomAnimation(LayoutWrapper* layoutWrapper) const;
329     void LayoutItem(LayoutWrapper* layoutWrapper, Axis axis, OffsetF offset, std::pair<int32_t, SwiperItemInfo> pos);
330     void SetInactive(
331         LayoutWrapper* layoutWrapper, float startMainPos, float endMainPos, std::optional<int32_t> targetIndex);
332 
333     void PlaceDigitChild(const RefPtr<LayoutWrapper>& indicatorWrapper, const RefPtr<LayoutProperty>& layoutProperty);
334     RefPtr<LayoutWrapper> GetNodeLayoutWrapperByTag(LayoutWrapper* layoutWrapper, const std::string& tagName) const;
335     void MeasureArrow(const RefPtr<LayoutWrapper>& arrowWrapper, const RefPtr<LayoutProperty>& layoutProperty) const;
336     void ArrowLayout(
337         LayoutWrapper* layoutWrapper, const RefPtr<LayoutWrapper>& arrowWrapper, const PaddingPropertyF padding) const;
338     void ResetOffscreenItemPosition(LayoutWrapper* layoutWrapper, int32_t index, bool isForward, Axis axis) const;
339     int32_t GetDisplayCount(LayoutWrapper* layoutWrapper) const;
340     void SetInactiveOnForward(LayoutWrapper* layoutWrapper, Axis axis);
341     void SetInactiveOnBackward(LayoutWrapper* layoutWrapper, Axis axis);
342     void AdjustStartInfoOnSwipeByGroup(
343         int32_t startIndex, const PositionMap& itemPosition, int32_t& startIndexInVisibleWindow, float& startPos);
344     bool HasCustomIndicatorOffset(const RefPtr<LayoutWrapper>& indicatorWrapper);
345     const OffsetF CalculateCustomOffset(
346         const RefPtr<LayoutWrapper>& indicatorWrapper, const OffsetF& currentOffset);
347     void CaptureMeasure(LayoutWrapper* layoutWrapper, LayoutConstraintF& childLayoutConstraint);
348     void CaptureLayout(LayoutWrapper* layoutWrapper);
349     bool IsNormalItem(const RefPtr<LayoutWrapper>& wrapper) const;
350     bool CheckIsSingleCase(const RefPtr<SwiperLayoutProperty>& property);
351     void UpdateLayoutInfoBeforeMeasureSwiper(const RefPtr<SwiperLayoutProperty>& property);
352     void IndicatorAndArrowMeasure(LayoutWrapper* layoutWrapper, const OptionalSizeF& parentIdealSize);
353     float GetChildMainAxisSize(
354         const RefPtr<LayoutWrapper>& childWrapper, const RefPtr<SwiperLayoutProperty>& swiperProperty, Axis axis);
355 
356     void CheckCachedItem(int32_t startIndex, int32_t endIndex, LayoutWrapper* layoutWrapper);
357 
358     bool isLoop_ = true;
359     float prevMargin_ = 0.0f;
360     float nextMargin_ = 0.0f;
361 
362     PositionMap itemPosition_;
363     PositionMap prevItemPosition_;
364     PositionMap itemPositionInAnimation_;
365     float currentOffset_ = 0.0f;
366     float currentDelta_ = 0.0f;
367     float startMainPos_ = 0.0f;
368     float endMainPos_ = 0.0f;
369 
370     float paddingBeforeContent_ = 0.0f;
371     float paddingAfterContent_ = 0.0f;
372     float contentMainSize_ = 0.0f;
373     float oldContentMainSize_ = 0.0f;
374     float contentCrossSize_ = 0.0f;
375     int32_t totalItemCount_ = 0;
376     bool mainSizeIsDefined_ = false;
377 
378     float spaceWidth_ = 0.0f;
379     bool overScrollFeature_ = false;
380     bool canOverScroll_ = false;
381 
382     bool mainSizeIsMeasured_ = false;
383     bool crossMatchChild_ = false;
384     bool measured_ = false; // to distinguish first and second measure in flex layout
385     bool duringInteraction_ = false; // user interacting, include touching and translating animation.
386 
387     std::optional<int32_t> jumpIndex_;
388     std::optional<int32_t> targetIndex_;
389     std::optional<int32_t> currentJumpIndex_;
390     std::optional<int32_t> currentTargetIndex_;
391     std::optional<int32_t> customAnimationToIndex_;
392     std::optional<int32_t> removeFromRSTreeIndex_;
393     int32_t currentIndex_ = 0;
394     bool targetIsSameWithStartFlag_ = false;
395     bool useCustomAnimation_ = false;
396     std::set<int32_t> indexsInAnimation_;
397     std::set<int32_t> needUnmountIndexs_;
398     bool swipeByGroup_ = false;
399     int32_t realTotalCount_ = 0;
400     std::optional<float> placeItemWidth_;
401     bool useCustomIndicatorOffset = false;
402     bool hasCachedCapture_ = false;
403     bool isCaptureReverse_ = false;
404     bool isNeedUpdateCapture_ = false;
405     bool isMeasureOneMoreItem_ = false;
406     bool isFrameAnimation_ = false;
407     float ignoreBlankOffset_ = 0.0f;
408     float currentIgnoreBlankOffset_ = 0.0f;
409     std::set<int32_t> measuredItems_;
410     std::set<int32_t> activeItems_;
411     std::set<int32_t> cachedItems_;
412     // only be used in AutoLinear mode
413     float targetStartPos_ = 0.0f;
414     int32_t cachedCount_ = 0;
415     LayoutConstraintF childLayoutConstraint_;
416 
417     std::mutex swiperMutex_;
418 };
419 
420 } // namespace OHOS::Ace::NG
421 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_SWIPER_SWIPER_LAYOUT_ALGORITHM_H
422