• 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/log/dump_log.h"
19 #include "base/perfmonitor/perf_constants.h"
20 #include "base/perfmonitor/perf_monitor.h"
21 #include "core/components_ng/base/observer_handler.h"
22 #include "core/components_ng/pattern/grid/grid_adaptive/grid_adaptive_layout_algorithm.h"
23 #include "core/components_ng/pattern/grid/grid_layout/grid_layout_algorithm.h"
24 #include "core/components_ng/pattern/grid/grid_paint_method.h"
25 #include "core/components_ng/pattern/grid/grid_scroll/grid_scroll_with_options_layout_algorithm.h"
26 #include "core/components_ng/pattern/grid/grid_utils.h"
27 #include "core/components_ng/pattern/grid/irregular/grid_irregular_layout_algorithm.h"
28 #include "core/components_ng/pattern/grid/irregular/grid_layout_utils.h"
29 #include "core/components_ng/pattern/scrollable/scrollable_pattern.h"
30 
31 namespace OHOS::Ace::NG {
32 
33 namespace {
34 const Color ITEM_FILL_COLOR = Color::TRANSPARENT;
35 
36 const int32_t MAX_NUM_SIZE = 4;
37 } // namespace
38 
CreateLayoutAlgorithm()39 RefPtr<LayoutAlgorithm> GridPattern::CreateLayoutAlgorithm()
40 {
41     auto gridLayoutProperty = GetLayoutProperty<GridLayoutProperty>();
42     CHECK_NULL_RETURN(gridLayoutProperty, nullptr);
43     std::vector<std::string> cols;
44     StringUtils::StringSplitter(gridLayoutProperty->GetColumnsTemplate().value_or(""), ' ', cols);
45     std::vector<std::string> rows;
46     StringUtils::StringSplitter(gridLayoutProperty->GetRowsTemplate().value_or(""), ' ', rows);
47 
48     // When rowsTemplate and columnsTemplate is both not setting, use adaptive layout algorithm.
49     if (rows.empty() && cols.empty()) {
50         return MakeRefPtr<GridAdaptiveLayoutAlgorithm>(info_);
51     }
52 
53     auto crossCount = cols.empty() ? Infinity<int32_t>() : static_cast<int32_t>(cols.size());
54     auto mainCount = rows.empty() ? Infinity<int32_t>() : static_cast<int32_t>(rows.size());
55     if (!gridLayoutProperty->IsVertical()) {
56         std::swap(crossCount, mainCount);
57     }
58     info_.crossCount_ = crossCount;
59     if (targetIndex_.has_value()) {
60         info_.targetIndex_ = targetIndex_;
61     }
62     // When rowsTemplate and columnsTemplate is both setting, use static layout algorithm.
63     if (!rows.empty() && !cols.empty()) {
64         return MakeRefPtr<GridLayoutAlgorithm>(info_, crossCount, mainCount);
65     }
66 
67     // If only set one of rowTemplate and columnsTemplate, use scrollable layout algorithm.
68     const bool disableSkip = IsOutOfBoundary(true) || (ScrollablePattern::AnimateRunning() && !IsBackToTopRunning());
69     const bool canOverScrollStart = CanOverScrollStart(GetScrollSource()) || preSpring_;
70     const bool canOverScrollEnd = CanOverScrollEnd(GetScrollSource()) || preSpring_;
71     if (UseIrregularLayout()) {
72         auto algo = MakeRefPtr<GridIrregularLayoutAlgorithm>(info_, canOverScrollStart, canOverScrollEnd);
73         algo->SetEnableSkip(!disableSkip);
74         return algo;
75     }
76     RefPtr<GridScrollLayoutAlgorithm> result;
77     if (!gridLayoutProperty->GetLayoutOptions().has_value()) {
78         result = MakeRefPtr<GridScrollLayoutAlgorithm>(info_, crossCount, mainCount);
79     } else {
80         result = MakeRefPtr<GridScrollWithOptionsLayoutAlgorithm>(info_, crossCount, mainCount);
81     }
82     result->SetCanOverScrollStart(canOverScrollStart);
83     result->SetCanOverScrollEnd(canOverScrollEnd);
84     result->SetScrollSource(GetScrollSource());
85     if (ScrollablePattern::AnimateRunning()) {
86         result->SetLineSkipping(!disableSkip);
87     }
88     return result;
89 }
90 
BeforeCreateLayoutWrapper()91 void GridPattern::BeforeCreateLayoutWrapper()
92 {
93     auto host = GetHost();
94     CHECK_NULL_VOID(host);
95     info_.childrenCount_ = host->GetTotalChildCount();
96 }
97 
CreatePaintProperty()98 RefPtr<PaintProperty> GridPattern::CreatePaintProperty()
99 {
100     auto defaultDisplayMode = GetDefaultScrollBarDisplayMode();
101     auto property = MakeRefPtr<GridPaintProperty>();
102     property->UpdateScrollBarMode(defaultDisplayMode);
103     return property;
104 }
105 
CreateNodePaintMethod()106 RefPtr<NodePaintMethod> GridPattern::CreateNodePaintMethod()
107 {
108     auto paint = MakeRefPtr<GridPaintMethod>(GetAxis() == Axis::HORIZONTAL, IsReverse(), GetScrollBar());
109     CHECK_NULL_RETURN(paint, nullptr);
110     paint->SetScrollBarOverlayModifier(GetScrollBarOverlayModifier());
111     auto scrollEffect = GetScrollEdgeEffect();
112     if (scrollEffect && scrollEffect->IsFadeEffect()) {
113         paint->SetEdgeEffect(scrollEffect);
114     }
115     if (!gridContentModifier_) {
116         gridContentModifier_ = AceType::MakeRefPtr<GridContentModifier>();
117     }
118     paint->SetContentModifier(gridContentModifier_);
119     UpdateFadingEdge(paint);
120     return paint;
121 }
122 
OnModifyDone()123 void GridPattern::OnModifyDone()
124 {
125     Pattern::OnModifyDone();
126     auto gridLayoutProperty = GetLayoutProperty<GridLayoutProperty>();
127     CHECK_NULL_VOID(gridLayoutProperty);
128 
129     if (multiSelectable_ && !isMouseEventInit_) {
130         InitMouseEvent();
131     }
132 
133     if (!multiSelectable_ && isMouseEventInit_) {
134         UninitMouseEvent();
135     }
136 
137     info_.axis_ = gridLayoutProperty->IsVertical() ? Axis::VERTICAL : Axis::HORIZONTAL;
138     isConfigScrollable_ = gridLayoutProperty->IsConfiguredScrollable();
139     if (!isConfigScrollable_) {
140         return;
141     }
142     SetAxis(info_.axis_);
143     if (!GetScrollableEvent()) {
144         AddScrollEvent();
145 #ifdef SUPPORT_DIGITAL_CROWN
146         SetDigitalCrownEvent();
147 #endif
148     }
149 
150     SetEdgeEffect();
151 
152     auto paintProperty = GetPaintProperty<ScrollablePaintProperty>();
153     CHECK_NULL_VOID(paintProperty);
154     if (paintProperty->GetScrollBarProperty()) {
155         SetScrollBar(paintProperty->GetScrollBarProperty());
156     }
157 
158     auto host = GetHost();
159     CHECK_NULL_VOID(host);
160     auto focusHub = host->GetFocusHub();
161     if (focusHub) {
162         InitOnKeyEvent(focusHub);
163     }
164     SetAccessibilityAction();
165     Register2DragDropManager();
166     auto overlayNode = host->GetOverlayNode();
167     if (!overlayNode && paintProperty->GetFadingEdge().value_or(false)) {
168         CreateAnalyzerOverlay(host);
169     }
170 }
171 
MultiSelectWithoutKeyboard(const RectF & selectedZone)172 void GridPattern::MultiSelectWithoutKeyboard(const RectF& selectedZone)
173 {
174     auto host = GetHost();
175     CHECK_NULL_VOID(host);
176     std::list<RefPtr<FrameNode>> children;
177     host->GenerateOneDepthVisibleFrame(children);
178     for (const auto& itemFrameNode : children) {
179         auto itemEvent = itemFrameNode->GetEventHub<EventHub>();
180         CHECK_NULL_VOID(itemEvent);
181         if (!itemEvent->IsEnabled()) {
182             continue;
183         }
184 
185         auto itemPattern = itemFrameNode->GetPattern<GridItemPattern>();
186         CHECK_NULL_VOID(itemPattern);
187         if (!itemPattern->Selectable()) {
188             continue;
189         }
190         auto itemGeometry = itemFrameNode->GetGeometryNode();
191         CHECK_NULL_VOID(itemGeometry);
192         auto context = itemFrameNode->GetRenderContext();
193         CHECK_NULL_VOID(context);
194 
195         auto itemRect = itemGeometry->GetFrameRect();
196         auto iter = itemToBeSelected_.find(itemFrameNode->GetId());
197         if (iter == itemToBeSelected_.end()) {
198             auto result = itemToBeSelected_.emplace(itemFrameNode->GetId(), ItemSelectedStatus());
199             iter = result.first;
200             iter->second.onSelected = itemPattern->GetEventHub<GridItemEventHub>()->GetOnSelect();
201             iter->second.selectChangeEvent = itemPattern->GetEventHub<GridItemEventHub>()->GetSelectChangeEvent();
202         }
203         auto startMainOffset = mouseStartOffset_.GetMainOffset(info_.axis_);
204         if (info_.axis_ == Axis::VERTICAL) {
205             iter->second.rect = itemRect + OffsetF(0, totalOffsetOfMousePressed_ - startMainOffset);
206         } else {
207             iter->second.rect = itemRect + OffsetF(totalOffsetOfMousePressed_ - startMainOffset, 0);
208         }
209 
210         if (!selectedZone.IsIntersectWith(itemRect)) {
211             itemPattern->MarkIsSelected(false);
212             iter->second.selected = false;
213             context->OnMouseSelectUpdate(false, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
214         } else {
215             itemPattern->MarkIsSelected(true);
216             iter->second.selected = true;
217             context->OnMouseSelectUpdate(true, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
218         }
219     }
220 
221     DrawSelectedZone(selectedZone);
222 }
223 
ClearMultiSelect()224 void GridPattern::ClearMultiSelect()
225 {
226     auto host = GetHost();
227     CHECK_NULL_VOID(host);
228     std::list<RefPtr<FrameNode>> children;
229     host->GenerateOneDepthAllFrame(children);
230     for (const auto& item : children) {
231         if (!AceType::InstanceOf<FrameNode>(item)) {
232             continue;
233         }
234 
235         auto itemFrameNode = AceType::DynamicCast<FrameNode>(item);
236         auto itemPattern = itemFrameNode->GetPattern<GridItemPattern>();
237         CHECK_NULL_VOID(itemPattern);
238         auto selectedStatus = itemToBeSelected_.find(itemFrameNode->GetId());
239         if (selectedStatus != itemToBeSelected_.end()) {
240             selectedStatus->second.selected = false;
241         }
242         itemPattern->MarkIsSelected(false);
243         auto renderContext = itemFrameNode->GetRenderContext();
244         CHECK_NULL_VOID(renderContext);
245         renderContext->OnMouseSelectUpdate(false, ITEM_FILL_COLOR, ITEM_FILL_COLOR);
246     }
247 
248     ClearSelectedZone();
249 }
250 
IsItemSelected(float offsetX,float offsetY)251 bool GridPattern::IsItemSelected(float offsetX, float offsetY)
252 {
253     auto host = GetHost();
254     CHECK_NULL_RETURN(host, false);
255     auto node = host->FindChildByPosition(offsetX, offsetY);
256     CHECK_NULL_RETURN(node, false);
257     auto itemPattern = node->GetPattern<GridItemPattern>();
258     CHECK_NULL_RETURN(itemPattern, false);
259     return itemPattern->IsSelected();
260 }
261 
FireOnScrollStart()262 void GridPattern::FireOnScrollStart()
263 {
264     ScrollablePattern::RecordScrollEvent(Recorder::EventType::SCROLL_START);
265     UIObserverHandler::GetInstance().NotifyScrollEventStateChange(
266         AceType::WeakClaim(this), ScrollEventType::SCROLL_START);
267     SuggestOpIncGroup(true);
268     PerfMonitor::GetPerfMonitor()->StartCommercial(PerfConstants::APP_LIST_FLING, PerfActionType::FIRST_MOVE, "");
269     if (GetScrollAbort()) {
270         return;
271     }
272     if (scrollStop_) {
273         // onScrollStart triggers immediately on gesture dragStart, but onScrollStop marks scrollStop_ to true on
274         // gesture dragEnd, and consumes it/fires onScrollStop after layout. When the user quickly swipes twice, the
275         // second onScrollStart can trigger before the first onScrollEnd. In this case, we let the two events annihilate
276         // each other and fire neither.
277         scrollStop_ = false;
278         return;
279     }
280     auto scrollBar = GetScrollBar();
281     if (scrollBar) {
282         scrollBar->PlayScrollBarAppearAnimation();
283     }
284     StopScrollBarAnimatorByProxy();
285     FireObserverOnScrollStart();
286     auto pipeline = GetContext();
287     if (pipeline) {
288         pipeline->GetFocusManager()->SetNeedTriggerScroll(std::nullopt);
289     }
290     auto host = GetHost();
291     CHECK_NULL_VOID(host);
292     auto hub = host->GetEventHub<GridEventHub>();
293     CHECK_NULL_VOID(hub);
294     auto onScrollStart = hub->GetOnScrollStart();
295     CHECK_NULL_VOID(onScrollStart);
296     onScrollStart();
297 }
298 
FireOnReachStart(const OnReachEvent & onReachStart)299 void GridPattern::FireOnReachStart(const OnReachEvent& onReachStart)
300 {
301     auto host = GetHost();
302     CHECK_NULL_VOID(host);
303     if (info_.startIndex_ == 0) {
304         if (!isInitialized_) {
305             FireObserverOnReachStart();
306             if (onReachStart) {
307                 onReachStart();
308                 AddEventsFiredInfo(ScrollableEventType::ON_REACH_START);
309             }
310         }
311         auto finalOffset = info_.currentHeight_ - info_.prevHeight_;
312         if (!NearZero(finalOffset)) {
313             bool scrollUpToStart = GreatOrEqual(info_.prevHeight_, 0.0) && LessOrEqual(info_.currentHeight_, 0.0);
314             bool scrollDownToStart = LessNotEqual(info_.prevHeight_, 0.0) && GreatOrEqual(info_.currentHeight_, 0.0);
315             if (scrollUpToStart || scrollDownToStart) {
316                 FireObserverOnReachStart();
317                 CHECK_NULL_VOID(onReachStart);
318                 ACE_SCOPED_TRACE("OnReachStart, scrollUpToStart:%u, scrollDownToStart:%u, id:%d, tag:Grid",
319                     scrollUpToStart, scrollDownToStart, static_cast<int32_t>(host->GetAccessibilityId()));
320                 onReachStart();
321                 AddEventsFiredInfo(ScrollableEventType::ON_REACH_START);
322             }
323         }
324     }
325 }
326 
FireOnReachEnd(const OnReachEvent & onReachEnd)327 void GridPattern::FireOnReachEnd(const OnReachEvent& onReachEnd)
328 {
329     auto host = GetHost();
330     CHECK_NULL_VOID(host);
331     if (info_.endIndex_ == (info_.childrenCount_ - 1)) {
332         if (!isInitialized_) {
333             FireObserverOnReachEnd();
334         }
335         auto finalOffset = info_.currentHeight_ - info_.prevHeight_;
336         if (!NearZero(finalOffset)) {
337             bool scrollDownToEnd =
338                 LessNotEqual(info_.prevHeight_, endHeight_) && GreatOrEqual(info_.currentHeight_, endHeight_);
339             bool scrollUpToEnd =
340                 GreatNotEqual(info_.prevHeight_, endHeight_) && LessOrEqual(info_.currentHeight_, endHeight_);
341             if (scrollDownToEnd || scrollUpToEnd) {
342                 FireObserverOnReachEnd();
343                 CHECK_NULL_VOID(onReachEnd);
344                 ACE_SCOPED_TRACE("OnReachEnd, scrollUpToEnd:%u, scrollDownToEnd:%u, id:%d, tag:Grid", scrollUpToEnd,
345                     scrollDownToEnd, static_cast<int32_t>(host->GetAccessibilityId()));
346                 onReachEnd();
347                 AddEventsFiredInfo(ScrollableEventType::ON_REACH_END);
348             }
349         }
350     }
351 }
352 
FireOnScrollIndex(bool indexChanged,const ScrollIndexFunc & onScrollIndex)353 void GridPattern::FireOnScrollIndex(bool indexChanged, const ScrollIndexFunc& onScrollIndex)
354 {
355     CHECK_NULL_VOID(indexChanged && onScrollIndex);
356     onScrollIndex(info_.startIndex_, info_.endIndex_);
357 }
358 
GetContentSize() const359 SizeF GridPattern::GetContentSize() const
360 {
361     auto host = GetHost();
362     CHECK_NULL_RETURN(host, SizeF());
363     auto geometryNode = host->GetGeometryNode();
364     CHECK_NULL_RETURN(geometryNode, SizeF());
365     return geometryNode->GetPaddingSize();
366 }
367 
GetMainGap() const368 float GridPattern::GetMainGap() const
369 {
370     float mainGap = 0.0;
371     auto host = GetHost();
372     CHECK_NULL_RETURN(host, 0.0);
373     auto geometryNode = host->GetGeometryNode();
374     CHECK_NULL_RETURN(geometryNode, 0.0);
375     auto viewScopeSize = geometryNode->GetPaddingSize();
376     auto layoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
377     mainGap = GridUtils::GetMainGap(layoutProperty, viewScopeSize, info_.axis_);
378     return mainGap;
379 }
380 
IsFadingBottom() const381 bool GridPattern::IsFadingBottom() const
382 {
383     float mainSize = info_.lastMainSize_ - info_.contentEndPadding_;
384     if (info_.startIndex_ == 0 && (info_.endIndex_ == info_.childrenCount_ - 1) &&
385         LessNotEqual(info_.totalHeightOfItemsInView_, mainSize)) {
386         return Positive(info_.currentOffset_);
387     } else {
388         return !info_.offsetEnd_;
389     }
390 }
391 
UpdateCurrentOffset(float offset,int32_t source)392 bool GridPattern::UpdateCurrentOffset(float offset, int32_t source)
393 {
394     if (!isConfigScrollable_ || !scrollable_) {
395         return true;
396     }
397 
398     auto host = GetHost();
399     CHECK_NULL_RETURN(host, false);
400 
401     // check edgeEffect is not springEffect
402     if (!HandleEdgeEffect(offset, source, GetContentSize())) {
403         if (IsOutOfBoundary(true)) {
404             host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
405         }
406         return false;
407     }
408     SetScrollSource(source);
409     FireAndCleanScrollingListener();
410     if (info_.synced_) {
411         info_.prevOffset_ = info_.currentOffset_;
412         info_.synced_ = false;
413     }
414     // When finger moves down, offset is positive.
415     // When finger moves up, offset is negative.
416     bool irregular = UseIrregularLayout();
417     float mainGap = GetMainGap();
418     auto itemsHeight = info_.GetTotalHeightOfItemsInView(mainGap, irregular);
419     if (info_.offsetEnd_) {
420         if (source == SCROLL_FROM_UPDATE) {
421             float overScroll = 0.0f;
422             if (irregular) {
423                 overScroll = info_.GetDistanceToBottom(GetMainContentSize(), itemsHeight, mainGap);
424             } else {
425                 overScroll = info_.currentOffset_ - (GetMainContentSize() - itemsHeight);
426             }
427             auto friction = CalculateFriction(std::abs(overScroll) / GetMainContentSize());
428             offset *= friction;
429         }
430         auto userOffset = FireOnWillScroll(-offset);
431         info_.currentOffset_ -= userOffset;
432 
433         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
434 
435         if (GreatNotEqual(info_.currentOffset_, GetMainContentSize() - itemsHeight)) {
436             info_.offsetEnd_ = false;
437             info_.reachEnd_ = false;
438         }
439 
440         return true;
441     }
442     if (info_.reachStart_) {
443         if (source == SCROLL_FROM_UPDATE) {
444             auto friction = CalculateFriction(std::abs(info_.currentOffset_) / GetMainContentSize());
445             offset *= friction;
446         }
447         auto userOffset = FireOnWillScroll(-offset);
448         info_.currentOffset_ -= userOffset;
449 
450         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
451 
452         if (LessNotEqual(info_.currentOffset_, 0.0)) {
453             info_.reachStart_ = false;
454         }
455         return true;
456     }
457     auto userOffset = FireOnWillScroll(-offset);
458     info_.currentOffset_ -= userOffset;
459     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
460     return true;
461 }
462 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)463 bool GridPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
464 {
465     if (config.skipMeasure && config.skipLayout) {
466         return false;
467     }
468     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
469     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
470     auto gridLayoutAlgorithm = DynamicCast<GridLayoutBaseAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
471     CHECK_NULL_RETURN(gridLayoutAlgorithm, false);
472     const auto& gridLayoutInfo = gridLayoutAlgorithm->GetGridLayoutInfo();
473     auto eventhub = GetEventHub<GridEventHub>();
474     CHECK_NULL_RETURN(eventhub, false);
475     Dimension offset(0, DimensionUnit::VP);
476     Dimension offsetPx(gridLayoutInfo.currentOffset_, DimensionUnit::PX);
477     auto offsetVpValue = offsetPx.ConvertToVp();
478     offset.SetValue(offsetVpValue);
479     scrollbarInfo_ = eventhub->FireOnScrollBarUpdate(gridLayoutInfo.startIndex_, offset);
480     if (!isInitialized_ || info_.startIndex_ != gridLayoutInfo.startIndex_) {
481         eventhub->FireOnScrollToIndex(gridLayoutInfo.startIndex_);
482     }
483 
484     bool indexChanged =
485         (gridLayoutInfo.startIndex_ != info_.startIndex_) || (gridLayoutInfo.endIndex_ != info_.endIndex_);
486     bool offsetEnd = info_.offsetEnd_;
487     info_ = gridLayoutInfo;
488     info_.synced_ = true;
489     AnimateToTarget(scrollAlign_, layoutAlgorithmWrapper);
490 
491     info_.reachStart_ = info_.startIndex_ == 0 && GreatOrEqual(info_.currentOffset_, 0.0f);
492 
493     auto curDelta = info_.currentOffset_ - info_.prevOffset_;
494     info_.currentHeight_ = EstimateHeight();
495     bool sizeDiminished =
496         IsOutOfBoundary(true) && !NearZero(curDelta) && (info_.prevHeight_ - info_.currentHeight_ - curDelta > 0.1f);
497 
498     if (!offsetEnd && info_.offsetEnd_) {
499         endHeight_ = info_.currentHeight_;
500     }
501     ProcessEvent(indexChanged, info_.currentHeight_ - info_.prevHeight_);
502     info_.prevHeight_ = info_.currentHeight_;
503     info_.extraOffset_.reset();
504     UpdateScrollBarOffset();
505     SetScrollSource(SCROLL_FROM_NONE);
506     if (config.frameSizeChange) {
507         if (GetScrollBar() != nullptr) {
508             GetScrollBar()->ScheduleDisappearDelayTask();
509         }
510     }
511     if (!preSpring_) {
512         CheckRestartSpring(sizeDiminished);
513     }
514     CheckScrollable();
515     MarkSelectedItems();
516     isInitialized_ = true;
517     auto paintProperty = GetPaintProperty<ScrollablePaintProperty>();
518     CHECK_NULL_RETURN(paintProperty, false);
519     return paintProperty->GetFadingEdge().value_or(false) || paintProperty->HasContentClip();
520 }
521 
CheckScrollable()522 void GridPattern::CheckScrollable()
523 {
524     auto host = GetHost();
525     CHECK_NULL_VOID(host);
526     auto gridLayoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
527     CHECK_NULL_VOID(gridLayoutProperty);
528     if (((info_.endIndex_ - info_.startIndex_ + 1) < info_.childrenCount_) ||
529         (info_.GetTotalHeightOfItemsInView(GetMainGap()) > GetMainContentSize())) {
530         scrollable_ = true;
531     } else {
532         scrollable_ = info_.startMainLineIndex_ != 0 || GetAlwaysEnabled();
533     }
534 
535     SetScrollEnabled(scrollable_);
536 
537     if (!gridLayoutProperty->GetScrollEnabled().value_or(scrollable_)) {
538         SetScrollEnabled(false);
539     }
540 }
541 
ProcessEvent(bool indexChanged,float finalOffset)542 void GridPattern::ProcessEvent(bool indexChanged, float finalOffset)
543 {
544     auto host = GetHost();
545     CHECK_NULL_VOID(host);
546     auto gridEventHub = host->GetEventHub<GridEventHub>();
547     CHECK_NULL_VOID(gridEventHub);
548 
549     auto onScroll = gridEventHub->GetOnScroll();
550     PrintOffsetLog(AceLogTag::ACE_GRID, host->GetId(), finalOffset);
551     if (onScroll) {
552         FireOnScroll(finalOffset, onScroll);
553     }
554     FireObserverOnDidScroll(finalOffset);
555     auto onDidScroll = gridEventHub->GetOnDidScroll();
556     if (onDidScroll) {
557         FireOnScroll(finalOffset, onDidScroll);
558     }
559     auto onScrollIndex = gridEventHub->GetOnScrollIndex();
560     FireOnScrollIndex(indexChanged, onScrollIndex);
561     if (indexChanged) {
562         host->OnAccessibilityEvent(AccessibilityEventType::SCROLLING_EVENT, info_.startIndex_, info_.endIndex_);
563     }
564     auto onReachStart = gridEventHub->GetOnReachStart();
565     FireOnReachStart(onReachStart);
566     auto onReachEnd = gridEventHub->GetOnReachEnd();
567     FireOnReachEnd(onReachEnd);
568     OnScrollStop(gridEventHub->GetOnScrollStop());
569     if (isSmoothScrolling_ && scrollStop_) {
570         isSmoothScrolling_ = false;
571     }
572     CHECK_NULL_VOID(isConfigScrollable_);
573     focusHandler_.ProcessFocusEvent(keyEvent_, indexChanged);
574 }
575 
MarkDirtyNodeSelf()576 void GridPattern::MarkDirtyNodeSelf()
577 {
578     auto host = GetHost();
579     CHECK_NULL_VOID(host);
580     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
581 }
582 
OnScrollEndCallback()583 void GridPattern::OnScrollEndCallback()
584 {
585     isSmoothScrolling_ = false;
586     if (AnimateStoped()) {
587         scrollStop_ = true;
588         MarkDirtyNodeSelf();
589     }
590 }
591 
GetFocusNodeIndex(const RefPtr<FocusHub> & focusNode)592 int32_t GridPattern::GetFocusNodeIndex(const RefPtr<FocusHub>& focusNode)
593 {
594     return focusHandler_.GetFocusNodeIndex(focusNode);
595 }
596 
ScrollToFocusNodeIndex(int32_t index)597 void GridPattern::ScrollToFocusNodeIndex(int32_t index)
598 {
599     StopAnimate();
600     UpdateStartIndex(index);
601     auto pipeline = GetContext();
602     if (pipeline) {
603         pipeline->FlushUITasks();
604     }
605     auto tarFocusNodeWeak = focusHandler_.GetChildFocusNodeByIndex(-1, -1, index);
606     auto tarFocusNode = tarFocusNodeWeak.Upgrade();
607     if (tarFocusNode) {
608         tarFocusNode->RequestFocusImmediately();
609     }
610 }
611 
ScrollToNode(const RefPtr<FrameNode> & focusFrameNode)612 bool GridPattern::ScrollToNode(const RefPtr<FrameNode>& focusFrameNode)
613 {
614     CHECK_NULL_RETURN(focusFrameNode, false);
615     auto focusHub = focusFrameNode->GetFocusHub();
616     CHECK_NULL_RETURN(focusHub, false);
617     auto scrollToIndex = focusHandler_.GetFocusNodeIndex(focusHub);
618     if (scrollToIndex < 0) {
619         return false;
620     }
621     StopAnimate();
622     auto ret = UpdateStartIndex(scrollToIndex);
623     auto* pipeline = GetContext();
624     if (pipeline) {
625         pipeline->FlushUITasks();
626     }
627     return ret;
628 }
629 
GetScrollOffsetAbility()630 ScrollOffsetAbility GridPattern::GetScrollOffsetAbility()
631 {
632     return { [wp = WeakClaim(this)](float moveOffset) -> bool {
633                 auto pattern = wp.Upgrade();
634                 CHECK_NULL_RETURN(pattern, false);
635                 pattern->ScrollBy(-moveOffset);
636                 return true;
637             },
638         GetAxis() };
639 }
640 
GetScrollIndexAbility()641 std::function<bool(int32_t)> GridPattern::GetScrollIndexAbility()
642 {
643     return [wp = WeakClaim(this)](int32_t index) -> bool {
644         auto pattern = wp.Upgrade();
645         CHECK_NULL_RETURN(pattern, false);
646         if (index == FocusHub::SCROLL_TO_HEAD) {
647             pattern->ScrollToEdge(ScrollEdgeType::SCROLL_TOP, false);
648         } else if (index == FocusHub::SCROLL_TO_TAIL) {
649             pattern->ScrollToEdge(ScrollEdgeType::SCROLL_BOTTOM, false);
650         } else {
651             pattern->UpdateStartIndex(index);
652         }
653         return true;
654     };
655 }
656 
ScrollBy(float offset)657 void GridPattern::ScrollBy(float offset)
658 {
659     StopAnimate();
660     UpdateCurrentOffset(-offset, SCROLL_FROM_JUMP);
661     // AccessibilityEventType::SCROLL_END
662 }
663 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const664 void GridPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
665 {
666     ScrollablePattern::ToJsonValue(json, filter);
667     /* no fixed attr below, just return */
668     if (filter.IsFastFilter()) {
669         return;
670     }
671     json->PutExtAttr("multiSelectable", multiSelectable_ ? "true" : "false", filter);
672     json->PutExtAttr("supportAnimation", supportAnimation_ ? "true" : "false", filter);
673 }
674 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)675 void GridPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
676 {
677     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
678         auto pattern = wp.Upgrade();
679         if (pattern) {
680             return pattern->OnKeyEvent(event);
681         }
682         return false;
683     };
684     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
685 }
686 
OnKeyEvent(const KeyEvent & event)687 bool GridPattern::OnKeyEvent(const KeyEvent& event)
688 {
689     if (event.action != KeyAction::DOWN) {
690         return false;
691     }
692     if ((event.code == KeyCode::KEY_PAGE_DOWN) || (event.code == KeyCode::KEY_PAGE_UP)) {
693         ScrollPage(event.code == KeyCode::KEY_PAGE_UP);
694     }
695 
696     if (FocusHub::IsFocusStepKey(event.code)) {
697         if (focusHandler_.ScrollToLastFocusIndex(event.code)) {
698             keyEvent_ = event;
699             return true;
700         }
701     }
702     return false;
703 }
704 
ScrollPage(bool reverse,bool smooth,AccessibilityScrollType scrollType)705 void GridPattern::ScrollPage(bool reverse, bool smooth, AccessibilityScrollType scrollType)
706 {
707     float distance = reverse ? GetMainContentSize() : -GetMainContentSize();
708     if (scrollType == AccessibilityScrollType::SCROLL_HALF) {
709         distance = distance / 2.f;
710     }
711     if (smooth) {
712         float position = -info_.currentHeight_ + distance;
713         ScrollablePattern::AnimateTo(-position, -1, nullptr, true, false, false);
714         return;
715     } else {
716         if (!isConfigScrollable_) {
717             return;
718         }
719         StopAnimate();
720         UpdateCurrentOffset(distance, SCROLL_FROM_JUMP);
721     }
722     // AccessibilityEventType::SCROLL_END
723 }
724 
UpdateStartIndex(int32_t index)725 bool GridPattern::UpdateStartIndex(int32_t index)
726 {
727     if (!isConfigScrollable_) {
728         return false;
729     }
730     auto host = GetHost();
731     CHECK_NULL_RETURN(host, false);
732     info_.jumpIndex_ = index;
733     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
734     // AccessibilityEventType::SCROLL_END
735     SetScrollSource(SCROLL_FROM_JUMP);
736     return true;
737 }
738 
UpdateStartIndex(int32_t index,ScrollAlign align)739 bool GridPattern::UpdateStartIndex(int32_t index, ScrollAlign align)
740 {
741     info_.scrollAlign_ = align;
742     return UpdateStartIndex(index);
743 }
744 
OnAnimateStop()745 void GridPattern::OnAnimateStop()
746 {
747     if (!GetIsDragging() || GetScrollAbort()) {
748         scrollStop_ = true;
749         MarkDirtyNodeSelf();
750     }
751 }
752 
AnimateTo(float position,float duration,const RefPtr<Curve> & curve,bool smooth,bool canOverScroll,bool useTotalOffset)753 void GridPattern::AnimateTo(
754     float position, float duration, const RefPtr<Curve>& curve, bool smooth, bool canOverScroll, bool useTotalOffset)
755 {
756     if (!isConfigScrollable_) {
757         return;
758     }
759     ScrollablePattern::AnimateTo(position, duration, curve, smooth, canOverScroll);
760 }
761 
ScrollTo(float position)762 void GridPattern::ScrollTo(float position)
763 {
764     if (!isConfigScrollable_) {
765         return;
766     }
767     TAG_LOGI(AceLogTag::ACE_GRID, "ScrollTo:%{public}f", position);
768     StopAnimate();
769     UpdateCurrentOffset(GetTotalOffset() - position, SCROLL_FROM_JUMP);
770     // AccessibilityEventType::SCROLL_END
771 }
772 
EstimateHeight() const773 float GridPattern::EstimateHeight() const
774 {
775     if (!isConfigScrollable_) {
776         return 0.0f;
777     }
778     // During the scrolling animation, the exact current position is used. Other times use the estimated location
779     if (isSmoothScrolling_) {
780         const auto* infoPtr = UseIrregularLayout() ? &info_ : infoCopy_.get();
781         CHECK_NULL_RETURN(infoPtr, 0.0f);
782         return infoPtr->GetTotalHeightFromZeroIndex(info_.startMainLineIndex_, GetMainGap()) - info_.currentOffset_;
783     }
784     auto host = GetHost();
785     CHECK_NULL_RETURN(host, 0.0);
786     auto geometryNode = host->GetGeometryNode();
787     CHECK_NULL_RETURN(geometryNode, 0.0);
788     const auto& info = info_;
789     auto viewScopeSize = geometryNode->GetPaddingSize();
790     auto layoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
791     auto mainGap = GridUtils::GetMainGap(layoutProperty, viewScopeSize, info.axis_);
792     if (UseIrregularLayout()) {
793         return info.GetIrregularOffset(mainGap);
794     }
795     if (!layoutProperty->GetLayoutOptions().has_value()) {
796         return info.GetContentOffset(mainGap);
797     }
798 
799     return info.GetContentOffset(layoutProperty->GetLayoutOptions().value(), mainGap);
800 }
801 
GetAverageHeight() const802 float GridPattern::GetAverageHeight() const
803 {
804     auto host = GetHost();
805     CHECK_NULL_RETURN(host, 0.0);
806     auto geometryNode = host->GetGeometryNode();
807     CHECK_NULL_RETURN(geometryNode, 0.0);
808     const auto& info = info_;
809     auto viewScopeSize = geometryNode->GetPaddingSize();
810     auto layoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
811 
812     float heightSum = 0;
813     int32_t itemCount = 0;
814     auto mainGap = GridUtils::GetMainGap(layoutProperty, viewScopeSize, info.axis_);
815     for (const auto& item : info.lineHeightMap_) {
816         auto line = info.gridMatrix_.find(item.first);
817         if (line == info.gridMatrix_.end()) {
818             continue;
819         }
820         if (line->second.empty()) {
821             continue;
822         }
823         auto lineStart = line->second.begin()->second;
824         auto lineEnd = line->second.rbegin()->second;
825         itemCount += (lineEnd - lineStart + 1);
826         heightSum += item.second + mainGap;
827     }
828     if (itemCount == 0) {
829         return 0;
830     }
831     return heightSum / itemCount;
832 }
833 
GetTotalHeight() const834 float GridPattern::GetTotalHeight() const
835 {
836     if (scrollbarInfo_.first.has_value() && scrollbarInfo_.second.has_value()) {
837         return scrollbarInfo_.second.value();
838     }
839     auto host = GetHost();
840     CHECK_NULL_RETURN(host, 0.0f);
841     auto geometryNode = host->GetGeometryNode();
842     CHECK_NULL_RETURN(geometryNode, 0.0f);
843     auto viewScopeSize = geometryNode->GetPaddingSize();
844     auto props = host->GetLayoutProperty<GridLayoutProperty>();
845     auto mainGap = GridUtils::GetMainGap(props, viewScopeSize, info_.axis_);
846     if (UseIrregularLayout()) {
847         return info_.GetIrregularHeight(mainGap);
848     }
849     if (props->HasLayoutOptions()) {
850         return info_.GetContentHeight(*props->GetLayoutOptions(), info_.childrenCount_, mainGap);
851     }
852     return info_.GetContentHeight(mainGap);
853 }
854 
UpdateScrollBarOffset()855 void GridPattern::UpdateScrollBarOffset()
856 {
857     CheckScrollBarOff();
858     if ((!GetScrollBar() && !GetScrollBarProxy()) || !isConfigScrollable_) {
859         return;
860     }
861     auto host = GetHost();
862     CHECK_NULL_VOID(host);
863     auto geometryNode = host->GetGeometryNode();
864     CHECK_NULL_VOID(geometryNode);
865     const auto& info = info_;
866     float offset = 0;
867     float estimatedHeight = 0.f;
868     if (scrollbarInfo_.first.has_value() && scrollbarInfo_.second.has_value()) {
869         offset = scrollbarInfo_.first.value();
870         estimatedHeight = scrollbarInfo_.second.value();
871     } else {
872         auto viewScopeSize = geometryNode->GetPaddingSize();
873         auto layoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
874         auto mainGap = GridUtils::GetMainGap(layoutProperty, viewScopeSize, info.axis_);
875         if (UseIrregularLayout()) {
876             offset = info.GetIrregularOffset(mainGap);
877             estimatedHeight = info.GetIrregularHeight(mainGap);
878         } else if (!layoutProperty->GetLayoutOptions().has_value()) {
879             offset = info.GetContentOffset(mainGap);
880             estimatedHeight = info.GetContentHeight(mainGap);
881         } else {
882             offset = info.GetContentOffset(layoutProperty->GetLayoutOptions().value(), mainGap);
883             estimatedHeight =
884                 info.GetContentHeight(layoutProperty->GetLayoutOptions().value(), info.childrenCount_, mainGap);
885         }
886     }
887     if (info.startMainLineIndex_ != 0 && info.startIndex_ == 0) {
888         for (int32_t lineIndex = info.startMainLineIndex_ - 1; lineIndex >= 0; lineIndex--) {
889             offset += info.lineHeightMap_.find(lineIndex)->second;
890         }
891     }
892     auto viewSize = geometryNode->GetFrameSize();
893     auto overScroll = 0.0f;
894     if (info_.reachStart_ && Positive(info_.currentOffset_)) {
895         overScroll = info_.currentOffset_;
896     } else {
897         overScroll = info_.lastMainSize_ - estimatedHeight + offset;
898         overScroll = Positive(overScroll) ? overScroll : 0.0f;
899     }
900     if (info_.offsetEnd_ && NearZero(overScroll)) {
901         offset = estimatedHeight - info_.lastMainSize_;
902     }
903     HandleScrollBarOutBoundary(overScroll);
904     UpdateScrollBarRegion(offset, estimatedHeight, Size(viewSize.Width(), viewSize.Height()), Offset(0.0f, 0.0f));
905 }
906 
GetDefaultScrollBarDisplayMode() const907 DisplayMode GridPattern::GetDefaultScrollBarDisplayMode() const
908 {
909     auto defaultDisplayMode = DisplayMode::OFF;
910     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
911         defaultDisplayMode = DisplayMode::AUTO;
912     }
913     return defaultDisplayMode;
914 }
915 
GetOriginalIndex() const916 int32_t GridPattern::GetOriginalIndex() const
917 {
918     return info_.GetOriginalIndex();
919 }
920 
GetCrossCount() const921 int32_t GridPattern::GetCrossCount() const
922 {
923     return info_.crossCount_;
924 }
925 
GetChildrenCount() const926 int32_t GridPattern::GetChildrenCount() const
927 {
928     return info_.childrenCount_;
929 }
930 
ClearDragState()931 void GridPattern::ClearDragState()
932 {
933     info_.ClearDragState();
934     MarkDirtyNodeSelf();
935 }
936 
UpdateRectOfDraggedInItem(int32_t insertIndex)937 void GridPattern::UpdateRectOfDraggedInItem(int32_t insertIndex)
938 {
939     auto host = GetHost();
940     CHECK_NULL_VOID(host);
941     std::list<RefPtr<FrameNode>> children;
942     host->GenerateOneDepthAllFrame(children);
943     for (const auto& item : children) {
944         auto itemPattern = item->GetPattern<GridItemPattern>();
945         CHECK_NULL_VOID(itemPattern);
946         auto itemProperty = itemPattern->GetLayoutProperty<GridItemLayoutProperty>();
947         CHECK_NULL_VOID(itemProperty);
948         auto mainIndex = itemProperty->GetMainIndex().value_or(-1);
949         auto crossIndex = itemProperty->GetCrossIndex().value_or(-1);
950         if (mainIndex * info_.crossCount_ + crossIndex == insertIndex) {
951             auto size = item->GetRenderContext()->GetPaintRectWithTransform();
952             size.SetOffset(item->GetTransformRelativeOffset());
953             info_.currentRect_ = size;
954             break;
955         }
956     }
957 }
958 
MoveItems(int32_t itemIndex,int32_t insertIndex)959 void GridPattern::MoveItems(int32_t itemIndex, int32_t insertIndex)
960 {
961     if (insertIndex < 0 || insertIndex >= ((itemIndex == -1) ? (info_.childrenCount_ + 1) : info_.childrenCount_)) {
962         return;
963     }
964 
965     if (itemIndex == -1) {
966         UpdateRectOfDraggedInItem(insertIndex);
967     }
968 
969     info_.SwapItems(itemIndex, insertIndex);
970 
971     auto host = GetHost();
972     CHECK_NULL_VOID(host);
973     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
974     auto pipeline = GetContext();
975     if (pipeline) {
976         pipeline->FlushUITasks();
977     }
978 }
979 
IsOutOfBoundary(bool)980 bool GridPattern::IsOutOfBoundary(bool /*useCurrentDelta*/)
981 {
982     const bool scrollable = GetAlwaysEnabled() || (info_.startIndex_ > 0) ||
983                             (info_.endIndex_ < info_.childrenCount_ - 1) ||
984                             GreatNotEqual(info_.totalHeightOfItemsInView_, info_.lastMainSize_);
985     return scrollable && (info_.IsOutOfStart() || info_.IsOutOfEnd(GetMainGap(), UseIrregularLayout()));
986 }
987 
GetEndOffset()988 float GridPattern::GetEndOffset()
989 {
990     auto& info = info_;
991     float contentHeight = info.lastMainSize_ - info.contentEndPadding_;
992     const float mainGap = GetMainGap();
993     const bool irregular = UseIrregularLayout();
994     float heightInView = info.GetTotalHeightOfItemsInView(mainGap, irregular);
995 
996     const float totalHeight = GetTotalHeight();
997     if (GetAlwaysEnabled() && LessNotEqual(totalHeight, contentHeight)) {
998         // overScroll with contentHeight < viewport
999         if (irregular) {
1000             return info.GetHeightInRange(0, info.startMainLineIndex_, mainGap);
1001         }
1002         return totalHeight - heightInView;
1003     }
1004 
1005     if (!irregular) {
1006         return contentHeight - heightInView;
1007     }
1008     float disToBot = info_.GetDistanceToBottom(contentHeight, heightInView, mainGap);
1009     return info_.currentOffset_ - disToBot;
1010 }
1011 
SetEdgeEffectCallback(const RefPtr<ScrollEdgeEffect> & scrollEffect)1012 void GridPattern::SetEdgeEffectCallback(const RefPtr<ScrollEdgeEffect>& scrollEffect)
1013 {
1014     scrollEffect->SetCurrentPositionCallback([weak = AceType::WeakClaim(this)]() -> double {
1015         auto grid = weak.Upgrade();
1016         CHECK_NULL_RETURN(grid, 0.0);
1017         if (!grid->info_.synced_) {
1018             grid->SyncLayoutBeforeSpring();
1019         }
1020         return grid->info_.currentOffset_;
1021     });
1022     scrollEffect->SetLeadingCallback([weak = AceType::WeakClaim(this)]() -> double {
1023         auto grid = weak.Upgrade();
1024         CHECK_NULL_RETURN(grid, 0.0);
1025         return grid->GetEndOffset();
1026     });
1027     scrollEffect->SetTrailingCallback([]() -> double { return 0.0; });
1028     scrollEffect->SetInitLeadingCallback([weak = AceType::WeakClaim(this)]() -> double {
1029         auto grid = weak.Upgrade();
1030         CHECK_NULL_RETURN(grid, 0.0);
1031         return grid->GetEndOffset();
1032     });
1033     scrollEffect->SetInitTrailingCallback([]() -> double { return 0.0; });
1034 }
1035 
SyncLayoutBeforeSpring()1036 void GridPattern::SyncLayoutBeforeSpring()
1037 {
1038     auto& info = info_;
1039     if (info.synced_) {
1040         return;
1041     }
1042     if (!UseIrregularLayout()) {
1043         const float delta = info.currentOffset_ - info.prevOffset_;
1044         if (!info.lineHeightMap_.empty() && LessOrEqual(delta, -info_.lastMainSize_)) {
1045             // old layout can't handle large overScroll offset. Avoid by skipping this layout.
1046             // Spring animation plays immediately afterwards, so losing this frame's offset is fine
1047             info.currentOffset_ = info.prevOffset_;
1048             info.synced_ = true;
1049             return;
1050         }
1051     }
1052     auto host = GetHost();
1053     CHECK_NULL_VOID(host);
1054 
1055     preSpring_ = true;
1056     host->SetActive();
1057     auto* context = host->GetContext();
1058     if (context) {
1059         context->FlushUITaskWithSingleDirtyNode(host);
1060     }
1061     preSpring_ = false;
1062 }
1063 
GetEndOverScrollIrregular(OverScrollOffset & offset,float delta) const1064 void GridPattern::GetEndOverScrollIrregular(OverScrollOffset& offset, float delta) const
1065 {
1066     const float mainGap = GetMainGap();
1067     const float viewport = info_.lastMainSize_ - info_.contentEndPadding_;
1068     float heightInView = info_.totalHeightOfItemsInView_;
1069     if (info_.HeightSumSmaller(viewport, mainGap)) {
1070         // content < viewport, use viewport height to calculate overScroll
1071         heightInView = viewport - info_.GetHeightInRange(0, info_.startMainLineIndex_, mainGap);
1072     }
1073     float disToBot = info_.GetDistanceToBottom(viewport, heightInView, mainGap);
1074     if (!info_.IsOutOfEnd(mainGap, true)) {
1075         offset.end = std::min(0.0f, disToBot + delta);
1076     } else if (Negative(delta)) {
1077         offset.end = delta;
1078     } else {
1079         offset.end = std::min(delta, -disToBot);
1080     }
1081 }
1082 
GetOverScrollOffset(double delta) const1083 OverScrollOffset GridPattern::GetOverScrollOffset(double delta) const
1084 {
1085     OverScrollOffset offset = { 0, 0 };
1086     if (info_.startIndex_ == 0 && info_.startMainLineIndex_ == 0) {
1087         auto startPos = info_.currentOffset_;
1088         auto newStartPos = startPos + delta;
1089         if (startPos > 0 && newStartPos > 0) {
1090             offset.start = delta;
1091         }
1092         if (startPos > 0 && newStartPos <= 0) {
1093             offset.start = -startPos;
1094         }
1095         if (startPos <= 0 && newStartPos > 0) {
1096             offset.start = newStartPos;
1097         }
1098     }
1099     if (UseIrregularLayout()) {
1100         GetEndOverScrollIrregular(offset, static_cast<float>(delta));
1101         return offset;
1102     }
1103     if (info_.endIndex_ == info_.childrenCount_ - 1) {
1104         float endPos = info_.currentOffset_ + info_.totalHeightOfItemsInView_;
1105         float mainSize = info_.lastMainSize_ - info_.contentEndPadding_;
1106         if (GreatNotEqual(GetMainContentSize(), info_.currentOffset_ + info_.totalHeightOfItemsInView_)) {
1107             endPos = info_.currentOffset_ + GetMainContentSize();
1108         }
1109         float newEndPos = endPos + delta;
1110         if (endPos < mainSize && newEndPos < mainSize) {
1111             offset.end = delta;
1112         }
1113         if (endPos < mainSize && newEndPos >= mainSize) {
1114             offset.end = mainSize - endPos;
1115         }
1116         if (endPos >= mainSize && newEndPos < mainSize) {
1117             offset.end = newEndPos - mainSize;
1118         }
1119     }
1120     return offset;
1121 }
1122 
DumpAdvanceInfo()1123 void GridPattern::DumpAdvanceInfo()
1124 {
1125     auto property = GetLayoutProperty<GridLayoutProperty>();
1126     CHECK_NULL_VOID(property);
1127     ScrollablePattern::DumpAdvanceInfo();
1128     if (!property->HasLayoutOptions()) {
1129         DumpLog::GetInstance().AddDesc("GridLayoutOptions:null");
1130     } else {
1131         DumpLog::GetInstance().AddDesc("GridLayoutOptions:true");
1132         DumpLog::GetInstance().AddDesc(GetIrregularIndexesString());
1133     }
1134     supportAnimation_ ? DumpLog::GetInstance().AddDesc("supportAnimation:true")
1135                       : DumpLog::GetInstance().AddDesc("supportAnimation:false");
1136     isConfigScrollable_ ? DumpLog::GetInstance().AddDesc("isConfigScrollable:true")
1137                         : DumpLog::GetInstance().AddDesc("isConfigScrollable:false");
1138     info_.lastCrossCount_.has_value()
1139         ? DumpLog::GetInstance().AddDesc("lastCrossCount:" + std::to_string(info_.lastCrossCount_.value()))
1140         : DumpLog::GetInstance().AddDesc("lastCrossCount:null");
1141     info_.reachEnd_ ? DumpLog::GetInstance().AddDesc("reachEnd:true")
1142                     : DumpLog::GetInstance().AddDesc("reachEnd:false");
1143     info_.reachStart_ ? DumpLog::GetInstance().AddDesc("reachStart:true")
1144                       : DumpLog::GetInstance().AddDesc("reachStart:false");
1145     info_.offsetEnd_ ? DumpLog::GetInstance().AddDesc("offsetEnd:true")
1146                      : DumpLog::GetInstance().AddDesc("offsetEnd:false");
1147     info_.hasBigItem_ ? DumpLog::GetInstance().AddDesc("hasBigItem:true")
1148                       : DumpLog::GetInstance().AddDesc("hasBigItem:false");
1149     info_.synced_ ? DumpLog::GetInstance().AddDesc("synced:true") : DumpLog::GetInstance().AddDesc("synced:false");
1150     DumpLog::GetInstance().AddDesc("scrollStop:" + std::to_string(scrollStop_));
1151     DumpLog::GetInstance().AddDesc("prevHeight:" + std::to_string(info_.prevHeight_));
1152     DumpLog::GetInstance().AddDesc("currentHeight:" + std::to_string(info_.currentHeight_));
1153     DumpLog::GetInstance().AddDesc("endHeight:" + std::to_string(endHeight_));
1154     DumpLog::GetInstance().AddDesc("currentOffset:" + std::to_string(info_.currentOffset_));
1155     DumpLog::GetInstance().AddDesc("prevOffset:" + std::to_string(info_.prevOffset_));
1156     DumpLog::GetInstance().AddDesc("lastMainSize:" + std::to_string(info_.lastMainSize_));
1157     DumpLog::GetInstance().AddDesc("totalHeightOfItemsInView:" + std::to_string(info_.totalHeightOfItemsInView_));
1158     DumpLog::GetInstance().AddDesc("startIndex:" + std::to_string(info_.startIndex_));
1159     DumpLog::GetInstance().AddDesc("endIndex:" + std::to_string(info_.endIndex_));
1160     DumpLog::GetInstance().AddDesc("jumpIndex:" + std::to_string(info_.jumpIndex_));
1161     DumpLog::GetInstance().AddDesc("crossCount:" + std::to_string(info_.crossCount_));
1162     DumpLog::GetInstance().AddDesc("childrenCount:" + std::to_string(info_.childrenCount_));
1163     DumpLog::GetInstance().AddDesc("RowsTemplate:", property->GetRowsTemplate()->c_str());
1164     DumpLog::GetInstance().AddDesc("ColumnsTemplate:", property->GetColumnsTemplate()->c_str());
1165     property->GetRowsGap().has_value()
1166         ? DumpLog::GetInstance().AddDesc("RowsGap:" + std::to_string(property->GetRowsGap().value().Value()))
1167         : DumpLog::GetInstance().AddDesc("RowsGap:null");
1168     property->GetColumnsGap().has_value()
1169         ? DumpLog::GetInstance().AddDesc("ColumnsGap:" + std::to_string(property->GetColumnsGap().value().Value()))
1170         : DumpLog::GetInstance().AddDesc("ColumnsGap:null");
1171     property->GetCachedCount().has_value()
1172         ? DumpLog::GetInstance().AddDesc("CachedCount:" + std::to_string(property->GetCachedCount().value()))
1173         : DumpLog::GetInstance().AddDesc("CachedCount:null");
1174     property->GetMaxCount().has_value()
1175         ? DumpLog::GetInstance().AddDesc("MaxCount:" + std::to_string(property->GetMaxCount().value()))
1176         : DumpLog::GetInstance().AddDesc("MaxCount:null");
1177     property->GetMinCount().has_value()
1178         ? DumpLog::GetInstance().AddDesc("MinCount:" + std::to_string(property->GetMinCount().value()))
1179         : DumpLog::GetInstance().AddDesc("MinCount:null");
1180     property->GetCellLength().has_value()
1181         ? DumpLog::GetInstance().AddDesc("CellLength:" + std::to_string(property->GetCellLength().value()))
1182         : DumpLog::GetInstance().AddDesc("CellLength:null");
1183     property->GetEditable().has_value()
1184         ? DumpLog::GetInstance().AddDesc("Editable:" + std::to_string(property->GetEditable().value()))
1185         : DumpLog::GetInstance().AddDesc("Editable:null");
1186     property->GetScrollEnabled().has_value()
1187         ? DumpLog::GetInstance().AddDesc("ScrollEnabled:" + std::to_string(property->GetScrollEnabled().value()))
1188         : DumpLog::GetInstance().AddDesc("ScrollEnabled:null");
1189     switch (property->GetAlignItems().value_or(GridItemAlignment::DEFAULT)) {
1190         case GridItemAlignment::STRETCH: {
1191             DumpLog::GetInstance().AddDesc("AlignItems:GridItemAlignment.STRETCH");
1192             break;
1193         }
1194         default: {
1195             DumpLog::GetInstance().AddDesc("AlignItems:GridItemAlignment.DEFAULT");
1196             break;
1197         }
1198     }
1199     switch (info_.scrollAlign_) {
1200         case ScrollAlign::NONE: {
1201             DumpLog::GetInstance().AddDesc("ScrollAlign:NONE");
1202             break;
1203         }
1204         case ScrollAlign::CENTER: {
1205             DumpLog::GetInstance().AddDesc("ScrollAlign:CENTER");
1206             break;
1207         }
1208         case ScrollAlign::END: {
1209             DumpLog::GetInstance().AddDesc("ScrollAlign:END");
1210             break;
1211         }
1212         case ScrollAlign::START: {
1213             DumpLog::GetInstance().AddDesc("ScrollAlign:START");
1214             break;
1215         }
1216         case ScrollAlign::AUTO: {
1217             DumpLog::GetInstance().AddDesc("ScrollAlign:AUTO");
1218             break;
1219         }
1220         default: {
1221             break;
1222         }
1223     }
1224     if (!info_.gridMatrix_.empty()) {
1225         DumpLog::GetInstance().AddDesc("-----------start print gridMatrix------------");
1226         std::string res = std::string("");
1227         for (auto item : info_.gridMatrix_) {
1228             res.append(std::to_string(item.first));
1229             res.append(": ");
1230             for (auto index : item.second) {
1231                 res.append("[")
1232                     .append(std::to_string(index.first))
1233                     .append(",")
1234                     .append(std::to_string(index.second))
1235                     .append("] ");
1236             }
1237             DumpLog::GetInstance().AddDesc(res);
1238             res.clear();
1239         }
1240         DumpLog::GetInstance().AddDesc("-----------end print gridMatrix------------");
1241     }
1242     if (!info_.lineHeightMap_.empty()) {
1243         DumpLog::GetInstance().AddDesc("-----------start print lineHeightMap------------");
1244         for (auto item : info_.lineHeightMap_) {
1245             DumpLog::GetInstance().AddDesc(std::to_string(item.first).append(" :").append(std::to_string(item.second)));
1246         }
1247         DumpLog::GetInstance().AddDesc("-----------end print lineHeightMap------------");
1248     }
1249     if (!info_.irregularItemsPosition_.empty()) {
1250         DumpLog::GetInstance().AddDesc("-----------start print irregularItemsPosition_------------");
1251         for (auto item : info_.irregularItemsPosition_) {
1252             DumpLog::GetInstance().AddDesc(std::to_string(item.first).append(" :").append(std::to_string(item.second)));
1253         }
1254         DumpLog::GetInstance().AddDesc("-----------end print irregularItemsPosition_------------");
1255     }
1256 }
1257 
GetIrregularIndexesString() const1258 std::string GridPattern::GetIrregularIndexesString() const
1259 {
1260     auto property = GetLayoutProperty<GridLayoutProperty>();
1261     if (!property || !property->HasLayoutOptions()) {
1262         return std::string("");
1263     }
1264     const auto& options = *property->GetLayoutOptions();
1265     if (options.irregularIndexes.empty()) {
1266         return std::string("");
1267     }
1268     std::string irregularIndexes = std::string("IrregularIndexes: [");
1269     int count = 0;
1270     for (const auto& index : options.irregularIndexes) {
1271         if (count > 0) {
1272             irregularIndexes.append(", ");
1273         }
1274         irregularIndexes.append(std::to_string(index));
1275         count++;
1276         if (count == MAX_NUM_SIZE) {
1277             irregularIndexes.append("...");
1278             break;
1279         }
1280     }
1281     irregularIndexes.append("]");
1282     return irregularIndexes;
1283 }
1284 
ProvideRestoreInfo()1285 std::string GridPattern::ProvideRestoreInfo()
1286 {
1287     return std::to_string(info_.startIndex_);
1288 }
1289 
OnRestoreInfo(const std::string & restoreInfo)1290 void GridPattern::OnRestoreInfo(const std::string& restoreInfo)
1291 {
1292     info_.jumpIndex_ = StringUtils::StringToInt(restoreInfo);
1293     info_.scrollAlign_ = ScrollAlign::START;
1294 }
1295 
GetItemRect(int32_t index) const1296 Rect GridPattern::GetItemRect(int32_t index) const
1297 {
1298     if (index < 0 || index < info_.startIndex_ || index > info_.endIndex_) {
1299         return Rect();
1300     }
1301     auto host = GetHost();
1302     CHECK_NULL_RETURN(host, Rect());
1303     auto item = host->GetChildByIndex(index);
1304     CHECK_NULL_RETURN(item, Rect());
1305     auto itemGeometry = item->GetGeometryNode();
1306     CHECK_NULL_RETURN(itemGeometry, Rect());
1307     return Rect(itemGeometry->GetFrameRect().GetX(), itemGeometry->GetFrameRect().GetY(),
1308         itemGeometry->GetFrameRect().Width(), itemGeometry->GetFrameRect().Height());
1309 }
1310 
GetItemIndex(double x,double y) const1311 int32_t GridPattern::GetItemIndex(double x, double y) const
1312 {
1313     for (int32_t index = info_.startIndex_; index <= info_.endIndex_; ++index) {
1314         Rect rect = GetItemRect(index);
1315         if (rect.IsInRegion({ x, y })) {
1316             return index;
1317         }
1318     }
1319     return -1;
1320 }
1321 
ScrollToIndex(int32_t index,bool smooth,ScrollAlign align,std::optional<float> extraOffset)1322 void GridPattern::ScrollToIndex(int32_t index, bool smooth, ScrollAlign align, std::optional<float> extraOffset)
1323 {
1324     SetScrollSource(SCROLL_FROM_JUMP);
1325     StopAnimate();
1326     auto host = GetHost();
1327     CHECK_NULL_VOID(host);
1328     int32_t totalChildCount = host->TotalChildCount();
1329     if (((index >= 0) && (index < totalChildCount)) || (index == LAST_ITEM)) {
1330         if (extraOffset.has_value()) {
1331             info_.extraOffset_ = -extraOffset.value();
1332         }
1333         if (smooth) {
1334             SetExtraOffset(extraOffset);
1335             targetIndex_ = index;
1336             scrollAlign_ = align;
1337             host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1338         } else {
1339             UpdateStartIndex(index, align);
1340         }
1341     }
1342     FireAndCleanScrollingListener();
1343 }
1344 
ScrollToEdge(ScrollEdgeType scrollEdgeType,bool smooth)1345 void GridPattern::ScrollToEdge(ScrollEdgeType scrollEdgeType, bool smooth)
1346 {
1347     if (UseIrregularLayout() && scrollEdgeType == ScrollEdgeType::SCROLL_BOTTOM) {
1348         ScrollToIndex(LAST_ITEM, smooth);
1349         // for irregular layout, last item might not be at bottom
1350         info_.jumpIndex_ = JUMP_TO_BOTTOM_EDGE;
1351         auto host = GetHost();
1352         CHECK_NULL_VOID(host);
1353         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1354         return;
1355     }
1356     ScrollablePattern::ScrollToEdge(scrollEdgeType, smooth);
1357 }
1358 
1359 // Turn on the scrolling animation
AnimateToTarget(ScrollAlign align,const RefPtr<LayoutAlgorithmWrapper> & algo)1360 void GridPattern::AnimateToTarget(ScrollAlign align, const RefPtr<LayoutAlgorithmWrapper>& algo)
1361 {
1362     if (targetIndex_.has_value()) {
1363         AnimateToTargetImpl(align, algo);
1364         targetIndex_.reset();
1365     }
1366 }
1367 
1368 // scroll to the item where the index is located
AnimateToTargetImpl(ScrollAlign align,const RefPtr<LayoutAlgorithmWrapper> & algo)1369 bool GridPattern::AnimateToTargetImpl(ScrollAlign align, const RefPtr<LayoutAlgorithmWrapper>& algo)
1370 {
1371     const float mainGap = GetMainGap();
1372     float targetPos = 0.0f;
1373     auto host = GetHost();
1374     CHECK_NULL_RETURN(host, false);
1375     auto&& extraOffset = GetExtraOffset();
1376     bool success = true;
1377     if (UseIrregularLayout()) {
1378         auto host = GetHost();
1379         CHECK_NULL_RETURN(host, false);
1380         auto size = GridLayoutUtils::GetItemSize(&info_, RawPtr(host), *targetIndex_);
1381         targetPos = info_.GetAnimatePosIrregular(*targetIndex_, size.rows, align, mainGap);
1382         if (Negative(targetPos)) {
1383             success = false;
1384         }
1385     } else {
1386         auto gridScrollLayoutAlgorithm = DynamicCast<GridScrollLayoutAlgorithm>(algo->GetLayoutAlgorithm());
1387         infoCopy_ = gridScrollLayoutAlgorithm->MoveInfoCopy();
1388         // Based on the index, align gets the position to scroll to
1389         success = infoCopy_ && infoCopy_->GetGridItemAnimatePos(info_, *targetIndex_, align, mainGap, targetPos);
1390     }
1391     if (!success) {
1392         if (NearZero(extraOffset.value_or(0.0f))) {
1393             return false;
1394         }
1395         targetPos = GetTotalOffset();
1396     }
1397 
1398     isSmoothScrolling_ = true;
1399     if (extraOffset.has_value()) {
1400         ACE_SCOPED_TRACE(
1401             "AnimateToTargetImpl, success:%u, targetPos:%f, extraOffset:%f", success, targetPos, *extraOffset);
1402         targetPos += *extraOffset;
1403         ResetExtraOffset();
1404     } else {
1405         ACE_SCOPED_TRACE("AnimateToTargetImpl, targetPos:%f", targetPos);
1406     }
1407     if (NearEqual(targetPos, GetTotalOffset())) {
1408         isSmoothScrolling_ = false;
1409         return false;
1410     }
1411     AnimateTo(targetPos, -1, nullptr, true);
1412     return true;
1413 }
1414 
GetVisibleSelectedItems()1415 std::vector<RefPtr<FrameNode>> GridPattern::GetVisibleSelectedItems()
1416 {
1417     std::vector<RefPtr<FrameNode>> children;
1418     auto host = GetHost();
1419     CHECK_NULL_RETURN(host, children);
1420     for (int32_t index = info_.startIndex_; index <= info_.endIndex_; ++index) {
1421         auto item = host->GetChildByIndex(index);
1422         if (!AceType::InstanceOf<FrameNode>(item)) {
1423             continue;
1424         }
1425         auto itemFrameNode = AceType::DynamicCast<FrameNode>(item);
1426         auto itemPattern = itemFrameNode->GetPattern<GridItemPattern>();
1427         if (!itemPattern) {
1428             continue;
1429         }
1430         if (!itemPattern->IsSelected()) {
1431             continue;
1432         }
1433         children.emplace_back(itemFrameNode);
1434     }
1435     return children;
1436 }
1437 
StopAnimate()1438 void GridPattern::StopAnimate()
1439 {
1440     ScrollablePattern::StopAnimate();
1441     isSmoothScrolling_ = false;
1442 }
1443 
IsPredictOutOfRange(int32_t index) const1444 bool GridPattern::IsPredictOutOfRange(int32_t index) const
1445 {
1446     CHECK_NULL_RETURN(info_.reachEnd_, false);
1447     auto host = GetHost();
1448     CHECK_NULL_RETURN(host, true);
1449     auto gridLayoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
1450     CHECK_NULL_RETURN(gridLayoutProperty, true);
1451     auto cacheCount = gridLayoutProperty->GetCachedCountValue(info_.defCachedCount_) * info_.crossCount_;
1452     return index < info_.startIndex_ - cacheCount || index > info_.endIndex_ + cacheCount;
1453 }
1454 
IsPredictInRange(int32_t index) const1455 bool GridPattern::IsPredictInRange(int32_t index) const
1456 {
1457     return index >= info_.startIndex_ && index <= info_.endIndex_;
1458 }
1459 
UseIrregularLayout() const1460 inline bool GridPattern::UseIrregularLayout() const
1461 {
1462     return irregular_ || (SystemProperties::GetGridIrregularLayoutEnabled() &&
1463                              GetLayoutProperty<GridLayoutProperty>()->HasLayoutOptions());
1464 }
1465 
IsReverse() const1466 bool GridPattern::IsReverse() const
1467 {
1468     auto host = GetHost();
1469     CHECK_NULL_RETURN(host, false);
1470     auto gridLayoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
1471     CHECK_NULL_RETURN(gridLayoutProperty, false);
1472     return gridLayoutProperty->IsReverse();
1473 }
1474 
BuildScrollAlignInfo(std::unique_ptr<JsonValue> & json)1475 void GridPattern::BuildScrollAlignInfo(std::unique_ptr<JsonValue>& json)
1476 {
1477     switch (info_.scrollAlign_) {
1478         case ScrollAlign::NONE: {
1479             json->Put("ScrollAlign", "NONE");
1480             break;
1481         }
1482         case ScrollAlign::CENTER: {
1483             json->Put("ScrollAlign", "CENTER");
1484             break;
1485         }
1486         case ScrollAlign::END: {
1487             json->Put("ScrollAlign", "END");
1488             break;
1489         }
1490         case ScrollAlign::START: {
1491             json->Put("ScrollAlign", "START");
1492             break;
1493         }
1494         case ScrollAlign::AUTO: {
1495             json->Put("ScrollAlign", "AUTO");
1496             break;
1497         }
1498         default: {
1499             break;
1500         }
1501     }
1502 }
1503 
BuildGridLayoutInfo(std::unique_ptr<JsonValue> & json)1504 void GridPattern::BuildGridLayoutInfo(std::unique_ptr<JsonValue>& json)
1505 {
1506     if (!info_.gridMatrix_.empty()) {
1507         std::unique_ptr<JsonValue> children = JsonUtil::Create(true);
1508         std::string res = std::string("");
1509         for (auto item : info_.gridMatrix_) {
1510             for (auto index : item.second) {
1511                 res.append("[")
1512                     .append(std::to_string(index.first))
1513                     .append(",")
1514                     .append(std::to_string(index.second))
1515                     .append("] ");
1516             }
1517             children->Put(std::to_string(item.first).c_str(), res.c_str());
1518             res.clear();
1519         }
1520         children->Put("gridMatrix", children);
1521     }
1522     if (!info_.lineHeightMap_.empty()) {
1523         std::unique_ptr<JsonValue> children = JsonUtil::Create(true);
1524         for (auto item : info_.lineHeightMap_) {
1525             children->Put(std::to_string(item.first).c_str(), std::to_string(item.second).c_str());
1526         }
1527         children->Put("lineHeightMap", children);
1528     }
1529     if (!info_.irregularItemsPosition_.empty()) {
1530         std::unique_ptr<JsonValue> children = JsonUtil::Create(true);
1531         for (auto item : info_.irregularItemsPosition_) {
1532             children->Put(std::to_string(item.first).c_str(), std::to_string(item.second).c_str());
1533         }
1534         children->Put("irregularItemsPosition_", children);
1535     }
1536 }
1537 
DumpAdvanceInfo(std::unique_ptr<JsonValue> & json)1538 void GridPattern::DumpAdvanceInfo(std::unique_ptr<JsonValue>& json)
1539 {
1540     auto property = GetLayoutProperty<GridLayoutProperty>();
1541     CHECK_NULL_VOID(property);
1542     ScrollablePattern::DumpAdvanceInfo(json);
1543     json->Put("GridLayoutOptions", property->HasLayoutOptions() ? GetIrregularIndexesString().c_str() : "null");
1544     json->Put("supportAnimation", supportAnimation_);
1545     json->Put("isConfigScrollable", isConfigScrollable_);
1546     json->Put("lastCrossCount",
1547         info_.lastCrossCount_.has_value() ? std::to_string(info_.lastCrossCount_.value()).c_str() : "null");
1548     json->Put("reachEnd", info_.reachEnd_);
1549     json->Put("reachStart", info_.reachStart_);
1550     json->Put("offsetEnd", info_.offsetEnd_);
1551     json->Put("hasBigItem", info_.hasBigItem_);
1552     json->Put("synced", info_.synced_);
1553     json->Put("scrollStop", std::to_string(scrollStop_).c_str());
1554     json->Put("prevHeight", info_.prevHeight_);
1555     json->Put("currentHeight", info_.currentHeight_);
1556     json->Put("endHeight", endHeight_);
1557     json->Put("currentOffset", std::to_string(info_.currentOffset_).c_str());
1558     json->Put("prevOffset", std::to_string(info_.prevOffset_).c_str());
1559     json->Put("lastMainSize", std::to_string(info_.lastMainSize_).c_str());
1560     json->Put("totalHeightOfItemsInView", std::to_string(info_.totalHeightOfItemsInView_).c_str());
1561     json->Put("startIndex", info_.startIndex_);
1562     json->Put("endIndex", info_.endIndex_);
1563     json->Put("jumpIndex", info_.jumpIndex_);
1564     json->Put("crossCount", info_.crossCount_);
1565     json->Put("childrenCount", info_.childrenCount_);
1566     json->Put("RowsTemplate", property->GetRowsTemplate()->c_str());
1567     json->Put("ColumnsTemplate", property->GetColumnsTemplate()->c_str());
1568     json->Put("CachedCount",
1569         property->GetCachedCount().has_value() ? std::to_string(property->GetCachedCount().value()).c_str() : "null");
1570     json->Put("ShowCache", std::to_string(property->GetShowCachedItemsValue(false)).c_str());
1571     json->Put("MaxCount",
1572         property->GetMaxCount().has_value() ? std::to_string(property->GetMaxCount().value()).c_str() : "null");
1573     json->Put("MinCount",
1574         property->GetMinCount().has_value() ? std::to_string(property->GetMinCount().value()).c_str() : "null");
1575     json->Put("CellLength",
1576         property->GetCellLength().has_value() ? std::to_string(property->GetCellLength().value()).c_str() : "null");
1577     json->Put("Editable",
1578         property->GetEditable().has_value() ? std::to_string(property->GetEditable().value()).c_str() : "null");
1579     json->Put("ScrollEnabled", property->GetScrollEnabled().has_value()
1580                                    ? std::to_string(property->GetScrollEnabled().value()).c_str()
1581                                    : "null");
1582 
1583     json->Put("AlignItems", property->GetAlignItems() ? "GridItemAlignment.STRETCH" : "GridItemAlignment.DEFAULT");
1584     BuildScrollAlignInfo(json);
1585     BuildGridLayoutInfo(json);
1586 }
1587 
GetChildrenExpandedSize()1588 SizeF GridPattern::GetChildrenExpandedSize()
1589 {
1590     auto host = GetHost();
1591     CHECK_NULL_RETURN(host, SizeF());
1592     auto layoutProperty = host->GetLayoutProperty<GridLayoutProperty>();
1593     CHECK_NULL_RETURN(layoutProperty, SizeF());
1594     auto padding = layoutProperty->CreatePaddingAndBorder();
1595     auto geometryNode = host->GetGeometryNode();
1596     CHECK_NULL_RETURN(geometryNode, SizeF());
1597     auto viewSize = geometryNode->GetFrameSize();
1598     MinusPaddingToSize(padding, viewSize);
1599 
1600     auto axis = GetAxis();
1601     float estimatedHeight = 0.f;
1602     const auto& info = info_;
1603     auto viewScopeSize = geometryNode->GetPaddingSize();
1604     auto mainGap = GridUtils::GetMainGap(layoutProperty, viewScopeSize, info.axis_);
1605     if (UseIrregularLayout()) {
1606         estimatedHeight = info.GetIrregularHeight(mainGap);
1607     } else if (!layoutProperty->GetLayoutOptions().has_value()) {
1608         estimatedHeight = info.GetContentHeight(mainGap);
1609     } else {
1610         estimatedHeight =
1611             info.GetContentHeight(layoutProperty->GetLayoutOptions().value(), info.childrenCount_, mainGap);
1612     }
1613 
1614     if (axis == Axis::VERTICAL) {
1615         return SizeF(viewSize.Width(), estimatedHeight);
1616     } else if (axis == Axis::HORIZONTAL) {
1617         return SizeF(estimatedHeight, viewSize.Height());
1618     }
1619     return SizeF();
1620 }
1621 
GetScopeFocusAlgorithm()1622 ScopeFocusAlgorithm GridPattern::GetScopeFocusAlgorithm()
1623 {
1624     auto property = GetLayoutProperty<GridLayoutProperty>();
1625     if (!property) {
1626         return ScopeFocusAlgorithm();
1627     }
1628     return ScopeFocusAlgorithm(property->IsVertical(), true, ScopeType::OTHERS,
1629         [wp = WeakClaim(this)](
1630             FocusStep step, const WeakPtr<FocusHub>& currFocusNode, WeakPtr<FocusHub>& nextFocusNode) -> bool {
1631             auto grid = wp.Upgrade();
1632             CHECK_NULL_RETURN(grid, false);
1633             if (grid->UseIrregularLayout() && (step == FocusStep::TAB || step == FocusStep::SHIFT_TAB)) {
1634                 nextFocusNode = grid->focusHandler_.GetNextFocusSimplified(step, currFocusNode.Upgrade());
1635             } else {
1636                 nextFocusNode = grid->focusHandler_.GetNextFocusNode(step, currFocusNode);
1637             }
1638             return nextFocusNode.Upgrade() != currFocusNode.Upgrade();
1639         });
1640 }
1641 
HandleOnItemFocus(int32_t index)1642 void GridPattern::HandleOnItemFocus(int32_t index)
1643 {
1644     focusHandler_.SetFocusIndex(index);
1645 }
1646 } // namespace OHOS::Ace::NG
1647