1 /*
2 * Copyright (c) 2024 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 #include "core/components_ng/pattern/waterflow/layout/sliding_window/water_flow_layout_info_sw.h"
16
17 #include <algorithm>
18 #include <cstdint>
19
20 #include "base/utils/utils.h"
21
22 namespace OHOS::Ace::NG {
Sync(int32_t itemCnt,float mainSize,const std::vector<float> & mainGap)23 void WaterFlowLayoutInfoSW::Sync(int32_t itemCnt, float mainSize, const std::vector<float>& mainGap)
24 {
25 if (lanes_.empty()) {
26 return;
27 }
28 startIndex_ = StartIndex();
29 endIndex_ = EndIndex();
30 if (startIndex_ > endIndex_) {
31 SyncOnEmptyLanes();
32 return;
33 }
34 if (!idxToLane_.count(startIndex_) || lanes_[GetSegment(startIndex_)].size() <= idxToLane_.at(startIndex_)) {
35 return;
36 }
37 storedOffset_ = lanes_[GetSegment(startIndex_)][idxToLane_.at(startIndex_)].startPos;
38
39 delta_ = 0.0f;
40 lastMainSize_ = mainSize;
41 mainGap_ = mainGap;
42 startPos_ = StartPos();
43 endPos_ = EndPos();
44
45 itemStart_ = startIndex_ == 0 && NonNegative(startPos_ - TopMargin());
46 itemEnd_ = endIndex_ == itemCnt - 1;
47 if (footerIndex_ == 0) {
48 itemEnd_ &= LessOrEqual(endPos_, mainSize);
49 }
50 offsetEnd_ = itemEnd_ && LessOrEqual(endPos_ + footerHeight_ + BotMargin(), mainSize);
51 maxHeight_ = std::max(endPos_ - startPos_ + footerHeight_, maxHeight_);
52
53 if (!itemEnd_) {
54 footerHeight_ = 0.0f;
55 }
56
57 newStartIndex_ = EMPTY_NEW_START_INDEX;
58
59 synced_ = true;
60 }
61
CalibrateOffset()62 float WaterFlowLayoutInfoSW::CalibrateOffset()
63 {
64 if (startIndex_ == 0) {
65 // can calibrate totalOffset when at top
66 const float prev = totalOffset_;
67 totalOffset_ = startPos_ - TopMargin();
68 return totalOffset_ - prev;
69 }
70 return 0.0f;
71 }
72
DistanceToTop(int32_t itemIdx,float mainGap) const73 float WaterFlowLayoutInfoSW::DistanceToTop(int32_t itemIdx, float mainGap) const
74 {
75 if (!ItemInView(itemIdx)) {
76 return 0.0f;
77 }
78 const auto& lane = lanes_[GetSegment(itemIdx)][idxToLane_.at(itemIdx)];
79 float dist = lane.startPos;
80 for (const auto& item : lane.items_) {
81 if (item.idx == itemIdx) {
82 break;
83 }
84 dist += item.mainSize + mainGap;
85 }
86 return dist;
87 }
88
DistanceToBottom(int32_t itemIdx,float mainSize,float mainGap) const89 float WaterFlowLayoutInfoSW::DistanceToBottom(int32_t itemIdx, float mainSize, float mainGap) const
90 {
91 if (!ItemInView(itemIdx)) {
92 return 0.0f;
93 }
94 const auto& lane = lanes_[GetSegment(itemIdx)][idxToLane_.at(itemIdx)];
95 float dist = mainSize - lane.endPos;
96 for (auto item = lane.items_.rbegin(); item != lane.items_.rend(); ++item) {
97 if (item->idx == itemIdx) {
98 break;
99 }
100 dist += item->mainSize + mainGap;
101 }
102 return dist;
103 }
104
OutOfBounds() const105 bool WaterFlowLayoutInfoSW::OutOfBounds() const
106 {
107 if (lanes_.empty()) {
108 return false;
109 }
110 // checking first lane is enough because re-align automatically happens when reaching start
111 if (itemStart_ && Positive(lanes_[0][0].startPos - TopMargin())) {
112 return true;
113 }
114 if (!itemStart_ && offsetEnd_) {
115 return std::all_of(lanes_.back().begin(), lanes_.back().end(), [this](const Lane& lane) {
116 return LessNotEqual(lane.endPos + footerHeight_ + BotMargin(), lastMainSize_);
117 });
118 }
119 return false;
120 }
121
GetOverScrolledDelta(float delta) const122 OverScrollOffset WaterFlowLayoutInfoSW::GetOverScrolledDelta(float delta) const
123 {
124 OverScrollOffset res {};
125 if (lanes_.empty()) {
126 return res;
127 }
128
129 if (startIndex_ == 0) {
130 float disToTop = -StartPosWithMargin();
131 if (!itemStart_) {
132 res.start = std::max(0.0f, delta - disToTop);
133 } else if (Positive(delta)) {
134 res.start = delta;
135 } else {
136 res.start = std::max(delta, disToTop);
137 }
138 }
139
140 if (!itemEnd_) {
141 return res;
142 }
143 float disToBot = EndPosWithMargin() + footerHeight_ - std::min(lastMainSize_, maxHeight_);
144 if (Positive(disToBot) && LessNotEqual(maxHeight_, lastMainSize_)) {
145 res.end = std::min(0.0f, disToBot + delta);
146 return res;
147 }
148 if (!offsetEnd_) {
149 res.end = std::min(0.0f, disToBot + delta);
150 } else if (Negative(delta)) {
151 res.end = delta;
152 } else {
153 res.end = std::min(delta, -disToBot);
154 }
155 return res;
156 }
157
CalcOverScroll(float mainSize,float delta) const158 float WaterFlowLayoutInfoSW::CalcOverScroll(float mainSize, float delta) const
159 {
160 if (lanes_.empty()) {
161 return 0.0f;
162 }
163 float res = 0.0f;
164 if (itemStart_) {
165 res = StartPosWithMargin() + delta;
166 }
167 if (offsetEnd_) {
168 res = mainSize - (EndPosWithMargin() + footerHeight_ + delta);
169 }
170 return res;
171 }
172
173 namespace {
174 using Lane = WaterFlowLayoutInfoSW::Lane;
SectionEmpty(const std::vector<WaterFlowLayoutInfoSW::Lane> & section)175 inline bool SectionEmpty(const std::vector<WaterFlowLayoutInfoSW::Lane>& section)
176 {
177 return section.empty() ||
178 std::all_of(section.begin(), section.end(), [](const auto& lane) { return lane.items_.empty(); });
179 }
SectionEndPos(const std::vector<WaterFlowLayoutInfoSW::Lane> & section)180 inline float SectionEndPos(const std::vector<WaterFlowLayoutInfoSW::Lane>& section)
181 {
182 return std::max_element(section.begin(), section.end(), [](const Lane& left, const Lane& right) {
183 return LessNotEqual(left.endPos, right.endPos);
184 })->endPos;
185 }
186
SectionStartPos(const std::vector<WaterFlowLayoutInfoSW::Lane> & section)187 inline float SectionStartPos(const std::vector<WaterFlowLayoutInfoSW::Lane>& section)
188 {
189 return std::min_element(section.begin(), section.end(), [](const Lane& left, const Lane& right) {
190 return LessNotEqual(left.startPos, right.startPos);
191 })->startPos;
192 }
193 } // namespace
194
EndPos() const195 float WaterFlowLayoutInfoSW::EndPos() const
196 {
197 if (synced_) {
198 return endPos_;
199 }
200 for (auto it = lanes_.rbegin(); it != lanes_.rend(); ++it) {
201 if (SectionEmpty(*it)) {
202 continue;
203 }
204 return SectionEndPos(*it);
205 }
206 return 0.0f;
207 }
208
StartPos() const209 float WaterFlowLayoutInfoSW::StartPos() const
210 {
211 if (synced_) {
212 return startPos_;
213 }
214 for (const auto& section : lanes_) {
215 if (SectionEmpty(section)) {
216 continue;
217 }
218 return SectionStartPos(section);
219 }
220 return 0.0f;
221 }
222
ReachStart(float prevPos,bool firstLayout) const223 bool WaterFlowLayoutInfoSW::ReachStart(float prevPos, bool firstLayout) const
224 {
225 if (!itemStart_ || lanes_.empty()) {
226 return false;
227 }
228 return firstLayout || Negative(prevPos);
229 }
230
ReachEnd(float prevPos,bool firstLayout) const231 bool WaterFlowLayoutInfoSW::ReachEnd(float prevPos, bool firstLayout) const
232 {
233 if (!offsetEnd_ || lanes_.empty()) {
234 return false;
235 }
236 float prevEndPos = EndPos() - (totalOffset_ - prevPos);
237 return firstLayout || GreatNotEqual(prevEndPos + footerHeight_, lastMainSize_);
238 }
239
GetContentHeight() const240 float WaterFlowLayoutInfoSW::GetContentHeight() const
241 {
242 // only height in view are remembered
243 return maxHeight_;
244 }
245
GetMainCount() const246 int32_t WaterFlowLayoutInfoSW::GetMainCount() const
247 {
248 if (lanes_.empty()) {
249 return 0;
250 }
251 for (const auto& section : lanes_) {
252 if (SectionEmpty(section)) {
253 continue;
254 }
255 return static_cast<int32_t>(
256 std::max_element(section.begin(), section.end(), [](const Lane& left, const Lane& right) {
257 return left.items_.size() < right.items_.size();
258 })->items_.size());
259 }
260 return 0;
261 }
262
CalcTargetPosition(int32_t idx,int32_t) const263 float WaterFlowLayoutInfoSW::CalcTargetPosition(int32_t idx, int32_t /* crossIdx */) const
264 {
265 if (!ItemInView(idx)) {
266 return Infinity<float>();
267 }
268 const auto& lane = lanes_[GetSegment(idx)][idxToLane_.at(idx)];
269 float pos = 0.0f; // main-axis position of the item's top edge relative to viewport top. Positive if below viewport
270 float itemSize = 0.0f;
271 if (idx < endIndex_) {
272 pos = DistanceToTop(idx, mainGap_[GetSegment(idx)]);
273 auto it = std::find_if(
274 lane.items_.begin(), lane.items_.end(), [idx](const ItemInfo& item) { return item.idx == idx; });
275 itemSize = it->mainSize;
276 } else {
277 itemSize = lane.items_.back().mainSize;
278 pos = lane.endPos - itemSize;
279 }
280 switch (align_) {
281 case ScrollAlign::START:
282 break;
283 case ScrollAlign::END:
284 pos = pos - lastMainSize_ + itemSize;
285 break;
286 case ScrollAlign::AUTO:
287 if (Negative(pos)) {
288 /* */
289 } else if (GreatNotEqual(pos + itemSize, lastMainSize_)) {
290 pos = pos - lastMainSize_ + itemSize;
291 } else {
292 pos = 0.0f; // already in viewport, no movement needed
293 }
294 break;
295 case ScrollAlign::CENTER:
296 pos = pos - (lastMainSize_ - itemSize) / 2.0f;
297 break;
298 default:
299 pos = 0.0f;
300 break;
301 }
302 // convert to absolute position
303 return pos - totalOffset_;
304 }
305
PrepareJump()306 void WaterFlowLayoutInfoSW::PrepareJump()
307 {
308 if (startIndex_ > endIndex_) {
309 return;
310 }
311 align_ = ScrollAlign::START;
312 jumpIndex_ = startIndex_;
313 delta_ = storedOffset_;
314 }
315
Reset()316 void WaterFlowLayoutInfoSW::Reset()
317 {
318 PrepareJump();
319 for (auto& section : lanes_) {
320 for (auto& lane : section) {
321 lane.items_.clear();
322 }
323 }
324 idxToLane_.clear();
325 maxHeight_ = 0.0f;
326 synced_ = false;
327 }
328
EndIndex() const329 int32_t WaterFlowLayoutInfoSW::EndIndex() const
330 {
331 if (synced_) {
332 return endIndex_;
333 }
334 int32_t maxIdx = -1;
335 for (auto it = lanes_.rbegin(); it != lanes_.rend(); ++it) {
336 bool flag = false;
337 for (const auto& lane : *it) {
338 if (lane.items_.empty()) {
339 continue;
340 }
341 flag = true;
342 maxIdx = std::max(maxIdx, lane.items_.back().idx);
343 }
344 if (flag) {
345 break;
346 }
347 }
348 return maxIdx;
349 }
350
StartIndex() const351 int32_t WaterFlowLayoutInfoSW::StartIndex() const
352 {
353 if (synced_) {
354 return startIndex_;
355 }
356 auto minIdx = Infinity<int32_t>();
357 for (const auto& section : lanes_) {
358 bool flag = false;
359 for (const auto& lane : section) {
360 if (lane.items_.empty()) {
361 continue;
362 }
363 flag = true;
364 minIdx = std::min(minIdx, lane.items_.front().idx);
365 }
366 if (flag) {
367 break;
368 }
369 }
370 return minIdx;
371 }
372
GetCrossIndex(int32_t itemIndex) const373 int32_t WaterFlowLayoutInfoSW::GetCrossIndex(int32_t itemIndex) const
374 {
375 if (ItemInView(itemIndex)) {
376 return static_cast<int32_t>(idxToLane_.at(itemIndex));
377 }
378 return -1;
379 }
380
ResetWithLaneOffset(std::optional<float> laneBasePos)381 void WaterFlowLayoutInfoSW::ResetWithLaneOffset(std::optional<float> laneBasePos)
382 {
383 for (auto& section : lanes_) {
384 std::for_each(section.begin(), section.end(), [&laneBasePos](auto& lane) {
385 lane.items_.clear();
386 if (laneBasePos) {
387 lane.startPos = *laneBasePos;
388 lane.endPos = *laneBasePos;
389 } else {
390 lane.endPos = lane.startPos;
391 }
392 });
393 }
394 maxHeight_ = 0.0f;
395 idxToLane_.clear();
396 synced_ = false;
397 }
398
ToString() const399 std::string WaterFlowLayoutInfoSW::Lane::ToString() const
400 {
401 std::string res = "{StartPos: " + std::to_string(startPos) + " EndPos: " + std::to_string(endPos) + " ";
402 if (items_.empty()) {
403 res += "empty";
404 } else {
405 res += "Items [";
406 for (const auto& item : items_) {
407 res += std::to_string(item.idx) + " ";
408 }
409 res += "] ";
410 }
411 res += "}";
412 return res;
413 }
414
ItemCloseToView(int32_t idx) const415 bool WaterFlowLayoutInfoSW::ItemCloseToView(int32_t idx) const
416 {
417 if (lanes_.empty() || std::all_of(lanes_.begin(), lanes_.end(), [](const auto& lanes) { return lanes.empty(); })) {
418 return false;
419 }
420 int32_t startIdx = StartIndex();
421 int32_t endIdx = EndIndex();
422 using std::abs, std::min;
423 return min(abs(idx - endIdx), abs(idx - startIdx)) < endIdx - startIdx + 1;
424 }
425
ClearDataFrom(int32_t idx,const std::vector<float> & mainGap)426 void WaterFlowLayoutInfoSW::ClearDataFrom(int32_t idx, const std::vector<float>& mainGap)
427 {
428 for (auto it = idxToLane_.begin(); it != idxToLane_.end();) {
429 if (it->first >= idx) {
430 it = idxToLane_.erase(it); // Erase and get the iterator to the next element
431 } else {
432 ++it;
433 }
434 }
435 for (int32_t i = GetSegment(idx); i < static_cast<int32_t>(lanes_.size()); ++i) {
436 for (auto& lane : lanes_[i]) {
437 while (!lane.items_.empty() && lane.items_.back().idx >= idx) {
438 lane.endPos -= lane.items_.back().mainSize + mainGap[i];
439 lane.items_.pop_back();
440 }
441 lane.endPos = std::max(lane.endPos, lane.startPos);
442 }
443 }
444 }
445
TopFinalPos() const446 float WaterFlowLayoutInfoSW::TopFinalPos() const
447 {
448 return -(StartPosWithMargin() + delta_);
449 };
450
BottomFinalPos(float viewHeight) const451 float WaterFlowLayoutInfoSW::BottomFinalPos(float viewHeight) const
452 {
453 return -(EndPosWithMargin() + delta_ + footerHeight_) + std::min(maxHeight_, viewHeight);
454 };
455
IsMisaligned() const456 bool WaterFlowLayoutInfoSW::IsMisaligned() const
457 {
458 if (lanes_.empty()) {
459 return false;
460 }
461
462 const int32_t startIdx = StartIndex();
463 int32_t startSeg = GetSegment(startIdx);
464 if (startSeg < 0) {
465 return false;
466 }
467 if (startSeg == 0) {
468 if (startIdx > 0) {
469 ++startSeg;
470 }
471 } else if (startIdx != segmentTails_[startSeg - 1] + 1) {
472 ++startSeg;
473 }
474
475 const int32_t endSeg = GetSegment(EndIndex());
476 for (int32_t i = startSeg; i <= endSeg; ++i) {
477 if (SectionEmpty(lanes_[i])) {
478 continue;
479 }
480 const float startPos = SectionStartPos(lanes_[i]);
481 if (std::any_of(lanes_[i].begin(), lanes_[i].end(),
482 [&startPos](const auto& lane) { return !NearEqual(lane.startPos, startPos); })) {
483 return true;
484 }
485 const int32_t sectionStart = (i == 0) ? 0 : segmentTails_[i - 1] + 1;
486 if (sectionStart != lanes_[i][0].items_.front().idx) {
487 return true;
488 }
489 }
490 return false;
491 }
492
InitSegments(const std::vector<WaterFlowSections::Section> & sections,int32_t start)493 void WaterFlowLayoutInfoSW::InitSegments(const std::vector<WaterFlowSections::Section>& sections, int32_t start)
494 {
495 synced_ = false;
496 const size_t n = sections.size();
497 if (n == 0) {
498 return;
499 }
500
501 InitSegmentTails(sections);
502
503 InitLanes(sections, start);
504
505 margins_.clear(); // to be initialized during layout
506 }
507
PrepareSectionPos(int32_t idx,bool fillBack)508 void WaterFlowLayoutInfoSW::PrepareSectionPos(int32_t idx, bool fillBack)
509 {
510 int32_t prevSeg = GetSegment(fillBack ? idx - 1 : idx + 1);
511 int32_t curSeg = GetSegment(idx);
512 if (prevSeg == curSeg) {
513 return;
514 }
515 if (SectionEmpty(lanes_[prevSeg])) {
516 // previous section is invalid
517 return;
518 }
519 // prepare sections below
520 if (prevSeg < curSeg) {
521 for (int32_t i = prevSeg + 1; i <= curSeg; ++i) {
522 float pos = SectionEndPos(lanes_[i - 1]);
523 pos += axis_ == Axis::VERTICAL ? margins_[i - 1].bottom.value_or(0.0f) + margins_[i].top.value_or(0.0f)
524 : margins_[i - 1].right.value_or(0.0f) + margins_[i].left.value_or(0.0f);
525 std::for_each(lanes_[i].begin(), lanes_[i].end(), [pos](Lane& lane) {
526 lane.startPos = lane.endPos = pos;
527 lane.items_.clear();
528 });
529 }
530 return;
531 }
532 // prepare sections above
533 for (int32_t i = prevSeg - 1; i >= curSeg; --i) {
534 float pos = SectionStartPos(lanes_[i + 1]);
535 pos -= axis_ == Axis::VERTICAL ? margins_[i + 1].top.value_or(0.0f) + margins_[i].bottom.value_or(0.0f)
536 : margins_[i + 1].left.value_or(0.0f) + margins_[i].right.value_or(0.0f);
537 float diff = SectionEndPos(lanes_[i]) - pos;
538 if (NearZero(diff)) {
539 continue;
540 }
541 // use subtraction to keep the end positions staggered
542 std::for_each(lanes_[i].begin(), lanes_[i].end(), [diff](Lane& lane) {
543 lane.endPos -= diff;
544 lane.startPos = lane.endPos;
545 lane.items_.clear();
546 });
547 }
548 }
549
InitSegmentTails(const std::vector<WaterFlowSections::Section> & sections)550 void WaterFlowLayoutInfoSW::InitSegmentTails(const std::vector<WaterFlowSections::Section>& sections)
551 {
552 const size_t n = sections.size();
553 segmentCache_.clear();
554 segmentTails_ = { sections[0].itemsCount - 1 };
555 for (size_t i = 1; i < n; ++i) {
556 segmentTails_.push_back(segmentTails_[i - 1] + sections[i].itemsCount);
557 }
558 }
559
InitLanes(const std::vector<WaterFlowSections::Section> & sections,const int32_t start)560 void WaterFlowLayoutInfoSW::InitLanes(const std::vector<WaterFlowSections::Section>& sections, const int32_t start)
561 {
562 const size_t n = sections.size();
563
564 const int32_t lastValidIdx = start > 0 ? segmentTails_[start - 1] : -1;
565 if (lastValidIdx < endIndex_) {
566 PrepareJump();
567 }
568
569 lanes_.resize(n);
570 for (size_t i = static_cast<size_t>(start); i < n; ++i) {
571 lanes_[i] = std::vector<Lane>(sections[i].crossCount.value_or(1));
572 }
573
574 for (auto it = idxToLane_.begin(); it != idxToLane_.end();) {
575 if (it->first > lastValidIdx) {
576 it = idxToLane_.erase(it);
577 } else {
578 ++it;
579 }
580 }
581 }
582
InitSegmentsForKeepPositionMode(const std::vector<WaterFlowSections::Section> & sections,const std::vector<WaterFlowSections::Section> & prevSections,int32_t start)583 void WaterFlowLayoutInfoSW::InitSegmentsForKeepPositionMode(const std::vector<WaterFlowSections::Section>& sections,
584 const std::vector<WaterFlowSections::Section>& prevSections, int32_t start)
585 {
586 synced_ = false;
587 const size_t n = sections.size();
588 if (n == 0) {
589 ClearData();
590 return;
591 }
592
593 WaterFlowSections::Section prevSection;
594 auto prevSegIdx = GetSegment(startIndex_);
595 if (prevSections.size() > static_cast<size_t>(prevSegIdx)) {
596 prevSection = prevSections[prevSegIdx];
597 }
598
599 InitSegmentTails(sections);
600
601 if (AdjustLanes(sections, prevSection, start, prevSegIdx)) {
602 margins_.clear();
603 return;
604 }
605
606 InitLanes(sections, start);
607
608 margins_.clear(); // to be initialized during layout
609 }
610
AdjustLanes(const std::vector<WaterFlowSections::Section> & sections,const WaterFlowSections::Section & prevSection,int32_t start,int32_t prevSegIdx)611 bool WaterFlowLayoutInfoSW::AdjustLanes(const std::vector<WaterFlowSections::Section>& sections,
612 const WaterFlowSections::Section& prevSection, int32_t start, int32_t prevSegIdx)
613 {
614 if (newStartIndex_ < 0) {
615 return false;
616 }
617 const size_t n = sections.size();
618 const size_t curSegIdx = static_cast<size_t>(GetSegment(newStartIndex_));
619 const auto& curSection = sections[curSegIdx];
620 if (curSection.OnlyCountDiff(prevSection)) {
621 // move old lanes_[prevSegIdx,...] to Lanes_[curSegIdx,...]
622 if (n <= lanes_.size()) {
623 // means curSegIdx <= prevSegIdx
624 for (size_t i = 0; i < curSegIdx; ++i) {
625 lanes_[i] = std::vector<Lane>(sections[i].crossCount.value_or(1));
626 }
627 for (size_t i = curSegIdx; i < n; ++i) {
628 lanes_[i] = lanes_[prevSegIdx++];
629 }
630 lanes_.resize(n);
631 } else {
632 // 分组增加了,means curSegIdx > prevSegIdx
633 size_t oriSize = lanes_.size() - 1;
634 lanes_.resize(n);
635 for (size_t i = n - 1; i >= curSegIdx; i--) {
636 lanes_[i] = lanes_[oriSize--];
637 }
638 for (size_t i = 0; i < curSegIdx; ++i) {
639 lanes_[i] = std::vector<Lane>(sections[i].crossCount.value_or(1));
640 }
641 }
642 margins_.clear();
643 return true;
644 } else {
645 newStartIndex_ = INVALID_NEW_START_INDEX;
646 }
647 return false;
648 }
649
PrepareNewStartIndex()650 bool WaterFlowLayoutInfoSW::PrepareNewStartIndex()
651 {
652 if (newStartIndex_ == EMPTY_NEW_START_INDEX) {
653 newStartIndex_ = StartIndex();
654 }
655 if (newStartIndex_ == Infinity<int32_t>()) {
656 newStartIndex_ = INVALID_NEW_START_INDEX;
657 }
658 if (newStartIndex_ == INVALID_NEW_START_INDEX) {
659 return false;
660 }
661 return true;
662 }
663
NotifyDataChange(int32_t index,int32_t count)664 void WaterFlowLayoutInfoSW::NotifyDataChange(int32_t index, int32_t count)
665 {
666 if (!PrepareNewStartIndex()) {
667 return;
668 }
669 // 更新的index是否在newStartIndex_上方、是否会影响newStartIndex_
670 if ((count == 0 && newStartIndex_ <= index) || (count > 0 && newStartIndex_ < index) ||
671 (count < 0 && newStartIndex_ <= index - count - 1)) {
672 newStartIndex_ = INVALID_NEW_START_INDEX;
673 return;
674 }
675 newStartIndex_ += count;
676 }
677
UpdateLanesIndex(int32_t updateIdx)678 void WaterFlowLayoutInfoSW::UpdateLanesIndex(int32_t updateIdx)
679 {
680 idxToLane_.clear();
681 const int32_t diff = newStartIndex_ - startIndex_;
682 for (auto& section : lanes_) {
683 for (size_t i = 0; i < section.size(); i++) {
684 for (auto& item : section[i].items_) {
685 item.idx += diff;
686 idxToLane_[item.idx] = i;
687 }
688 }
689 }
690 startIndex_ = StartIndex();
691 endIndex_ = EndIndex();
692 }
693
BeginCacheUpdate()694 void WaterFlowLayoutInfoSW::BeginCacheUpdate()
695 {
696 savedLanes_ = std::make_unique<decltype(lanes_)>(lanes_);
697 synced_ = false;
698 }
699
EndCacheUpdate()700 void WaterFlowLayoutInfoSW::EndCacheUpdate()
701 {
702 synced_ = true;
703 if (savedLanes_) {
704 lanes_ = std::move(*savedLanes_);
705 savedLanes_.reset();
706 }
707 }
708
ClearData()709 void WaterFlowLayoutInfoSW::ClearData()
710 {
711 segmentCache_.clear();
712 segmentTails_.clear();
713 lanes_.clear();
714 idxToLane_.clear();
715 margins_.clear();
716 maxHeight_ = 0.0f;
717 synced_ = false;
718 startIndex_ = 0;
719 endIndex_ = -1;
720 }
721
SyncOnEmptyLanes()722 void WaterFlowLayoutInfoSW::SyncOnEmptyLanes()
723 {
724 startPos_ = 0.0f;
725 endPos_ = 0.0f;
726 itemStart_ = true;
727 itemEnd_ = true;
728 offsetEnd_ = true;
729 maxHeight_ = footerHeight_;
730 newStartIndex_ = EMPTY_NEW_START_INDEX;
731 synced_ = true;
732 }
733 } // namespace OHOS::Ace::NG
734