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