1 /*
2 * Copyright (c) 2022-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 #include "core/components_ng/pattern/checkbox/checkbox_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/checkbox/checkbox_paint_property.h"
29 #include "core/components_ng/pattern/checkbox/checkbox_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 CHECKBOX_DOUBLE_RATIO = 2.0f;
44 constexpr float CHECKBOX_LENGTH_ZERO = 0.0f;
45 } // namespace
46
CheckBoxModifier(bool isSelect,const Color & boardColor,const Color & checkColor,const Color & borderColor,const Color & shadowColor)47 CheckBoxModifier::CheckBoxModifier(
48 bool isSelect, const Color& boardColor, const Color& checkColor, const Color& borderColor, const Color& shadowColor)
49 {
50 auto pipeline = PipelineBase::GetCurrentContext();
51 CHECK_NULL_VOID(pipeline);
52 auto checkBoxTheme = pipeline->GetTheme<CheckboxTheme>();
53 CHECK_NULL_VOID(checkBoxTheme);
54
55 animatableBoardColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(boardColor));
56 animatableCheckColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(checkColor));
57 animatableBorderColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(borderColor));
58 animatableShadowColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(shadowColor));
59 checkStroke_ =
60 AceType::MakeRefPtr<AnimatablePropertyFloat>(static_cast<float>(checkBoxTheme->GetCheckStroke().ConvertToPx()));
61 strokeSize_ =
62 AceType::MakeRefPtr<AnimatablePropertyFloat>(static_cast<float>(checkBoxTheme->GetWidth().ConvertToPx()));
63 animateTouchHoverColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(Color::TRANSPARENT));
64 isSelect_ = AceType::MakeRefPtr<PropertyBool>(isSelect);
65 offset_ = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(OffsetF());
66 size_ = AceType::MakeRefPtr<AnimatablePropertySizeF>(SizeF());
67 enabled_ = AceType::MakeRefPtr<PropertyBool>(true);
68
69 AttachProperty(animatableBoardColor_);
70 AttachProperty(animatableCheckColor_);
71 AttachProperty(animatableBorderColor_);
72 AttachProperty(animatableShadowColor_);
73 AttachProperty(animateTouchHoverColor_);
74 AttachProperty(checkStroke_);
75 AttachProperty(strokeSize_);
76 AttachProperty(isSelect_);
77 AttachProperty(offset_);
78 AttachProperty(size_);
79 AttachProperty(enabled_);
80 }
81
InitializeParam()82 void CheckBoxModifier::InitializeParam()
83 {
84 auto pipeline = PipelineBase::GetCurrentContext();
85 CHECK_NULL_VOID(pipeline);
86 auto checkBoxTheme = pipeline->GetTheme<CheckboxTheme>();
87 CHECK_NULL_VOID(checkBoxTheme);
88 borderWidth_ = checkBoxTheme->GetBorderWidth().ConvertToPx();
89 borderRadius_ = checkBoxTheme->GetBorderRadius().ConvertToPx();
90 pointColor_ = checkBoxTheme->GetPointColor();
91 activeColor_ = checkBoxTheme->GetActiveColor();
92 inactiveColor_ = checkBoxTheme->GetInactiveColor();
93 inactivePointColor_ = checkBoxTheme->GetInactivePointColor();
94 shadowColor_ = checkBoxTheme->GetShadowColor();
95 clickEffectColor_ = checkBoxTheme->GetClickEffectColor();
96 hoverColor_ = checkBoxTheme->GetHoverColor();
97 hoverRadius_ = checkBoxTheme->GetHoverRadius();
98 hotZoneHorizontalPadding_ = checkBoxTheme->GetHotZoneHorizontalPadding();
99 hotZoneVerticalPadding_ = checkBoxTheme->GetHotZoneVerticalPadding();
100 shadowWidth_ = checkBoxTheme->GetShadowWidth();
101 userActiveColor_ = activeColor_;
102 hoverDuration_ = checkBoxTheme->GetHoverDuration();
103 hoverToTouchDuration_ = checkBoxTheme->GetHoverToTouchDuration();
104 touchDuration_ = checkBoxTheme->GetTouchDuration();
105 colorAnimationDuration_ = checkBoxTheme->GetColorAnimationDuration();
106 }
107
PaintCheckBox(RSCanvas & canvas,const OffsetF & paintOffset,const SizeF & contentSize) const108 void CheckBoxModifier::PaintCheckBox(RSCanvas& canvas, const OffsetF& paintOffset, const SizeF& contentSize) const
109 {
110 RSPen pen;
111 RSBrush brush;
112 pen.SetWidth(borderWidth_);
113 pen.SetAntiAlias(true);
114 DrawTouchAndHoverBoard(canvas, contentSize, paintOffset);
115 RSPen shadowPen = RSPen(pen);
116 brush.SetColor(ToRSColor(animatableBoardColor_->Get()));
117 brush.SetAntiAlias(true);
118 if (!enabled_->Get()) {
119 brush.SetColor(
120 ToRSColor(animatableBoardColor_->Get().BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
121 }
122 DrawBackboard(canvas, paintOffset, brush, contentSize);
123 pen.SetColor(ToRSColor(animatableBorderColor_->Get()));
124 if (!enabled_->Get()) {
125 pen.SetColor(
126 ToRSColor(animatableBorderColor_->Get().BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
127 }
128 if (enabled_->Get() || !isSelect_->Get()) {
129 DrawBorder(canvas, paintOffset, pen, contentSize);
130 }
131 pen.SetColor(ToRSColor(animatableCheckColor_->Get()));
132 shadowPen.SetColor(ToRSColor(animatableShadowColor_->Get()));
133 DrawCheck(canvas, paintOffset, pen, shadowPen, contentSize);
134 }
135
DrawTouchAndHoverBoard(RSCanvas & canvas,const SizeF & size,const OffsetF & offset) const136 void CheckBoxModifier::DrawTouchAndHoverBoard(RSCanvas& canvas, const SizeF& size, const OffsetF& offset) const
137 {
138 RSBrush brush;
139 brush.SetColor(ToRSColor(animateTouchHoverColor_->Get()));
140 brush.SetAntiAlias(true);
141 float originX = offset.GetX() - hotZoneHorizontalPadding_.ConvertToPx();
142 float originY = offset.GetY() - hotZoneVerticalPadding_.ConvertToPx();
143 float endX = size.Width() + originX + CHECKBOX_DOUBLE_RATIO * hotZoneHorizontalPadding_.ConvertToPx();
144 float endY = size.Height() + originY + CHECKBOX_DOUBLE_RATIO * hotZoneVerticalPadding_.ConvertToPx();
145 auto rrect = RSRoundRect({ originX, originY, endX, endY }, hoverRadius_.ConvertToPx(), hoverRadius_.ConvertToPx());
146 canvas.AttachBrush(brush);
147 canvas.DrawRoundRect(rrect);
148 }
149
DrawBorder(RSCanvas & canvas,const OffsetF & origin,RSPen & pen,const SizeF & paintSize) const150 void CheckBoxModifier::DrawBorder(RSCanvas& canvas, const OffsetF& origin, RSPen& pen, const SizeF& paintSize) const
151 {
152 float originX = origin.GetX() + borderWidth_ / CHECKBOX_DOUBLE_RATIO;
153 float originY = origin.GetY() + borderWidth_ / CHECKBOX_DOUBLE_RATIO;
154 float endX = originX + paintSize.Width() - borderWidth_;
155 float endY = originY + paintSize.Height() - borderWidth_;
156 auto rrect = RSRoundRect({ originX, originY, endX, endY }, borderRadius_, borderRadius_);
157 canvas.AttachPen(pen);
158 canvas.DrawRoundRect(rrect);
159 }
160
DrawBackboard(RSCanvas & canvas,const OffsetF & origin,RSBrush & brush,const SizeF & paintSize) const161 void CheckBoxModifier::DrawBackboard(
162 RSCanvas& canvas, const OffsetF& origin, RSBrush& brush, const SizeF& paintSize) const
163 {
164 float originX = origin.GetX();
165 float originY = origin.GetY();
166 float endX = originX + paintSize.Width();
167 float endY = originY + paintSize.Height();
168 auto rrect = RSRoundRect({ originX, originY, endX, endY }, borderRadius_, borderRadius_);
169 canvas.AttachBrush(brush);
170 canvas.DrawRoundRect(rrect);
171 }
172
DrawCheck(RSCanvas & canvas,const OffsetF & origin,RSPen & pen,RSPen & shadowPen,const SizeF & paintSize) const173 void CheckBoxModifier::DrawCheck(
174 RSCanvas& canvas, const OffsetF& origin, RSPen& pen, RSPen& shadowPen, const SizeF& paintSize) const
175 {
176 if (strokeSize_->Get() == CHECKBOX_LENGTH_ZERO || checkStroke_->Get() == CHECKBOX_LENGTH_ZERO) {
177 return;
178 }
179 RSPath path;
180 float originX = origin.GetX();
181 float originY = origin.GetY();
182 float strokeSize = strokeSize_->Get();
183 const Offset start = Offset(strokeSize * CHECK_MARK_START_X_POSITION, strokeSize * CHECK_MARK_START_Y_POSITION);
184 const Offset middle = Offset(strokeSize * CHECK_MARK_MIDDLE_X_POSITION, strokeSize * CHECK_MARK_MIDDLE_Y_POSITION);
185 const Offset end = Offset(strokeSize * CHECK_MARK_END_X_POSITION, strokeSize * CHECK_MARK_END_Y_POSITION);
186 path.MoveTo(originX + start.GetX() + (paintSize.Width() - strokeSize) / CHECKBOX_DOUBLE_RATIO,
187 originY + start.GetY() + (paintSize.Height() - strokeSize) / CHECKBOX_DOUBLE_RATIO);
188 path.LineTo(originX + middle.GetX() + (paintSize.Width() - strokeSize) / CHECKBOX_DOUBLE_RATIO,
189 originY + middle.GetY() + (paintSize.Height() - strokeSize) / CHECKBOX_DOUBLE_RATIO);
190 path.MoveTo(originX + middle.GetX() + (paintSize.Width() - strokeSize) / CHECKBOX_DOUBLE_RATIO,
191 originY + middle.GetY() + (paintSize.Height() - strokeSize) / CHECKBOX_DOUBLE_RATIO);
192 path.LineTo(originX + end.GetX() + (paintSize.Width() - strokeSize) / CHECKBOX_DOUBLE_RATIO,
193 originY + end.GetY() + (paintSize.Height() - strokeSize) / CHECKBOX_DOUBLE_RATIO);
194 shadowPen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
195 shadowPen.SetWidth(checkStroke_->Get() + shadowWidth_.ConvertToPx() * CHECKBOX_DOUBLE_RATIO);
196 pen.SetWidth(checkStroke_->Get());
197 pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
198 canvas.AttachPen(shadowPen);
199 canvas.DrawPath(path);
200 canvas.AttachPen(pen);
201 canvas.DrawPath(path);
202 }
203
204 } // namespace OHOS::Ace::NG
205