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