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 focusColor_ = switchTheme->GetFocusedBGColorUnselected();
69 userActiveColor_ = activeColor_;
70 hoverDuration_ = switchTheme->GetHoverDuration();
71 hoverToTouchDuration_ = switchTheme->GetHoverToTouchDuration();
72 touchDuration_ = switchTheme->GetTouchDuration();
73 colorAnimationDuration_ = switchTheme->GetColorAnimationDuration();
74 pointAnimationDuration_ = switchTheme->GetPointAnimationDuration();
75 pointColorUnchecked_ = switchTheme->GetPointColorUnchecked();
76 isUseDiffPointColor_ = switchTheme->GetSwitchUseDiffPointColor();
77 focusBoardColor_ = switchTheme->GetFocusBoardColor();
78 isCancelAnimation_ = isUseDiffPointColor_;
79 }
80
CalcActualWidth(float width,float height,double actualGap,double defaultWidthGap)81 float SwitchModifier::CalcActualWidth(float width, float height, double actualGap, double defaultWidthGap)
82 {
83 float result = 0.0f;
84 if (GreatOrEqual(width, height)) {
85 result = (pointRadius_ * NUM_TWO > height ? (width - (actualGap * NUM_TWO)) : width) + defaultWidthGap;
86 } else {
87 result = (pointRadius_ > actualTrackRadius_ ? (width + (pointRadius_ - actualTrackRadius_) * NUM_TWO) : width) +
88 defaultWidthGap;
89 }
90 return result;
91 }
92
PaintSwitch(RSCanvas & canvas,const OffsetF & contentOffset,const SizeF & contentSize)93 void SwitchModifier::PaintSwitch(RSCanvas& canvas, const OffsetF& contentOffset, const SizeF& contentSize)
94 {
95 auto pipelineContext = PipelineBase::GetCurrentContext();
96 CHECK_NULL_VOID(pipelineContext);
97 auto switchTheme = pipelineContext->GetTheme<SwitchTheme>();
98 CHECK_NULL_VOID(switchTheme);
99
100 auto width = contentSize.Width();
101 auto height = contentSize.Height();
102 auto radius = height / 2;
103 auto actualGap = radiusGap_.ConvertToPx() * height /
104 (switchTheme->GetHeight() - switchTheme->GetHotZoneVerticalPadding() * 2).ConvertToPx();
105 auto xOffset = contentOffset.GetX();
106 auto yOffset = contentOffset.GetY();
107 if (animatePointRadius_->Get() < 0) {
108 pointRadius_ = radius - actualGap;
109 } else {
110 pointRadius_ = animatePointRadius_->Get();
111 actualGap = radius - pointRadius_;
112 }
113 auto defaultWidth = switchTheme->GetDefaultWidth().ConvertToPx();
114 auto defaultHeight = switchTheme->GetDefaultHeight().ConvertToPx();
115 auto boardWidth = isFocused_->Get() ? switchTheme->GetFocusBoardWidth() : switchTheme->GetWidth();
116 auto boardHeight = isFocused_->Get() ? switchTheme->GetFocusBoardHeight() : switchTheme->GetHeight();
117 auto defaultWidthGap =
118 defaultWidth - (boardWidth - switchTheme->GetHotZoneHorizontalPadding() * 2).ConvertToPx();
119 auto defaultHeightGap =
120 defaultHeight - (boardHeight - switchTheme->GetHotZoneVerticalPadding() * 2).ConvertToPx();
121 actualWidth_ = CalcActualWidth(width, height, actualGap, defaultWidthGap);
122 actualHeight_ = (pointRadius_ * NUM_TWO > height ? pointRadius_ * NUM_TWO : height) + defaultHeightGap;
123 focusRadius_ = switchTheme->GetFocusBoardRadius();
124 float idealHeight =
125 (switchTheme->GetHeight() - switchTheme->GetHotZoneVerticalPadding() * NUM_TWO).ConvertToPx();
126 float boardIdealHeight =
127 (switchTheme->GetFocusBoardHeight() - switchTheme->GetHotZoneVerticalPadding() * NUM_TWO).ConvertToPx();
128 if (animateTrackRadius_->Get() < 0 && !NearZero(idealHeight)) {
129 focusRadius_ = focusRadius_ * height / idealHeight + switchTheme->GetFocusPaintPadding();
130 } else if (!NearZero(boardIdealHeight)) {
131 focusRadius_ = focusRadius_ * height / boardIdealHeight + switchTheme->GetFocusPaintPadding();
132 }
133
134 OffsetF hoverBoardOffset;
135 hoverBoardOffset.SetX(xOffset - (actualWidth_ - width) / 2.0);
136 hoverBoardOffset.SetY(yOffset - (actualHeight_ - height) / 2.0);
137
138 OffsetF focusBoardOffset = hoverBoardOffset;
139 DrawFocusBoard(canvas, focusBoardOffset);
140 DrawRectCircle(canvas, contentOffset, contentSize, actualGap);
141 }
142
DrawRectCircle(RSCanvas & canvas,const OffsetF & contentOffset,const SizeF & contentSize,const double & actualGap)143 void SwitchModifier::DrawRectCircle(RSCanvas& canvas, const OffsetF& contentOffset, const SizeF& contentSize,
144 const double& actualGap)
145 {
146 auto xOffset = contentOffset.GetX();
147 auto yOffset = contentOffset.GetY();
148 auto height = contentSize.Height();
149 auto trackRadius =
150 (animateTrackRadius_->Get() < 0) ? height / NUM_TWO : animateTrackRadius_->Get();
151 RSRect rect = RSRect(xOffset, yOffset, xOffset + contentSize.Width(), yOffset + height);
152 RSRoundRect roundRect(rect, trackRadius, trackRadius);
153
154 RSBrush brush;
155 brush.SetColor(ToRSColor(animatableBoardColor_->Get()));
156 SetIsFocusOrBlur(false);
157 brush.SetBlendMode(RSBlendMode::SRC_OVER);
158 brush.SetAntiAlias(true);
159 canvas.AttachBrush(brush);
160 canvas.DrawRoundRect(roundRect);
161 canvas.DetachBrush();
162 brush.SetColor(ToRSColor(animateTouchHoverColor_->Get()));
163 canvas.AttachBrush(brush);
164 canvas.DrawRoundRect(roundRect);
165 canvas.DetachBrush();
166
167 brush.SetColor(ToRSColor(animatePointColor_->Get()));
168 if (isUseDiffPointColor_ && !hasPointColor_) {
169 if (isFocused_->Get()) {
170 brush.SetColor(ToRSColor(isSelect_->Get() ? animatePointColor_->Get() : LinearColor(pointColor_)));
171 } else {
172 brush.SetColor(ToRSColor(isSelect_->Get() ? animatePointColor_->Get() : LinearColor(pointColorUnchecked_)));
173 }
174 }
175 brush.SetAntiAlias(true);
176 canvas.AttachBrush(brush);
177 RSPoint point;
178 if (GreatOrEqual(contentSize.Width(), contentSize.Height())) {
179 point.SetX(xOffset + actualGap + pointRadius_ + pointOffset_->Get());
180 } else {
181 point.SetX(xOffset + pointOffset_->Get());
182 }
183 point.SetY(yOffset + height / NUM_TWO);
184 canvas.DrawCircle(point, pointRadius_);
185 canvas.DetachBrush();
186 }
187
DrawFocusBoard(RSCanvas & canvas,const OffsetF & offset)188 void SwitchModifier::DrawFocusBoard(RSCanvas& canvas, const OffsetF& offset)
189 {
190 if (!isFocused_->Get()) {
191 return;
192 }
193 auto rightBottomX = offset.GetX() + actualWidth_;
194 auto rightBottomY = offset.GetY() + actualHeight_;
195 auto rrect = RSRoundRect({ offset.GetX(), offset.GetY(), rightBottomX, rightBottomY }, focusRadius_.ConvertToPx(),
196 focusRadius_.ConvertToPx());
197 RSBrush brush;
198 brush.SetColor(ToRSColor(focusBoardColor_));
199 brush.SetAntiAlias(true);
200 canvas.AttachBrush(brush);
201 canvas.DrawRoundRect(rrect);
202 canvas.DetachBrush();
203 }
204
GetSwitchWidth(const SizeF & contentSize) const205 float SwitchModifier::GetSwitchWidth(const SizeF& contentSize) const
206 {
207 const float switchGap = 2.0f;
208 auto pipelineContext = PipelineBase::GetCurrentContext();
209 CHECK_NULL_RETURN(pipelineContext, false);
210 auto switchTheme = pipelineContext->GetTheme<SwitchTheme>();
211 auto actualGap = switchGap * contentSize.Height() /
212 (switchTheme->GetHeight() - switchTheme->GetHotZoneVerticalPadding() * 2).ConvertToPx();
213 auto switchWidth = contentSize.Width() - contentSize.Height() + actualGap;
214 return switchWidth;
215 }
216
FixPointOffset()217 void SwitchModifier::FixPointOffset()
218 {
219 if (!isSizeChange_) {
220 return;
221 }
222 auto currentOffset = pointOffset_->Get();
223 if (GreatOrEqual(actualSize_.Width(), actualSize_.Height())) {
224 if (currentOffset > actualSize_.Width() - actualSize_.Height()) {
225 pointOffset_->Set(actualSize_.Width() - actualSize_.Height());
226 }
227 } else {
228 if (currentOffset > actualSize_.Width() - actualTrackRadius_) {
229 pointOffset_->Set(actualSize_.Width() - actualTrackRadius_);
230 }
231 }
232 isSizeChange_ = false;
233 }
234
GetThemeScopeId(PaintWrapper * paintWrapper) const235 int32_t SwitchPaintMethod::GetThemeScopeId(PaintWrapper* paintWrapper) const
236 {
237 const int32_t defaultThemeScopeId = 0;
238 CHECK_NULL_RETURN(paintWrapper, defaultThemeScopeId);
239 auto renderContext = paintWrapper->GetRenderContext();
240 CHECK_NULL_RETURN(renderContext, defaultThemeScopeId);
241 auto host = renderContext->GetHost();
242 CHECK_NULL_RETURN(host, defaultThemeScopeId);
243 return host->GetThemeScopeId();
244 }
245 } // namespace OHOS::Ace::NG
246