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_RENDER_LIST_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_LIST_RENDER_LIST_H
18 
19 #include <functional>
20 #include <map>
21 #include <vector>
22 
23 #include "core/animation/simple_spring_chain.h"
24 #include "core/components/common/layout/constants.h"
25 #include "core/components/list/layout_manager.h"
26 #include "core/components/list/render_list_item.h"
27 #include "core/components/scroll/render_scroll.h"
28 #include "core/components/scroll/scrollable.h"
29 
30 namespace OHOS::Ace {
31 
32 class ListComponent;
33 
34 constexpr int32_t INVALID_INDEX = -1;
35 constexpr int32_t ZERO_INDEX = 0;
36 
37 using RotationEventFunc = std::function<void(const RotationEvent& info)>;
38 
39 class RenderList : public RenderNode {
40     DECLARE_ACE_TYPE(RenderList, RenderNode);
41 
42 public:
43     static RefPtr<RenderNode> Create();
44 
45     void Update(const RefPtr<Component>& component) override;
46 
47     void UpdateTouchRect() override;
48 
IsUseOnly()49     bool IsUseOnly() override
50     {
51         return true;
52     }
53 
54     void PerformLayout() override;
55 
56     void OnPaintFinish() override;
57 
58     bool TouchTest(const Point& globalPoint, const Point& parentLocalPoint, const TouchRestrict& touchRestrict,
59         TouchTestResult& result) override;
60 
61     void ResetLayoutRange(double head, double tail, Offset position, Size viewport);
62 
63     using RequestListDataFunc = std::function<void(int32_t index, int32_t count)>;
RegisterRequestItemsCallback(const RequestListDataFunc & requestItems)64     void RegisterRequestItemsCallback(const RequestListDataFunc& requestItems)
65     {
66         requestItems_ = requestItems;
67     }
68 
69     using StickyItemBuildFunc = std::function<RefPtr<RenderNode>(int32_t index, bool next)>;
RegisterStickyItemBuilderCallback(const StickyItemBuildFunc & stickyItemBuilder)70     void RegisterStickyItemBuilderCallback(const StickyItemBuildFunc& stickyItemBuilder)
71     {
72         stickyItemBuilder_ = stickyItemBuilder;
73     }
74 
75     using StickyItemSearchFunc = std::function<int32_t(int32_t index)>;
RegisterStickyItemSearcherCallback(const StickyItemSearchFunc & stickyItemSearcher)76     void RegisterStickyItemSearcherCallback(const StickyItemSearchFunc& stickyItemSearcher)
77     {
78         stickyItemSearcher_ = stickyItemSearcher;
79     }
80 
81     using RecycleByRangeFunc = std::function<bool(int32_t& from, int32_t& to)>;
RegisterRecycleByRangeCallback(const RecycleByRangeFunc & recycle)82     void RegisterRecycleByRangeCallback(const RecycleByRangeFunc& recycle)
83     {
84         recycleByRange_ = recycle;
85     }
86 
87     using RecycleByItemsFunc = std::function<bool(const std::vector<int32_t>& items)>;
RegisterRecycleByItemsCallback(const RecycleByItemsFunc & recycle)88     void RegisterRecycleByItemsCallback(const RecycleByItemsFunc& recycle)
89     {
90         recycleByItems_ = recycle;
91     }
92 
93     using BuildListDataFunc = std::function<bool(int32_t index)>;
RegisterBuildItemCallback(const BuildListDataFunc & buildItem)94     void RegisterBuildItemCallback(const BuildListDataFunc& buildItem)
95     {
96         buildItem_ = buildItem;
97     }
98 
99     using OnRefreshedFunc = std::function<void()>;
RegisterOnRefreshedCallback(const OnRefreshedFunc & onRefreshed)100     void RegisterOnRefreshedCallback(const OnRefreshedFunc& onRefreshed)
101     {
102         onRefreshed_ = onRefreshed;
103     }
104 
105     void AddListItem(int32_t index, const RefPtr<RenderNode>& renderNode);
106 
107     template<typename T>
MakeValue(double mainValue,double crossValue)108     T MakeValue(double mainValue, double crossValue) const
109     {
110         return IsRowDirection() ? T(mainValue, crossValue) : T(crossValue, mainValue);
111     }
112 
SetMainSize(Size & size,double mainValue)113     void SetMainSize(Size& size, double mainValue)
114     {
115         IsRowDirection() ? size.SetWidth(mainValue) : size.SetHeight(mainValue);
116     }
117 
SetCrossSize(Size & size,double crossValue)118     void SetCrossSize(Size& size, double crossValue)
119     {
120         IsRowDirection() ? size.SetHeight(crossValue) : size.SetWidth(crossValue);
121     }
122 
GetMainSize(const Size & size)123     double GetMainSize(const Size& size) const
124     {
125         return IsRowDirection() ? size.Width() : size.Height();
126     }
127 
GetCrossSize(const Size & size)128     double GetCrossSize(const Size& size) const
129     {
130         return IsRowDirection() ? size.Height() : size.Width();
131     }
132 
GetMainPosition(const Offset & offset)133     double GetMainPosition(const Offset& offset) const
134     {
135         return IsRowDirection() ? offset.GetX() : offset.GetY();
136     }
137 
IsRowDirection()138     bool IsRowDirection() const
139     {
140         return direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE;
141     }
142 
IsLayoutChanged()143     bool IsLayoutChanged() const
144     {
145         return IsLayoutParamChanged();
146     }
147 
GetMaxCount()148     int32_t GetMaxCount() const
149     {
150         return maxCount_;
151     }
152 
SetMaxCount(int32_t maxCount)153     void SetMaxCount(int32_t maxCount)
154     {
155         maxCount_ = maxCount;
156     }
157 
GetCurrentMinIndex()158     int32_t GetCurrentMinIndex() const
159     {
160         int32_t currentMin = -1;
161         if (items_.begin() != items_.end()) {
162             currentMin = items_.begin()->first;
163         }
164         return currentMin;
165     }
166 
GetCurrentMaxIndex()167     int32_t GetCurrentMaxIndex() const
168     {
169         int32_t currentMax = -1;
170         if (items_.rbegin() != items_.rend()) {
171             currentMax = items_.rbegin()->first;
172         }
173         return currentMax;
174     }
175 
GetDirection()176     FlexDirection GetDirection() const
177     {
178         return direction_;
179     }
180 
GetCachedCount()181     int32_t GetCachedCount() const
182     {
183         return cachedCount_;
184     }
185 
GetBeginIndex()186     int32_t GetBeginIndex() const
187     {
188         return beginIndex_;
189     }
190 
GetEndIndex()191     int32_t GetEndIndex() const
192     {
193         return endIndex_;
194     }
195 
GetRepeatedLength()196     int32_t GetRepeatedLength() const
197     {
198         return repeatLength_;
199     }
200 
GetLength()201     int32_t GetLength() const
202     {
203         return length_;
204     }
205 
SetLength(int32_t length)206     void SetLength(int32_t length)
207     {
208         length_ = length;
209     }
210 
GetIndexOffset()211     int32_t GetIndexOffset() const
212     {
213         return indexOffset_;
214     }
215 
GetFlexAlign()216     FlexAlign GetFlexAlign() const
217     {
218         return crossAxisAlign_;
219     }
220 
GetColumnCount()221     int32_t GetColumnCount() const
222     {
223         return columnCount_;
224     }
225 
GetColumnExtent()226     int32_t GetColumnExtent() const
227     {
228         return columnExtent_;
229     }
230 
GetWidth()231     double GetWidth() const
232     {
233         return listWidth_;
234     }
235 
GetHeight()236     double GetHeight() const
237     {
238         return listHeight_;
239     }
240 
GetItemExtent()241     const Dimension& GetItemExtent() const
242     {
243         return itemExtent_;
244     }
245 
GetRightToLeft()246     bool GetRightToLeft() const
247     {
248         return rightToLeft_;
249     }
250 
GetItems()251     const std::map<int32_t, RefPtr<RenderNode>>& GetItems() const
252     {
253         return items_;
254     }
255 
ResetItems(std::map<int32_t,RefPtr<RenderNode>> & items)256     void ResetItems(std::map<int32_t, RefPtr<RenderNode>>& items)
257     {
258         items_.clear();
259         items_.swap(items);
260     }
261 
262     void CalculateStickyItem(const Offset& position);
263 
264     void RequestMoreItems(int32_t index, int32_t count);
265 
266     int32_t RequestNextFocus(bool vertical, bool reverse);
267 
268     void ListItemFocused(int32_t focusIndex);
269 
270     void MoveItemToViewPort(double position);
271 
272     void MoveItemGroupToViewPort(double position, double size);
273 
274     RefPtr<RenderListItem> GetItemByIndex(int32_t index);
275 
276     RefPtr<RenderNode> GetChildByPosition(double position) const;
277     RefPtr<RenderNode> GetNearChildByPosition(double position) const;
278     RefPtr<RenderNode> FindChildByIndex(int32_t index);
279     RefPtr<RenderNode> GetChildByIndex(int32_t index);
280     int32_t GetIndexByPosition(double position) const;
281     bool RecycleByRange(int32_t from, int32_t to);
282     bool RecycleByItems(const std::vector<int32_t>& items);
283     bool RecycleAllChild();
284     void RecycleHead(int32_t head);
285     void RecycleTail(int32_t tail);
286     void SyncIndex(int32_t begin, int32_t end);
287 
288     void CalculateFocusIndexPosition();
289 
290     double CalculateItemPosition(int32_t index, ScrollType type);
291 
292     void CalculateItemPosition(double targetPos);
293 
294     void MarkNeedRefresh();
295 
296     void RefreshOffset(double offset);
297 
298     void RefreshScrollExtent();
299 
300     void SetGroupState(int32_t index, bool expand);
301 
OnRefreshed()302     void OnRefreshed()
303     {
304         onRefreshed_();
305     }
306 
GetLayoutManager()307     const RefPtr<LayoutManager>& GetLayoutManager() const
308     {
309         return layoutManager_;
310     }
311 
GetItemPosition(int32_t index)312     double GetItemPosition(int32_t index) const
313     {
314         if (layoutManager_) {
315             return layoutManager_->GetItemPosition(index);
316         }
317         return 0.0;
318     }
319 
GetItemAnimationPosition(int32_t index)320     double GetItemAnimationPosition(int32_t index) const
321     {
322         if (layoutManager_) {
323             return layoutManager_->GetItemAnimationValue(index);
324         }
325         return 0.0;
326     }
327 
GetController()328     const RefPtr<ScrollPositionController>& GetController() const
329     {
330         return controller_;
331     }
332 
IsSupportScale()333     bool IsSupportScale() const
334     {
335         return itemScale_;
336     }
337 
SetSupportItemCenter(bool center)338     void SetSupportItemCenter(bool center)
339     {
340         supportItemCenter_ = center;
341     }
342 
GetSupportItemCenter()343     bool GetSupportItemCenter() const
344     {
345         return supportItemCenter_;
346     }
347 
SupportStickyItem()348     bool SupportStickyItem() const
349     {
350         return !chainAnimation_ && (direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE);
351     }
352 
IsCenterLayout()353     bool IsCenterLayout() const
354     {
355         return isCenterLayout_;
356     }
357 
IsPageReady()358     bool IsPageReady() const
359     {
360         return pageReady_;
361     }
362 
GetAddDeleteEffect()363     bool GetAddDeleteEffect() const
364     {
365         return updateEffect_ && pageReady_;
366     }
367 
SetAddDeleteEffect(bool enabled)368     void SetAddDeleteEffect(bool enabled)
369     {
370         updateEffect_ = enabled;
371     }
372 
373     void BuildNextItem(double start, double end, Offset position, Size viewPort);
374 
SetShiftHeight(double shiftHeight)375     void SetShiftHeight(double shiftHeight)
376     {
377         shiftHeight_ = shiftHeight;
378     }
379 
380     // notify start position in global main axis
381     void NotifyDragStart(double startPosition);
382 
383     // notify drag offset in global main axis
384     void NotifyDragUpdate(double dragOffset);
385 
386     void NotifyScrollOver(double velocity, bool isCrashTop, bool isCrashBottom);
387 
IsEnableChain()388     bool IsEnableChain() const
389     {
390         return chainAnimation_;
391     }
392 
GetDragStartIndexPending()393     int32_t GetDragStartIndexPending() const
394     {
395         return dragStartIndexPending_;
396     }
397 
SetDragStartIndexPending(int32_t index)398     void SetDragStartIndexPending(int32_t index)
399     {
400         dragStartIndexPending_ = index;
401     }
402 
GetDragStartIndex()403     int32_t GetDragStartIndex() const
404     {
405         return dragStartIndex_;
406     }
407 
SetDragStartIndex(int32_t index)408     void SetDragStartIndex(int32_t index)
409     {
410         dragStartIndex_ = index;
411     }
412 
GetCurrentDelta()413     double GetCurrentDelta() const
414     {
415         return currentDelta_;
416     }
417 
418     // Reset when performLayout done.
ResetCurrentDelta()419     void ResetCurrentDelta()
420     {
421         currentDelta_ = 0.0;
422     }
423 
GetOverSpringProperty()424     const RefPtr<SpringProperty>& GetOverSpringProperty() const
425     {
426         return overSpringProperty_;
427     }
428 
GetChainProperty()429     const SpringChainProperty& GetChainProperty() const
430     {
431         return chainProperty_;
432     }
433 
FlushChainAnimation()434     double FlushChainAnimation()
435     {
436         if (!layoutManager_) {
437             return 0.0;
438         }
439         return layoutManager_->FlushChainAnimation();
440     }
441 
GetHeadAnimationValue()442     double GetHeadAnimationValue() const
443     {
444         if (chainAnimation_ && layoutManager_) {
445             return layoutManager_->GetItemAnimationValue(GetCurrentMinIndex());
446         } else {
447             return 0.0;
448         }
449     }
450 
IsVertical()451     bool IsVertical() const
452     {
453         return direction_ == FlexDirection::COLUMN || direction_ == FlexDirection::COLUMN_REVERSE;
454     }
455 
GetListPosition()456     double GetListPosition() const
457     {
458         if (layoutManager_) {
459             return IsVertical() ? layoutManager_->GetPosition().GetY() : layoutManager_->GetPosition().GetX();
460         }
461         return 0.0;
462     }
463 
EstimateIndexByPosition(double position)464     double EstimateIndexByPosition(double position) const
465     {
466         if (layoutManager_) {
467             return layoutManager_->GetIndexByPosition(position);
468         }
469         return INVALID_INDEX;
470     }
471 
GetTailAnimationValue()472     double GetTailAnimationValue() const
473     {
474         if (chainAnimation_ && layoutManager_) {
475             return GetItemAnimationPosition(GetCurrentMaxIndex());
476         } else {
477             return 0.0;
478         }
479     }
480 
SetMakeCardTransition(bool makeCardTransition)481     void SetMakeCardTransition(bool makeCardTransition)
482     {
483         makeCardTransition_ = makeCardTransition;
484     }
485 
GetCenterIndex()486     int32_t GetCenterIndex() const
487     {
488         return centerIndex_;
489     }
490 
SetCenterIndex(int32_t centerIndex)491     void SetCenterIndex(int32_t centerIndex)
492     {
493         centerIndex_ = centerIndex;
494     }
495 
NeedRefresh()496     bool NeedRefresh() const
497     {
498         return needRefresh_;
499     }
500 
SetNeedRefresh(bool needRefresh)501     void SetNeedRefresh(bool needRefresh)
502     {
503         needRefresh_ = needRefresh;
504     }
505 
506     void OnChildRemoved(const RefPtr<RenderNode>& child) override;
507     void SetOnRotateCallback(const RefPtr<ListComponent>& component);
508 
GetOnRotateCallback()509     const RotationEventFunc& GetOnRotateCallback() const
510     {
511         return rotationEvent_;
512     }
513 
514 protected:
GetStickyItem()515     RefPtr<RenderNode> GetStickyItem() const
516     {
517         return stickyItem_;
518     }
519 
GetStickyNext()520     RefPtr<RenderNode> GetStickyNext() const
521     {
522         return stickyNext_;
523     }
524 
GetStickyItemOffset()525     Offset GetStickyItemOffset() const
526     {
527         return stickyItemOffset_;
528     }
529 
GetStickyNextOffset()530     Offset GetStickyNextOffset() const
531     {
532         return stickyNextOffset_;
533     }
534 
535     int32_t GetItemIndex(const RefPtr<RenderNode>& node);
536     void PaintItems(RenderContext& context, const Offset& offset);
537 
538     double shiftHeight_ = 0.0;
539     bool makeCardTransition_ = false;
540 
541 private:
542     double GetStickyMainSize(int32_t index);
543     void CalculateStickyItemOffset(int32_t index, double position);
544     void UpdateAccessibilityAttr();
545     bool HandleActionScroll(bool forward);
546     void ResetGroupItem(const RefPtr<RenderNode>& renderNode);
547 
548     FlexDirection direction_ { FlexDirection::COLUMN };
549     FlexAlign crossAxisAlign_ = FlexAlign::STRETCH;
550 
551     int32_t cachedCount_ = 1;
552     int32_t beginIndex_ = LIST_PARAM_INVAID;
553     int32_t endIndex_ = LIST_PARAM_INVAID;
554     int32_t repeatLength_ = 0;
555     int32_t length_ = 0;
556     int32_t indexOffset_ = 0;
557     int32_t maxCount_ = 0;
558     int32_t itemsCount_ = 0;
559     // center list-item index if item center option is enabled.
560     int32_t centerIndex_ = INVALID_INDEX;
561 
562     double listWidth_ = -1.0;
563     double listHeight_ = -1.0;
564     double currentDelta_ = 0.0;
565     SpringChainProperty chainProperty_;
566     RefPtr<SpringProperty> overSpringProperty_;
567     int32_t dragStartIndexPending_ = 0;
568     int32_t dragStartIndex_ = 0;
569     int32_t columnCount_ = 0;
570     int32_t columnExtent_ = 0;
571     int32_t firstItemIndex_ = 0;
572     Dimension itemExtent_;
573     bool rightToLeft_ = false;
574     bool updateEffect_ = false;
575     bool supportItemCenter_ = false;
576     bool isCenterLayout_ = false;
577     bool pageReady_ = false;
578     bool itemScale_ = false;
579     bool chainAnimation_ = false;
580     bool needRefresh_ = false;
581 
582     std::map<int32_t, RefPtr<RenderNode>> items_;
583     RequestListDataFunc requestItems_;
584     RecycleByRangeFunc recycleByRange_;
585     RecycleByItemsFunc recycleByItems_;
586     BuildListDataFunc buildItem_;
587     OnRefreshedFunc onRefreshed_;
588     RefPtr<ScrollPositionController> controller_;
589     RefPtr<LayoutManager> layoutManager_;
590 
591     StickyItemBuildFunc stickyItemBuilder_;
592     StickyItemSearchFunc stickyItemSearcher_;
593     RefPtr<RenderNode> stickyItem_;
594     RefPtr<RenderNode> stickyNext_;
595     std::map<int32_t, double> stickyItemMap_;
596     Offset stickyItemOffset_;
597     Offset stickyNextOffset_;
598     Offset currentOffset_;
599     RotationEventFunc rotationEvent_;
600 };
601 
602 } // namespace OHOS::Ace
603 
604 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_LIST_RENDER_LIST_H
605