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