• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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/grid_layout/render_grid_layout.h"
17 
18 #include <algorithm>
19 #include <cmath>
20 #include <numeric>
21 #include <regex>
22 
23 #include "base/geometry/offset.h"
24 #include "base/log/event_report.h"
25 #include "base/log/log.h"
26 #include "base/memory/referenced.h"
27 #include "base/utils/string_utils.h"
28 #include "base/utils/utils.h"
29 #include "core/animation/curve_animation.h"
30 #include "core/components/grid_layout/grid_layout_component.h"
31 #include "core/components/grid_layout/render_grid_layout_item.h"
32 #include "core/event/ace_event_helper.h"
33 #include "core/gestures/long_press_recognizer.h"
34 #include "core/gestures/pan_recognizer.h"
35 #include "core/gestures/sequenced_recognizer.h"
36 
37 namespace OHOS::Ace {
38 namespace {
39 
40 constexpr int32_t DEFAULT_DEPTH = 10;
41 constexpr bool HORIZONTAL = false;
42 constexpr bool VERTICAL = true;
43 constexpr bool FORWARD = false;
44 constexpr bool REVERSE = true;
45 constexpr double FULL_PERCENT = 100.0;
46 constexpr uint32_t REPEAT_MIN_SIZE = 6;
47 constexpr int32_t GAP_DIVIDE_CONSTEXPR = 2;
48 constexpr int32_t CELL_EMPTY = -1;
49 constexpr int32_t CELL_FOR_INSERT = -2;
50 const char UNIT_PIXEL[] = "px";
51 const char UNIT_VP[] = "vp";
52 const char UNIT_PERCENT[] = "%";
53 const char UNIT_RATIO[] = "fr";
54 const char UNIT_AUTO[] = "auto";
55 const char UNIT_AUTO_FILL[] = "auto-fill";
56 const char REPEAT_PREFIX[] = "repeat";
57 const std::regex REPEAT_NUM_REGEX(R"(^repeat\((\d+),(.+)\))", std::regex::icase); // regex for "repeat(2, 100px)"
58 const std::regex AUTO_REGEX(R"(^repeat\((.+),(.+)\))", std::regex::icase);        // regex for "repeat(auto-fill, 10px)"
59 const std::regex TRIM_REGEX(R"(^ +| +$|(\"[^\"\\\\]*(?:\\\\[\\s\\S][^\"\\\\]*)*\")|( ) +)", std::regex::icase);
60 const char TRIM_TEMPLATE[] = "$1$2";
61 const char INVALID_PATTERN[] = "((repeat)\\(\\s{0,}(auto-fill)\\s{0,},)";
62 const char SIZE_PATTERN[] = "\\s{0,}[0-9]+([.]{1}[0-9]+){0,1}(px|%|vp){0,1}";
63 const char PREFIX_PATTERN[] = "\\S{1,}(repeat)|(px|%|vp)\\d{1,}|\\)\\d{1,}";
64 const char REPEAT_WITH_AUTOFILL[] =
65            "((repeat)\\(\\s{0,}(auto-fill)\\s{0,},(\\s{0,}[0-9]+([.]{1}[0-9]+){0,1}(px|%|vp){0,1}){1,}\\s{0,}\\))";
66 
67 // first bool mean if vertical, second bool mean if reverse
68 // false, false --> RIGHT
69 // false, true --> LEFT
70 // true, false --> DOWN
71 // true, true ---> UP
72 // This map will adapter the Grid FlexDirection with Key Direction.
73 const std::map<bool, std::map<bool, std::map<bool, KeyDirection>>> DIRECTION_MAP = {
74     { false, // RTL is false
75         { { HORIZONTAL, { { FORWARD, KeyDirection::RIGHT }, { REVERSE, KeyDirection::LEFT } } },
76             { VERTICAL, { { FORWARD, KeyDirection::DOWN }, { REVERSE, KeyDirection::UP } } } } },
77     { true, // RTL is true
78         { { HORIZONTAL, { { FORWARD, KeyDirection::LEFT }, { REVERSE, KeyDirection::RIGHT } } },
79             { VERTICAL, { { FORWARD, KeyDirection::DOWN }, { REVERSE, KeyDirection::UP } } } } }
80 };
81 
82 } // namespace
83 
Update(const RefPtr<Component> & component)84 void RenderGridLayout::Update(const RefPtr<Component>& component)
85 {
86     const RefPtr<GridLayoutComponent> grid = AceType::DynamicCast<GridLayoutComponent>(component);
87     if (!grid) {
88         LOGE("RenderGridLayout update failed.");
89         EventReport::SendRenderException(RenderExcepType::RENDER_COMPONENT_ERR);
90         return;
91     }
92 
93     updateFlag_ = true;
94     direction_ = grid->GetDirection();
95     crossAxisAlign_ = grid->GetFlexAlign();
96     gridWidth_ = grid->GetWidth();
97     gridHeight_ = grid->GetHeight();
98     colsArgs_ = grid->GetColumnsArgs();
99     rowsArgs_ = grid->GetRowsArgs();
100     userColGap_ = grid->GetColumnGap();
101     userRowGap_ = grid->GetRowGap();
102     if (TextDirection::RTL == grid->GetTextDirection()) {
103         rightToLeft_ = true;
104     }
105     scrollBarWidth_ = grid->GetScrollBarWidth();
106     scrollBarColor_ = grid->GetScrollBarColor();
107     displayMode_ = grid->GetScrollBar();
108     isDeclarative_ = grid->IsDeclarative();
109 
110     // update other new prop
111     cellLength_ = grid->GetCellLength();
112     mainCountMax_ = grid->GetMaxCount();
113     mainCountMin_ = grid->GetMinCount();
114     editMode_ = grid->GetEditMode();
115 
116     supportAnimation_ = grid->GetSupportAnimation();
117     dragAnimation_ = grid->GetDragAnimation();
118     edgeEffect_ = grid->GetEdgeEffect();
119     onGridDragStartFunc_ = grid->GetOnGridDragStartId();
120     OnGridDragEnterFunc_ = grid->GetOnGridDragEnterId();
121     onGridDragMoveFunc_ = grid->GetOnGridDragMoveId();
122     onGridDragLeaveFunc_ = grid->GetOnGridDragLeaveId();
123     onGridDropFunc_ = grid->GetOnGridDropId();
124 
125     if (((rowsArgs_.empty() && (!colsArgs_.empty())) || ((!rowsArgs_.empty()) && colsArgs_.empty())) &&
126         (mainCountMax_ >= mainCountMin_) && (mainCountMin_ >= 1) && (cellLength_ > 0) && (editMode_ == true)) {
127         isDynamicGrid_ = true;
128     }
129 
130     CalIsVertical();
131 
132     component_ = grid;
133 
134     CreateSlideRecognizer();
135     CreateSpringController();
136     if (editMode_) {
137         if (grid->GetOnGridDropId()) {
138             CreateDragDropRecognizer();
139         }
140         InitAnimationController(GetContext());
141     }
142 
143     isMultiSelectable_ = grid->GetMultiSelectable();
144 
145     MarkNeedLayout();
146 }
147 
UpdateFocusInfo(int32_t focusIndex)148 void RenderGridLayout::UpdateFocusInfo(int32_t focusIndex)
149 {
150     if (focusIndex < 0) {
151         LOGW("Invalid focus index, update focus info failed.");
152         return;
153     }
154     if (focusIndex != focusIndex_) {
155         focusIndex_ = focusIndex;
156         for (const auto& gridMap : gridMatrix_) {
157             for (const auto& grid : gridMap.second) {
158                 if (grid.second == focusIndex) {
159                     focusRow_ = gridMap.first;
160                     focusCol_ = grid.first;
161                 }
162             }
163         }
164     }
165 }
166 
RequestNextFocus(bool vertical,bool reverse)167 int32_t RenderGridLayout::RequestNextFocus(bool vertical, bool reverse)
168 {
169     KeyDirection key = DIRECTION_MAP.at(rightToLeft_).at(vertical).at(reverse);
170     int32_t index = focusMove(key);
171     if (index < 0) {
172         return index;
173     }
174     return focusIndex_;
175 }
176 
177 // Handle direction key move
focusMove(KeyDirection direction)178 int32_t RenderGridLayout::focusMove(KeyDirection direction)
179 {
180     int32_t nextRow = focusRow_ < 0 ? 0 : focusRow_;
181     int32_t nextCol = focusCol_ < 0 ? 0 : focusCol_;
182     int32_t next = focusIndex_;
183     while (focusIndex_ == next || next < 0) {
184         switch (direction) {
185             case KeyDirection::UP:
186                 --nextRow;
187                 break;
188             case KeyDirection::DOWN:
189                 ++nextRow;
190                 break;
191             case KeyDirection::LEFT:
192                 --nextCol;
193                 break;
194             case KeyDirection::RIGHT:
195                 ++nextCol;
196                 break;
197             default:
198                 return -1;
199         }
200         if (nextRow < 0 || nextCol < 0 || nextRow >= rowCount_ || nextCol >= colCount_) {
201             return -1;
202         }
203         next = GetIndexByGrid(nextRow, nextCol);
204     }
205     focusRow_ = nextRow;
206     focusCol_ = nextCol;
207     focusIndex_ = next;
208     return next;
209 }
210 
GetIndexByGrid(int32_t row,int32_t column) const211 int32_t RenderGridLayout::GetIndexByGrid(int32_t row, int32_t column) const
212 {
213     auto rowIter = gridMatrix_.find(row);
214     if (rowIter != gridMatrix_.end()) {
215         auto colIter = rowIter->second.find(column);
216         if (colIter != rowIter->second.end()) {
217             return colIter->second;
218         }
219     }
220     return -1;
221 }
222 
MakeInnerLayoutParam(int32_t row,int32_t col,int32_t rowSpan,int32_t colSpan,bool itemIsPercentUnit) const223 LayoutParam RenderGridLayout::MakeInnerLayoutParam(
224     int32_t row, int32_t col, int32_t rowSpan, int32_t colSpan, bool itemIsPercentUnit) const
225 {
226     LayoutParam innerLayout;
227     double rowLen = 0.0;
228     double colLen = 0.0;
229     for (int32_t i = 0; i < rowSpan; ++i) {
230         rowLen += gridCells_.at(row + i).at(col).Height();
231     }
232     rowLen += (rowSpan - 1) * rowGap_;
233     for (int32_t i = 0; i < colSpan; ++i) {
234         colLen += gridCells_.at(row).at(col + i).Width();
235     }
236     colLen += (colSpan - 1) * colGap_;
237     if (crossAxisAlign_ == FlexAlign::STRETCH) {
238         innerLayout.SetMinSize(Size(colLen, rowLen));
239         innerLayout.SetMaxSize(Size(colLen, rowLen));
240     } else {
241         innerLayout.SetMaxSize(Size(colLen, rowLen));
242     }
243     return innerLayout;
244 }
245 
SetChildPosition(const RefPtr<RenderNode> & child,int32_t row,int32_t col,int32_t rowSpan,int32_t colSpan)246 void RenderGridLayout::SetChildPosition(
247     const RefPtr<RenderNode>& child, int32_t row, int32_t col, int32_t rowSpan, int32_t colSpan)
248 {
249     if (focusRow_ < 0 && focusCol_ < 0) {
250         // Make the first item obtain focus.
251         focusRow_ = row;
252         focusCol_ = col;
253     }
254 
255     // Calculate the position for current child.
256     double positionX = 0.0;
257     double positionY = 0.0;
258     for (int32_t i = 0; i < row; ++i) {
259         positionY += gridCells_.at(i).at(0).Height();
260     }
261     positionY += row * rowGap_;
262     for (int32_t i = 0; i < col; ++i) {
263         positionX += gridCells_.at(0).at(i).Width();
264     }
265     positionX += col * colGap_;
266 
267     // Calculate the size for current child.
268     double rowLen = 0.0;
269     double colLen = 0.0;
270     for (int32_t i = 0; i < rowSpan; ++i) {
271         rowLen += gridCells_.at(row + i).at(col).Height();
272     }
273     rowLen += (rowSpan - 1) * rowGap_;
274     for (int32_t i = 0; i < colSpan; ++i) {
275         colLen += gridCells_.at(row).at(col + i).Width();
276     }
277     colLen += (colSpan - 1) * colGap_;
278 
279     // If RTL, place the item from right.
280     if (rightToLeft_) {
281         positionX = colSize_ - positionX - colLen;
282     }
283 
284     double widthOffset = (colLen - child->GetLayoutSize().Width()) / GAP_DIVIDE_CONSTEXPR;
285     double heightOffset = (rowLen - child->GetLayoutSize().Height()) / GAP_DIVIDE_CONSTEXPR;
286     if (CheckNeedShrink()) {
287         auto allocatedPositionY = allocatedRowSizes_[row] + (row + rowSpan - 1) * rowGap_;
288         child->SetPosition(Offset(positionX + widthOffset, allocatedPositionY));
289     } else {
290         child->SetPosition(Offset(positionX + widthOffset, positionY + heightOffset));
291     }
292 }
293 
CalcChildPosition(const RefPtr<RenderNode> & child,int32_t row,int32_t col,int32_t rowSpan,int32_t colSpan)294 Point RenderGridLayout::CalcChildPosition(
295     const RefPtr<RenderNode>& child, int32_t row, int32_t col, int32_t rowSpan, int32_t colSpan)
296 {
297     if (focusRow_ < 0 && focusCol_ < 0) {
298         // Make the first item obtain focus.
299         focusRow_ = row;
300         focusCol_ = col;
301     }
302 
303     // Calculate the position for current child.
304     double positionX = 0.0;
305     double positionY = 0.0;
306     for (int32_t i = 0; i < row; ++i) {
307         positionY += gridCells_.at(i).at(0).Height();
308     }
309     positionY += row * rowGap_;
310     for (int32_t i = 0; i < col; ++i) {
311         positionX += gridCells_.at(0).at(i).Width();
312     }
313     positionX += col * colGap_;
314 
315     // Calculate the size for current child.
316     double rowLen = 0.0;
317     double colLen = 0.0;
318     for (int32_t i = 0; i < rowSpan; ++i) {
319         rowLen += gridCells_.at(row + i).at(col).Height();
320     }
321     rowLen += (rowSpan - 1) * rowGap_;
322     for (int32_t i = 0; i < colSpan; ++i) {
323         colLen += gridCells_.at(row).at(col + i).Width();
324     }
325     colLen += (colSpan - 1) * colGap_;
326 
327     // If RTL, place the item from right.
328     if (rightToLeft_) {
329         positionX = colSize_ - positionX - colLen;
330     }
331 
332     double widthOffset = (colLen - child->GetLayoutSize().Width()) / GAP_DIVIDE_CONSTEXPR;
333     double heightOffset = (rowLen - child->GetLayoutSize().Height()) / GAP_DIVIDE_CONSTEXPR;
334     return Point(positionX + widthOffset, positionY + heightOffset);
335 }
336 
CalcDragChildStartPosition(const ItemDragInfo & info)337 Point RenderGridLayout::CalcDragChildStartPosition(const ItemDragInfo& info)
338 {
339     double gridPositionX = GetGlobalOffset().GetX();
340     double gridPositionY = GetGlobalOffset().GetY();
341     double dragRelativelyX = info.GetX() - gridPositionX;
342     double dragRelativelyY = info.GetY() - gridPositionY;
343     return Point(dragRelativelyX, dragRelativelyY);
344 }
345 
CalcDragChildEndPosition(int32_t rowIndex,int32_t colIndex)346 Point RenderGridLayout::CalcDragChildEndPosition(int32_t rowIndex, int32_t colIndex)
347 {
348     double positionX = 0.0;
349     double positionY = 0.0;
350     for (int32_t i = 0; i < rowIndex; ++i) {
351         positionY += gridCells_.at(i).at(0).Height();
352     }
353 
354     positionY += rowIndex * rowGap_;
355     for (int32_t i = 0; i < colIndex; ++i) {
356         positionX += gridCells_.at(0).at(i).Width();
357     }
358     positionX += colIndex * colGap_;
359 
360     // If RTL, place the item from right.
361     if (rightToLeft_) {
362         double colLen = gridCells_.at(rowIndex).at(colIndex).Width();
363         positionX = colSize_ - positionX - colLen;
364     }
365     return Point(positionX + GetGlobalOffset().GetX(), positionY + GetGlobalOffset().GetY());
366 }
367 
DisableChild(const RefPtr<RenderNode> & child,int32_t index)368 void RenderGridLayout::DisableChild(const RefPtr<RenderNode>& child, int32_t index)
369 {
370     LayoutParam zeroLayout;
371     zeroLayout.SetMinSize(Size(0.0, 0.0));
372     zeroLayout.SetMaxSize(Size(0.0, 0.0));
373     child->Layout(zeroLayout);
374     child->SetPosition(Offset(0.0, 0.0));
375 }
376 
GetTargetLayoutSize(int32_t row,int32_t col)377 Size RenderGridLayout::GetTargetLayoutSize(int32_t row, int32_t col)
378 {
379     Size size;
380     if (GetChildren().empty()) {
381         return size;
382     }
383     LayoutParam innerLayout; // Init layout param for auto item.
384     innerLayout.SetMaxSize(Size(colSize_, rowSize_));
385     std::vector<std::string> rows, cols;
386     StringUtils::StringSplitter(rowsArgs_, ' ', rows);
387     rowCount_ = rows.size() == 0 ? 1 : rows.size();
388     StringUtils::StringSplitter(colsArgs_, ' ', cols);
389     colCount_ = cols.size() == 0 ? 1 : cols.size();
390     int32_t rowIndex = 0;
391     int32_t colIndex = 0;
392     int32_t itemIndex = 0;
393     for (const auto& item : GetChildren()) {
394         int32_t itemRow = GetItemRowIndex(item);
395         int32_t itemCol = GetItemColumnIndex(item);
396         int32_t itemRowSpan = GetItemSpan(item, true);
397         int32_t itemColSpan = GetItemSpan(item, false);
398         if (itemRow >= 0 && itemRow < rowCount_ && itemCol >= 0 && itemCol < colCount_ &&
399             CheckGridPlaced(itemIndex, itemRow, itemCol, itemRowSpan, itemColSpan)) {
400             if (itemRow == row && itemCol == col) {
401                 item->Layout(innerLayout);
402                 return item->GetLayoutSize();
403             }
404         } else {
405             while (!CheckGridPlaced(itemIndex, rowIndex, colIndex, itemRowSpan, itemColSpan)) {
406                 GetNextGrid(rowIndex, colIndex);
407                 if (rowIndex >= rowCount_ || colIndex >= colCount_) {
408                     break;
409                 }
410             }
411             if (rowIndex == row && colIndex == col) {
412                 item->Layout(innerLayout);
413                 return item->GetLayoutSize();
414             }
415         }
416         ++itemIndex;
417     }
418     return size;
419 }
420 
PreParseRows()421 std::string RenderGridLayout::PreParseRows()
422 {
423     if (rowsArgs_.empty() || rowsArgs_.find(UNIT_AUTO) == std::string::npos) {
424         return rowsArgs_;
425     }
426     std::string rowsArgs;
427     std::vector<std::string> strs;
428     StringUtils::StringSplitter(rowsArgs_, ' ', strs);
429     std::string current;
430     int32_t rowArgSize = strs.size();
431     for (int32_t i = 0; i < rowArgSize; ++i) {
432         current = strs[i];
433         if (strs[i] == std::string(UNIT_AUTO)) {
434             Size layoutSize = GetTargetLayoutSize(i, 0);
435             current = StringUtils::DoubleToString(layoutSize.Height()) + std::string(UNIT_PIXEL);
436             gridMatrix_.clear();
437         }
438         rowsArgs += ' ' + current;
439     }
440     return rowsArgs;
441 }
442 
PreParseCols()443 std::string RenderGridLayout::PreParseCols()
444 {
445     if (colsArgs_.empty() || colsArgs_.find(UNIT_AUTO) == std::string::npos) {
446         return colsArgs_;
447     }
448     std::string colsArgs;
449     std::vector<std::string> strs;
450     StringUtils::StringSplitter(colsArgs_, ' ', strs);
451     std::string current;
452     int32_t colArgSize = strs.size();
453     for (int32_t i = 0; i < colArgSize; ++i) {
454         current = strs[i];
455         if (strs[i] == std::string(UNIT_AUTO)) {
456             Size layoutSize = GetTargetLayoutSize(0, i);
457             current = StringUtils::DoubleToString(layoutSize.Width()) + std::string(UNIT_PIXEL);
458             gridMatrix_.clear();
459         }
460         colsArgs += ' ' + current;
461     }
462     return colsArgs;
463 }
464 
PreParseArgs(const std::string & args)465 std::string RenderGridLayout::PreParseArgs(const std::string& args)
466 {
467     if (args.empty() || args.find(UNIT_AUTO) == std::string::npos) {
468         return args;
469     }
470     std::string arg;
471     std::vector<std::string> strs;
472     StringUtils::StringSplitter(args, ' ', strs);
473     std::string current;
474     int32_t argSize = strs.size();
475     for (int32_t i = 0; i < argSize; ++i) {
476         current = strs[i];
477         if (strs[i] == std::string(UNIT_AUTO)) {
478             Size layoutSize = GetTargetLayoutSize(i, 0);
479             current = StringUtils::DoubleToString(layoutSize.Height()) + std::string(UNIT_PIXEL);
480             gridMatrix_.clear();
481         }
482         arg += ' ' + current;
483     }
484     return arg;
485 }
486 
InitialGridProp()487 void RenderGridLayout::InitialGridProp()
488 {
489     // Not first time layout after update, no need to initial.
490     if (!updateFlag_) {
491         return;
492     }
493     rowGap_ = NormalizePercentToPx(userRowGap_, true);
494     colGap_ = NormalizePercentToPx(userColGap_, false);
495 
496     rowSize_ = ((gridHeight_ > 0.0) && (gridHeight_ < GetLayoutParam().GetMaxSize().Height())) ? gridHeight_
497         : GetLayoutParam().GetMaxSize().Height();
498     colSize_ = ((gridWidth_ > 0.0) && (gridWidth_ < GetLayoutParam().GetMaxSize().Width())) ? gridWidth_
499         : GetLayoutParam().GetMaxSize().Width();
500     if (NearEqual(rowSize_, Size::INFINITE_SIZE) &&
501         (rowsArgs_.find(UNIT_PERCENT) != std::string::npos || rowsArgs_.find(UNIT_RATIO) != std::string::npos)) {
502         rowSize_ = viewPort_.Height();
503     }
504     if (NearEqual(colSize_, Size::INFINITE_SIZE) &&
505         (colsArgs_.find(UNIT_PERCENT) != std::string::npos || colsArgs_.find(UNIT_RATIO) != std::string::npos)) {
506         colSize_ = viewPort_.Width();
507     }
508     std::vector<double> rows = ParseArgs(GetRowTemplate(), rowSize_, rowGap_);
509     std::vector<double> cols = ParseArgs(GetColumnsTemplate(), colSize_, colGap_);
510     if (rows.empty()) {
511         rows.push_back(rowSize_);
512     }
513     if (cols.empty()) {
514         cols.push_back(colSize_);
515     }
516     if (NearEqual(rowSize_, Size::INFINITE_SIZE)) {
517         rowSize_ = std::accumulate(rows.begin(), rows.end(), (rows.size() - 1) * rowGap_);
518         // This case means grid's height is not set and the layout param is infinite(e.g. in a column)
519         // To protect [rowSize_] being set to the max height of layout param in another instant [PerformLayout],
520         // use [gridHeight_] to record grid's height.
521         gridHeight_ = rowSize_;
522     }
523     if (NearEqual(colSize_, Size::INFINITE_SIZE)) {
524         colSize_ = std::accumulate(cols.begin(), cols.end(), (cols.size() - 1) * colGap_);
525         gridWidth_ = colSize_;
526     }
527     // Initialize the columnCount and rowCount, default is 1
528     colCount_ = cols.size();
529     rowCount_ = rows.size();
530     itemCountMax_ = colCount_ * rowCount_;
531     gridCells_.clear();
532     int32_t row = 0;
533     for (auto height : rows) {
534         int32_t col = 0;
535         for (auto width : cols) {
536             gridCells_[row][col] = Size(width, height);
537             ++col;
538         }
539         ++row;
540     }
541     UpdateAccessibilityAttr();
542 }
543 
UpdateAccessibilityAttr()544 void RenderGridLayout::UpdateAccessibilityAttr()
545 {
546     auto refPtr = accessibilityNode_.Upgrade();
547     if (!refPtr) {
548         LOGI("accessibility node is not enabled.");
549         return;
550     }
551     auto collectionInfo = refPtr->GetCollectionInfo();
552     collectionInfo.rows = rowCount_;
553     collectionInfo.columns = colCount_;
554     refPtr->SetCollectionInfo(collectionInfo);
555     refPtr->AddSupportAction(AceAction::ACTION_SCROLL_FORWARD);
556     refPtr->AddSupportAction(AceAction::ACTION_SCROLL_BACKWARD);
557 }
558 
559 // Support five ways below:
560 // (1) 50px 100px 60px
561 // (2) 1fr 1fr 2fr
562 // (3) 30% 20% 50%
563 // (4) repeat(2,100px 20%) -- will be prebuilt by JS Engine to --- 100px 20% 100px 20%
564 // (5) repeat(auto-fill, 100px 300px)  -- will be prebuilt by JS Engine to --- auto-fill 100px 300px
ParseArgsInner(const std::string & args,double size,double gap)565 std::vector<double> RenderGridLayout::ParseArgsInner(const std::string& args, double size, double gap)
566 {
567     std::vector<double> lens;
568     if (args.empty()) {
569         return lens;
570     }
571     double pxSum = 0.0; // First priority: such as 50px
572     double peSum = 0.0; // Second priority: such as 20%
573     double frSum = 0.0; // Third priority: such as 2fr
574     std::vector<std::string> strs;
575     std::string handledArg = args;
576     ConvertRepeatArgs(handledArg);
577     StringUtils::StringSplitter(handledArg, ' ', strs);
578     if (!strs.empty() && strs[0] == UNIT_AUTO_FILL) {
579         return ParseAutoFill(strs, size, gap);
580     }
581     // first loop calculate all type sums.
582     for (auto str : strs) {
583         if (str.find(UNIT_PIXEL) != std::string::npos) {
584             pxSum += StringUtils::StringToDouble(str);
585         } else if (str.find(UNIT_PERCENT) != std::string::npos) {
586             peSum += StringUtils::StringToDouble(str);
587         } else if (str.find(UNIT_RATIO) != std::string::npos) {
588             frSum += StringUtils::StringToDouble(str);
589         } else {
590             LOGE("Unsupported type: %{public}s, and use 0.0", str.c_str());
591         }
592     }
593     if (GreatOrEqual(peSum, FULL_PERCENT)) {
594         peSum = FULL_PERCENT;
595     }
596     // Second loop calculate actual width or height.
597     double sizeLeft = size - (strs.size() - 1) * gap;
598     double prSumLeft = FULL_PERCENT;
599     double frSizeSum = size * (FULL_PERCENT - peSum) / FULL_PERCENT - (strs.size() - 1) * gap - pxSum;
600     for (const auto& str : strs) {
601         double num = StringUtils::StringToDouble(str);
602         if (str.find(UNIT_PIXEL) != std::string::npos) {
603             lens.push_back(sizeLeft < 0.0 ? 0.0 : std::clamp(num, 0.0, sizeLeft));
604             sizeLeft -= num;
605         } else if (str.find(UNIT_PERCENT) != std::string::npos) {
606             num = prSumLeft < num ? prSumLeft : num;
607             auto prSize = size * num / FULL_PERCENT;
608             lens.push_back(prSize);
609             prSumLeft -= num;
610             sizeLeft -= prSize;
611         } else if (str.find(UNIT_RATIO) != std::string::npos) {
612             lens.push_back(NearZero(frSum) ? 0.0 : frSizeSum / frSum * num);
613         } else {
614             lens.push_back(0.0);
615         }
616     }
617     return lens;
618 }
619 
ConvertRepeatArgs(std::string & handledArg)620 void RenderGridLayout::ConvertRepeatArgs(std::string& handledArg)
621 {
622     if (handledArg.find(REPEAT_PREFIX) == std::string::npos) {
623         return;
624     }
625     handledArg.erase(0, handledArg.find_first_not_of(" ")); // trim the input str
626     std::smatch matches;
627     if (handledArg.find(UNIT_AUTO_FILL) != std::string::npos) {
628         // VP vs PX vs no other rules
629         if (handledArg.size() > REPEAT_MIN_SIZE && std::regex_match(handledArg, matches, AUTO_REGEX)) {
630             handledArg = matches[1].str() + matches[2].str();
631         }
632     } else {
633         if (handledArg.size() > REPEAT_MIN_SIZE && std::regex_match(handledArg, matches, REPEAT_NUM_REGEX)) {
634             auto count = StringUtils::StringToInt(matches[1].str());
635             std::string repeatString = matches[2].str();
636             while (count > 1) {
637                 repeatString.append(" " + std::string(matches[2].str()));
638                 --count;
639             }
640             handledArg = repeatString;
641         }
642     }
643 }
644 
ParseAutoFill(const std::vector<std::string> & strs,double size,double gap)645 std::vector<double> RenderGridLayout::ParseAutoFill(const std::vector<std::string>& strs, double size, double gap)
646 {
647     std::vector<double> lens;
648     if (strs.size() <= 1) {
649         return lens;
650     }
651     auto allocatedSize = size - (strs.size() - 2) * gap; // size() - 2 means 'auto-fill' should be erased.
652     double pxSum = 0.0;
653     double peSum = 0.0;
654     for (const auto& str : strs) {
655         auto num = StringUtils::StringToDouble(str);
656         if (str.find(UNIT_PIXEL) != std::string::npos) {
657             num = pxSum > allocatedSize ? 0.0 : num;
658             pxSum += num;
659             lens.emplace_back(num);
660         } else if (str.find(UNIT_PERCENT) != std::string::npos) {
661             // adjust invalid percent
662             num = peSum >= FULL_PERCENT ? 0.0 : num;
663             peSum += num;
664             pxSum += num / FULL_PERCENT * size;
665             lens.emplace_back(num / FULL_PERCENT * size);
666         }
667     }
668     allocatedSize -= pxSum;
669     if (LessOrEqual(allocatedSize, 0.0)) {
670         return lens;
671     }
672     pxSum += lens.size() * gap;
673     int32_t repeatCount = allocatedSize / pxSum;
674     std::vector<double> newLens;
675     for (int32_t i = 0; i < repeatCount + 1; i++) {
676         newLens.insert(newLens.end(), lens.begin(), lens.end());
677     }
678     allocatedSize -= pxSum * repeatCount;
679     for (auto lenIter = lens.begin(); lenIter != lens.end(); lenIter++) {
680         allocatedSize -= *lenIter + gap;
681         if (LessNotEqual(allocatedSize, 0.0)) {
682             break;
683         }
684         newLens.emplace_back(*lenIter);
685     }
686     return newLens;
687 }
688 
SetItemIndex(const RefPtr<RenderNode> & child,int32_t index)689 void RenderGridLayout::SetItemIndex(const RefPtr<RenderNode>& child, int32_t index)
690 {
691     int32_t depth = DEFAULT_DEPTH;
692     auto item = child;
693     auto gridLayoutItem = AceType::DynamicCast<RenderGridLayoutItem>(item);
694     while (!gridLayoutItem && depth > 0) {
695         if (!item || item->GetChildren().empty()) {
696             return;
697         }
698         item = item->GetChildren().front();
699         gridLayoutItem = AceType::DynamicCast<RenderGridLayoutItem>(item);
700         --depth;
701     }
702     if (gridLayoutItem) {
703         gridLayoutItem->SetIndex(index);
704     }
705 }
706 
GetItemRowIndex(const RefPtr<RenderNode> & child) const707 int32_t RenderGridLayout::GetItemRowIndex(const RefPtr<RenderNode>& child) const
708 {
709     int32_t depth = DEFAULT_DEPTH;
710     int32_t rowIndex = -1;
711     auto item = child;
712     auto gridLayoutItem = AceType::DynamicCast<RenderGridLayoutItem>(item);
713     while (!gridLayoutItem && depth > 0) {
714         if (!item || item->GetChildren().empty()) {
715             return rowIndex;
716         }
717         item = item->GetChildren().front();
718         gridLayoutItem = AceType::DynamicCast<RenderGridLayoutItem>(item);
719         --depth;
720     }
721     if (gridLayoutItem) {
722         rowIndex = gridLayoutItem->GetRowIndex();
723     }
724     return rowIndex;
725 }
726 
GetItemColumnIndex(const RefPtr<RenderNode> & child) const727 int32_t RenderGridLayout::GetItemColumnIndex(const RefPtr<RenderNode>& child) const
728 {
729     int32_t depth = DEFAULT_DEPTH;
730     int32_t columnIndex = -1;
731     auto item = child;
732     auto gridLayoutItem = AceType::DynamicCast<RenderGridLayoutItem>(item);
733     while (!gridLayoutItem && depth > 0) {
734         if (!item || item->GetChildren().empty()) {
735             return columnIndex;
736         }
737         item = item->GetChildren().front();
738         gridLayoutItem = AceType::DynamicCast<RenderGridLayoutItem>(item);
739         --depth;
740     }
741     if (gridLayoutItem) {
742         columnIndex = gridLayoutItem->GetColumnIndex();
743     }
744     return columnIndex;
745 }
746 
GetItemSpan(const RefPtr<RenderNode> & child,bool isRow) const747 int32_t RenderGridLayout::GetItemSpan(const RefPtr<RenderNode>& child, bool isRow) const
748 {
749     int32_t depth = DEFAULT_DEPTH;
750     int32_t span = -1;
751     auto item = child;
752     auto gridLayoutItem = AceType::DynamicCast<RenderGridLayoutItem>(item);
753     while (!gridLayoutItem && depth > 0) {
754         if (!item || item->GetChildren().empty()) {
755             return span;
756         }
757         item = item->GetChildren().front();
758         gridLayoutItem = AceType::DynamicCast<RenderGridLayoutItem>(item);
759         --depth;
760     }
761     if (gridLayoutItem) {
762         span = isRow ? gridLayoutItem->GetRowSpan() : gridLayoutItem->GetColumnSpan();
763     }
764     return span < 1 ? 1 : span;
765 }
766 
GetNextGrid(int32_t & curRow,int32_t & curCol) const767 void RenderGridLayout::GetNextGrid(int32_t& curRow, int32_t& curCol) const
768 {
769     if (isVertical_) {
770         ++curCol;
771         if (curCol >= colCount_) {
772             curCol = 0;
773             ++curRow;
774         }
775     } else {
776         ++curRow;
777         if (curRow >= rowCount_) {
778             curRow = 0;
779             ++curCol;
780         }
781     }
782 }
783 
GetPreviousGird(int32_t & curRow,int32_t & curCol) const784 void RenderGridLayout::GetPreviousGird(int32_t& curRow, int32_t& curCol) const
785 {
786     if (isVertical_) {
787         --curCol;
788         if (curCol < 0) {
789             curCol = colCount_ - 1;
790             --curRow;
791         }
792     } else {
793         --curRow;
794         if (curRow < 0) {
795             curRow = rowCount_ - 1;
796             --curCol;
797         }
798     }
799 }
800 
CheckGridPlaced(int32_t index,int32_t row,int32_t col,int32_t & rowSpan,int32_t & colSpan)801 bool RenderGridLayout::CheckGridPlaced(int32_t index, int32_t row, int32_t col, int32_t& rowSpan, int32_t& colSpan)
802 {
803     auto rowIter = gridMatrix_.find(row);
804     if (rowIter != gridMatrix_.end()) {
805         auto colIter = rowIter->second.find(col);
806         if (colIter != rowIter->second.end()) {
807             return false;
808         }
809     }
810     rowSpan = std::min(rowCount_ - row, rowSpan);
811     colSpan = std::min(colCount_ - col, colSpan);
812     int32_t rSpan = 0;
813     int32_t cSpan = 0;
814     int32_t retColSpan = 1;
815     while (rSpan < rowSpan) {
816         rowIter = gridMatrix_.find(rSpan + row);
817         if (rowIter != gridMatrix_.end()) {
818             cSpan = 0;
819             while (cSpan < colSpan) {
820                 if (rowIter->second.find(cSpan + col) != rowIter->second.end()) {
821                     colSpan = cSpan;
822                     break;
823                 }
824                 ++cSpan;
825             }
826         } else {
827             cSpan = colSpan;
828         }
829         if (retColSpan > cSpan) {
830             break;
831         }
832         retColSpan = cSpan;
833         ++rSpan;
834     }
835     rowSpan = rSpan;
836     colSpan = retColSpan;
837     for (int32_t i = row; i < row + rowSpan; ++i) {
838         std::map<int32_t, int32_t> rowMap;
839         auto iter = gridMatrix_.find(i);
840         if (iter != gridMatrix_.end()) {
841             rowMap = iter->second;
842         }
843         for (int32_t j = col; j < col + colSpan; ++j) {
844             rowMap.emplace(std::make_pair(j, index));
845         }
846         gridMatrix_[i] = rowMap;
847     }
848     return true;
849 }
850 
PerformLayout()851 void RenderGridLayout::PerformLayout()
852 {
853     if (CheckAnimation()) {
854         return;
855     }
856     if (isDragChangeLayout_ && !needRestoreScene_) {
857         isDragChangeLayout_ = false;
858         return;
859     }
860     needRestoreScene_ = false;
861     isDragChangeLayout_ = false;
862     gridMatrix_.clear();
863     itemsInGrid_.clear();
864     if (GetChildren().empty()) {
865         return;
866     }
867 
868     // register the item selected callback
869     if (editMode_) {
870         RegisterLongPressedForItems();
871     }
872     // Initialize the the grid layout prop
873     if (isDynamicGrid_) {
874         InitialDynamicGridProp();
875     } else {
876         InitialGridProp();
877     }
878     allocatedRowSizes_.clear();
879     allocatedRowSizes_.insert(allocatedRowSizes_.begin(), rowCount_ + 1, 0.0);
880     if (editMode_) {
881         PerformLayoutForEditGrid();
882         if (needResetItemPosition_) {
883             ResetItemPosition();
884             needResetItemPosition_ = false;
885         }
886     } else {
887         PerformLayoutForStaticGrid();
888     }
889     if (CheckNeedShrink()) {
890         SetLayoutSize(GetLayoutParam().Constrain(Size(colSize_,
891             allocatedRowSizes_.back() + (rowCount_ - 1) * rowGap_)));
892     } else {
893         SetLayoutSize(GetLayoutParam().Constrain(Size(colSize_, rowSize_)));
894     }
895 }
896 
IsUseOnly()897 bool RenderGridLayout::IsUseOnly()
898 {
899     return true;
900 }
901 
CouldBeInserted()902 bool RenderGridLayout::CouldBeInserted()
903 {
904     int32_t itemCount = CountItemInGrid();
905     if (itemCount >= itemCountMax_) {
906         return false;
907     }
908     return true;
909 }
910 
NeedBeLarger()911 bool RenderGridLayout::NeedBeLarger()
912 {
913     int32_t itemCount = CountItemInGrid();
914     if (curItemCountMax_ >= (itemCount + 1)) {
915         return false;
916     }
917     return true;
918 }
919 
NeedBeSmaller()920 bool RenderGridLayout::NeedBeSmaller()
921 {
922     int32_t itemCount = CountItemInGrid();
923     int32_t crossItemCount = 0;
924     if (isVertical_) {
925         crossItemCount = colCount_;
926     } else {
927         crossItemCount = rowCount_;
928     }
929     if ((curItemCountMax_ - crossItemCount) < itemCount) {
930         return false;
931     }
932     return true;
933 }
934 
BackGridMatrix()935 void RenderGridLayout::BackGridMatrix()
936 {
937     gridMatrixBack_.clear();
938     gridMatrixBack_ = gridMatrix_;
939     if (supportAnimation_ || dragAnimation_) {
940         gridItemPosition_.clear();
941         std::map<int32_t, GridItemIndexPosition> backData;
942         ParseRestoreScenePosition(gridMatrixBack_, backData);
943         for (auto& iter : backData) {
944             if (iter.first >= 0 && iter.first < (int32_t)itemsInGrid_.size()) {
945                 auto item = itemsInGrid_[iter.first];
946                 gridItemPosition_[iter.first] = Point(item->GetPosition().GetX(), item->GetPosition().GetY());
947             }
948         }
949     }
950 }
951 
RestoreScene(const ItemDragInfo & info)952 void RenderGridLayout::RestoreScene(const ItemDragInfo& info)
953 {
954     // Until the moving animation is done, only performlayout needs to be triggered here to retrieve the original data
955     // for layout
956     needRestoreScene_ = true;
957     if (supportAnimation_ || dragAnimation_) {
958         CalcRestoreScenePosition(info);
959         if (needRunAnimation_.load()) {
960             StartAnimationController(GridLayoutAnimationAct::ANIMATION_RESTORE_SCENE, nullptr);
961         }
962     }
963     StartFlexController(startGlobalPoint_);
964 }
965 
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)966 void RenderGridLayout::OnTouchTestHit(
967     const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
968 {
969     if (dragDropGesture_) {
970         dragDropGesture_->SetCoordinateOffset(coordinateOffset);
971         result.emplace_back(dragDropGesture_);
972     }
973     if (slideRecognizer_) {
974         slideRecognizer_->SetCoordinateOffset(coordinateOffset);
975         result.emplace_back(slideRecognizer_);
976     }
977 }
978 
ClearPartDragInfo()979 void RenderGridLayout::ClearPartDragInfo()
980 {
981     curInsertRowIndex_ = -1;
982     curInsertColumnIndex_ = -1;
983     dragPosRowIndex_ = -1;
984     dragPosColumnIndex_ = -1;
985     dragPosChanged_ = false;
986 }
987 
ClearAllDragInfo()988 void RenderGridLayout::ClearAllDragInfo()
989 {
990     curInsertRowIndex_ = -1;
991     curInsertColumnIndex_ = -1;
992     dragPosRowIndex_ = -1;
993     dragPosColumnIndex_ = -1;
994     draggingItemIndex_ = -1;
995     dragPosChanged_ = false;
996     itemLongPressed_ = false;
997     itemDragEntered_ = false;
998     itemDragStarted_ = false;
999     isInMainGrid_ = false;
1000     isMainGrid_ = false;
1001     reEnter_ = false;
1002     isDragChangeLayout_ = false;
1003     draggingItemRenderNode_.Reset();
1004     subGrid_.Reset();
1005     mainGrid_.Reset();
1006 }
1007 
CalIsVertical()1008 void RenderGridLayout::CalIsVertical()
1009 {
1010     if (isDynamicGrid_) {
1011         if (!colsArgs_.empty() && rowsArgs_.empty()) {
1012             isVertical_ = true;
1013         } else {
1014             isVertical_ = false;
1015         }
1016     } else {
1017         if (direction_ == FlexDirection::COLUMN) {
1018             isVertical_ = true;
1019         } else {
1020             isVertical_ = false;
1021         }
1022     }
1023 }
1024 
RegisterLongPressedForItems()1025 void RenderGridLayout::RegisterLongPressedForItems()
1026 {
1027     if (GetChildren().empty()) {
1028         LOGE("%{public}s. has no children", __PRETTY_FUNCTION__);
1029         return;
1030     }
1031 
1032     for (const auto& child : GetChildren()) {
1033         int32_t depth = DEFAULT_DEPTH;
1034         auto item = child;
1035         auto gridLayoutItem = AceType::DynamicCast<RenderGridLayoutItem>(item);
1036         while (!gridLayoutItem && depth > 0) {
1037             if (!item || item->GetChildren().empty()) {
1038                 LOGE("%{public}s. item has no children anymore", __PRETTY_FUNCTION__);
1039                 break;
1040             }
1041             item = item->GetChildren().front();
1042             gridLayoutItem = AceType::DynamicCast<RenderGridLayoutItem>(item);
1043             --depth;
1044         }
1045         if (gridLayoutItem) {
1046             gridLayoutItem->SetOnItemLongPressed(
1047                 [weak = WeakClaim(this)](int32_t index, const WeakPtr<RenderNode>& itemRenderNode) {
1048                     auto render = weak.Upgrade();
1049                     if (!render) {
1050                         LOGE("%{public}s .renderGrid is null", __PRETTY_FUNCTION__);
1051                         return false;
1052                     }
1053                     auto item = itemRenderNode.Upgrade();
1054                     if ((index < 0) || (!item)) {
1055                         LOGE("%{public}s .index invalid or item is null", __PRETTY_FUNCTION__);
1056                         return false;
1057                     }
1058 
1059                     if (render->GetSlideDirect() != GridSlideDirect::SLIDE_NODE) {
1060                         LOGE("%{public}s .the grid is sliding now", __PRETTY_FUNCTION__);
1061                         return false;
1062                     }
1063                     render->draggingItemIndex_ = index;
1064                     render->draggingItemRenderNode_ = itemRenderNode;
1065                     render->itemLongPressed_ = true;
1066                     return true;
1067                 });
1068         } else {
1069             LOGI("%{public}s begin child is not item.", __PRETTY_FUNCTION__);
1070         }
1071     }
1072 }
1073 
CreateDragDropRecognizer()1074 void RenderGridLayout::CreateDragDropRecognizer()
1075 {
1076     if (dragDropGesture_) {
1077         return;
1078     }
1079     auto longPress = AceType::MakeRefPtr<LongPressRecognizer>(GetContext(), DEFAULT_DURATION, DEFAULT_FINGERS, false);
1080     longPress->SetOnLongPress(
1081         [weak = WeakClaim<RenderGridLayout>(this), context = GetContext()](const LongPressInfo& info) {
1082             auto renderGrid = weak.Upgrade();
1083             if (renderGrid) {
1084                 GestureEvent eventinfo;
1085                 eventinfo.SetGlobalPoint(Point(info.GetGlobalLocation().GetX(), info.GetGlobalLocation().GetY()));
1086                 auto targetItem = renderGrid->FindTargetRenderNode<RenderGridLayoutItem>(context.Upgrade(), eventinfo);
1087                 if (targetItem) {
1088                     targetItem->OnLongPressEvent();
1089                     renderGrid->SetMainTargetRenderGrid(renderGrid);
1090                     renderGrid->SetPreTargetRenderGrid(renderGrid);
1091                     Point lastLongPressPoint;
1092                     lastLongPressPoint.SetX(eventinfo.GetGlobalPoint().GetX());
1093                     lastLongPressPoint.SetY(eventinfo.GetGlobalPoint().GetY());
1094                     renderGrid->SetLongPressPoint(lastLongPressPoint);
1095                     // update curInsertIndex
1096                     ItemDragInfo dragInfo = ItemDragInfo();
1097                     dragInfo.SetX(info.GetGlobalLocation().GetX());
1098                     dragInfo.SetY(info.GetGlobalLocation().GetY());
1099                     if (renderGrid->CalDragCell(dragInfo)) {
1100                         renderGrid->UpdateCurInsertPos(
1101                             renderGrid->GetDragPosRowIndex(), renderGrid->GetDragPosColumnIndex());
1102                     }
1103                 }
1104             }
1105         });
1106     PanDirection panDirection;
1107     auto pan = AceType::MakeRefPtr<PanRecognizer>(GetContext(), DEFAULT_FINGERS, panDirection, DEFAULT_DISTANCE);
1108     pan->SetOnActionUpdate(std::bind(&RenderGridLayout::PanOnActionUpdate, this, std::placeholders::_1));
1109     pan->SetOnActionEnd(std::bind(&RenderGridLayout::PanOnActionEnd, this, std::placeholders::_1));
1110     pan->SetOnActionCancel([weak = WeakClaim<RenderGridLayout>(this)]() {
1111         auto renderGrid = weak.Upgrade();
1112         if (renderGrid) {
1113             renderGrid->SetPreTargetRenderGrid(nullptr);
1114             renderGrid->SetMainTargetRenderGrid(nullptr);
1115         }
1116     });
1117 
1118     std::vector<RefPtr<GestureRecognizer>> recognizers { longPress, pan };
1119     dragDropGesture_ = AceType::MakeRefPtr<OHOS::Ace::SequencedRecognizer>(GetContext(), recognizers);
1120 }
1121 
ActionStart(const ItemDragInfo & info,RefPtr<Component> customComponent)1122 void RenderGridLayout::ActionStart(const ItemDragInfo& info, RefPtr<Component> customComponent)
1123 {
1124     auto pipelineContext = GetContext().Upgrade();
1125     if (pipelineContext) {
1126         auto stackElement = pipelineContext->GetLastStack();
1127         auto positionedComponent = AceType::MakeRefPtr<PositionedComponent>(customComponent);
1128         positionedComponent->SetTop(Dimension(info.GetY()));
1129         positionedComponent->SetLeft(Dimension(info.GetX()));
1130 
1131         auto updatePosition = [renderGirdLayout = AceType::Claim(this)](const OnItemDragFunc& func) {
1132             if (!renderGirdLayout) {
1133                 return;
1134             }
1135             renderGirdLayout->SetUpdatePositionId(func);
1136         };
1137 
1138         positionedComponent->SetUpdatePositionFuncId(updatePosition);
1139         stackElement->PushComponent(positionedComponent);
1140         stackElement->PerformBuild();
1141     }
1142 }
1143 
PanOnActionUpdate(const GestureEvent & info)1144 void RenderGridLayout::PanOnActionUpdate(const GestureEvent& info)
1145 {
1146     auto renderGirdLayout = AceType::Claim(this);
1147     if (!renderGirdLayout) {
1148         return;
1149     }
1150     if (renderGirdLayout->GetUpdatePositionId() && isExistComponent_) {
1151         Point point = info.GetGlobalPoint();
1152         renderGirdLayout->GetUpdatePositionId()(Dimension(point.GetX()), Dimension(point.GetY()));
1153     }
1154     ItemDragInfo event;
1155     // MMIO could not provide correct point info when touch up, so keep the last point info
1156     lastGlobalPoint_.SetX(info.GetGlobalPoint().GetX());
1157     lastGlobalPoint_.SetY(info.GetGlobalPoint().GetY());
1158     event.SetX(info.GetGlobalPoint().GetX());
1159     event.SetY(info.GetGlobalPoint().GetY());
1160     auto targetRenderGrid = FindTargetRenderNode<RenderGridLayout>(GetContext().Upgrade(), info);
1161     auto preTargetRenderGrid = GetPreTargetRenderGrid();
1162     auto mainTargetRenderGrid = GetMainTargetRenderGrid();
1163 
1164     if (!mainTargetRenderGrid) {
1165         return;
1166     }
1167 
1168     if (targetRenderGrid) {
1169         if (preTargetRenderGrid == targetRenderGrid) {
1170             mainTargetRenderGrid->OnDragMove(event);
1171             return;
1172         }
1173     }
1174     if (preTargetRenderGrid) {
1175         if (itemLongPressed_) {
1176             ItemDragInfo eventLongPress;
1177             eventLongPress.SetX(lastLongPressPoint_.GetX());
1178             eventLongPress.SetY(lastLongPressPoint_.GetY());
1179             mainTargetRenderGrid->OnDragMove(eventLongPress);
1180         }
1181         preTargetRenderGrid->OnDragLeave(event);
1182         subGrid_.Reset();
1183         mainGrid_.Reset();
1184     } else if (targetRenderGrid && !itemLongPressed_) {
1185         targetRenderGrid->mainGrid_ = mainTargetRenderGrid;
1186         subGrid_ = AceType::WeakClaim(AceType::RawPtr(targetRenderGrid));
1187         targetRenderGrid->OnDragEnter(event);
1188     } else {
1189         // drag out of all gridLayout
1190         mainTargetRenderGrid->OnDragMove(event);
1191     }
1192     SetPreTargetRenderGrid(targetRenderGrid);
1193 }
1194 
PanOnActionEnd(const GestureEvent & info)1195 void RenderGridLayout::PanOnActionEnd(const GestureEvent& info)
1196 {
1197     if (!(supportAnimation_ || dragAnimation_)) {
1198         CloseFlexComponent();
1199     }
1200     ItemDragInfo event;
1201     // MMIO could not provide correct point info when touch up, so restore the last point info
1202     event.SetX(lastGlobalPoint_.GetX());
1203     event.SetY(lastGlobalPoint_.GetY());
1204     auto targetRenderGrid = GetPreTargetRenderGrid();
1205     auto mainTargetRenderGrid = GetMainTargetRenderGrid();
1206 
1207     if (targetRenderGrid) {
1208         if (mainTargetRenderGrid) {
1209             mainTargetRenderGrid->OnDrop(event);
1210             SetPreTargetRenderGrid(nullptr);
1211             SetMainTargetRenderGrid(nullptr);
1212         }
1213     } else {
1214         // drag out of all gridLayout
1215         if (mainTargetRenderGrid) {
1216             mainTargetRenderGrid->OnDrop(event);
1217         }
1218     }
1219 }
1220 
OnDragEnter(const ItemDragInfo & info)1221 void RenderGridLayout::OnDragEnter(const ItemDragInfo& info)
1222 {
1223     if (!editMode_) {
1224         LOGW("%{public}s no editMode no dragevent.", __PRETTY_FUNCTION__);
1225         return;
1226     }
1227 
1228     if (component_->GetOnGridDragEnterId()) {
1229         component_->GetOnGridDragEnterId()(info);
1230     }
1231     if (isMainGrid_) {
1232         if (itemDragStarted_) {
1233             ImpDragEnterMainGrid(info);
1234         }
1235     } else {
1236         ImpDragEnterSubGrid(info);
1237     }
1238 }
1239 
OnDragLeave(const ItemDragInfo & info)1240 void RenderGridLayout::OnDragLeave(const ItemDragInfo& info)
1241 {
1242     if (!editMode_) {
1243         LOGW("%{public}s no editMode no dragevent.", __PRETTY_FUNCTION__);
1244         return;
1245     }
1246 
1247     if (isMainGrid_) {
1248         if (itemDragStarted_) {
1249             ImpDragLeaveMainGrid(info);
1250         }
1251     } else {
1252         if (itemDragEntered_) {
1253             ImpDragLeaveSubGrid(info);
1254         }
1255     }
1256 }
1257 
OnDragMove(const ItemDragInfo & info)1258 void RenderGridLayout::OnDragMove(const ItemDragInfo& info)
1259 {
1260     if (!editMode_) {
1261         LOGW("%{public}s no editMode no dragevent.", __PRETTY_FUNCTION__);
1262         return;
1263     }
1264 
1265     if (!itemDragEntered_ && itemLongPressed_ && !itemDragStarted_) {
1266         ImpDragStart(info);
1267     }
1268 
1269     if ((!isInMainGrid_ && itemDragEntered_) || (itemDragStarted_ && isInMainGrid_ && isMainGrid_)) {
1270         ImpDragMove(info);
1271         return;
1272     }
1273     if (isMainGrid_) {
1274         auto subGrid = subGrid_.Upgrade();
1275         if (subGrid && !isInMainGrid_) {
1276             subGrid->OnDragMove(info);
1277             if (component_->GetOnGridDragMoveId()) {
1278                 component_->GetOnGridDragMoveId()(info, draggingItemIndex_, -1);
1279             }
1280         } else if (!isInMainGrid_) {
1281             if (component_->GetOnGridDragMoveId()) {
1282                 component_->GetOnGridDragMoveId()(info, draggingItemIndex_, -1);
1283             }
1284         }
1285     }
1286 }
1287 
ImpDropInGrid(const ItemDragInfo & info)1288 bool RenderGridLayout::ImpDropInGrid(const ItemDragInfo& info)
1289 {
1290     itemDragStarted_ = false;
1291     itemDragEntered_ = false;
1292     bool result = false;
1293     int32_t insertIndex = -1;
1294     gridMatrixBack_.clear();
1295     if (CouldBeInserted()) {
1296         if (CalDragCell(info)) {
1297             MoveItems();
1298         }
1299         insertIndex = CalIndexForItemByRowAndColum(curInsertRowIndex_, curInsertColumnIndex_);
1300         if (insertIndex >= 0 && insertIndex < itemCountMax_) {
1301             result = true;
1302             Point endPoint = CalcDragChildEndPosition(curInsertRowIndex_, curInsertColumnIndex_);
1303             RegisterDropJSEvent(info, insertIndex, result);
1304 
1305             if (needRunAnimation_.load()) {
1306                 StartAnimationController(GridLayoutAnimationAct::ANIMATION_DRAG_DROP, nullptr);
1307             }
1308 
1309             if (isMainGrid_ && isInMainGrid_) {
1310                 StartFlexController(endPoint);
1311             } else {
1312                 auto mainGrid = mainGrid_.Upgrade();
1313                 if (mainGrid) {
1314                     mainGrid->RegisterDropJSEvent(info, -1, result);
1315                     mainGrid->StartFlexController(endPoint, true);
1316                 }
1317             }
1318         } else {
1319             RegisterDropJSEvent(info, -1, false);
1320             RestoreScene(info);
1321             result = true;
1322         }
1323     } else {
1324         RegisterDropJSEvent(info, -1, false);
1325         RestoreScene(info);
1326     }
1327     return result;
1328 }
1329 
ImpDragMove(const ItemDragInfo & info)1330 void RenderGridLayout::ImpDragMove(const ItemDragInfo& info)
1331 {
1332     if (CouldBeInserted() || itemDragStarted_) {
1333         if (CalDragCell(info)) {
1334             MoveItems();
1335             if (needRunAnimation_.load()) {
1336                 StartAnimationController(GridLayoutAnimationAct::ANIMATION_DRAG_MOVE, nullptr);
1337             }
1338         }
1339         if (supportAnimation_ || dragAnimation_) {
1340             TriggerMoveEventForJS(info);
1341         } else {
1342             isDragChangeLayout_ = true;
1343             TriggerMoveEventForJS(info);
1344             MarkNeedLayout();
1345         }
1346     } else {
1347         if (component_->GetOnGridDragMoveId()) {
1348             component_->GetOnGridDragMoveId()(info, draggingItemIndex_, -1);
1349         } else {
1350             LOGE("%{public}s no onGridDragMove registered.", __PRETTY_FUNCTION__);
1351         }
1352     }
1353 }
1354 
ImpDragLeaveMainGrid(const ItemDragInfo & info)1355 void RenderGridLayout::ImpDragLeaveMainGrid(const ItemDragInfo& info)
1356 {
1357     isInMainGrid_ = false;
1358     if (component_->GetOnGridDragLeaveId()) {
1359         component_->GetOnGridDragLeaveId()(info, draggingItemIndex_);
1360     } else {
1361         LOGE("%{public}s no onGridDragLeave registered.", __PRETTY_FUNCTION__);
1362     }
1363     FakeRemoveDragItem();
1364     ClearPartDragInfo();
1365     if ((supportAnimation_ || dragAnimation_) && needRunAnimation_.load()) {
1366         StartAnimationController(GridLayoutAnimationAct::ANIMATION_DRAG_MOVE, [weak = WeakClaim(this)]() {
1367             auto renderGrid = weak.Upgrade();
1368             if (renderGrid) {
1369                 renderGrid->FakeRemoveDragItemUpdate();
1370             }
1371         });
1372     } else {
1373         FakeRemoveDragItemUpdate();
1374         isDragChangeLayout_ = true;
1375         MarkNeedLayout();
1376     }
1377 }
1378 
ImpDragLeaveSubGrid(const ItemDragInfo & info)1379 void RenderGridLayout::ImpDragLeaveSubGrid(const ItemDragInfo& info)
1380 {
1381     ClearAllDragInfo();
1382     if (component_->GetOnGridDragLeaveId()) {
1383         component_->GetOnGridDragLeaveId()(info, -1);
1384     } else {
1385         LOGE("%{public}s no onGridDragLeave registered.", __PRETTY_FUNCTION__);
1386     }
1387     if (isDynamicGrid_ && NeedBeSmaller()) {
1388         // BeSmaller
1389         InitialDynamicGridProp(DRAG_LEAVE);
1390         if (rightToLeft_) {
1391             needResetItemPosition_ = true;
1392         }
1393     }
1394     RestoreScene(info);
1395     isDragChangeLayout_ = true;
1396     MarkNeedLayout();
1397 }
1398 
ImpDragEnterMainGrid(const ItemDragInfo & info)1399 void RenderGridLayout::ImpDragEnterMainGrid(const ItemDragInfo& info)
1400 {
1401     isInMainGrid_ = true;
1402     reEnter_ = true;
1403     if ((supportAnimation_ || dragAnimation_) && needRunAnimation_.load()) {
1404         StartAnimationController(GridLayoutAnimationAct::ANIMATION_DRAG_MOVE, [weak = WeakClaim(this)]() {
1405             auto renderGrid = weak.Upgrade();
1406             if (renderGrid) {
1407                 renderGrid->ImpDragEnterMainGridUpdate();
1408             }
1409         });
1410     } else {
1411         ImpDragEnterMainGridUpdate();
1412     }
1413 }
1414 
ImpDragEnterMainGridUpdate()1415 void RenderGridLayout::ImpDragEnterMainGridUpdate()
1416 {
1417     if (isDynamicGrid_ && NeedBeLarger()) {
1418         // BeLager and render
1419         InitialDynamicGridProp(DRAG_ENTER);
1420         SetLayoutSize(GetLayoutParam().Constrain(Size(colSize_, rowSize_)));
1421         isDragChangeLayout_ = true;
1422         if (rightToLeft_) {
1423             ResetItemPosition();
1424         }
1425         MarkNeedLayout();
1426     }
1427 }
1428 
ImpDragEnterSubGrid(const ItemDragInfo & info)1429 void RenderGridLayout::ImpDragEnterSubGrid(const ItemDragInfo& info)
1430 {
1431     itemDragEntered_ = true;
1432     if (CouldBeInserted()) {
1433         BackGridMatrix();
1434         if (isDynamicGrid_ && NeedBeLarger()) {
1435             // BeLager and render
1436             InitialDynamicGridProp(DRAG_ENTER);
1437             SetLayoutSize(GetLayoutParam().Constrain(Size(colSize_, rowSize_)));
1438             isDragChangeLayout_ = true;
1439             if (rightToLeft_) {
1440                 ResetItemPosition();
1441             }
1442             MarkNeedLayout();
1443         }
1444     }
1445 }
1446 
OnDrop(const ItemDragInfo & info)1447 bool RenderGridLayout::OnDrop(const ItemDragInfo& info)
1448 {
1449     if (!editMode_) {
1450         LOGW("%{public}s no editMode no dragevent.", __PRETTY_FUNCTION__);
1451         return false;
1452     }
1453 
1454     if ((isMainGrid_ && isInMainGrid_ && itemDragStarted_) || (!isMainGrid_ && itemDragEntered_)) {
1455         bool ret = ImpDropInGrid(info);
1456         if (!(supportAnimation_ || dragAnimation_)) {
1457             ClearAllDragInfo();
1458         }
1459         return ret;
1460     }
1461 
1462     if (isMainGrid_) {
1463         auto subGrid = subGrid_.Upgrade();
1464         if (subGrid && !isInMainGrid_) {
1465             bool result = subGrid->OnDrop(info);
1466             if (!result) {
1467                 RestoreScene(info);
1468                 MarkNeedLayout();
1469             }
1470             return result;
1471         } else if (!isInMainGrid_) {
1472             RegisterDropJSEvent(info, -1, false);
1473             RestoreScene(info);
1474             isDragChangeLayout_ = true;
1475             return false;
1476         }
1477     }
1478     ClearAllDragInfo();
1479     return false;
1480 }
1481 
ImpDragStart(const ItemDragInfo & info)1482 void RenderGridLayout::ImpDragStart(const ItemDragInfo& info)
1483 {
1484     itemDragStarted_ = true;
1485     itemLongPressed_ = false;
1486     isMainGrid_ = true;
1487     isInMainGrid_ = true;
1488     ClearSpringSlideData();
1489     BackGridMatrix();
1490     isDragging_.store(true);
1491     auto itemRender = draggingItemRenderNode_.Upgrade();
1492     if (itemRender) {
1493         startGlobalPoint_.SetX(itemRender->GetGlobalOffset().GetX());
1494         startGlobalPoint_.SetY(itemRender->GetGlobalOffset().GetY());
1495         itemRender->SetVisible(false);
1496         DisableChild(itemRender, draggingItemIndex_);
1497     }
1498     if (component_->GetOnGridDragStartId()) {
1499         auto customComponent = component_->GetOnGridDragStartId()(info, draggingItemIndex_);
1500         if (customComponent) {
1501             isExistComponent_ = true;
1502             ActionStart(info, customComponent);
1503         }
1504     } else {
1505         LOGE("%{public}s no onGridDragStart registered.", __PRETTY_FUNCTION__);
1506     }
1507 }
1508 
OnCallSubDragEnter(const ItemDragInfo & info)1509 void RenderGridLayout::OnCallSubDragEnter(const ItemDragInfo& info)
1510 {
1511     auto subGrid = subGrid_.Upgrade();
1512     if (subGrid) {
1513         subGrid->OnDragEnter(info);
1514     }
1515 }
1516 
OnCallSubDragLeave(const ItemDragInfo & info)1517 void RenderGridLayout::OnCallSubDragLeave(const ItemDragInfo& info)
1518 {
1519     auto subGrid = subGrid_.Upgrade();
1520     if (subGrid) {
1521         subGrid->OnDragLeave(info);
1522     }
1523 }
1524 
CountItemInGrid()1525 int32_t RenderGridLayout::CountItemInGrid()
1526 {
1527     int32_t count = 0;
1528     for (int main = 0; main < rowCount_; main++) {
1529         auto mainIter = gridMatrix_.find(main);
1530         if (mainIter != gridMatrix_.end()) {
1531             count += CountItemInRow(mainIter);
1532         }
1533     }
1534     return count;
1535 }
1536 
CountItemInRow(const std::map<int32_t,std::map<int32_t,int32_t>>::iterator & rowGrid)1537 int32_t RenderGridLayout::CountItemInRow(const std::map<int32_t, std::map<int32_t, int32_t>>::iterator& rowGrid)
1538 {
1539     int32_t count = 0;
1540     for (int cross = 0; cross < colCount_; cross++) {
1541         auto crossIter = rowGrid->second.find(cross);
1542         if (crossIter != rowGrid->second.end()) {
1543             int32_t index = crossIter->second;
1544             if (index >= 0) {
1545                 count++;
1546             }
1547         }
1548     }
1549     return count;
1550 }
1551 
ResetItemPosition()1552 void RenderGridLayout::ResetItemPosition()
1553 {
1554     for (const auto& gridMap : gridMatrix_) {
1555         int32_t row = gridMap.first;
1556         for (const auto& grid : gridMap.second) {
1557             int32_t col = grid.first;
1558             int32_t index = grid.second;
1559             if (index >= 0 && index < (int32_t)itemsInGrid_.size()) {
1560                 SetChildPosition(itemsInGrid_[index], row, col, 1, 1);
1561             }
1562         }
1563     }
1564 }
1565 
InitialDynamicGridProp(int32_t dragLeaveOrEnter)1566 void RenderGridLayout::InitialDynamicGridProp(int32_t dragLeaveOrEnter)
1567 {
1568     rowGap_ = NormalizePercentToPx(userRowGap_, true);
1569     colGap_ = NormalizePercentToPx(userColGap_, false);
1570 
1571     SetGridLayoutParam();
1572 
1573     std::vector<double> cols;
1574     std::vector<double> rows;
1575     if (isVertical_) {
1576         CalculateVerticalSize(cols, rows, dragLeaveOrEnter);
1577         itemCountMax_ = colCount_ * mainCountMax_;
1578     } else {
1579         CalculateHorizontalSize(cols, rows, dragLeaveOrEnter);
1580         itemCountMax_ = rowCount_ * mainCountMax_;
1581     }
1582     curItemCountMax_ = colCount_ * rowCount_;
1583 
1584     UpdateCollectionInfo(cols, rows);
1585 }
1586 
SetGridLayoutParam()1587 void RenderGridLayout::SetGridLayoutParam()
1588 {
1589     LayoutParam gridLayoutParam = GetLayoutParam();
1590     auto maxHeight = isVertical_ ? mainCountMax_ * cellLength_ + (mainCountMax_ - 1) * rowGap_
1591                                  : GetLayoutParam().GetMaxSize().Height();
1592     auto maxWidth = isVertical_ ? GetLayoutParam().GetMaxSize().Width()
1593                                 : mainCountMax_ * cellLength_ + (mainCountMax_ - 1) * colGap_;
1594     auto minHeight = isVertical_ ? mainCountMin_ * cellLength_ + (mainCountMin_ - 1) * rowGap_
1595                                  : GetLayoutParam().GetMaxSize().Height();
1596     auto minWidth = isVertical_ ? GetLayoutParam().GetMaxSize().Width()
1597                                 : mainCountMin_ * cellLength_ + (mainCountMin_ - 1) * colGap_;
1598     gridLayoutParam.SetMaxSize(Size(maxWidth, maxHeight));
1599     gridLayoutParam.SetMinSize(Size(minWidth, minHeight));
1600     SetLayoutParam(gridLayoutParam);
1601 }
1602 
CalculateVerticalSize(std::vector<double> & cols,std::vector<double> & rows,int32_t dragLeaveOrEnter)1603 void RenderGridLayout::CalculateVerticalSize(
1604     std::vector<double>& cols, std::vector<double>& rows, int32_t dragLeaveOrEnter)
1605 {
1606     colSize_ = ((gridWidth_ > 0.0) && (gridWidth_ < GetLayoutParam().GetMaxSize().Width()))
1607                    ? gridWidth_
1608                    : GetLayoutParam().GetMaxSize().Width();
1609     if (NearEqual(colSize_, Size::INFINITE_SIZE) &&
1610         (colsArgs_.find(UNIT_PERCENT) != std::string::npos || colsArgs_.find(UNIT_RATIO) != std::string::npos)) {
1611         colSize_ = viewPort_.Width();
1612     }
1613     // Get item width
1614     cols = ParseArgs(GetColumnsTemplate(), colSize_, colGap_);
1615     if (cols.empty()) {
1616         cols.push_back(colSize_);
1617     }
1618     // Get the number of items in each row
1619     colCount_ = cols.size();
1620     // Get the number of items
1621     auto totalNum = (int32_t)GetChildren().size() + dragLeaveOrEnter;
1622     // Count the number of rows
1623     rowCount_ =
1624         std::clamp((totalNum / colCount_ + (((totalNum % colCount_) == 0) ? 0 : 1)), mainCountMin_, mainCountMax_);
1625     rows = std::vector<double>(rowCount_, cellLength_);
1626     rowSize_ = rowCount_ * cellLength_ + (rowCount_ - 1) * rowGap_;
1627 }
1628 
CalculateHorizontalSize(std::vector<double> & cols,std::vector<double> & rows,int32_t dragLeaveOrEnter)1629 void RenderGridLayout::CalculateHorizontalSize(
1630     std::vector<double>& cols, std::vector<double>& rows, int32_t dragLeaveOrEnter)
1631 {
1632     rowSize_ = ((gridHeight_ > 0.0) && (gridHeight_ < GetLayoutParam().GetMaxSize().Height()))
1633                    ? gridHeight_
1634                    : GetLayoutParam().GetMaxSize().Height();
1635     if (NearEqual(rowSize_, Size::INFINITE_SIZE) &&
1636         (rowsArgs_.find(UNIT_PERCENT) != std::string::npos || rowsArgs_.find(UNIT_RATIO) != std::string::npos)) {
1637         rowSize_ = viewPort_.Height();
1638     }
1639     // Get item width
1640     rows = ParseArgs(GetRowTemplate(), rowSize_, rowGap_);
1641     if (rows.empty()) {
1642         rows.push_back(rowSize_);
1643     }
1644     // Get the number of items in each col
1645     rowCount_ = rows.size();
1646     // Get the number of items
1647     auto totalNum = (int32_t)GetChildren().size() + dragLeaveOrEnter;
1648     // Count the number of cols
1649     colCount_ =
1650         std::clamp((totalNum / rowCount_ + (((totalNum % rowCount_) == 0) ? 0 : 1)), mainCountMin_, mainCountMax_);
1651     cols = std::vector<double>(colCount_, cellLength_);
1652     colSize_ = colCount_ * cellLength_ + (colCount_ - 1) * colGap_;
1653 }
1654 
UpdateCollectionInfo(std::vector<double> cols,std::vector<double> rows)1655 void RenderGridLayout::UpdateCollectionInfo(std::vector<double> cols, std::vector<double> rows)
1656 {
1657     gridCells_.clear();
1658     int32_t row = 0;
1659     for (auto height : rows) {
1660         int32_t col = 0;
1661         for (auto width : cols) {
1662             gridCells_[row][col] = Size(width, height);
1663             ++col;
1664         }
1665         ++row;
1666     }
1667     UpdateAccessibilityAttr();
1668 }
1669 
PerformLayoutForEditGrid()1670 void RenderGridLayout::PerformLayoutForEditGrid()
1671 {
1672     int32_t itemIndex = 0;
1673     int32_t rowIndex = 0;
1674     int32_t colIndex = 0;
1675     itemsInGrid_.clear();
1676     for (const auto& item : GetChildren()) {
1677         int32_t itemRowSpan = 1;
1678         int32_t itemColSpan = 1;
1679         if (rowIndex >= 0 && rowIndex < rowCount_ && colIndex >= 0 && colIndex < colCount_) {
1680             while (!CheckGridPlaced(itemIndex, rowIndex, colIndex, itemRowSpan, itemColSpan)) {
1681                 GetNextGrid(rowIndex, colIndex);
1682                 if (rowIndex >= rowCount_ || colIndex >= colCount_) {
1683                     break;
1684                 }
1685             }
1686             if (rowIndex >= rowCount_ || colIndex >= colCount_) {
1687                 DisableChild(item, itemIndex);
1688                 continue;
1689             }
1690             item->Layout(MakeInnerLayoutParam(rowIndex, colIndex, itemRowSpan, itemColSpan));
1691             SetChildPosition(item, rowIndex, colIndex, itemRowSpan, itemColSpan);
1692             itemsInGrid_.push_back(item);
1693             RefreshAllocatedRowSizes(rowIndex, itemRowSpan, item);
1694             SetItemIndex(item, itemIndex); // Set index for focus adjust.
1695             ++itemIndex;
1696         }
1697     }
1698 }
1699 
PerformLayoutForStaticGrid()1700 void RenderGridLayout::PerformLayoutForStaticGrid()
1701 {
1702     int32_t rowIndex = 0;
1703     int32_t colIndex = 0;
1704     int32_t itemIndex = 0;
1705     for (const auto& item : GetChildren()) {
1706         int32_t itemRow = GetItemRowIndex(item);
1707         int32_t itemCol = GetItemColumnIndex(item);
1708         int32_t itemRowSpan = GetItemSpan(item, true);
1709         int32_t itemColSpan = GetItemSpan(item, false);
1710         if (itemRow >= 0 && itemRow < rowCount_ && itemCol >= 0 && itemCol < colCount_ &&
1711             CheckGridPlaced(itemIndex, itemRow, itemCol, itemRowSpan, itemColSpan)) {
1712             item->Layout(MakeInnerLayoutParam(itemRow, itemCol, itemRowSpan, itemColSpan));
1713             SetChildPosition(item, itemRow, itemCol, itemRowSpan, itemColSpan);
1714         } else {
1715             while (!CheckGridPlaced(itemIndex, rowIndex, colIndex, itemRowSpan, itemColSpan)) {
1716                 GetNextGrid(rowIndex, colIndex);
1717                 if (rowIndex >= rowCount_ || colIndex >= colCount_) {
1718                     break;
1719                 }
1720             }
1721             if (rowIndex >= rowCount_ || colIndex >= colCount_) {
1722                 DisableChild(item, itemIndex);
1723                 continue;
1724             }
1725             item->Layout(MakeInnerLayoutParam(rowIndex, colIndex, itemRowSpan, itemColSpan));
1726             SetChildPosition(item, rowIndex, colIndex, itemRowSpan, itemColSpan);
1727         }
1728         RefreshAllocatedRowSizes(rowIndex, itemRowSpan, item);
1729         SetItemIndex(item, itemIndex); // Set index for focus adjust.
1730         ++itemIndex;
1731     }
1732 }
1733 
CalDragCell(const ItemDragInfo & info)1734 bool RenderGridLayout::CalDragCell(const ItemDragInfo& info)
1735 {
1736     double gridPositionX = GetGlobalOffset().GetX();
1737     double gridPositionY = GetGlobalOffset().GetY();
1738     double dragRelativelyX = info.GetX() - gridPositionX;
1739     double dragRelativelyY = info.GetY() - gridPositionY;
1740     if (rightToLeft_) {
1741         dragRelativelyX = colSize_ - dragRelativelyX;
1742     }
1743 
1744     int32_t tmpDragPosRowIndex = -1;
1745     int32_t tmpDragPosColumIndex = -1;
1746     if (!CalDragRowIndex(dragRelativelyY, tmpDragPosRowIndex)) {
1747         return false;
1748     }
1749 
1750     if (!CalDragColumIndex(dragRelativelyX, tmpDragPosColumIndex)) {
1751         return false;
1752     }
1753 
1754     if ((dragPosRowIndex_ != tmpDragPosRowIndex) || (dragPosColumnIndex_ != tmpDragPosColumIndex)) {
1755         dragPosRowIndex_ = tmpDragPosRowIndex;
1756         dragPosColumnIndex_ = tmpDragPosColumIndex;
1757         dragPosChanged_ = true;
1758     }
1759     return true;
1760 }
1761 
CalDragRowIndex(double dragRelativelyY,int32_t & dragRowIndex)1762 bool RenderGridLayout::CalDragRowIndex(double dragRelativelyY, int32_t& dragRowIndex)
1763 {
1764     double rowStart = 0.0;
1765     double rowEnd = 0.0;
1766     for (int row = 0; row < rowCount_; row++) {
1767         rowStart = rowEnd;
1768         double offsetY = 0.0;
1769         if (row > 0 && row < (rowCount_ - 1)) {
1770             offsetY = rowGap_ / GAP_DIVIDE_CONSTEXPR;
1771         } else {
1772             offsetY = rowGap_;
1773         }
1774         rowEnd += gridCells_.at(row).at(0).Height() + offsetY;
1775         if (dragRelativelyY >= rowStart && dragRelativelyY <= rowEnd) {
1776             dragRowIndex = row;
1777             return true;
1778         }
1779     }
1780     return false;
1781 }
1782 
CalDragColumIndex(double dragRelativelyX,int32_t & dragColIndex)1783 bool RenderGridLayout::CalDragColumIndex(double dragRelativelyX, int32_t& dragColIndex)
1784 {
1785     double columStart = 0.0;
1786     double columEnd = 0.0;
1787     for (int col = 0; col < colCount_; col++) {
1788         columStart = columEnd;
1789         double offsetX = 0.0;
1790         if (col > 0 && col < (colCount_ - 1)) {
1791             offsetX = colGap_ / GAP_DIVIDE_CONSTEXPR;
1792         } else {
1793             offsetX = colGap_;
1794         }
1795         columEnd += gridCells_.at(0).at(col).Width() + offsetX;
1796         if (dragRelativelyX >= columStart && dragRelativelyX <= columEnd) {
1797             dragColIndex = col;
1798             return true;
1799         }
1800     }
1801     return false;
1802 }
1803 
MoveItems()1804 void RenderGridLayout::MoveItems()
1805 {
1806     if (!dragPosChanged_) {
1807         LOGI("%{public}s dragPos not change no need to move.", __PRETTY_FUNCTION__);
1808         return;
1809     }
1810     if (curInsertRowIndex_ >= 0 && curInsertColumnIndex_ >= 0) {
1811         // If there has been insert Cell now.
1812         MoveWhenWithInsertCell();
1813     } else {
1814         MoveWhenNoInsertCell();
1815     }
1816     dragPosChanged_ = false;
1817 }
1818 
MoveWhenNoInsertCell()1819 void RenderGridLayout::MoveWhenNoInsertCell()
1820 {
1821     int32_t dragposIndex = GetIndexByGrid(dragPosRowIndex_, dragPosColumnIndex_);
1822     if (dragposIndex == -1) {
1823         // If there is no item in the cell
1824         MoveWhenNoInsertCellAndNoItemInDragCell();
1825     } else {
1826         MoveWhenNoInsertCellButWithItemInDragCell();
1827     }
1828 }
1829 
MoveWhenNoInsertCellAndNoItemInDragCell()1830 void RenderGridLayout::MoveWhenNoInsertCellAndNoItemInDragCell()
1831 {
1832     int32_t FirstEmptyCellRowIndex = -1;
1833     int32_t FirstEmptyCellColumIndex = -1;
1834     if (CalTheFirstEmptyCell(FirstEmptyCellRowIndex, FirstEmptyCellColumIndex, true)) {
1835         UpdateCurInsertPos(FirstEmptyCellRowIndex, FirstEmptyCellColumIndex);
1836     }
1837 }
1838 
MoveWhenNoInsertCellButWithItemInDragCell()1839 void RenderGridLayout::MoveWhenNoInsertCellButWithItemInDragCell()
1840 {
1841     if (itemDragEntered_ || (itemDragStarted_ && reEnter_)) {
1842         MoveWhenNoInsertCellButWithItemInDragCellAndDragEnter();
1843     } else if (itemDragStarted_ && !reEnter_) {
1844         MoveWhenNoInsertCellButWithItemInDragCellAndDragStart();
1845     }
1846 }
1847 
MoveWhenNoInsertCellButWithItemInDragCellAndDragEnter()1848 void RenderGridLayout::MoveWhenNoInsertCellButWithItemInDragCellAndDragEnter()
1849 {
1850     int32_t endRow = -1;
1851     int32_t endColum = -1;
1852     if (CalTheFirstEmptyCell(endRow, endColum, true)) {
1853         GetPreviousGird(endRow, endColum);
1854         if (MoveItemsForward(dragPosRowIndex_, dragPosColumnIndex_, endRow, endColum)) {
1855             if (supportAnimation_ || dragAnimation_) {
1856                 std::string key(__FUNCTION__);
1857                 RegisterAnimationFinishedFunc(
1858                     key, [weak = WeakClaim(this), rowIndex = dragPosRowIndex_, colIndex = dragPosColumnIndex_]() {});
1859                 UpdateCurInsertPos(dragPosRowIndex_, dragPosColumnIndex_);
1860                 PrepareAnimationController(key);
1861             } else {
1862                 UpdateCurInsertPos(dragPosRowIndex_, dragPosColumnIndex_);
1863             }
1864         }
1865     }
1866 }
1867 
MoveWhenNoInsertCellButWithItemInDragCellAndDragStart()1868 void RenderGridLayout::MoveWhenNoInsertCellButWithItemInDragCellAndDragStart()
1869 {
1870     UpdateCurInsertPos(dragPosRowIndex_, dragPosColumnIndex_);
1871 }
1872 
MoveWhenWithInsertCell()1873 void RenderGridLayout::MoveWhenWithInsertCell()
1874 {
1875     int32_t dragposIndex = GetIndexByGrid(dragPosRowIndex_, dragPosColumnIndex_);
1876     if (dragposIndex == -1) {
1877         // If there is no item in the cell
1878         MoveWhenWithInsertCellAndNoItemInDragCell();
1879     } else {
1880         MoveWhenWithInsertCellButWithItemInDragCell();
1881     }
1882 }
1883 
MoveWhenWithInsertCellAndNoItemInDragCell()1884 void RenderGridLayout::MoveWhenWithInsertCellAndNoItemInDragCell()
1885 {
1886     int32_t endRow = -1;
1887     int32_t endColum = -1;
1888     if (CalTheFirstEmptyCell(endRow, endColum, true)) {
1889         GetPreviousGird(endRow, endColum);
1890         int32_t startRow = curInsertRowIndex_;
1891         int32_t startColum = curInsertColumnIndex_;
1892         GetNextGrid(startRow, startColum);
1893         if (MoveItemsBackward(startRow, startColum, endRow, endColum)) {
1894             if (supportAnimation_ || dragAnimation_) {
1895                 std::string key(__FUNCTION__);
1896                 RegisterAnimationFinishedFunc(
1897                     key, [weak = WeakClaim(this), rowIndex = endRow, colIndex = endColum]() {});
1898                 UpdateCurInsertPos(endRow, endColum);
1899                 PrepareAnimationController(key);
1900             } else {
1901                 UpdateCurInsertPos(endRow, endColum);
1902             }
1903         }
1904     }
1905 }
1906 
MoveWhenWithInsertCellButWithItemInDragCell()1907 void RenderGridLayout::MoveWhenWithInsertCellButWithItemInDragCell()
1908 {
1909     bool dragIsBefore = false;
1910     bool dragIsCur =
1911         SortCellIndex(dragPosRowIndex_, dragPosColumnIndex_, curInsertRowIndex_, curInsertColumnIndex_, dragIsBefore);
1912     if (!dragIsCur && dragIsBefore) {
1913         MoveWhenWithInsertCellButWithItemInDragCellDragBeforeInsert();
1914     } else if (!dragIsCur && !dragIsBefore) {
1915         MoveWhenWithInsertCellButWithItemInDragCellDragAfterInsert();
1916     }
1917 }
1918 
MoveWhenWithInsertCellButWithItemInDragCellDragBeforeInsert()1919 void RenderGridLayout::MoveWhenWithInsertCellButWithItemInDragCellDragBeforeInsert()
1920 {
1921     int32_t endRow = curInsertRowIndex_;
1922     int32_t endColum = curInsertColumnIndex_;
1923     GetPreviousGird(endRow, endColum);
1924     if (MoveItemsForward(dragPosRowIndex_, dragPosColumnIndex_, endRow, endColum)) {
1925         if (supportAnimation_ || dragAnimation_) {
1926             std::string key(__FUNCTION__);
1927             RegisterAnimationFinishedFunc(
1928                 key, [weak = WeakClaim(this), rowIndex = dragPosRowIndex_, colIndex = dragPosColumnIndex_]() {});
1929             UpdateCurInsertPos(dragPosRowIndex_, dragPosColumnIndex_);
1930             PrepareAnimationController(key);
1931         } else {
1932             UpdateCurInsertPos(dragPosRowIndex_, dragPosColumnIndex_);
1933         }
1934     }
1935 }
1936 
MoveWhenWithInsertCellButWithItemInDragCellDragAfterInsert()1937 void RenderGridLayout::MoveWhenWithInsertCellButWithItemInDragCellDragAfterInsert()
1938 {
1939     int32_t startRow = curInsertRowIndex_;
1940     int32_t startColum = curInsertColumnIndex_;
1941     GetNextGrid(startRow, startColum);
1942     if (MoveItemsBackward(startRow, startColum, dragPosRowIndex_, dragPosColumnIndex_)) {
1943         if (supportAnimation_ || dragAnimation_) {
1944             std::string key(__FUNCTION__);
1945             RegisterAnimationFinishedFunc(
1946                 key, [weak = WeakClaim(this), rowIndex = dragPosRowIndex_, colIndex = dragPosColumnIndex_]() {});
1947             UpdateCurInsertPos(dragPosRowIndex_, dragPosColumnIndex_);
1948             PrepareAnimationController(key);
1949         } else {
1950             UpdateCurInsertPos(dragPosRowIndex_, dragPosColumnIndex_);
1951         }
1952     }
1953 }
1954 
FakeRemoveDragItem()1955 void RenderGridLayout::FakeRemoveDragItem()
1956 {
1957     dragPosRowIndex_ = -1;
1958     dragPosColumnIndex_ = -1;
1959 
1960     int32_t endRow = -1;
1961     int32_t endColum = -1;
1962     bool ret = CalTheFirstEmptyCell(endRow, endColum, true);
1963     if (!ret) {
1964         endRow = rowCount_ - 1;
1965         endColum = colCount_ - 1;
1966     }
1967     if (curInsertRowIndex_ == endRow && curInsertColumnIndex_ == endColum) {
1968         UpdateMatrixByIndexStrong(CELL_EMPTY, curInsertRowIndex_, curInsertColumnIndex_);
1969         curInsertRowIndex_ = -1;
1970         curInsertColumnIndex_ = -1;
1971     } else {
1972         int32_t startRow = curInsertRowIndex_;
1973         int32_t startColum = curInsertColumnIndex_;
1974         if (ret) {
1975             GetPreviousGird(endRow, endColum);
1976         }
1977         GetNextGrid(startRow, startColum);
1978         if (MoveItemsBackward(startRow, startColum, endRow, endColum)) {
1979             if ((supportAnimation_ || dragAnimation_) && needRunAnimation_.load()) {
1980                 std::string key(__FUNCTION__);
1981                 RegisterAnimationFinishedFunc(key, [weak = WeakClaim(this), rowIndex = endRow, colIndex = endColum]() {
1982                     auto renderGrid = weak.Upgrade();
1983                     if (renderGrid) {
1984                         renderGrid->curInsertRowIndex_ = -1;
1985                         renderGrid->curInsertColumnIndex_ = -1;
1986                         renderGrid->UpdateMatrixByIndexStrong(CELL_EMPTY, rowIndex, colIndex);
1987                     }
1988                 });
1989                 PrepareAnimationController(key);
1990             } else {
1991                 curInsertRowIndex_ = -1;
1992                 curInsertColumnIndex_ = -1;
1993                 UpdateMatrixByIndexStrong(CELL_EMPTY, endRow, endColum);
1994             }
1995         } else {
1996             if ((supportAnimation_ || dragAnimation_) && needRunAnimation_.load()) {
1997                 std::string key(__FUNCTION__);
1998                 PrepareAnimationController(key);
1999             }
2000         }
2001     }
2002 }
2003 
FakeRemoveDragItemUpdate()2004 void RenderGridLayout::FakeRemoveDragItemUpdate()
2005 {
2006     if (isDynamicGrid_ && NeedBeSmaller()) {
2007         InitialDynamicGridProp(DRAG_LEAVE);
2008         SetLayoutSize(GetLayoutParam().Constrain(Size(colSize_, rowSize_)));
2009         if (rightToLeft_) {
2010             ResetItemPosition();
2011         }
2012     }
2013 }
2014 
MoveItemsForward(int32_t fromRow,int32_t fromColum,int32_t toRow,int32_t toColum)2015 bool RenderGridLayout::MoveItemsForward(int32_t fromRow, int32_t fromColum, int32_t toRow, int32_t toColum)
2016 {
2017     bool valid = false;
2018     if (!SortCellIndex(fromRow, fromColum, toRow, toColum, valid) && (!valid)) {
2019         return false;
2020     }
2021 
2022     int32_t curRow = toRow;
2023     int32_t curColum = toColum;
2024     int32_t targetRow = toRow;
2025     int32_t targetColum = toColum;
2026     int32_t tmpIndex = -1;
2027 
2028     bool equal = false;
2029     equal = SortCellIndex(fromRow, fromColum, curRow, curColum, valid);
2030 
2031     if (supportAnimation_ || dragAnimation_) {
2032         animationItemList_.clear();
2033     }
2034 
2035     while (valid || equal) {
2036         // Get target pos
2037         GetNextGrid(targetRow, targetColum);
2038 
2039         // Get index in the curpos
2040         tmpIndex = GetIndexByGrid(curRow, curColum);
2041         if (tmpIndex < 0 || (int32_t)itemsInGrid_.size() <= tmpIndex) {
2042             return false;
2043         }
2044 
2045         // Move the curpos index to the targetpos
2046         UpdateMatrixByIndexStrong(tmpIndex, targetRow, targetColum);
2047         UpdateMatrixByIndexStrong(CELL_EMPTY, curRow, curColum);
2048 
2049         auto item = itemsInGrid_[tmpIndex];
2050         if (supportAnimation_ || dragAnimation_) {
2051             AddNodeAnimationToController(tmpIndex, targetRow, targetColum, 1, 1);
2052         } else {
2053             item->Layout(MakeInnerLayoutParam(targetRow, targetColum, 1, 1));
2054             SetChildPosition(item, targetRow, targetColum, 1, 1);
2055         }
2056 
2057         // move the curpos backward
2058         GetPreviousGird(curRow, curColum);
2059         targetRow = curRow;
2060         targetColum = curColum;
2061 
2062         equal = SortCellIndex(fromRow, fromColum, curRow, curColum, valid);
2063     }
2064     return true;
2065 }
2066 
MoveItemsBackward(int32_t fromRow,int32_t fromColum,int32_t toRow,int32_t toColum)2067 bool RenderGridLayout::MoveItemsBackward(int32_t fromRow, int32_t fromColum, int32_t toRow, int32_t toColum)
2068 {
2069     bool valid = false;
2070     if (!SortCellIndex(fromRow, fromColum, toRow, toColum, valid) && (!valid)) {
2071         return false;
2072     }
2073 
2074     int32_t curRow = fromRow;
2075     int32_t curColum = fromColum;
2076     int32_t targetRow = fromRow;
2077     int32_t targetColum = fromColum;
2078     int32_t tmpIndex = -1;
2079 
2080     bool equal = false;
2081     equal = SortCellIndex(curRow, curColum, toRow, toColum, valid);
2082     if (supportAnimation_ || dragAnimation_) {
2083         animationItemList_.clear();
2084     }
2085     while (valid || equal) {
2086         // Get target pos
2087         GetPreviousGird(targetRow, targetColum);
2088 
2089         // Get index in the curpos
2090         tmpIndex = GetIndexByGrid(curRow, curColum);
2091         if (tmpIndex < 0 || (int32_t)itemsInGrid_.size() <= tmpIndex) {
2092             return false;
2093         }
2094 
2095         // Move the curpos index to the targetpos
2096         UpdateMatrixByIndexStrong(tmpIndex, targetRow, targetColum);
2097         UpdateMatrixByIndexStrong(CELL_EMPTY, curRow, curColum);
2098 
2099         auto item = itemsInGrid_[tmpIndex];
2100         if (supportAnimation_ || dragAnimation_) {
2101             AddNodeAnimationToController(tmpIndex, targetRow, targetColum, 1, 1);
2102         } else {
2103             item->Layout(MakeInnerLayoutParam(targetRow, targetColum, 1, 1));
2104             SetChildPosition(item, targetRow, targetColum, 1, 1);
2105         }
2106         // move the curpos and targetpos backward
2107         GetNextGrid(curRow, curColum);
2108         targetRow = curRow;
2109         targetColum = curColum;
2110 
2111         equal = SortCellIndex(curRow, curColum, toRow, toColum, valid);
2112     }
2113 
2114     return true;
2115 }
2116 
UpdateMatrixByIndexStrong(int32_t index,int32_t row,int32_t column)2117 void RenderGridLayout::UpdateMatrixByIndexStrong(int32_t index, int32_t row, int32_t column)
2118 {
2119     std::map<int32_t, int32_t> rowMap;
2120 
2121     auto rowIter = gridMatrix_.find(row);
2122     if (rowIter != gridMatrix_.end()) {
2123         rowMap = rowIter->second;
2124     }
2125 
2126     auto indexIter = rowMap.find(column);
2127     if (indexIter != rowMap.end()) {
2128         rowMap[column] = index;
2129     } else {
2130         rowMap.emplace(std::make_pair(column, index));
2131     }
2132 
2133     gridMatrix_[row] = rowMap;
2134 }
2135 
UpdateCurInsertPos(int32_t curInsertRow,int32_t curInsertColum)2136 void RenderGridLayout::UpdateCurInsertPos(int32_t curInsertRow, int32_t curInsertColum)
2137 {
2138     curInsertRowIndex_ = curInsertRow;
2139     curInsertColumnIndex_ = curInsertColum;
2140     UpdateMatrixByIndexStrong(CELL_FOR_INSERT, curInsertRowIndex_, curInsertColumnIndex_);
2141 }
2142 
CalIndexForItemByRowAndColum(int32_t row,int32_t column)2143 int32_t RenderGridLayout::CalIndexForItemByRowAndColum(int32_t row, int32_t column)
2144 {
2145     int32_t curRow = 0;
2146     int32_t curColum = 0;
2147     int32_t targetIndex = 0;
2148     if (row >= 0 && row < rowCount_ && column >= 0 && column < colCount_) {
2149         while (curRow != row || curColum != column) {
2150             GetNextGrid(curRow, curColum);
2151             if (curRow >= rowCount_ || curColum >= colCount_) {
2152                 targetIndex = -1;
2153                 break;
2154             }
2155             targetIndex++;
2156         }
2157     } else {
2158         targetIndex = -1;
2159     }
2160     return targetIndex;
2161 }
2162 
SortCellIndex(int32_t rowFirst,int32_t columFirst,int32_t rowSecond,int32_t columSecond,bool & firstIsPre)2163 bool RenderGridLayout::SortCellIndex(
2164     int32_t rowFirst, int32_t columFirst, int32_t rowSecond, int32_t columSecond, bool& firstIsPre)
2165 {
2166     if ((rowFirst == rowSecond) && (columFirst == columSecond)) {
2167         firstIsPre = false;
2168         return true;
2169     }
2170 
2171     if (isVertical_) {
2172         if (rowFirst > rowSecond) {
2173             firstIsPre = false;
2174         } else if (rowFirst == rowSecond) {
2175             if (columFirst > columSecond) {
2176                 firstIsPre = false;
2177             } else {
2178                 firstIsPre = true;
2179             }
2180         } else {
2181             firstIsPre = true;
2182         }
2183     } else {
2184         if (columFirst > columSecond) {
2185             firstIsPre = false;
2186         } else if (columFirst == columSecond) {
2187             if (rowFirst > rowSecond) {
2188                 firstIsPre = false;
2189             } else {
2190                 firstIsPre = true;
2191             }
2192         } else {
2193             firstIsPre = true;
2194         }
2195     }
2196     return false;
2197 }
2198 
CalTheFirstEmptyCell(int32_t & rowIndex,int32_t & columIndex,bool ignoreInsert)2199 bool RenderGridLayout::CalTheFirstEmptyCell(int32_t& rowIndex, int32_t& columIndex, bool ignoreInsert)
2200 {
2201     int32_t row = 0;
2202     int32_t column = 0;
2203     int32_t index = -3;
2204 
2205     index = GetIndexByGrid(row, column);
2206 
2207     while ((-1 != index) && (ignoreInsert || (CELL_FOR_INSERT != index))) {
2208         GetNextGrid(row, column);
2209         if (row >= rowCount_ || column >= colCount_) {
2210             return false;
2211         }
2212         index = GetIndexByGrid(row, column);
2213     }
2214 
2215     rowIndex = row;
2216     columIndex = column;
2217     return true;
2218 }
2219 
InitAnimationController(const WeakPtr<PipelineContext> & context)2220 void RenderGridLayout::InitAnimationController(const WeakPtr<PipelineContext>& context)
2221 {
2222     if (!animationController_) {
2223         animationController_ = CREATE_ANIMATOR(context);
2224     }
2225     if (!flexController_) {
2226         flexController_ = CREATE_ANIMATOR(context);
2227     }
2228 }
2229 
AddNodeAnimationToController(int32_t itemIndex,int32_t row,int32_t col,int32_t rowSpan,int32_t colSpan)2230 bool RenderGridLayout::AddNodeAnimationToController(
2231     int32_t itemIndex, int32_t row, int32_t col, int32_t rowSpan, int32_t colSpan)
2232 {
2233     auto item = itemsInGrid_[itemIndex];
2234     if (!item || !animationController_) {
2235         return false;
2236     }
2237 
2238     Point startPoint(item->GetPosition().GetX(), item->GetPosition().GetY());
2239     Point endPoint = CalcChildPosition(item, row, col, rowSpan, colSpan);
2240     auto animationRef = AceType::MakeRefPtr<CurveAnimation<Point>>(startPoint, endPoint, Curves::FRICTION);
2241     animationRef->AddListener(
2242         [item, weak = WeakClaim(this)](const Point& newPoint) {
2243             if (item) {
2244                 item->SetPosition(Offset(newPoint.GetX(), newPoint.GetY()));
2245             }
2246             auto renderGrid = weak.Upgrade();
2247             if (renderGrid) {
2248                 renderGrid->MarkNeedLayout();
2249             }
2250     });
2251 
2252     auto gridLayoutItem = AceType::DynamicCast<RenderGridLayoutItem>(item);
2253     int32_t depth = DEFAULT_DEPTH;
2254     while (!gridLayoutItem && depth > 0) {
2255         if (!item || item->GetChildren().empty()) {
2256             LOGE("%{public}s. item has no children anymore", __PRETTY_FUNCTION__);
2257             break;
2258         }
2259         item = item->GetChildren().front();
2260         gridLayoutItem = AceType::DynamicCast<RenderGridLayoutItem>(item);
2261         --depth;
2262     }
2263     if (gridLayoutItem) {
2264         if (gridLayoutItem->AnimationAddInterpolator(animationRef)) {
2265             needRunAnimation_.store(true);
2266             animationItemList_.emplace_back(item);
2267         }
2268     }
2269     return true;
2270 }
2271 
AddNodeAnimationToControllerForDrop(const RefPtr<RenderNode> & item,const Point & startPoint,const Point & endPoint)2272 void RenderGridLayout::AddNodeAnimationToControllerForDrop(
2273     const RefPtr<RenderNode>& item, const Point& startPoint, const Point& endPoint)
2274 {
2275     if (!item || !animationController_ || startPoint == endPoint) {
2276         return;
2277     }
2278     item->SetNeedRender(true);
2279     item->MarkNeedPredictLayout();
2280 
2281     if (curInsertRowIndex_ >= 0 && curInsertColumnIndex_ >= 0) {
2282         item->Layout(MakeInnerLayoutParam(curInsertRowIndex_, curInsertColumnIndex_, 1, 1));
2283     }
2284     auto animationRef = AceType::MakeRefPtr<CurveAnimation<Point>>(startPoint, endPoint, Curves::FRICTION);
2285     animationRef->AddListener([weak = WeakClaim(this), item](const Point newPoint) {
2286         auto renderGrid = weak.Upgrade();
2287         if (renderGrid) {
2288             if (item) {
2289                 item->SetPosition(Offset(newPoint.GetX(), newPoint.GetY()));
2290             }
2291             renderGrid->MarkNeedLayout();
2292         }
2293     });
2294 
2295     auto itemTmp = item;
2296     auto gridLayoutItem = AceType::DynamicCast<RenderGridLayoutItem>(itemTmp);
2297     int32_t depth = DEFAULT_DEPTH;
2298     while (!gridLayoutItem && depth > 0) {
2299         if (!itemTmp || itemTmp->GetChildren().empty()) {
2300             LOGE("%{public}s. itemTmp has no children anymore", __PRETTY_FUNCTION__);
2301             break;
2302         }
2303         itemTmp = itemTmp->GetChildren().front();
2304         gridLayoutItem = AceType::DynamicCast<RenderGridLayoutItem>(itemTmp);
2305         --depth;
2306     }
2307     if (gridLayoutItem) {
2308         if (gridLayoutItem->AnimationAddInterpolator(animationRef)) {
2309             needRunAnimation_.store(true);
2310             animationItemList_.emplace_back(itemTmp);
2311         }
2312     }
2313 }
2314 
PrepareAnimationController(const std::string & key)2315 void RenderGridLayout::PrepareAnimationController(const std::string& key)
2316 {
2317     if (animationAct_ != GridLayoutAnimationAct::ANIMATION_NONE) {
2318         return;
2319     }
2320 
2321     needRunAnimation_.store(true);
2322     animationController_->SetDuration(ITEM_ANIMATION_DURATION);
2323     animationController_->ClearStopListeners();
2324     animationController_->AddStopListener([weak = AceType::WeakClaim(this), key]() {
2325         auto renderGrid = weak.Upgrade();
2326         if (renderGrid) {
2327             renderGrid->FinishedAnimationController(key);
2328         }
2329     });
2330 }
2331 
StartAnimationController(GridLayoutAnimationAct animationAct,const OnAnimationCallJSFunc & func)2332 void RenderGridLayout::StartAnimationController(GridLayoutAnimationAct animationAct, const OnAnimationCallJSFunc& func)
2333 {
2334     if (needRunAnimation_) {
2335         animationAct_ = animationAct;
2336         needRunAnimation_.store(false);
2337         switch (animationAct_) {
2338             case GridLayoutAnimationAct::ANIMATION_DRAG_MOVE:
2339                 jsMoveFunc_ = func;
2340                 break;
2341             case GridLayoutAnimationAct::ANIMATION_DRAG_DROP:
2342                 jsDropFunc_ = func;
2343                 break;
2344             case GridLayoutAnimationAct::ANIMATION_RESTORE_SCENE:
2345                 restoreSceneFunc_ = func;
2346                 break;
2347             default:
2348                 jsMoveFunc_ = nullptr;
2349                 jsDropFunc_ = nullptr;
2350                 restoreSceneFunc_ = nullptr;
2351                 break;
2352         }
2353         animationController_->Play();
2354 
2355         for (auto iter = animationItemList_.begin(); iter != animationItemList_.end(); ++iter) {
2356             AceType::DynamicCast<RenderGridLayoutItem>(*iter)->AnimationPlay();
2357         }
2358     }
2359 }
2360 
StopAnimationController()2361 void RenderGridLayout::StopAnimationController()
2362 {
2363     if (animationController_ && !animationController_->IsStopped()) {
2364         animationController_->ClearStopListeners();
2365         animationController_->Stop();
2366         animationAct_ = GridLayoutAnimationAct::ANIMATION_NONE;
2367     }
2368 }
2369 
FinishedAnimationController(const std::string & key)2370 void RenderGridLayout::FinishedAnimationController(const std::string& key)
2371 {
2372     {
2373         std::lock_guard<std::mutex> funLock(animationLock_);
2374         auto iter = animationFinishedFuncList_.find(key);
2375         if (iter != animationFinishedFuncList_.end()) {
2376             iter->second();
2377             animationFinishedFuncList_.erase(iter);
2378         }
2379         animationController_->ClearInterpolators();
2380     }
2381 
2382     OnAnimationCallJSFunc func = nullptr;
2383     switch (animationAct_) {
2384         case GridLayoutAnimationAct::ANIMATION_DRAG_MOVE:
2385             func = jsMoveFunc_;
2386             break;
2387         case GridLayoutAnimationAct::ANIMATION_DRAG_DROP:
2388             func = jsDropFunc_;
2389             break;
2390         case GridLayoutAnimationAct::ANIMATION_RESTORE_SCENE:
2391             func = restoreSceneFunc_;
2392             break;
2393         default:
2394             break;
2395     }
2396     animationAct_ = GridLayoutAnimationAct::ANIMATION_NONE;
2397     if (func) {
2398         func();
2399     }
2400     MarkNeedLayout();
2401 }
2402 
RegisterAnimationFinishedFunc(const std::string & key,std::function<void ()> func)2403 void RenderGridLayout::RegisterAnimationFinishedFunc(const std::string& key, std::function<void()> func)
2404 {
2405     std::lock_guard<std::mutex> funLock(animationLock_);
2406     if (func) {
2407         animationFinishedFuncList_[key] = func;
2408     }
2409 }
2410 
TriggerMoveEventForJS(const ItemDragInfo & info)2411 void RenderGridLayout::TriggerMoveEventForJS(const ItemDragInfo& info)
2412 {
2413     int32_t insertIndex = CalIndexForItemByRowAndColum(curInsertRowIndex_, curInsertColumnIndex_);
2414     if (component_->GetOnGridDragMoveId()) {
2415         component_->GetOnGridDragMoveId()(info, draggingItemIndex_, insertIndex);
2416     } else {
2417         LOGE("%{public}s no onGridDragMove registered.", __PRETTY_FUNCTION__);
2418     }
2419 }
2420 
TriggerDropEventForJS(const ItemDragInfo & info,int32_t insertIndex,bool success)2421 void RenderGridLayout::TriggerDropEventForJS(const ItemDragInfo& info, int32_t insertIndex, bool success)
2422 {
2423     if (component_->GetOnGridDropId()) {
2424         component_->GetOnGridDropId()(info, draggingItemIndex_, insertIndex, success);
2425     } else {
2426         LOGE("%{public}s no onGridDrop registered.", __PRETTY_FUNCTION__);
2427     }
2428 }
2429 
RegisterDropJSEvent(const ItemDragInfo & info,int32_t insertIndex,bool success)2430 void RenderGridLayout::RegisterDropJSEvent(const ItemDragInfo& info, int32_t insertIndex, bool success)
2431 {
2432     auto weak = WeakClaim(this);
2433     RegisterDropJSFunc([weak, info, insertIndex, success]() {
2434         auto renderGrid = weak.Upgrade();
2435         if (renderGrid) {
2436             renderGrid->TriggerDropEventForJS(info, insertIndex, success);
2437         }
2438     });
2439     triggerJSDrop_.store(true);
2440 }
2441 
RegisterDropJSFunc(const OnCallJSDropFunc & func)2442 void RenderGridLayout::RegisterDropJSFunc(const OnCallJSDropFunc& func)
2443 {
2444     std::lock_guard<std::mutex> lock(dropJSFuncListLock_);
2445     if (func != nullptr) {
2446         dropJSFuncList_.push_back(std::move(func));
2447     }
2448 }
2449 
CallDropJSFunc()2450 void RenderGridLayout::CallDropJSFunc()
2451 {
2452     std::lock_guard<std::mutex> lock(dropJSFuncListLock_);
2453     for (auto& func: dropJSFuncList_) {
2454         func();
2455     }
2456     dropJSFuncList_.clear();
2457 }
2458 
CheckAnimation()2459 bool RenderGridLayout::CheckAnimation()
2460 {
2461     if (!(supportAnimation_ || dragAnimation_ || edgeEffect_ == EdgeEffect::SPRING)) {
2462         return false;
2463     }
2464     if (animationAct_ != GridLayoutAnimationAct::ANIMATION_NONE || runFlexAnimation_.load()) {
2465         return true;
2466     }
2467     if (!(GetSlideStatus() == GridSlideStatus::SLIDE_NONE || GetSlideStatus() == GridSlideStatus::SLIDE_START)) {
2468         return true;
2469     }
2470 
2471     if (!isMainGrid_) {
2472         if (itemDragEntered_) {
2473             auto mainGrid = mainGrid_.Upgrade();
2474             if (mainGrid) {
2475                 return mainGrid->isDragging_.load();
2476             }
2477         } else {
2478             return false;
2479         }
2480     } else {
2481         return isDragging_.load();
2482     }
2483     return false;
2484 }
2485 
CheckNeedShrink() const2486 bool RenderGridLayout::CheckNeedShrink() const
2487 {
2488     return isDeclarative_ && needShrink_;
2489 }
2490 
RefreshAllocatedRowSizes(int32_t rowIndex,int32_t itemRowSpan,const RefPtr<RenderNode> & item)2491 void RenderGridLayout::RefreshAllocatedRowSizes(int32_t rowIndex, int32_t itemRowSpan, const RefPtr<RenderNode>& item)
2492 {
2493     if (CheckNeedShrink()) {
2494         allocatedRowSizes_[rowIndex + itemRowSpan] = allocatedRowSizes_[rowIndex] + item->GetLayoutSize().Height();
2495     }
2496 }
2497 
ParseRestoreScenePosition(const std::map<int32_t,std::map<int32_t,int32_t>> & data,std::map<int32_t,GridItemIndexPosition> & info)2498 void RenderGridLayout::ParseRestoreScenePosition(
2499     const std::map<int32_t, std::map<int32_t, int32_t>>& data, std::map<int32_t, GridItemIndexPosition>& info)
2500 {
2501     info.clear();
2502     for (auto rowIter = data.begin(); rowIter != data.end(); rowIter++) {
2503         for (auto colIter = rowIter->second.begin(); colIter != rowIter->second.end(); colIter++) {
2504             if (info.find(colIter->second) == info.end()) {
2505                 GridItemIndexPosition itemIndexPosition(rowIter->first, colIter->first);
2506                 info.emplace(colIter->second, itemIndexPosition);
2507             }
2508         }
2509     }
2510 }
2511 
CalcRestoreScenePosition(const ItemDragInfo & info)2512 void RenderGridLayout::CalcRestoreScenePosition(const ItemDragInfo& info)
2513 {
2514     std::map<int32_t, GridItemIndexPosition> backData;
2515     std::map<int32_t, GridItemIndexPosition> recentData;
2516     ParseRestoreScenePosition(gridMatrixBack_, backData);
2517     ParseRestoreScenePosition(gridMatrix_, recentData);
2518 
2519     for (auto backIter = backData.begin(); backIter != backData.end(); backIter++) {
2520         auto recentIter = recentData.find(backIter->first);
2521         if (recentIter != recentData.end() && backIter->second != recentIter->second &&
2522             backIter->first != draggingItemIndex_ && backIter->first >= 0 &&
2523             backIter->first < (int32_t)itemsInGrid_.size()) {
2524             auto item = itemsInGrid_[backIter->first];
2525             if (item) {
2526                 Point startPoint(item->GetPosition().GetX(), item->GetPosition().GetY());
2527                 AddNodeAnimationToControllerForDrop(item, startPoint, gridItemPosition_[backIter->first]);
2528             }
2529         }
2530     }
2531 }
2532 
StartFlexController(const Point & endPoint,bool includeSubGrid)2533 void RenderGridLayout::StartFlexController(const Point& endPoint, bool includeSubGrid)
2534 {
2535     if (!(supportAnimation_ || dragAnimation_)) {
2536         CloseFlexComponent();
2537         if (includeSubGrid) {
2538             FinishedFlexControllerForSubGrid();
2539         }
2540         FinishedFlexController();
2541         ClearAllDragInfo();
2542         MarkNeedLayout();
2543         return;
2544     }
2545     runFlexAnimation_.store(true);
2546     auto animationRef = AceType::MakeRefPtr<CurveAnimation<Point>>(lastGlobalPoint_, endPoint, Curves::FRICTION);
2547     animationRef->AddListener(
2548         [weak = WeakClaim(this)](const Point& newPoint) {
2549             auto renderGrid = weak.Upgrade();
2550             if (renderGrid) {
2551                 renderGrid->UpdateFlexComponentPosition(newPoint);
2552             }
2553         });
2554 
2555     flexController_->AddInterpolator(animationRef);
2556     if (isExistComponent_) {
2557         flexController_->SetDuration(ITEM_ANIMATION_DURATION);
2558     } else {
2559         flexController_->SetDuration(ITEM_ANIMATION_DURATION_NO);
2560     }
2561     flexController_->ClearStopListeners();
2562     flexController_->AddStopListener([weak = AceType::WeakClaim(this), includeSubGrid]() {
2563         auto renderGrid = weak.Upgrade();
2564         if (renderGrid) {
2565             if (includeSubGrid) {
2566                 renderGrid->FinishedFlexControllerForSubGrid();
2567             }
2568             renderGrid->FinishedFlexController();
2569             renderGrid->ClearAllDragInfo();
2570             renderGrid->MarkNeedLayout();
2571         }
2572     });
2573     flexController_->Play();
2574 }
2575 
FinishedFlexController()2576 void RenderGridLayout::FinishedFlexController()
2577 {
2578     runFlexAnimation_.store(false);
2579     CloseFlexComponent();
2580     if (animationAct_ == GridLayoutAnimationAct::ANIMATION_NONE) {
2581         if (triggerJSDrop_.load()) {
2582             triggerJSDrop_.store(false);
2583             CallDropJSFunc();
2584         }
2585     }
2586 }
2587 
FinishedFlexControllerForSubGrid()2588 void RenderGridLayout::FinishedFlexControllerForSubGrid()
2589 {
2590     auto subGrid = subGrid_.Upgrade();
2591     if (subGrid) {
2592         subGrid->CallDropJSFunc();
2593         subGrid->ClearAllDragInfo();
2594     }
2595 }
2596 
CloseFlexComponent()2597 void RenderGridLayout::CloseFlexComponent()
2598 {
2599     auto pipelineContext = GetContext().Upgrade();
2600     if (pipelineContext && isExistComponent_) {
2601         auto stackElement = pipelineContext->GetLastStack();
2602         stackElement->PopComponent();
2603         isExistComponent_ = false;
2604     }
2605     isDragging_.store(false);
2606 }
2607 
UpdateFlexComponentPosition(const Point & pos)2608 void RenderGridLayout::UpdateFlexComponentPosition(const Point& pos)
2609 {
2610     if (GetUpdatePositionId() && isExistComponent_) {
2611         auto eventInfo = ItemDragInfo();
2612         eventInfo.SetX(pos.GetX());
2613         eventInfo.SetY(pos.GetY());
2614         GetUpdatePositionId()(Dimension(pos.GetX()), Dimension(pos.GetY()));
2615         MarkNeedLayout();
2616     }
2617 }
2618 
ClearSpringSlideData()2619 void RenderGridLayout::ClearSpringSlideData()
2620 {
2621     gravitationDirect_ = GridSpringGravitationDirect::SPRING_NONE;
2622     slideDirect_ = GridSlideDirect::SLIDE_NODE;
2623     slideStatus_.store(GridSlideStatus::SLIDE_NONE);
2624     slideStartPoint_ = Point(0.0, 0.0);
2625     slideDistance_ = Point(0.0, 0.0);
2626     slidePriPoint_ = Point(0.0, 0.0);
2627     slideCurPoint_ = Point(0.0, 0.0);
2628 }
2629 
CreateSlideRecognizer()2630 void RenderGridLayout::CreateSlideRecognizer()
2631 {
2632     if (!(supportAnimation_ || edgeEffect_ == EdgeEffect::SPRING) || slideRecognizer_) {
2633         return;
2634     }
2635     slideRecognizer_ = AceType::MakeRefPtr<RawRecognizer>();
2636     auto weak = AceType::WeakClaim(this);
2637     slideRecognizer_->SetOnTouchDown([weak](const TouchEventInfo& info) {
2638         auto renderGrid = weak.Upgrade();
2639         if (renderGrid) {
2640             renderGrid->HandleSlideStart(info);
2641         }
2642     });
2643     slideRecognizer_->SetOnTouchUp([weak](const TouchEventInfo& info) {
2644         auto renderGrid = weak.Upgrade();
2645         if (renderGrid) {
2646             renderGrid->HandleSlideEnd(info);
2647         }
2648     });
2649     slideRecognizer_->SetOnTouchMove([weak](const TouchEventInfo& info) {
2650         auto renderGrid = weak.Upgrade();
2651         if (renderGrid) {
2652             renderGrid->HandleSlideUpdate(info);
2653         }
2654     });
2655 }
2656 
HandleSlideStart(const TouchEventInfo & info)2657 void RenderGridLayout::HandleSlideStart(const TouchEventInfo& info)
2658 {
2659     if (CheckLongPress() || GetSlideStatus() != GridSlideStatus::SLIDE_NONE) {
2660         return;
2661     }
2662     slideStartPoint_ = GetPointFromTouchInfo(info);
2663     slidePriPoint_ = slideStartPoint_;
2664     slideCurPoint_ = slideStartPoint_;
2665     slideDistance_ = Point(0.0, 0.0);
2666     UpdateSlideStatus(GridSlideStatus::SLIDE_START);
2667 }
2668 
HandleSlideUpdate(const TouchEventInfo & info)2669 void RenderGridLayout::HandleSlideUpdate(const TouchEventInfo& info)
2670 {
2671     if (CheckLongPress()) {
2672         return;
2673     }
2674     if (GetSlideStatus() != GridSlideStatus::SLIDE_START && GetSlideStatus() != GridSlideStatus::SLIDE_SLIDING) {
2675         return;
2676     }
2677     if (GetSlideStatus() == GridSlideStatus::SLIDE_START && !MayStartToSlide(info)) {
2678         return;
2679     }
2680     UpdateSlideStatus(GridSlideStatus::SLIDE_SLIDING);
2681     slideCurPoint_ = GetPointFromTouchInfo(info);
2682     CalcSlideDirect(slideCurPoint_);
2683     double dx = slideCurPoint_.GetX() - slidePriPoint_.GetX();
2684     double dy = slideCurPoint_.GetY() - slidePriPoint_.GetY();
2685     MoveRelativeDistance(dx, dy);
2686     for (auto& item : itemsInGrid_) {
2687         if (slideDirect_ == GridSlideDirect::SLIDE_VERTICAL) {
2688             item->SetPosition(Offset(item->GetPosition().GetX(), item->GetPosition().GetY() + dy));
2689         } else {
2690             item->SetPosition(Offset(item->GetPosition().GetX() + dx, item->GetPosition().GetY()));
2691         }
2692     }
2693     MarkNeedLayout();
2694     slidePriPoint_ = slideCurPoint_;
2695 }
2696 
HandleSlideEnd(const TouchEventInfo & info)2697 void RenderGridLayout::HandleSlideEnd(const TouchEventInfo& info)
2698 {
2699     if (CheckLongPress()) {
2700         return;
2701     }
2702     if (GetSlideStatus() == GridSlideStatus::SLIDE_SPRING_START || GetSlideStatus() == GridSlideStatus::SLIDE_NONE) {
2703         return;
2704     }
2705     UpdateSlideStatus(GridSlideStatus::SLIDE_SPRING_START);
2706     CalcSpringGravitationDirect();
2707     if (gravitationDirect_ != GridSpringGravitationDirect::SPRING_NONE) {
2708         BackupSpringItemsData();
2709         Point startPoint = GetSpringStartPoint();
2710         Point endPoint = GetSpringEndPoint();
2711         StartSpringAnimation(startPoint, endPoint);
2712     } else {
2713         FinishedSpringAnimation();
2714     }
2715 }
2716 
MayStartToSlide(const TouchEventInfo & info)2717 bool RenderGridLayout::MayStartToSlide(const TouchEventInfo& info)
2718 {
2719     bool result = false;
2720     Point movePoint = GetPointFromTouchInfo(info);
2721     double dx = std::fabs(movePoint.GetX() - slideStartPoint_.GetX());
2722     double dy = std::fabs(movePoint.GetY() - slideStartPoint_.GetY());
2723     if (dx >= GRID_SPRING_SLIDE_LIMIT || dy >= GRID_SPRING_SLIDE_LIMIT) {
2724         slideCurPoint_ = movePoint;
2725         result = true;
2726     }
2727     return result;
2728 }
2729 
CheckLongPress()2730 bool RenderGridLayout::CheckLongPress()
2731 {
2732     if (animationAct_ != GridLayoutAnimationAct::ANIMATION_NONE || itemLongPressed_ || isDragging_.load() ||
2733         itemDragStarted_ || GetChildren().empty()) {
2734         return true;
2735     } else {
2736         return false;
2737     }
2738 }
2739 
UpdateSlideStatus(GridSlideStatus status)2740 void RenderGridLayout::UpdateSlideStatus(GridSlideStatus status)
2741 {
2742     slideStatus_.store(status);
2743 }
2744 
GetSlideStatus()2745 GridSlideStatus RenderGridLayout::GetSlideStatus()
2746 {
2747     return slideStatus_.load();
2748 }
2749 
GetSlideDirect()2750 GridSlideDirect RenderGridLayout::GetSlideDirect()
2751 {
2752     return slideDirect_;
2753 }
2754 
GetPointFromTouchInfo(const TouchEventInfo & info)2755 Point RenderGridLayout::GetPointFromTouchInfo(const TouchEventInfo& info)
2756 {
2757     const auto& locationInfo = info.GetTouches().front();
2758     return Point(locationInfo.GetLocalLocation().GetX() - GetGlobalOffset().GetX(),
2759         locationInfo.GetLocalLocation().GetY() - GetGlobalOffset().GetY());
2760 }
2761 
MoveRelativeDistance(double & dx,double & dy)2762 void RenderGridLayout::MoveRelativeDistance(double& dx, double& dy)
2763 {
2764     if (slideDistance_.GetX() + dx < 0.0) {
2765         dx = -slideDistance_.GetX();
2766     }
2767     slideDistance_.SetX(slideDistance_.GetX() + dx);
2768 
2769     if (slideDistance_.GetY() + dy < 0.0) {
2770         dy = -slideDistance_.GetY();
2771     }
2772     slideDistance_.SetY(slideDistance_.GetY() + dy);
2773 }
2774 
CreateSpringController()2775 void RenderGridLayout::CreateSpringController()
2776 {
2777     if (!springController_) {
2778         springController_ = CREATE_ANIMATOR(GetContext());
2779     }
2780 }
2781 
GetSpringStartPoint()2782 Point RenderGridLayout::GetSpringStartPoint()
2783 {
2784     double dx = 0.0;
2785     double dy = 0.0;
2786     if (slideDirect_ == GridSlideDirect::SLIDE_HORIZON) {
2787         dx = GetLeft().Value();
2788         dy = (GetTop().Value() + GetBottom().Value()) / GAP_DIVIDE_CONSTEXPR;
2789     } else {
2790         dx = (GetLeft().Value() + GetRight().Value()) / GAP_DIVIDE_CONSTEXPR;
2791         dy = GetTop().Value();
2792     }
2793     return Point(dx, dy);
2794 }
2795 
GetSpringEndPoint()2796 Point RenderGridLayout::GetSpringEndPoint()
2797 {
2798     double dx = 0.0;
2799     double dy = 0.0;
2800     if (slideDirect_ == GridSlideDirect::SLIDE_HORIZON) {
2801         dx = GetLeft().Value() + slideDistance_.GetX();
2802         dy = (GetTop().Value() + GetRight().Value()) / GAP_DIVIDE_CONSTEXPR;
2803     } else {
2804         dx = (GetLeft().Value() + GetRight().Value()) / GAP_DIVIDE_CONSTEXPR;
2805         dy = GetTop().Value() + slideDistance_.GetY();
2806     }
2807     return Point(dx, dy);
2808 }
2809 
StartSpringAnimation(const Point & startPoint,const Point & endPoint)2810 void RenderGridLayout::StartSpringAnimation(const Point& startPoint, const Point& endPoint)
2811 {
2812     double start = 0.0;
2813     double end = 0.0;
2814     GetMotionPosition(startPoint, endPoint, start, end);
2815     auto springDes = AceType::MakeRefPtr<SpringProperty>(GRID_SPRING_MASS, GRID_SPRING_STIFF, GRID_SPRING_DAMP);
2816     if (!springMotion_) {
2817         springMotion_ = AceType::MakeRefPtr<SpringMotion>(start, end, 0.0, springDes);
2818     } else {
2819         springMotion_->Reset(start, end, 0.0, springDes);
2820     }
2821 
2822     springMotion_->ClearListeners();
2823     springMotion_->AddListener([weak = AceType::WeakClaim(this)](double position) {
2824         auto renderGrid = weak.Upgrade();
2825         if (renderGrid) {
2826             renderGrid->UpdateSprintAnimationPosition(position);
2827         }
2828     });
2829     springController_->AddStopListener([weak = AceType::WeakClaim(this)]() {
2830         auto renderGrid = weak.Upgrade();
2831         if (renderGrid) {
2832             renderGrid->FinishedSpringAnimation();
2833         }
2834     });
2835     springController_->PlayMotion(springMotion_);
2836 }
2837 
FinishedSpringAnimation()2838 void RenderGridLayout::FinishedSpringAnimation()
2839 {
2840     ClearSpringSlideData();
2841     MarkNeedLayout();
2842 }
2843 
UpdateSprintAnimationPosition(double position)2844 void RenderGridLayout::UpdateSprintAnimationPosition(double position)
2845 {
2846     size_t index = 0;
2847     for (auto& item : itemsInGrid_) {
2848         auto& itemPos = springStartPosition_[index];
2849         if (slideDirect_ == GridSlideDirect::SLIDE_HORIZON) {
2850             item->SetPosition(Offset(itemPos.GetX() - position, itemPos.GetY()));
2851         } else {
2852             item->SetPosition(Offset(itemPos.GetX(), itemPos.GetY() - position));
2853         }
2854         index++;
2855     }
2856     MarkNeedLayout();
2857 }
2858 
BackupSpringItemsData()2859 void RenderGridLayout::BackupSpringItemsData()
2860 {
2861     springStartPosition_.clear();
2862     for (auto& item : itemsInGrid_) {
2863         springStartPosition_.push_back(item->GetPosition());
2864     }
2865 }
2866 
GetMotionPosition(const Point & startPoint,const Point & endPoint,double & start,double & end)2867 void RenderGridLayout::GetMotionPosition(const Point& startPoint, const Point& endPoint, double& start, double& end)
2868 {
2869     if (slideDirect_ == GridSlideDirect::SLIDE_HORIZON) {
2870         start = startPoint.GetX();
2871         end = endPoint.GetX();
2872     } else {
2873         start = startPoint.GetY();
2874         end = endPoint.GetY();
2875     }
2876 }
2877 
CalcSlideDirect(const Point & curPos)2878 void RenderGridLayout::CalcSlideDirect(const Point& curPos)
2879 {
2880     if (slideDirect_ != GridSlideDirect::SLIDE_NODE) {
2881         return;
2882     }
2883     if (isVertical_) {
2884         slideDirect_ = GridSlideDirect::SLIDE_VERTICAL;
2885     } else {
2886         slideDirect_ = GridSlideDirect::SLIDE_HORIZON;
2887     }
2888 }
2889 
CalcSpringGravitationDirect()2890 void RenderGridLayout::CalcSpringGravitationDirect()
2891 {
2892     if (slideDirect_ == GridSlideDirect::SLIDE_HORIZON) {
2893         gravitationDirect_ = GridSpringGravitationDirect::SPRING_TO_LEFT;
2894     } else {
2895         gravitationDirect_ = GridSpringGravitationDirect::SPRING_TO_UP;
2896     }
2897 }
2898 
HandleMouseEvent(const MouseEvent & event)2899 bool RenderGridLayout::HandleMouseEvent(const MouseEvent& event)
2900 {
2901     if (!isMultiSelectable_) {
2902         return false;
2903     }
2904 
2905     auto context = context_.Upgrade();
2906     if (context) {
2907         context->SubscribeCtrlA([wp = AceType::WeakClaim(this)]() {
2908             auto sp = wp.Upgrade();
2909             if (sp) {
2910                 sp->MultiSelectAllWhenCtrlA();
2911             }
2912         });
2913     }
2914 
2915     if (context && context->IsCtrlDown()) {
2916         if (context->IsKeyboardA()) {
2917             MultiSelectAllWhenCtrlA();
2918             return true;
2919         }
2920         HandleMouseEventWhenCtrlDown(event);
2921         return true;
2922     }
2923     selectedItemsWithCtrl_.clear();
2924 
2925     if (context && context->IsShiftDown()) {
2926         HandleMouseEventWhenShiftDown(event);
2927         return true;
2928     }
2929     firstItemWithShift_ = nullptr;
2930 
2931     HandleMouseEventWithoutKeyboard(event);
2932     return true;
2933 }
2934 
ClearMultiSelect()2935 void RenderGridLayout::ClearMultiSelect()
2936 {
2937     for (const auto& item : GetChildren()) {
2938         auto gridLayoutItem = FindChildOfClass<RenderGridLayoutItem>(item);
2939         if (!gridLayoutItem) {
2940             continue;
2941         }
2942         gridLayoutItem->MarkIsSelected(false);
2943     }
2944 }
2945 
MultiSelectWithoutKeyboard(const Rect & selectedZone)2946 void RenderGridLayout::MultiSelectWithoutKeyboard(const Rect& selectedZone)
2947 {
2948     if (!selectedZone.IsValid()) {
2949         Point mousePoint(selectedZone.GetOffset().GetX(), selectedZone.GetOffset().GetY());
2950         auto gridLayoutItem = FindChildNodeOfClass<RenderGridLayoutItem>(mousePoint, mousePoint);
2951         if (!gridLayoutItem) {
2952             return;
2953         }
2954         if (!gridLayoutItem->GetSelectable()) {
2955             return;
2956         }
2957         gridLayoutItem->MarkIsSelected(true);
2958         if (gridLayoutItem->GetOnSelectId()) {
2959             (gridLayoutItem->GetOnSelectId())(gridLayoutItem->IsSelected());
2960         }
2961         return;
2962     }
2963 
2964     for (const auto& item : GetChildren()) {
2965         auto gridLayoutItem = FindChildOfClass<RenderGridLayoutItem>(item);
2966         if (!gridLayoutItem) {
2967             continue;
2968         }
2969         if (!gridLayoutItem->GetSelectable()) {
2970             continue;
2971         }
2972         if (!selectedZone.IsIntersectWith(item->GetPaintRect())) {
2973             gridLayoutItem->MarkIsSelected(false);
2974             if (gridLayoutItem->GetOnSelectId()) {
2975                 (gridLayoutItem->GetOnSelectId())(gridLayoutItem->IsSelected());
2976             }
2977             continue;
2978         }
2979         gridLayoutItem->MarkIsSelected(true);
2980         if (gridLayoutItem->GetOnSelectId()) {
2981             (gridLayoutItem->GetOnSelectId())(gridLayoutItem->IsSelected());
2982         }
2983     }
2984 }
2985 
HandleMouseEventWithoutKeyboard(const MouseEvent & event)2986 void RenderGridLayout::HandleMouseEventWithoutKeyboard(const MouseEvent& event)
2987 {
2988     if (event.button == MouseButton::LEFT_BUTTON) {
2989         if (event.action == MouseAction::PRESS) {
2990             ClearMultiSelect();
2991             mouseStartOffset_ = event.GetOffset() - GetPaintRect().GetOffset();
2992             mouseEndOffset_ = event.GetOffset() - GetPaintRect().GetOffset();
2993             auto selectedZone = ComputeSelectedZone(mouseStartOffset_, mouseEndOffset_);
2994             MultiSelectWithoutKeyboard(selectedZone);
2995             MarkNeedRender();
2996         } else if (event.action == MouseAction::MOVE) {
2997             mouseEndOffset_ = event.GetOffset() - GetPaintRect().GetOffset();
2998             auto selectedZone = ComputeSelectedZone(mouseStartOffset_, mouseEndOffset_);
2999             MultiSelectWithoutKeyboard(selectedZone);
3000             MarkNeedRender();
3001         } else if (event.action == MouseAction::RELEASE) {
3002             mouseStartOffset_ = Offset(0.0, 0.0);
3003             mouseEndOffset_ = Offset(0.0, 0.0);
3004             MarkNeedRender();
3005         }
3006     }
3007 }
3008 
GetPressItemWhenShiftDown(const Rect & selectedZone)3009 RefPtr<RenderGridLayoutItem> RenderGridLayout::GetPressItemWhenShiftDown(const Rect& selectedZone)
3010 {
3011     if (!selectedZone.IsValid()) {
3012         Point mousePoint(selectedZone.GetOffset().GetX(), selectedZone.GetOffset().GetY());
3013         auto gridLayoutItem = FindChildNodeOfClass<RenderGridLayoutItem>(mousePoint, mousePoint);
3014         if (!gridLayoutItem) {
3015             return nullptr;
3016         }
3017         if (!gridLayoutItem->GetSelectable()) {
3018             return nullptr;
3019         }
3020         return gridLayoutItem;
3021     }
3022     return nullptr;
3023 }
3024 
MultiSelectWhenShiftDown(const Rect & selectedZone)3025 void RenderGridLayout::MultiSelectWhenShiftDown(const Rect& selectedZone)
3026 {
3027     for (const auto& item : GetChildren()) {
3028         auto gridLayoutItem = FindChildOfClass<RenderGridLayoutItem>(item);
3029         if (!gridLayoutItem) {
3030             continue;
3031         }
3032         if (!gridLayoutItem->GetSelectable()) {
3033             continue;
3034         }
3035         if (!selectedZone.IsIntersectWith(item->GetPaintRect())) {
3036             continue;
3037         }
3038         gridLayoutItem->MarkIsSelected(true);
3039         if (gridLayoutItem->GetOnSelectId()) {
3040             (gridLayoutItem->GetOnSelectId())(gridLayoutItem->IsSelected());
3041         }
3042     }
3043 }
3044 
HandleMouseEventWhenShiftDown(const MouseEvent & event)3045 void RenderGridLayout::HandleMouseEventWhenShiftDown(const MouseEvent& event)
3046 {
3047     if (event.button == MouseButton::LEFT_BUTTON) {
3048         if (event.action == MouseAction::PRESS) {
3049             mouseStartOffset_ = event.GetOffset() - GetPaintRect().GetOffset();
3050             mouseEndOffset_ = event.GetOffset() - GetPaintRect().GetOffset();
3051             auto selectedZone = ComputeSelectedZone(mouseStartOffset_, mouseEndOffset_);
3052             if (firstItemWithShift_ == nullptr) {
3053                 firstItemWithShift_ = GetPressItemWhenShiftDown(selectedZone);
3054             }
3055             secondItemWithShift_ = GetPressItemWhenShiftDown(selectedZone);
3056             MultiSelectAllInRange(firstItemWithShift_, secondItemWithShift_);
3057             MarkNeedRender();
3058         } else if (event.action == MouseAction::MOVE) {
3059             mouseEndOffset_ = event.GetOffset() - GetPaintRect().GetOffset();
3060             auto selectedZone = ComputeSelectedZone(mouseStartOffset_, mouseEndOffset_);
3061             MultiSelectWhenShiftDown(selectedZone);
3062             MarkNeedRender();
3063         } else if (event.action == MouseAction::RELEASE) {
3064             mouseStartOffset_ = Offset(0.0, 0.0);
3065             mouseEndOffset_ = Offset(0.0, 0.0);
3066             MarkNeedRender();
3067         }
3068     }
3069 }
3070 
MultiSelectAllInRange(const RefPtr<RenderGridLayoutItem> & firstItem,const RefPtr<RenderGridLayoutItem> & secondItem)3071 void RenderGridLayout::MultiSelectAllInRange(const RefPtr<RenderGridLayoutItem>& firstItem,
3072     const RefPtr<RenderGridLayoutItem>& secondItem)
3073 {
3074     ClearMultiSelect();
3075     if (!firstItem) {
3076         return;
3077     }
3078 
3079     if (!secondItem) {
3080         firstItem->MarkIsSelected(true);
3081         if (firstItem->GetOnSelectId()) {
3082             (firstItem->GetOnSelectId())(firstItem->IsSelected());
3083         }
3084         return;
3085     }
3086 
3087     auto fromItemIndex = std::min(firstItem->GetIndex(), secondItem->GetIndex());
3088     auto toItemIndex = std::max(firstItem->GetIndex(), secondItem->GetIndex());
3089 
3090     for (const auto& item : GetChildren()) {
3091         auto gridLayoutItem = FindChildOfClass<RenderGridLayoutItem>(item);
3092         if (!gridLayoutItem) {
3093             continue;
3094         }
3095         if (!gridLayoutItem->GetSelectable()) {
3096             continue;
3097         }
3098 
3099         auto nowIndex = gridLayoutItem->GetIndex();
3100         if (nowIndex <= toItemIndex && nowIndex >= fromItemIndex) {
3101             gridLayoutItem->MarkIsSelected(true);
3102             if (gridLayoutItem->GetOnSelectId()) {
3103                 (gridLayoutItem->GetOnSelectId())(gridLayoutItem->IsSelected());
3104             }
3105         }
3106     }
3107 }
3108 
MultiSelectWhenCtrlDown(const Rect & selectedZone)3109 void RenderGridLayout::MultiSelectWhenCtrlDown(const Rect& selectedZone)
3110 {
3111     if (!selectedZone.IsValid()) {
3112         Point mousePoint(selectedZone.GetOffset().GetX(), selectedZone.GetOffset().GetY());
3113         auto gridLayoutItem = FindChildNodeOfClass<RenderGridLayoutItem>(mousePoint, mousePoint);
3114         if (!gridLayoutItem) {
3115             return;
3116         }
3117         if (!gridLayoutItem->GetSelectable()) {
3118             return;
3119         }
3120 
3121         if (selectedItemsWithCtrl_.find(gridLayoutItem) != selectedItemsWithCtrl_.end()) {
3122             gridLayoutItem->MarkIsSelected(false);
3123         } else {
3124             gridLayoutItem->MarkIsSelected(true);
3125         }
3126 
3127         if (gridLayoutItem->GetOnSelectId()) {
3128             (gridLayoutItem->GetOnSelectId())(gridLayoutItem->IsSelected());
3129         }
3130         return;
3131     }
3132 
3133     for (const auto& item : GetChildren()) {
3134         auto gridLayoutItem = FindChildOfClass<RenderGridLayoutItem>(item);
3135         if (!gridLayoutItem) {
3136             continue;
3137         }
3138         if (!gridLayoutItem->GetSelectable()) {
3139             continue;
3140         }
3141         if (!selectedZone.IsIntersectWith(item->GetPaintRect())) {
3142             if (selectedItemsWithCtrl_.find(gridLayoutItem) != selectedItemsWithCtrl_.end()) {
3143                 gridLayoutItem->MarkIsSelected(true);
3144             }  else {
3145                 gridLayoutItem->MarkIsSelected(false);
3146             }
3147             if (gridLayoutItem->GetOnSelectId()) {
3148                 (gridLayoutItem->GetOnSelectId())(gridLayoutItem->IsSelected());
3149             }
3150             continue;
3151         }
3152 
3153         if (selectedItemsWithCtrl_.find(gridLayoutItem) != selectedItemsWithCtrl_.end()) {
3154             gridLayoutItem->MarkIsSelected(false);
3155         } else {
3156             gridLayoutItem->MarkIsSelected(true);
3157         }
3158 
3159         if (gridLayoutItem->GetOnSelectId()) {
3160             (gridLayoutItem->GetOnSelectId())(gridLayoutItem->IsSelected());
3161         }
3162     }
3163 }
3164 
HandleMouseEventWhenCtrlDown(const MouseEvent & event)3165 void RenderGridLayout::HandleMouseEventWhenCtrlDown(const MouseEvent& event)
3166 {
3167     if (event.button == MouseButton::LEFT_BUTTON) {
3168         if (event.action == MouseAction::PRESS) {
3169             mouseStartOffset_ = event.GetOffset() - GetPaintRect().GetOffset();
3170             mouseEndOffset_ = event.GetOffset() - GetPaintRect().GetOffset();
3171             auto selectedZone = ComputeSelectedZone(mouseStartOffset_, mouseEndOffset_);
3172             MultiSelectWhenCtrlDown(selectedZone);
3173             MarkNeedRender();
3174         } else if (event.action == MouseAction::MOVE) {
3175             mouseEndOffset_ = event.GetOffset() - GetPaintRect().GetOffset();
3176             auto selectedZone = ComputeSelectedZone(mouseStartOffset_, mouseEndOffset_);
3177             MultiSelectWhenCtrlDown(selectedZone);
3178             MarkNeedRender();
3179         } else if (event.action == MouseAction::RELEASE) {
3180             mouseStartOffset_ = Offset(0.0, 0.0);
3181             mouseEndOffset_ = Offset(0.0, 0.0);
3182             MarkNeedRender();
3183             CollectSelectedItems();
3184         }
3185     }
3186 }
3187 
CollectSelectedItems()3188 void RenderGridLayout::CollectSelectedItems()
3189 {
3190     selectedItemsWithCtrl_.clear();
3191     for (const auto& item : GetChildren()) {
3192         auto gridLayoutItem = FindChildOfClass<RenderGridLayoutItem>(item);
3193         if (!gridLayoutItem) {
3194             continue;
3195         }
3196         if (!gridLayoutItem->GetSelectable()) {
3197             continue;
3198         }
3199         if (gridLayoutItem->IsSelected()) {
3200             selectedItemsWithCtrl_.insert(gridLayoutItem);
3201         }
3202     }
3203 }
3204 
MultiSelectAllWhenCtrlA()3205 void RenderGridLayout::MultiSelectAllWhenCtrlA()
3206 {
3207     for (const auto& item : GetChildren()) {
3208         auto gridLayoutItem = FindChildOfClass<RenderGridLayoutItem>(item);
3209         if (!gridLayoutItem) {
3210             continue;
3211         }
3212         if (!gridLayoutItem->GetSelectable()) {
3213             continue;
3214         }
3215         gridLayoutItem->MarkIsSelected(true);
3216         if (gridLayoutItem->GetOnSelectId()) {
3217             (gridLayoutItem->GetOnSelectId())(gridLayoutItem->IsSelected());
3218         }
3219     }
3220     MarkNeedRender();
3221 }
3222 
TrimTemplate(std::string & str)3223 std::string RenderGridLayout::TrimTemplate(std::string& str)
3224 {
3225     return std::regex_replace(str, TRIM_REGEX, TRIM_TEMPLATE);
3226 }
3227 
RTrim(std::string & str)3228 void RenderGridLayout::RTrim(std::string& str)
3229 {
3230     str.erase(std::find_if(str.rbegin(), str.rend(), [](int ch) {
3231         return !std::isspace(ch);
3232         }).base(), str.end());
3233 }
3234 
SplitTemplate(const std::string & str,std::vector<Value> & vec,bool isRepeat)3235 bool RenderGridLayout::SplitTemplate(const std::string& str, std::vector<Value>& vec, bool isRepeat)
3236 {
3237     std::string merge;
3238     std::string regexResult;
3239     std::smatch result;
3240     std::regex pattern(SIZE_PATTERN, std::regex::icase);
3241     std::string::const_iterator iterStart = str.begin();
3242     std::string::const_iterator iterEnd = str.end();
3243 
3244     while (std::regex_search(iterStart, iterEnd, result, pattern)) {
3245         regexResult = result[0];
3246         merge += regexResult;
3247         Value value;
3248         value.str = TrimTemplate(regexResult);
3249         value.isRepeat = isRepeat;
3250         vec.emplace_back(value);
3251         iterStart = result[0].second;
3252     }
3253     return (merge.length() == str.length());
3254 }
3255 
GetRepeat(const std::string & str)3256 std::string RenderGridLayout::GetRepeat(const std::string& str)
3257 {
3258     std::smatch result;
3259     std::regex pattern(REPEAT_WITH_AUTOFILL, std::regex::icase);
3260     std::string::const_iterator iterStart = str.begin();
3261     std::string::const_iterator iterEnd = str.end();
3262     std::string regexResult;
3263     size_t count = 0;
3264     while (std::regex_search(iterStart, iterEnd, result, pattern)) {
3265         regexResult = result[0];
3266         iterStart = result[0].second;
3267         ++count;
3268     }
3269     if (count == 1) {
3270         return regexResult;
3271     } else {
3272         return std::string("");
3273     }
3274 }
3275 
CheckRepeatAndSplitString(std::vector<std::string> & vec,std::string & repeat,std::vector<Value> & resultvec)3276 bool RenderGridLayout::CheckRepeatAndSplitString(
3277     std::vector<std::string>& vec, std::string& repeat, std::vector<Value>& resultvec)
3278 {
3279     if (repeat.length() == 0 && vec.size() == 0) {
3280         return false;
3281     }
3282     std::string regexResult;
3283     std::regex pattern(INVALID_PATTERN, std::regex::icase);
3284 
3285     for (auto it = vec.begin(); it != vec.end(); it++) {
3286         RTrim(*it);
3287         bool ret = SplitTemplate(*it, resultvec);
3288         if (!ret) {
3289             return ret;
3290         }
3291         if (it == vec.begin()) {
3292             regexResult = std::regex_replace(repeat, pattern, "");
3293             if (regexResult.length() == 0) {
3294                 return false;
3295             }
3296             regexResult.erase(regexResult.end() - 1);
3297             RTrim(regexResult);
3298             ret = SplitTemplate(regexResult, resultvec, true);
3299             if (!ret) {
3300                 return ret;
3301             }
3302         }
3303     }
3304     return true;
3305 }
3306 
ConvertVirtualSize(const std::string & size,const DimensionUnit & unit)3307 double RenderGridLayout::ConvertVirtualSize(const std::string& size, const DimensionUnit& unit)
3308 {
3309     double ret = StringUtils::StringToDouble(size);
3310     switch (unit) {
3311         case DimensionUnit::PERCENT:
3312             ret = NormalizePercentToPx(Dimension(ret / FULL_PERCENT, DimensionUnit::PERCENT), !isVertical_);
3313             break;
3314         case DimensionUnit::VP:
3315             ret = NormalizeToPx(Dimension(ret, DimensionUnit::VP));
3316             break;
3317         case DimensionUnit::PX:
3318             break;
3319         default:
3320             ret = 0.0;
3321             break;
3322     }
3323     return ret;
3324 }
3325 
ParseUnit(const Value & val)3326 double RenderGridLayout::ParseUnit(const Value& val)
3327 {
3328     double ret = 0;
3329     if (val.str.find(UNIT_PIXEL) != std::string::npos) {
3330         ret = ConvertVirtualSize(val.str, DimensionUnit::PX);
3331     } else if (val.str.find(UNIT_PERCENT) != std::string::npos) {
3332         ret = ConvertVirtualSize(val.str, DimensionUnit::PERCENT);
3333     } else if (val.str.find(UNIT_VP) != std::string::npos || StringUtils::IsNumber(val.str)) {
3334         ret = ConvertVirtualSize(val.str, DimensionUnit::VP);
3335     }
3336     return ret;
3337 }
3338 
CheckAutoFillParameter(const std::string & args,double size,std::vector<double> & out,std::vector<Value> & resultvec)3339 bool RenderGridLayout::CheckAutoFillParameter(
3340     const std::string& args, double size, std::vector<double>& out, std::vector<Value>& resultvec)
3341 {
3342     out.clear();
3343     if (args.empty()) {
3344         return false;
3345     }
3346     std::smatch result;
3347     std::regex patternFilter(PREFIX_PATTERN, std::regex::icase);
3348     if(std::regex_search(args, result, patternFilter)) {
3349         out.push_back(size);
3350         return false;
3351     }
3352 
3353     std::regex pattern(REPEAT_WITH_AUTOFILL, std::regex::icase);
3354     std::vector<std::string> vec(
3355         std::sregex_token_iterator(args.begin(), args.end(), pattern, -1), std::sregex_token_iterator());
3356 
3357     std::string repeat = GetRepeat(args);
3358     bool bRet = CheckRepeatAndSplitString(vec, repeat, resultvec);
3359     if (!bRet && out.size() == 0) {
3360         out.push_back(size);
3361     }
3362     return bRet;
3363 }
3364 
ParseArgsWithAutoFill(const std::string & args,double size,double gap)3365 std::vector<double> RenderGridLayout::ParseArgsWithAutoFill(const std::string& args, double size, double gap)
3366 {
3367     std::vector<double> lens;
3368     if (args.find(UNIT_AUTO_FILL) == std::string::npos) {
3369         return ParseArgsInner(PreParseArgs(args), size, gap);
3370     }
3371     std::vector<Value> retTemplates;
3372     if (!CheckAutoFillParameter(args, size, lens, retTemplates)) {
3373         return lens;
3374     }
3375     int countNonRepeat = 0;
3376     double sizeRepeat = 0.0;
3377     double sizeNonRepeat = 0.0;
3378     bool bRepeat = false;
3379     std::vector<double> prefixLens;
3380     std::vector<double> repeatLens;
3381     std::vector<double> suffixLens;
3382     for (auto ret : retTemplates) {
3383         double sizeItem = ParseUnit(ret);
3384         if (ret.isRepeat) {
3385             bRepeat = true;
3386             sizeRepeat += sizeItem;
3387             repeatLens.push_back(sizeItem);
3388         } else {
3389             ++countNonRepeat;
3390             sizeNonRepeat += sizeItem;
3391             if (bRepeat) {
3392                 suffixLens.push_back(sizeItem);
3393             } else {
3394                 prefixLens.push_back(sizeItem);
3395             }
3396         }
3397     }
3398     double sizeNonRepeatGap = GreatNotEqual(countNonRepeat, 0) ? (countNonRepeat - 1) * gap : 0;
3399     double sizeLeft = size - sizeNonRepeatGap - sizeNonRepeat;
3400     int count = 0;
3401     if (!NearZero(sizeRepeat)) {
3402         count = LessOrEqual(sizeLeft / sizeRepeat, 1) ? 1 : floor(sizeLeft / sizeRepeat);
3403     } else {
3404         if (GetChildren().size() >= countNonRepeat && retTemplates.size() > 0) {
3405             count = ceil((GetChildren().size() - countNonRepeat) * 1.0 / (retTemplates.size() - countNonRepeat));
3406         }
3407     }
3408     lens.insert(lens.end(), prefixLens.begin(), prefixLens.end());
3409     for (int i = 0; i < count; i++) {
3410         lens.insert(lens.end(), repeatLens.begin(), repeatLens.end());
3411     }
3412     lens.insert(lens.end(), suffixLens.begin(), suffixLens.end());
3413     return lens;
3414 }
3415 
ParseArgs(const std::string & args,double size,double gap)3416 std::vector<double> RenderGridLayout::ParseArgs(const std::string& args, double size, double gap)
3417 {
3418     if (args.find(REPEAT_PREFIX) != std::string::npos && args.find(UNIT_AUTO_FILL) != std::string::npos) {
3419         return ParseArgsWithAutoFill(args, size, gap);
3420     } else {
3421         return ParseArgsInner(PreParseArgs(args), size, gap);
3422     }
3423 }
3424 } // namespace OHOS::Ace
3425