• 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 #include "core/components_ng/pattern/checkboxgroup/checkboxgroup_paint_method.h"
16 
17 #include <optional>
18 
19 #include "base/geometry/ng/offset_t.h"
20 #include "base/geometry/ng/rect_t.h"
21 #include "base/geometry/rect.h"
22 #include "base/geometry/rrect.h"
23 #include "base/utils/utils.h"
24 #include "core/components/checkable/checkable_theme.h"
25 #include "core/components/common/properties/alignment.h"
26 #include "core/components/common/properties/color.h"
27 #include "core/components/theme/theme_manager.h"
28 #include "core/components_ng/pattern/checkboxgroup/checkboxgroup_paint_property.h"
29 #include "core/components_ng/pattern/checkboxgroup/checkboxgroup_pattern.h"
30 #include "core/components_ng/render/drawing.h"
31 #include "core/components_ng/render/drawing_prop_convertor.h"
32 
33 namespace OHOS::Ace::NG {
34 namespace {
35 constexpr uint8_t ENABLED_ALPHA = 255;
36 constexpr uint8_t DISABLED_ALPHA = 102;
37 constexpr float CHECK_MARK_START_X_POSITION = 0.25f;
38 constexpr float CHECK_MARK_START_Y_POSITION = 0.49f;
39 constexpr float CHECK_MARK_MIDDLE_X_POSITION = 0.44f;
40 constexpr float CHECK_MARK_MIDDLE_Y_POSITION = 0.68f;
41 constexpr float CHECK_MARK_END_X_POSITION = 0.76f;
42 constexpr float CHECK_MARK_END_Y_POSITION = 0.33f;
43 constexpr float CHECK_MARK_PART_START_X_POSITION = 0.20f;
44 constexpr float CHECK_MARK_PART_END_Y_POSITION = 0.80f;
45 constexpr float CHECK_MARK_PART_Y_POSITION = 0.50f;
46 constexpr float CHECK_MARK_LEFT_ANIMATION_PERCENT = 0.45;
47 constexpr float CHECK_MARK_RIGHT_ANIMATION_PERCENT = 0.55;
48 constexpr float DEFAULT_MAX_CHECKBOX_SHAPE_SCALE = 1.0;
49 constexpr float DEFAULT_MIN_CHECKBOX_SHAPE_SCALE = 0.0;
50 } // namespace
51 
GetContentDrawFunction(PaintWrapper * paintWrapper)52 CanvasDrawFunction CheckBoxGroupPaintMethod::GetContentDrawFunction(PaintWrapper* paintWrapper)
53 {
54     InitializeParam();
55     auto paintFunc = [weak = WeakClaim(this), paintWrapper](RSCanvas& canvas) {
56         auto checkboxgroup = weak.Upgrade();
57         if (checkboxgroup) {
58             checkboxgroup->PaintCheckBox(canvas, paintWrapper);
59         }
60     };
61     return paintFunc;
62 }
63 
InitializeParam()64 void CheckBoxGroupPaintMethod::InitializeParam()
65 {
66     auto pipeline = PipelineContext::GetCurrentContext();
67     CHECK_NULL_VOID(pipeline);
68     auto checkBoxTheme = pipeline->GetTheme<CheckboxTheme>();
69     CHECK_NULL_VOID(checkBoxTheme);
70     borderWidth_ = checkBoxTheme->GetBorderWidth().ConvertToPx();
71     borderRadius_ = checkBoxTheme->GetBorderRadius().ConvertToPx();
72     checkStroke_ = checkBoxTheme->GetCheckStroke().ConvertToPx();
73     pointColor_ = checkBoxTheme->GetPointColor();
74     activeColor_ = checkBoxTheme->GetActiveColor();
75     inactiveColor_ = checkBoxTheme->GetInactiveColor();
76     inactivePointColor_ = checkBoxTheme->GetInactivePointColor();
77     shadowColor_ = checkBoxTheme->GetShadowColor();
78     clickEffectColor_ = checkBoxTheme->GetClickEffectColor();
79     hoverColor_ = checkBoxTheme->GetHoverColor();
80     hoverRadius_ = checkBoxTheme->GetHoverRadius();
81     hotZoneHorizontalPadding_ = checkBoxTheme->GetHotZoneHorizontalPadding();
82     hotZoneVerticalPadding_ = checkBoxTheme->GetHotZoneVerticalPadding();
83     shadowWidth_ = checkBoxTheme->GetShadowWidth();
84 }
85 
PaintCheckBox(RSCanvas & canvas,PaintWrapper * paintWrapper) const86 void CheckBoxGroupPaintMethod::PaintCheckBox(RSCanvas& canvas, PaintWrapper* paintWrapper) const
87 {
88     CHECK_NULL_VOID(paintWrapper);
89     auto paintProperty = DynamicCast<CheckBoxGroupPaintProperty>(paintWrapper->GetPaintProperty());
90     CHECK_NULL_VOID(paintProperty);
91     auto contentSize = paintWrapper->GetContentSize();
92     auto status = paintProperty->GetSelectStatus();
93     auto color = activeColor_;
94     if (paintProperty->HasCheckBoxGroupSelectedColor()) {
95         color = paintProperty->GetCheckBoxGroupSelectedColorValue();
96     }
97     auto paintOffset = paintWrapper->GetContentOffset();
98     RSPen pen;
99     RSBrush brush;
100     pen.SetWidth(borderWidth_);
101     pen.SetAntiAlias(true);
102     if (isTouch_) {
103         LOGI("Touch effect is to be realized here");
104     }
105     if (isHover_) {
106         DrawHoverBoard(canvas, contentSize, paintOffset);
107     }
108     if (status == CheckBoxGroupPaintProperty::SelectStatus::PART) {
109         brush.SetColor(ToRSColor(color));
110         brush.SetAntiAlias(true);
111         pen.SetColor(ToRSColor(pointColor_));
112         if (!enabled_) {
113             brush.SetColor(ToRSColor(color.BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
114         }
115         DrawActiveBorder(canvas, paintOffset, brush, contentSize);
116         DrawPart(canvas, paintOffset, pen, contentSize);
117         return;
118     }
119     if (uiStatus_ == UIStatus::OFF_TO_ON) {
120         brush.SetColor(ToRSColor(color));
121         brush.SetAntiAlias(true);
122         pen.SetColor(ToRSColor(pointColor_));
123         if (!enabled_) {
124             brush.SetColor(ToRSColor(color.BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
125         }
126         DrawActiveBorder(canvas, paintOffset, brush, contentSize);
127         DrawAnimationOffToOn(canvas, paintOffset, pen, contentSize);
128     } else if (uiStatus_ == UIStatus::ON_TO_OFF) {
129         brush.SetColor(ToRSColor(color));
130         brush.SetAntiAlias(true);
131         pen.SetColor(ToRSColor(pointColor_));
132         if (!enabled_) {
133             brush.SetColor(ToRSColor(color.BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
134         }
135         DrawActiveBorder(canvas, paintOffset, brush, contentSize);
136         DrawAnimationOnToOff(canvas, paintOffset, pen, contentSize);
137     } else if (uiStatus_ == UIStatus::UNSELECTED || uiStatus_ == UIStatus::PART_TO_OFF) {
138         brush.SetColor(ToRSColor(inactivePointColor_));
139         pen.SetColor(ToRSColor(inactiveColor_));
140         if (!enabled_) {
141             brush.SetColor(
142                 ToRSColor(inactivePointColor_.BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
143             pen.SetColor(ToRSColor(inactiveColor_.BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
144         }
145         DrawUnselectedBorder(canvas, paintOffset, brush, contentSize);
146         DrawUnselected(canvas, paintOffset, pen, contentSize);
147     }
148 }
149 
DrawUnselected(RSCanvas & canvas,const OffsetF & origin,RSPen & pen,SizeF & paintSize) const150 void CheckBoxGroupPaintMethod::DrawUnselected(
151     RSCanvas& canvas, const OffsetF& origin, RSPen& pen, SizeF& paintSize) const
152 {
153     float originX = origin.GetX() + borderWidth_ / 2.0;
154     float originY = origin.GetY() + borderWidth_ / 2.0;
155     float endX = originX + paintSize.Width() - borderWidth_;
156     float endY = originY + paintSize.Height() - borderWidth_;
157     auto rrect = RSRoundRect({ originX, originY, endX, endY }, borderRadius_, borderRadius_);
158     canvas.AttachPen(pen);
159     canvas.DrawRoundRect(rrect);
160 }
161 
DrawActiveBorder(RSCanvas & canvas,const OffsetF & paintOffset,RSBrush & brush,const SizeF & paintSize) const162 void CheckBoxGroupPaintMethod::DrawActiveBorder(
163     RSCanvas& canvas, const OffsetF& paintOffset, RSBrush& brush, const SizeF& paintSize) const
164 {
165     float originX = paintOffset.GetX();
166     float originY = paintOffset.GetY();
167     float endX = originX + paintSize.Width();
168     float endY = originY + paintSize.Height();
169     auto rrect = RSRoundRect({ originX, originY, endX, endY }, borderRadius_, borderRadius_);
170     canvas.AttachBrush(brush);
171     canvas.DrawRoundRect(rrect);
172 }
173 
DrawUnselectedBorder(RSCanvas & canvas,const OffsetF & paintOffset,RSBrush & brush,const SizeF & paintSize) const174 void CheckBoxGroupPaintMethod::DrawUnselectedBorder(
175     RSCanvas& canvas, const OffsetF& paintOffset, RSBrush& brush, const SizeF& paintSize) const
176 {
177     float originX = paintOffset.GetX() + borderWidth_;
178     float originY = paintOffset.GetY() + borderWidth_;
179     float endX = originX + paintSize.Width() - 2 * borderWidth_;
180     float endY = originY + paintSize.Height() - 2 * borderWidth_;
181     auto rrect = RSRoundRect({ originX, originY, endX, endY }, borderRadius_, borderRadius_);
182     canvas.AttachBrush(brush);
183     canvas.DrawRoundRect(rrect);
184 }
185 
DrawPart(RSCanvas & canvas,const OffsetF & origin,RSPen & pen,const SizeF & paintSize) const186 void CheckBoxGroupPaintMethod::DrawPart(
187     RSCanvas& canvas, const OffsetF& origin, RSPen& pen, const SizeF& paintSize) const
188 {
189     RSPath path;
190     RSPen shadowPen;
191     float originX = origin.GetX();
192     float originY = origin.GetY();
193     const Offset start =
194         Offset(paintSize.Width() * CHECK_MARK_PART_START_X_POSITION, paintSize.Width() * CHECK_MARK_PART_Y_POSITION);
195     const Offset end =
196         Offset(paintSize.Width() * CHECK_MARK_PART_END_Y_POSITION, paintSize.Width() * CHECK_MARK_PART_Y_POSITION);
197     path.MoveTo(originX + start.GetX(), originY + start.GetY());
198     path.LineTo(originX + end.GetX(), originY + end.GetY());
199     shadowPen.SetColor(ToRSColor(shadowColor_));
200     shadowPen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
201     shadowPen.SetWidth(checkStroke_ + shadowWidth_.ConvertToPx() * 2);
202     canvas.AttachPen(shadowPen);
203     canvas.DrawPath(path);
204     pen.SetWidth(checkStroke_);
205     pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
206     canvas.AttachPen(pen);
207     canvas.DrawPath(path);
208 }
209 
DrawAnimationOffToOn(RSCanvas & canvas,const OffsetF & origin,RSPen & pen,const SizeF & paintSize) const210 void CheckBoxGroupPaintMethod::DrawAnimationOffToOn(
211     RSCanvas& canvas, const OffsetF& origin, RSPen& pen, const SizeF& paintSize) const
212 {
213     RSPath path;
214     RSPen shadowPen = RSPen(pen);
215     float originX = origin.GetX();
216     float originY = origin.GetY();
217     const Offset start =
218         Offset(paintSize.Width() * CHECK_MARK_START_X_POSITION, paintSize.Height() * CHECK_MARK_START_Y_POSITION);
219     const Offset middle =
220         Offset(paintSize.Width() * CHECK_MARK_MIDDLE_X_POSITION, paintSize.Height() * CHECK_MARK_MIDDLE_Y_POSITION);
221     const Offset end =
222         Offset(paintSize.Width() * CHECK_MARK_END_X_POSITION, paintSize.Height() * CHECK_MARK_END_Y_POSITION);
223 
224     float deltaX = middle.GetX() - start.GetX();
225     float deltaY = middle.GetY() - start.GetY();
226     path.MoveTo(originX + start.GetX(), originY + start.GetY());
227     shadowPen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
228     shadowPen.SetWidth(checkStroke_ + shadowWidth_.ConvertToPx() * 2);
229     shadowPen.SetColor(ToRSColor(shadowColor_));
230     pen.SetWidth(checkStroke_);
231     pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
232     float ratio = DEFAULT_MIN_CHECKBOX_SHAPE_SCALE;
233     if (shapeScale_ < CHECK_MARK_LEFT_ANIMATION_PERCENT) {
234         ratio = shapeScale_ / CHECK_MARK_LEFT_ANIMATION_PERCENT;
235         path.LineTo(originX + start.GetX() + deltaX * ratio, originY + start.GetY() + deltaY * ratio);
236     } else {
237         path.LineTo(originX + middle.GetX(), originY + middle.GetY());
238     }
239     canvas.AttachPen(shadowPen);
240     canvas.DrawPath(path);
241     canvas.AttachPen(pen);
242     canvas.DrawPath(path);
243     if (shapeScale_ > CHECK_MARK_LEFT_ANIMATION_PERCENT) {
244         deltaX = end.GetX() - middle.GetX();
245         deltaY = middle.GetY() - end.GetY();
246         path.MoveTo(originX + middle.GetX(), originY + middle.GetY());
247         if (shapeScale_ == DEFAULT_MAX_CHECKBOX_SHAPE_SCALE) {
248             path.LineTo(originX + end.GetX(), originY + end.GetY());
249         } else {
250             ratio = (shapeScale_ - CHECK_MARK_LEFT_ANIMATION_PERCENT) / CHECK_MARK_RIGHT_ANIMATION_PERCENT;
251             path.LineTo(originX + middle.GetX() + deltaX * ratio, originY + middle.GetY() - deltaY * ratio);
252         }
253         canvas.AttachPen(shadowPen);
254         canvas.DrawPath(path);
255         canvas.AttachPen(pen);
256         canvas.DrawPath(path);
257     }
258 }
259 
DrawAnimationOnToOff(RSCanvas & canvas,const OffsetF & origin,RSPen & pen,const SizeF & paintSize) const260 void CheckBoxGroupPaintMethod::DrawAnimationOnToOff(
261     RSCanvas& canvas, const OffsetF& origin, RSPen& pen, const SizeF& paintSize) const
262 {
263     if (shapeScale_ == DEFAULT_MIN_CHECKBOX_SHAPE_SCALE) {
264         return;
265     }
266     RSPath path;
267     RSPen shadowPen = RSPen(pen);
268     float originX = origin.GetX();
269     float originY = origin.GetY();
270     const Offset start =
271         Offset(paintSize.Width() * CHECK_MARK_START_X_POSITION, paintSize.Height() * CHECK_MARK_START_Y_POSITION);
272     const Offset middle =
273         Offset(paintSize.Width() * CHECK_MARK_MIDDLE_X_POSITION, paintSize.Height() * CHECK_MARK_MIDDLE_Y_POSITION);
274     const Offset end =
275         Offset(paintSize.Width() * CHECK_MARK_END_X_POSITION, paintSize.Height() * CHECK_MARK_END_Y_POSITION);
276     const Offset middlePoint = Offset(paintSize.Width() / 2, paintSize.Height() / 2);
277     float deltaX = middlePoint.GetX() - start.GetX();
278     float deltaY = middlePoint.GetY() - start.GetY();
279     float ratio = DEFAULT_MAX_CHECKBOX_SHAPE_SCALE - shapeScale_;
280     shadowPen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
281     shadowPen.SetWidth(checkStroke_ + shadowWidth_.ConvertToPx() * 2);
282     shadowPen.SetColor(ToRSColor(shadowColor_));
283     pen.SetWidth(checkStroke_);
284     pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
285     path.MoveTo(originX + start.GetX() + deltaX * ratio, originY + start.GetY() + deltaY * ratio);
286     deltaX = middlePoint.GetX() - middle.GetX();
287     deltaY = middle.GetY() - middlePoint.GetY();
288     path.LineTo(originX + middle.GetX() + deltaX * ratio, originY + middle.GetY() - deltaY * ratio);
289     canvas.AttachPen(shadowPen);
290     canvas.DrawPath(path);
291     canvas.AttachPen(pen);
292     canvas.DrawPath(path);
293     path.MoveTo(originX + middle.GetX() + deltaX * ratio, originY + middle.GetY() - deltaY * ratio);
294     deltaX = end.GetX() - middlePoint.GetX();
295     deltaY = middlePoint.GetY() - end.GetY();
296     path.LineTo(originX + end.GetX() - deltaX * ratio, originY + end.GetY() + deltaY * ratio);
297     canvas.AttachPen(shadowPen);
298     canvas.DrawPath(path);
299     canvas.AttachPen(pen);
300     canvas.DrawPath(path);
301 }
302 
DrawTouchBoard(RSCanvas & canvas,const SizeF & size,const OffsetF & offset) const303 void CheckBoxGroupPaintMethod::DrawTouchBoard(RSCanvas& canvas, const SizeF& size, const OffsetF& offset) const
304 {
305     RSBrush brush;
306     brush.SetColor(ToRSColor(Color(clickEffectColor_)));
307     brush.SetAntiAlias(true);
308     float originX = offset.GetX() - hotZoneHorizontalPadding_.ConvertToPx();
309     float originY = offset.GetY() - hotZoneVerticalPadding_.ConvertToPx();
310     float endX = size.Width() + originX + 2 * hotZoneHorizontalPadding_.ConvertToPx();
311     float endY = size.Height() + originY + 2 * hotZoneVerticalPadding_.ConvertToPx();
312     auto rrect = RSRoundRect({ originX, originY, endX, endY }, hoverRadius_.ConvertToPx(), hoverRadius_.ConvertToPx());
313     canvas.AttachBrush(brush);
314     canvas.DrawRoundRect(rrect);
315 }
316 
DrawHoverBoard(RSCanvas & canvas,const SizeF & size,const OffsetF & offset) const317 void CheckBoxGroupPaintMethod::DrawHoverBoard(RSCanvas& canvas, const SizeF& size, const OffsetF& offset) const
318 {
319     RSBrush brush;
320     brush.SetColor(ToRSColor(Color(hoverColor_)));
321     brush.SetAntiAlias(true);
322     float originX = offset.GetX() - hotZoneHorizontalPadding_.ConvertToPx();
323     float originY = offset.GetY() - hotZoneVerticalPadding_.ConvertToPx();
324     float endX = size.Width() + originX + 2 * hotZoneHorizontalPadding_.ConvertToPx();
325     float endY = size.Height() + originY + 2 * hotZoneVerticalPadding_.ConvertToPx();
326     auto rrect = RSRoundRect({ originX, originY, endX, endY }, hoverRadius_.ConvertToPx(), hoverRadius_.ConvertToPx());
327     canvas.AttachBrush(brush);
328     canvas.DrawRoundRect(rrect);
329 }
330 
331 } // namespace OHOS::Ace::NG
332