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