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