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 UpdateFadingGradient(renderContext);
54
55 if (TryContentClip(paintWrapper)) {
56 listContentModifier_->SetClip(false);
57 } else {
58 const bool hasPadding = padding && padding->HasValue();
59 bool clip = hasPadding && (!renderContext || renderContext->GetClipEdge().value_or(true));
60 listContentModifier_->SetClipOffset(paddingOffset);
61 listContentModifier_->SetClipSize(frameSize);
62 listContentModifier_->SetClip(clip);
63 }
64
65 float contentSize = vertical_ ? frameSize.Width() : frameSize.Height();
66 if (!divider_.strokeWidth.IsValid() || totalItemCount_ <= 0 ||
67 divider_.strokeWidth.Unit() == DimensionUnit::PERCENT ||
68 GreatOrEqual(divider_.strokeWidth.ConvertToPx(), contentSize)) {
69 ListDividerMap dividerMap;
70 listContentModifier_->SetDividerMap(std::move(dividerMap));
71 return;
72 }
73 Axis axis = vertical_ ? Axis::HORIZONTAL : Axis::VERTICAL;
74 DividerInfo dividerInfo = {
75 .constrainStrokeWidth = divider_.strokeWidth.ConvertToPx(),
76 .mainSize = vertical_ ? frameSize.Width() : frameSize.Height(),
77 .crossSize = vertical_ ? frameSize.Height() : frameSize.Width(),
78 .mainPadding = paddingOffset.GetMainOffset(axis),
79 .crossPadding = paddingOffset.GetCrossOffset(axis),
80 .startMargin = std::max(0.0, divider_.startMargin.ConvertToPx()),
81 .endMargin = std::max(0.0, divider_.endMargin.ConvertToPx()),
82 .space = space_,
83 .laneGutter = laneGutter_,
84 .lanes = lanes_ > 1 ? lanes_ : 1,
85 .totalItemCount = totalItemCount_,
86 .color = divider_.color,
87 .isVertical = vertical_
88 };
89 float checkMargin = dividerInfo.crossSize / dividerInfo.lanes - dividerInfo.startMargin - dividerInfo.endMargin;
90 if (NearZero(checkMargin)) return;
91 if (LessNotEqual(checkMargin, 0.0f)) {
92 dividerInfo.startMargin = 0.0f;
93 dividerInfo.endMargin = 0.0f;
94 }
95 UpdateDividerList(dividerInfo);
96 }
97
UpdateDividerList(const DividerInfo & dividerInfo)98 void ListPaintMethod::UpdateDividerList(const DividerInfo& dividerInfo)
99 {
100 listContentModifier_->SetDividerPainter(
101 dividerInfo.constrainStrokeWidth, dividerInfo.isVertical, dividerInfo.color);
102 int32_t lanes = dividerInfo.lanes;
103 int32_t laneIdx = 0;
104 bool lastIsItemGroup = false;
105 bool isFirstItem = (itemPosition_.begin()->first == 0);
106 std::map<int32_t, int32_t> lastLineIndex;
107 ListDividerMap dividerMap;
108 bool nextIsPressed = false;
109 for (const auto& child : itemPosition_) {
110 auto nextId = child.first - lanes;
111 nextIsPressed = nextId < 0 || lastIsItemGroup || child.second.isGroup ?
112 false : itemPosition_[nextId].isPressed;
113 if (!isFirstItem && !(child.second.isPressed || nextIsPressed)) {
114 dividerMap[child.second.id] = HandleDividerList(child.first, lastIsItemGroup, laneIdx, dividerInfo);
115 }
116 if (laneIdx == 0 || child.second.isGroup) {
117 lastLineIndex.clear();
118 }
119 lastLineIndex[child.first] = child.second.id;
120 lastIsItemGroup = child.second.isGroup;
121 laneIdx = (lanes <= 1 || (laneIdx + 1) >= lanes || child.second.isGroup) ? 0 : laneIdx + 1;
122 isFirstItem = isFirstItem ? laneIdx > 0 : false;
123 }
124 if (!lastLineIndex.empty() && lastLineIndex.rbegin()->first < dividerInfo.totalItemCount - 1) {
125 int32_t laneIdx = 0;
126 for (auto index : lastLineIndex) {
127 if (index.first + lanes >= dividerInfo.totalItemCount) {
128 break;
129 }
130 if (!itemPosition_.at(index.first).isPressed) {
131 dividerMap[-index.second] = HandleLastLineIndex(index.first, laneIdx, dividerInfo);
132 }
133 laneIdx++;
134 }
135 }
136 listContentModifier_->SetDividerMap(std::move(dividerMap));
137 }
138
HandleDividerList(int32_t index,bool lastIsGroup,int32_t laneIdx,const DividerInfo & dividerInfo)139 ListDivider ListPaintMethod::HandleDividerList(
140 int32_t index, bool lastIsGroup, int32_t laneIdx, const DividerInfo& dividerInfo)
141 {
142 ListDivider divider;
143 bool laneIdxValid = dividerInfo.lanes > 1 && !lastIsGroup && !itemPosition_.at(index).isGroup;
144 float avgCrossSize = (dividerInfo.crossSize + dividerInfo.laneGutter) / dividerInfo.lanes - dividerInfo.laneGutter;
145 float dividerLen = laneIdxValid ? avgCrossSize : dividerInfo.crossSize;
146 dividerLen = dividerLen - dividerInfo.startMargin - dividerInfo.endMargin;
147 float mainPos = dividerInfo.mainPadding + itemPosition_.at(index).startPos -
148 (dividerInfo.space + dividerInfo.constrainStrokeWidth) / 2; /* 2 half */
149 float crossPos = dividerInfo.startMargin + dividerInfo.crossPadding;
150 if (isRTL_ && dividerInfo.isVertical) {
151 mainPos = dividerInfo.mainPadding + dividerInfo.mainSize - itemPosition_.at(index).startPos +
152 (dividerInfo.space - dividerInfo.constrainStrokeWidth) / 2; /* 2 half */
153 crossPos += (int)laneIdxValid * laneIdx * (avgCrossSize + dividerInfo.laneGutter);
154 } else if (isRTL_ && !dividerInfo.isVertical) {
155 crossPos = dividerInfo.crossPadding + dividerInfo.crossSize - dividerInfo.startMargin - dividerLen;
156 crossPos -= (int)laneIdxValid * laneIdx * (avgCrossSize + dividerInfo.laneGutter);
157 } else {
158 crossPos += (int)laneIdxValid * laneIdx * (avgCrossSize + dividerInfo.laneGutter);
159 }
160 divider.length = dividerLen;
161 divider.offset = dividerInfo.isVertical ?
162 OffsetF(mainPos, crossPos) : OffsetF(crossPos, mainPos);
163 return divider;
164 }
165
HandleLastLineIndex(int32_t index,int32_t laneIdx,const DividerInfo & dividerInfo)166 ListDivider ListPaintMethod::HandleLastLineIndex(int32_t index, int32_t laneIdx, const DividerInfo& dividerInfo)
167 {
168 ListDivider divider;
169 bool laneIdxValid = dividerInfo.lanes > 1 && !itemPosition_.at(index).isGroup;
170 float avgCrossSize = (dividerInfo.crossSize + dividerInfo.laneGutter) / dividerInfo.lanes - dividerInfo.laneGutter;
171 float dividerLen = laneIdxValid ? avgCrossSize : dividerInfo.crossSize;
172 dividerLen = dividerLen - dividerInfo.startMargin - dividerInfo.endMargin;
173 float mainPos = dividerInfo.mainPadding + itemPosition_.at(index).endPos +
174 (dividerInfo.space - dividerInfo.constrainStrokeWidth) / 2; /* 2 half */
175 float crossPos = dividerInfo.startMargin + dividerInfo.crossPadding;
176 if (isRTL_ && dividerInfo.isVertical) {
177 mainPos = dividerInfo.mainPadding + dividerInfo.mainSize - itemPosition_.at(index).endPos -
178 (dividerInfo.space + dividerInfo.constrainStrokeWidth) / 2; /* 2 half */
179 crossPos += (int)laneIdxValid * laneIdx * (avgCrossSize + dividerInfo.laneGutter);
180 } else if (isRTL_ && !dividerInfo.isVertical) {
181 crossPos = dividerInfo.crossPadding + dividerInfo.crossSize - dividerInfo.startMargin - dividerLen;
182 crossPos -= (int)laneIdxValid * laneIdx * (avgCrossSize + dividerInfo.laneGutter);
183 } else {
184 crossPos += (int)laneIdxValid * laneIdx * (avgCrossSize + dividerInfo.laneGutter);
185 }
186 divider.length = dividerLen;
187 divider.offset = dividerInfo.isVertical ?
188 OffsetF(mainPos, crossPos) : OffsetF(crossPos, mainPos);
189 return divider;
190 }
191
UpdateOverlayModifier(PaintWrapper * paintWrapper)192 void ListPaintMethod::UpdateOverlayModifier(PaintWrapper* paintWrapper)
193 {
194 CHECK_NULL_VOID(paintWrapper);
195 auto scrollBarOverlayModifier = scrollBarOverlayModifier_.Upgrade();
196 CHECK_NULL_VOID(scrollBarOverlayModifier);
197 auto scrollBar = scrollBar_.Upgrade();
198 CHECK_NULL_VOID(scrollBar);
199 if (scrollBar->GetPositionModeUpdate()) {
200 scrollBarOverlayModifier->SetPositionMode(scrollBar->GetPositionMode());
201 }
202 OffsetF fgOffset(scrollBar->GetActiveRect().Left(), scrollBar->GetActiveRect().Top());
203 scrollBarOverlayModifier->StartBarAnimation(scrollBar->GetHoverAnimationType(),
204 scrollBar->GetOpacityAnimationType(), scrollBar->GetNeedAdaptAnimation(), scrollBar->GetActiveRect());
205 scrollBar->SetHoverAnimationType(HoverAnimationType::NONE);
206 scrollBarOverlayModifier->SetBarColor(scrollBar->GetForegroundColor());
207 scrollBar->SetOpacityAnimationType(OpacityAnimationType::NONE);
208 }
209 } // namespace OHOS::Ace::NG
210