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 "base/geometry/ng/offset_t.h"
19 #include "base/utils/utils.h"
20 #include "core/animation/curves.h"
21 #include "core/components/common/properties/color.h"
22 #include "core/components/slider/slider_theme.h"
23 #include "core/components_ng/render/drawing.h"
24 #include "core/components_ng/render/drawing_prop_convertor.h"
25 #include "core/components_ng/render/path_painter.h"
26 #include "core/pipeline/pipeline_base.h"
27 
28 namespace OHOS::Ace::NG {
29 namespace {
30 constexpr float HALF = 0.5f;
31 constexpr float SPRING_MOTION_RESPONSE = 0.314f;
32 constexpr float SPRING_MOTION_DAMPING_FRACTION = 0.95f;
33 } // namespace
SliderContentModifier(const Parameters & parameters,std::function<void (float)> updateImageCenterX,std::function<void (float)> updateImageCenterY)34 SliderContentModifier::SliderContentModifier(const Parameters& parameters,
35     std::function<void(float)> updateImageCenterX, std::function<void(float)> updateImageCenterY)
36     : updateImageCenterX_(std::move(updateImageCenterX)), updateImageCenterY_(std::move(updateImageCenterY)),
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     blockCenterX_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(parameters.circleCenter.GetX());
45     blockCenterY_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(parameters.circleCenter.GetY());
46     trackThickness_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(parameters.trackThickness);
47     trackBackgroundColor_ =
48         AceType::MakeRefPtr<AnimatablePropertyVectorColor>(GradientArithmetic(parameters.trackBackgroundColor));
49     selectColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(parameters.selectColor));
50     blockColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(parameters.blockColor));
51     trackBorderRadius_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(parameters.trackThickness * HALF);
52     selectedBorderRadius_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(trackBorderRadius_->Get());
53     stepSize_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(1);
54     blockBorderWidth_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(0);
55     stepColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor::TRANSPARENT);
56     blockBorderColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(parameters.blockColor));
57     blockSize_ = AceType::MakeRefPtr<AnimatablePropertySizeF>(parameters.blockSize);
58     // non-animatable property
59     stepRatio_ = AceType::MakeRefPtr<PropertyFloat>(parameters.stepRatio);
60     sliderMode_ = AceType::MakeRefPtr<PropertyInt>(static_cast<int>(SliderModelNG::SliderMode::OUTSET));
61     directionAxis_ = AceType::MakeRefPtr<PropertyInt>(static_cast<int>(Axis::HORIZONTAL));
62     isShowStep_ = AceType::MakeRefPtr<PropertyBool>(false);
63     sliderInteractionMode_ =
64         AceType::MakeRefPtr<PropertyInt>(static_cast<int>(SliderModelNG::SliderInteraction::SLIDE_AND_CLICK));
65     minResponse_ = AceType::MakeRefPtr<PropertyFloat>(0.0f);
66     blockType_ = AceType::MakeRefPtr<PropertyInt>(static_cast<int>(SliderModelNG::BlockStyleType::DEFAULT));
67     useContentModifier_ = AceType::MakeRefPtr<PropertyBool>(false);
68     // others
69     UpdateData(parameters);
70     UpdateThemeColor();
71 
72     AttachProperty(selectStart_);
73     AttachProperty(selectEnd_);
74     AttachProperty(backStart_);
75     AttachProperty(backEnd_);
76     AttachProperty(blockCenterX_);
77     AttachProperty(blockCenterY_);
78     AttachProperty(trackThickness_);
79     AttachProperty(trackBackgroundColor_);
80     AttachProperty(selectColor_);
81     AttachProperty(blockColor_);
82     AttachProperty(boardColor_);
83     AttachProperty(trackBorderRadius_);
84     AttachProperty(selectedBorderRadius_);
85     AttachProperty(stepSize_);
86     AttachProperty(blockBorderWidth_);
87     AttachProperty(stepColor_);
88     AttachProperty(blockBorderColor_);
89     AttachProperty(blockSize_);
90     AttachProperty(stepRatio_);
91     AttachProperty(sliderMode_);
92     AttachProperty(directionAxis_);
93     AttachProperty(isShowStep_);
94     AttachProperty(sliderInteractionMode_);
95     AttachProperty(minResponse_);
96     AttachProperty(blockType_);
97 
98     InitializeShapeProperty();
99 }
100 
InitializeShapeProperty()101 void SliderContentModifier::InitializeShapeProperty()
102 {
103     shapeWidth_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(.0f);
104     shapeHeight_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(.0f);
105     circleRadius_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(.0f);
106     ellipseRadiusX_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(.0f);
107     ellipseRadiusY_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(.0f);
108     rectTopLeftRadiusX_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(.0f);
109     rectTopLeftRadiusY_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(.0f);
110     rectTopRightRadiusX_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(.0f);
111     rectTopRightRadiusY_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(.0f);
112     rectBottomLeftRadiusX_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(.0f);
113     rectBottomLeftRadiusY_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(.0f);
114     rectBottomRightRadiusX_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(.0f);
115     rectBottomRightRadiusY_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(.0f);
116     AttachProperty(shapeWidth_);
117     AttachProperty(shapeHeight_);
118     AttachProperty(circleRadius_);
119     AttachProperty(ellipseRadiusX_);
120     AttachProperty(ellipseRadiusY_);
121     AttachProperty(rectTopLeftRadiusX_);
122     AttachProperty(rectTopLeftRadiusY_);
123     AttachProperty(rectTopRightRadiusX_);
124     AttachProperty(rectTopRightRadiusY_);
125     AttachProperty(rectBottomLeftRadiusX_);
126     AttachProperty(rectBottomLeftRadiusY_);
127     AttachProperty(rectBottomRightRadiusX_);
128     AttachProperty(rectBottomRightRadiusY_);
129 }
130 
onDraw(DrawingContext & context)131 void SliderContentModifier::onDraw(DrawingContext& context)
132 {
133     if (useContentModifier_->Get()) {
134         return;
135     }
136     DrawBackground(context);
137     DrawStep(context);
138     DrawSelect(context);
139     DrawShadow(context);
140     DrawBlock(context);
141     DrawHoverOrPress(context);
142 }
143 
SetStartEndPointLocation(Axis & direction,RSRect & trackRect,RSPoint & startPoint,RSPoint & endPoint)144 void SetStartEndPointLocation(Axis& direction, RSRect& trackRect, RSPoint& startPoint, RSPoint& endPoint)
145 {
146     if (direction == Axis::HORIZONTAL) {
147         startPoint.SetX(trackRect.GetLeft());
148         startPoint.SetY(trackRect.GetTop());
149         endPoint.SetX(trackRect.GetRight());
150         endPoint.SetY(trackRect.GetTop());
151     } else {
152         startPoint.SetX(trackRect.GetLeft());
153         startPoint.SetY(trackRect.GetTop());
154         endPoint.SetX(trackRect.GetLeft());
155         endPoint.SetY(trackRect.GetBottom());
156     }
157 }
158 
DrawBackground(DrawingContext & context)159 void SliderContentModifier::DrawBackground(DrawingContext& context)
160 {
161     auto& canvas = context.canvas;
162     auto trackBorderRadius = trackBorderRadius_->Get();
163     std::vector<GradientColor> gradientColors = GetTrackBackgroundColor();
164     std::vector<RSColorQuad> colors;
165     std::vector<float> pos;
166     for (size_t i = 0; i < gradientColors.size(); i++) {
167         colors.emplace_back(gradientColors[i].GetLinearColor().GetValue());
168         pos.emplace_back(gradientColors[i].GetDimension().Value());
169     }
170     RSRect trackRect = GetTrackRect();
171     auto direction = static_cast<Axis>(directionAxis_->Get());
172     RSPoint startPoint;
173     RSPoint endPoint;
174     SetStartEndPointLocation(direction, trackRect, startPoint, endPoint);
175     RSBrush brush;
176     brush.SetAntiAlias(true);
177     if (reverse_) {
178 #ifndef USE_ROSEN_DRAWING
179         brush.SetShaderEffect(
180             RSShaderEffect::CreateLinearGradient(endPoint, startPoint, colors, pos, RSTileMode::CLAMP));
181 #else
182         brush.SetShaderEffect(
183             RSRecordingShaderEffect::CreateLinearGradient(endPoint, startPoint, colors, pos, RSTileMode::CLAMP));
184 #endif
185     } else {
186 #ifndef USE_ROSEN_DRAWING
187         brush.SetShaderEffect(
188             RSShaderEffect::CreateLinearGradient(startPoint, endPoint, colors, pos, RSTileMode::CLAMP));
189 #else
190         brush.SetShaderEffect(
191             RSRecordingShaderEffect::CreateLinearGradient(startPoint, endPoint, colors, pos, RSTileMode::CLAMP));
192 #endif
193     }
194     canvas.AttachBrush(brush);
195     RSRoundRect roundRect(trackRect, trackBorderRadius, trackBorderRadius);
196     canvas.DrawRoundRect(roundRect);
197     canvas.DetachBrush();
198     canvas.Save();
199     canvas.ClipRoundRect(roundRect, RSClipOp::INTERSECT, true);
200 }
201 
DrawStep(DrawingContext & context)202 void SliderContentModifier::DrawStep(DrawingContext& context)
203 {
204     if (!isShowStep_->Get()) {
205         return;
206     }
207     auto& canvas = context.canvas;
208     auto stepSize = stepSize_->Get();
209     auto stepColor = stepColor_->Get();
210     auto backStart = backStart_->Get();
211     auto backEnd = backEnd_->Get();
212     auto stepRatio = stepRatio_->Get();
213     if (NearEqual(stepRatio, .0f)) {
214         return;
215     }
216     float startX = backStart.GetX();
217     float endX = backEnd.GetX();
218     float startY = backStart.GetY();
219     float endY = backEnd.GetY();
220     if (NearEqual(startX, endX) && NearEqual(startY, endY)) {
221         return;
222     }
223     auto stepsLengthX = (endX - startX) * stepRatio;
224     auto stepsLengthY = (endY - startY) * stepRatio;
225     auto trackThickness = trackThickness_->Get();
226     if (GreatNotEqual(stepSize, trackThickness)) {
227         stepSize = trackThickness;
228     }
229 
230     RSBrush brush;
231     brush.SetAntiAlias(true);
232     brush.SetColor(ToRSColor(stepColor));
233     canvas.AttachBrush(brush);
234     stepPointVec_.clear();
235 
236     if (reverse_) {
237         while (GreatOrEqual(endX, startX) && GreatOrEqual(endY, startY)) {
238             canvas.DrawCircle(RSPoint(endX, endY), stepSize * HALF);
239             stepPointVec_.emplace_back(PointF(endX, endY));
240             endX -= stepsLengthX;
241             endY -= stepsLengthY;
242         }
243     } else {
244         while (LessOrEqual(startX, endX) && LessOrEqual(startY, endY)) {
245             canvas.DrawCircle(RSPoint(startX, startY), stepSize * HALF);
246             stepPointVec_.emplace_back(PointF(startX, startY));
247             startX += stepsLengthX;
248             startY += stepsLengthY;
249         }
250     }
251 
252     canvas.DetachBrush();
253 }
254 
DrawSelect(DrawingContext & context)255 void SliderContentModifier::DrawSelect(DrawingContext& context)
256 {
257     auto& canvas = context.canvas;
258     if (!NearEqual(selectStart_->Get().GetX(), selectEnd_->Get().GetX(), HALF) ||
259         !NearEqual(selectStart_->Get().GetY(), selectEnd_->Get().GetY(), HALF)) {
260         auto selectedBorderRadius = selectedBorderRadius_->Get();
261         auto direction = static_cast<Axis>(directionAxis_->Get());
262         auto blockCenter = GetBlockCenter();
263         auto trackThickness = trackThickness_->Get();
264         auto sliderMode = static_cast<SliderModelNG::SliderMode>(sliderMode_->Get());
265         auto rect = GetTrackRect();
266         auto insetOffset = .0f;
267         if (sliderMode == SliderModelNG::SliderMode::INSET) {
268             insetOffset = std::max(selectedBorderRadius, trackThickness * HALF);
269         }
270         if (!reverse_) {
271             if (direction == Axis::HORIZONTAL) {
272                 rect.SetRight(blockCenter.GetX() + insetOffset);
273             } else {
274                 rect.SetBottom(blockCenter.GetY() + insetOffset);
275             }
276         } else {
277             if (direction == Axis::HORIZONTAL) {
278                 rect.SetLeft(blockCenter.GetX() - insetOffset);
279             } else {
280                 rect.SetTop(blockCenter.GetY() - insetOffset);
281             }
282         }
283 
284         RSBrush brush;
285         brush.SetAntiAlias(true);
286         brush.SetColor(ToRSColor(selectColor_->Get()));
287 
288         canvas.AttachBrush(brush);
289         canvas.DrawRoundRect(RSRoundRect(rect, selectedBorderRadius, selectedBorderRadius));
290         canvas.DetachBrush();
291     }
292     canvas.Restore();
293 }
294 
DrawDefaultBlock(DrawingContext & context)295 void SliderContentModifier::DrawDefaultBlock(DrawingContext& context)
296 {
297     auto& canvas = context.canvas;
298     auto borderWidth = blockBorderWidth_->Get();
299     auto blockSize = blockSize_->Get();
300     auto blockCenter = GetBlockCenter();
301     float blockRadius = std::min(blockSize.Width(), blockSize.Height()) * HALF;
302     float radius = blockRadius;
303     RSBrush brush;
304     brush.SetAntiAlias(true);
305     if (GreatOrEqual(borderWidth * HALF, radius)) {
306         brush.SetColor(ToRSColor(blockBorderColor_->Get()));
307     } else {
308         radius = std::min(blockSize.Width(), blockSize.Height()) * HALF - borderWidth * HALF;
309         brush.SetColor(ToRSColor(blockColor_->Get()));
310     }
311     canvas.AttachBrush(brush);
312     RSPen pen;
313     if (!NearEqual(borderWidth, .0f) && LessNotEqual(borderWidth * HALF, blockRadius)) {
314         pen.SetAntiAlias(true);
315         pen.SetWidth(borderWidth);
316         pen.SetColor(ToRSColor(blockBorderColor_->Get()));
317         canvas.AttachPen(pen);
318     }
319     canvas.DrawCircle(ToRSPoint(PointF(blockCenter.GetX(), blockCenter.GetY())), radius);
320     canvas.DetachBrush();
321     if (!NearEqual(borderWidth, .0f) && LessNotEqual(borderWidth * HALF, blockRadius)) {
322         canvas.DetachPen();
323     }
324 }
325 
DrawHoverOrPress(DrawingContext & context)326 void SliderContentModifier::DrawHoverOrPress(DrawingContext& context)
327 {
328     auto sliderMode = static_cast<SliderModelNG::SliderMode>(sliderMode_->Get());
329     if (static_cast<SliderModelNG::BlockStyleType>(blockType_->Get()) != SliderModelNG::BlockStyleType::DEFAULT ||
330         sliderMode == SliderModelNG::SliderMode::NONE) {
331         return;
332     }
333 
334     auto& canvas = context.canvas;
335     RSPen circleStatePen;
336     circleStatePen.SetAntiAlias(true);
337     // add animate color
338     circleStatePen.SetColor(ToRSColor(boardColor_->Get()));
339     circleStatePen.SetWidth(hotCircleShadowWidth_);
340     canvas.AttachPen(circleStatePen);
341     auto blockSize = blockSize_->Get();
342     float diameter = std::min(blockSize.Width(), blockSize.Height());
343     auto penRadius = (diameter + hotCircleShadowWidth_) * HALF;
344     auto blockCenter = GetBlockCenter();
345     canvas.DrawCircle(ToRSPoint(blockCenter), penRadius);
346     canvas.DetachPen();
347 }
348 
DrawShadow(DrawingContext & context)349 void SliderContentModifier::DrawShadow(DrawingContext& context)
350 {
351     auto sliderMode = static_cast<SliderModelNG::SliderMode>(sliderMode_->Get());
352     if (static_cast<SliderModelNG::BlockStyleType>(blockType_->Get()) != SliderModelNG::BlockStyleType::DEFAULT ||
353         sliderMode == SliderModelNG::SliderMode::NONE) {
354         return;
355     }
356 
357     if (!mouseHoverFlag_ && !mousePressedFlag_) {
358         auto& canvas = context.canvas;
359         auto blockSize = blockSize_->Get();
360         auto blockCenter = GetBlockCenter();
361         float radius = std::min(blockSize.Width(), blockSize.Height()) * HALF;
362         canvas.Save();
363         RSBrush shadowBrush;
364         shadowBrush.SetAntiAlias(true);
365         shadowBrush.SetColor(ToRSColor(blockShadowColor_));
366         RSFilter filter;
367         filter.SetMaskFilter(RSMaskFilter::CreateBlurMaskFilter(
368             RSBlurType::NORMAL, RSDrawing::ConvertRadiusToSigma(hotCircleShadowWidth_)));
369         shadowBrush.SetFilter(filter);
370 
371         canvas.AttachBrush(shadowBrush);
372         RSPath path;
373         path.AddCircle(ToRSPoint(blockCenter).GetX(), ToRSPoint(blockCenter).GetY(), radius);
374         canvas.DrawPath(path);
375         canvas.DetachBrush();
376         canvas.Restore();
377     }
378 }
379 
SetBoardColor()380 void SliderContentModifier::SetBoardColor()
381 {
382     CHECK_NULL_VOID(boardColor_);
383     auto pipeline = PipelineBase::GetCurrentContext();
384     CHECK_NULL_VOID(pipeline);
385     auto theme = pipeline->GetTheme<SliderTheme>();
386     CHECK_NULL_VOID(theme);
387     Color shadowColor = Color::TRANSPARENT;
388     shadowColor = mouseHoverFlag_ ? theme->GetBlockHoverColor() : shadowColor;
389     shadowColor = mousePressedFlag_ ? theme->GetBlockPressedColor() : shadowColor;
390     auto duration = mousePressedFlag_ ? static_cast<int32_t>(theme->GetPressAnimationDuration())
391                                       : static_cast<int32_t>(theme->GetHoverAnimationDuration());
392     auto curve = mousePressedFlag_ ? Curves::SHARP : Curves::FRICTION;
393     AnimationOption option = AnimationOption();
394     option.SetDuration(duration);
395     option.SetCurve(curve);
396     AnimationUtils::Animate(option, [&]() { boardColor_->Set(LinearColor(shadowColor)); });
397 }
398 
UpdateData(const Parameters & parameters)399 void SliderContentModifier::UpdateData(const Parameters& parameters)
400 {
401     mouseHoverFlag_ = parameters.mouseHoverFlag_;
402     mousePressedFlag_ = parameters.mousePressedFlag_;
403     hotCircleShadowWidth_ = parameters.hotCircleShadowWidth;
404 }
405 
JudgeNeedAnimate(bool reverse)406 void SliderContentModifier::JudgeNeedAnimate(bool reverse)
407 {
408     // when reverse is changed, slider block position changes do not animated.
409     if (reverse_ != reverse) {
410         SetAnimatorStatus(SliderStatus::DEFAULT);
411         reverse_ = reverse;
412     }
413 }
414 
StopSelectAnimation()415 void SliderContentModifier::StopSelectAnimation()
416 {
417     AnimationOption option = AnimationOption();
418     option.SetCurve(Curves::LINEAR);
419     AnimationUtils::Animate(option, [this]() {
420         selectEnd_->Set(selectEnd_->Get());
421         if (animatorStatus_ == SliderStatus::MOVE) {
422             selectEnd_->Set(targetSelectEnd_);
423         }
424     });
425 }
426 
SetSelectSize(const PointF & start,const PointF & end)427 void SliderContentModifier::SetSelectSize(const PointF& start, const PointF& end)
428 {
429     if (selectStart_) {
430         selectStart_->Set(start - PointF());
431     }
432     CHECK_NULL_VOID(selectEnd_);
433     auto currentEnd = end - PointF();
434     if (targetSelectEnd_ == currentEnd) {
435         return;
436     }
437     if (animatorStatus_ != SliderStatus::DEFAULT && isVisible_) {
438         StopSelectAnimation();
439         AnimationOption option = AnimationOption();
440         auto motion =
441             AceType::MakeRefPtr<ResponsiveSpringMotion>(SPRING_MOTION_RESPONSE, SPRING_MOTION_DAMPING_FRACTION);
442         option.SetCurve(motion);
443         AnimationUtils::Animate(option, [&]() { selectEnd_->Set(end - PointF()); });
444     } else {
445         selectEnd_->Set(end - PointF());
446     }
447     targetSelectEnd_ = end - PointF();
448 }
449 
StopCircleCenterAnimation()450 void SliderContentModifier::StopCircleCenterAnimation()
451 {
452     AnimationOption option = AnimationOption();
453     option.SetCurve(Curves::LINEAR);
454     AnimationUtils::Animate(option, [this]() {
455         if (static_cast<Axis>(directionAxis_->Get()) == Axis::HORIZONTAL) {
456             blockCenterX_->Set(blockCenterX_->Get());
457         } else {
458             blockCenterY_->Set(blockCenterY_->Get());
459         }
460         if (animatorStatus_ == SliderStatus::MOVE) {
461             if (static_cast<Axis>(directionAxis_->Get()) == Axis::HORIZONTAL) {
462                 blockCenterX_->Set(targetCenter_.GetX());
463             } else {
464                 blockCenterY_->Set(targetCenter_.GetY());
465             }
466         }
467     });
468 }
469 
SetCircleCenter(const PointF & center)470 void SliderContentModifier::SetCircleCenter(const PointF& center)
471 {
472     if (center == targetCenter_) {
473         return;
474     }
475 
476     CHECK_NULL_VOID(blockCenterX_);
477     CHECK_NULL_VOID(blockCenterY_);
478     if (animatorStatus_ != SliderStatus::DEFAULT && isVisible_) {
479         StopCircleCenterAnimation();
480         AnimationOption option = AnimationOption();
481         auto motion =
482             AceType::MakeRefPtr<ResponsiveSpringMotion>(SPRING_MOTION_RESPONSE, SPRING_MOTION_DAMPING_FRACTION);
483         option.SetCurve(motion);
484         AnimationUtils::Animate(option, [this, center]() {
485             if (static_cast<Axis>(directionAxis_->Get()) == Axis::HORIZONTAL) {
486                 blockCenterX_->Set(center.GetX());
487             } else {
488                 blockCenterY_->Set(center.GetY());
489             }
490         });
491         if (static_cast<Axis>(directionAxis_->Get()) == Axis::HORIZONTAL) {
492             blockCenterY_->Set(center.GetY());
493         } else {
494             blockCenterX_->Set(center.GetX());
495         }
496     } else {
497         blockCenterX_->Set(center.GetX());
498         blockCenterY_->Set(center.GetY());
499     }
500     targetCenter_ = center;
501 }
502 
GetTrackRect()503 RSRect SliderContentModifier::GetTrackRect()
504 {
505     auto backStart = backStart_->Get();
506     auto backEnd = backEnd_->Get();
507     auto trackThickness = trackThickness_->Get();
508     auto direction = static_cast<Axis>(directionAxis_->Get());
509     auto stepSize = stepSize_->Get();
510     if (GreatNotEqual(stepSize, trackThickness)) {
511         stepSize = trackThickness;
512     }
513     RSRect rect;
514     if (direction == Axis::HORIZONTAL) {
515         if (sliderMode_->Get() == static_cast<int32_t>(SliderModel::SliderMode::OUTSET)) {
516             rect.SetLeft(backStart.GetX() - stepSize * HALF);
517             rect.SetRight(backEnd.GetX() + stepSize * HALF);
518         } else if (sliderMode_->Get() == static_cast<int32_t>(SliderModel::SliderMode::INSET)) {
519             rect.SetLeft(backStart.GetX() - trackThickness * HALF);
520             rect.SetRight(backEnd.GetX() + trackThickness * HALF);
521         } else {
522             rect.SetLeft(backStart.GetX());
523             rect.SetRight(backEnd.GetX());
524         }
525         rect.SetTop(backStart.GetY() - trackThickness * HALF);
526         rect.SetBottom(backEnd.GetY() + trackThickness * HALF);
527     } else {
528         rect.SetLeft(backStart.GetX() - trackThickness * HALF);
529         rect.SetRight(backEnd.GetX() + trackThickness * HALF);
530         if (sliderMode_->Get() == static_cast<int32_t>(SliderModel::SliderMode::OUTSET)) {
531             rect.SetTop(backStart.GetY() - stepSize * HALF);
532             rect.SetBottom(backEnd.GetY() + stepSize * HALF);
533         } else if (sliderMode_->Get() == static_cast<int32_t>(SliderModel::SliderMode::INSET)) {
534             rect.SetTop(backStart.GetY() - trackThickness * HALF);
535             rect.SetBottom(backEnd.GetY() + trackThickness * HALF);
536         } else {
537             rect.SetTop(backStart.GetY());
538             rect.SetBottom(backEnd.GetY());
539         }
540     }
541     return rect;
542 }
543 
DrawBlock(DrawingContext & context)544 void SliderContentModifier::DrawBlock(DrawingContext& context)
545 {
546     auto sliderMode = static_cast<SliderModelNG::SliderMode>(sliderMode_->Get());
547     if (sliderMode != SliderModelNG::SliderMode::NONE) {
548         auto blockType = static_cast<SliderModelNG::BlockStyleType>(blockType_->Get());
549         if (blockType == SliderModelNG::BlockStyleType::DEFAULT) {
550             DrawDefaultBlock(context);
551         } else if (blockType == SliderModelNG::BlockStyleType::SHAPE) {
552             DrawBlockShape(context);
553         } else if (blockType == SliderModelNG::BlockStyleType::IMAGE) {
554             auto blockCenter = GetBlockCenter();
555             if (updateImageCenterX_) {
556                 updateImageCenterX_(blockCenter.GetX());
557             }
558             if (updateImageCenterY_) {
559                 updateImageCenterY_(blockCenter.GetY());
560             }
561         }
562     }
563 }
564 
DrawBlockShape(DrawingContext & context)565 void SliderContentModifier::DrawBlockShape(DrawingContext& context)
566 {
567     if (shape_ == nullptr) {
568         return;
569     }
570 
571     switch (shape_->GetBasicShapeType()) {
572         case BasicShapeType::CIRCLE: {
573             auto circle = DynamicCast<Circle>(shape_);
574             CHECK_NULL_VOID(circle);
575             DrawBlockShapeCircle(context, circle);
576             break;
577         }
578         case BasicShapeType::ELLIPSE: {
579             auto ellipse = DynamicCast<Ellipse>(shape_);
580             CHECK_NULL_VOID(ellipse);
581             DrawBlockShapeEllipse(context, ellipse);
582             break;
583         }
584         case BasicShapeType::PATH: {
585             auto path = DynamicCast<Path>(shape_);
586             CHECK_NULL_VOID(path);
587             DrawBlockShapePath(context, path);
588             break;
589         }
590         case BasicShapeType::RECT: {
591             auto rect = DynamicCast<ShapeRect>(shape_);
592             CHECK_NULL_VOID(rect);
593             DrawBlockShapeRect(context, rect);
594             break;
595         }
596         default:
597             break;
598     }
599 }
600 
DrawBlockShapeCircle(DrawingContext & context,RefPtr<Circle> & circle)601 void SliderContentModifier::DrawBlockShapeCircle(DrawingContext& context, RefPtr<Circle>& circle)
602 {
603     auto blockSize = blockSize_->Get();
604     auto shapeWidth = shapeWidth_->Get();
605     auto shapeHeight = shapeHeight_->Get();
606     auto blockBorderWidth = blockBorderWidth_->Get();
607     if (NearZero(shapeWidth) || NearZero(shapeHeight)) {
608         return;
609     }
610 
611     auto blockCenter = GetBlockCenter();
612     float scale = std::max(blockSize.Width() / shapeWidth, blockSize.Height() / shapeHeight);
613     if (NearZero(scale)) {
614         return;
615     }
616     float blockBorderWidthUnscale = blockBorderWidth / scale;
617 
618     auto& canvas = context.canvas;
619     canvas.Save();
620     SetBlockClip(context);
621     canvas.Translate(blockCenter.GetX(), blockCenter.GetY());
622     canvas.Scale(scale, scale);
623     canvas.Translate(-blockCenter.GetX(), -blockCenter.GetY());
624 
625     RSPen pen;
626     pen.SetAntiAlias(true);
627     pen.SetWidth(blockBorderWidthUnscale);
628     pen.SetColor(ToRSColor(blockBorderColor_->Get()));
629     canvas.AttachPen(pen);
630     RSBrush brush;
631     brush.SetAntiAlias(true);
632     brush.SetColor(ToRSColor(blockColor_->Get()));
633     canvas.AttachBrush(brush);
634 
635     float radius = std::min(shapeWidth, shapeHeight) * HALF;
636     float drawRadius = radius - blockBorderWidthUnscale * HALF;
637     PointF drawCenter(
638         blockCenter.GetX() - shapeWidth * HALF + radius, blockCenter.GetY() - shapeHeight * HALF + radius);
639     canvas.DrawCircle(ToRSPoint(drawCenter), drawRadius);
640 
641     canvas.DetachBrush();
642     canvas.DetachPen();
643     canvas.Restore();
644 }
645 
DrawBlockShapeEllipse(DrawingContext & context,RefPtr<Ellipse> & ellipse)646 void SliderContentModifier::DrawBlockShapeEllipse(DrawingContext& context, RefPtr<Ellipse>& ellipse)
647 {
648     auto blockSize = blockSize_->Get();
649     auto shapeWidth = shapeWidth_->Get();
650     auto shapeHeight = shapeHeight_->Get();
651     auto blockBorderWidth = blockBorderWidth_->Get();
652     if (NearZero(shapeWidth) || NearZero(shapeHeight)) {
653         return;
654     }
655 
656     auto blockCenter = GetBlockCenter();
657     float scale = std::max(blockSize.Width() / shapeWidth, blockSize.Height() / shapeHeight);
658     if (NearZero(scale)) {
659         return;
660     }
661     float blockBorderWidthUnscale = blockBorderWidth / scale;
662 
663     auto& canvas = context.canvas;
664     canvas.Save();
665     SetBlockClip(context);
666     canvas.Translate(blockCenter.GetX(), blockCenter.GetY());
667     canvas.Scale(scale, scale);
668     canvas.Translate(-blockCenter.GetX(), -blockCenter.GetY());
669 
670     RSPen pen;
671     pen.SetAntiAlias(true);
672     pen.SetWidth(blockBorderWidth);
673     pen.SetColor(ToRSColor(blockBorderColor_->Get()));
674     canvas.AttachPen(pen);
675     RSBrush brush;
676     brush.SetAntiAlias(true);
677     brush.SetColor(ToRSColor(blockColor_->Get()));
678     canvas.AttachBrush(brush);
679 
680     RectF drawRect(blockCenter.GetX() - shapeWidth * HALF + blockBorderWidthUnscale * HALF,
681         blockCenter.GetY() - shapeHeight * HALF + blockBorderWidthUnscale * HALF, shapeWidth - blockBorderWidthUnscale,
682         shapeHeight - blockBorderWidthUnscale);
683     canvas.DrawOval(ToRSRect(drawRect));
684 
685     canvas.DetachBrush();
686     canvas.DetachPen();
687     canvas.Restore();
688 }
689 
DrawBlockShapePath(DrawingContext & context,RefPtr<Path> & path)690 void SliderContentModifier::DrawBlockShapePath(DrawingContext& context, RefPtr<Path>& path)
691 {
692     auto blockSize = blockSize_->Get();
693     auto blockBorderWidth = blockBorderWidth_->Get();
694 
695     auto blockCenter = GetBlockCenter();
696     SizeF shapeSize = PathPainter::GetPathSize(path->GetValue());
697     if (NearZero(shapeSize.Width()) || NearZero(shapeSize.Height())) {
698         return;
699     }
700     float scale = std::max(blockSize.Width() / (shapeSize.Width() + blockBorderWidth),
701         blockSize.Height() / (shapeSize.Height() + blockBorderWidth));
702     if (NearZero(scale)) {
703         return;
704     }
705 
706     auto& canvas = context.canvas;
707     canvas.Save();
708     SetBlockClip(context);
709     canvas.Translate(blockCenter.GetX(), blockCenter.GetY());
710     canvas.Scale(scale, scale);
711     canvas.Translate(-blockCenter.GetX(), -blockCenter.GetY());
712 
713     RSPen pen;
714     pen.SetAntiAlias(true);
715     pen.SetWidth(blockBorderWidth);
716     pen.SetColor(ToRSColor(blockBorderColor_->Get()));
717     canvas.AttachPen(pen);
718     RSBrush brush;
719     brush.SetAntiAlias(true);
720     brush.SetColor(ToRSColor(blockColor_->Get()));
721     canvas.AttachBrush(brush);
722 
723     OffsetF offset(blockCenter.GetX() - shapeSize.Width() * HALF, blockCenter.GetY() - shapeSize.Height() * HALF);
724     PathPainter::DrawPath(canvas, path->GetValue(), offset);
725     canvas.DetachBrush();
726     canvas.DetachPen();
727     canvas.Restore();
728 }
729 
SetShapeRectRadius(RSRoundRect & roundRect,float borderWidth)730 void SliderContentModifier::SetShapeRectRadius(RSRoundRect& roundRect, float borderWidth)
731 {
732     float radiusX = rectTopLeftRadiusX_->Get() - borderWidth * HALF;
733     float radiusY = rectTopLeftRadiusY_->Get() - borderWidth * HALF;
734     roundRect.SetCornerRadius(RSRoundRect::TOP_LEFT_POS, radiusX, radiusY);
735 
736     radiusX = rectTopRightRadiusX_->Get() - borderWidth * HALF;
737     radiusY = rectTopRightRadiusY_->Get() - borderWidth * HALF;
738     roundRect.SetCornerRadius(RSRoundRect::TOP_RIGHT_POS, radiusX, radiusY);
739 
740     radiusX = rectBottomLeftRadiusX_->Get() - borderWidth * HALF;
741     radiusY = rectBottomLeftRadiusY_->Get() - borderWidth * HALF;
742     roundRect.SetCornerRadius(RSRoundRect::BOTTOM_LEFT_POS, radiusX, radiusY);
743 
744     radiusX = rectBottomRightRadiusX_->Get() - borderWidth * HALF;
745     radiusY = rectBottomRightRadiusY_->Get() - borderWidth * HALF;
746     roundRect.SetCornerRadius(RSRoundRect::BOTTOM_RIGHT_POS, radiusX, radiusY);
747 }
748 
DrawBlockShapeRect(DrawingContext & context,RefPtr<ShapeRect> & rect)749 void SliderContentModifier::DrawBlockShapeRect(DrawingContext& context, RefPtr<ShapeRect>& rect)
750 {
751     auto shapeWidth = shapeWidth_->Get();
752     auto shapeHeight = shapeHeight_->Get();
753     if (NearZero(shapeWidth) || NearZero(shapeHeight)) {
754         return;
755     }
756     auto blockSize = blockSize_->Get();
757     float scale = std::max(blockSize.Width() / shapeWidth, blockSize.Height() / shapeHeight);
758     if (NearZero(scale)) {
759         return;
760     }
761     auto blockBorderWidth = blockBorderWidth_->Get();
762     float blockBorderWidthUnscale = blockBorderWidth / scale;
763     auto blockCenter = GetBlockCenter();
764 
765     auto& canvas = context.canvas;
766     canvas.Save();
767     SetBlockClip(context);
768     canvas.Translate(blockCenter.GetX(), blockCenter.GetY());
769     canvas.Scale(scale, scale);
770     canvas.Translate(-blockCenter.GetX(), -blockCenter.GetY());
771 
772     RSPen pen;
773     pen.SetAntiAlias(true);
774     pen.SetWidth(blockBorderWidth_->Get());
775     pen.SetColor(ToRSColor(blockBorderColor_->Get()));
776     canvas.AttachPen(pen);
777     RSBrush brush;
778     brush.SetAntiAlias(true);
779     brush.SetColor(ToRSColor(blockColor_->Get()));
780     canvas.AttachBrush(brush);
781 
782     RSRoundRect roundRect;
783     RSRect rsRect;
784     rsRect.SetLeft(blockCenter.GetX() - shapeWidth * HALF + blockBorderWidthUnscale * HALF);
785     rsRect.SetRight(blockCenter.GetX() + shapeWidth * HALF - blockBorderWidthUnscale);
786     rsRect.SetTop(blockCenter.GetY() - shapeHeight * HALF + blockBorderWidthUnscale * HALF);
787     rsRect.SetBottom(blockCenter.GetY() + shapeHeight * HALF - blockBorderWidthUnscale);
788     roundRect.SetRect(rsRect);
789     SetShapeRectRadius(roundRect, blockBorderWidthUnscale);
790 
791     canvas.DrawRoundRect(roundRect);
792     canvas.DetachBrush();
793     canvas.DetachPen();
794     canvas.Restore();
795 }
796 
SetBlockShape(const RefPtr<BasicShape> & shape)797 void SliderContentModifier::SetBlockShape(const RefPtr<BasicShape>& shape)
798 {
799     shape_ = shape;
800     CHECK_NULL_VOID(shape_);
801     shapeWidth_->Set(shape_->GetWidth().ConvertToPx());
802     shapeHeight_->Set(shape_->GetHeight().ConvertToPx());
803     if (shape->GetBasicShapeType() == BasicShapeType::CIRCLE) {
804         auto circle = DynamicCast<Circle>(shape_);
805         CHECK_NULL_VOID(circle);
806         if (circle->GetRadius().IsValid()) {
807             circleRadius_->Set(circle->GetRadius().ConvertToPx());
808         } else {
809             circleRadius_->Set(std::min(shape_->GetWidth().ConvertToPx(), shape_->GetHeight().ConvertToPx()) * HALF);
810         }
811     } else if (shape->GetBasicShapeType() == BasicShapeType::ELLIPSE) {
812         auto ellipse = DynamicCast<Ellipse>(shape_);
813         CHECK_NULL_VOID(ellipse);
814         if (ellipse->GetRadiusX().IsValid() && ellipse->GetRadiusY().IsValid()) {
815             ellipseRadiusX_->Set(ellipse->GetRadiusX().ConvertToPx());
816             ellipseRadiusY_->Set(ellipse->GetRadiusY().ConvertToPx());
817         } else {
818             ellipseRadiusX_->Set(shape_->GetWidth().ConvertToPx() * HALF);
819             ellipseRadiusY_->Set(shape_->GetHeight().ConvertToPx() * HALF);
820         }
821     } else if (shape->GetBasicShapeType() == BasicShapeType::RECT) {
822         auto rect = DynamicCast<ShapeRect>(shape_);
823         CHECK_NULL_VOID(rect);
824         rectTopLeftRadiusX_->Set(rect->GetTopLeftRadius().GetX().ConvertToPx());
825         rectTopLeftRadiusY_->Set(rect->GetTopLeftRadius().GetY().ConvertToPx());
826         rectTopRightRadiusX_->Set(rect->GetTopRightRadius().GetX().ConvertToPx());
827         rectTopRightRadiusY_->Set(rect->GetTopRightRadius().GetY().ConvertToPx());
828         rectBottomLeftRadiusX_->Set(rect->GetBottomLeftRadius().GetX().ConvertToPx());
829         rectBottomLeftRadiusY_->Set(rect->GetBottomLeftRadius().GetY().ConvertToPx());
830         rectBottomRightRadiusX_->Set(rect->GetBottomRightRadius().GetX().ConvertToPx());
831         rectBottomRightRadiusY_->Set(rect->GetBottomRightRadius().GetY().ConvertToPx());
832     }
833 }
834 
UpdateContentDirtyRect(const SizeF & frameSize)835 void SliderContentModifier::UpdateContentDirtyRect(const SizeF& frameSize)
836 {
837     if (useContentModifier_->Get()) {
838         return;
839     }
840     auto pipeline = PipelineBase::GetCurrentContext();
841     CHECK_NULL_VOID(pipeline);
842     auto theme = pipeline->GetTheme<SliderTheme>();
843     CHECK_NULL_VOID(theme);
844     auto hotShadowWidth = sliderMode_->Get() == static_cast<int32_t>(SliderModel::SliderMode::OUTSET)
845                               ? theme->GetOutsetHotBlockShadowWidth().ConvertToPx()
846                               : theme->GetInsetHotBlockShadowWidth().ConvertToPx();
847     auto circleSize =
848         SizeF(blockSize_->Get().Width() + hotShadowWidth / HALF, blockSize_->Get().Height() + hotShadowWidth / HALF);
849     RectF rect;
850     if (directionAxis_->Get() == static_cast<int32_t>(Axis::HORIZONTAL)) {
851         auto maxWidth = std::max(circleSize.Height(), frameSize.Height()) * HALF;
852         rect.SetOffset(OffsetF(-circleSize.Width(), blockCenterY_->Get() - maxWidth));
853         rect.SetSize(SizeF(circleSize.Width() / HALF + frameSize.Width(), maxWidth / HALF));
854     } else {
855         auto maxWidth = std::max(circleSize.Width(), frameSize.Width()) * HALF;
856         rect.SetOffset(OffsetF(blockCenterX_->Get() - maxWidth, -circleSize.Height()));
857         rect.SetSize(SizeF(maxWidth / HALF, circleSize.Height() / HALF + frameSize.Height()));
858     }
859 
860     SetBoundsRect(rect);
861 }
862 
SetBlockClip(DrawingContext & context)863 void SliderContentModifier::SetBlockClip(DrawingContext& context)
864 {
865     auto& canvas = context.canvas;
866     auto blockCenter = GetBlockCenter();
867     auto blockSize = blockSize_->Get();
868     RectF rect(blockCenter.GetX() - blockSize.Width() * HALF, blockCenter.GetY() - blockSize.Height() * HALF,
869         blockSize.Width(), blockSize.Height());
870     canvas.ClipRect(ToRSRect(rect), RSClipOp::INTERSECT);
871 }
872 
GetTrackBackgroundColor() const873 std::vector<GradientColor> SliderContentModifier::GetTrackBackgroundColor() const
874 {
875     Gradient gradient = SortGradientColorsByOffset(trackBackgroundColor_->Get().GetGradient());
876     std::vector<GradientColor> gradientColors = gradient.GetColors();
877     // Fault protection processing, if gradientColors is empty, set to default colors.
878 
879     if (gradientColors.empty()) {
880         auto pipeline = PipelineBase::GetCurrentContext();
881         CHECK_NULL_RETURN(pipeline, gradientColors);
882         auto theme = pipeline->GetTheme<SliderTheme>();
883         CHECK_NULL_RETURN(theme, gradientColors);
884         gradientColors = SliderModelNG::CreateSolidGradient(theme->GetTrackBgColor()).GetColors();
885     }
886     return gradientColors;
887 }
888 
SortGradientColorsByOffset(const Gradient & gradient) const889 Gradient SliderContentModifier::SortGradientColorsByOffset(const Gradient& gradient) const
890 {
891     auto srcGradientColors = gradient.GetColors();
892     std::sort(
893         srcGradientColors.begin(), srcGradientColors.end(), [](const GradientColor& left, const GradientColor& right) {
894             return left.GetDimension().Value() < right.GetDimension().Value();
895         });
896 
897     Gradient sortedGradient;
898     for (const auto& item : srcGradientColors) {
899         sortedGradient.AddColor(item);
900     }
901 
902     return sortedGradient;
903 }
904 } // namespace OHOS::Ace::NG
905