• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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/slider/slider_content_modifier.h"
17 
18 #include <optional>
19 #include <utility>
20 
21 #include "base/geometry/ng/offset_t.h"
22 #include "base/utils/utils.h"
23 #include "core/animation/curves.h"
24 #include "core/components/common/properties/color.h"
25 #include "core/components/slider/slider_theme.h"
26 #include "core/components_ng/render/drawing_prop_convertor.h"
27 #include "core/pipeline/pipeline_base.h"
28 
29 namespace OHOS::Ace::NG {
30 namespace {
31 constexpr float HALF = 0.5f;
32 constexpr Dimension CIRCLE_SHADOW_WIDTH = 1.0_vp;
33 constexpr float SPRING_MOTION_RESPONSE = 0.314f;
34 constexpr float SPRING_MOTION_DAMPING_FRACTION = 0.95f;
35 } // namespace
SliderContentModifier(const Parameters & parameters)36 SliderContentModifier::SliderContentModifier(const Parameters& parameters)
37     : boardColor_(AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(Color::TRANSPARENT)))
38 {
39     // animatable property
40     selectStart_ = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(parameters.selectStart - PointF());
41     selectEnd_ = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(parameters.selectEnd - PointF());
42     backStart_ = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(parameters.backStart - PointF());
43     backEnd_ = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(parameters.backEnd - PointF());
44     circleCenter_ = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(parameters.circleCenter - PointF());
45     trackThickness_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(parameters.trackThickness);
46     trackBackgroundColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(parameters.trackBackgroundColor));
47     selectColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(parameters.selectColor));
48     blockColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(parameters.blockColor));
49     // non-animatable property
50     blockDiameter_ = AceType::MakeRefPtr<PropertyFloat>(parameters.blockDiameter);
51     stepRatio_ = AceType::MakeRefPtr<PropertyFloat>(parameters.stepRatio);
52     isShowStep_ = AceType::MakeRefPtr<PropertyBool>(false);
53     // others
54     UpdateData(parameters);
55     UpdateThemeColor();
56 
57     AttachProperty(selectStart_);
58     AttachProperty(selectEnd_);
59     AttachProperty(backStart_);
60     AttachProperty(backEnd_);
61     AttachProperty(circleCenter_);
62     AttachProperty(trackThickness_);
63     AttachProperty(trackBackgroundColor_);
64     AttachProperty(selectColor_);
65     AttachProperty(blockColor_);
66     AttachProperty(boardColor_);
67     AttachProperty(blockDiameter_);
68     AttachProperty(stepRatio_);
69     AttachProperty(isShowStep_);
70 }
71 
onDraw(DrawingContext & context)72 void SliderContentModifier::onDraw(DrawingContext& context)
73 {
74     DrawBackground(context);
75     DrawStep(context);
76     DrawSelect(context);
77     DrawDefaultBlock(context);
78     DrawShadow(context);
79     DrawHoverOrPress(context);
80 }
81 
DrawBackground(DrawingContext & context)82 void SliderContentModifier::DrawBackground(DrawingContext& context)
83 {
84     auto& canvas = context.canvas;
85     RSPen backgroundPen;
86     backgroundPen.SetAntiAlias(true);
87     backgroundPen.SetWidth(trackThickness_->Get());
88     backgroundPen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
89     backgroundPen.SetColor(ToRSColor(trackBackgroundColor_->Get()));
90     canvas.AttachPen(backgroundPen);
91     canvas.DrawLine(RSPoint(backStart_->Get().GetX(), backStart_->Get().GetY()),
92         RSPoint(backEnd_->Get().GetX(), backEnd_->Get().GetY()));
93     canvas.DetachPen();
94 }
95 
DrawStep(DrawingContext & context)96 void SliderContentModifier::DrawStep(DrawingContext& context)
97 {
98     if (!isShowStep_->Get()) {
99         return;
100     }
101     auto& canvas = context.canvas;
102     auto stepSize = stepSize_;
103     auto stepColor = stepColor_;
104     auto backStart = backStart_->Get();
105     auto backEnd = backEnd_->Get();
106     auto stepRatio = stepRatio_->Get();
107     if (NearEqual(stepRatio, .0f)) {
108         return;
109     }
110     RSBrush brush;
111     brush.SetAntiAlias(true);
112     brush.SetColor(ToRSColor(stepColor));
113     canvas.AttachBrush(brush);
114     // Distance between slide track and Content boundary
115     auto centerWidth = directionAxis_ == Axis::HORIZONTAL ? context.height : context.width;
116     centerWidth *= HALF;
117     if (directionAxis_ == Axis::HORIZONTAL) {
118         auto stepsLength = (backEnd.GetX() - backStart.GetX()) * stepRatio;
119         float dyOffset = backEnd.GetY();
120         float start = backStart.GetX();
121         float end = backEnd.GetX();
122         float current = start;
123         while (LessOrEqual(current, end)) {
124             float dxOffset = std::clamp(current, start, end);
125             canvas.DrawCircle(RSPoint(dxOffset, dyOffset), stepSize * HALF);
126             current += stepsLength;
127         }
128     } else {
129         auto stepsLength = (backEnd.GetY() - backStart.GetY()) * stepRatio;
130         float dxOffset = backEnd.GetX();
131         float start = backStart.GetY();
132         float end = backEnd.GetY();
133         float current = start;
134         while (LessOrEqual(current, end)) {
135             float dyOffset = std::clamp(current, start, end);
136             canvas.DrawCircle(RSPoint(dxOffset, dyOffset), stepSize * HALF);
137             current += stepsLength;
138         }
139     }
140 
141     canvas.DetachBrush();
142 }
143 
DrawSelect(DrawingContext & context)144 void SliderContentModifier::DrawSelect(DrawingContext& context)
145 {
146     auto& canvas = context.canvas;
147     if (selectStart_->Get() != selectEnd_->Get()) {
148         RSPen selectPen;
149         selectPen.SetAntiAlias(true);
150         selectPen.SetWidth(trackThickness_->Get());
151         selectPen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
152         selectPen.SetColor(ToRSColor(selectColor_->Get()));
153         canvas.AttachPen(selectPen);
154         canvas.DrawLine(RSPoint(selectStart_->Get().GetX(), selectStart_->Get().GetY()),
155             RSPoint(selectEnd_->Get().GetX(), selectEnd_->Get().GetY()));
156     }
157 }
158 
DrawDefaultBlock(DrawingContext & context)159 void SliderContentModifier::DrawDefaultBlock(DrawingContext& context)
160 {
161     auto& canvas = context.canvas;
162     RSPen circlePen;
163     circlePen.SetAntiAlias(true);
164     circlePen.SetColor(ToRSColor(blockColor_->Get()));
165     circlePen.SetWidth(blockDiameter_->Get() * HALF);
166     canvas.AttachPen(circlePen);
167     auto penRadius = blockDiameter_->Get() * HALF * HALF;
168     canvas.DrawCircle(RSPoint(circleCenter_->Get().GetX(), circleCenter_->Get().GetY()), penRadius);
169     canvas.DetachPen();
170 }
171 
DrawHoverOrPress(DrawingContext & context)172 void SliderContentModifier::DrawHoverOrPress(DrawingContext& context)
173 {
174     auto& canvas = context.canvas;
175     RSPen circleStatePen;
176     circleStatePen.SetAntiAlias(true);
177     // add animate color
178     circleStatePen.SetColor(ToRSColor(boardColor_->Get()));
179     circleStatePen.SetWidth(hotCircleShadowWidth_);
180     canvas.AttachPen(circleStatePen);
181     auto penRadius = (blockDiameter_->Get() + hotCircleShadowWidth_) * HALF;
182     canvas.DrawCircle(RSPoint(circleCenter_->Get().GetX(), circleCenter_->Get().GetY()), penRadius);
183     canvas.DetachPen();
184 }
185 
DrawShadow(DrawingContext & context)186 void SliderContentModifier::DrawShadow(DrawingContext& context)
187 {
188     auto& canvas = context.canvas;
189     if (!mouseHoverFlag_ && !mousePressedFlag_) {
190         RSPen circleShadowPen;
191         circleShadowPen.SetAntiAlias(true);
192         circleShadowPen.SetColor(ToRSColor(blockOuterEdgeColor_));
193         circleShadowPen.SetWidth(static_cast<float>(CIRCLE_SHADOW_WIDTH.ConvertToPx()));
194         canvas.AttachPen(circleShadowPen);
195         auto penRadius = (blockDiameter_->Get() + static_cast<float>(CIRCLE_SHADOW_WIDTH.ConvertToPx())) * HALF;
196         canvas.DrawCircle(
197             RSPoint(circleCenter_->Get().GetX(), circleCenter_->Get().GetY()), penRadius);
198         canvas.DetachPen();
199     }
200 }
201 
SetBoardColor()202 void SliderContentModifier::SetBoardColor()
203 {
204     CHECK_NULL_VOID(boardColor_);
205     auto pipeline = PipelineBase::GetCurrentContext();
206     CHECK_NULL_VOID(pipeline);
207     auto theme = pipeline->GetTheme<SliderTheme>();
208     CHECK_NULL_VOID(theme);
209     Color shadowColor = Color::TRANSPARENT;
210     shadowColor = mouseHoverFlag_ ? theme->GetBlockHoverColor() : shadowColor;
211     shadowColor = mousePressedFlag_ ? theme->GetBlockPressedColor() : shadowColor;
212     auto duration = mousePressedFlag_ ? static_cast<int32_t>(theme->GetPressAnimationDuration())
213                                       : static_cast<int32_t>(theme->GetHoverAnimationDuration());
214     auto curve = mousePressedFlag_ ? Curves::SHARP : Curves::FRICTION;
215     AnimationOption option = AnimationOption();
216     option.SetDuration(duration);
217     option.SetCurve(curve);
218     AnimationUtils::Animate(option, [&]() { boardColor_->Set(LinearColor(shadowColor)); });
219 }
220 
UpdateData(const Parameters & parameters)221 void SliderContentModifier::UpdateData(const Parameters& parameters)
222 {
223     mouseHoverFlag_ = parameters.mouseHoverFlag_;
224     mousePressedFlag_ = parameters.mousePressedFlag_;
225     hotCircleShadowWidth_ = parameters.hotCircleShadowWidth;
226 }
227 
JudgeNeedAimate(const RefPtr<SliderPaintProperty> & property)228 void SliderContentModifier::JudgeNeedAimate(const RefPtr<SliderPaintProperty>& property)
229 {
230     auto reverse = property->GetReverseValue(false);
231     // when reverse is changed, slider block position changes do not animated.
232     if (reverse_ != reverse) {
233         SetNotAnimated();
234         reverse_ = reverse;
235     }
236 }
237 
SetSelectSize(const PointF & start,const PointF & end)238 void SliderContentModifier::SetSelectSize(const PointF& start, const PointF& end)
239 {
240     if (selectStart_) {
241         selectStart_->Set(start - PointF());
242     }
243     CHECK_NULL_VOID(selectEnd_);
244     if (needAnimate_) {
245         AnimationOption option = AnimationOption();
246         auto motion =
247             AceType::MakeRefPtr<ResponsiveSpringMotion>(SPRING_MOTION_RESPONSE, SPRING_MOTION_DAMPING_FRACTION);
248         option.SetCurve(motion);
249         AnimationUtils::Animate(option, [&]() { selectEnd_->Set(end - PointF()); });
250     } else {
251         selectEnd_->Set(end - PointF());
252     }
253 }
254 
SetCircleCenter(const PointF & center)255 void SliderContentModifier::SetCircleCenter(const PointF& center)
256 {
257     CHECK_NULL_VOID(circleCenter_);
258     if (needAnimate_) {
259         AnimationOption option = AnimationOption();
260         auto motion =
261             AceType::MakeRefPtr<ResponsiveSpringMotion>(SPRING_MOTION_RESPONSE, SPRING_MOTION_DAMPING_FRACTION);
262         option.SetCurve(motion);
263         AnimationUtils::Animate(option, [&]() { circleCenter_->Set(center - PointF()); });
264     } else {
265         circleCenter_->Set(center - PointF());
266     }
267 }
268 } // namespace OHOS::Ace::NG
269