1 /*
2 * Copyright (c) 2023 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/checkboxgroup/checkboxgroup_modifier.h"
17
18 #include "core/components_ng/render/drawing_prop_convertor.h"
19
20 namespace OHOS::Ace::NG {
21 namespace {
22 constexpr uint8_t ENABLED_ALPHA = 255;
23 constexpr uint8_t DISABLED_ALPHA = 102;
24 constexpr float CHECK_MARK_START_X_POSITION = 0.25f;
25 constexpr float CHECK_MARK_START_Y_POSITION = 0.49f;
26 constexpr float CHECK_MARK_MIDDLE_X_POSITION = 0.44f;
27 constexpr float CHECK_MARK_MIDDLE_Y_POSITION = 0.68f;
28 constexpr float CHECK_MARK_END_X_POSITION = 0.76f;
29 constexpr float CHECK_MARK_END_Y_POSITION = 0.33f;
30 constexpr float CHECK_MARK_PART_START_X_POSITION = 0.20f;
31 constexpr float CHECK_MARK_PART_END_Y_POSITION = 0.80f;
32 constexpr float CHECK_MARK_PART_Y_POSITION = 0.50f;
33 constexpr float CHECKBOX_GROUP_DOUBLE_RATIO = 2.0f;
34 constexpr float CHECKBOX_GROUP_LENGTH_ZERO = 0.0f;
35 } // namespace
36
CheckBoxGroupModifier(const Parameters & parameters)37 CheckBoxGroupModifier::CheckBoxGroupModifier(const Parameters& parameters)
38 {
39 activeColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(parameters.activeColor));
40 pointColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(parameters.pointColor));
41 inactiveColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(parameters.inactiveColor));
42 checkMarkPaintSize_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(parameters.checkMarkPaintSize);
43 checkStroke_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(parameters.checkStroke);
44 enabled_ = AceType::MakeRefPtr<PropertyBool>(true);
45 uiStatus_ = AceType::MakeRefPtr<PropertyInt>(static_cast<int>(parameters.uiStatus));
46 status_ = AceType::MakeRefPtr<PropertyInt>(static_cast<int>(UIStatus::UNSELECTED));
47 offset_ = AceType::MakeRefPtr<PropertyOffsetF>(OffsetF());
48 size_ = AceType::MakeRefPtr<PropertySizeF>(SizeF());
49 animateTouchHoverColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(Color::TRANSPARENT));
50 inactivePointColor_ = AceType::MakeRefPtr<PropertyColor>(parameters.inactivePointColor);
51
52 borderWidth_ = parameters.borderWidth;
53 borderRadius_ = parameters.borderRadius;
54 shadowColor_ = parameters.shadowColor;
55 clickEffectColor_ = parameters.clickEffectColor;
56 hoverColor_ = parameters.hoverColor;
57 hoverRadius_ = parameters.hoverRadius;
58 hotZoneHorizontalPadding_ = parameters.hotZoneHorizontalPadding;
59 defaultPaddingSize_ = parameters.defaultPaddingSize;
60 hoverPaddingSize_ = parameters.hoverPaddingSize;
61 showCircleDial_ = parameters.showCircleDial;
62 hotZoneVerticalPadding_ = parameters.hotZoneVerticalPadding;
63 shadowWidth_ = parameters.shadowWidth;
64 hoverDuration_ = parameters.hoverDuration;
65 hoverToTouchDuration_ = parameters.hoverToTouchDuration;
66 checkBoxGroupShape_ = AceType::MakeRefPtr<PropertyInt>(static_cast<int32_t>(CheckBoxStyle::CIRCULAR_STYLE));
67 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
68 checkBoxGroupStyle_ = CheckBoxStyle::CIRCULAR_STYLE;
69 } else {
70 checkBoxGroupStyle_ = CheckBoxStyle::SQUARE_STYLE;
71 }
72 AttachProperty(activeColor_);
73 AttachProperty(pointColor_);
74 AttachProperty(inactiveColor_);
75 AttachProperty(inactivePointColor_);
76 AttachProperty(checkMarkPaintSize_);
77 AttachProperty(checkStroke_);
78 AttachProperty(enabled_);
79 AttachProperty(uiStatus_);
80 AttachProperty(status_);
81 AttachProperty(offset_);
82 AttachProperty(size_);
83 AttachProperty(animateTouchHoverColor_);
84 AttachProperty(checkBoxGroupShape_);
85 }
86
PaintCheckBox(DrawingContext & context,const OffsetF & paintOffset,const SizeF & contentSize) const87 void CheckBoxGroupModifier::PaintCheckBox(
88 DrawingContext& context, const OffsetF& paintOffset, const SizeF& contentSize) const
89 {
90 auto& canvas = context.canvas;
91 auto color = activeColor_;
92
93 RSPen pen;
94 RSBrush brush;
95 pen.SetWidth(borderWidth_);
96 pen.SetAntiAlias(true);
97 DrawTouchAndHoverBoard(canvas, contentSize, paintOffset);
98 RSPen shadowPen = RSPen(pen);
99 shadowPen.SetColor(ToRSColor(shadowColor_));
100 if (static_cast<CheckBoxGroupPaintProperty::SelectStatus>(status_->Get()) ==
101 CheckBoxGroupPaintProperty::SelectStatus::PART) {
102 PaintCheckBoxGroupPartStatus(canvas, paintOffset, brush, pen, contentSize);
103 return;
104 }
105 if (static_cast<UIStatus>(uiStatus_->Get()) == UIStatus::OFF_TO_ON ||
106 static_cast<UIStatus>(uiStatus_->Get()) == UIStatus::PART_TO_ON) {
107 brush.SetColor(ToRSColor(color->Get()));
108 brush.SetAntiAlias(true);
109 pen.SetColor(ToRSColor(pointColor_->Get()));
110 if (!enabled_->Get()) {
111 brush.SetColor(ToRSColor(color->Get().BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
112 }
113 DrawActiveBorder(canvas, paintOffset, brush, contentSize);
114 DrawCheck(canvas, paintOffset, pen, shadowPen, contentSize);
115 } else {
116 brush.SetColor(ToRSColor(inactivePointColor_->Get()));
117 pen.SetColor(ToRSColor(inactiveColor_->Get()));
118 if (!enabled_->Get()) {
119 brush.SetColor(
120 ToRSColor(inactivePointColor_->Get().BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
121 pen.SetColor(
122 ToRSColor(inactiveColor_->Get().BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
123 }
124 DrawUnselectedBorder(canvas, paintOffset, brush, contentSize);
125 DrawUnselected(canvas, paintOffset, pen, contentSize);
126 }
127 }
128
PaintCheckBoxGroupPartStatus(RSCanvas & canvas,const OffsetF & paintOffset,RSBrush & brush,RSPen & pen,const SizeF & paintSize) const129 void CheckBoxGroupModifier::PaintCheckBoxGroupPartStatus(
130 RSCanvas& canvas, const OffsetF& paintOffset, RSBrush& brush, RSPen& pen, const SizeF& paintSize) const
131 {
132 auto color = activeColor_;
133 brush.SetColor(ToRSColor(color->Get()));
134 brush.SetAntiAlias(true);
135 pen.SetColor(ToRSColor(pointColor_->Get()));
136 if (!enabled_->Get()) {
137 brush.SetColor(ToRSColor(color->Get().BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
138 }
139 DrawActiveBorder(canvas, paintOffset, brush, paintSize);
140 DrawPart(canvas, paintOffset, pen, paintSize);
141 }
142
DrawCheck(RSCanvas & canvas,const OffsetF & origin,RSPen & pen,RSPen & shadowPen,const SizeF & paintSize) const143 void CheckBoxGroupModifier::DrawCheck(
144 RSCanvas& canvas, const OffsetF& origin, RSPen& pen, RSPen& shadowPen, const SizeF& paintSize) const
145 {
146 if (checkMarkPaintSize_->Get() == CHECKBOX_GROUP_LENGTH_ZERO || checkStroke_->Get() == CHECKBOX_GROUP_LENGTH_ZERO) {
147 return;
148 }
149 #ifndef USE_ROSEN_DRAWING
150 RSPath path;
151 #else
152 RSRecordingPath path;
153 #endif
154 float originX = origin.GetX();
155 float originY = origin.GetY();
156 float strokeSize = checkMarkPaintSize_->Get();
157 const Offset start = Offset(strokeSize * CHECK_MARK_START_X_POSITION, strokeSize * CHECK_MARK_START_Y_POSITION);
158 const Offset middle = Offset(strokeSize * CHECK_MARK_MIDDLE_X_POSITION, strokeSize * CHECK_MARK_MIDDLE_Y_POSITION);
159 const Offset end = Offset(strokeSize * CHECK_MARK_END_X_POSITION, strokeSize * CHECK_MARK_END_Y_POSITION);
160 path.MoveTo(originX + start.GetX() + (paintSize.Width() - strokeSize) / CHECKBOX_GROUP_DOUBLE_RATIO,
161 originY + start.GetY() + (paintSize.Height() - strokeSize) / CHECKBOX_GROUP_DOUBLE_RATIO);
162 path.LineTo(originX + middle.GetX() + (paintSize.Width() - strokeSize) / CHECKBOX_GROUP_DOUBLE_RATIO,
163 originY + middle.GetY() + (paintSize.Height() - strokeSize) / CHECKBOX_GROUP_DOUBLE_RATIO);
164 path.MoveTo(originX + middle.GetX() + (paintSize.Width() - strokeSize) / CHECKBOX_GROUP_DOUBLE_RATIO,
165 originY + middle.GetY() + (paintSize.Height() - strokeSize) / CHECKBOX_GROUP_DOUBLE_RATIO);
166 path.LineTo(originX + end.GetX() + (paintSize.Width() - strokeSize) / CHECKBOX_GROUP_DOUBLE_RATIO,
167 originY + end.GetY() + (paintSize.Height() - strokeSize) / CHECKBOX_GROUP_DOUBLE_RATIO);
168 shadowPen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
169 shadowPen.SetWidth(checkStroke_->Get() + shadowWidth_.ConvertToPx() * CHECKBOX_GROUP_DOUBLE_RATIO);
170 pen.SetWidth(checkStroke_->Get());
171 pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
172 canvas.AttachPen(shadowPen);
173 canvas.DrawPath(path);
174 canvas.AttachPen(pen);
175 canvas.DrawPath(path);
176 #ifdef USE_ROSEN_DRAWING
177 canvas.DetachPen();
178 #endif
179 }
180
DrawUnselected(RSCanvas & canvas,const OffsetF & origin,RSPen & pen,const SizeF & paintSize) const181 void CheckBoxGroupModifier::DrawUnselected(
182 RSCanvas& canvas, const OffsetF& origin, RSPen& pen, const SizeF& paintSize) const
183 {
184 float originX = origin.GetX() + borderWidth_ / CHECKBOX_GROUP_DOUBLE_RATIO;
185 float originY = origin.GetY() + borderWidth_ / CHECKBOX_GROUP_DOUBLE_RATIO;
186 float endX = originX + paintSize.Width() - borderWidth_;
187 float endY = originY + paintSize.Height() - borderWidth_;
188 RSRect rect(originX, originY, endX, endY);
189 auto rrect = RSRoundRect(rect, borderRadius_, borderRadius_);
190 canvas.AttachPen(pen);
191 DrawRectOrCircle(canvas, rrect);
192 #ifdef USE_ROSEN_DRAWING
193 canvas.DetachPen();
194 #endif
195 }
196
DrawActiveBorder(RSCanvas & canvas,const OffsetF & paintOffset,RSBrush & brush,const SizeF & paintSize) const197 void CheckBoxGroupModifier::DrawActiveBorder(
198 RSCanvas& canvas, const OffsetF& paintOffset, RSBrush& brush, const SizeF& paintSize) const
199 {
200 float originX = paintOffset.GetX();
201 float originY = paintOffset.GetY();
202 float endX = originX + paintSize.Width();
203 float endY = originY + paintSize.Height();
204 RSRect rect(originX, originY, endX, endY);
205 auto rrect = RSRoundRect(rect, borderRadius_, borderRadius_);
206 canvas.AttachBrush(brush);
207 DrawRectOrCircle(canvas, rrect);
208 canvas.DetachBrush();
209 }
210
DrawUnselectedBorder(RSCanvas & canvas,const OffsetF & paintOffset,RSBrush & brush,const SizeF & paintSize) const211 void CheckBoxGroupModifier::DrawUnselectedBorder(
212 RSCanvas& canvas, const OffsetF& paintOffset, RSBrush& brush, const SizeF& paintSize) const
213 {
214 float originX = paintOffset.GetX() + borderWidth_;
215 float originY = paintOffset.GetY() + borderWidth_;
216 float endX = originX + paintSize.Width() - CHECKBOX_GROUP_DOUBLE_RATIO * borderWidth_;
217 float endY = originY + paintSize.Height() - CHECKBOX_GROUP_DOUBLE_RATIO * borderWidth_;
218 RSRect rect(originX, originY, endX, endY);
219 auto rrect = RSRoundRect(rect, borderRadius_, borderRadius_);
220 canvas.AttachBrush(brush);
221 DrawRectOrCircle(canvas, rrect);
222 #ifdef USE_ROSEN_DRAWING
223 canvas.DetachBrush();
224 #endif
225 }
226
DrawPart(RSCanvas & canvas,const OffsetF & origin,RSPen & pen,const SizeF & paintSize) const227 void CheckBoxGroupModifier::DrawPart(RSCanvas& canvas, const OffsetF& origin, RSPen& pen, const SizeF& paintSize) const
228 {
229 if (checkMarkPaintSize_->Get() == CHECKBOX_GROUP_LENGTH_ZERO || checkStroke_->Get() == CHECKBOX_GROUP_LENGTH_ZERO) {
230 return;
231 }
232 #ifndef USE_ROSEN_DRAWING
233 RSPath path;
234 #else
235 RSRecordingPath path;
236 #endif
237 RSPen shadowPen;
238 float originX = origin.GetX();
239 float originY = origin.GetY();
240 const Offset start = Offset(checkMarkPaintSize_->Get() * CHECK_MARK_PART_START_X_POSITION,
241 checkMarkPaintSize_->Get() * CHECK_MARK_PART_Y_POSITION);
242 const Offset end = Offset(checkMarkPaintSize_->Get() * CHECK_MARK_PART_END_Y_POSITION,
243 checkMarkPaintSize_->Get() * CHECK_MARK_PART_Y_POSITION);
244 path.MoveTo(originX + start.GetX() + (paintSize.Width() - checkMarkPaintSize_->Get()) / CHECKBOX_GROUP_DOUBLE_RATIO,
245 originY + start.GetY() + (paintSize.Height() - checkMarkPaintSize_->Get()) / CHECKBOX_GROUP_DOUBLE_RATIO);
246 path.LineTo(originX + end.GetX() + (paintSize.Width() - checkMarkPaintSize_->Get()) / CHECKBOX_GROUP_DOUBLE_RATIO,
247 originY + end.GetY() + (paintSize.Height() - checkMarkPaintSize_->Get()) / CHECKBOX_GROUP_DOUBLE_RATIO);
248 shadowPen.SetColor(ToRSColor(shadowColor_));
249 shadowPen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
250 shadowPen.SetWidth(checkStroke_->Get() + shadowWidth_.ConvertToPx() * CHECKBOX_GROUP_DOUBLE_RATIO);
251 canvas.AttachPen(shadowPen);
252 canvas.DrawPath(path);
253 pen.SetWidth(checkStroke_->Get());
254 pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
255 canvas.AttachPen(pen);
256 canvas.DrawPath(path);
257 #ifdef USE_ROSEN_DRAWING
258 canvas.DetachPen();
259 #endif
260 }
261
DrawTouchAndHoverBoard(RSCanvas & canvas,const SizeF & size,const OffsetF & offset) const262 void CheckBoxGroupModifier::DrawTouchAndHoverBoard(RSCanvas& canvas, const SizeF& size, const OffsetF& offset) const
263 {
264 if (HoverEffectType::NONE == hoverEffectType_) {
265 return;
266 }
267 RSBrush brush;
268 brush.SetColor(ToRSColor(animateTouchHoverColor_->Get()));
269 brush.SetAntiAlias(true);
270 float originX;
271 float originY;
272 float endX;
273 float endY;
274 auto paddingPx = (showCircleDial_ ? hoverPaddingSize_.ConvertToPx() : defaultPaddingSize_.ConvertToPx());
275 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
276 originX = offset.GetX() - paddingPx;
277 originY = offset.GetY() - paddingPx;
278 endX = size.Width() + originX +
279 CHECKBOX_GROUP_DOUBLE_RATIO * paddingPx;
280 endY = size.Height() + originY +
281 CHECKBOX_GROUP_DOUBLE_RATIO * paddingPx;
282 } else {
283 originX = offset.GetX() - hotZoneHorizontalPadding_.ConvertToPx();
284 originY = offset.GetY() - hotZoneVerticalPadding_.ConvertToPx();
285 endX = size.Width() + originX + CHECKBOX_GROUP_DOUBLE_RATIO * hotZoneHorizontalPadding_.ConvertToPx();
286 endY = size.Height() + originY + CHECKBOX_GROUP_DOUBLE_RATIO * hotZoneVerticalPadding_.ConvertToPx();
287 }
288 auto rrect = RSRoundRect({ originX, originY, endX, endY }, hoverRadius_.ConvertToPx(), hoverRadius_.ConvertToPx());
289 canvas.AttachBrush(brush);
290 DrawRectOrCircle(canvas, rrect);
291 #ifdef USE_ROSEN_DRAWING
292 canvas.DetachBrush();
293 #endif
294 }
295
DrawRectOrCircle(RSCanvas & canvas,const RSRoundRect & rrect) const296 void CheckBoxGroupModifier::DrawRectOrCircle(RSCanvas& canvas, const RSRoundRect& rrect) const
297 {
298 if (CheckBoxStyle::SQUARE_STYLE == checkBoxGroupStyle_) {
299 canvas.DrawRoundRect(rrect);
300 } else {
301 RSScalar halfDenominator = 2.0f;
302 RSRect rect = rrect.GetRect();
303 RSScalar x = (rect.GetLeft() + rect.GetRight()) / halfDenominator;
304 RSScalar y = (rect.GetTop() + rect.GetBottom()) / halfDenominator;
305 RSPoint centerPt(x, y);
306 RSScalar radius = std::min(rect.GetWidth(), rect.GetHeight()) / halfDenominator;
307 canvas.DrawCircle(centerPt, radius);
308 }
309 }
310 } // namespace OHOS::Ace::NG
311