1 /*
2 * Copyright (c) 2022-2024 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/text_picker/textpicker_paint_method.h"
17
18 #include "core/components/common/properties/color.h"
19 #include "core/components/picker/picker_theme.h"
20 #include "core/components_ng/pattern/text_picker/textpicker_layout_property.h"
21 #include "core/components_ng/pattern/text_picker/textpicker_pattern.h"
22 #include "core/components_ng/render/drawing.h"
23 #include "core/components_ng/render/drawing_prop_convertor.h"
24 #include "core/pipeline_ng/pipeline_context.h"
25
26 namespace OHOS::Ace::NG {
27
28 namespace {
29 constexpr uint8_t DOUBLE = 2;
30 const Dimension PICKER_DIALOG_DIVIDER_MARGIN = 24.0_vp;
31 } // namespace
32
GetForegroundDrawFunction(PaintWrapper * paintWrapper)33 CanvasDrawFunction TextPickerPaintMethod::GetForegroundDrawFunction(PaintWrapper* paintWrapper)
34 {
35 const auto& geometryNode = paintWrapper->GetGeometryNode();
36 CHECK_NULL_RETURN(geometryNode, nullptr);
37 auto frameRect = geometryNode->GetFrameRect();
38
39 auto renderContext = paintWrapper->GetRenderContext();
40 CHECK_NULL_RETURN(renderContext, nullptr);
41 auto pickerNode = renderContext->GetHost();
42 CHECK_NULL_RETURN(pickerNode, nullptr);
43 auto layoutProperty = pickerNode->GetLayoutProperty<TextPickerLayoutProperty>();
44 CHECK_NULL_RETURN(layoutProperty, nullptr);
45
46 auto textPickerPattern = pickerNode->GetPattern<TextPickerPattern>();
47 CHECK_NULL_RETURN(textPickerPattern, nullptr);
48 auto fontScale = textPickerPattern->GetPaintDividerSpacing();
49
50 return
51 [weak = WeakClaim(this), layoutProperty, frameRect,
52 fontScale, pattern = pattern_](RSCanvas& canvas) {
53 auto picker = weak.Upgrade();
54 CHECK_NULL_VOID(picker);
55 auto textPickerPattern = DynamicCast<TextPickerPattern>(pattern.Upgrade());
56 CHECK_NULL_VOID(textPickerPattern);
57
58 PaddingPropertyF padding = layoutProperty->CreatePaddingAndBorder();
59 RectF contentRect = { padding.left.value_or(0), padding.top.value_or(0),
60 frameRect.Width() - padding.Width(), frameRect.Height() - padding.Height() };
61
62 double dividerHeight = picker->defaultPickerItemHeight_ * fontScale;
63 if (textPickerPattern->GetResizeFlag()) {
64 dividerHeight = textPickerPattern->GetResizePickerItemHeight() * fontScale;
65 }
66
67 if (contentRect.Width() >= 0.0f && (contentRect.Height() >= dividerHeight)) {
68 if (textPickerPattern->GetCustomDividerFlag()) {
69 auto divider = textPickerPattern->GetDivider();
70 auto textDirection = layoutProperty->GetNonAutoLayoutDirection();
71 divider.isRtl = (textDirection == TextDirection::RTL) ? true : false;
72 picker->PaintCustomDividerLines(canvas, contentRect, frameRect, divider, dividerHeight);
73 } else {
74 picker->PaintDefaultDividerLines(canvas, contentRect, dividerHeight);
75 }
76 }
77 };
78 }
79
PaintCustomDividerLines(RSCanvas & canvas,const RectF & contentRect,const RectF & frameRect,const ItemDivider & divider,double dividerHeight)80 void TextPickerPaintMethod::PaintCustomDividerLines(RSCanvas& canvas, const RectF &contentRect, const RectF &frameRect,
81 const ItemDivider ÷r, double dividerHeight)
82 {
83 DividerInfo info;
84 if (NeedPaintDividerLines(contentRect, divider, dividerHeight, info)) {
85 PaintDividerLines(canvas, contentRect, info, false);
86 }
87 }
88
PaintDefaultDividerLines(RSCanvas & canvas,const RectF & contentRect,double dividerHeight)89 void TextPickerPaintMethod::PaintDefaultDividerLines(RSCanvas& canvas, const RectF &contentRect,
90 double dividerHeight)
91 {
92 auto pipeline = PipelineContext::GetCurrentContext();
93 CHECK_NULL_VOID(pipeline);
94 auto theme = pipeline->GetTheme<PickerTheme>();
95 auto dividerColor = theme->GetDividerColor();
96 auto dividerLineWidth = theme->GetDividerThickness().ConvertToPx();
97
98 auto dividerLength = contentRect.Width();
99 auto dividerMargin = contentRect.GetX();
100 auto textPickerPattern = DynamicCast<TextPickerPattern>(pattern_.Upgrade());
101 CHECK_NULL_VOID(textPickerPattern);
102 if (textPickerPattern->GetIsShowInDialog()) {
103 dividerLength -= PICKER_DIALOG_DIVIDER_MARGIN.ConvertToPx() * DOUBLE;
104 dividerMargin += PICKER_DIALOG_DIVIDER_MARGIN.ConvertToPx();
105 }
106
107 DividerInfo info;
108 info.dividerColor = dividerColor;
109 info.dividerWidth = dividerLineWidth;
110 info.dividerLength = dividerLength;
111 info.dividerMargin = dividerMargin;
112 info.dividerHeight = dividerHeight;
113 PaintDividerLines(canvas, contentRect, info);
114 }
115
SetStrokeWidth(const ItemDivider & divider,double dividerHeight,DividerInfo & info)116 bool TextPickerPaintMethod::SetStrokeWidth(const ItemDivider ÷r, double dividerHeight, DividerInfo& info)
117 {
118 if (divider.strokeWidth.ConvertToPx() > dividerHeight / DOUBLE) {
119 auto pipeline = PipelineContext::GetCurrentContext();
120 if (!pipeline) {
121 return false;
122 }
123 auto theme = pipeline->GetTheme<PickerTheme>();
124 if (theme) {
125 info.dividerWidth = theme->GetDividerThickness().ConvertToPx();
126 } else {
127 info.dividerWidth = 0.0f;
128 }
129 } else {
130 info.dividerWidth = divider.strokeWidth.ConvertToPx();
131 }
132
133 if (info.dividerWidth <= 0.0f) {
134 return false;
135 }
136 return true;
137 }
138
NeedPaintDividerLines(const RectF & contentRect,const ItemDivider & divider,double dividerHeight,DividerInfo & info)139 bool TextPickerPaintMethod::NeedPaintDividerLines(const RectF &contentRect, const ItemDivider ÷r,
140 double dividerHeight, DividerInfo& info)
141 {
142 if (!SetStrokeWidth(divider, dividerHeight, info)) {
143 return false;
144 }
145 info.dividerHeight = dividerHeight;
146 info.startMargin = std::max(0.0, divider.startMargin.ConvertToPx());
147 info.endMargin = std::max(0.0, divider.endMargin.ConvertToPx());
148 info.dividerColor = divider.color;
149
150 auto dividerLength = contentRect.Width();
151 auto dividerMargin = contentRect.GetX();
152 auto textPickerPattern = DynamicCast<TextPickerPattern>(pattern_.Upgrade());
153 if (!textPickerPattern) {
154 return false;
155 }
156 if (textPickerPattern->GetIsShowInDialog()) {
157 dividerLength -= PICKER_DIALOG_DIVIDER_MARGIN.ConvertToPx() * DOUBLE;
158 dividerMargin += PICKER_DIALOG_DIVIDER_MARGIN.ConvertToPx();
159 }
160
161 float checkMargin = dividerLength - info.startMargin - info.endMargin;
162 if (NearZero(checkMargin)) {
163 return false;
164 }
165 if (LessNotEqual(checkMargin, 0.0f)) {
166 LOGE("StartMagin and endMargin are set to 0, because the parameters are wrong");
167 info.startMargin = 0.0f;
168 info.endMargin = 0.0f;
169 }
170 if (divider.isRtl) {
171 dividerMargin += info.endMargin;
172 } else {
173 dividerMargin += info.startMargin;
174 }
175 dividerLength = dividerLength - info.startMargin - info.endMargin;
176 info.dividerMargin = dividerMargin;
177 info.dividerLength = dividerLength;
178 return true;
179 }
180
PaintDividerLines(RSCanvas & canvas,const RectF & contentRect,const DividerInfo & info,bool isDefaultLine)181 void TextPickerPaintMethod::PaintDividerLines(RSCanvas& canvas, const RectF& contentRect, const DividerInfo &info,
182 bool isDefaultLine)
183 {
184 double upperLine = 0.0f;
185 double downLine = 0.0f;
186 if (isDefaultLine) {
187 upperLine = (contentRect.Height() - info.dividerHeight) / DOUBLE + contentRect.GetY();
188 downLine = (contentRect.Height() + info.dividerHeight) / DOUBLE + contentRect.GetY();
189 } else {
190 upperLine = (contentRect.Height() - info.dividerHeight - info.dividerWidth) / DOUBLE + contentRect.GetY();
191 downLine = (contentRect.Height() + info.dividerHeight - info.dividerWidth) / DOUBLE + contentRect.GetY();
192 }
193 OffsetF offset = OffsetF(info.dividerMargin, upperLine);
194 PaintLine(offset, info, canvas);
195 OffsetF offsetY = OffsetF(info.dividerMargin, downLine);
196 PaintLine(offsetY, info, canvas);
197 }
198
PaintLine(const OffsetF & offset,const DividerInfo & info,RSCanvas & canvas)199 void TextPickerPaintMethod::PaintLine(const OffsetF& offset, const DividerInfo &info, RSCanvas& canvas)
200 {
201 canvas.Save();
202 RSBrush brush;
203 brush.SetColor(info.dividerColor.GetValue());
204 canvas.AttachBrush(brush);
205
206 auto startPointX = offset.GetX();
207 auto startPointY = offset.GetY();
208 auto endPointX = offset.GetX() + info.dividerLength;
209 auto endPointY = offset.GetY() + info.dividerWidth;
210
211 canvas.DrawRect(RSRect(startPointX, startPointY, endPointX, endPointY));
212 canvas.DetachBrush();
213 canvas.Restore();
214 }
215
216 } // namespace OHOS::Ace::NG
217