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_item_group_paint_method.h"
17
18 namespace OHOS::Ace::NG {
PaintDivider(PaintWrapper * paintWrapper,RSCanvas & canvas)19 void ListItemGroupPaintMethod::PaintDivider(PaintWrapper* paintWrapper, RSCanvas& canvas)
20 {
21 if (!divider_.strokeWidth.IsValid() || divider_.strokeWidth.Unit() == DimensionUnit::PERCENT) {
22 return;
23 }
24 const auto& geometryNode = paintWrapper->GetGeometryNode();
25 auto frameSize = geometryNode->GetPaddingSize();
26 OffsetF paddingOffset = geometryNode->GetPaddingOffset() - geometryNode->GetFrameOffset();
27 Axis axis = vertical_ ? Axis::HORIZONTAL : Axis::VERTICAL;
28 DividerGroupInfo info = {
29 .lanes = lanes_ > 1 ? lanes_ : 1,
30 .crossSize = frameSize.CrossSize(axis),
31 .mainPadding = paddingOffset.GetMainOffset(axis),
32 .crossPadding = paddingOffset.GetCrossOffset(axis),
33 .constrainStrokeWidth = divider_.strokeWidth.ConvertToPx(),
34 .halfSpaceWidth = (spaceWidth_ + divider_.strokeWidth.ConvertToPx()) / 2.0f, /* 2.0f half */
35 .startMargin = std::max(0.0, divider_.startMargin.ConvertToPx()),
36 .endMargin = std::max(0.0, divider_.endMargin.ConvertToPx())
37 };
38 fSpacingTotal_ = (info.lanes - 1) * laneGutter_;
39 float laneLen = (info.crossSize - fSpacingTotal_) / info.lanes -
40 info.startMargin - info.endMargin;
41 if (NearZero(laneLen)) return;
42 if (LessNotEqual(laneLen, 0.0f)) {
43 info.startMargin = 0.0f;
44 info.endMargin = 0.0f;
45 laneLen = (info.crossSize - fSpacingTotal_) / info.lanes -
46 info.startMargin - info.endMargin;
47 }
48 DividerPainter dividerPainter(
49 info.constrainStrokeWidth, laneLen, vertical_, divider_.color, LineCap::SQUARE);
50 UpdateDividerList(info, dividerPainter, canvas);
51 }
52
UpdateDividerList(const DividerGroupInfo & info,const DividerPainter & dividerPainter,RSCanvas & canvas)53 void ListItemGroupPaintMethod::UpdateDividerList(const DividerGroupInfo& info,
54 const DividerPainter& dividerPainter, RSCanvas& canvas)
55 {
56 int32_t laneIdx = 0;
57 bool isFirstItem = (itemPosition_.begin()->first == 0);
58 std::list<int32_t> lastLineIndex;
59 bool nextIsPressed = false;
60 for (const auto& child : itemPosition_) {
61 auto nextId = child.first - info.lanes;
62 nextIsPressed = nextId < 0 ? child.second.isPressed : itemPosition_[nextId].isPressed;
63 if (!isFirstItem && !(child.second.isPressed || nextIsPressed)) {
64 DrawDivider(child.first, laneIdx, info, dividerPainter, canvas);
65 }
66 if (laneIdx == 0) {
67 lastLineIndex.clear();
68 }
69 lastLineIndex.emplace_back(child.first);
70 laneIdx = (laneIdx + 1) >= info.lanes ? 0 : laneIdx + 1;
71 isFirstItem = isFirstItem ? laneIdx > 0 : false;
72 }
73 if (!lastLineIndex.empty() && *lastLineIndex.rbegin() < totalItemCount_ - 1) {
74 int32_t laneIdx = 0;
75 for (auto index : lastLineIndex) {
76 if (index + info.lanes >= totalItemCount_) {
77 break;
78 }
79 if (!itemPosition_.at(index).isPressed) {
80 DrawLastLineDivider(index, laneIdx, info, dividerPainter, canvas);
81 }
82 laneIdx++;
83 }
84 }
85 }
86
DrawDivider(int32_t index,int32_t laneIdx,const DividerGroupInfo & info,const DividerPainter & dividerPainter,RSCanvas & canvas)87 void ListItemGroupPaintMethod::DrawDivider(int32_t index, int32_t laneIdx, const DividerGroupInfo& info,
88 const DividerPainter& dividerPainter, RSCanvas& canvas)
89 {
90 float mainPos = info.mainPadding + itemPosition_.at(index).startPos - info.halfSpaceWidth;
91 float crossPos = info.startMargin + info.crossPadding +
92 laneIdx * ((info.crossSize - fSpacingTotal_) / info.lanes + laneGutter_);
93 if (layoutDirection_ == TextDirection::RTL && vertical_) {
94 mainPos = info.mainPadding + mainSize_ - itemPosition_.at(index).startPos +
95 info.halfSpaceWidth - info.constrainStrokeWidth;
96 } else if (layoutDirection_ == TextDirection::RTL && !vertical_) {
97 float dividerLen = (info.crossSize - fSpacingTotal_) / info.lanes - info.startMargin - info.endMargin;
98 crossPos = info.crossPadding + info.crossSize - info.startMargin - dividerLen -
99 laneIdx * ((info.crossSize - fSpacingTotal_) / info.lanes + laneGutter_);
100 }
101 OffsetF offset = vertical_ ? OffsetF(mainPos, crossPos) : OffsetF(crossPos, mainPos);
102 dividerPainter.DrawLine(canvas, offset);
103 }
104
DrawLastLineDivider(int32_t index,int32_t laneIdx,const DividerGroupInfo & info,const DividerPainter & dividerPainter,RSCanvas & canvas)105 void ListItemGroupPaintMethod::DrawLastLineDivider(int32_t index, int32_t laneIdx, const DividerGroupInfo& info,
106 const DividerPainter& dividerPainter, RSCanvas& canvas)
107 {
108 float mainPos = info.mainPadding + itemPosition_.at(index).endPos + spaceWidth_ - info.halfSpaceWidth;
109 float crossPos = info.startMargin + info.crossPadding +
110 laneIdx * ((info.crossSize - fSpacingTotal_) / info.lanes + laneGutter_);
111 if (layoutDirection_ == TextDirection::RTL && vertical_) {
112 mainPos = info.mainPadding + mainSize_ - itemPosition_.at(index).endPos - info.halfSpaceWidth;
113 } else if (layoutDirection_ == TextDirection::RTL && !vertical_) {
114 float dividerLen = (info.crossSize - fSpacingTotal_) / info.lanes - info.startMargin - info.endMargin;
115 crossPos = info.crossPadding + info.crossSize - info.startMargin - dividerLen -
116 laneIdx * ((info.crossSize - fSpacingTotal_) / info.lanes + laneGutter_);
117 }
118 OffsetF offset = vertical_ ? OffsetF(mainPos, crossPos) : OffsetF(crossPos, mainPos);
119 dividerPainter.DrawLine(canvas, offset);
120 }
121
GetContentDrawFunction(PaintWrapper * paintWrapper)122 CanvasDrawFunction ListItemGroupPaintMethod::GetContentDrawFunction(PaintWrapper* paintWrapper)
123 {
124 auto paintFunc = [weak = WeakClaim(this), paintWrapper](RSCanvas& canvas) {
125 auto painter = weak.Upgrade();
126 CHECK_NULL_VOID(painter);
127 painter->PaintDivider(paintWrapper, canvas);
128 };
129 return paintFunc;
130 }
131 } // namespace OHOS::Ace::NG