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