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