• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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