• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 "base/geometry/ng/offset_t.h"
16 #include "base/utils/utils.h"
17 #include "core/components/checkable/checkable_theme.h"
18 #include "core/components/common/properties/color.h"
19 #include "core/components_ng/pattern/radio/radio_modifier.h"
20 #include "core/components_ng/render/animation_utils.h"
21 #include "core/components_ng/render/drawing.h"
22 #include "core/components_ng/render/drawing_prop_convertor.h"
23 #include "core/pipeline/pipeline_base.h"
24 
25 namespace OHOS::Ace::NG {
26 namespace {
27 constexpr uint8_t ENABLED_ALPHA = 255;
28 constexpr uint8_t DISABLED_ALPHA = 102;
29 constexpr float CALC_RADIUS = 2.0f;
30 constexpr float DEFAULT_POINT_SCALE = 0.5f;
31 constexpr float DEFAULT_TOTAL_SCALE = 1.0f;
32 constexpr float DEFAULT_SHRINK_SCALE = 0.9f;
33 constexpr int32_t DEFAULT_RADIO_ANIMATION_DURATION = 300;
34 } // namespace
35 
RadioModifier()36 RadioModifier::RadioModifier()
37 {
38     auto pipeline = PipelineBase::GetCurrentContext();
39     CHECK_NULL_VOID(pipeline);
40     auto radioTheme = pipeline->GetTheme<RadioTheme>();
41 
42     pointColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(radioTheme->GetPointColor()));
43     AttachProperty(pointColor_);
44 
45     activeColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(radioTheme->GetActiveColor()));
46     AttachProperty(activeColor_);
47 
48     inactiveColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(radioTheme->GetInactiveColor()));
49     AttachProperty(inactiveColor_);
50     isOnAnimationFlag_ = AceType::MakeRefPtr<PropertyBool>(false);
51     enabled_ = AceType::MakeRefPtr<PropertyBool>(true);
52     isCheck_ = AceType::MakeRefPtr<PropertyBool>(false);
53     uiStatus_ = AceType::MakeRefPtr<PropertyInt>(static_cast<int32_t>(UIStatus::UNSELECTED));
54     offset_ = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(OffsetF());
55     size_ = AceType::MakeRefPtr<AnimatablePropertySizeF>(SizeF());
56     totalScale_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(DEFAULT_TOTAL_SCALE);
57     pointScale_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(DEFAULT_POINT_SCALE);
58     ringPointScale_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f);
59     animateTouchHoverColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(Color::TRANSPARENT));
60 
61     AttachProperty(enabled_);
62     AttachProperty(isCheck_);
63     AttachProperty(uiStatus_);
64     AttachProperty(offset_);
65     AttachProperty(size_);
66     AttachProperty(totalScale_);
67     AttachProperty(pointScale_);
68     AttachProperty(ringPointScale_);
69     AttachProperty(animateTouchHoverColor_);
70 
71     InitializeParam();
72 }
73 
InitializeParam()74 void RadioModifier::InitializeParam()
75 {
76     auto pipeline = PipelineBase::GetCurrentContext();
77     CHECK_NULL_VOID(pipeline);
78     auto radioTheme = pipeline->GetTheme<RadioTheme>();
79     shadowWidth_ = radioTheme->GetShadowWidth().ConvertToPx();
80     borderWidth_ = radioTheme->GetBorderWidth().ConvertToPx();
81     inactivePointColor_ = radioTheme->GetInactivePointColor();
82     shadowColor_ = radioTheme->GetShadowColor();
83     clickEffectColor_ = radioTheme->GetClickEffectColor();
84     hoverColor_ = radioTheme->GetHoverColor();
85     hotZoneHorizontalPadding_ = radioTheme->GetHotZoneHorizontalPadding();
86     hoverDuration_ = radioTheme->GetHoverDuration();
87     hoverToTouchDuration_ = radioTheme->GetHoverToTouchDuration();
88     touchDuration_ = radioTheme->GetTouchDuration();
89 }
90 
UpdateAnimatableProperty()91 void RadioModifier::UpdateAnimatableProperty()
92 {
93     switch (touchHoverType_) {
94         case TouchHoverAnimationType::HOVER:
95             SetBoardColor(LinearColor(hoverColor_), hoverDuration_, Curves::FRICTION);
96             break;
97         case TouchHoverAnimationType::PRESS_TO_HOVER:
98             SetBoardColor(LinearColor(hoverColor_), hoverToTouchDuration_, Curves::SHARP);
99             break;
100         case TouchHoverAnimationType::NONE:
101             SetBoardColor(LinearColor(hoverColor_.BlendOpacity(0)), hoverDuration_, Curves::FRICTION);
102             break;
103         case TouchHoverAnimationType::HOVER_TO_PRESS:
104             SetBoardColor(LinearColor(clickEffectColor_), hoverToTouchDuration_, Curves::SHARP);
105             break;
106         case TouchHoverAnimationType::PRESS:
107             SetBoardColor(LinearColor(clickEffectColor_), hoverDuration_, Curves::FRICTION);
108             break;
109         default:
110             break;
111     }
112 }
113 
UpdateIsOnAnimatableProperty(bool isCheck)114 void RadioModifier::UpdateIsOnAnimatableProperty(bool isCheck)
115 {
116     AnimationOption delayOption;
117     delayOption.SetDelay(DEFAULT_RADIO_ANIMATION_DURATION / 2);
118     delayOption.SetDuration(DEFAULT_RADIO_ANIMATION_DURATION / 2);
119     delayOption.SetCurve(Curves::FRICTION);
120 
121     AnimationOption halfDurationOption;
122     halfDurationOption.SetDuration(DEFAULT_RADIO_ANIMATION_DURATION / 2);
123     halfDurationOption.SetCurve(Curves::FRICTION);
124 
125     if (isOnAnimationFlag_->Get()) {
126         pointScale_->Set(0);
127         AnimationUtils::Animate(delayOption, [&]() { pointScale_->Set(DEFAULT_POINT_SCALE); });
128         ringPointScale_->Set(1);
129         AnimationUtils::Animate(halfDurationOption, [&]() { ringPointScale_->Set(0); });
130     } else {
131         pointScale_->Set(DEFAULT_POINT_SCALE);
132         AnimationUtils::Animate(halfDurationOption, [&]() { pointScale_->Set(0); });
133         ringPointScale_->Set(0);
134         AnimationUtils::Animate(delayOption, [&]() { ringPointScale_->Set(1); });
135     }
136 
137     totalScale_->Set(DEFAULT_TOTAL_SCALE);
138     AnimationUtils::Animate(halfDurationOption, [&]() { totalScale_->Set(DEFAULT_SHRINK_SCALE); });
139     totalScale_->Set(DEFAULT_SHRINK_SCALE);
140     AnimationUtils::Animate(
141         delayOption, [&]() { totalScale_->Set(1); },
142         [isCheck, weakUiStatus = AceType::WeakClaim(AceType::RawPtr(uiStatus_))]() {
143             auto uiStatus = weakUiStatus.Upgrade();
144             if (uiStatus) {
145                 uiStatus->Set(static_cast<int32_t>(isCheck ? UIStatus::SELECTED : UIStatus::UNSELECTED));
146             }
147             auto context = PipelineBase::GetCurrentContext();
148             if (context) {
149                 context->RequestFrame();
150             }
151         });
152 }
153 
SetBoardColor(LinearColor color,int32_t duratuion,const RefPtr<CubicCurve> & curve)154 void RadioModifier::SetBoardColor(LinearColor color, int32_t duratuion, const RefPtr<CubicCurve>& curve)
155 {
156     if (animateTouchHoverColor_) {
157         AnimationOption option = AnimationOption();
158         option.SetDuration(duratuion);
159         option.SetCurve(curve);
160         AnimationUtils::Animate(option, [&]() { animateTouchHoverColor_->Set(color); });
161     }
162 }
163 
PaintRadio(RSCanvas & canvas,bool,const SizeF & contentSize,const OffsetF & contentOffset) const164 void RadioModifier::PaintRadio(
165     RSCanvas& canvas, bool /* checked */, const SizeF& contentSize, const OffsetF& contentOffset) const
166 {
167     DrawTouchAndHoverBoard(canvas, contentSize, contentOffset);
168     float outCircleRadius = contentSize.Width() / CALC_RADIUS;
169     float centerX = contentOffset.GetX() + outCircleRadius;
170     float centerY = contentOffset.GetY() + outCircleRadius;
171     RSPen pen;
172     RSPen outPen;
173     RSBrush brush;
174     RSBrush shadowBrush;
175     pen.SetAntiAlias(true);
176     pen.SetWidth(borderWidth_);
177     outPen.SetAntiAlias(true);
178     brush.SetAntiAlias(true);
179     shadowBrush.SetAntiAlias(true);
180     shadowBrush.SetColor(ToRSColor(shadowColor_));
181     if (uiStatus_->Get() == static_cast<int32_t>(UIStatus::SELECTED)) {
182         if (!enabled_->Get()) {
183             brush.SetColor(
184                 ToRSColor(pointColor_->Get().BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
185         } else {
186             brush.SetColor(ToRSColor(pointColor_->Get()));
187         }
188         if (!NearZero(pointScale_->Get())) {
189             // draw shadow
190             canvas.AttachBrush(shadowBrush);
191             canvas.DrawCircle(RSPoint(centerX, centerY), outCircleRadius * pointScale_->Get() + shadowWidth_);
192             // draw inner circle
193             canvas.AttachBrush(brush);
194             canvas.DrawCircle(RSPoint(centerX, centerY), outCircleRadius * pointScale_->Get());
195         }
196         // draw ring circle
197         if (!enabled_->Get()) {
198             brush.SetColor(
199                 ToRSColor(inactivePointColor_.BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
200         } else {
201             brush.SetColor(ToRSColor(inactivePointColor_));
202         }
203         if (!NearZero(ringPointScale_->Get())) {
204             canvas.AttachBrush(brush);
205             canvas.DrawCircle(RSPoint(centerX, centerY), outCircleRadius * ringPointScale_->Get());
206         }
207         // draw out circular ring
208         if (!enabled_->Get()) {
209             outPen.SetColor(
210                 ToRSColor(activeColor_->Get().BlendOpacity(static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA)));
211         } else {
212             outPen.SetColor(ToRSColor(activeColor_->Get()));
213         }
214         auto outWidth = outCircleRadius * (totalScale_->Get() - pointScale_->Get() - ringPointScale_->Get());
215         if (outWidth < borderWidth_) {
216             outWidth = borderWidth_;
217         }
218         outPen.SetWidth(outWidth);
219         canvas.AttachPen(outPen);
220         canvas.DrawCircle(RSPoint(centerX, centerY), outCircleRadius * totalScale_->Get() - outWidth / CALC_RADIUS);
221     } else if (uiStatus_->Get() == static_cast<int32_t>(UIStatus::UNSELECTED)) {
222         auto alphaCalculate = static_cast<float>(DISABLED_ALPHA) / ENABLED_ALPHA;
223         if (!enabled_->Get()) {
224             brush.SetColor(ToRSColor(inactivePointColor_.BlendOpacity(alphaCalculate)));
225             pen.SetColor(ToRSColor(inactiveColor_->Get().BlendOpacity(alphaCalculate)));
226         } else {
227             brush.SetColor(ToRSColor(inactivePointColor_));
228             pen.SetColor(ToRSColor(inactiveColor_->Get()));
229         }
230         canvas.AttachBrush(brush);
231         canvas.DrawCircle(RSPoint(centerX, centerY), outCircleRadius - borderWidth_);
232         // draw border with unselected color
233         canvas.AttachPen(pen);
234         canvas.DrawCircle(RSPoint(centerX, centerY), outCircleRadius - borderWidth_ / CALC_RADIUS);
235     }
236 }
237 
DrawTouchAndHoverBoard(RSCanvas & canvas,const SizeF & contentSize,const OffsetF & offset) const238 void RadioModifier::DrawTouchAndHoverBoard(RSCanvas& canvas, const SizeF& contentSize, const OffsetF& offset) const
239 {
240     float outCircleRadius = contentSize.Width() / CALC_RADIUS;
241     float centerX = outCircleRadius + offset.GetX();
242     float centerY = outCircleRadius + offset.GetY();
243     outCircleRadius += hotZoneHorizontalPadding_.ConvertToPx();
244     RSBrush brush;
245     brush.SetColor(ToRSColor(animateTouchHoverColor_->Get()));
246     brush.SetAntiAlias(true);
247     canvas.AttachBrush(brush);
248     canvas.DrawCircle(RSPoint(centerX, centerY), outCircleRadius);
249 }
250 
251 } // namespace OHOS::Ace::NG
252