1 /*
2 * Copyright (c) 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_ng/pattern/list/list_paint_method.h"
17
18 #include "core/components_ng/pattern/scroll/inner/scroll_bar_overlay_modifier.h"
19 #include "core/components_ng/render/divider_painter.h"
20
21 namespace OHOS::Ace::NG {
PaintEdgeEffect(PaintWrapper * paintWrapper,RSCanvas & canvas)22 void ListPaintMethod::PaintEdgeEffect(PaintWrapper* paintWrapper, RSCanvas& canvas)
23 {
24 auto edgeEffect = edgeEffect_.Upgrade();
25 CHECK_NULL_VOID(edgeEffect);
26 CHECK_NULL_VOID(paintWrapper);
27 auto frameSize = paintWrapper->GetGeometryNode()->GetFrameSize();
28 edgeEffect->Paint(canvas, frameSize, { 0.0f, 0.0f });
29 }
30
GetForegroundDrawFunction(PaintWrapper * paintWrapper)31 CanvasDrawFunction ListPaintMethod::GetForegroundDrawFunction(PaintWrapper* paintWrapper)
32 {
33 auto paintFunc = [weak = WeakClaim(this), paintWrapper](RSCanvas& canvas) {
34 auto painter = weak.Upgrade();
35 CHECK_NULL_VOID(painter);
36 painter->PaintEdgeEffect(paintWrapper, canvas);
37 };
38 return paintFunc;
39 }
40
UpdateContentModifier(PaintWrapper * paintWrapper)41 void ListPaintMethod::UpdateContentModifier(PaintWrapper* paintWrapper)
42 {
43 CHECK_NULL_VOID(listContentModifier_);
44 const auto& geometryNode = paintWrapper->GetGeometryNode();
45 OffsetF paddingOffset = geometryNode->GetPaddingOffset() - geometryNode->GetFrameOffset();
46 auto renderContext = paintWrapper->GetRenderContext();
47 CHECK_NULL_VOID(renderContext);
48 auto frameSize = renderContext->GetPaintRectWithoutTransform().GetSize();
49 auto& padding = geometryNode->GetPadding();
50 if (padding) {
51 frameSize.MinusPadding(*padding->left, *padding->right, *padding->top, *padding->bottom);
52 }
53 bool hasPadding = padding && padding->HasValue();
54 bool clip = hasPadding && (!renderContext || renderContext->GetClipEdge().value_or(true));
55 listContentModifier_->SetClipOffset(paddingOffset);
56 listContentModifier_->SetClipSize(frameSize);
57 listContentModifier_->SetClip(clip);
58 float contentSize = vertical_ ? frameSize.Width() : frameSize.Height();
59 if (!divider_.strokeWidth.IsValid() || totalItemCount_ <= 0 ||
60 divider_.strokeWidth.Unit() == DimensionUnit::PERCENT ||
61 GreatOrEqual(divider_.strokeWidth.ConvertToPx(), contentSize)) {
62 ListDividerMap dividerMap;
63 listContentModifier_->SetDividerMap(std::move(dividerMap));
64 return;
65 }
66 Axis axis = vertical_ ? Axis::HORIZONTAL : Axis::VERTICAL;
67 DividerInfo dividerInfo = {
68 .constrainStrokeWidth = divider_.strokeWidth.ConvertToPx(),
69 .mainSize = vertical_ ? frameSize.Width() : frameSize.Height(),
70 .crossSize = vertical_ ? frameSize.Height() : frameSize.Width(),
71 .mainPadding = paddingOffset.GetMainOffset(axis),
72 .crossPadding = paddingOffset.GetCrossOffset(axis),
73 .startMargin = std::max(0.0, divider_.startMargin.ConvertToPx()),
74 .endMargin = std::max(0.0, divider_.endMargin.ConvertToPx()),
75 .space = space_,
76 .laneGutter = laneGutter_,
77 .lanes = lanes_ > 1 ? lanes_ : 1,
78 .totalItemCount = totalItemCount_,
79 .color = divider_.color,
80 .isVertical = vertical_
81 };
82 float checkMargin = dividerInfo.crossSize / dividerInfo.lanes - dividerInfo.startMargin - dividerInfo.endMargin;
83 if (NearZero(checkMargin)) return;
84 if (LessNotEqual(checkMargin, 0.0f)) {
85 dividerInfo.startMargin = 0.0f;
86 dividerInfo.endMargin = 0.0f;
87 }
88 UpdateDividerList(dividerInfo);
89 }
90
UpdateDividerList(const DividerInfo & dividerInfo)91 void ListPaintMethod::UpdateDividerList(const DividerInfo& dividerInfo)
92 {
93 listContentModifier_->SetDividerPainter(
94 dividerInfo.constrainStrokeWidth, dividerInfo.isVertical, dividerInfo.color);
95 int32_t lanes = dividerInfo.lanes;
96 int32_t laneIdx = 0;
97 bool lastIsItemGroup = false;
98 bool isFirstItem = (itemPosition_.begin()->first == 0);
99 std::map<int32_t, int32_t> lastLineIndex;
100 ListDividerMap dividerMap;
101 bool nextIsPressed = false;
102 for (const auto& child : itemPosition_) {
103 auto nextId = child.first - lanes;
104 nextIsPressed = nextId < 0 || lastIsItemGroup || child.second.isGroup ?
105 false : itemPosition_[nextId].isPressed;
106 if (!isFirstItem && !(child.second.isPressed || nextIsPressed)) {
107 dividerMap[child.second.id] = HandleDividerList(child.first, lastIsItemGroup, laneIdx, dividerInfo);
108 }
109 if (laneIdx == 0 || child.second.isGroup) {
110 lastLineIndex.clear();
111 }
112 lastLineIndex[child.first] = child.second.id;
113 lastIsItemGroup = child.second.isGroup;
114 laneIdx = (lanes <= 1 || (laneIdx + 1) >= lanes || child.second.isGroup) ? 0 : laneIdx + 1;
115 isFirstItem = isFirstItem ? laneIdx > 0 : false;
116 }
117 if (!lastLineIndex.empty() && lastLineIndex.rbegin()->first < dividerInfo.totalItemCount - 1) {
118 int32_t laneIdx = 0;
119 for (auto index : lastLineIndex) {
120 if (index.first + lanes >= dividerInfo.totalItemCount) {
121 break;
122 }
123 if (!itemPosition_.at(index.first).isPressed) {
124 dividerMap[-index.second] = HandleLastLineIndex(index.first, laneIdx, dividerInfo);
125 }
126 laneIdx++;
127 }
128 }
129 listContentModifier_->SetDividerMap(std::move(dividerMap));
130 }
131
HandleDividerList(int32_t index,bool lastIsGroup,int32_t laneIdx,const DividerInfo & dividerInfo)132 ListDivider ListPaintMethod::HandleDividerList(
133 int32_t index, bool lastIsGroup, int32_t laneIdx, const DividerInfo& dividerInfo)
134 {
135 ListDivider divider;
136 bool laneIdxValid = dividerInfo.lanes > 1 && !lastIsGroup && !itemPosition_.at(index).isGroup;
137 float avgCrossSize = (dividerInfo.crossSize + dividerInfo.laneGutter) / dividerInfo.lanes - dividerInfo.laneGutter;
138 float dividerLen = laneIdxValid ? avgCrossSize : dividerInfo.crossSize;
139 dividerLen = dividerLen - dividerInfo.startMargin - dividerInfo.endMargin;
140 float mainPos = dividerInfo.mainPadding + itemPosition_.at(index).startPos -
141 (dividerInfo.space + dividerInfo.constrainStrokeWidth) / 2; /* 2 half */
142 float crossPos = dividerInfo.startMargin + dividerInfo.crossPadding;
143 if (isRTL_ && dividerInfo.isVertical) {
144 mainPos = dividerInfo.mainPadding + dividerInfo.mainSize - itemPosition_.at(index).startPos +
145 (dividerInfo.space - dividerInfo.constrainStrokeWidth) / 2; /* 2 half */
146 crossPos += (int)laneIdxValid * laneIdx * (avgCrossSize + dividerInfo.laneGutter);
147 } else if (isRTL_ && !dividerInfo.isVertical) {
148 crossPos = dividerInfo.crossPadding + dividerInfo.crossSize - dividerInfo.startMargin - dividerLen;
149 crossPos -= (int)laneIdxValid * laneIdx * (avgCrossSize + dividerInfo.laneGutter);
150 } else {
151 crossPos += (int)laneIdxValid * laneIdx * (avgCrossSize + dividerInfo.laneGutter);
152 }
153 divider.length = dividerLen;
154 divider.offset = dividerInfo.isVertical ?
155 OffsetF(mainPos, crossPos) : OffsetF(crossPos, mainPos);
156 return divider;
157 }
158
HandleLastLineIndex(int32_t index,int32_t laneIdx,const DividerInfo & dividerInfo)159 ListDivider ListPaintMethod::HandleLastLineIndex(int32_t index, int32_t laneIdx, const DividerInfo& dividerInfo)
160 {
161 ListDivider divider;
162 bool laneIdxValid = dividerInfo.lanes > 1 && !itemPosition_.at(index).isGroup;
163 float avgCrossSize = (dividerInfo.crossSize + dividerInfo.laneGutter) / dividerInfo.lanes - dividerInfo.laneGutter;
164 float dividerLen = laneIdxValid ? avgCrossSize : dividerInfo.crossSize;
165 dividerLen = dividerLen - dividerInfo.startMargin - dividerInfo.endMargin;
166 float mainPos = dividerInfo.mainPadding + itemPosition_.at(index).endPos +
167 (dividerInfo.space - dividerInfo.constrainStrokeWidth) / 2; /* 2 half */
168 float crossPos = dividerInfo.startMargin + dividerInfo.crossPadding;
169 if (isRTL_ && dividerInfo.isVertical) {
170 mainPos = dividerInfo.mainPadding + dividerInfo.mainSize - itemPosition_.at(index).endPos -
171 (dividerInfo.space + dividerInfo.constrainStrokeWidth) / 2; /* 2 half */
172 crossPos += (int)laneIdxValid * laneIdx * (avgCrossSize + dividerInfo.laneGutter);
173 } else if (isRTL_ && !dividerInfo.isVertical) {
174 crossPos = dividerInfo.crossPadding + dividerInfo.crossSize - dividerInfo.startMargin - dividerLen;
175 crossPos -= (int)laneIdxValid * laneIdx * (avgCrossSize + dividerInfo.laneGutter);
176 } else {
177 crossPos += (int)laneIdxValid * laneIdx * (avgCrossSize + dividerInfo.laneGutter);
178 }
179 divider.length = dividerLen;
180 divider.offset = dividerInfo.isVertical ?
181 OffsetF(mainPos, crossPos) : OffsetF(crossPos, mainPos);
182 return divider;
183 }
184
UpdateOverlayModifier(PaintWrapper * paintWrapper)185 void ListPaintMethod::UpdateOverlayModifier(PaintWrapper* paintWrapper)
186 {
187 CHECK_NULL_VOID(paintWrapper);
188 auto scrollBarOverlayModifier = scrollBarOverlayModifier_.Upgrade();
189 CHECK_NULL_VOID(scrollBarOverlayModifier);
190 auto scrollBar = scrollBar_.Upgrade();
191 CHECK_NULL_VOID(scrollBar);
192 if (scrollBar->GetPositionModeUpdate()) {
193 scrollBarOverlayModifier->SetPositionMode(scrollBar->GetPositionMode());
194 }
195 OffsetF fgOffset(scrollBar->GetActiveRect().Left(), scrollBar->GetActiveRect().Top());
196 scrollBarOverlayModifier->StartBarAnimation(scrollBar->GetHoverAnimationType(),
197 scrollBar->GetOpacityAnimationType(), scrollBar->GetNeedAdaptAnimation(), scrollBar->GetActiveRect());
198 scrollBar->SetHoverAnimationType(HoverAnimationType::NONE);
199 scrollBarOverlayModifier->SetBarColor(scrollBar->GetForegroundColor());
200 scrollBar->SetOpacityAnimationType(OpacityAnimationType::NONE);
201 }
202 } // namespace OHOS::Ace::NG
203