1 /*
2  * Copyright (c) 2021 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_LIST_LAYOUT_MANAGER_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_LIST_LAYOUT_MANAGER_H
18 
19 #include <map>
20 
21 #include "base/geometry/dimension.h"
22 #include "base/geometry/offset.h"
23 #include "base/memory/ace_type.h"
24 #include "base/utils/system_properties.h"
25 #include "core/event/touch_event.h"
26 #include "core/pipeline/base/component.h"
27 #include "core/pipeline/base/render_node.h"
28 
29 namespace OHOS::Ace {
30 
31 const double DEFAULT_SCALE = 1.0;
32 const double TV_ITEM_SCALE = 1.05;
33 const double HALF_ITEM_SIZE = 0.5;
34 const int32_t LIST_PARAM_INVAID = -2;
35 const int32_t LIST_LENGTH_INFINITE = -1;
36 const double INFINITE_POSITION = 0.0;
37 
38 // first bool mean if vertical, second bool mean if reverse
39 // false, false --> RIGHT
40 // false, true --> LEFT
41 // true, false --> DOWN
42 // true, true ---> UP
43 // This map will adapter the Grid FlexDirection with Key Direction.
44 extern const std::map<bool, std::map<FlexDirection, std::map<bool, std::map<bool, KeyDirection>>>> DIRECTION_MAP;
45 
46 class LayoutManager : public virtual AceType {
47     DECLARE_ACE_TYPE(LayoutManager, AceType);
48 
49 public:
50     LayoutManager() = default;
51     ~LayoutManager() override = default;
52 
53     virtual void Update() = 0;
54 
55     virtual void PerformLayout() = 0;
56 
57     virtual void RefreshLayout() = 0;
58 
59     virtual void CalculateCachedRange(int32_t viewBegin, int32_t viewEnd, int32_t cachedCount, int32_t& cachedBegin,
60         int32_t& cachedEnd) = 0;
61 
62     virtual void RequestMoreItemsIfNeeded(int32_t viewBegin, int32_t viewEnd) = 0;
63 
64     virtual int32_t focusMove(KeyDirection key) = 0;
65 
CalculateFocusIndexPosition()66     virtual void CalculateFocusIndexPosition() {}
67 
MoveItemToViewPort(double position)68     virtual void MoveItemToViewPort(double position) {}
69 
MoveItemGroupToViewPort(double position,double size)70     virtual void MoveItemGroupToViewPort(double position, double size) {}
71 
LayoutToItem(int32_t toIndex)72     virtual void LayoutToItem(int32_t toIndex) {}
73 
LayoutToPosition(double position)74     virtual void LayoutToPosition(double position) {}
75 
LayoutMore(double incDistance)76     virtual void LayoutMore(double incDistance) {}
77 
NotifyNeedRefresh()78     virtual void NotifyNeedRefresh() {}
79 
RequestNextFocus(bool vertical,bool reverse)80     int32_t RequestNextFocus(bool vertical, bool reverse)
81     {
82         KeyDirection key = DIRECTION_MAP.at(rightToLeft_).at(direction_).at(vertical).at(reverse);
83         int32_t index = focusMove(key);
84         if (index < 0) {
85             focusMove_ = focusIndex_;
86             return index;
87         }
88         focusMove_ = index;
89         focusIndex_ = index;
90         return focusMove_;
91     }
92 
ListItemFocused(int32_t focusIndex)93     void ListItemFocused(int32_t focusIndex)
94     {
95         focusIndex_ = focusIndex;
96         focusMove_ = focusIndex;
97     }
98 
MarkNeedRefresh()99     void MarkNeedRefresh()
100     {
101         needRefresh_ = true;
102         NotifyNeedRefresh();
103     }
104 
ResetLayoutRange(double head,double tail,Offset position,Size viewPort)105     void ResetLayoutRange(double head, double tail, Offset position, Size viewPort)
106     {
107         head_ = head;
108         tail_ = tail;
109         position_ = position;
110         viewPort_ = viewPort;
111     }
112 
GetPosition()113     const Offset& GetPosition() const
114     {
115         return position_;
116     }
117 
FlushChainAnimation()118     virtual double FlushChainAnimation()
119     {
120         return 0.0;
121     }
122 
IsRowReverse()123     bool IsRowReverse() const
124     {
125         return (rightToLeft_ && direction_ == FlexDirection::ROW)
126          || (!rightToLeft_ && direction_ == FlexDirection::ROW_REVERSE);
127     }
128 
IsColReverse()129     bool IsColReverse() const
130     {
131         return direction_ == FlexDirection::COLUMN_REVERSE;
132     }
133 
GetItemGrid(int32_t index)134     int32_t GetItemGrid(int32_t index) const
135     {
136         auto iter = itemGrid_.find(index);
137         if (iter == itemGrid_.end()) {
138             return 0;
139         }
140         return iter->second;
141     }
142 
CheckItemPosition(int32_t index)143     bool CheckItemPosition(int32_t index) const
144     {
145         return itemPosition_.find(index) != itemPosition_.end();
146     }
147 
GetItemAnimationValue(int32_t index)148     virtual double GetItemAnimationValue(int32_t index) const
149     {
150         return 0.0;
151     }
152 
GetItemPosition(int32_t index)153     double GetItemPosition(int32_t index) const
154     {
155         auto iter = itemPosition_.find(index);
156         if (iter == itemPosition_.end()) {
157             return 0.0;
158         }
159         return iter->second;
160     }
161 
GetChainInterval()162     double GetChainInterval() const
163     {
164         return enableChain_ ? chainInterval_ : 0.0;
165     }
166 
GetChainItemRange(int32_t index,double & start,double & end)167     void GetChainItemRange(int32_t index, double& start, double& end) const
168     {
169         if (!enableChain_) {
170             return;
171         }
172         start = GetItemPosition(index) - GetChainInterval() * HALF_ITEM_SIZE;
173         double nextStartPosition = GetItemPosition(index + 1);
174         if (!NearZero(nextStartPosition)) {
175             end = nextStartPosition - GetChainInterval() * HALF_ITEM_SIZE;
176         }
177     }
178 
GetIndexByPosition(double position)179     int32_t GetIndexByPosition(double position) const
180     {
181         int32_t index = 0;
182         double curPosition = 0.0;
183         for (const auto& item : itemPosition_) {
184             double correctedPosition =  item.second + GetItemAnimationValue(item.first);
185             if (NearEqual(correctedPosition, position)) {
186                 return item.first;
187             } else {
188                 if (NearEqual(curPosition, correctedPosition)) {
189                     continue;
190                 }
191                 curPosition = correctedPosition;
192                 if (correctedPosition < position) {
193                     index = item.first;
194                 } else {
195                     return index;
196                 }
197             }
198         }
199         return index;
200     }
201 
CalculateRepeatedIndex(int32_t cachedIndex)202     int32_t CalculateRepeatedIndex(int32_t cachedIndex)
203     {
204         int32_t repeatedIndex;
205         if (repeatedLength_ == LIST_LENGTH_INFINITE) {
206             repeatedIndex = ((cachedIndex - indexOffset_) > 0 ? (cachedIndex - indexOffset_) : 0);
207         } else {
208             if (cachedIndex < indexOffset_) {
209                 repeatedIndex = 0;
210             } else {
211                 if (cachedIndex > indexOffset_ + repeatedLength_) {
212                     repeatedIndex = repeatedLength_;
213                 } else {
214                     repeatedIndex = cachedIndex - indexOffset_;
215                 }
216             }
217         }
218         return repeatedIndex;
219     }
220 
GetExpandStatus(int32_t groupIndex)221     bool GetExpandStatus(int32_t groupIndex) const
222     {
223         auto iter = itemGroupsExpand_.find(groupIndex);
224         if (iter != itemGroupsExpand_.end()) {
225             return iter->second;
226         } else {
227             return expandAll_;
228         }
229     }
230 
GetItemGroupFocusIndex(int32_t groupIndex)231     int32_t GetItemGroupFocusIndex(int32_t groupIndex) const
232     {
233         auto iter = itemGroupsFocusIndex_.find(groupIndex);
234         if (iter != itemGroupsFocusIndex_.end()) {
235             return iter->second;
236         }
237         return 0;
238     }
239 
SetExpandAll(bool expandAll)240     void SetExpandAll(bool expandAll)
241     {
242         expandAll_ = expandAll;
243     }
244 
ClearItemGroupsExpand()245     void ClearItemGroupsExpand()
246     {
247         itemGroupsExpand_.clear();
248     }
249 
ClearItemPosition()250     void ClearItemPosition()
251     {
252         itemPosition_.clear();
253     }
254 
AddItemGroupExpand(int32_t index,bool expand)255     void AddItemGroupExpand(int32_t index, bool expand)
256     {
257         itemGroupsExpand_[index] = expand;
258     }
259 
AddItemGroupFocusIndex(int32_t index,int32_t groupFocusIndex)260     void AddItemGroupFocusIndex(int32_t index, int32_t groupFocusIndex)
261     {
262         itemGroupsFocusIndex_[index] = groupFocusIndex;
263     }
264 
GetFriction()265     double GetFriction() const
266     {
267         return friction_;
268     }
269 
SetFriction(double friction)270     void SetFriction(double friction)
271     {
272         friction_ = friction;
273     }
274 
GetSlipFactor()275     double GetSlipFactor() const
276     {
277         return slipFactor_;
278     }
279 
280 protected:
281     double head_ = 0.0;
282     double tail_ = 0.0;
283     double lastHead_ = 0.0;
284     double lastTail_ = 0.0;
285     int32_t focusMove_ = 0; // Record the focus move path.
286     int32_t focusIndex_ = 0; // Record the index of focus item.
287     Offset position_;
288     Size viewPort_;
289     bool needRefresh_ = false;
290     bool firstLayout_ = true;
291     Dimension itemExtent_;
292 
293     bool rightToLeft_ = false;
294     bool isVertical_ = false;
295     FlexDirection direction_ { FlexDirection::COLUMN };
296     FlexAlign crossAxisAlign_ { FlexAlign::STRETCH };
297     int32_t beginIndex_ = LIST_PARAM_INVAID;
298     int32_t endIndex_ = LIST_PARAM_INVAID;
299     int32_t length_ = 0;
300     int32_t repeatedLength_ = 0;
301     int32_t indexOffset_ = 0;
302 
303     std::map<int32_t, int32_t> itemGrid_;
304     std::map<int32_t, double> itemPosition_;
305     std::map<int32_t, bool> itemGroupsExpand_;
306     std::map<int32_t, int32_t> itemGroupsFocusIndex_;
307 
308     RefPtr<Animator> controller_;
309     std::vector<int32_t> needRemoveItems_;
310     std::map<int32_t, RefPtr<RenderNode>> newItems_;
311     bool isAnimating_ = false;
312     double friction_ = 1.0;
313     bool expandAll_ = false;
314     bool enableChain_ = false; // whether enables spring chain effect.
315     double chainInterval_ = 0.0;
316     int32_t itemCountOfPage_ = 0;
317     double slipFactor_ = 0.0;
318 };
319 
320 } // namespace OHOS::Ace
321 
322 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_LIST_LAYOUT_MANAGER_H
323