• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 #include "core/components_ng/pattern/grid/grid_pattern.h"
17 
18 #include "base/geometry/axis.h"
19 #include "base/log/dump_log.h"
20 #include "base/perfmonitor/perf_constants.h"
21 #include "base/perfmonitor/perf_monitor.h"
22 #include "base/utils/utils.h"
23 #include "core/common/container.h"
24 #include "core/components/scroll/scroll_controller_base.h"
25 #include "core/components_ng/pattern/grid/grid_adaptive/grid_adaptive_layout_algorithm.h"
26 #include "core/components_ng/pattern/grid/grid_item_layout_property.h"
27 #include "core/components_ng/pattern/grid/grid_item_pattern.h"
28 #include "core/components_ng/pattern/grid/grid_layout/grid_layout_algorithm.h"
29 #include "core/components_ng/pattern/grid/grid_layout_property.h"
30 #include "core/components_ng/pattern/grid/grid_scroll/grid_scroll_layout_algorithm.h"
31 #include "core/components_ng/pattern/grid/grid_scroll/grid_scroll_with_options_layout_algorithm.h"
32 #include "core/components_ng/pattern/grid/grid_utils.h"
33 #include "core/components_ng/pattern/grid/irregular/grid_irregular_layout_algorithm.h"
34 #include "core/components_ng/pattern/scroll_bar/proxy/scroll_bar_proxy.h"
35 #include "core/pipeline_ng/pipeline_context.h"
36 
37 namespace OHOS::Ace::NG {
38 
39 namespace {
40 const Color ITEM_FILL_COLOR = Color::TRANSPARENT;
41 
CalcCoordinatesDistance(double curFocusMain,double curFocusCross,double childMain,double childCross)42 double CalcCoordinatesDistance(double curFocusMain, double curFocusCross, double childMain, double childCross)
43 {
44     return std::sqrt(std::pow((curFocusMain - childMain), 2) + std::pow((curFocusCross - childCross), 2));
45 }
46 } // namespace
47 
CreateLayoutAlgorithm()48 RefPtr<LayoutAlgorithm> GridPattern::CreateLayoutAlgorithm()
49 {
50     auto gridLayoutProperty = GetLayoutProperty<GridLayoutProperty>();
51     CHECK_NULL_RETURN(gridLayoutProperty, nullptr);
52     std::vector<std::string> cols;
53     StringUtils::StringSplitter(gridLayoutProperty->GetColumnsTemplate().value_or(""), ' ', cols);
54     std::vector<std::string> rows;
55     StringUtils::StringSplitter(gridLayoutProperty->GetRowsTemplate().value_or(""), ' ', rows);
56     auto crossCount = cols.empty() ? Infinity<int32_t>() : static_cast<int32_t>(cols.size());
57     auto mainCount = rows.empty() ? Infinity<int32_t>() : static_cast<int32_t>(rows.size());
58     if (!gridLayoutProperty->IsVertical()) {
59         std::swap(crossCount, mainCount);
60     }
61     gridLayoutInfo_.crossCount_ = crossCount;
62     if (targetIndex_.has_value()) {
63         gridLayoutInfo_.targetIndex_ = targetIndex_;
64     }
65     // When rowsTemplate and columnsTemplate is both setting, use static layout algorithm.
66     if (!rows.empty() && !cols.empty()) {
67         return MakeRefPtr<GridLayoutAlgorithm>(gridLayoutInfo_, crossCount, mainCount);
68     }
69 
70     // When rowsTemplate and columnsTemplate is both not setting, use adaptive layout algorithm.
71     if (rows.empty() && cols.empty()) {
72         return MakeRefPtr<GridAdaptiveLayoutAlgorithm>(gridLayoutInfo_);
73     }
74 
75     // If only set one of rowTemplate and columnsTemplate, use scrollable layout algorithm.
76     RefPtr<GridScrollLayoutAlgorithm> result;
77     if (!gridLayoutProperty->GetLayoutOptions().has_value()) {
78         result = MakeRefPtr<GridScrollLayoutAlgorithm>(gridLayoutInfo_, crossCount, mainCount);
79     } else {
80         result = MakeRefPtr<GridScrollWithOptionsLayoutAlgorithm>(gridLayoutInfo_, crossCount, mainCount);
81     }
82     result->SetCanOverScroll(CanOverScroll(GetScrollSource()));
83     result->SetScrollSource(GetScrollSource());
84     if (ScrollablePattern::AnimateRunning()) {
85         result->SetLineSkipping(false);
86     }
87     return result;
88 }
89 
BeforeCreateLayoutWrapper()90 void GridPattern::BeforeCreateLayoutWrapper()
91 {
92     auto host = GetHost();
93     CHECK_NULL_VOID(host);
94     gridLayoutInfo_.childrenCount_ = host->GetTotalChildCount();
95 }
96 
CreateNodePaintMethod()97 RefPtr<NodePaintMethod> GridPattern::CreateNodePaintMethod()
98 {
99     auto paint = MakeRefPtr<GridPaintMethod>(GetScrollBar());
100     CHECK_NULL_RETURN(paint, nullptr);
101     CreateScrollBarOverlayModifier();
102     paint->SetScrollBarOverlayModifier(GetScrollBarOverlayModifier());
103     auto scrollEffect = GetScrollEdgeEffect();
104     if (scrollEffect && scrollEffect->IsFadeEffect()) {
105         paint->SetEdgeEffect(scrollEffect);
106     }
107     return paint;
108 }
109 
InitScrollableEvent()110 void GridPattern::InitScrollableEvent()
111 {
112     auto host = GetHost();
113     CHECK_NULL_VOID(host);
114     auto eventHub = host->GetEventHub<GridEventHub>();
115     CHECK_NULL_VOID(eventHub);
116     auto scrollFrameBeginEvent = eventHub->GetOnScrollFrameBegin();
117     SetScrollFrameBeginCallback(scrollFrameBeginEvent);
118 }
119 
OnModifyDone()120 void GridPattern::OnModifyDone()
121 {
122     auto gridLayoutProperty = GetLayoutProperty<GridLayoutProperty>();
123     CHECK_NULL_VOID(gridLayoutProperty);
124 
125     if (multiSelectable_ && !isMouseEventInit_) {
126         InitMouseEvent();
127     }
128 
129     if (!multiSelectable_ && isMouseEventInit_) {
130         UninitMouseEvent();
131     }
132 
133     gridLayoutInfo_.axis_ = gridLayoutProperty->IsVertical() ? Axis::VERTICAL : Axis::HORIZONTAL;
134     isConfigScrollable_ = gridLayoutProperty->IsConfiguredScrollable();
135     if (!isConfigScrollable_) {
136         return;
137     }
138     SetAxis(gridLayoutInfo_.axis_);
139     if (!GetScrollableEvent()) {
140         AddScrollEvent();
141         InitScrollableEvent();
142     }
143 
144     SetEdgeEffect();
145 
146     auto paintProperty = GetPaintProperty<ScrollablePaintProperty>();
147     CHECK_NULL_VOID(paintProperty);
148     if (paintProperty->GetScrollBarProperty()) {
149         SetScrollBar(paintProperty->GetScrollBarProperty());
150     }
151 
152     auto host = GetHost();
153     CHECK_NULL_VOID(host);
154     auto focusHub = host->GetFocusHub();
155     if (focusHub) {
156         InitOnKeyEvent(focusHub);
157     }
158     SetAccessibilityAction();
159     auto scrollable = GetScrollableEvent()->GetScrollable();
160     if (scrollable) {
161         scrollable->SetOnContinuousSliding([weak = AceType::WeakClaim(this)]() -> double {
162             auto grid = weak.Upgrade();
163             return grid->GetMainContentSize();
164         });
165     }
166 
167     Register2DragDropManager();
168     if (IsNeedInitClickEventRecorder()) {
169         Pattern::InitClickEventRecorder();
170     }
171 }
172 
MultiSelectWithoutKeyboard(const RectF & selectedZone)173 void GridPattern::MultiSelectWithoutKeyboard(const RectF& selectedZone)
174 {
175     auto host = GetHost();
176     CHECK_NULL_VOID(host);
177     std::list<RefPtr<FrameNode>> children;
178     host->GenerateOneDepthVisibleFrame(children);
179     for (const auto& itemFrameNode : children) {
180         auto itemEvent = itemFrameNode->GetEventHub<EventHub>();
181         CHECK_NULL_VOID(itemEvent);
182         if (!itemEvent->IsEnabled()) {
183             continue;
184         }
185 
186         auto itemPattern = itemFrameNode->GetPattern<GridItemPattern>();
187         CHECK_NULL_VOID(itemPattern);
188         if (!itemPattern->Selectable()) {
189             continue;
190         }
191         auto itemGeometry = itemFrameNode->GetGeometryNode();
192         CHECK_NULL_VOID(itemGeometry);
193         auto context = itemFrameNode->GetRenderContext();
194         CHECK_NULL_VOID(context);
195 
196         auto itemRect = itemGeometry->GetFrameRect();
197         auto iter = itemToBeSelected_.find(itemFrameNode->GetId());
198         if (iter == itemToBeSelected_.end()) {
199             auto result = itemToBeSelected_.emplace(itemFrameNode->GetId(), ItemSelectedStatus());
200             iter = result.first;
201             iter->second.onSelected = itemPattern->GetEventHub<GridItemEventHub>()->GetOnSelect();
202             iter->second.selectChangeEvent = itemPattern->GetEventHub<GridItemEventHub>()->GetSelectChangeEvent();
203         }
204         auto startMainOffset = mouseStartOffset_.GetMainOffset(gridLayoutInfo_.axis_);
205         if (gridLayoutInfo_.axis_ == Axis::VERTICAL) {
206             iter->second.rect = itemRect + OffsetF(0, totalOffsetOfMousePressed_ - startMainOffset);
207         } else {
208             iter->second.rect = itemRect + OffsetF(totalOffsetOfMousePressed_ - startMainOffset, 0);
209         }
210 
211         if (!selectedZone.IsIntersectWith(itemRect)) {
212             itemPattern->MarkIsSelected(false);
213             iter->second.selected = false;
214             context->OnMouseSelectUpdate(false, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
215         } else {
216             itemPattern->MarkIsSelected(true);
217             iter->second.selected = true;
218             context->OnMouseSelectUpdate(true, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
219         }
220     }
221 
222     DrawSelectedZone(selectedZone);
223 }
224 
ClearMultiSelect()225 void GridPattern::ClearMultiSelect()
226 {
227     auto host = GetHost();
228     CHECK_NULL_VOID(host);
229     std::list<RefPtr<FrameNode>> children;
230     host->GenerateOneDepthAllFrame(children);
231     for (const auto& item : children) {
232         if (!AceType::InstanceOf<FrameNode>(item)) {
233             continue;
234         }
235 
236         auto itemFrameNode = AceType::DynamicCast<FrameNode>(item);
237         auto itemPattern = itemFrameNode->GetPattern<GridItemPattern>();
238         CHECK_NULL_VOID(itemPattern);
239         auto selectedStatus = itemToBeSelected_.find(itemFrameNode->GetId());
240         if (selectedStatus != itemToBeSelected_.end()) {
241             selectedStatus->second.selected = false;
242         }
243         itemPattern->MarkIsSelected(false);
244         auto renderContext = itemFrameNode->GetRenderContext();
245         CHECK_NULL_VOID(renderContext);
246         renderContext->OnMouseSelectUpdate(false, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
247     }
248 
249     ClearSelectedZone();
250 }
251 
IsItemSelected(const GestureEvent & info)252 bool GridPattern::IsItemSelected(const GestureEvent& info)
253 {
254     auto host = GetHost();
255     CHECK_NULL_RETURN(host, false);
256     auto node = host->FindChildByPosition(info.GetGlobalLocation().GetX(), info.GetGlobalLocation().GetY());
257     CHECK_NULL_RETURN(node, false);
258     auto itemPattern = node->GetPattern<GridItemPattern>();
259     CHECK_NULL_RETURN(itemPattern, false);
260     return itemPattern->IsSelected();
261 }
262 
FireOnScrollStart()263 void GridPattern::FireOnScrollStart()
264 {
265     PerfMonitor::GetPerfMonitor()->Start(PerfConstants::APP_LIST_FLING, PerfActionType::FIRST_MOVE, "");
266     if (GetScrollAbort()) {
267         return;
268     }
269     if (scrollStop_) {
270         // onScrollStart triggers immediately on gesture dragStart, but onScrollStop marks scrollStop_ to true on
271         // gesture dragEnd, and consumes it/fires onScrollStop after layout. When the user quickly swipes twice, the
272         // second onScrollStart can trigger before the first onScrollEnd. In this case, we let the two events annihilate
273         // each other and fire neither.
274         scrollStop_ = false;
275         return;
276     }
277     auto scrollBar = GetScrollBar();
278     if (scrollBar) {
279         scrollBar->PlayScrollBarAppearAnimation();
280     }
281     StopScrollBarAnimatorByProxy();
282     auto host = GetHost();
283     CHECK_NULL_VOID(host);
284     auto hub = host->GetEventHub<GridEventHub>();
285     CHECK_NULL_VOID(hub);
286     auto onScrollStart = hub->GetOnScrollStart();
287     CHECK_NULL_VOID(onScrollStart);
288     onScrollStart();
289 }
290 
GetContentSize() const291 SizeF GridPattern::GetContentSize() const
292 {
293     auto host = GetHost();
294     CHECK_NULL_RETURN(host, SizeF());
295     auto geometryNode = host->GetGeometryNode();
296     CHECK_NULL_RETURN(geometryNode, SizeF());
297     return geometryNode->GetPaddingSize();
298 }
299 
CheckRestartSpring()300 void GridPattern::CheckRestartSpring()
301 {
302     if (!ScrollableIdle() || !IsOutOfBoundary()) {
303         return;
304     }
305     auto edgeEffect = GetScrollEdgeEffect();
306     if (!edgeEffect || !edgeEffect->IsSpringEffect()) {
307         return;
308     }
309     if (AnimateRunning()) {
310         return;
311     }
312 
313     FireOnScrollStart();
314     edgeEffect->ProcessScrollOver(0);
315 }
316 
GetMainGap() const317 float GridPattern::GetMainGap() const
318 {
319     float mainGap = 0.0;
320     auto host = GetHost();
321     CHECK_NULL_RETURN(host, 0.0);
322     auto geometryNode = host->GetGeometryNode();
323     CHECK_NULL_RETURN(geometryNode, 0.0);
324     auto viewScopeSize = geometryNode->GetPaddingSize();
325     auto layoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
326     mainGap = GridUtils::GetMainGap(layoutProperty, viewScopeSize, gridLayoutInfo_.axis_);
327     return mainGap;
328 }
329 
UpdateCurrentOffset(float offset,int32_t source)330 bool GridPattern::UpdateCurrentOffset(float offset, int32_t source)
331 {
332     if (!isConfigScrollable_ || !scrollable_) {
333         return true;
334     }
335 
336     auto host = GetHost();
337     CHECK_NULL_RETURN(host, false);
338     // check edgeEffect is not springEffect
339     if (!HandleEdgeEffect(offset, source, GetContentSize())) {
340         if (IsOutOfBoundary()) {
341             host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
342         }
343         return false;
344     }
345     SetScrollSource(source);
346     FireAndCleanScrollingListener();
347 
348     // When finger moves down, offset is positive.
349     // When finger moves up, offset is negative.
350     auto itemsHeight = gridLayoutInfo_.GetTotalHeightOfItemsInView(GetMainGap());
351     if (gridLayoutInfo_.offsetEnd_) {
352         auto overScroll = gridLayoutInfo_.currentOffset_ - (GetMainContentSize() - itemsHeight);
353         if (source == SCROLL_FROM_UPDATE) {
354             auto friction = ScrollablePattern::CalculateFriction(std::abs(overScroll) / GetMainContentSize());
355             gridLayoutInfo_.prevOffset_ = gridLayoutInfo_.currentOffset_;
356             gridLayoutInfo_.currentOffset_ = gridLayoutInfo_.currentOffset_ + offset * friction;
357         } else {
358             gridLayoutInfo_.prevOffset_ = gridLayoutInfo_.currentOffset_;
359             gridLayoutInfo_.currentOffset_ += offset;
360         }
361         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
362 
363         if (GreatNotEqual(gridLayoutInfo_.currentOffset_, GetMainContentSize() - itemsHeight)) {
364             gridLayoutInfo_.offsetEnd_ = false;
365             gridLayoutInfo_.reachEnd_ = false;
366         }
367         return true;
368     }
369     if (gridLayoutInfo_.reachStart_) {
370         if (source == SCROLL_FROM_UPDATE) {
371             auto friction =
372                 ScrollablePattern::CalculateFriction(std::abs(gridLayoutInfo_.currentOffset_) / GetMainContentSize());
373             gridLayoutInfo_.prevOffset_ = gridLayoutInfo_.currentOffset_;
374             gridLayoutInfo_.currentOffset_ = gridLayoutInfo_.currentOffset_ + offset * friction;
375         } else {
376             gridLayoutInfo_.prevOffset_ = gridLayoutInfo_.currentOffset_;
377             gridLayoutInfo_.currentOffset_ += offset;
378         }
379         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
380 
381         if (LessNotEqual(gridLayoutInfo_.currentOffset_, 0.0)) {
382             gridLayoutInfo_.reachStart_ = false;
383         }
384         return true;
385     }
386     // maybe no measure after last update
387     if (!gridLayoutInfo_.offsetUpdated_) {
388         gridLayoutInfo_.prevOffset_ = gridLayoutInfo_.currentOffset_;
389         gridLayoutInfo_.offsetUpdated_ = true;
390     }
391     gridLayoutInfo_.currentOffset_ += offset;
392     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
393     return true;
394 }
395 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)396 bool GridPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
397 {
398     if (config.skipMeasure && config.skipLayout) {
399         return false;
400     }
401     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
402     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
403     auto gridLayoutAlgorithm = DynamicCast<GridLayoutBaseAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
404     CHECK_NULL_RETURN(gridLayoutAlgorithm, false);
405     const auto& gridLayoutInfo = gridLayoutAlgorithm->GetGridLayoutInfo();
406     auto eventhub = GetEventHub<GridEventHub>();
407     CHECK_NULL_RETURN(eventhub, false);
408     Dimension offset(0, DimensionUnit::VP);
409     Dimension offsetPx(gridLayoutInfo.currentOffset_, DimensionUnit::PX);
410     auto offsetVpValue = offsetPx.ConvertToVp();
411     offset.SetValue(offsetVpValue);
412     scrollbarInfo_ = eventhub->FireOnScrollBarUpdate(gridLayoutInfo.startIndex_, offset);
413     if (!isInitialized_ || gridLayoutInfo_.startIndex_ != gridLayoutInfo.startIndex_) {
414         eventhub->FireOnScrollToIndex(gridLayoutInfo.startIndex_);
415     }
416 
417     bool indexChanged = (gridLayoutInfo.startIndex_ != gridLayoutInfo_.startIndex_) ||
418                         (gridLayoutInfo.endIndex_ != gridLayoutInfo_.endIndex_);
419     bool offsetEnd = gridLayoutInfo_.offsetEnd_;
420     gridLayoutInfo_ = gridLayoutInfo;
421     AnimateToTarget(scrollAlign_, layoutAlgorithmWrapper);
422 
423     gridLayoutInfo_.reachStart_ =
424         gridLayoutInfo_.startIndex_ == 0 && GreatOrEqual(gridLayoutInfo_.currentOffset_, 0.0f);
425 
426     currentHeight_ = EstimateHeight();
427     if (!offsetEnd && gridLayoutInfo_.offsetEnd_) {
428         endHeight_ = currentHeight_;
429     }
430     ProcessEvent(indexChanged, currentHeight_ - prevHeight_);
431     prevHeight_ = currentHeight_;
432     SetScrollSource(SCROLL_FROM_NONE);
433     UpdateScrollBarOffset();
434     if (config.frameSizeChange) {
435         if (GetScrollBar() != nullptr) {
436             GetScrollBar()->ScheduleDisappearDelayTask();
437         }
438     }
439     CheckRestartSpring();
440     CheckScrollable();
441     MarkSelectedItems();
442     isInitialized_ = true;
443     return false;
444 }
445 
CheckScrollable()446 void GridPattern::CheckScrollable()
447 {
448     auto host = GetHost();
449     CHECK_NULL_VOID(host);
450     auto gridLayoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
451     CHECK_NULL_VOID(gridLayoutProperty);
452     if (((gridLayoutInfo_.endIndex_ - gridLayoutInfo_.startIndex_ + 1) < gridLayoutInfo_.childrenCount_) ||
453         (gridLayoutInfo_.GetTotalHeightOfItemsInView(GetMainGap()) > GetMainContentSize())) {
454         scrollable_ = true;
455     } else {
456         if (gridLayoutInfo_.startMainLineIndex_ != 0 || GetAlwaysEnabled()) {
457             scrollable_ = true;
458         } else {
459             scrollable_ = false;
460         }
461     }
462 
463     SetScrollEnable(scrollable_);
464 
465     if (!gridLayoutProperty->GetScrollEnabled().value_or(scrollable_)) {
466         SetScrollEnable(false);
467     }
468 }
469 
ProcessEvent(bool indexChanged,float finalOffset)470 void GridPattern::ProcessEvent(bool indexChanged, float finalOffset)
471 {
472     auto host = GetHost();
473     CHECK_NULL_VOID(host);
474     auto gridEventHub = host->GetEventHub<GridEventHub>();
475     CHECK_NULL_VOID(gridEventHub);
476 
477     auto onScroll = gridEventHub->GetOnScroll();
478     if (onScroll) {
479         FireOnScroll(finalOffset, onScroll);
480     }
481 
482     if (indexChanged) {
483         auto onScrollIndex = gridEventHub->GetOnScrollIndex();
484         if (onScrollIndex) {
485             onScrollIndex(gridLayoutInfo_.startIndex_, gridLayoutInfo_.endIndex_);
486         }
487     }
488 
489     auto onReachStart = gridEventHub->GetOnReachStart();
490     if (onReachStart && gridLayoutInfo_.startIndex_ == 0) {
491         if (!isInitialized_) {
492             onReachStart();
493         }
494 
495         if (!NearZero(finalOffset)) {
496             bool scrollUpToStart = GreatOrEqual(prevHeight_, 0.0) && LessOrEqual(currentHeight_, 0.0);
497             bool scrollDownToStart = LessNotEqual(prevHeight_, 0.0) && GreatOrEqual(currentHeight_, 0.0);
498             if (scrollUpToStart || scrollDownToStart) {
499                 onReachStart();
500             }
501         }
502     }
503 
504     auto onReachEnd = gridEventHub->GetOnReachEnd();
505     if (onReachEnd && gridLayoutInfo_.endIndex_ == (gridLayoutInfo_.childrenCount_ - 1)) {
506         if (!NearZero(finalOffset)) {
507             bool scrollDownToEnd = LessNotEqual(prevHeight_, endHeight_) && GreatOrEqual(currentHeight_, endHeight_);
508             bool scrollUpToEnd = GreatNotEqual(prevHeight_, endHeight_) && LessOrEqual(currentHeight_, endHeight_);
509             if (scrollDownToEnd || scrollUpToEnd) {
510                 onReachEnd();
511             }
512         }
513     }
514 
515     OnScrollStop(gridEventHub->GetOnScrollStop());
516 }
517 
MarkDirtyNodeSelf()518 void GridPattern::MarkDirtyNodeSelf()
519 {
520     auto host = GetHost();
521     CHECK_NULL_VOID(host);
522     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
523 }
524 
OnScrollEndCallback()525 void GridPattern::OnScrollEndCallback()
526 {
527     isSmoothScrolling_ = false;
528     SetScrollSource(SCROLL_FROM_ANIMATION);
529     scrollStop_ = true;
530     MarkDirtyNodeSelf();
531 }
532 
IsFirstOrLastFocusableChild(int32_t curMainIndex,int32_t curCrossIndex)533 std::pair<bool, bool> GridPattern::IsFirstOrLastFocusableChild(int32_t curMainIndex, int32_t curCrossIndex)
534 {
535     std::unordered_set<int32_t> crossIndexSet;
536     size_t maxSize = 0;
537     for (int32_t index = curMainIndex - curFocusIndexInfo_.mainSpan + 1; index <= curMainIndex; index++) {
538         auto tempIndexSet = GetFocusableChildCrossIndexesAt(index);
539         if (tempIndexSet.size() > maxSize) {
540             maxSize = tempIndexSet.size();
541             crossIndexSet = tempIndexSet;
542         }
543     }
544     auto findLesser = std::find_if(crossIndexSet.begin(), crossIndexSet.end(),
545         [curCrossIndex](int32_t crossIndex) { return curCrossIndex > crossIndex; });
546     auto findGreater = std::find_if(crossIndexSet.begin(), crossIndexSet.end(),
547         [curCrossIndex](int32_t crossIndex) { return curCrossIndex < crossIndex; });
548     return { curCrossIndex == 0 || findLesser == crossIndexSet.end(),
549         curCrossIndex == gridLayoutInfo_.crossCount_ - 1 || findGreater == crossIndexSet.end() };
550 }
551 
GetFocusSteps(int32_t curMainIndex,int32_t curCrossIndex,FocusStep step)552 std::pair<FocusStep, FocusStep> GridPattern::GetFocusSteps(int32_t curMainIndex, int32_t curCrossIndex, FocusStep step)
553 {
554     auto firstStep = FocusStep::NONE;
555     auto secondStep = FocusStep::NONE;
556     auto isFirstOrLastFocusable = IsFirstOrLastFocusableChild(curMainIndex, curCrossIndex);
557     auto isFirstFocusable = isFirstOrLastFocusable.first;
558     auto isLastFocusable = isFirstOrLastFocusable.second;
559     if (gridLayoutInfo_.axis_ == Axis::VERTICAL) {
560         if (isFirstFocusable && step == FocusStep::SHIFT_TAB) {
561             firstStep = FocusStep::UP;
562             secondStep = FocusStep::RIGHT_END;
563         } else if (isLastFocusable && step == FocusStep::TAB) {
564             firstStep = FocusStep::DOWN;
565             secondStep = FocusStep::LEFT_END;
566         }
567     } else if (gridLayoutInfo_.axis_ == Axis::HORIZONTAL) {
568         if (isFirstFocusable && step == FocusStep::SHIFT_TAB) {
569             firstStep = FocusStep::LEFT;
570             secondStep = FocusStep::DOWN_END;
571         } else if (isLastFocusable && step == FocusStep::TAB) {
572             firstStep = FocusStep::RIGHT;
573             secondStep = FocusStep::UP_END;
574         }
575     }
576     TAG_LOGI(AceLogTag::ACE_GRID, "Get focus steps. First step is %{public}d. Second step is %{public}d", firstStep,
577         secondStep);
578     return { firstStep, secondStep };
579 }
580 
GetNextFocusNode(FocusStep step,const WeakPtr<FocusHub> & currentFocusNode)581 WeakPtr<FocusHub> GridPattern::GetNextFocusNode(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode)
582 {
583     auto curFocus = currentFocusNode.Upgrade();
584     CHECK_NULL_RETURN(curFocus, nullptr);
585     auto curFrame = curFocus->GetFrameNode();
586     CHECK_NULL_RETURN(curFrame, nullptr);
587     auto curPattern = curFrame->GetPattern();
588     CHECK_NULL_RETURN(curPattern, nullptr);
589     auto curItemPattern = AceType::DynamicCast<GridItemPattern>(curPattern);
590     CHECK_NULL_RETURN(curItemPattern, nullptr);
591     auto curItemProperty = curItemPattern->GetLayoutProperty<GridItemLayoutProperty>();
592     CHECK_NULL_RETURN(curItemProperty, nullptr);
593     auto irregularInfo = curItemPattern->GetIrregularItemInfo();
594     bool hasIrregularItemInfo = irregularInfo.has_value();
595 
596     auto curMainIndex = curItemProperty->GetMainIndex().value_or(-1);
597     auto curCrossIndex = curItemProperty->GetCrossIndex().value_or(-1);
598     auto curMainSpan =
599         hasIrregularItemInfo ? irregularInfo.value().mainSpan : curItemProperty->GetMainSpan(gridLayoutInfo_.axis_);
600     auto curCrossSpan =
601         hasIrregularItemInfo ? irregularInfo.value().crossSpan : curItemProperty->GetCrossSpan(gridLayoutInfo_.axis_);
602     auto curMainStart =
603         hasIrregularItemInfo ? irregularInfo.value().mainStart : curItemProperty->GetMainStart(gridLayoutInfo_.axis_);
604     auto curCrossStart =
605         hasIrregularItemInfo ? irregularInfo.value().crossStart : curItemProperty->GetCrossStart(gridLayoutInfo_.axis_);
606     auto curMainEnd =
607         hasIrregularItemInfo ? irregularInfo.value().mainEnd : curItemProperty->GetMainEnd(gridLayoutInfo_.axis_);
608     auto curCrossEnd =
609         hasIrregularItemInfo ? irregularInfo.value().crossEnd : curItemProperty->GetCrossEnd(gridLayoutInfo_.axis_);
610 
611     curFocusIndexInfo_.mainIndex = curMainIndex;
612     curFocusIndexInfo_.crossIndex = curCrossIndex;
613     curFocusIndexInfo_.mainSpan = curMainSpan;
614     curFocusIndexInfo_.crossSpan = curCrossSpan;
615     curFocusIndexInfo_.mainStart = curMainStart;
616     curFocusIndexInfo_.mainEnd = curMainEnd;
617     curFocusIndexInfo_.crossStart = curCrossStart;
618     curFocusIndexInfo_.crossEnd = curCrossEnd;
619 
620     if (curMainIndex < 0 || curCrossIndex < 0) {
621         TAG_LOGW(AceLogTag::ACE_GRID, "can't find focused child.");
622         return nullptr;
623     }
624     if (gridLayoutInfo_.gridMatrix_.find(curMainIndex) == gridLayoutInfo_.gridMatrix_.end()) {
625         TAG_LOGW(AceLogTag::ACE_GRID, "Can not find current main index: %{public}d", curMainIndex);
626         return nullptr;
627     }
628     LOGI("GetNextFocusNode: Current focused item is (%{public}d,%{public}d)-[%{public}d,%{public}d]. Focus step is "
629          "%{public}d",
630         curMainIndex, curCrossIndex, curMainSpan, curCrossSpan, step);
631     auto focusSteps = GetFocusSteps(curMainIndex, curCrossIndex, step);
632     if (focusSteps.first != FocusStep::NONE && focusSteps.second != FocusStep::NONE) {
633         auto firstStepRes = GetNextFocusNode(focusSteps.first, currentFocusNode);
634         if (!firstStepRes.Upgrade()) {
635             return nullptr;
636         }
637         auto secondStepRes = GetNextFocusNode(focusSteps.second, firstStepRes);
638         if (!secondStepRes.Upgrade()) {
639             return firstStepRes;
640         }
641         return secondStepRes;
642     }
643     auto indexes = GetNextIndexByStep(curMainIndex, curCrossIndex, curMainSpan, curCrossSpan, step);
644     auto nextMainIndex = indexes.first;
645     auto nextCrossIndex = indexes.second;
646     while (nextMainIndex >= 0 && nextCrossIndex >= 0) {
647         if (gridLayoutInfo_.gridMatrix_.find(nextMainIndex) == gridLayoutInfo_.gridMatrix_.end()) {
648             TAG_LOGW(AceLogTag::ACE_GRID, "Can not find next main index: %{public}d", nextMainIndex);
649             return nullptr;
650         }
651         auto nextMaxCrossCount = GetCrossCount();
652         auto flag = (step == FocusStep::LEFT_END) || (step == FocusStep::RIGHT_END);
653         auto weakChild = gridLayoutInfo_.hasBigItem_ ? SearchIrregularFocusableChild(nextMainIndex, nextCrossIndex)
654                                                      : SearchFocusableChildInCross(nextMainIndex, nextCrossIndex,
655                                                            nextMaxCrossCount, flag ? -1 : curMainIndex, curCrossIndex);
656         auto child = weakChild.Upgrade();
657         if (child && child->IsFocusable()) {
658             ScrollToFocusNode(weakChild);
659             return weakChild;
660         }
661         auto indexes = GetNextIndexByStep(nextMainIndex, nextCrossIndex, 1, 1, step);
662         nextMainIndex = indexes.first;
663         nextCrossIndex = indexes.second;
664     }
665     return nullptr;
666 }
667 
GetNextIndexByStep(int32_t curMainIndex,int32_t curCrossIndex,int32_t curMainSpan,int32_t curCrossSpan,FocusStep step)668 std::pair<int32_t, int32_t> GridPattern::GetNextIndexByStep(
669     int32_t curMainIndex, int32_t curCrossIndex, int32_t curMainSpan, int32_t curCrossSpan, FocusStep step)
670 {
671     LOGI("Current item: (%{public}d,%{public}d)-[%{public}d,%{public}d]. Grid axis: %{public}d, step: %{public}d",
672         curMainIndex, curCrossIndex, curMainSpan, curCrossSpan, gridLayoutInfo_.axis_, step);
673     auto curMainStart = gridLayoutInfo_.startMainLineIndex_;
674     auto curMainEnd = gridLayoutInfo_.endMainLineIndex_;
675     auto curChildStartIndex = gridLayoutInfo_.startIndex_;
676     auto curChildEndIndex = gridLayoutInfo_.endIndex_;
677     auto childrenCount = gridLayoutInfo_.childrenCount_;
678     auto hasIrregularItems = gridLayoutInfo_.hasBigItem_;
679     if (gridLayoutInfo_.gridMatrix_.find(curMainIndex) == gridLayoutInfo_.gridMatrix_.end()) {
680         TAG_LOGW(AceLogTag::ACE_GRID, "Can not find current main index: %{public}d", curMainIndex);
681         return { -1, -1 };
682     }
683     auto curMaxCrossCount = GetCrossCount();
684     auto nextMainIndex = curMainIndex;
685     auto nextCrossIndex = curCrossIndex;
686     if ((step == FocusStep::UP_END && gridLayoutInfo_.axis_ == Axis::HORIZONTAL) ||
687         (step == FocusStep::LEFT_END && gridLayoutInfo_.axis_ == Axis::VERTICAL)) {
688         nextMainIndex = curMainIndex;
689         nextCrossIndex = 0;
690         isLeftEndStep_ = hasIrregularItems ? true : false;
691     } else if ((step == FocusStep::DOWN_END && gridLayoutInfo_.axis_ == Axis::HORIZONTAL) ||
692                (step == FocusStep::RIGHT_END && gridLayoutInfo_.axis_ == Axis::VERTICAL)) {
693         nextMainIndex = curMainIndex;
694         nextCrossIndex = curMaxCrossCount - 1;
695         isRightEndStep_ = hasIrregularItems ? true : false;
696     } else if (((step == FocusStep::UP || step == FocusStep::SHIFT_TAB) && gridLayoutInfo_.axis_ == Axis::HORIZONTAL) ||
697                ((step == FocusStep::LEFT || step == FocusStep::SHIFT_TAB) && gridLayoutInfo_.axis_ == Axis::VERTICAL)) {
698         nextMainIndex = curMainIndex;
699         nextCrossIndex = curCrossIndex - 1;
700         isLeftStep_ = hasIrregularItems ? true : false;
701     } else if ((step == FocusStep::UP && gridLayoutInfo_.axis_ == Axis::VERTICAL) ||
702                (step == FocusStep::LEFT && gridLayoutInfo_.axis_ == Axis::HORIZONTAL)) {
703         nextMainIndex = hasIrregularItems ? curMainIndex - curMainSpan : curMainIndex - 1;
704         nextCrossIndex = curCrossIndex + static_cast<int32_t>((curCrossSpan - 1) / 2);
705         isUpStep_ = hasIrregularItems ? true : false;
706     } else if (((step == FocusStep::DOWN || step == FocusStep::TAB) && gridLayoutInfo_.axis_ == Axis::HORIZONTAL) ||
707                ((step == FocusStep::RIGHT || step == FocusStep::TAB) && gridLayoutInfo_.axis_ == Axis::VERTICAL)) {
708         nextMainIndex = curMainIndex;
709         nextCrossIndex = curCrossIndex + curCrossSpan;
710         isRightStep_ = hasIrregularItems ? true : false;
711     } else if ((step == FocusStep::DOWN && gridLayoutInfo_.axis_ == Axis::VERTICAL) ||
712                (step == FocusStep::RIGHT && gridLayoutInfo_.axis_ == Axis::HORIZONTAL)) {
713         nextMainIndex = hasIrregularItems ? curMainIndex + 1 : curMainIndex + curMainSpan;
714         nextCrossIndex = curCrossIndex + static_cast<int32_t>((curCrossSpan - 1) / 2);
715         isDownStep_ = hasIrregularItems ? true : false;
716     } else {
717         TAG_LOGW(AceLogTag::ACE_GRID, "Next index return: Invalid step: %{public}d and axis: %{public}d", step,
718             gridLayoutInfo_.axis_);
719         return { -1, -1 };
720     }
721     if (curChildStartIndex == 0 && curMainIndex == 0 && nextMainIndex < curMainIndex) {
722         nextMainIndex = curMainIndex;
723     }
724     if (curChildEndIndex == childrenCount - 1 && curMainIndex == curMainEnd && nextMainIndex > curMainIndex) {
725         nextMainIndex = curMainIndex;
726     }
727     if (nextMainIndex == curMainIndex && nextCrossIndex == curCrossIndex) {
728         TAG_LOGI(AceLogTag::ACE_GRID,
729             "Next index return: Move stoped. Next index: (%{public}d,%{public}d) is same as current.", nextMainIndex,
730             nextCrossIndex);
731         ResetAllDirectionsStep();
732         return { -1, -1 };
733     }
734     if (curChildStartIndex != 0 && curMainIndex == curMainStart && nextMainIndex < curMainIndex) {
735         // Scroll item up.
736         UpdateStartIndex(curChildStartIndex - 1);
737         auto pipeline = PipelineContext::GetCurrentContext();
738         if (pipeline) {
739             pipeline->FlushUITasks();
740         }
741     } else if (curChildEndIndex != childrenCount - 1 && curMainIndex == curMainEnd && nextMainIndex > curMainIndex) {
742         // Scroll item down.
743         UpdateStartIndex(curChildEndIndex + 1);
744         auto pipeline = PipelineContext::GetCurrentContext();
745         if (pipeline) {
746             pipeline->FlushUITasks();
747         }
748     }
749     curMainStart = gridLayoutInfo_.startMainLineIndex_;
750     curMainEnd = gridLayoutInfo_.endMainLineIndex_;
751     if (nextMainIndex < curMainStart || nextMainIndex > curMainEnd) {
752         ResetAllDirectionsStep();
753         return { -1, -1 };
754     }
755     if (nextCrossIndex < 0) {
756         ResetAllDirectionsStep();
757         return { -1, -1 };
758     }
759     if (gridLayoutInfo_.gridMatrix_.find(nextMainIndex) == gridLayoutInfo_.gridMatrix_.end()) {
760         ResetAllDirectionsStep();
761         return { -1, -1 };
762     }
763     auto nextMaxCrossCount = GetCrossCount();
764     if (nextCrossIndex >= nextMaxCrossCount) {
765         TAG_LOGI(AceLogTag::ACE_GRID,
766             "Next index: { %{public}d,%{public}d }. Next cross index is greater than max cross count: %{public}d.",
767             nextMainIndex, nextCrossIndex, nextMaxCrossCount - 1);
768         if (nextMaxCrossCount - 1 != (curCrossIndex + curCrossSpan - 1)) {
769             TAG_LOGI(AceLogTag::ACE_GRID,
770                 "Current cross index: %{public}d is not the tail item. Return to the tail: { %{public}d,%{public}d }",
771                 curCrossIndex, nextMainIndex, nextMaxCrossCount - 1);
772             return { nextMainIndex, nextMaxCrossCount - 1 };
773         }
774         ResetAllDirectionsStep();
775         TAG_LOGI(AceLogTag::ACE_GRID, "Current cross index: %{public}d is the tail item. No next item can be found!",
776             curCrossIndex);
777         return { -1, -1 };
778     }
779     TAG_LOGI(AceLogTag::ACE_GRID, "Next index return: { %{public}d,%{public}d }.", nextMainIndex, nextCrossIndex);
780     return { nextMainIndex, nextCrossIndex };
781 }
782 
SearchFocusableChildInCross(int32_t tarMainIndex,int32_t tarCrossIndex,int32_t maxCrossCount,int32_t curMainIndex,int32_t curCrossIndex)783 WeakPtr<FocusHub> GridPattern::SearchFocusableChildInCross(
784     int32_t tarMainIndex, int32_t tarCrossIndex, int32_t maxCrossCount, int32_t curMainIndex, int32_t curCrossIndex)
785 {
786     bool isDirectionLeft = true;
787     auto indexLeft = tarCrossIndex;
788     auto indexRight = tarCrossIndex;
789     if (curMainIndex == tarMainIndex) {
790         // Search on the same main index. Do not need search on both left and right side.
791         if (tarCrossIndex > curCrossIndex) {
792             // Only search on the right side.
793             indexLeft = -1;
794         } else if (tarCrossIndex < curCrossIndex) {
795             // Only search on the left side.
796             indexRight = maxCrossCount;
797         } else {
798             TAG_LOGW(AceLogTag::ACE_GRID, "Invalid search index: (%{public}d,%{public}d). It's same as current.",
799                 tarMainIndex, tarCrossIndex);
800             return nullptr;
801         }
802     }
803     while (indexLeft >= 0 || indexRight < maxCrossCount) {
804         int32_t curIndex = indexLeft;
805         if (indexLeft < 0) {
806             curIndex = indexRight++;
807         } else if (indexRight >= maxCrossCount) {
808             curIndex = indexLeft--;
809         } else {
810             curIndex = isDirectionLeft ? indexLeft-- : indexRight++;
811             isDirectionLeft = !isDirectionLeft;
812         }
813         auto weakChild = GetChildFocusNodeByIndex(tarMainIndex, curIndex);
814         auto child = weakChild.Upgrade();
815         if (child && child->IsFocusable()) {
816             TAG_LOGI(AceLogTag::ACE_GRID, "Found child. Index: %{public}d,%{public}d", tarMainIndex, curIndex);
817             return weakChild;
818         }
819     }
820     return nullptr;
821 }
822 
SearchIrregularFocusableChild(int32_t tarMainIndex,int32_t tarCrossIndex)823 WeakPtr<FocusHub> GridPattern::SearchIrregularFocusableChild(int32_t tarMainIndex, int32_t tarCrossIndex)
824 {
825     double minDistance = std::numeric_limits<double>::max();
826     int32_t minMainIndex = std::numeric_limits<int32_t>::max();
827     int32_t minCrossIndex = std::numeric_limits<int32_t>::max();
828     int32_t maxAreaInMainShadow = -1;
829     int32_t maxAreaInCrossShadow = -1;
830     WeakPtr<FocusHub> targetFocusHubWeak;
831 
832     auto gridFrame = GetHost();
833     CHECK_NULL_RETURN(gridFrame, nullptr);
834     auto gridFocus = gridFrame->GetFocusHub();
835     CHECK_NULL_RETURN(gridFocus, nullptr);
836     auto childFocusList = gridFocus->GetChildren();
837     for (const auto& childFocus : childFocusList) {
838         if (!childFocus->IsFocusable()) {
839             continue;
840         }
841         auto childFrame = childFocus->GetFrameNode();
842         if (!childFrame) {
843             continue;
844         }
845         auto childPattern = childFrame->GetPattern<GridItemPattern>();
846         if (!childPattern) {
847             continue;
848         }
849         auto childItemProperty = childFrame->GetLayoutProperty<GridItemLayoutProperty>();
850         if (!childItemProperty) {
851             continue;
852         }
853         auto irregularInfo = childPattern->GetIrregularItemInfo();
854         bool hasIrregularItemInfo = irregularInfo.has_value();
855 
856         auto childMainIndex = childItemProperty->GetMainIndex().value_or(-1);
857         auto childCrossIndex = childItemProperty->GetCrossIndex().value_or(-1);
858         auto childMainStart = hasIrregularItemInfo ? irregularInfo.value().mainStart
859                                                    : childItemProperty->GetMainStart(gridLayoutInfo_.axis_);
860         auto childMainEnd =
861             hasIrregularItemInfo ? irregularInfo.value().mainEnd : childItemProperty->GetMainEnd(gridLayoutInfo_.axis_);
862         auto chidCrossStart = hasIrregularItemInfo ? irregularInfo.value().crossStart
863                                                    : childItemProperty->GetCrossStart(gridLayoutInfo_.axis_);
864         auto chidCrossEnd = hasIrregularItemInfo ? irregularInfo.value().crossEnd
865                                                  : childItemProperty->GetCrossEnd(gridLayoutInfo_.axis_);
866         auto childCrossSpan = hasIrregularItemInfo ? irregularInfo.value().crossSpan
867                                                    : childItemProperty->GetCrossSpan(gridLayoutInfo_.axis_);
868         auto childMainSpan = hasIrregularItemInfo ? irregularInfo.value().mainSpan
869                                                   : childItemProperty->GetMainSpan(gridLayoutInfo_.axis_);
870 
871         GridItemIndexInfo childInfo;
872         childInfo.mainIndex = childMainIndex;
873         childInfo.crossIndex = childCrossIndex;
874         childInfo.mainStart = childMainStart;
875         childInfo.mainEnd = childMainEnd;
876         childInfo.crossStart = chidCrossStart;
877         childInfo.crossEnd = chidCrossEnd;
878 
879         if (childMainIndex < 0 || childCrossIndex < 0) {
880             continue;
881         }
882 
883         if ((isLeftStep_ && ((childCrossIndex == tarCrossIndex && childCrossSpan == 1) ||
884                                 (chidCrossEnd >= 0 && chidCrossEnd == tarCrossIndex))) ||
885             (isRightStep_ && childCrossIndex == tarCrossIndex)) {
886             double nearestDistance = GetNearestDistanceFromChildToCurFocusItemInMainAxis(tarCrossIndex, childInfo);
887             int32_t intersectAreaSize = CalcIntersectAreaInTargetDirectionShadow(childInfo, true);
888             if (LessNotEqual(nearestDistance, minDistance) ||
889                 (NearEqual(nearestDistance, minDistance) && intersectAreaSize > maxAreaInCrossShadow) ||
890                 (NearEqual(nearestDistance, minDistance) && intersectAreaSize == maxAreaInCrossShadow &&
891                     childMainIndex < minMainIndex)) {
892                 minDistance = nearestDistance;
893                 maxAreaInCrossShadow = intersectAreaSize;
894                 minMainIndex = childMainIndex;
895                 targetFocusHubWeak = AceType::WeakClaim(AceType::RawPtr(childFocus));
896             }
897         } else if ((isUpStep_ && childMainIndex == tarMainIndex) ||
898                    (isDownStep_ && ((childMainIndex == tarMainIndex && childMainSpan == 1) ||
899                                        (childMainStart >= 0 && childMainStart == tarMainIndex)))) {
900             double nearestDistance = GetNearestDistanceFromChildToCurFocusItemInCrossAxis(tarMainIndex, childInfo);
901             int32_t intersectAreaSize = CalcIntersectAreaInTargetDirectionShadow(childInfo, false);
902             if (LessNotEqual(nearestDistance, minDistance) ||
903                 (NearEqual(nearestDistance, minDistance) && intersectAreaSize > maxAreaInMainShadow) ||
904                 (NearEqual(nearestDistance, minDistance) && intersectAreaSize == maxAreaInMainShadow &&
905                     childCrossIndex < minCrossIndex)) {
906                 minDistance = nearestDistance;
907                 minCrossIndex = childCrossIndex;
908                 maxAreaInMainShadow = intersectAreaSize;
909                 targetFocusHubWeak = AceType::WeakClaim(AceType::RawPtr(childFocus));
910             }
911         } else if ((isLeftEndStep_ || isRightEndStep_) &&
912                    ((tarMainIndex == childMainIndex && tarCrossIndex == childCrossIndex) ||
913                        (childMainStart >= 0 && childMainStart <= tarMainIndex && tarMainIndex <= childMainIndex &&
914                            tarCrossIndex == childCrossIndex))) {
915             targetFocusHubWeak = AceType::WeakClaim(AceType::RawPtr(childFocus));
916         }
917     }
918     ResetAllDirectionsStep();
919     return targetFocusHubWeak;
920 }
921 
CalcIntersectAreaInTargetDirectionShadow(GridItemIndexInfo itemIndexInfo,bool isFindInMainAxis)922 int32_t GridPattern::CalcIntersectAreaInTargetDirectionShadow(GridItemIndexInfo itemIndexInfo, bool isFindInMainAxis)
923 {
924     int32_t curFocusLeftTopX = -1;
925     int32_t curFocusLeftTopY = -1;
926     int32_t curFocusRightBottonX = -1;
927     int32_t curFocusRightBottonY = -1;
928 
929     if (isFindInMainAxis) {
930         curFocusLeftTopX =
931             curFocusIndexInfo_.mainStart == -1 ? curFocusIndexInfo_.mainIndex : curFocusIndexInfo_.mainStart;
932         curFocusLeftTopY = 0;
933         curFocusRightBottonX =
934             curFocusIndexInfo_.mainEnd == -1 ? curFocusIndexInfo_.mainIndex : curFocusIndexInfo_.mainEnd;
935         curFocusRightBottonY = GetCrossCount();
936     } else {
937         curFocusLeftTopX = gridLayoutInfo_.startMainLineIndex_;
938         curFocusLeftTopY =
939             curFocusIndexInfo_.crossStart == -1 ? curFocusIndexInfo_.crossIndex : curFocusIndexInfo_.crossStart;
940         curFocusRightBottonX = gridLayoutInfo_.endMainLineIndex_;
941         curFocusRightBottonY =
942             curFocusIndexInfo_.crossEnd == -1 ? curFocusIndexInfo_.crossIndex : curFocusIndexInfo_.crossEnd;
943     }
944     int32_t childLeftTopX = itemIndexInfo.mainStart == -1 ? itemIndexInfo.mainIndex : itemIndexInfo.mainStart;
945     int32_t childLeftTopY = itemIndexInfo.crossStart == -1 ? itemIndexInfo.crossIndex : itemIndexInfo.crossStart;
946     int32_t childRightBottonX = itemIndexInfo.mainEnd == -1 ? itemIndexInfo.mainIndex : itemIndexInfo.mainEnd;
947     int32_t childRightBottonY = itemIndexInfo.crossEnd == -1 ? itemIndexInfo.crossIndex : itemIndexInfo.crossEnd;
948 
949     int32_t intersectAreaLeftTopX = std::max(curFocusLeftTopX, childLeftTopX);
950     int32_t intersectAreaLeftTopY = std::max(curFocusLeftTopY, childLeftTopY);
951     int32_t intersectAreaRightBottonX = std::min(curFocusRightBottonX, childRightBottonX);
952     int32_t intersectAreaRightBottonY = std::min(curFocusRightBottonY, childRightBottonY);
953 
954     int32_t intersectWidth = intersectAreaRightBottonX - intersectAreaLeftTopX + 1;
955     int32_t intersectHeight = intersectAreaRightBottonY - intersectAreaLeftTopY + 1;
956 
957     return (intersectWidth < 0 || intersectHeight < 0) ? -1 : intersectWidth * intersectHeight;
958 }
959 
GetNearestDistanceFromChildToCurFocusItemInMainAxis(int32_t targetIndex,GridItemIndexInfo itemIndexInfo)960 double GridPattern::GetNearestDistanceFromChildToCurFocusItemInMainAxis(
961     int32_t targetIndex, GridItemIndexInfo itemIndexInfo)
962 {
963     double minDistance = std::numeric_limits<double>::max();
964     auto mainAxisIndex =
965         curFocusIndexInfo_.mainStart == -1 ? curFocusIndexInfo_.mainIndex : curFocusIndexInfo_.mainStart;
966     auto mainAxisEndIndex =
967         curFocusIndexInfo_.mainEnd == -1 ? curFocusIndexInfo_.mainIndex : curFocusIndexInfo_.mainEnd;
968     for (int32_t i = mainAxisIndex; i <= mainAxisEndIndex; i++) {
969         double childMainIndexDistance =
970             CalcCoordinatesDistance(i, curFocusIndexInfo_.crossIndex, itemIndexInfo.mainIndex, targetIndex);
971         double childMainStartDistance =
972             itemIndexInfo.mainStart == -1
973                 ? std::numeric_limits<double>::max()
974                 : CalcCoordinatesDistance(i, curFocusIndexInfo_.crossIndex, itemIndexInfo.mainStart, targetIndex);
975         double distance = std::min(childMainIndexDistance, childMainStartDistance);
976         if (LessNotEqual(distance, minDistance)) {
977             minDistance = distance;
978         }
979     }
980     return minDistance;
981 }
982 
GetNearestDistanceFromChildToCurFocusItemInCrossAxis(int32_t targetIndex,GridItemIndexInfo itemIndexInfo)983 double GridPattern::GetNearestDistanceFromChildToCurFocusItemInCrossAxis(
984     int32_t targetIndex, GridItemIndexInfo itemIndexInfo)
985 {
986     double minDistance = std::numeric_limits<double>::max();
987     auto crossAxisIndex =
988         curFocusIndexInfo_.crossStart == -1 ? curFocusIndexInfo_.crossIndex : curFocusIndexInfo_.crossStart;
989     auto crossAxisEndIndex =
990         curFocusIndexInfo_.crossEnd == -1 ? curFocusIndexInfo_.crossIndex : curFocusIndexInfo_.crossEnd;
991     for (int32_t i = crossAxisIndex; i <= crossAxisEndIndex; i++) {
992         double childCrossIndexDistance =
993             CalcCoordinatesDistance(curFocusIndexInfo_.mainIndex, i, targetIndex, itemIndexInfo.crossIndex);
994         double childCrossEndDistance =
995             itemIndexInfo.crossEnd == -1
996                 ? std::numeric_limits<double>::max()
997                 : CalcCoordinatesDistance(curFocusIndexInfo_.mainIndex, i, targetIndex, itemIndexInfo.crossEnd);
998         double distance = std::min(childCrossIndexDistance, childCrossEndDistance);
999         if (LessNotEqual(distance, minDistance)) {
1000             minDistance = distance;
1001         }
1002     }
1003     return minDistance;
1004 }
1005 
ResetAllDirectionsStep()1006 void GridPattern::ResetAllDirectionsStep()
1007 {
1008     isLeftStep_ = false;
1009     isRightStep_ = false;
1010     isUpStep_ = false;
1011     isDownStep_ = false;
1012     isLeftEndStep_ = false;
1013     isRightEndStep_ = false;
1014 }
1015 
GetChildFocusNodeByIndex(int32_t tarMainIndex,int32_t tarCrossIndex,int32_t tarIndex)1016 WeakPtr<FocusHub> GridPattern::GetChildFocusNodeByIndex(int32_t tarMainIndex, int32_t tarCrossIndex, int32_t tarIndex)
1017 {
1018     auto gridFrame = GetHost();
1019     CHECK_NULL_RETURN(gridFrame, nullptr);
1020     auto gridFocus = gridFrame->GetFocusHub();
1021     CHECK_NULL_RETURN(gridFocus, nullptr);
1022     auto childFocusList = gridFocus->GetChildren();
1023     for (const auto& childFocus : childFocusList) {
1024         auto childFrame = childFocus->GetFrameNode();
1025         if (!childFrame) {
1026             continue;
1027         }
1028         auto childPattern = childFrame->GetPattern();
1029         if (!childPattern) {
1030             continue;
1031         }
1032         auto childItemPattern = AceType::DynamicCast<GridItemPattern>(childPattern);
1033         if (!childItemPattern) {
1034             continue;
1035         }
1036         auto childItemProperty = childItemPattern->GetLayoutProperty<GridItemLayoutProperty>();
1037         if (!childItemProperty) {
1038             continue;
1039         }
1040         auto curMainIndex = childItemProperty->GetMainIndex().value_or(-1);
1041         auto curCrossIndex = childItemProperty->GetCrossIndex().value_or(-1);
1042         if (tarIndex < 0) {
1043             auto curMainSpan = childItemProperty->GetMainSpan(gridLayoutInfo_.axis_);
1044             auto curCrossSpan = childItemProperty->GetCrossSpan(gridLayoutInfo_.axis_);
1045             if (curMainIndex <= tarMainIndex && curMainIndex + curMainSpan > tarMainIndex &&
1046                 curCrossIndex <= tarCrossIndex && curCrossIndex + curCrossSpan > tarCrossIndex) {
1047                 return AceType::WeakClaim(AceType::RawPtr(childFocus));
1048             }
1049         } else {
1050             if (gridLayoutInfo_.gridMatrix_.find(curMainIndex) == gridLayoutInfo_.gridMatrix_.end()) {
1051                 TAG_LOGW(AceLogTag::ACE_GRID, "Can not find target main index: %{public}d", curMainIndex);
1052                 continue;
1053             }
1054             if (gridLayoutInfo_.gridMatrix_[curMainIndex].find(curCrossIndex) ==
1055                 gridLayoutInfo_.gridMatrix_[curMainIndex].end()) {
1056                 TAG_LOGW(AceLogTag::ACE_GRID, "Can not find target cross index: %{public}d", curCrossIndex);
1057                 continue;
1058             }
1059             if (gridLayoutInfo_.gridMatrix_[curMainIndex][curCrossIndex] == tarIndex) {
1060                 return AceType::WeakClaim(AceType::RawPtr(childFocus));
1061             }
1062         }
1063     }
1064     return nullptr;
1065 }
1066 
GetFocusableChildCrossIndexesAt(int32_t tarMainIndex)1067 std::unordered_set<int32_t> GridPattern::GetFocusableChildCrossIndexesAt(int32_t tarMainIndex)
1068 {
1069     std::unordered_set<int32_t> result;
1070     auto gridFrame = GetHost();
1071     CHECK_NULL_RETURN(gridFrame, result);
1072     auto gridFocus = gridFrame->GetFocusHub();
1073     CHECK_NULL_RETURN(gridFocus, result);
1074     auto childFocusList = gridFocus->GetChildren();
1075     for (const auto& childFocus : childFocusList) {
1076         if (!childFocus->IsFocusable()) {
1077             continue;
1078         }
1079         auto childFrame = childFocus->GetFrameNode();
1080         if (!childFrame) {
1081             continue;
1082         }
1083         auto childPattern = childFrame->GetPattern();
1084         if (!childPattern) {
1085             continue;
1086         }
1087         auto childItemPattern = AceType::DynamicCast<GridItemPattern>(childPattern);
1088         if (!childItemPattern) {
1089             continue;
1090         }
1091         auto childItemProperty = childItemPattern->GetLayoutProperty<GridItemLayoutProperty>();
1092         if (!childItemProperty) {
1093             continue;
1094         }
1095         auto irregularInfo = childItemPattern->GetIrregularItemInfo();
1096         bool hasIrregularItemInfo = irregularInfo.has_value();
1097         auto curMainIndex = childItemProperty->GetMainIndex().value_or(-1);
1098         auto curCrossIndex = childItemProperty->GetCrossIndex().value_or(-1);
1099         auto curMainStart = hasIrregularItemInfo ? irregularInfo.value().mainStart
1100                                                  : childItemProperty->GetMainStart(gridLayoutInfo_.axis_);
1101         auto curMainEnd =
1102             hasIrregularItemInfo ? irregularInfo.value().mainEnd : childItemProperty->GetMainEnd(gridLayoutInfo_.axis_);
1103         if ((curMainIndex == tarMainIndex) ||
1104             (curMainStart >= 0 && curMainStart <= tarMainIndex && tarMainIndex <= curMainEnd)) {
1105             result.emplace(curCrossIndex);
1106         }
1107     }
1108     std::string output;
1109     for (const auto& index : result) {
1110         output += std::to_string(index);
1111     }
1112     return result;
1113 }
1114 
ScrollToFocusNode(const WeakPtr<FocusHub> & focusNode)1115 void GridPattern::ScrollToFocusNode(const WeakPtr<FocusHub>& focusNode)
1116 {
1117     auto nextFocus = focusNode.Upgrade();
1118     CHECK_NULL_VOID(nextFocus);
1119     UpdateStartIndex(GetFocusNodeIndex(nextFocus));
1120 }
1121 
GetFocusNodeIndex(const RefPtr<FocusHub> & focusNode)1122 int32_t GridPattern::GetFocusNodeIndex(const RefPtr<FocusHub>& focusNode)
1123 {
1124     auto tarFrame = focusNode->GetFrameNode();
1125     CHECK_NULL_RETURN(tarFrame, -1);
1126     auto tarPattern = tarFrame->GetPattern();
1127     CHECK_NULL_RETURN(tarPattern, -1);
1128     auto tarItemPattern = AceType::DynamicCast<GridItemPattern>(tarPattern);
1129     CHECK_NULL_RETURN(tarItemPattern, -1);
1130     auto tarItemProperty = tarItemPattern->GetLayoutProperty<GridItemLayoutProperty>();
1131     CHECK_NULL_RETURN(tarItemProperty, -1);
1132     auto tarMainIndex = tarItemProperty->GetMainIndex().value_or(-1);
1133     auto tarCrossIndex = tarItemProperty->GetCrossIndex().value_or(-1);
1134     if (gridLayoutInfo_.gridMatrix_.find(tarMainIndex) == gridLayoutInfo_.gridMatrix_.end()) {
1135         TAG_LOGW(AceLogTag::ACE_GRID, "Can not find target main index: %{public}d", tarMainIndex);
1136         if (tarMainIndex == 0) {
1137             return 0;
1138         }
1139         return gridLayoutInfo_.childrenCount_ - 1;
1140     }
1141     if (gridLayoutInfo_.gridMatrix_[tarMainIndex].find(tarCrossIndex) ==
1142         gridLayoutInfo_.gridMatrix_[tarMainIndex].end()) {
1143         TAG_LOGW(AceLogTag::ACE_GRID, "Can not find target cross index: %{public}d", tarCrossIndex);
1144         if (tarMainIndex == 0) {
1145             return 0;
1146         }
1147         return gridLayoutInfo_.childrenCount_ - 1;
1148     }
1149     return gridLayoutInfo_.gridMatrix_[tarMainIndex][tarCrossIndex];
1150 }
1151 
ScrollToFocusNodeIndex(int32_t index)1152 void GridPattern::ScrollToFocusNodeIndex(int32_t index)
1153 {
1154     UpdateStartIndex(index);
1155     auto pipeline = PipelineContext::GetCurrentContext();
1156     if (pipeline) {
1157         pipeline->FlushUITasks();
1158     }
1159     auto tarFocusNodeWeak = GetChildFocusNodeByIndex(-1, -1, index);
1160     auto tarFocusNode = tarFocusNodeWeak.Upgrade();
1161     if (tarFocusNode) {
1162         tarFocusNode->RequestFocusImmediately();
1163     }
1164 }
1165 
ScrollToNode(const RefPtr<FrameNode> & focusFrameNode)1166 bool GridPattern::ScrollToNode(const RefPtr<FrameNode>& focusFrameNode)
1167 {
1168     CHECK_NULL_RETURN(focusFrameNode, false);
1169     auto focusHub = focusFrameNode->GetFocusHub();
1170     CHECK_NULL_RETURN(focusHub, false);
1171     auto scrollToIndex = GetFocusNodeIndex(focusHub);
1172     if (scrollToIndex < 0) {
1173         return false;
1174     }
1175     auto ret = UpdateStartIndex(scrollToIndex);
1176     auto pipeline = PipelineContext::GetCurrentContext();
1177     if (pipeline) {
1178         pipeline->FlushUITasks();
1179     }
1180     return ret;
1181 }
1182 
ScrollBy(float offset)1183 void GridPattern::ScrollBy(float offset)
1184 {
1185     StopAnimate();
1186     UpdateCurrentOffset(-offset, SCROLL_FROM_JUMP);
1187     // AccessibilityEventType::SCROLL_END
1188 }
1189 
ToJsonValue(std::unique_ptr<JsonValue> & json) const1190 void GridPattern::ToJsonValue(std::unique_ptr<JsonValue>& json) const
1191 {
1192     ScrollablePattern::ToJsonValue(json);
1193     json->Put("multiSelectable", multiSelectable_ ? "true" : "false");
1194     json->Put("supportAnimation", supportAnimation_ ? "true" : "false");
1195 }
1196 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)1197 void GridPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
1198 {
1199     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
1200         auto pattern = wp.Upgrade();
1201         if (pattern) {
1202             return pattern->OnKeyEvent(event);
1203         }
1204         return false;
1205     };
1206     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
1207 }
1208 
OnKeyEvent(const KeyEvent & event)1209 bool GridPattern::OnKeyEvent(const KeyEvent& event)
1210 {
1211     if (event.action != KeyAction::DOWN) {
1212         return false;
1213     }
1214     if ((event.code == KeyCode::KEY_PAGE_DOWN) || (event.code == KeyCode::KEY_PAGE_UP)) {
1215         ScrollPage(event.code == KeyCode::KEY_PAGE_UP);
1216     }
1217     return false;
1218 }
1219 
HandleDirectionKey(KeyCode code)1220 bool GridPattern::HandleDirectionKey(KeyCode code)
1221 {
1222     if (code == KeyCode::KEY_DPAD_UP) {
1223         // Need to update: current selection
1224         return true;
1225     }
1226     if (code == KeyCode::KEY_DPAD_DOWN) {
1227         // Need to update: current selection
1228         return true;
1229     }
1230     return false;
1231 }
1232 
ScrollPage(bool reverse)1233 void GridPattern::ScrollPage(bool reverse)
1234 {
1235     StopAnimate();
1236     if (!isConfigScrollable_) {
1237         return;
1238     }
1239     if (!reverse) {
1240         UpdateCurrentOffset(-GetMainContentSize(), SCROLL_FROM_JUMP);
1241     } else {
1242         UpdateCurrentOffset(GetMainContentSize(), SCROLL_FROM_JUMP);
1243     }
1244     // AccessibilityEventType::SCROLL_END
1245 }
1246 
UpdateStartIndex(int32_t index)1247 bool GridPattern::UpdateStartIndex(int32_t index)
1248 {
1249     if (!isConfigScrollable_) {
1250         return false;
1251     }
1252     auto host = GetHost();
1253     CHECK_NULL_RETURN(host, false);
1254     gridLayoutInfo_.jumpIndex_ = index;
1255     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1256     // AccessibilityEventType::SCROLL_END
1257     SetScrollSource(SCROLL_FROM_JUMP);
1258     return true;
1259 }
1260 
UpdateStartIndex(int32_t index,ScrollAlign align)1261 bool GridPattern::UpdateStartIndex(int32_t index, ScrollAlign align)
1262 {
1263     gridLayoutInfo_.scrollAlign_ = align;
1264     return UpdateStartIndex(index);
1265 }
1266 
OnAnimateStop()1267 void GridPattern::OnAnimateStop()
1268 {
1269     scrollStop_ = true;
1270     MarkDirtyNodeSelf();
1271     // AccessibilityEventType::SCROLL_END
1272 }
1273 
AnimateTo(float position,float duration,const RefPtr<Curve> & curve,bool smooth,bool canOverScroll)1274 void GridPattern::AnimateTo(float position, float duration, const RefPtr<Curve>& curve, bool smooth, bool canOverScroll)
1275 {
1276     if (!isConfigScrollable_) {
1277         return;
1278     }
1279     ScrollablePattern::AnimateTo(position, duration, curve, smooth, canOverScroll);
1280 }
1281 
ScrollTo(float position)1282 void GridPattern::ScrollTo(float position)
1283 {
1284     if (!isConfigScrollable_) {
1285         return;
1286     }
1287     TAG_LOGI(AceLogTag::ACE_GRID, "ScrollTo:%{public}f", position);
1288     StopAnimate();
1289     UpdateCurrentOffset(GetTotalOffset() - position, SCROLL_FROM_JUMP);
1290     // AccessibilityEventType::SCROLL_END
1291 }
1292 
EstimateHeight() const1293 float GridPattern::EstimateHeight() const
1294 {
1295     if (!isConfigScrollable_) {
1296         return 0.0f;
1297     }
1298     // During the scrolling animation, the exact current position is used. Other times use the estimated location
1299     if (isSmoothScrolling_) {
1300         auto lineIndex = 0;
1301         scrollGridLayoutInfo_.GetLineIndexByIndex(gridLayoutInfo_.startIndex_, lineIndex);
1302         return scrollGridLayoutInfo_.GetTotalHeightFromZeroIndex(lineIndex, GetMainGap()) -
1303                gridLayoutInfo_.currentOffset_;
1304     } else {
1305         auto host = GetHost();
1306         CHECK_NULL_RETURN(host, 0.0);
1307         auto geometryNode = host->GetGeometryNode();
1308         CHECK_NULL_RETURN(geometryNode, 0.0);
1309         const auto& info = gridLayoutInfo_;
1310         auto viewScopeSize = geometryNode->GetPaddingSize();
1311         auto layoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
1312         auto mainGap = GridUtils::GetMainGap(layoutProperty, viewScopeSize, info.axis_);
1313         if (!layoutProperty->GetLayoutOptions().has_value()) {
1314             return info.GetContentOffset(mainGap);
1315         }
1316 
1317         return info.GetContentOffset(layoutProperty->GetLayoutOptions().value(), mainGap);
1318     }
1319 }
1320 
GetAverageHeight() const1321 float GridPattern::GetAverageHeight() const
1322 {
1323     auto host = GetHost();
1324     CHECK_NULL_RETURN(host, 0.0);
1325     auto geometryNode = host->GetGeometryNode();
1326     CHECK_NULL_RETURN(geometryNode, 0.0);
1327     const auto& info = gridLayoutInfo_;
1328     auto viewScopeSize = geometryNode->GetPaddingSize();
1329     auto layoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
1330 
1331     float heightSum = 0;
1332     int32_t itemCount = 0;
1333     auto mainGap = GridUtils::GetMainGap(layoutProperty, viewScopeSize, info.axis_);
1334     for (const auto& item : info.lineHeightMap_) {
1335         auto line = info.gridMatrix_.find(item.first);
1336         if (line == info.gridMatrix_.end()) {
1337             continue;
1338         }
1339         if (line->second.empty()) {
1340             continue;
1341         }
1342         auto lineStart = line->second.begin()->second;
1343         auto lineEnd = line->second.rbegin()->second;
1344         itemCount += (lineEnd - lineStart + 1);
1345         heightSum += item.second + mainGap;
1346     }
1347     if (itemCount == 0) {
1348         return 0;
1349     }
1350     return heightSum / itemCount;
1351 }
1352 
GetTotalHeight() const1353 float GridPattern::GetTotalHeight() const
1354 {
1355     if (scrollbarInfo_.first.has_value() && scrollbarInfo_.second.has_value()) {
1356         return scrollbarInfo_.second.value();
1357     }
1358     auto host = GetHost();
1359     CHECK_NULL_RETURN(host, 0.0f);
1360     auto geometryNode = host->GetGeometryNode();
1361     CHECK_NULL_RETURN(geometryNode, 0.0f);
1362     auto viewScopeSize = geometryNode->GetPaddingSize();
1363     auto layoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
1364     auto mainGap = GridUtils::GetMainGap(layoutProperty, viewScopeSize, gridLayoutInfo_.axis_);
1365     return gridLayoutInfo_.GetContentHeight(mainGap);
1366 }
1367 
UpdateScrollBarOffset()1368 void GridPattern::UpdateScrollBarOffset()
1369 {
1370     if (!GetScrollBar() && !GetScrollBarProxy()) {
1371         return;
1372     }
1373     auto host = GetHost();
1374     CHECK_NULL_VOID(host);
1375     auto geometryNode = host->GetGeometryNode();
1376     CHECK_NULL_VOID(geometryNode);
1377     const auto& info = gridLayoutInfo_;
1378     float offset = 0;
1379     float estimatedHeight = 0.f;
1380     if (scrollbarInfo_.first.has_value() && scrollbarInfo_.second.has_value()) {
1381         offset = scrollbarInfo_.first.value();
1382         estimatedHeight = scrollbarInfo_.second.value();
1383     } else {
1384         auto viewScopeSize = geometryNode->GetPaddingSize();
1385         auto layoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
1386         auto mainGap = GridUtils::GetMainGap(layoutProperty, viewScopeSize, info.axis_);
1387         if (!layoutProperty->GetLayoutOptions().has_value()) {
1388             offset = gridLayoutInfo_.GetContentOffset(mainGap);
1389             estimatedHeight = gridLayoutInfo_.GetContentHeight(mainGap);
1390         } else {
1391             offset = info.GetContentOffset(layoutProperty->GetLayoutOptions().value(), mainGap);
1392             estimatedHeight =
1393                 info.GetContentHeight(layoutProperty->GetLayoutOptions().value(), info.childrenCount_, mainGap);
1394         }
1395     }
1396     if (info.startMainLineIndex_ != 0 && info.startIndex_ == 0) {
1397         for (int32_t lineIndex = info.startMainLineIndex_ - 1; lineIndex >= 0; lineIndex--) {
1398             offset += info.lineHeightMap_.find(lineIndex)->second;
1399         }
1400     }
1401     auto viewSize = geometryNode->GetFrameSize();
1402     auto overScroll = 0.0f;
1403     if (Positive(gridLayoutInfo_.currentOffset_)) {
1404         overScroll = gridLayoutInfo_.currentOffset_;
1405     } else {
1406         overScroll = gridLayoutInfo_.lastMainSize_ - estimatedHeight + offset;
1407         overScroll = Positive(overScroll) ? overScroll : 0.0f;
1408     }
1409     HandleScrollBarOutBoundary(overScroll);
1410     UpdateScrollBarRegion(offset, estimatedHeight, Size(viewSize.Width(), viewSize.Height()), Offset(0.0f, 0.0f));
1411 }
1412 
GetDefaultScrollBarDisplayMode() const1413 DisplayMode GridPattern::GetDefaultScrollBarDisplayMode() const
1414 {
1415     auto defaultDisplayMode = DisplayMode::OFF;
1416     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
1417         defaultDisplayMode = DisplayMode::AUTO;
1418     }
1419     return defaultDisplayMode;
1420 }
1421 
GetOriginalIndex() const1422 int32_t GridPattern::GetOriginalIndex() const
1423 {
1424     return gridLayoutInfo_.GetOriginalIndex();
1425 }
1426 
GetCrossCount() const1427 int32_t GridPattern::GetCrossCount() const
1428 {
1429     return gridLayoutInfo_.crossCount_;
1430 }
1431 
GetChildrenCount() const1432 int32_t GridPattern::GetChildrenCount() const
1433 {
1434     return gridLayoutInfo_.childrenCount_;
1435 }
1436 
ClearDragState()1437 void GridPattern::ClearDragState()
1438 {
1439     gridLayoutInfo_.ClearDragState();
1440     MarkDirtyNodeSelf();
1441 }
1442 
UpdateRectOfDraggedInItem(int32_t insertIndex)1443 void GridPattern::UpdateRectOfDraggedInItem(int32_t insertIndex)
1444 {
1445     auto host = GetHost();
1446     CHECK_NULL_VOID(host);
1447     std::list<RefPtr<FrameNode>> children;
1448     host->GenerateOneDepthAllFrame(children);
1449     for (const auto& item : children) {
1450         auto itemPattern = item->GetPattern<GridItemPattern>();
1451         CHECK_NULL_VOID(itemPattern);
1452         auto itemProperty = itemPattern->GetLayoutProperty<GridItemLayoutProperty>();
1453         CHECK_NULL_VOID(itemProperty);
1454         auto mainIndex = itemProperty->GetMainIndex().value_or(-1);
1455         auto crossIndex = itemProperty->GetCrossIndex().value_or(-1);
1456         if (mainIndex * gridLayoutInfo_.crossCount_ + crossIndex == insertIndex) {
1457             auto size = item->GetRenderContext()->GetPaintRectWithTransform();
1458             size.SetOffset(item->GetTransformRelativeOffset());
1459             gridLayoutInfo_.currentRect_ = size;
1460             break;
1461         }
1462     }
1463 }
1464 
MoveItems(int32_t itemIndex,int32_t insertIndex)1465 void GridPattern::MoveItems(int32_t itemIndex, int32_t insertIndex)
1466 {
1467     if (insertIndex < 0 ||
1468         insertIndex >= ((itemIndex == -1) ? (gridLayoutInfo_.childrenCount_ + 1) : gridLayoutInfo_.childrenCount_)) {
1469         return;
1470     }
1471 
1472     if (itemIndex == -1) {
1473         UpdateRectOfDraggedInItem(insertIndex);
1474     }
1475 
1476     gridLayoutInfo_.SwapItems(itemIndex, insertIndex);
1477 
1478     auto host = GetHost();
1479     CHECK_NULL_VOID(host);
1480     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1481     auto pipeline = PipelineContext::GetCurrentContext();
1482     if (pipeline) {
1483         pipeline->FlushUITasks();
1484     }
1485 }
1486 
IsOutOfBoundary(bool useCurrentDelta)1487 bool GridPattern::IsOutOfBoundary(bool useCurrentDelta)
1488 {
1489     auto scrollable = GetAlwaysEnabled() || (gridLayoutInfo_.startIndex_ > 0) ||
1490                       (gridLayoutInfo_.endIndex_ < gridLayoutInfo_.childrenCount_ - 1) ||
1491                       GreatNotEqual(gridLayoutInfo_.totalHeightOfItemsInView_, gridLayoutInfo_.lastMainSize_);
1492     return scrollable && (gridLayoutInfo_.IsOutOfStart() || gridLayoutInfo_.IsOutOfEnd());
1493 }
1494 
GetEndOffset()1495 float GridPattern::GetEndOffset()
1496 {
1497     float contentHeight = gridLayoutInfo_.lastMainSize_ - gridLayoutInfo_.contentEndPadding_;
1498     float mainGap = GetMainGap();
1499     if (GetAlwaysEnabled() &&
1500         GreatNotEqual(contentHeight, gridLayoutInfo_.GetTotalLineHeight(mainGap))) {
1501         return gridLayoutInfo_.GetTotalLineHeight(mainGap) -
1502                 gridLayoutInfo_.GetTotalHeightOfItemsInView(mainGap);
1503     }
1504     return contentHeight - gridLayoutInfo_.GetTotalHeightOfItemsInView(mainGap);
1505 }
1506 
SetEdgeEffectCallback(const RefPtr<ScrollEdgeEffect> & scrollEffect)1507 void GridPattern::SetEdgeEffectCallback(const RefPtr<ScrollEdgeEffect>& scrollEffect)
1508 {
1509     scrollEffect->SetCurrentPositionCallback([weak = AceType::WeakClaim(this)]() -> double {
1510         auto grid = weak.Upgrade();
1511         CHECK_NULL_RETURN(grid, 0.0);
1512         return grid->gridLayoutInfo_.currentOffset_;
1513     });
1514     scrollEffect->SetLeadingCallback([weak = AceType::WeakClaim(this)]() -> double {
1515         auto grid = weak.Upgrade();
1516         CHECK_NULL_RETURN(grid, 0.0);
1517         return grid->GetEndOffset();
1518     });
1519     scrollEffect->SetTrailingCallback([]() -> double { return 0.0; });
1520     scrollEffect->SetInitLeadingCallback([weak = AceType::WeakClaim(this)]() -> double {
1521         auto grid = weak.Upgrade();
1522         CHECK_NULL_RETURN(grid, 0.0);
1523         return grid->GetEndOffset();
1524     });
1525     scrollEffect->SetInitTrailingCallback([]() -> double { return 0.0; });
1526 }
1527 
OutBoundaryCallback()1528 bool GridPattern::OutBoundaryCallback()
1529 {
1530     return IsOutOfBoundary();
1531 }
1532 
GetOverScrollOffset(double delta) const1533 OverScrollOffset GridPattern::GetOverScrollOffset(double delta) const
1534 {
1535     OverScrollOffset offset = { 0, 0 };
1536     if (gridLayoutInfo_.startIndex_ == 0) {
1537         auto startPos = gridLayoutInfo_.currentOffset_;
1538         auto newStartPos = startPos + delta;
1539         if (startPos > 0 && newStartPos > 0) {
1540             offset.start = delta;
1541         }
1542         if (startPos > 0 && newStartPos <= 0) {
1543             offset.start = -startPos;
1544         }
1545         if (startPos <= 0 && newStartPos > 0) {
1546             offset.start = newStartPos;
1547         }
1548     }
1549     if (gridLayoutInfo_.endIndex_ == gridLayoutInfo_.childrenCount_ - 1) {
1550         auto endPos = gridLayoutInfo_.currentOffset_ + gridLayoutInfo_.totalHeightOfItemsInView_;
1551         if (GreatNotEqual(GetMainContentSize(),
1552             gridLayoutInfo_.currentOffset_ + gridLayoutInfo_.totalHeightOfItemsInView_)) {
1553             endPos = gridLayoutInfo_.currentOffset_ + GetMainContentSize();
1554         }
1555         auto newEndPos = endPos + delta;
1556         if (endPos < gridLayoutInfo_.lastMainSize_ && newEndPos < gridLayoutInfo_.lastMainSize_) {
1557             offset.end = delta;
1558         }
1559         if (endPos < gridLayoutInfo_.lastMainSize_ && newEndPos >= gridLayoutInfo_.lastMainSize_) {
1560             offset.end = gridLayoutInfo_.lastMainSize_ - endPos;
1561         }
1562         if (endPos >= gridLayoutInfo_.lastMainSize_ && newEndPos < gridLayoutInfo_.lastMainSize_) {
1563             offset.end = newEndPos - gridLayoutInfo_.lastMainSize_;
1564         }
1565     }
1566     return offset;
1567 }
1568 
SetAccessibilityAction()1569 void GridPattern::SetAccessibilityAction()
1570 {
1571     auto host = GetHost();
1572     CHECK_NULL_VOID(host);
1573     auto accessibilityProperty = host->GetAccessibilityProperty<AccessibilityProperty>();
1574     CHECK_NULL_VOID(accessibilityProperty);
1575     accessibilityProperty->SetActionScrollForward([weakPtr = WeakClaim(this)]() {
1576         const auto& pattern = weakPtr.Upgrade();
1577         CHECK_NULL_VOID(pattern);
1578         if (!pattern->IsScrollable()) {
1579             return;
1580         }
1581         pattern->ScrollPage(false);
1582     });
1583 
1584     accessibilityProperty->SetActionScrollBackward([weakPtr = WeakClaim(this)]() {
1585         const auto& pattern = weakPtr.Upgrade();
1586         CHECK_NULL_VOID(pattern);
1587         if (!pattern->IsScrollable()) {
1588             return;
1589         }
1590         pattern->ScrollPage(true);
1591     });
1592 }
1593 
DumpAdvanceInfo()1594 void GridPattern::DumpAdvanceInfo()
1595 {
1596     auto property = GetLayoutProperty<GridLayoutProperty>();
1597     CHECK_NULL_VOID(property);
1598     supportAnimation_ ? DumpLog::GetInstance().AddDesc("supportAnimation:true")
1599                       : DumpLog::GetInstance().AddDesc("supportAnimation:false");
1600     isConfigScrollable_ ? DumpLog::GetInstance().AddDesc("isConfigScrollable:true")
1601                         : DumpLog::GetInstance().AddDesc("isConfigScrollable:false");
1602     scrollable_ ? DumpLog::GetInstance().AddDesc("scrollable:true")
1603                 : DumpLog::GetInstance().AddDesc("scrollable:false");
1604     gridLayoutInfo_.lastCrossCount_.has_value()
1605         ? DumpLog::GetInstance().AddDesc("lastCrossCount:" + std::to_string(gridLayoutInfo_.lastCrossCount_.value()))
1606         : DumpLog::GetInstance().AddDesc("lastCrossCount:null");
1607     gridLayoutInfo_.reachEnd_ ? DumpLog::GetInstance().AddDesc("reachEnd:true")
1608                               : DumpLog::GetInstance().AddDesc("reachEnd:false");
1609     gridLayoutInfo_.reachStart_ ? DumpLog::GetInstance().AddDesc("reachStart:true")
1610                                 : DumpLog::GetInstance().AddDesc("reachStart:false");
1611     gridLayoutInfo_.offsetEnd_ ? DumpLog::GetInstance().AddDesc("offsetEnd:true")
1612                                : DumpLog::GetInstance().AddDesc("offsetEnd:false");
1613     gridLayoutInfo_.hasBigItem_ ? DumpLog::GetInstance().AddDesc("hasBigItem:true")
1614                                 : DumpLog::GetInstance().AddDesc("hasBigItem:false");
1615     gridLayoutInfo_.offsetUpdated_ ? DumpLog::GetInstance().AddDesc("offsetUpdated:true")
1616                                    : DumpLog::GetInstance().AddDesc("offsetUpdated:false");
1617     DumpLog::GetInstance().AddDesc("scrollStop:" + std::to_string(scrollStop_));
1618     DumpLog::GetInstance().AddDesc("prevHeight:" + std::to_string(prevHeight_));
1619     DumpLog::GetInstance().AddDesc("currentHeight:" + std::to_string(currentHeight_));
1620     DumpLog::GetInstance().AddDesc("endHeight:" + std::to_string(endHeight_));
1621     DumpLog::GetInstance().AddDesc("currentOffset:" + std::to_string(gridLayoutInfo_.currentOffset_));
1622     DumpLog::GetInstance().AddDesc("prevOffset:" + std::to_string(gridLayoutInfo_.prevOffset_));
1623     DumpLog::GetInstance().AddDesc("lastMainSize:" + std::to_string(gridLayoutInfo_.lastMainSize_));
1624     DumpLog::GetInstance().AddDesc(
1625         "totalHeightOfItemsInView:" + std::to_string(gridLayoutInfo_.totalHeightOfItemsInView_));
1626     DumpLog::GetInstance().AddDesc("startIndex:" + std::to_string(gridLayoutInfo_.startIndex_));
1627     DumpLog::GetInstance().AddDesc("endIndex:" + std::to_string(gridLayoutInfo_.endIndex_));
1628     DumpLog::GetInstance().AddDesc("jumpIndex:" + std::to_string(gridLayoutInfo_.jumpIndex_));
1629     DumpLog::GetInstance().AddDesc("crossCount:" + std::to_string(gridLayoutInfo_.crossCount_));
1630     DumpLog::GetInstance().AddDesc("childrenCount:" + std::to_string(gridLayoutInfo_.childrenCount_));
1631     DumpLog::GetInstance().AddDesc("RowsTemplate:", property->GetRowsTemplate()->c_str());
1632     DumpLog::GetInstance().AddDesc("ColumnsTemplate:", property->GetColumnsTemplate()->c_str());
1633     property->GetCachedCount().has_value()
1634         ? DumpLog::GetInstance().AddDesc("CachedCount:" + std::to_string(property->GetCachedCount().value()))
1635         : DumpLog::GetInstance().AddDesc("CachedCount:null");
1636     property->GetMaxCount().has_value()
1637         ? DumpLog::GetInstance().AddDesc("MaxCount:" + std::to_string(property->GetMaxCount().value()))
1638         : DumpLog::GetInstance().AddDesc("MaxCount:null");
1639     property->GetMinCount().has_value()
1640         ? DumpLog::GetInstance().AddDesc("MinCount:" + std::to_string(property->GetMinCount().value()))
1641         : DumpLog::GetInstance().AddDesc("MinCount:null");
1642     property->GetCellLength().has_value()
1643         ? DumpLog::GetInstance().AddDesc("CellLength:" + std::to_string(property->GetCellLength().value()))
1644         : DumpLog::GetInstance().AddDesc("CellLength:null");
1645     property->GetEditable().has_value()
1646         ? DumpLog::GetInstance().AddDesc("Editable:" + std::to_string(property->GetEditable().value()))
1647         : DumpLog::GetInstance().AddDesc("Editable:null");
1648     property->GetScrollEnabled().has_value()
1649         ? DumpLog::GetInstance().AddDesc("ScrollEnabled:" + std::to_string(property->GetScrollEnabled().value()))
1650         : DumpLog::GetInstance().AddDesc("ScrollEnabled:null");
1651     switch (gridLayoutInfo_.scrollAlign_) {
1652         case ScrollAlign::NONE: {
1653             DumpLog::GetInstance().AddDesc("ScrollAlign:NONE");
1654             break;
1655         }
1656         case ScrollAlign::CENTER: {
1657             DumpLog::GetInstance().AddDesc("ScrollAlign:CENTER");
1658             break;
1659         }
1660         case ScrollAlign::END: {
1661             DumpLog::GetInstance().AddDesc("ScrollAlign:END");
1662             break;
1663         }
1664         case ScrollAlign::START: {
1665             DumpLog::GetInstance().AddDesc("ScrollAlign:START");
1666             break;
1667         }
1668         case ScrollAlign::AUTO: {
1669             DumpLog::GetInstance().AddDesc("ScrollAlign:AUTO");
1670             break;
1671         }
1672         default: {
1673             break;
1674         }
1675     }
1676     if (!gridLayoutInfo_.gridMatrix_.empty()) {
1677         DumpLog::GetInstance().AddDesc("-----------start print gridMatrix------------");
1678         std::string res = std::string("");
1679         for (auto item : gridLayoutInfo_.gridMatrix_) {
1680             res.append(std::to_string(item.first));
1681             res.append(": ");
1682             for (auto index : item.second) {
1683                 res.append("[")
1684                     .append(std::to_string(index.first))
1685                     .append(",")
1686                     .append(std::to_string(index.second))
1687                     .append("] ");
1688             }
1689             DumpLog::GetInstance().AddDesc(res);
1690             res.clear();
1691         }
1692         DumpLog::GetInstance().AddDesc("-----------end print gridMatrix------------");
1693     }
1694     if (!gridLayoutInfo_.lineHeightMap_.empty()) {
1695         DumpLog::GetInstance().AddDesc("-----------start print lineHeightMap------------");
1696         for (auto item : gridLayoutInfo_.lineHeightMap_) {
1697             DumpLog::GetInstance().AddDesc(std::to_string(item.first).append(" :").append(std::to_string(item.second)));
1698         }
1699         DumpLog::GetInstance().AddDesc("-----------end print lineHeightMap------------");
1700     }
1701     if (!gridLayoutInfo_.irregularItemsPosition_.empty()) {
1702         DumpLog::GetInstance().AddDesc("-----------start print irregularItemsPosition_------------");
1703         for (auto item : gridLayoutInfo_.irregularItemsPosition_) {
1704             DumpLog::GetInstance().AddDesc(std::to_string(item.first).append(" :").append(std::to_string(item.second)));
1705         }
1706         DumpLog::GetInstance().AddDesc("-----------end print irregularItemsPosition_------------");
1707     }
1708 }
1709 
ProvideRestoreInfo()1710 std::string GridPattern::ProvideRestoreInfo()
1711 {
1712     return std::to_string(gridLayoutInfo_.startIndex_);
1713 }
1714 
OnRestoreInfo(const std::string & restoreInfo)1715 void GridPattern::OnRestoreInfo(const std::string& restoreInfo)
1716 {
1717     gridLayoutInfo_.jumpIndex_ = StringUtils::StringToInt(restoreInfo);
1718     gridLayoutInfo_.scrollAlign_ = ScrollAlign::START;
1719 }
1720 
GetItemRect(int32_t index) const1721 Rect GridPattern::GetItemRect(int32_t index) const
1722 {
1723     if (index < 0 || index < gridLayoutInfo_.startIndex_ || index > gridLayoutInfo_.endIndex_) {
1724         return Rect();
1725     }
1726     auto host = GetHost();
1727     CHECK_NULL_RETURN(host, Rect());
1728     auto item = host->GetChildByIndex(index);
1729     CHECK_NULL_RETURN(item, Rect());
1730     auto itemGeometry = item->GetGeometryNode();
1731     CHECK_NULL_RETURN(itemGeometry, Rect());
1732     return Rect(itemGeometry->GetFrameRect().GetX(), itemGeometry->GetFrameRect().GetY(),
1733         itemGeometry->GetFrameRect().Width(), itemGeometry->GetFrameRect().Height());
1734 }
1735 
ScrollToIndex(int32_t index,bool smooth,ScrollAlign align)1736 void GridPattern::ScrollToIndex(int32_t index, bool smooth, ScrollAlign align)
1737 {
1738     SetScrollSource(SCROLL_FROM_JUMP);
1739     StopAnimate();
1740     auto host = GetHost();
1741     CHECK_NULL_VOID(host);
1742     int32_t totalChildCount = host->TotalChildCount();
1743     if (((index >= 0) && (index < totalChildCount)) || (index == LAST_ITEM)) {
1744         if (smooth) {
1745             targetIndex_ = index;
1746             scrollAlign_ = align;
1747             host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1748         } else {
1749             UpdateStartIndex(index, align);
1750         }
1751     }
1752     FireAndCleanScrollingListener();
1753 }
1754 
1755 // Turn on the scrolling animation
AnimateToTarget(ScrollAlign align,RefPtr<LayoutAlgorithmWrapper> & layoutAlgorithmWrapper)1756 void GridPattern::AnimateToTarget(ScrollAlign align, RefPtr<LayoutAlgorithmWrapper>& layoutAlgorithmWrapper)
1757 {
1758     if (targetIndex_.has_value()) {
1759         AnimateToTargetImp(align, layoutAlgorithmWrapper);
1760         targetIndex_.reset();
1761     }
1762 }
1763 
1764 // scroll to the item where the index is located
AnimateToTargetImp(ScrollAlign align,RefPtr<LayoutAlgorithmWrapper> & layoutAlgorithmWrapper)1765 bool GridPattern::AnimateToTargetImp(ScrollAlign align, RefPtr<LayoutAlgorithmWrapper>& layoutAlgorithmWrapper)
1766 {
1767     auto gridScrollLayoutAlgorithm =
1768         DynamicCast<GridScrollLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
1769     scrollGridLayoutInfo_ = gridScrollLayoutAlgorithm->GetScrollGridLayoutInfo();
1770 
1771     float targetPos = 0.0f;
1772     // Based on the index, align gets the position to scroll to
1773 
1774     auto sucess = scrollGridLayoutInfo_.GetGridItemAnimatePos(
1775         gridLayoutInfo_, targetIndex_.value(), align, GetMainGap(), targetPos);
1776     CHECK_NULL_RETURN(sucess, false);
1777 
1778     isSmoothScrolling_ = true;
1779     AnimateTo(targetPos, -1, nullptr, true);
1780     return true;
1781 }
1782 
1783 } // namespace OHOS::Ace::NG
1784