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
16 #include "core/components_ng/pattern/toggle/switch_paint_method.h"
17
18 #include "core/components_ng/render/drawing_prop_convertor.h"
19
20 namespace OHOS::Ace::NG {
21
22 namespace {
23 } // namespace
24
SwitchModifier(const SizeF & size,const OffsetF & offset,float pointOffset,bool isSelect,const Color & boardColor,const Color & pointColor,float dragOffsetX)25 SwitchModifier::SwitchModifier(const SizeF& size, const OffsetF& offset, float pointOffset, bool isSelect,
26 const Color& boardColor, const Color& pointColor, float dragOffsetX)
27 {
28 animatableBoardColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(boardColor));
29 animateTouchHoverColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(Color::TRANSPARENT));
30 animatePointColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(pointColor));
31 pointOffset_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(pointOffset);
32 dragOffsetX_ = AceType::MakeRefPtr<PropertyFloat>(dragOffsetX);
33 isSelect_ = AceType::MakeRefPtr<PropertyBool>(isSelect);
34 isHover_ = AceType::MakeRefPtr<PropertyBool>(false);
35 isFocused_ = AceType::MakeRefPtr<PropertyBool>(false);
36 isOn_ = AceType::MakeRefPtr<PropertyBool>(false);
37 offset_ = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(offset);
38 size_ = AceType::MakeRefPtr<AnimatablePropertySizeF>(size);
39 useContentModifier_ = AceType::MakeRefPtr<PropertyBool>(false);
40 animatePointRadius_ = AceType::MakeRefPtr<PropertyFloat>(SWITCH_ERROR_RADIUS);
41 animateTrackRadius_ = AceType::MakeRefPtr<PropertyFloat>(SWITCH_ERROR_RADIUS);
42
43 AttachProperty(animatableBoardColor_);
44 AttachProperty(animateTouchHoverColor_);
45 AttachProperty(animatePointColor_);
46 AttachProperty(pointOffset_);
47 AttachProperty(dragOffsetX_);
48 AttachProperty(isSelect_);
49 AttachProperty(isFocused_);
50 AttachProperty(isOn_);
51 AttachProperty(isHover_);
52 AttachProperty(offset_);
53 AttachProperty(size_);
54 AttachProperty(animatePointRadius_);
55 AttachProperty(animateTrackRadius_);
56 }
57
InitializeParam(int32_t themeScopeId)58 void SwitchModifier::InitializeParam(int32_t themeScopeId)
59 {
60 auto pipeline = PipelineBase::GetCurrentContext();
61 CHECK_NULL_VOID(pipeline);
62 auto switchTheme = pipeline->GetTheme<SwitchTheme>();
63 CHECK_NULL_VOID(switchTheme);
64 activeColor_ = switchTheme->GetActiveColor();
65 inactiveColor_ = switchTheme->GetInactiveColor();
66 clickEffectColor_ = switchTheme->GetInteractivePressedColor();
67 hoverColor_ = switchTheme->GetInteractiveHoverColor();
68 userActiveColor_ = activeColor_;
69 hoverDuration_ = switchTheme->GetHoverDuration();
70 hoverToTouchDuration_ = switchTheme->GetHoverToTouchDuration();
71 touchDuration_ = switchTheme->GetTouchDuration();
72 colorAnimationDuration_ = switchTheme->GetColorAnimationDuration();
73 pointAnimationDuration_ = switchTheme->GetPointAnimationDuration();
74 pointColorUnchecked_ = switchTheme->GetPointColorUnchecked();
75 isUseDiffPointColor_ = switchTheme->GetSwitchUseDiffPointColor();
76 focusBoardColor_ = switchTheme->GetFocusBoardColor();
77 isCancelAnimation_ = isUseDiffPointColor_;
78 }
79
CalcActualWidth(float width,float height,double actualGap,double defaultWidthGap)80 float SwitchModifier::CalcActualWidth(float width, float height, double actualGap, double defaultWidthGap)
81 {
82 float result = 0.0f;
83 if (GreatOrEqual(width, height)) {
84 result = (pointRadius_ * NUM_TWO > height ? (width - (actualGap * NUM_TWO)) : width) + defaultWidthGap;
85 } else {
86 result = (pointRadius_ > actualTrackRadius_ ? (width + (pointRadius_ - actualTrackRadius_) * NUM_TWO) : width) +
87 defaultWidthGap;
88 }
89 return result;
90 }
91
PaintSwitch(RSCanvas & canvas,const OffsetF & contentOffset,const SizeF & contentSize)92 void SwitchModifier::PaintSwitch(RSCanvas& canvas, const OffsetF& contentOffset, const SizeF& contentSize)
93 {
94 auto pipelineContext = PipelineBase::GetCurrentContext();
95 CHECK_NULL_VOID(pipelineContext);
96 auto switchTheme = pipelineContext->GetTheme<SwitchTheme>();
97 CHECK_NULL_VOID(switchTheme);
98
99 auto width = contentSize.Width();
100 auto height = contentSize.Height();
101 auto radius = height / 2;
102 auto actualGap = radiusGap_.ConvertToPx() * height /
103 (switchTheme->GetHeight() - switchTheme->GetHotZoneVerticalPadding() * 2).ConvertToPx();
104 auto xOffset = contentOffset.GetX();
105 auto yOffset = contentOffset.GetY();
106 if (animatePointRadius_->Get() < 0) {
107 pointRadius_ = radius - actualGap;
108 } else {
109 pointRadius_ = animatePointRadius_->Get();
110 actualGap = radius - pointRadius_;
111 }
112 auto defaultWidth = switchTheme->GetDefaultWidth().ConvertToPx();
113 auto defaultHeight = switchTheme->GetDefaultHeight().ConvertToPx();
114 auto boardWidth = isFocused_->Get() ? switchTheme->GetFocusBoardWidth() : switchTheme->GetWidth();
115 auto boardHeight = isFocused_->Get() ? switchTheme->GetFocusBoardHeight() : switchTheme->GetHeight();
116 auto defaultWidthGap =
117 defaultWidth - (boardWidth - switchTheme->GetHotZoneHorizontalPadding() * 2).ConvertToPx();
118 auto defaultHeightGap =
119 defaultHeight - (boardHeight - switchTheme->GetHotZoneVerticalPadding() * 2).ConvertToPx();
120 actualWidth_ = CalcActualWidth(width, height, actualGap, defaultWidthGap);
121 actualHeight_ = (pointRadius_ * NUM_TWO > height ? pointRadius_ * NUM_TWO : height) + defaultHeightGap;
122 focusRadius_ = switchTheme->GetFocusBoardRadius();
123 float idealHeight =
124 (switchTheme->GetHeight() - switchTheme->GetHotZoneVerticalPadding() * NUM_TWO).ConvertToPx();
125 float boardIdealHeight =
126 (switchTheme->GetFocusBoardHeight() - switchTheme->GetHotZoneVerticalPadding() * NUM_TWO).ConvertToPx();
127 if (animateTrackRadius_->Get() < 0 && !NearZero(idealHeight)) {
128 focusRadius_ = focusRadius_ * height / idealHeight + switchTheme->GetFocusPaintPadding();
129 } else if (!NearZero(boardIdealHeight)) {
130 focusRadius_ = focusRadius_ * height / boardIdealHeight + switchTheme->GetFocusPaintPadding();
131 }
132
133 OffsetF hoverBoardOffset;
134 hoverBoardOffset.SetX(xOffset - (actualWidth_ - width) / 2.0);
135 hoverBoardOffset.SetY(yOffset - (actualHeight_ - height) / 2.0);
136
137 OffsetF focusBoardOffset = hoverBoardOffset;
138 DrawFocusBoard(canvas, focusBoardOffset);
139 DrawRectCircle(canvas, contentOffset, contentSize, actualGap);
140 }
141
DrawRectCircle(RSCanvas & canvas,const OffsetF & contentOffset,const SizeF & contentSize,const double & actualGap)142 void SwitchModifier::DrawRectCircle(RSCanvas& canvas, const OffsetF& contentOffset, const SizeF& contentSize,
143 const double& actualGap)
144 {
145 auto xOffset = contentOffset.GetX();
146 auto yOffset = contentOffset.GetY();
147 auto height = contentSize.Height();
148 auto trackRadius =
149 (animateTrackRadius_->Get() < 0) ? height / NUM_TWO : animateTrackRadius_->Get();
150 RSRect rect = RSRect(xOffset, yOffset, xOffset + contentSize.Width(), yOffset + height);
151 RSRoundRect roundRect(rect, trackRadius, trackRadius);
152
153 RSBrush brush;
154 brush.SetColor(ToRSColor(animatableBoardColor_->Get()));
155 SetIsFocusOrBlur(false);
156 brush.SetBlendMode(RSBlendMode::SRC_OVER);
157 brush.SetAntiAlias(true);
158 canvas.AttachBrush(brush);
159 canvas.DrawRoundRect(roundRect);
160 canvas.DetachBrush();
161 brush.SetColor(ToRSColor(animateTouchHoverColor_->Get()));
162 canvas.AttachBrush(brush);
163 canvas.DrawRoundRect(roundRect);
164 canvas.DetachBrush();
165
166 brush.SetColor(ToRSColor(animatePointColor_->Get()));
167 if (isUseDiffPointColor_ && !hasPointColor_) {
168 if (isFocused_->Get()) {
169 brush.SetColor(ToRSColor(isSelect_->Get() ? animatePointColor_->Get() : LinearColor(pointColor_)));
170 } else {
171 brush.SetColor(ToRSColor(isSelect_->Get() ? animatePointColor_->Get() : LinearColor(pointColorUnchecked_)));
172 }
173 }
174 brush.SetAntiAlias(true);
175 canvas.AttachBrush(brush);
176 RSPoint point;
177 if (GreatOrEqual(contentSize.Width(), contentSize.Height())) {
178 point.SetX(xOffset + actualGap + pointRadius_ + pointOffset_->Get());
179 } else {
180 point.SetX(xOffset + pointOffset_->Get());
181 }
182 point.SetY(yOffset + height / NUM_TWO);
183 canvas.DrawCircle(point, pointRadius_);
184 canvas.DetachBrush();
185 }
186
DrawFocusBoard(RSCanvas & canvas,const OffsetF & offset)187 void SwitchModifier::DrawFocusBoard(RSCanvas& canvas, const OffsetF& offset)
188 {
189 if (!isFocused_->Get()) {
190 return;
191 }
192 auto rightBottomX = offset.GetX() + actualWidth_;
193 auto rightBottomY = offset.GetY() + actualHeight_;
194 auto rrect = RSRoundRect({ offset.GetX(), offset.GetY(), rightBottomX, rightBottomY }, focusRadius_.ConvertToPx(),
195 focusRadius_.ConvertToPx());
196 RSBrush brush;
197 brush.SetColor(ToRSColor(focusBoardColor_));
198 brush.SetAntiAlias(true);
199 canvas.AttachBrush(brush);
200 canvas.DrawRoundRect(rrect);
201 canvas.DetachBrush();
202 }
203
GetSwitchWidth(const SizeF & contentSize) const204 float SwitchModifier::GetSwitchWidth(const SizeF& contentSize) const
205 {
206 const float switchGap = 2.0f;
207 auto pipelineContext = PipelineBase::GetCurrentContext();
208 CHECK_NULL_RETURN(pipelineContext, false);
209 auto switchTheme = pipelineContext->GetTheme<SwitchTheme>();
210 auto actualGap = switchGap * contentSize.Height() /
211 (switchTheme->GetHeight() - switchTheme->GetHotZoneVerticalPadding() * 2).ConvertToPx();
212 auto switchWidth = contentSize.Width() - contentSize.Height() + actualGap;
213 return switchWidth;
214 }
215
GetThemeScopeId(PaintWrapper * paintWrapper) const216 int32_t SwitchPaintMethod::GetThemeScopeId(PaintWrapper* paintWrapper) const
217 {
218 const int32_t defaultThemeScopeId = 0;
219 CHECK_NULL_RETURN(paintWrapper, defaultThemeScopeId);
220 auto renderContext = paintWrapper->GetRenderContext();
221 CHECK_NULL_RETURN(renderContext, defaultThemeScopeId);
222 auto host = renderContext->GetHost();
223 CHECK_NULL_RETURN(host, defaultThemeScopeId);
224 return host->GetThemeScopeId();
225 }
226 } // namespace OHOS::Ace::NG
227