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