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