1 /*
2 * Copyright (c) 2023 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_ng/pattern/list/list_content_modifier.h"
17
18 #include "base/utils/utils.h"
19 #include "core/components_ng/base/modifier.h"
20 #include "core/components_ng/render/divider_painter.h"
21 #include "core/components_ng/render/drawing.h"
22
23 namespace OHOS::Ace::NG {
ListContentModifier(const OffsetF & clipOffset,const SizeF & clipSize)24 ListContentModifier::ListContentModifier(const OffsetF& clipOffset, const SizeF& clipSize)
25 {
26 clipOffset_ = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(clipOffset);
27 clipSize_ = AceType::MakeRefPtr<AnimatablePropertySizeF>(clipSize);
28 clip_ = AceType::MakeRefPtr<PropertyBool>(true);
29 flushDivider_ = AceType::MakeRefPtr<PropertyBool>(true);
30
31 AttachProperty(clipOffset_);
32 AttachProperty(clipSize_);
33 AttachProperty(clip_);
34 AttachProperty(flushDivider_);
35 }
36
onDraw(DrawingContext & context)37 void ListContentModifier::onDraw(DrawingContext& context)
38 {
39 if (clip_->Get()) {
40 auto offset = clipOffset_->Get();
41 auto size = clipSize_->Get();
42 auto clipRect = RSRect(offset.GetX(), offset.GetY(),
43 offset.GetX() + size.Width(), offset.GetY() + size.Height());
44 context.canvas.ClipRect(clipRect, RSClipOp::INTERSECT);
45 }
46 if (dividerInfo_.has_value()) {
47 PaintDivider(dividerInfo_.value(), itemPosition_, context.canvas);
48 }
49 }
50
PaintDivider(const DividerInfo & dividerInfo,const PositionMap & itemPosition,RSCanvas & canvas)51 void ListContentModifier::PaintDivider(
52 const DividerInfo& dividerInfo, const PositionMap& itemPosition, RSCanvas& canvas)
53 {
54 float fSpacingTotal = (dividerInfo.lanes - 1) * dividerInfo.laneGutter;
55 float laneLen =
56 (dividerInfo.crossSize - fSpacingTotal) / dividerInfo.lanes - dividerInfo.startMargin - dividerInfo.endMargin;
57 float crossLen = dividerInfo.crossSize - dividerInfo.startMargin - dividerInfo.endMargin;
58 DividerPainter dividerPainter(
59 dividerInfo.constrainStrokeWidth, crossLen, dividerInfo.isVertical, dividerInfo.color, LineCap::SQUARE);
60
61 int32_t lanes = dividerInfo.lanes;
62 int32_t laneIdx = 0;
63 bool lastIsItemGroup = false;
64 bool isFirstItem = (itemPosition.begin()->first == 0);
65 std::list<int32_t> lastLineIndex;
66
67 for (const auto& child : itemPosition) {
68 if (!isFirstItem) {
69 float divOffset = (dividerInfo.space + dividerInfo.constrainStrokeWidth) / 2; /* 2 half */
70 float mainPos = child.second.startPos - divOffset + dividerInfo.mainPadding;
71 float crossPos = dividerInfo.startMargin + dividerInfo.crossPadding;
72 if (lanes > 1 && !lastIsItemGroup && !child.second.isGroup) {
73 crossPos +=
74 laneIdx * ((dividerInfo.crossSize - fSpacingTotal) / dividerInfo.lanes + dividerInfo.laneGutter);
75 dividerPainter.SetDividerLength(laneLen);
76 } else {
77 dividerPainter.SetDividerLength(crossLen);
78 }
79 OffsetF offset = dividerInfo.isVertical ? OffsetF(mainPos, crossPos) : OffsetF(crossPos, mainPos);
80 if (dividerPainter.GetDividerLength() > 0) {
81 dividerPainter.DrawLine(canvas, offset);
82 }
83 }
84 if (laneIdx == 0 || child.second.isGroup) {
85 lastLineIndex.clear();
86 }
87 lastLineIndex.emplace_back(child.first);
88 lastIsItemGroup = child.second.isGroup;
89 laneIdx = (lanes <= 1 || (laneIdx + 1) >= lanes || child.second.isGroup) ? 0 : laneIdx + 1;
90 isFirstItem = isFirstItem ? laneIdx > 0 : false;
91 }
92 if (!lastLineIndex.empty() && *lastLineIndex.rbegin() < dividerInfo.totalItemCount - 1) {
93 int32_t laneIdx = 0;
94 for (auto index : lastLineIndex) {
95 if (index + lanes >= dividerInfo.totalItemCount) {
96 break;
97 }
98 float divOffset = (dividerInfo.space - dividerInfo.constrainStrokeWidth) / 2; /* 2 half */
99 float mainPos = itemPosition.at(index).endPos + divOffset + dividerInfo.mainPadding;
100 float crossPos = dividerInfo.startMargin + dividerInfo.crossPadding;
101 if (lanes > 1 && !itemPosition.at(index).isGroup) {
102 crossPos +=
103 laneIdx * ((dividerInfo.crossSize - fSpacingTotal) / dividerInfo.lanes + dividerInfo.laneGutter);
104 dividerPainter.SetDividerLength(laneLen);
105 } else {
106 dividerPainter.SetDividerLength(crossLen);
107 }
108 OffsetF offset = dividerInfo.isVertical ? OffsetF(mainPos, crossPos) : OffsetF(crossPos, mainPos);
109 if (dividerPainter.GetDividerLength() > 0) {
110 dividerPainter.DrawLine(canvas, offset);
111 }
112 laneIdx++;
113 }
114 }
115 }
116 } // namespace OHOS::Ace::NG
117