1 /*
2  * Copyright (c) 2022-2023 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_PATTERNS_GRID_GRID_PATTERN_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_GRID_GRID_PATTERN_H
18 
19 #include "core/components_ng/pattern/grid/grid_accessibility_property.h"
20 #include "core/components_ng/pattern/grid/grid_content_modifier.h"
21 #include "core/components_ng/pattern/grid/grid_event_hub.h"
22 #include "core/components_ng/pattern/grid/grid_layout_info.h"
23 #include "core/components_ng/pattern/grid/grid_layout_property.h"
24 #include "core/components_ng/pattern/grid/grid_paint_method.h"
25 #include "core/components_ng/pattern/scrollable/scrollable_pattern.h"
26 
27 namespace OHOS::Ace::NG {
28 class InspectorFilter;
29 
30 struct GridItemIndexInfo {
31     int32_t mainIndex = -1;
32     int32_t crossIndex = -1;
33     int32_t mainSpan = -1;
34     int32_t crossSpan = -1;
35     int32_t mainStart = -1;
36     int32_t mainEnd = -1;
37     int32_t crossStart = -1;
38     int32_t crossEnd = -1;
39 };
40 
41 class ACE_EXPORT GridPattern : public ScrollablePattern {
42     DECLARE_ACE_TYPE(GridPattern, ScrollablePattern);
43 
44 public:
45     GridPattern() = default;
46 
CreateLayoutProperty()47     RefPtr<LayoutProperty> CreateLayoutProperty() override
48     {
49         return MakeRefPtr<GridLayoutProperty>();
50     }
51 
52     RefPtr<LayoutAlgorithm> CreateLayoutAlgorithm() override;
53 
54     void BeforeCreateLayoutWrapper() override;
55 
56     RefPtr<PaintProperty> CreatePaintProperty() override;
57 
58     RefPtr<NodePaintMethod> CreateNodePaintMethod() override;
59 
CreateAccessibilityProperty()60     RefPtr<AccessibilityProperty> CreateAccessibilityProperty() override
61     {
62         return MakeRefPtr<GridAccessibilityProperty>();
63     }
64 
IsScrollable()65     bool IsScrollable() const override
66     {
67         return isConfigScrollable_;
68     }
69 
70     DisplayMode GetDefaultScrollBarDisplayMode() const override;
71 
SetMultiSelectable(bool multiSelectable)72     void SetMultiSelectable(bool multiSelectable)
73     {
74         multiSelectable_ = multiSelectable;
75     }
76 
MultiSelectable()77     bool MultiSelectable() const
78     {
79         return multiSelectable_;
80     }
81 
SetSupportAnimation(bool supportAnimation)82     void SetSupportAnimation(bool supportAnimation)
83     {
84         supportAnimation_ = supportAnimation;
85     }
86 
SupportAnimation()87     bool SupportAnimation() const
88     {
89         return supportAnimation_;
90     }
91 
GetFocusPattern()92     FocusPattern GetFocusPattern() const override
93     {
94         return { FocusType::SCOPE, true };
95     }
96 
GetScopeFocusAlgorithm()97     ScopeFocusAlgorithm GetScopeFocusAlgorithm() override
98     {
99         auto property = GetLayoutProperty<GridLayoutProperty>();
100         if (!property) {
101             return ScopeFocusAlgorithm();
102         }
103         return ScopeFocusAlgorithm(property->IsVertical(), true, ScopeType::OTHERS,
104             [wp = WeakClaim(this)](
105                 FocusStep step, const WeakPtr<FocusHub>& currFocusNode, WeakPtr<FocusHub>& nextFocusNode) {
106                 auto grid = wp.Upgrade();
107                 if (grid) {
108                     nextFocusNode = grid->GetNextFocusNode(step, currFocusNode);
109                 }
110             });
111     }
112 
113     int32_t GetFocusNodeIndex(const RefPtr<FocusHub>& focusNode) override;
114 
115     void ScrollToFocusNodeIndex(int32_t index) override;
116 
117     ScrollOffsetAbility GetScrollOffsetAbility() override;
118 
119     std::function<bool(int32_t)> GetScrollIndexAbility() override;
120 
121     bool ScrollToNode(const RefPtr<FrameNode>& focusFrameNode) override;
122 
CreateEventHub()123     RefPtr<EventHub> CreateEventHub() override
124     {
125         return MakeRefPtr<GridEventHub>();
126     }
127 
UsResRegion()128     bool UsResRegion() override
129     {
130         return false;
131     }
132 
GetGridLayoutInfo()133     const GridLayoutInfo& GetGridLayoutInfo() const
134     {
135         return gridLayoutInfo_;
136     }
137 
138     /* caution when using mutable reference */
GetMutableLayoutInfo()139     GridLayoutInfo& GetMutableLayoutInfo()
140     {
141         return gridLayoutInfo_;
142     }
143 
ResetGridLayoutInfo()144     void ResetGridLayoutInfo()
145     {
146         gridLayoutInfo_.lineHeightMap_.clear();
147         gridLayoutInfo_.gridMatrix_.clear();
148         gridLayoutInfo_.endIndex_ = gridLayoutInfo_.startIndex_ - 1;
149         gridLayoutInfo_.endMainLineIndex_ = 0;
150         gridLayoutInfo_.ResetPositionFlags();
151         gridLayoutInfo_.irregularItemsPosition_.clear();
152         gridLayoutInfo_.clearStretch_ = true;
153     }
154 
SetIrregular(bool value)155     void SetIrregular(bool value)
156     {
157         irregular_ = value;
158     }
159 
ResetPositionFlags()160     void ResetPositionFlags()
161     {
162         gridLayoutInfo_.ResetPositionFlags();
163     }
164 
165     void ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const override;
166 
167     bool UpdateCurrentOffset(float offset, int32_t source) override;
168 
IsAtTop()169     bool IsAtTop() const override
170     {
171         return gridLayoutInfo_.reachStart_;
172     }
173 
IsAtBottom()174     bool IsAtBottom() const override
175     {
176         return gridLayoutInfo_.offsetEnd_;
177     }
178 
179     bool IsFadingBottom() const override;
180 
181     OverScrollOffset GetOverScrollOffset(double delta) const override;
182     void GetEndOverScrollIrregular(OverScrollOffset& offset, float delta) const;
183 
184     void ScrollPage(bool reverse, bool smooth = false,
185         AccessibilityScrollType scrollType = AccessibilityScrollType::SCROLL_FULL) override;
186 
187     bool UpdateStartIndex(int32_t index);
188 
189     bool UpdateStartIndex(int32_t index, ScrollAlign align);
190 
GetTotalOffset()191     float GetTotalOffset() const override
192     {
193         return EstimateHeight();
194     }
195 
196     float GetTotalHeight() const override;
197 
198     void OnAnimateStop() override;
199 
200     void AnimateTo(
201         float position, float duration, const RefPtr<Curve>& curve, bool smooth, bool canOverScroll = false,
202         bool useTotalOffset = true) override;
203     void ScrollTo(float position) override;
204 
205     void ScrollBy(float offset);
206 
GetDefaultScrollAlign()207     ScrollAlign GetDefaultScrollAlign() const override
208     {
209         return ScrollAlign::AUTO;
210     }
211 
212     void ScrollToEdge(ScrollEdgeType scrollEdgeType, bool smooth) override;
213 
214     void ScrollToIndex(int32_t index, bool smooth = false, ScrollAlign align = ScrollAlign::AUTO,
215         std::optional<float> extraOffset = std::nullopt) override;
216     void AnimateToTarget(ScrollAlign align, const RefPtr<LayoutAlgorithmWrapper>& algo);
217     bool AnimateToTargetImpl(ScrollAlign align, const RefPtr<LayoutAlgorithmWrapper>& algo);
218 
219     int32_t GetOriginalIndex() const;
220     int32_t GetCrossCount() const;
221     int32_t GetChildrenCount() const;
222     void MoveItems(int32_t itemIndex, int32_t insertIndex);
223     void ClearDragState();
224     float EstimateHeight() const;
225     float GetAverageHeight() const;
226 
227     void DumpAdvanceInfo() override;
228 
229     std::string ProvideRestoreInfo() override;
230     void OnRestoreInfo(const std::string& restoreInfo) override;
231     Rect GetItemRect(int32_t index) const override;
232     int32_t GetItemIndex(double x, double y) const override;
233 
IsNeedInitClickEventRecorder()234     bool IsNeedInitClickEventRecorder() const override
235     {
236         return true;
237     }
238 
HasPreloadItemList()239     bool HasPreloadItemList() const
240     {
241         return !preloadItemList_.empty();
242     }
243 
MovePreloadItemList()244     std::list<GridPreloadItem> MovePreloadItemList()
245     {
246         return std::move(preloadItemList_);
247     }
248 
SetPreloadItemList(std::list<GridPreloadItem> && list)249     void SetPreloadItemList(std::list<GridPreloadItem>&& list)
250     {
251         preloadItemList_ = std::move(list);
252     }
253 
254     std::vector<RefPtr<FrameNode>> GetVisibleSelectedItems() override;
255 
256     void StopAnimate() override;
257 
258     bool IsPredictOutOfRange(int32_t index) const;
259 
260     bool IsReverse() const override;
261 
GetAxis()262     Axis GetAxis() const override
263     {
264         return gridLayoutInfo_.axis_;
265     }
266 
GetDefaultCachedCount()267     int32_t GetDefaultCachedCount() const
268     {
269         return gridLayoutInfo_.defCachedCount_;
270     }
271 
272     SizeF GetChildrenExpandedSize() override;
273 
274 private:
275     /**
276      * @brief calculate where startMainLine_ should be after spring animation.
277      * @return main axis position relative to viewport, positive when below viewport.
278      */
279     float GetEndOffset();
280     float GetMainGap() const;
281     float GetAllDelta();
282     void CheckScrollable();
283     bool IsOutOfBoundary(bool useCurrentDelta) override;
284     void SetEdgeEffectCallback(const RefPtr<ScrollEdgeEffect>& scrollEffect) override;
285     SizeF GetContentSize() const;
286     void OnModifyDone() override;
287     bool OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config) override;
288     WeakPtr<FocusHub> GetNextFocusNode(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode);
289     std::pair<int32_t, int32_t> GetNextIndexByStep(
290         int32_t curMainIndex, int32_t curCrossIndex, int32_t curMainSpan, int32_t curCrossSpan, FocusStep step);
291     WeakPtr<FocusHub> SearchFocusableChildInCross(int32_t tarMainIndex, int32_t tarCrossIndex, int32_t maxCrossCount,
292         int32_t curMainIndex = -1, int32_t curCrossIndex = -1);
293     WeakPtr<FocusHub> SearchIrregularFocusableChild(int32_t tarMainIndex, int32_t tarCrossIndex);
294     WeakPtr<FocusHub> GetChildFocusNodeByIndex(int32_t tarMainIndex, int32_t tarCrossIndex, int32_t tarIndex = -1);
295     std::unordered_set<int32_t> GetFocusableChildCrossIndexesAt(int32_t tarMainIndex);
296     void ScrollToFocusNode(const WeakPtr<FocusHub>& focusNode);
297     void FlushFocusOnScroll(const GridLayoutInfo& gridLayoutInfo);
298     std::pair<bool, bool> IsFirstOrLastFocusableChild(int32_t curMainIndex, int32_t curCrossIndex);
299     std::pair<FocusStep, FocusStep> GetFocusSteps(int32_t curMainIndex, int32_t curCrossIndex, FocusStep step);
300     void InitOnKeyEvent(const RefPtr<FocusHub>& focusHub);
301     bool OnKeyEvent(const KeyEvent& event);
302     bool HandleDirectionKey(KeyCode code);
303 
304     void ClearMultiSelect() override;
305     bool IsItemSelected(const GestureEvent& info) override;
306     void MultiSelectWithoutKeyboard(const RectF& selectedZone) override;
307     void UpdateScrollBarOffset() override;
308     void UpdateRectOfDraggedInItem(int32_t insertIndex);
309 
310     void ProcessEvent(bool indexChanged, float finalOffset);
311     void MarkDirtyNodeSelf();
312     void OnScrollEndCallback() override;
313 
314     /**
315      * @brief preform a layout if LayoutInfo is out of sync before calculating spring positions.
316      * INVARIANT: overScroll always enabled in the scope of this function. Because this function only runs in the
317      * context of spring animation.
318      */
319     void SyncLayoutBeforeSpring();
320 
321     void FireOnScrollStart() override;
322     void FireOnReachStart(const OnReachEvent& onReachStart) override;
323     void FireOnReachEnd(const OnReachEvent& onReachEnd) override;
324     void FireOnScrollIndex(bool indexChanged, const ScrollIndexFunc& onScrollIndex);
325 
326     inline bool UseIrregularLayout() const;
327 
328     int32_t CalcIntersectAreaInTargetDirectionShadow(GridItemIndexInfo itemIndexInfo, bool isFindInMainAxis);
329     double GetNearestDistanceFromChildToCurFocusItemInMainAxis(int32_t targetIndex, GridItemIndexInfo itemIndexInfo);
330     double GetNearestDistanceFromChildToCurFocusItemInCrossAxis(int32_t targetIndex, GridItemIndexInfo itemIndexInfo);
331     void ResetAllDirectionsStep();
332 
333     std::string GetIrregularIndexesString() const;
334 
335     bool supportAnimation_ = false;
336     bool isConfigScrollable_ = false;
337 
338     bool scrollable_ = true;
339     bool forceOverScroll_ = false;
340 
341     RefPtr<GridContentModifier> gridContentModifier_;
342 
343     float endHeight_ = 0.0f;
344     bool isLeftStep_ = false;
345     bool isRightStep_ = false;
346     bool isUpStep_ = false;
347     bool isDownStep_ = false;
348     bool isLeftEndStep_ = false;
349     bool isRightEndStep_ = false;
350     bool isSmoothScrolling_ = false;
351     bool irregular_ = false; // true if LayoutOptions require running IrregularLayout
352 
353     ScrollAlign scrollAlign_ = ScrollAlign::AUTO;
354     std::optional<int32_t> targetIndex_;
355     std::pair<std::optional<float>, std::optional<float>> scrollbarInfo_;
356     GridItemIndexInfo curFocusIndexInfo_;
357     GridLayoutInfo scrollGridLayoutInfo_;
358     GridLayoutInfo gridLayoutInfo_;
359     std::list<GridPreloadItem> preloadItemList_; // list of GridItems to build preemptively in IdleTask
360     ACE_DISALLOW_COPY_AND_MOVE(GridPattern);
361 };
362 
363 } // namespace OHOS::Ace::NG
364 
365 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_GRID_GRID_PATTERN_H
366