1 /*
2  * Copyright (c) 2021-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_V2_LIST_RENDER_LIST_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_V2_LIST_RENDER_LIST_H
18 
19 #include <functional>
20 #include <limits>
21 #include <list>
22 
23 #include "core/animation/bilateral_spring_adapter.h"
24 #include "core/animation/simple_spring_chain.h"
25 #include "core/components/positioned/positioned_component.h"
26 #include "core/components/refresh/render_refresh_target.h"
27 #include "core/components/scroll/scroll_edge_effect.h"
28 #include "core/components/scroll/scrollable.h"
29 #include "core/components_v2/list/list_component.h"
30 #include "core/components_v2/list/render_list_item.h"
31 #include "core/components_v2/list/list_item_generator.h"
32 #include "core/gestures/raw_recognizer.h"
33 #include "core/pipeline/base/render_node.h"
34 
35 namespace OHOS::Ace::V2 {
36 
37 using UpdateBuilderFunc = std::function<void(const Dimension&, const Dimension&)>;
38 
39 enum class ListEvents {
40     NONE = 0,
41     SCROLL,
42     SCROLL_STOP,
43     REACH_START,
44     REACH_END,
45 };
46 
47 enum class ItemPositionState {
48     AHEAD_OF_VIEWPORT = 0,
49     IN_VIEWPORT,
50     BEHIND_VIEWPORT,
51 };
52 
53 class RenderList : public RenderNode, public RenderRefreshTarget {
54     DECLARE_ACE_TYPE(V2::RenderList, RenderNode, RenderRefreshTarget);
55 
56 public:
57     using ScrollEventBack = std::function<void(void)>;
58     static RefPtr<RenderNode> Create();
59 
60     RenderList() = default;
61     ~RenderList() override;
62 
63     void Update(const RefPtr<Component>& component) override;
64 
65     void PerformLayout() override;
66 
67     void PaintChild(const RefPtr<RenderNode>& child, RenderContext& context, const Offset& offset) override;
68 
69     void OnPaintFinish() override;
70 
71     bool IsUseOnly() override;
72 
73     template<class T>
MakeValue(double mainValue,double crossValue)74     T MakeValue(double mainValue, double crossValue) const
75     {
76         return vertical_ ? T(crossValue, mainValue) : T(mainValue, crossValue);
77     }
78 
GetMainSize(const Size & size)79     double GetMainSize(const Size& size) const
80     {
81         return vertical_ ? size.Height() : size.Width();
82     }
83 
GetCrossSize(const Size & size)84     double GetCrossSize(const Size& size) const
85     {
86         return vertical_ ? size.Width() : size.Height();
87     }
88 
GetMainAxis(const Offset & size)89     double GetMainAxis(const Offset& size) const
90     {
91         return vertical_ ? size.GetY() : size.GetX();
92     }
93 
GetCrossAxis(const Offset & size)94     double GetCrossAxis(const Offset& size) const
95     {
96         return vertical_ ? size.GetX() : size.GetY();
97     }
98 
GetSpace()99     double GetSpace() const
100     {
101         return spaceWidth_;
102     }
103 
GetStartIndex()104     double GetStartIndex() const
105     {
106         return startIndex_;
107     }
108 
GetIndex()109     double GetIndex() const
110     {
111         return initialIndex_;
112     }
113 
IsVertical()114     bool IsVertical() const
115     {
116         return vertical_;
117     }
118 
GetAxis()119     Axis GetAxis() const
120     {
121         return vertical_ ? Axis::VERTICAL : Axis::HORIZONTAL;
122     }
123 
GetEditable()124     bool GetEditable() const
125     {
126         if (component_) {
127             return component_->GetEditMode();
128         }
129         return false;
130     }
131 
GetLinkage()132     bool GetLinkage() const
133     {
134         if (component_) {
135             return component_->GetChainAnimation();
136         }
137         return false;
138     }
139 
RegisterItemGenerator(WeakPtr<ListItemGenerator> && listItemGenerator)140     void RegisterItemGenerator(WeakPtr<ListItemGenerator>&& listItemGenerator)
141     {
142         itemGenerator_ = std::move(listItemGenerator);
143     }
144 
GetRestoreId()145     int32_t GetRestoreId() const
146     {
147         return component_ ? component_->GetRestoreId() : -1;
148     }
149 
GetMultiSelectable()150     bool GetMultiSelectable() const
151     {
152         return isMultiSelectable_;
153     }
154 
155     void RemoveAllItems();
156 
157     void JumpToIndex(int32_t idx);
158 
159     void AnimateTo(const Dimension& position, float duration, const RefPtr<Curve>& curve);
160 
161     void ScrollToEdge(ScrollEdgeType scrollEdgeType, bool smooth);
162 
163     void ScrollPage(bool reverse, bool smooth);
164 
165     void ScrollBy(double pixelX, double pixelY);
166 
GetComponent()167     RefPtr<Component> GetComponent() override
168     {
169         return component_;
170     }
171 
GetCurrentOffset()172     Offset GetCurrentOffset() const
173     {
174         return vertical_ ? Offset(0.0, -currentOffset_) : Offset(-currentOffset_, 0.0);
175     }
176 
GetRealMainSize()177     double GetRealMainSize() const
178     {
179         return realMainSize_;
180     }
181 
GetEstimatedHeight()182     double GetEstimatedHeight() const
183     {
184         return estimatedHeight_;
185     }
186 
GetLastOffset()187     Offset GetLastOffset() const
188     {
189         return vertical_ ? Offset(0.0, lastOffset_) : Offset(lastOffset_, 0.0);
190     }
191 
192     Offset CurrentOffset();
193 
GetListSpace()194     Dimension GetListSpace() const
195     {
196         return listSpace_;
197     }
198 
GetUpdateBuilderFuncId()199     const UpdateBuilderFunc& GetUpdateBuilderFuncId() const
200     {
201         return updateBuilder_;
202     }
203 
SetUpdateBuilderFuncId(const UpdateBuilderFunc & updateBuilder)204     void SetUpdateBuilderFuncId(const UpdateBuilderFunc& updateBuilder)
205     {
206         updateBuilder_ = updateBuilder;
207     }
208 
GetOnItemDragEnter()209     const OnItemDragEnterFunc& GetOnItemDragEnter() const
210     {
211         return onItemDragEnter_;
212     }
213 
GetOnItemDragMove()214     const OnItemDragMoveFunc& GetOnItemDragMove() const
215     {
216         return onItemDragMove_;
217     }
218 
GetOnItemDragLeave()219     const OnItemDragLeaveFunc& GetOnItemDragLeave() const
220     {
221         return onItemDragLeave_;
222     }
223 
GetOnItemDrop()224     const OnItemDropFunc& GetOnItemDrop() const
225     {
226         return onItemDrop_;
227     }
228 
SetPreTargetRenderList(const RefPtr<RenderList> & preTargetRenderList)229     void SetPreTargetRenderList(const RefPtr<RenderList>& preTargetRenderList)
230     {
231         preTargetRenderList_ = preTargetRenderList;
232     }
233 
GetPreTargetRenderList()234     const RefPtr<RenderList>& GetPreTargetRenderList() const
235     {
236         return preTargetRenderList_;
237     }
238 
SetBetweenItemAndBuilder(const Offset & betweenItemAndBuilder)239     void SetBetweenItemAndBuilder(const Offset& betweenItemAndBuilder)
240     {
241         betweenItemAndBuilder_ = betweenItemAndBuilder;
242     }
243 
GetBetweenItemAndBuilder()244     const Offset& GetBetweenItemAndBuilder() const
245     {
246         return betweenItemAndBuilder_;
247     }
248 
249     size_t CalculateSelectedIndex(
250         const RefPtr<RenderList> targetRenderlist, const GestureEvent& info, Size& selectedItemSize);
251     int32_t CalculateInsertIndex(
252         const RefPtr<RenderList> targetRenderlist, const GestureEvent& info, Size selectedItemSize);
253 
254     void HandleAxisEvent(const AxisEvent& event) override;
255 
256     bool IsAxisScrollable(AxisDirection direction) override;
257 
258     int32_t RequestNextFocus(bool vertical, bool reverse);
259 
260     // distribute
261     std::string ProvideRestoreInfo() override;
262 
SetFocusIndex(int32_t focusIndex)263     void SetFocusIndex(int32_t focusIndex)
264     {
265         focusIndex_ = focusIndex;
266     }
267 
GetLanes()268     int32_t GetLanes() const
269     {
270         return lanes_;
271     }
272 
IsFramePaintStateValid()273     bool IsFramePaintStateValid() const
274     {
275         return isFramePaintStateValid_;
276     }
277 
MarkFramePaintStateValid(bool isValid)278     void MarkFramePaintStateValid(bool isValid)
279     {
280         isFramePaintStateValid_ = isValid;
281     }
282 
GetPaintState()283     bool GetPaintState() const
284     {
285         return paintStateFlag_;
286     }
287 
SetPaintState(bool flag)288     void SetPaintState(bool flag)
289     {
290         paintStateFlag_ = flag;
291         MarkFramePaintStateValid(true);
292     }
293 
294 protected:
295     void UpdateAccessibilityAttr();
296     void UpdateAccessibilityScrollAttr();
297     void UpdateAccessibilityVisible();
298     bool HandleActionScroll(bool forward);
299     LayoutParam MakeInnerLayout();
300     LayoutParam MakeInnerLayoutForLane();
301     Size SetItemsPosition(double mainSize);
302     Size SetItemsPositionForLaneList(double mainSize);
303     bool HandleOverScroll();
304     bool UpdateScrollPosition(double offset, int32_t source);
305 
306     bool TouchTest(const Point& globalPoint, const Point& parentLocalPoint, const TouchRestrict& touchRestrict,
307         TouchTestResult& result) override;
308     void OnTouchTestHit(
309         const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result) override;
310 
311     double ApplyLayoutParam();
312     double LayoutOrRecycleCurrentItems(double mainSize);
313     void BackwardLayoutForCache(size_t& backwardLayoutIndex, double& backwardLayoutOffset);
314     double LayoutOrRecycleCurrentItemsForCache(double mainSize);
315     double LayoutOrRecycleCurrentItemsForLaneList(double mainSize);
316     RefPtr<RenderListItem> RequestAndLayoutNewItem(size_t index, double currMainPos, bool forward = true);
317 
318     RefPtr<RenderListItem> RequestListItem(size_t index);
319     void RecycleListItem(size_t index);
320     size_t FindItemStartIndex(size_t index);
321     size_t GetItemRelativeIndex(size_t index);
322     size_t TotalCount();
323     size_t FindPreviousStickyListItem(size_t index);
324 
325     void OnItemDelete(const RefPtr<RenderListItem>& item);
326     void OnItemSelect(const RefPtr<RenderListItem>& item);
327     size_t GetIndexByListItem(const RefPtr<RenderListItem>& item) const;
328     bool PrepareRawRecognizer();
329     void OnSelectedItemMove(double position);
330     void OnSelectedItemStopMoving(bool canceled);
331 
332     void UpdateStickyListItem(const RefPtr<RenderListItem>& newStickyItem, size_t newStickyItemIndex,
333         const RefPtr<RenderListItem>& nextStickyItem);
334 
335     void ApplyPreviousStickyListItem(size_t index, bool forceLayout = false);
336 
337     double GetCurrentPosition() const;
338     void AdjustOffset(Offset& delta, int32_t source);
339     bool IsOutOfBoundary() const;
340     void ResetEdgeEffect();
341     void SetEdgeEffectAttribute();
342     void CalculateMainScrollExtent(double curMainPos, double mainSize);
343     bool GetCurMainPosAndMainSize(double &curMainPos, double &mainSize);
344 
345     // notify start position in global main axis when drag start
346     void ProcessDragStart(double startPosition);
347     // notify drag offset in global main axis
348     void ProcessDragUpdate(double dragOffset);
349     // notify scroll over
350     void ProcessScrollOverCallback(double velocity);
351     void InitChainAnimation(int32_t nodeCount);
352     double GetChainDelta(int32_t index) const;
353     size_t GetNearChildByPosition(double mainOffset) const;
354     double FlushChainAnimation();
GetOverSpringProperty()355     const RefPtr<SpringProperty>& GetOverSpringProperty() const
356     {
357         return overSpringProperty_;
358     }
GetChainProperty()359     const SpringChainProperty& GetChainProperty() const
360     {
361         return chainProperty_;
362     }
363     void CalculateLanes();
364     void ModifyLaneLength(const std::optional<std::pair<Dimension, Dimension>>& laneConstrain);
365     ItemPositionState GetItemPositionState(double curMainPos, double lastItemMainSize);
366     double GetLaneLengthInPx(const Dimension& length);
367     double CalculateLaneCrossOffset(double crossSize, double childCrossSize);
368     void RequestNewItemsAtEnd(double& curMainPos, double mainSize);
369     void RequestNewItemsAtEndForLaneList(double& curMainPos, double mainSize);
370     void RequestNewItemsAtStart();
371     void RequestNewItemsAtStartForLaneList();
372 
373     RefPtr<ListComponent> component_;
374 
375     static constexpr size_t INVALID_CHILD_INDEX = std::numeric_limits<size_t>::max();
376     static constexpr size_t INITIAL_CHILD_INDEX = INVALID_CHILD_INDEX - 1;
377 
378     size_t startIndex_ = INITIAL_CHILD_INDEX;
379     size_t initialIndex_ = INITIAL_CHILD_INDEX;
380     std::list<RefPtr<RenderListItem>> items_;
381 
382     int32_t midDisplayIndex_ = 0;
383     double spaceWidth_ = 0.0;
384     double lastOffset_ = 0.0;
385     double startIndexOffset_ = 0.0;
386     double startMainPos_ = 0.0;
387     double endMainPos_ = 0.0;
388     double currentOffset_ = 0.0;
389     double mainSize_ = 0.0;
390     double mainScrollExtent_ = 0.0;
391 
392     bool useEstimateCurrentOffset_ = false;
393     bool reachStart_ = false;
394     bool reachEnd_ = false;
395     bool isOutOfBoundary_ = false;
396     bool vertical_ = true;
397     bool fixedMainSizeByLayoutParam_ = true;
398     bool fixedMainSize_ = true;
399     bool fixedCrossSize_ = false;
400     bool chainAnimation_ = false;
401     bool chainOverScroll_ = false;
402     double currentDelta_ = 0.0;
403     bool inLinkRefresh_ = false;
404 
405     SpringChainProperty chainProperty_;
406     RefPtr<SpringProperty> overSpringProperty_;
407     RefPtr<BilateralSpringAdapter> chainAdapter_;
408     RefPtr<SimpleSpringChain> chain_;
409     RefPtr<Animator> animator_;
410 
411     size_t firstDisplayIndex_ = INITIAL_CHILD_INDEX;
412     size_t lastDisplayIndex_ = INITIAL_CHILD_INDEX;
413     size_t dragStartIndexPending_ = 0;
414     size_t dragStartIndex_ = 0;
415     bool hasActionScroll_ = false;
416     bool isActionByScroll_ = false;
417     ScrollEventBack scrollFinishEventBack_;
418 
419     WeakPtr<ListItemGenerator> itemGenerator_;
420     RefPtr<Scrollable> scrollable_;
421     RefPtr<ScrollEdgeEffect> scrollEffect_;
422     RefPtr<ScrollBarProxy> scrollBarProxy_; // user defined scroll bar
423     RefPtr<ScrollBar> scrollBar_;           // system defined scroll bar
424 
425     size_t currentStickyIndex_ = INITIAL_CHILD_INDEX;
426     RefPtr<RenderListItem> currentStickyItem_;
427 
428     size_t targetIndex_ = INITIAL_CHILD_INDEX;
429     size_t selectedItemIndex_ = INITIAL_CHILD_INDEX;
430     RefPtr<RenderListItem> selectedItem_;
431     double selectedItemMainAxis_ = 0.0;
432     double targetMainAxis_ = 0.0;
433     RefPtr<RawRecognizer> rawRecognizer_;
434     double lastPos_ = 0.0f;
435     bool autoScrollingForItemMove_ = false;
436     bool movingForward_ = false;
437     double dipScale_ = 1.0;
438     double offset_ = 0.0;
439 
440     size_t insertItemIndex_ = INITIAL_CHILD_INDEX;
441     Offset betweenItemAndBuilder_;
442     RefPtr<RenderListItem> selectedDragItem_;
443 
444     Offset mouseStartOffset_;
445     Offset mouseEndOffset_;
446     int32_t focusIndex_ = 0;
447     int32_t scrollBarOpacity_ = 0;
448     double prevOffset_ = 0.0;
449     double prevMainPos_ = 0.0;
450     double estimatedHeight_ = 0.0;
451     bool isRightToLeft_ = false;
452     bool drivenRender_ = false;
453 
454 private:
455     int32_t lanes_ = -1;
456     double minLaneLength_ = -1.0; // in vertical list, [minLaneLength_] means the minimum width of a lane
457     double maxLaneLength_ = -1.0; // in vertical list, [maxLaneLength_] means the maximum width of a lane
458     bool isLaneList_ = false;
459     bool IsReachStart();
460     void HandleListEvent();
461     bool ActionByScroll(bool forward, ScrollEventBack scrollEventBack);
462     void ModifyActionScroll();
463     void InitScrollBarProxy();
464     void InitScrollBar();
465     void SetScrollBarCallback();
466     void LayoutChild(RefPtr<RenderNode> child, double referencePos = 0.0, bool forward = true);
467     static void SetChildPosition(RefPtr<RenderNode> child, const Offset& offset);
468     void AddChildItem(RefPtr<RenderNode> child);
469     void AdjustForReachEnd(double mainSize, double curMainPos);
470     void AdjustForReachStart(double &curMainPos);
471     Dimension listSpace_;
472     double realMainSize_ = 0.0; // Real size of main axis.
473     size_t startCachedCount_ = 0;
474     size_t endCachedCount_ = 0;
475     size_t cachedCount_ = 0;
476     StickyStyle sticky_ = StickyStyle::NONE;
477 
478     void CreateDragDropRecognizer();
479     RefPtr<RenderListItem> FindCurrentListItem(const Point& point);
480 
481     RefPtr<GestureRecognizer> dragDropGesture_;
482     RefPtr<RenderList> preTargetRenderList_;
483     OnItemDragStartFunc onItemDragStart_;
484     OnItemDragEnterFunc onItemDragEnter_;
485     OnItemDragMoveFunc onItemDragMove_;
486     OnItemDragLeaveFunc onItemDragLeave_;
487     OnItemDropFunc onItemDrop_;
488 
489     UpdateBuilderFunc updateBuilder_;
490 
491     bool HandleMouseEvent(const MouseEvent& event) override;
492     bool isMultiSelectable_ = false;
493     bool forbidMultiSelect_ = false;
494     void ClearMultiSelect();
495     bool mouseIsHover_ = false;
496     bool hasHeight_ = false;
497     bool hasWidth_ = false;
498     bool isAxisResponse_ = true;
499     ScrollState scrollState_;
500     bool paintStateFlag_ = false;
501     bool isFramePaintStateValid_ = false;
502 
503     void MultiSelectWithoutKeyboard(const Rect& selectedZone);
504     void HandleMouseEventWithoutKeyboard(const MouseEvent& event);
505 
506     void MultiSelectWhenCtrlDown(const Rect& selectedZone);
507     void HandleMouseEventWhenCtrlDown(const MouseEvent& event);
508     void CollectSelectedItems();
509     std::set<RefPtr<RenderListItem>> selectedItemsWithCtrl_;
510 
511     void MultiSelectWhenShiftDown(const Rect& selectedZone);
512     RefPtr<RenderListItem> GetPressItemWhenShiftDown(const Rect& selectedZone);
513     void HandleMouseEventWhenShiftDown(const MouseEvent& event);
514     void MultiSelectAllInRange(const RefPtr<RenderListItem>& firstItem, const RefPtr<RenderListItem>& secondItem);
515     RefPtr<RenderListItem> firstItemWithShift_;
516     RefPtr<RenderListItem> secondItemWithShift_;
517 
518     void MultiSelectAllWhenCtrlA();
519 
520     // distribute
521     void ApplyRestoreInfo();
522 
523     void InitScrollable(Axis axis);
524 
525     // when window size change, add offset to keep clicked textfield in display area
526     void SizeChangeOffset(double newWindowHeight);
527 
528     bool hasDragItem_ = false;
529     std::map<ListEvents, bool> listEventFlags_;
530 
531     ACE_DISALLOW_COPY_AND_MOVE(RenderList);
532 };
533 
534 } // namespace OHOS::Ace::V2
535 
536 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_V2_LIST_RENDER_LIST_H
537