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_SEGMENTED_LAYOUT_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_WATERFLOW_WATER_FLOW_SEGMENTED_LAYOUT_H
18 
19 #include "core/components_ng/pattern/waterflow/layout/top_down/water_flow_layout_info.h"
20 #include "core/components_ng/pattern/waterflow/layout/water_flow_layout_algorithm_base.h"
21 #include "core/components_ng/pattern/waterflow/water_flow_layout_property.h"
22 
23 namespace OHOS::Ace::NG {
24 // inherited by SegmentedLayout and SWLayout
25 class WaterFlowSegmentLayoutBase : public WaterFlowLayoutBase {
26     DECLARE_ACE_TYPE(WaterFlowSegmentLayoutBase, WaterFlowLayoutBase);
27 
28 protected:
29     /**
30      * @brief init member variables for segmented WaterFlow with section info.
31      *
32      * @param options vector of SectionInfo
33      * @param margins of each section.
34      * @param frameSize of WaterFlow.
35      */
36     void SegmentedInit(const std::vector<WaterFlowSections::Section>& options,
37         const std::vector<PaddingPropertyF>& margins, const SizeF& frameSize);
38 
39     /**
40      * @brief Check if Sections info align with actual children and if internal data structures are consistent.
41      */
42     static bool IsSectionValid(const RefPtr<WaterFlowLayoutInfoBase>& info, int32_t childrenCnt);
43 
44     LayoutWrapper* wrapper_ {};
45     Axis axis_ = Axis::VERTICAL;
46     // [segmentIdx, [crossIdx, item's width]]
47     std::vector<std::vector<float>> itemsCrossSize_;
48 
49     // rowGap and columnGap for each segment
50     std::vector<float> crossGaps_;
51     std::vector<float> mainGaps_;
52 };
53 
54 class WaterFlowSegmentedLayout : public WaterFlowSegmentLayoutBase {
55     DECLARE_ACE_TYPE(WaterFlowSegmentedLayout, WaterFlowSegmentLayoutBase);
56 
57 public:
WaterFlowSegmentedLayout(const RefPtr<WaterFlowLayoutInfo> & layoutInfo)58     explicit WaterFlowSegmentedLayout(const RefPtr<WaterFlowLayoutInfo>& layoutInfo) : info_(layoutInfo) {}
59     ~WaterFlowSegmentedLayout() override = default;
60 
61     void Measure(LayoutWrapper* layoutWrapper) override;
62 
63     void Layout(LayoutWrapper* layoutWrapper) override;
64 
SetCanOverScroll(bool value)65     void SetCanOverScroll(bool value) override
66     {
67         overScroll_ = value;
68     }
69 
70     bool PreloadItem(LayoutWrapper* host, int32_t itemIdx, int64_t deadline) override;
71 
72 private:
73     /**
74      * @brief Initialize member variables from LayoutProperty.
75      *
76      * @param frameSize of WaterFlow component.
77      */
78     void Init(const SizeF& frameSize);
79 
80     /**
81      * @brief check if any items in view have changed height.
82      *
83      * @return index of the first dirty item. -1 if no dirty item found.
84      */
85     int32_t CheckDirtyItem() const;
86 
87     /**
88      * @brief init regular WaterFlow with a single segment.
89      *
90      * @param frameSize
91      */
92     void RegularInit(const SizeF& frameSize);
93     void InitFooter(float crossSize);
94 
95     /**
96      * @brief Measure self after measuring children. Only when pre-measure failed.
97      *
98      * @param size ideal content size from parent.
99      */
100     void PostMeasureSelf(SizeF size);
101 
102     void MeasureOnOffset();
103 
104     /**
105      * @brief Fills the viewport with new items.
106      *
107      * WaterFlow's item map only supports orderly forward layout,
108      * because the position of a new item always depends on previous items.
109      *
110      * @param startIdx index of the first new FlowItem.
111      */
112     void Fill(int32_t startIdx);
113 
114     /**
115      * @brief Obtain sizes of new FlowItems up to [targetIdx] and record them in ItemMap.
116      *
117      * If user has defined a size for any FlowItem, use that size instead of calling child->Measure.
118      *
119      * @param targetIdx index of the last FlowItem to measure.
120      * @param cacheDeadline when called during a cache layout, return early if deadline is reached.
121      * @param force explicitly measure items even if their heights are user-defined.
122      */
123     void MeasureToTarget(int32_t targetIdx, std::optional<int64_t> cacheDeadline, bool force = false);
124 
125     /**
126      * @brief Helper to measure a single FlowItems.
127      *
128      * @param props LayoutProps.
129      * @param idx index of the FlowItem.
130      * @param crossIdx column (when vertical) index of the target FlowItem.
131      * @param userDefMainSize user-defined main-axis size of the FlowItem.
132      * @return LayoutWrapper of the FlowItem.
133      */
134     RefPtr<LayoutWrapper> MeasureItem(const RefPtr<WaterFlowLayoutProperty>& props, int32_t idx, int32_t crossIdx,
135         float userDefMainSize, bool isCache) const;
136 
137     /**
138      * @brief Layout a FlowItem at [idx].
139      *
140      * @param idx FlowItem index.
141      * @param padding top-left padding of WaterFlow component.
142      * @param isReverse need to layout in reverse.
143      */
144     void LayoutItem(int32_t idx, float crossPos, const OffsetF& padding, bool isReverse);
145 
146     void MeasureOnJump(int32_t jumpIdx);
147 
148     /**
149      * @brief Parse AUTO align value. If jump item is above viewport, use START; if it's below viewport, use END.
150      *
151      * @param item ItemInfo of the FlowItem to jump to.
152      * @return transformed ScrollAlign value.
153      */
154     ScrollAlign TransformAutoScroll(const WaterFlowLayoutInfo::ItemInfo& item) const;
155 
156     /**
157      * @brief Calculate the new offset after jumping to the target item.
158      *
159      * @param item  ItemInfo of the FlowItem to jump to.
160      * @return new offset after jumping.
161      */
162     float SolveJumpOffset(const WaterFlowLayoutInfo::ItemInfo& item) const;
163 
164     void SyncPreloadItem(LayoutWrapper* host, int32_t itemIdx) override;
165 
166     RefPtr<WaterFlowSections> sections_;
167 
168     // WaterFlow node's main-axis length
169     float mainSize_ = 0.0f;
170 
171     // offset to apply after a ResetAndJump
172     std::optional<float> postJumpOffset_;
173 
174     RefPtr<WaterFlowLayoutInfo> info_;
175 
176     // true if WaterFlow can be overScrolled
177     bool overScroll_ = false;
178 
179     ACE_DISALLOW_COPY_AND_MOVE(WaterFlowSegmentedLayout);
180 };
181 } // namespace OHOS::Ace::NG
182 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_WATERFLOW_WATER_FLOW_SEGMENTED_LAYOUT_H
183