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