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 "base/utils/utils.h"
19 #include "core/components/checkable/checkable_theme.h"
20 #include "core/components_ng/base/modifier.h"
21 #include "core/components_ng/pattern/checkboxgroup/checkboxgroup_paint_property.h"
22 #include "core/components_ng/render/drawing.h"
23 #include "core/components_ng/render/drawing_prop_convertor.h"
24
25 namespace OHOS::Ace::NG {
26 namespace {
27 constexpr uint8_t ENABLED_ALPHA = 255;
28 constexpr uint8_t DISABLED_ALPHA = 102;
29 constexpr float CHECK_MARK_START_X_POSITION = 0.25f;
30 constexpr float CHECK_MARK_START_Y_POSITION = 0.49f;
31 constexpr float CHECK_MARK_MIDDLE_X_POSITION = 0.44f;
32 constexpr float CHECK_MARK_MIDDLE_Y_POSITION = 0.68f;
33 constexpr float CHECK_MARK_END_X_POSITION = 0.76f;
34 constexpr float CHECK_MARK_END_Y_POSITION = 0.33f;
35 constexpr float CHECK_MARK_PART_START_X_POSITION = 0.20f;
36 constexpr float CHECK_MARK_PART_END_Y_POSITION = 0.80f;
37 constexpr float CHECK_MARK_PART_Y_POSITION = 0.50f;
38 constexpr float CHECKBOX_GROUP_DOUBLE_RATIO = 2.0f;
39 constexpr float CHECKBOX_GROUP_LENGTH_ZERO = 0.0f;
40 } // namespace
41
CheckBoxGroupModifier(const Parameters & parameters)42 CheckBoxGroupModifier::CheckBoxGroupModifier(const Parameters& parameters)
43 {
44 activeColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(parameters.activeColor));
45 pointColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(parameters.pointColor));
46 inactiveColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(parameters.inactiveColor));
47 checkMarkPaintSize_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(parameters.checkMarkPaintSize);
48 checkStroke_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(parameters.checkStroke);
49 enabled_ = AceType::MakeRefPtr<PropertyBool>(true);
50 uiStatus_ = AceType::MakeRefPtr<PropertyInt>(static_cast<int>(parameters.uiStatus));
51 status_ = AceType::MakeRefPtr<PropertyInt>(static_cast<int>(UIStatus::UNSELECTED));
52 offset_ = AceType::MakeRefPtr<PropertyOffsetF>(OffsetF());
53 size_ = AceType::MakeRefPtr<PropertySizeF>(SizeF());
54 animateTouchHoverColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(Color::TRANSPARENT));
55
56 borderWidth_ = parameters.borderWidth;
57 borderRadius_ = parameters.borderRadius;
58 shadowColor_ = parameters.shadowColor;
59 clickEffectColor_ = parameters.clickEffectColor;
60 hoverColor_ = parameters.hoverColor;
61 inactivePointColor_ = parameters.inactivePointColor;
62 hoverRadius_ = parameters.hoverRadius;
63 hotZoneHorizontalPadding_ = parameters.hotZoneHorizontalPadding;
64 hotZoneVerticalPadding_ = parameters.hotZoneVerticalPadding;
65 shadowWidth_ = parameters.shadowWidth;
66 hoverDuration_ = parameters.hoverDuration;
67 hoverToTouchDuration_ = parameters.hoverToTouchDuration;
68
69 AttachProperty(activeColor_);
70 AttachProperty(pointColor_);
71 AttachProperty(inactiveColor_);
72 AttachProperty(checkMarkPaintSize_);
73 AttachProperty(checkStroke_);
74 AttachProperty(enabled_);
75 AttachProperty(uiStatus_);
76 AttachProperty(status_);
77 AttachProperty(offset_);
78 AttachProperty(size_);
79 AttachProperty(animateTouchHoverColor_);
80 }
81
PaintCheckBox(DrawingContext & context,const OffsetF & paintOffset,const SizeF & contentSize) const82 void CheckBoxGroupModifier::PaintCheckBox(
83 DrawingContext& context, const OffsetF& paintOffset, const SizeF& contentSize) const
84 {
85 auto canvas = context.canvas;
86 auto color = activeColor_;
87
88 RSPen pen;
89 RSBrush brush;
90 pen.SetWidth(borderWidth_);
91 pen.SetAntiAlias(true);
92 DrawTouchAndHoverBoard(canvas, contentSize, paintOffset);
93 RSPen shadowPen = RSPen(pen);
94 shadowPen.SetColor(ToRSColor(shadowColor_));
95 if (static_cast<CheckBoxGroupPaintProperty::SelectStatus>(status_->Get()) ==
96 CheckBoxGroupPaintProperty::SelectStatus::PART) {
97 PaintCheckBoxGroupPartStatus(canvas, paintOffset, brush, pen, contentSize);
98 return;
99 }
100 if (static_cast<UIStatus>(uiStatus_->Get()) == UIStatus::OFF_TO_ON ||
101 static_cast<UIStatus>(uiStatus_->Get()) == UIStatus::PART_TO_ON) {
102 brush.SetColor(ToRSColor(color->Get()));
103 brush.SetAntiAlias(true);
104 pen.SetColor(ToRSColor(pointColor_->Get()));
105 if (!enabled_->Get()) {
106 brush.SetColor(ToRSColor(color->Get().BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
107 }
108 DrawActiveBorder(canvas, paintOffset, brush, contentSize);
109 DrawCheck(canvas, paintOffset, pen, shadowPen, contentSize);
110 } else {
111 brush.SetColor(ToRSColor(inactivePointColor_));
112 pen.SetColor(ToRSColor(inactiveColor_->Get()));
113 if (!enabled_->Get()) {
114 brush.SetColor(
115 ToRSColor(inactivePointColor_.BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
116 pen.SetColor(
117 ToRSColor(inactiveColor_->Get().BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
118 }
119 DrawUnselectedBorder(canvas, paintOffset, brush, contentSize);
120 DrawUnselected(canvas, paintOffset, pen, contentSize);
121 }
122 }
123
PaintCheckBoxGroupPartStatus(RSCanvas & canvas,const OffsetF & paintOffset,RSBrush & brush,RSPen & pen,const SizeF & paintSize) const124 void CheckBoxGroupModifier::PaintCheckBoxGroupPartStatus(
125 RSCanvas& canvas, const OffsetF& paintOffset, RSBrush& brush, RSPen& pen, const SizeF& paintSize) const
126 {
127 auto color = activeColor_;
128 brush.SetColor(ToRSColor(color->Get()));
129 brush.SetAntiAlias(true);
130 pen.SetColor(ToRSColor(pointColor_->Get()));
131 if (!enabled_->Get()) {
132 brush.SetColor(ToRSColor(color->Get().BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
133 }
134 DrawActiveBorder(canvas, paintOffset, brush, paintSize);
135 DrawPart(canvas, paintOffset, pen, paintSize);
136 }
137
DrawCheck(RSCanvas & canvas,const OffsetF & origin,RSPen & pen,RSPen & shadowPen,const SizeF & paintSize) const138 void CheckBoxGroupModifier::DrawCheck(
139 RSCanvas& canvas, const OffsetF& origin, RSPen& pen, RSPen& shadowPen, const SizeF& paintSize) const
140 {
141 if (checkMarkPaintSize_->Get() == CHECKBOX_GROUP_LENGTH_ZERO || checkStroke_->Get() == CHECKBOX_GROUP_LENGTH_ZERO) {
142 return;
143 }
144 RSPath path;
145 float originX = origin.GetX();
146 float originY = origin.GetY();
147 float strokeSize = checkMarkPaintSize_->Get();
148 const Offset start = Offset(strokeSize * CHECK_MARK_START_X_POSITION, strokeSize * CHECK_MARK_START_Y_POSITION);
149 const Offset middle = Offset(strokeSize * CHECK_MARK_MIDDLE_X_POSITION, strokeSize * CHECK_MARK_MIDDLE_Y_POSITION);
150 const Offset end = Offset(strokeSize * CHECK_MARK_END_X_POSITION, strokeSize * CHECK_MARK_END_Y_POSITION);
151 path.MoveTo(originX + start.GetX() + (paintSize.Width() - strokeSize) / CHECKBOX_GROUP_DOUBLE_RATIO,
152 originY + start.GetY() + (paintSize.Height() - strokeSize) / CHECKBOX_GROUP_DOUBLE_RATIO);
153 path.LineTo(originX + middle.GetX() + (paintSize.Width() - strokeSize) / CHECKBOX_GROUP_DOUBLE_RATIO,
154 originY + middle.GetY() + (paintSize.Height() - strokeSize) / CHECKBOX_GROUP_DOUBLE_RATIO);
155 path.MoveTo(originX + middle.GetX() + (paintSize.Width() - strokeSize) / CHECKBOX_GROUP_DOUBLE_RATIO,
156 originY + middle.GetY() + (paintSize.Height() - strokeSize) / CHECKBOX_GROUP_DOUBLE_RATIO);
157 path.LineTo(originX + end.GetX() + (paintSize.Width() - strokeSize) / CHECKBOX_GROUP_DOUBLE_RATIO,
158 originY + end.GetY() + (paintSize.Height() - strokeSize) / CHECKBOX_GROUP_DOUBLE_RATIO);
159 shadowPen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
160 shadowPen.SetWidth(checkStroke_->Get() + shadowWidth_.ConvertToPx() * CHECKBOX_GROUP_DOUBLE_RATIO);
161 pen.SetWidth(checkStroke_->Get());
162 pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
163 canvas.AttachPen(shadowPen);
164 canvas.DrawPath(path);
165 canvas.AttachPen(pen);
166 canvas.DrawPath(path);
167 }
168
DrawUnselected(RSCanvas & canvas,const OffsetF & origin,RSPen & pen,const SizeF & paintSize) const169 void CheckBoxGroupModifier::DrawUnselected(
170 RSCanvas& canvas, const OffsetF& origin, RSPen& pen, const SizeF& paintSize) const
171 {
172 float originX = origin.GetX() + borderWidth_ / CHECKBOX_GROUP_DOUBLE_RATIO;
173 float originY = origin.GetY() + borderWidth_ / CHECKBOX_GROUP_DOUBLE_RATIO;
174 float endX = originX + paintSize.Width() - borderWidth_;
175 float endY = originY + paintSize.Height() - borderWidth_;
176 RSRect rect(originX, originY, endX, endY);
177 auto rrect = RSRoundRect(rect, borderRadius_, borderRadius_);
178 canvas.AttachPen(pen);
179 canvas.DrawRoundRect(rrect);
180 }
181
DrawActiveBorder(RSCanvas & canvas,const OffsetF & paintOffset,RSBrush & brush,const SizeF & paintSize) const182 void CheckBoxGroupModifier::DrawActiveBorder(
183 RSCanvas& canvas, const OffsetF& paintOffset, RSBrush& brush, const SizeF& paintSize) const
184 {
185 float originX = paintOffset.GetX();
186 float originY = paintOffset.GetY();
187 float endX = originX + paintSize.Width();
188 float endY = originY + paintSize.Height();
189 RSRect rect(originX, originY, endX, endY);
190 auto rrect = RSRoundRect(rect, borderRadius_, borderRadius_);
191 canvas.AttachBrush(brush);
192 canvas.DrawRoundRect(rrect);
193 }
194
DrawUnselectedBorder(RSCanvas & canvas,const OffsetF & paintOffset,RSBrush & brush,const SizeF & paintSize) const195 void CheckBoxGroupModifier::DrawUnselectedBorder(
196 RSCanvas& canvas, const OffsetF& paintOffset, RSBrush& brush, const SizeF& paintSize) const
197 {
198 float originX = paintOffset.GetX() + borderWidth_;
199 float originY = paintOffset.GetY() + borderWidth_;
200 float endX = originX + paintSize.Width() - CHECKBOX_GROUP_DOUBLE_RATIO * borderWidth_;
201 float endY = originY + paintSize.Height() - CHECKBOX_GROUP_DOUBLE_RATIO * borderWidth_;
202 RSRect rect(originX, originY, endX, endY);
203 auto rrect = RSRoundRect(rect, borderRadius_, borderRadius_);
204 canvas.AttachBrush(brush);
205 canvas.DrawRoundRect(rrect);
206 }
207
DrawPart(RSCanvas & canvas,const OffsetF & origin,RSPen & pen,const SizeF & paintSize) const208 void CheckBoxGroupModifier::DrawPart(RSCanvas& canvas, const OffsetF& origin, RSPen& pen, const SizeF& paintSize) const
209 {
210 if (checkMarkPaintSize_->Get() == CHECKBOX_GROUP_LENGTH_ZERO || checkStroke_->Get() == CHECKBOX_GROUP_LENGTH_ZERO) {
211 return;
212 }
213 RSPath path;
214 RSPen shadowPen;
215 float originX = origin.GetX();
216 float originY = origin.GetY();
217 const Offset start = Offset(checkMarkPaintSize_->Get() * CHECK_MARK_PART_START_X_POSITION,
218 checkMarkPaintSize_->Get() * CHECK_MARK_PART_Y_POSITION);
219 const Offset end = Offset(checkMarkPaintSize_->Get() * CHECK_MARK_PART_END_Y_POSITION,
220 checkMarkPaintSize_->Get() * CHECK_MARK_PART_Y_POSITION);
221 path.MoveTo(originX + start.GetX() + (paintSize.Width() - checkMarkPaintSize_->Get()) / CHECKBOX_GROUP_DOUBLE_RATIO,
222 originY + start.GetY() + (paintSize.Height() - checkMarkPaintSize_->Get()) / CHECKBOX_GROUP_DOUBLE_RATIO);
223 path.LineTo(originX + end.GetX() + (paintSize.Width() - checkMarkPaintSize_->Get()) / CHECKBOX_GROUP_DOUBLE_RATIO,
224 originY + end.GetY() + (paintSize.Height() - checkMarkPaintSize_->Get()) / CHECKBOX_GROUP_DOUBLE_RATIO);
225 shadowPen.SetColor(ToRSColor(shadowColor_));
226 shadowPen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
227 shadowPen.SetWidth(checkStroke_->Get() + shadowWidth_.ConvertToPx() * CHECKBOX_GROUP_DOUBLE_RATIO);
228 canvas.AttachPen(shadowPen);
229 canvas.DrawPath(path);
230 pen.SetWidth(checkStroke_->Get());
231 pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
232 canvas.AttachPen(pen);
233 canvas.DrawPath(path);
234 }
235
DrawTouchAndHoverBoard(RSCanvas & canvas,const SizeF & size,const OffsetF & offset) const236 void CheckBoxGroupModifier::DrawTouchAndHoverBoard(RSCanvas& canvas, const SizeF& size, const OffsetF& offset) const
237 {
238 RSBrush brush;
239 brush.SetColor(ToRSColor(animateTouchHoverColor_->Get()));
240 brush.SetAntiAlias(true);
241 float originX = offset.GetX() - hotZoneHorizontalPadding_.ConvertToPx();
242 float originY = offset.GetY() - hotZoneVerticalPadding_.ConvertToPx();
243 float endX = size.Width() + originX + CHECKBOX_GROUP_DOUBLE_RATIO * hotZoneHorizontalPadding_.ConvertToPx();
244 float endY = size.Height() + originY + CHECKBOX_GROUP_DOUBLE_RATIO * hotZoneVerticalPadding_.ConvertToPx();
245 auto rrect = RSRoundRect({ originX, originY, endX, endY }, hoverRadius_.ConvertToPx(), hoverRadius_.ConvertToPx());
246 canvas.AttachBrush(brush);
247 canvas.DrawRoundRect(rrect);
248 }
249 } // namespace OHOS::Ace::NG
250