• 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 
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