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