• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,const SizeF & size,const OffsetF & offset,float checkStroke,float strokeSize)47 CheckBoxModifier::CheckBoxModifier(bool isSelect, const Color& boardColor, const Color& checkColor,
48     const Color& borderColor, const Color& shadowColor, const SizeF& size, const OffsetF& offset, float checkStroke,
49     float strokeSize)
50 {
51     animatableBoardColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(boardColor));
52     animatableCheckColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(checkColor));
53     animatableBorderColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(borderColor));
54     animatableShadowColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(shadowColor));
55     checkStroke_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(checkStroke);
56     strokeSize_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(strokeSize);
57     offset_ = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(offset);
58     size_ = AceType::MakeRefPtr<AnimatablePropertySizeF>(size);
59     animateTouchHoverColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(Color::TRANSPARENT));
60 
61     isSelect_ = AceType::MakeRefPtr<PropertyBool>(isSelect);
62     enabled_ = AceType::MakeRefPtr<PropertyBool>(true);
63     hasBuilder_ = AceType::MakeRefPtr<PropertyBool>(false);
64     useContentModifier_ = AceType::MakeRefPtr<PropertyBool>(false);
65     checkBoxShape_ = AceType::MakeRefPtr<PropertyInt>(static_cast<int32_t>(CheckBoxStyle::CIRCULAR_STYLE));
66 
67     AttachProperty(animatableBoardColor_);
68     AttachProperty(animatableCheckColor_);
69     AttachProperty(animatableBorderColor_);
70     AttachProperty(animatableShadowColor_);
71     AttachProperty(animateTouchHoverColor_);
72     AttachProperty(checkStroke_);
73     AttachProperty(strokeSize_);
74     AttachProperty(isSelect_);
75     AttachProperty(offset_);
76     AttachProperty(size_);
77     AttachProperty(enabled_);
78     AttachProperty(hasBuilder_);
79     AttachProperty(checkBoxShape_);
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     defaultPaddingSize_ = checkBoxTheme->GetDefaultPaddingSize();
101     shadowWidth_ = checkBoxTheme->GetShadowWidth();
102     userActiveColor_ = activeColor_;
103     hoverDuration_ = checkBoxTheme->GetHoverDuration();
104     hoverToTouchDuration_ = checkBoxTheme->GetHoverToTouchDuration();
105     touchDuration_ = checkBoxTheme->GetTouchDuration();
106     colorAnimationDuration_ = checkBoxTheme->GetColorAnimationDuration();
107 }
108 
PaintCheckBox(RSCanvas & canvas,const OffsetF & paintOffset,const SizeF & contentSize) const109 void CheckBoxModifier::PaintCheckBox(RSCanvas& canvas, const OffsetF& paintOffset, const SizeF& contentSize) const
110 {
111     RSPen pen;
112     RSBrush brush;
113     pen.SetWidth(borderWidth_);
114     pen.SetAntiAlias(true);
115     DrawTouchAndHoverBoard(canvas, contentSize, paintOffset);
116     RSPen shadowPen = RSPen(pen);
117     brush.SetColor(ToRSColor(animatableBoardColor_->Get()));
118     brush.SetAntiAlias(true);
119     if (!enabled_->Get()) {
120         brush.SetColor(
121             ToRSColor(animatableBoardColor_->Get().BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
122     }
123     DrawBackboard(canvas, paintOffset, brush, contentSize);
124     pen.SetColor(ToRSColor(animatableBorderColor_->Get()));
125     if (!enabled_->Get()) {
126         pen.SetColor(
127             ToRSColor(animatableBorderColor_->Get().BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
128     }
129     if (enabled_->Get() || !isSelect_->Get()) {
130         DrawBorder(canvas, paintOffset, pen, contentSize);
131     }
132     pen.SetColor(ToRSColor(animatableCheckColor_->Get()));
133     shadowPen.SetColor(ToRSColor(animatableShadowColor_->Get()));
134     if (!hasBuilder_->Get()) {
135         DrawCheck(canvas, paintOffset, pen, shadowPen, contentSize);
136     }
137 }
138 
DrawTouchAndHoverBoard(RSCanvas & canvas,const SizeF & size,const OffsetF & offset) const139 void CheckBoxModifier::DrawTouchAndHoverBoard(RSCanvas& canvas, const SizeF& size, const OffsetF& offset) const
140 {
141     if (HoverEffectType::NONE == hoverEffectType_) {
142         return;
143     }
144     RSBrush brush;
145     brush.SetColor(ToRSColor(animateTouchHoverColor_->Get()));
146     brush.SetAntiAlias(true);
147     float originX;
148     float originY;
149     float endX;
150     float endY;
151     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
152         originX = offset.GetX() - defaultPaddingSize_.ConvertToPx();
153         originY = offset.GetY() - defaultPaddingSize_.ConvertToPx();
154         endX = size.Width() + originX + CHECKBOX_DOUBLE_RATIO * defaultPaddingSize_.ConvertToPx();
155         endY = size.Height() + originY + CHECKBOX_DOUBLE_RATIO * defaultPaddingSize_.ConvertToPx();
156     } else {
157         originX = offset.GetX() - hotZoneHorizontalPadding_.ConvertToPx();
158         originY = offset.GetY() - hotZoneVerticalPadding_.ConvertToPx();
159         endX = size.Width() + originX + CHECKBOX_DOUBLE_RATIO * hotZoneHorizontalPadding_.ConvertToPx();
160         endY = size.Height() + originY + CHECKBOX_DOUBLE_RATIO * hotZoneVerticalPadding_.ConvertToPx();
161     }
162     auto rrect = RSRoundRect({ originX, originY, endX, endY }, hoverRadius_.ConvertToPx(), hoverRadius_.ConvertToPx());
163     canvas.AttachBrush(brush);
164     if (CheckBoxStyle::SQUARE_STYLE == checkBoxStyle_) {
165         canvas.DrawRoundRect(rrect);
166     } else {
167         RSScalar halfDenominator = 2.0f;
168         RSScalar radius = 0.0f;
169         RSRect rect = rrect.GetRect();
170         RSScalar x = (rect.GetLeft() + rect.GetRight()) / halfDenominator;
171         RSScalar y = (rect.GetTop() + rect.GetBottom()) / halfDenominator;
172         RSPoint centerPt(x, y);
173         if (rect.GetWidth() > rect.GetHeight()) {
174             radius = rect.GetHeight() / halfDenominator;
175         } else {
176             radius = rect.GetWidth() / halfDenominator;
177         }
178         canvas.DrawCircle(centerPt, radius);
179     }
180     canvas.DetachBrush();
181 }
182 
DrawBorder(RSCanvas & canvas,const OffsetF & origin,RSPen & pen,const SizeF & paintSize) const183 void CheckBoxModifier::DrawBorder(RSCanvas& canvas, const OffsetF& origin, RSPen& pen, const SizeF& paintSize) const
184 {
185     float originX = origin.GetX() + borderWidth_ / CHECKBOX_DOUBLE_RATIO;
186     float originY = origin.GetY() + borderWidth_ / CHECKBOX_DOUBLE_RATIO;
187     float endX = originX + paintSize.Width() - borderWidth_;
188     float endY = originY + paintSize.Height() - borderWidth_;
189     auto rrect = RSRoundRect({ originX, originY, endX, endY }, borderRadius_, borderRadius_);
190     canvas.AttachPen(pen);
191     if (CheckBoxStyle::SQUARE_STYLE == checkBoxStyle_) {
192         canvas.DrawRoundRect(rrect);
193     } else {
194         RSScalar halfDenominator = 2.0f;
195         RSScalar radius = 0.0f;
196         RSRect rect = rrect.GetRect();
197         RSScalar x = (rect.GetLeft() + rect.GetRight()) / halfDenominator;
198         RSScalar y = (rect.GetTop() + rect.GetBottom()) / halfDenominator;
199         RSPoint centerPt(x, y);
200         if (rect.GetWidth() > rect.GetHeight()) {
201             radius = rect.GetHeight() / halfDenominator;
202         } else {
203             radius = rect.GetWidth() / halfDenominator;
204         }
205         canvas.DrawCircle(centerPt, radius);
206     }
207     canvas.DetachPen();
208 }
209 
DrawBackboard(RSCanvas & canvas,const OffsetF & origin,RSBrush & brush,const SizeF & paintSize) const210 void CheckBoxModifier::DrawBackboard(
211     RSCanvas& canvas, const OffsetF& origin, RSBrush& brush, const SizeF& paintSize) const
212 {
213     float originX = origin.GetX();
214     float originY = origin.GetY();
215     float endX = originX + paintSize.Width();
216     float endY = originY + paintSize.Height();
217     auto rrect = RSRoundRect({ originX, originY, endX, endY }, borderRadius_, borderRadius_);
218     canvas.AttachBrush(brush);
219     if (CheckBoxStyle::SQUARE_STYLE == checkBoxStyle_) {
220         canvas.DrawRoundRect(rrect);
221     } else {
222         RSScalar halfDenominator = 2.0f;
223         RSScalar radius = 0.0f;
224         RSRect rect = rrect.GetRect();
225         RSScalar x = (rect.GetLeft() + rect.GetRight()) / halfDenominator;
226         RSScalar y = (rect.GetTop() + rect.GetBottom()) / halfDenominator;
227         RSPoint centerPt(x, y);
228         if (rect.GetWidth() > rect.GetHeight()) {
229             radius = rect.GetHeight() / halfDenominator;
230         } else {
231             radius = rect.GetWidth() / halfDenominator;
232         }
233         canvas.DrawCircle(centerPt, radius);
234     }
235     canvas.DetachBrush();
236 }
237 
DrawCheck(RSCanvas & canvas,const OffsetF & origin,RSPen & pen,RSPen & shadowPen,const SizeF & paintSize) const238 void CheckBoxModifier::DrawCheck(
239     RSCanvas& canvas, const OffsetF& origin, RSPen& pen, RSPen& shadowPen, const SizeF& paintSize) const
240 {
241     if (strokeSize_->Get() == CHECKBOX_LENGTH_ZERO || checkStroke_->Get() == CHECKBOX_LENGTH_ZERO) {
242         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "checkbox draw check zero %{public}f %{public}f", strokeSize_->Get(),
243             checkStroke_->Get());
244         return;
245     }
246 #ifndef USE_ROSEN_DRAWING
247     RSPath path;
248 #else
249     RSRecordingPath path;
250 #endif
251     float originX = origin.GetX();
252     float originY = origin.GetY();
253     float strokeSize = strokeSize_->Get();
254     const Offset start = Offset(strokeSize * CHECK_MARK_START_X_POSITION, strokeSize * CHECK_MARK_START_Y_POSITION);
255     const Offset middle = Offset(strokeSize * CHECK_MARK_MIDDLE_X_POSITION, strokeSize * CHECK_MARK_MIDDLE_Y_POSITION);
256     const Offset end = Offset(strokeSize * CHECK_MARK_END_X_POSITION, strokeSize * CHECK_MARK_END_Y_POSITION);
257     path.MoveTo(originX + start.GetX() + (paintSize.Width() - strokeSize) / CHECKBOX_DOUBLE_RATIO,
258         originY + start.GetY() + (paintSize.Height() - strokeSize) / CHECKBOX_DOUBLE_RATIO);
259     path.LineTo(originX + middle.GetX() + (paintSize.Width() - strokeSize) / CHECKBOX_DOUBLE_RATIO,
260         originY + middle.GetY() + (paintSize.Height() - strokeSize) / CHECKBOX_DOUBLE_RATIO);
261     path.MoveTo(originX + middle.GetX() + (paintSize.Width() - strokeSize) / CHECKBOX_DOUBLE_RATIO,
262         originY + middle.GetY() + (paintSize.Height() - strokeSize) / CHECKBOX_DOUBLE_RATIO);
263     path.LineTo(originX + end.GetX() + (paintSize.Width() - strokeSize) / CHECKBOX_DOUBLE_RATIO,
264         originY + end.GetY() + (paintSize.Height() - strokeSize) / CHECKBOX_DOUBLE_RATIO);
265     shadowPen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
266     shadowPen.SetWidth(checkStroke_->Get() + shadowWidth_.ConvertToPx() * CHECKBOX_DOUBLE_RATIO);
267     pen.SetWidth(checkStroke_->Get());
268     pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
269     canvas.AttachPen(shadowPen);
270     canvas.DrawPath(path);
271     canvas.DetachPen();
272     canvas.AttachPen(pen);
273     canvas.DrawPath(path);
274     canvas.DetachPen();
275 }
276 
277 } // namespace OHOS::Ace::NG
278