1 /*
2 * Copyright (c) 2023-2025 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/progress/progress_modifier.h"
17
18 #include "core/components/progress/progress_theme.h"
19 #include "core/components_ng/render/drawing_prop_convertor.h"
20
21 namespace OHOS::Ace::NG {
22 namespace {
23 constexpr int32_t INT32_TWO = 2;
24 constexpr int32_t ANGLE_45 = 45;
25 constexpr int32_t ANGLE_90 = 90;
26 constexpr int32_t ANGLE_180 = 180;
27 constexpr int32_t ANGLE_270 = 270;
28 constexpr int32_t ANGLE_360 = 360;
29 constexpr int32_t TIME_2000 = 2000; // 2000 ms
30 constexpr int32_t TIME_4000 = 4000; // 4000 ms
31 constexpr int32_t LOADING_ANIMATION_DURATION = 2000;
32 constexpr float DEFAULT_MAX_VALUE = 100.0f;
33 constexpr float DEFAULT_SCALE_WIDTH = 10.0f;
34 constexpr float DEFAULT_MIN_PROGRESS_WIDTH = 0.0f;
35 constexpr int32_t DEFAULT_SCALE_COUNT = 100;
36 constexpr double DEFAULT_CAPSULE_BORDER_WIDTH = 0.0;
37 constexpr float FLOAT_ZERO_FIVE = 0.5f;
38 constexpr float FLOAT_TWO_ZERO = 2.0f;
39 constexpr float SPRING_MOTION_RESPONSE = 0.314f;
40 constexpr float SPRING_MOTION_DAMPING_FRACTION = 0.95f;
41 constexpr Dimension SWEEP_WIDTH = 80.0_vp;
42 constexpr float RING_SHADOW_OFFSET_X = 5.0f;
43 constexpr float RING_SHADOW_OFFSET_Y = 5.0f;
44 constexpr float RING_SHADOW_BLUR_RADIUS_MIN = 5.0f;
45 constexpr float RING_SHADOW_VALID_RADIUS_MIN = 10.0f;
46 constexpr float RING_SHADOW_OPACITY = 0.4f;
47 constexpr Dimension LINEAR_SWEEPING_LEN = 80.0_vp;
48 } // namespace
ProgressModifier(const WeakPtr<FrameNode> & host,const ProgressAnimatableProperty & progressAnimatableProperty_)49 ProgressModifier::ProgressModifier(const WeakPtr<FrameNode>& host,
50 const ProgressAnimatableProperty& progressAnimatableProperty_)
51 : strokeWidth_(AceType::MakeRefPtr<AnimatablePropertyFloat>(progressAnimatableProperty_.strokeWidth)),
52 color_(AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(progressAnimatableProperty_.color))),
53 bgColor_(AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(progressAnimatableProperty_.bgColor))),
54 borderColor_(AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(progressAnimatableProperty_.borderColor))),
55 value_(AceType::MakeRefPtr<AnimatablePropertyFloat>(progressAnimatableProperty_.value)),
56 ringProgressColors_(AceType::MakeRefPtr<AnimatablePropertyVectorColor>(
57 GradientArithmetic(progressAnimatableProperty_.ringProgressColor))),
58 sweepingDate_(AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f)),
59 trailingHeadDate_(AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f)),
60 trailingTailDate_(AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f)),
61 strokeRadius_(AceType::MakeRefPtr<AnimatablePropertyFloat>(progressAnimatableProperty_.strokeRadius)),
62 offset_(AceType::MakeRefPtr<PropertyOffsetF>(OffsetF())),
63 contentSize_(AceType::MakeRefPtr<PropertySizeF>(SizeF())),
64 maxValue_(AceType::MakeRefPtr<PropertyFloat>(DEFAULT_MAX_VALUE)),
65 scaleWidth_(AceType::MakeRefPtr<PropertyFloat>(DEFAULT_SCALE_WIDTH)),
66 scaleCount_(AceType::MakeRefPtr<PropertyInt>(DEFAULT_SCALE_COUNT)),
67 progressType_(AceType::MakeRefPtr<PropertyInt>(static_cast<int32_t>(ProgressType::LINEAR))),
68 capsuleBorderWidth_(AceType::MakeRefPtr<PropertyFloat>(DEFAULT_CAPSULE_BORDER_WIDTH)),
69 sweepEffect_(AceType::MakeRefPtr<PropertyBool>(false)),
70 ringSweepEffect_(AceType::MakeRefPtr<PropertyBool>(false)),
71 linearSweepEffect_(AceType::MakeRefPtr<PropertyBool>(false)),
72 paintShadow_(AceType::MakeRefPtr<PropertyBool>(false)),
73 progressStatus_(AceType::MakeRefPtr<PropertyInt>(static_cast<int32_t>(ProgressStatus::PROGRESSING))),
74 isItalic_(AceType::MakeRefPtr<PropertyBool>(false)),
75 smoothEffect_(AceType::MakeRefPtr<PropertyBool>(true)),
76 useContentModifier_(AceType::MakeRefPtr<PropertyBool>(false)),
77 isRightToLeft_(AceType::MakeRefPtr<PropertyBool>(false)),
78 progressUpdate_(AceType::MakeRefPtr<PropertyBool>(false)),
79 capsuleBorderRadius_(AceType::MakeRefPtr<PropertyFloat>(0.0f)),
80 host_(host)
81 {
82 AttachProperty(strokeWidth_);
83 AttachProperty(color_);
84 AttachProperty(bgColor_);
85 AttachProperty(borderColor_);
86 AttachProperty(maxValue_);
87 AttachProperty(value_);
88 AttachProperty(scaleWidth_);
89 AttachProperty(scaleCount_);
90 AttachProperty(progressType_);
91 AttachProperty(capsuleBorderWidth_);
92 AttachProperty(sweepEffect_);
93 AttachProperty(trailingHeadDate_);
94 AttachProperty(trailingTailDate_);
95 AttachProperty(strokeRadius_);
96
97 AttachProperty(ringProgressColors_);
98 AttachProperty(sweepingDate_);
99 AttachProperty(paintShadow_);
100 AttachProperty(progressStatus_);
101 AttachProperty(ringSweepEffect_);
102 AttachProperty(linearSweepEffect_);
103 AttachProperty(isItalic_);
104 AttachProperty(smoothEffect_);
105 AttachProperty(isRightToLeft_);
106 AttachProperty(progressUpdate_);
107 AttachProperty(capsuleBorderRadius_);
108
109 auto pipeline = PipelineBase::GetCurrentContext();
110 CHECK_NULL_VOID(pipeline);
111 auto theme = pipeline->GetTheme<ProgressTheme>(GetThemeScopeId());
112 CHECK_NULL_VOID(theme);
113
114 pressBlendColor_ = theme->GetClickEffect();
115 hoverBlendColor_ = theme->GetHoverBlendColor();
116 }
117
onDraw(DrawingContext & context)118 void ProgressModifier::onDraw(DrawingContext& context)
119 {
120 if (useContentModifier_->Get()) {
121 return;
122 }
123 ContentDrawWithFunction(context);
124 }
125
SetUseContentModifier(bool useContentModifier)126 void ProgressModifier::SetUseContentModifier(bool useContentModifier)
127 {
128 if (useContentModifier_) {
129 useContentModifier_->Set(useContentModifier);
130 }
131 }
132
SetStrokeWidth(float width)133 void ProgressModifier::SetStrokeWidth(float width)
134 {
135 CHECK_NULL_VOID(strokeWidth_);
136 strokeWidth_->Set(width);
137 }
138
SetColor(LinearColor color)139 void ProgressModifier::SetColor(LinearColor color)
140 {
141 CHECK_NULL_VOID(color_);
142 color_->Set(color);
143 }
144
SetBackgroundColor(LinearColor color)145 void ProgressModifier::SetBackgroundColor(LinearColor color)
146 {
147 CHECK_NULL_VOID(bgColor_);
148 bgColor_->Set(color);
149 }
150
SetBorderColor(LinearColor color)151 void ProgressModifier::SetBorderColor(LinearColor color)
152 {
153 CHECK_NULL_VOID(borderColor_);
154 borderColor_->Set(color);
155 }
156
SetProgressType(ProgressType type)157 void ProgressModifier::SetProgressType(ProgressType type)
158 {
159 CHECK_NULL_VOID(progressType_);
160 progressType_->Set(static_cast<int32_t>(type));
161 }
162
UpdateProgress()163 void ProgressModifier::UpdateProgress()
164 {
165 progressUpdate_->Set(!progressUpdate_->Get());
166 }
167
ProcessSweepingAnimation(ProgressType type,float value)168 void ProgressModifier::ProcessSweepingAnimation(ProgressType type, float value)
169 {
170 if (!isVisible_) {
171 return;
172 }
173
174 switch (type) {
175 case ProgressType::RING:
176 ProcessRingSweepingAnimation(value);
177 break;
178 case ProgressType::LINEAR:
179 ProcessLinearSweepingAnimation(value);
180 break;
181 case ProgressType::CAPSULE:
182 StartCapsuleSweepingAnimation(value);
183 break;
184 default:
185 break;
186 }
187 }
188
StartCapsuleSweepingAnimation(float value)189 void ProgressModifier::StartCapsuleSweepingAnimation(float value)
190 {
191 auto contentSize = contentSize_->Get();
192 float barLength =
193 GreatOrEqual(contentSize.Width(), contentSize.Height()) ? contentSize.Width() : contentSize.Height();
194 float date = (value / maxValue_->Get()) * barLength + SWEEP_WIDTH.ConvertToPx();
195 float sweepSpeed = barLength / TIME_2000; // It takes 2 seconds to sweep the whole bar length.
196
197 if (!isSweeping_ && sweepEffect_->Get() && isVisible_) {
198 StartCapsuleSweepingAnimationImpl(date, sweepSpeed);
199 } else if (!sweepEffect_->Get() || !isVisible_) {
200 StopSweepingAnimation();
201 } else {
202 dateUpdated_ = !NearEqual(sweepingDateBackup_, date);
203 }
204 sweepingDateBackup_ = date;
205 }
206
StartCapsuleSweepingAnimationImpl(float value,float speed)207 void ProgressModifier::StartCapsuleSweepingAnimationImpl(float value, float speed)
208 {
209 if (!isVisible_ || !sweepEffect_) {
210 return;
211 }
212
213 isSweeping_ = true;
214 sweepingDate_->Set(0.0f);
215 speed = NearZero(speed) ? 1.0f : speed;
216 int32_t time = value / speed;
217 AnimationOption option = AnimationOption();
218 auto motion = AceType::MakeRefPtr<LinearCurve>();
219 option.SetCurve(motion);
220 option.SetIteration(-1);
221 option.SetDuration(time);
222
223 AnimationUtils::Animate(
224 option,
225 [value, id = Container::CurrentId(), weak = WeakClaim(this)]() {
226 ContainerScope scope(id);
227 auto modifier = weak.Upgrade();
228 CHECK_NULL_VOID(modifier);
229 modifier->sweepingDate_->Set(value);
230 },
231 nullptr,
232 [id = Container::CurrentId(), weak = WeakClaim(this), speed]() {
233 ContainerScope scope(id);
234 auto modifier = weak.Upgrade();
235 CHECK_NULL_VOID(modifier);
236 float currentDate = modifier->sweepingDate_->Get();
237 if (modifier->dateUpdated_) {
238 modifier->dateUpdated_ = false;
239 modifier->StopSweepingAnimation(currentDate);
240 modifier->StartContinuousSweepingAnimation(currentDate, modifier->sweepingDateBackup_, speed);
241 auto context = PipelineBase::GetCurrentContext();
242 context->RequestFrame();
243 }
244 });
245 }
246
SetRingProgressColor(const Gradient & color)247 void ProgressModifier::SetRingProgressColor(const Gradient& color)
248 {
249 CHECK_NULL_VOID(ringProgressColors_);
250 ringProgressColors_->Set(GradientArithmetic(color));
251 }
252
SetPaintShadow(bool paintShadow)253 void ProgressModifier::SetPaintShadow(bool paintShadow)
254 {
255 CHECK_NULL_VOID(paintShadow_);
256 paintShadow_->Set(paintShadow);
257 }
258
SetProgressStatus(ProgressStatus status)259 void ProgressModifier::SetProgressStatus(ProgressStatus status)
260 {
261 CHECK_NULL_VOID(progressStatus_);
262 progressStatus_->Set(static_cast<int32_t>(status));
263 if (status == ProgressStatus::LOADING) {
264 StartRingLoadingAnimation();
265 }
266 }
267
SetIsItalic(bool isItalic)268 void ProgressModifier::SetIsItalic(bool isItalic)
269 {
270 CHECK_NULL_VOID(isItalic_);
271 isItalic_->Set(isItalic);
272 }
273
SetVisible(bool isVisible)274 void ProgressModifier::SetVisible(bool isVisible)
275 {
276 CHECK_NULL_VOID(isVisible_ != isVisible);
277 isVisible_ = isVisible;
278
279 if (!isVisible) {
280 if (isLoading_) {
281 StopRingLoadingHeadAnimation();
282 StopRingLoadingTailAnimation();
283 }
284
285 if (isSweeping_) {
286 StopSweepingAnimation();
287 }
288 }
289 }
290
SetSmoothEffect(bool value)291 void ProgressModifier::SetSmoothEffect(bool value)
292 {
293 CHECK_NULL_VOID(smoothEffect_);
294 smoothEffect_->Set(value);
295 }
296
StartRingLoadingAnimation()297 void ProgressModifier::StartRingLoadingAnimation()
298 {
299 if (!isLoading_ && isVisible_) {
300 isLoading_ = true;
301 StartRingLoadingHeadAnimation();
302 StartRingLoadingTailAnimation();
303 }
304 }
305
StartRingLoadingHeadAnimation()306 void ProgressModifier::StartRingLoadingHeadAnimation()
307 {
308 auto context = PipelineBase::GetCurrentContext();
309 CHECK_NULL_VOID(context);
310 bool isFormRender = context->IsFormRender() && !IsDynamicComponent();
311 AnimationOption optionHead = AnimationOption();
312 auto curveHead = AceType::MakeRefPtr<TailingHeadCurve>();
313 optionHead.SetDuration(LOADING_ANIMATION_DURATION);
314 optionHead.SetCurve(curveHead);
315 optionHead.SetIteration(isFormRender ? 1 : -1);
316 AnimationUtils::Animate(
317 optionHead, [&]() { trailingHeadDate_->Set(ANGLE_360); }, nullptr,
318 [weak = AceType::WeakClaim(this), id = Container::CurrentId()]() {
319 ContainerScope scope(id);
320 auto modifier = weak.Upgrade();
321 CHECK_NULL_VOID(modifier);
322 if (static_cast<ProgressStatus>(modifier->progressStatus_->Get()) == ProgressStatus::PROGRESSING) {
323 modifier->StopRingLoadingHeadAnimation();
324 }
325 });
326 }
327
StartRingLoadingTailAnimation()328 void ProgressModifier::StartRingLoadingTailAnimation()
329 {
330 auto context = PipelineBase::GetCurrentContext();
331 CHECK_NULL_VOID(context);
332 bool isFormRender = context->IsFormRender() && !IsDynamicComponent();
333 AnimationOption optionTail = AnimationOption();
334 auto curveTail = AceType::MakeRefPtr<CubicCurve>(0.33f, 0.00f, 0.66f, 0.10f);
335 optionTail.SetDuration(LOADING_ANIMATION_DURATION);
336 optionTail.SetCurve(curveTail);
337 optionTail.SetIteration(isFormRender ? 1 : -1);
338 AnimationUtils::Animate(
339 optionTail,
340 [&]() { trailingTailDate_->Set(ANGLE_360); },
341 nullptr,
342 [weak = AceType::WeakClaim(this), id = Container::CurrentId()]() {
343 ContainerScope scope(id);
344 auto modifier = weak.Upgrade();
345 CHECK_NULL_VOID(modifier);
346 if (static_cast<ProgressStatus>(modifier->progressStatus_->Get()) == ProgressStatus::PROGRESSING) {
347 modifier->StopRingLoadingTailAnimation();
348 if (GreatOrEqual(modifier->valueBackup_, 0.0f)) {
349 modifier->SetValue(modifier->valueBackup_);
350 }
351 }
352 });
353 }
354
StopRingLoadingHeadAnimation()355 void ProgressModifier::StopRingLoadingHeadAnimation()
356 {
357 AnimationOption option = AnimationOption();
358 option.SetDuration(0);
359 AnimationUtils::Animate(option, [&]() { trailingHeadDate_->Set(0.0f); });
360 }
361
StopRingLoadingTailAnimation()362 void ProgressModifier::StopRingLoadingTailAnimation()
363 {
364 AnimationOption option = AnimationOption();
365 option.SetDuration(0);
366 AnimationUtils::Animate(option, [&]() { trailingTailDate_->Set(0.0f); });
367 isLoading_ = false;
368 }
369
ProcessRingSweepingAnimation(float value)370 void ProgressModifier::ProcessRingSweepingAnimation(float value)
371 {
372 if (NearZero(value) || NearEqual(value, maxValue_->Get())) {
373 StopSweepingAnimation();
374 } else {
375 StartRingSweepingAnimation(value);
376 }
377 }
378
ProcessLinearSweepingAnimation(float value)379 void ProgressModifier::ProcessLinearSweepingAnimation(float value)
380 {
381 if (NearZero(value) || NearEqual(value, maxValue_->Get())) {
382 StopSweepingAnimation();
383 } else {
384 StartLinearSweepingAnimation(value);
385 }
386 }
387
StartRingSweepingAnimation(float value)388 void ProgressModifier::StartRingSweepingAnimation(float value)
389 {
390 float maxValue = NearZero(maxValue_->Get()) ? 1.0f : maxValue_->Get();
391 float date = value / maxValue * ANGLE_360 + ANGLE_45;
392 float additionalAngle = CalcRingProgressAdditionalAngle();
393 date += additionalAngle * 2;
394 float sweepSpeed = float(ANGLE_360) / TIME_4000; // It takes 4 seconds to sweep a circle
395
396 if (!isSweeping_ && ringSweepEffect_->Get()) {
397 StartRingSweepingAnimationImpl(date, sweepSpeed);
398 } else if (!ringSweepEffect_->Get() || NearEqual(valueBackup_, maxValue_->Get())) {
399 StopSweepingAnimation();
400 } else {
401 dateUpdated_ = !NearEqual(sweepingDateBackup_, date);
402 }
403
404 sweepingDateBackup_ = date;
405 }
406
StartRingSweepingAnimationImpl(float date,float speed)407 void ProgressModifier::StartRingSweepingAnimationImpl(float date, float speed)
408 {
409 if (!isVisible_ || !ringSweepEffect_) {
410 return;
411 }
412
413 if (NearEqual(valueBackup_, maxValue_->Get())) {
414 return;
415 }
416
417 auto context = PipelineBase::GetCurrentContext();
418 CHECK_NULL_VOID(context);
419 bool isFormRender = context->IsFormRender() && !IsDynamicComponent();
420 isSweeping_ = true;
421 AnimationOption option = AnimationOption();
422 speed = NearZero(speed) ? 1.0f : speed;
423 int32_t time = date / speed;
424 auto motion = AceType::MakeRefPtr<LinearCurve>();
425 option.SetCurve(motion);
426 option.SetIteration(isFormRender ? 1 : -1);
427 option.SetDuration(time);
428 AnimationUtils::Animate(
429 option,
430 [&]() { sweepingDate_->Set(date); },
431 nullptr,
432 [weak = WeakClaim(this), id = Container::CurrentId(), speed]() {
433 ContainerScope scope(id);
434 auto modifier = weak.Upgrade();
435 CHECK_NULL_VOID(modifier);
436 if (modifier->dateUpdated_) {
437 modifier->dateUpdated_ = false;
438 float currentDate = modifier->sweepingDate_->Get();
439 modifier->StopSweepingAnimation(currentDate);
440 modifier->StartContinuousSweepingAnimation(currentDate, modifier->sweepingDateBackup_, speed);
441 auto context = PipelineBase::GetCurrentContext();
442 context->RequestFrame();
443 }
444 });
445 }
446
StartContinuousSweepingAnimation(float currentDate,float newDate,float speed)447 void ProgressModifier::StartContinuousSweepingAnimation(float currentDate, float newDate, float speed)
448 {
449 if (!isVisible_ || !IsSweepEffectOn()) {
450 return;
451 }
452
453 if (NearEqual(valueBackup_, maxValue_->Get()) &&
454 (ProgressType(progressType_->Get()) == ProgressType::LINEAR ||
455 ProgressType(progressType_->Get()) == ProgressType::RING)) {
456 return;
457 }
458
459 isSweeping_ = true;
460 speed = NearZero(speed) ? 1.0f : speed;
461 int32_t time = (newDate - currentDate) / speed;
462 AnimationOption option = AnimationOption();
463 auto motion = AceType::MakeRefPtr<LinearCurve>();
464 option.SetCurve(motion);
465 option.SetDuration(time);
466 AnimationUtils::Animate(
467 option,
468 [&]() { sweepingDate_->Set(newDate); },
469 [weak = WeakClaim(this), id = Container::CurrentId(), speed]() {
470 ContainerScope scope(id);
471 auto modifier = weak.Upgrade();
472 CHECK_NULL_VOID(modifier);
473 if (!modifier->dateUpdated_) {
474 modifier->sweepingDate_->Set(0.0f);
475 switch (ProgressType(modifier->progressType_->Get())) {
476 case ProgressType::LINEAR:
477 modifier->StartLinearSweepingAnimationImpl(modifier->sweepingDateBackup_, speed);
478 break;
479 case ProgressType::CAPSULE:
480 modifier->StartCapsuleSweepingAnimationImpl(modifier->sweepingDateBackup_, speed);
481 break;
482 case ProgressType::RING:
483 modifier->StartRingSweepingAnimationImpl(modifier->sweepingDateBackup_, speed);
484 break;
485 default:
486 return;
487 }
488 auto context = PipelineBase::GetCurrentContext();
489 context->RequestFrame();
490 } else {
491 modifier->dateUpdated_ = false;
492 float currentDate = modifier->sweepingDate_->Get();
493 modifier->StartContinuousSweepingAnimation(currentDate, modifier->sweepingDateBackup_, speed);
494 auto context = PipelineBase::GetCurrentContext();
495 context->RequestFrame();
496 }
497 });
498 }
499
IsSweepEffectOn()500 bool ProgressModifier::IsSweepEffectOn()
501 {
502 switch (ProgressType(progressType_->Get())) {
503 case ProgressType::LINEAR:
504 return linearSweepEffect_;
505 case ProgressType::CAPSULE:
506 return sweepEffect_;
507 case ProgressType::RING:
508 return ringSweepEffect_;
509 default:
510 return false;
511 }
512 }
513
StopSweepingAnimation(float date)514 void ProgressModifier::StopSweepingAnimation(float date)
515 {
516 if (isSweeping_) {
517 isSweeping_ = false;
518 dateUpdated_ = false;
519 AnimationOption option = AnimationOption();
520 option.SetDuration(0);
521 AnimationUtils::Animate(option, [&]() { sweepingDate_->Set(date); });
522 }
523 }
524
CalcRingProgressAdditionalAngle() const525 float ProgressModifier::CalcRingProgressAdditionalAngle() const
526 {
527 auto contentSize = contentSize_->Get();
528 auto strokeWidth = strokeWidth_->Get();
529 PointF centerPt = PointF(contentSize.Width() / 2, contentSize.Height() / 2);
530 float radius = std::min(contentSize.Width() / 2, contentSize.Height() / 2);
531 auto paintShadow = paintShadow_->Get() && GreatNotEqual(radius, RING_SHADOW_VALID_RADIUS_MIN);
532 auto shadowBlurOffset = paintShadow ? strokeWidth / 2 + std::max(RING_SHADOW_OFFSET_X, RING_SHADOW_OFFSET_Y) : 0.0f;
533 if (GreatOrEqual(strokeWidth + shadowBlurOffset, radius)) {
534 strokeWidth = radius / 2;
535 shadowBlurOffset = paintShadow ? strokeWidth / 2 + std::max(RING_SHADOW_OFFSET_X, RING_SHADOW_OFFSET_Y) : 0.0f;
536 }
537 return asinf((strokeWidth / 2) / (radius - strokeWidth / 2 - shadowBlurOffset)) * ANGLE_180 / PI_NUM;
538 }
539
StartLinearSweepingAnimation(float value)540 void ProgressModifier::StartLinearSweepingAnimation(float value)
541 {
542 auto contentSize = contentSize_->Get();
543 float radius = strokeWidth_->Get() / 2;
544 float barLength = 0.0f;
545 float dateLength = 0.0f;
546
547 if (GreatOrEqual(contentSize.Width(), contentSize.Height())) {
548 barLength = contentSize.Width() - radius * 2;
549 } else {
550 barLength = contentSize.Height() - radius * 2;
551 }
552
553 if (NearEqual(barLength, 0.0f)) {
554 return;
555 }
556
557 dateLength = barLength * value / maxValue_->Get();
558 if (NearEqual(dateLength, 0.0f)) {
559 return;
560 }
561
562 float date = dateLength + strokeWidth_->Get() + LINEAR_SWEEPING_LEN.ConvertToPx();
563 float sweepSpeed = barLength / TIME_2000; // It takes 2 seconds to sweep the whole bar length
564 if (!isSweeping_ && linearSweepEffect_->Get()) {
565 StartLinearSweepingAnimationImpl(date, sweepSpeed);
566 } else if (!linearSweepEffect_->Get() || NearEqual(valueBackup_, maxValue_->Get())) {
567 StopSweepingAnimation();
568 } else {
569 dateUpdated_ = !NearEqual(sweepingDateBackup_, date);
570 }
571
572 sweepingDateBackup_ = date;
573 }
574
StartLinearSweepingAnimationImpl(float date,float speed)575 void ProgressModifier::StartLinearSweepingAnimationImpl(float date, float speed)
576 {
577 if (!isVisible_ || !linearSweepEffect_) {
578 return;
579 }
580
581 if (NearEqual(valueBackup_, maxValue_->Get())) {
582 return;
583 }
584
585 auto context = PipelineBase::GetCurrentContext();
586 CHECK_NULL_VOID(context);
587 bool isFormRender = context->IsFormRender() && !IsDynamicComponent();
588 isSweeping_ = true;
589 sweepingDate_->Set(0.0f);
590 speed = NearZero(speed) ? 1.0f : speed;
591 int32_t time = date / speed;
592 AnimationOption option = AnimationOption();
593 auto motion = AceType::MakeRefPtr<LinearCurve>();
594 option.SetCurve(motion);
595 option.SetIteration(isFormRender ? 1 : -1);
596 option.SetDuration(time);
597 AnimationUtils::Animate(
598 option,
599 [&]() { sweepingDate_->Set(date); },
600 nullptr,
601 [weak = WeakClaim(this), id = Container::CurrentId(), speed]() {
602 ContainerScope scope(id);
603 auto modifier = weak.Upgrade();
604 CHECK_NULL_VOID(modifier);
605 if (modifier->dateUpdated_) {
606 modifier->dateUpdated_ = false;
607 float currentDate = modifier->sweepingDate_->Get();
608 modifier->StopSweepingAnimation(currentDate);
609 modifier->StartContinuousSweepingAnimation(currentDate, modifier->sweepingDateBackup_, speed);
610 auto context = PipelineBase::GetCurrentContext();
611 context->RequestFrame();
612 }
613 });
614 }
615
SetMaxValue(float value)616 void ProgressModifier::SetMaxValue(float value)
617 {
618 CHECK_NULL_VOID(maxValue_);
619 maxValue_->Set(value);
620 }
621
SetValue(float value)622 void ProgressModifier::SetValue(float value)
623 {
624 valueBackup_ = value;
625
626 if (isLoading_) {
627 return;
628 }
629
630 CHECK_NULL_VOID(value_);
631 AnimationOption option = AnimationOption();
632 if (smoothEffect_->Get()) {
633 if (isVisible_) {
634 auto motion =
635 AceType::MakeRefPtr<ResponsiveSpringMotion>(SPRING_MOTION_RESPONSE, SPRING_MOTION_DAMPING_FRACTION);
636 option.SetCurve(motion);
637 } else {
638 option.SetDuration(0);
639 }
640 AnimationUtils::Animate(option, [&]() { value_->Set(value); });
641 } else {
642 value_->Set(value);
643 }
644 ProcessSweepingAnimation(ProgressType(progressType_->Get()), value);
645 }
646
SetScaleWidth(float value)647 void ProgressModifier::SetScaleWidth(float value)
648 {
649 CHECK_NULL_VOID(scaleWidth_);
650 scaleWidth_->Set(value);
651 }
652
SetScaleCount(int32_t value)653 void ProgressModifier::SetScaleCount(int32_t value)
654 {
655 CHECK_NULL_VOID(scaleCount_);
656 scaleCount_->Set(value);
657 }
658
SetContentOffset(const OffsetF & offset)659 void ProgressModifier::SetContentOffset(const OffsetF& offset)
660 {
661 CHECK_NULL_VOID(offset_);
662 offset_->Set(offset);
663 }
664
SetContentSize(const SizeF & contentSize)665 void ProgressModifier::SetContentSize(const SizeF& contentSize)
666 {
667 CHECK_NULL_VOID(contentSize_);
668 contentSize_->Set(contentSize);
669 }
670
SetBorderWidth(float width)671 void ProgressModifier::SetBorderWidth(float width)
672 {
673 capsuleBorderWidth_->Set(width);
674 }
675
SetSweepEffect(bool value)676 void ProgressModifier::SetSweepEffect(bool value)
677 {
678 sweepEffect_->Set(value);
679 }
680
SetRingSweepEffect(bool value)681 void ProgressModifier::SetRingSweepEffect(bool value)
682 {
683 ringSweepEffect_->Set(value);
684 }
685
SetLinearSweepEffect(bool value)686 void ProgressModifier::SetLinearSweepEffect(bool value)
687 {
688 linearSweepEffect_->Set(value);
689 }
690
SetCapsuleBorderRadius(float borderRadius)691 void ProgressModifier::SetCapsuleBorderRadius(float borderRadius)
692 {
693 CHECK_NULL_VOID(capsuleBorderRadius_);
694 capsuleBorderRadius_->Set(borderRadius);
695 }
696
SetRingProgressLeftPadding(const Dimension & ringProgressLeftPadding)697 void ProgressModifier::SetRingProgressLeftPadding(const Dimension& ringProgressLeftPadding)
698 {
699 ringProgressLeftPadding_ = ringProgressLeftPadding;
700 }
701
ContentDrawWithFunction(DrawingContext & context)702 void ProgressModifier::ContentDrawWithFunction(DrawingContext& context)
703 {
704 auto contentSize = contentSize_->Get();
705 auto& canvas = context.canvas;
706 if (progressType_->Get() == static_cast<int32_t>(ProgressType::LINEAR)) {
707 PaintLinear(canvas, offset_->Get(), contentSize);
708 } else if (progressType_->Get() == static_cast<int32_t>(ProgressType::RING)) {
709 PaintRing(canvas, offset_->Get(), contentSize);
710 } else if (progressType_->Get() == static_cast<int32_t>(ProgressType::SCALE)) {
711 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
712 PaintScaleRingForApiNine(canvas, offset_->Get(), contentSize);
713 } else {
714 PaintScaleRing(canvas, offset_->Get(), contentSize);
715 }
716 } else if (progressType_->Get() == static_cast<int32_t>(ProgressType::MOON)) {
717 PaintMoon(canvas, offset_->Get(), contentSize);
718 } else if (progressType_->Get() == static_cast<int32_t>(ProgressType::CAPSULE)) {
719 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
720 if (contentSize.Width() >= contentSize.Height()) {
721 PaintCapsuleForApiNine(canvas, offset_->Get(), contentSize);
722 } else {
723 PaintVerticalCapsuleForApiNine(canvas, offset_->Get(), contentSize);
724 }
725 } else if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
726 if (contentSize.Width() >= contentSize.Height()) {
727 PaintCapsule(canvas, offset_->Get(), contentSize, contentSize.Height() / INT32_TWO);
728 } else {
729 PaintVerticalCapsule(canvas, offset_->Get(), contentSize, contentSize.Width() / INT32_TWO);
730 }
731 } else {
732 if (contentSize.Width() >= contentSize.Height()) {
733 PaintCapsule(canvas, offset_->Get(), contentSize, capsuleBorderRadius_->Get());
734 } else {
735 PaintVerticalCapsule(canvas, offset_->Get(), contentSize, capsuleBorderRadius_->Get());
736 }
737 }
738 } else {
739 PaintLinear(canvas, offset_->Get(), contentSize);
740 }
741 }
742
PaintLinear(RSCanvas & canvas,const OffsetF & offset,const SizeF & contentSize) const743 void ProgressModifier::PaintLinear(RSCanvas& canvas, const OffsetF& offset, const SizeF& contentSize) const
744 {
745 RSBrush brush;
746 brush.SetAntiAlias(true);
747 brush.SetColor(ToRSColor(bgColor_->Get()));
748 double radius = strokeRadius_->Get();
749 if (contentSize.Width() >= contentSize.Height()) {
750 double barLength = contentSize.Width() - radius * INT32_TWO;
751 CHECK_NULL_VOID(Positive(barLength));
752 double dateLength = std::min(barLength * value_->Get() / maxValue_->Get(), barLength);
753 canvas.AttachBrush(brush);
754 canvas.DrawRoundRect(
755 { { offset.GetX(), offset.GetY(), contentSize.Width() + offset.GetX(),
756 strokeWidth_->Get() + offset.GetY() },
757 radius, radius });
758 canvas.DetachBrush();
759 // progress selected part
760 CHECK_NULL_VOID(Positive(value_->Get()));
761 brush.SetColor(ToRSColor((color_->Get())));
762 canvas.AttachBrush(brush);
763 #ifndef USE_ROSEN_DRAWING
764 RSPath path;
765 #else
766 RSRecordingPath path;
767 #endif
768 float leftTopX = !isRightToLeft_->Get()
769 ? offset.GetX()
770 : contentSize.Width() + offset.GetX() - (dateLength + radius * INT32_TWO);
771 float leftTopY = offset.GetY();
772 float rightBottomX = !isRightToLeft_->Get() ? dateLength + offset.GetX() + radius * INT32_TWO
773 : contentSize.Width() + offset.GetX();
774 float rightBottomY = strokeWidth_->Get() + offset.GetY();
775 path.AddRoundRect({ leftTopX, leftTopY, rightBottomX, rightBottomY }, radius, radius);
776 canvas.DrawPath(path);
777 canvas.DetachBrush();
778 canvas.Restore();
779 PaintLinearSweeping(canvas, offset, path, true, contentSize);
780 } else {
781 double barLength = contentSize.Height() - radius * INT32_TWO;
782 CHECK_NULL_VOID(Positive(barLength));
783 double dateLength = std::min(barLength * value_->Get() / maxValue_->Get(), barLength);
784 canvas.AttachBrush(brush);
785 canvas.DrawRoundRect(
786 { { offset.GetX(), offset.GetY(), strokeWidth_->Get() + offset.GetX(),
787 contentSize.Height() + offset.GetY() },
788 radius, radius });
789 canvas.DetachBrush();
790 // progress selected part
791 CHECK_NULL_VOID(Positive(value_->Get()));
792 brush.SetColor(ToRSColor((color_->Get())));
793 canvas.AttachBrush(brush);
794 #ifndef USE_ROSEN_DRAWING
795 RSPath path;
796 #else
797 RSRecordingPath path;
798 #endif
799 path.AddRoundRect(
800 { offset.GetX(), offset.GetY(), strokeWidth_->Get() + offset.GetX(),
801 dateLength + offset.GetY() + radius * INT32_TWO },
802 radius, radius);
803 canvas.DrawPath(path);
804 canvas.DetachBrush();
805 canvas.Restore();
806 PaintLinearSweeping(canvas, offset, path, false, contentSize);
807 }
808 }
809
PaintLinearSweeping(RSCanvas & canvas,const OffsetF & offset,const RSPath & path,bool isHorizontal,const SizeF & contentSize) const810 void ProgressModifier::PaintLinearSweeping(
811 RSCanvas& canvas, const OffsetF& offset, const RSPath& path, bool isHorizontal, const SizeF& contentSize) const
812 {
813 if (NearZero(value_->Get()) || NearZero(maxValue_->Get())) {
814 return;
815 }
816
817 // If the progress reaches 100%, stop sweeping.
818 if (NearEqual(value_->Get(), maxValue_->Get())) {
819 return;
820 }
821
822 std::vector<RSColorQuad> colors;
823 std::vector<float> pos;
824 GenerateLinearSweepingGradientInfo(colors, pos);
825
826 RSBrush brush;
827 float leftTopX = 0.0f;
828 float leftTopY = 0.0f;
829 float rightBottomX = 0.0f;
830 float rightBottomY = 0.0f;
831 if (isHorizontal) {
832 leftTopX = !isRightToLeft_->Get() ? offset.GetX() + sweepingDate_->Get() - LINEAR_SWEEPING_LEN.ConvertToPx()
833 : contentSize.Width() + offset.GetX() - sweepingDate_->Get();
834 leftTopY = offset.GetY();
835 rightBottomX = !isRightToLeft_->Get() ? offset.GetX() + sweepingDate_->Get()
836 : contentSize.Width() + offset.GetX() - sweepingDate_->Get() +
837 LINEAR_SWEEPING_LEN.ConvertToPx();
838 rightBottomY = offset.GetY() + strokeWidth_->Get();
839 } else {
840 leftTopX = offset.GetX();
841 leftTopY = offset.GetY() + sweepingDate_->Get() - LINEAR_SWEEPING_LEN.ConvertToPx();
842 rightBottomX = offset.GetX() + strokeWidth_->Get();
843 rightBottomY = offset.GetY() + sweepingDate_->Get();
844 }
845
846 RSRect rect(leftTopX, leftTopY, rightBottomX, rightBottomY);
847 #ifndef USE_ROSEN_DRAWING
848 brush.SetShaderEffect(RSShaderEffect::CreateLinearGradient(
849 ToRSPoint(PointF(leftTopX, leftTopY)),
850 ToRSPoint(PointF(rightBottomX, rightBottomY)),
851 colors, pos, RSTileMode::CLAMP));
852 #else
853 brush.SetShaderEffect(RSRecordingShaderEffect::CreateLinearGradient(
854 ToRSPoint(PointF(leftTopX, leftTopY)),
855 ToRSPoint(PointF(rightBottomX, rightBottomY)),
856 colors, pos, RSTileMode::CLAMP));
857 #endif
858 canvas.Save();
859 canvas.ClipPath(path, RSClipOp::INTERSECT, true);
860 canvas.AttachBrush(brush);
861 canvas.DrawRect(rect);
862 canvas.DetachBrush();
863 canvas.Restore();
864 }
865
GenerateLinearSweepingGradientInfo(std::vector<RSColorQuad> & colors,std::vector<float> & pos) const866 void ProgressModifier::GenerateLinearSweepingGradientInfo(
867 std::vector<RSColorQuad>& colors, std::vector<float>& pos) const
868 {
869 Gradient gradient;
870 Color sweepingColorBase = Color::WHITE;
871 Color sweepingColorEnd = sweepingColorBase.ChangeOpacity(0.0);
872 GradientColor gradientColorEnd;
873 gradientColorEnd.SetColor(sweepingColorEnd);
874 gradientColorEnd.SetDimension(Dimension(0.0, DimensionUnit::PERCENT));
875 gradient.AddColor(gradientColorEnd);
876
877 // The sweep layer is a white gradient layer of length 80 vp with a opacity of 0.3 at 75 vp and 0.0 at both ends.
878 Dimension stageLen = 75.0_vp;
879 Color sweepingColorMiddle = sweepingColorBase.ChangeOpacity(0.3);
880 GradientColor gradientColorMiddle;
881 gradientColorMiddle.SetColor(sweepingColorMiddle);
882 gradientColorMiddle.SetDimension(
883 Dimension(!isRightToLeft_->Get() ? stageLen.ConvertToPx() / LINEAR_SWEEPING_LEN.ConvertToPx()
884 : 1 - stageLen.ConvertToPx() / LINEAR_SWEEPING_LEN.ConvertToPx(),
885 DimensionUnit::PERCENT));
886 gradient.AddColor(gradientColorMiddle);
887
888 Color sweepingColorStart = sweepingColorBase.ChangeOpacity(0.0);
889 GradientColor gradientColorStart;
890 gradientColorStart.SetColor(sweepingColorStart);
891 gradientColorStart.SetDimension(Dimension(1.0, DimensionUnit::PERCENT));
892 gradient.AddColor(gradientColorStart);
893
894 auto gradientColors = gradient.GetColors();
895 for (size_t i = 0; i < gradientColors.size(); i++) {
896 colors.emplace_back(gradientColors[i].GetColor().GetValue());
897 pos.emplace_back(gradientColors[i].GetDimension().Value());
898 }
899 }
900
PaintRing(RSCanvas & canvas,const OffsetF & offset,const SizeF & contentSize) const901 void ProgressModifier::PaintRing(RSCanvas& canvas, const OffsetF& offset, const SizeF& contentSize) const
902 {
903 auto centerPt = PointF(contentSize.Width() / 2, contentSize.Height() / 2) + offset;
904 auto radius = std::min(contentSize.Width() / 2, contentSize.Height() / 2);
905 auto angle = std::min((value_->Get() / maxValue_->Get()) * ANGLE_360, static_cast<float>(ANGLE_360));
906 auto thickness = strokeWidth_->Get();
907 // No shadow is drawn if radius is less or equal to 10, because it is no enough space to draw both ring and shadow.
908 auto paintShadow = paintShadow_->Get() && GreatNotEqual(radius, RING_SHADOW_VALID_RADIUS_MIN);
909 auto shadowBlurOffset = paintShadow ? thickness / 2 + std::max(RING_SHADOW_OFFSET_X, RING_SHADOW_OFFSET_Y) : 0.0f;
910 if (GreatOrEqual(thickness + shadowBlurOffset, radius)) {
911 thickness = radius / 2;
912 shadowBlurOffset = paintShadow ? thickness / 2 + std::max(RING_SHADOW_OFFSET_X, RING_SHADOW_OFFSET_Y) : 0.0f;
913 }
914 // The shadowBlurSigma is an empirical value. If it is greater than thickness / 5, the shadow will be cut by
915 // the canvas boundary.
916 auto shadowBlurSigma = std::max(thickness / 5, RING_SHADOW_BLUR_RADIUS_MIN);
917 radius = radius - thickness / 2 - shadowBlurOffset;
918
919 RingProgressData ringData;
920 ringData.centerPt = centerPt;
921 ringData.radius = radius;
922 ringData.angle = angle;
923 ringData.thickness = thickness;
924 ringData.shadowBlurSigma = shadowBlurSigma;
925
926 PaintRingBackground(canvas, ringData);
927 if (isRightToLeft_->Get()) {
928 canvas.Scale(-1, 1);
929 canvas.Translate(
930 -((radius + shadowBlurOffset + ringProgressLeftPadding_.ConvertToPx()) * INT32_TWO + thickness), 0);
931 }
932 if (isLoading_) {
933 PaintTrailing(canvas, ringData);
934 return;
935 }
936
937 if (NearZero(angle)) {
938 return;
939 }
940
941 if (paintShadow) {
942 ringData.centerPt = centerPt + OffsetF(RING_SHADOW_OFFSET_X, RING_SHADOW_OFFSET_Y);
943 PaintRingProgressOrShadow(canvas, ringData, true);
944 }
945 ringData.centerPt = centerPt;
946 PaintRingProgressOrShadow(canvas, ringData, false);
947 PaintRingSweeping(canvas, ringData);
948 }
949
PaintRingBackground(RSCanvas & canvas,const RingProgressData & ringProgressData) const950 void ProgressModifier::PaintRingBackground(RSCanvas& canvas, const RingProgressData& ringProgressData) const
951 {
952 RSPen pen;
953 pen.SetAntiAlias(true);
954 pen.SetWidth(ringProgressData.thickness);
955 pen.SetCapStyle(ToRSCapStyle(LineCap::ROUND));
956 pen.SetColor(ToRSColor(bgColor_->Get()));
957
958 canvas.Save();
959 canvas.AttachPen(pen);
960 canvas.DrawCircle(ToRSPoint(ringProgressData.centerPt), ringProgressData.radius);
961 canvas.DetachPen();
962 canvas.Restore();
963 }
964
GetRingProgressGradientColors() const965 std::vector<GradientColor> ProgressModifier::GetRingProgressGradientColors() const
966 {
967 Gradient gradient = SortGradientColorsByOffset(ringProgressColors_->Get().GetGradient());
968 std::vector<GradientColor> gradientColors = gradient.GetColors();
969 // Fault protection processing, if gradientColors is empty, set to default colors.
970
971 if (gradientColors.empty()) {
972 auto pipeline = PipelineBase::GetCurrentContext();
973 CHECK_NULL_RETURN(pipeline, gradientColors);
974 auto theme = pipeline->GetTheme<ProgressTheme>(GetThemeScopeId());
975 CHECK_NULL_RETURN(theme, gradientColors);
976 GradientColor endColor;
977 GradientColor beginColor;
978 endColor.SetLinearColor(LinearColor(theme->GetRingProgressEndSideColor()));
979 endColor.SetDimension(0.0);
980 beginColor.SetLinearColor(LinearColor(theme->GetRingProgressBeginSideColor()));
981 beginColor.SetDimension(1.0);
982 gradientColors.emplace_back(endColor);
983 gradientColors.emplace_back(beginColor);
984 }
985 return gradientColors;
986 }
987
PaintRingProgressOrShadow(RSCanvas & canvas,const RingProgressData & ringProgressData,bool isShadow) const988 void ProgressModifier::PaintRingProgressOrShadow(
989 RSCanvas& canvas, const RingProgressData& ringProgressData, bool isShadow) const
990 {
991 auto angle = ringProgressData.angle;
992 float additionalAngle = CalcRingProgressAdditionalAngle();
993
994 std::vector<GradientColor> gradientColors = GetRingProgressGradientColors();
995
996 RSBrush brush;
997 brush.SetAntiAlias(true);
998
999 if (isShadow) {
1000 for (size_t i = 0; i < gradientColors.size(); i++) {
1001 Color color = gradientColors[i].GetLinearColor().BlendOpacity(RING_SHADOW_OPACITY);
1002 gradientColors[i].SetLinearColor(LinearColor(color));
1003 }
1004 RSFilter filter;
1005 #ifndef USE_ROSEN_DRAWING
1006 filter.SetImageFilter(RSImageFilter::CreateBlurImageFilter(
1007 ringProgressData.shadowBlurSigma, ringProgressData.shadowBlurSigma, RSTileMode::DECAL, nullptr));
1008 #else
1009 filter.SetImageFilter(RSRecordingImageFilter::CreateBlurImageFilter(
1010 ringProgressData.shadowBlurSigma, ringProgressData.shadowBlurSigma, RSTileMode::DECAL, nullptr));
1011 #endif
1012 brush.SetFilter(filter);
1013 }
1014
1015 if (LessOrEqual(angle + additionalAngle * INT32_TWO, ANGLE_360)) {
1016 PaintWhole(canvas, brush, ringProgressData, gradientColors);
1017 } else {
1018 PaintBeginHalf(canvas, brush, ringProgressData, gradientColors);
1019 PaintEndHalf(canvas, brush, ringProgressData, gradientColors);
1020 }
1021 }
1022
PaintWhole(RSCanvas & canvas,RSBrush & brush,const RingProgressData & ringProgressData,std::vector<GradientColor> & gradientColors) const1023 void ProgressModifier::PaintWhole(RSCanvas& canvas, RSBrush& brush, const RingProgressData& ringProgressData,
1024 std::vector<GradientColor>& gradientColors) const
1025 {
1026 PointF centerPt = ringProgressData.centerPt;
1027 auto radius = ringProgressData.radius;
1028 auto angle = ringProgressData.angle;
1029 auto thickness = ringProgressData.thickness;
1030 double halfThickness = thickness / 2;
1031 float additionalAngle = CalcRingProgressAdditionalAngle();
1032 double radAngle = angle / ANGLE_180 * PI_NUM;
1033 double radAdditionalAngle = additionalAngle / ANGLE_180 * PI_NUM;
1034 double sinPointOutside = std::sin(radAngle + radAdditionalAngle) * (radius - halfThickness);
1035 double cosPointOutside = std::cos(radAngle + radAdditionalAngle) * (radius - halfThickness);
1036 double sinPointStart = std::sin(radAdditionalAngle) * radius;
1037 double cosPointStart = std::cos(radAdditionalAngle) * radius;
1038
1039 std::vector<RSColorQuad> colors;
1040 std::vector<float> pos;
1041 for (size_t i = 0; i < gradientColors.size(); i++) {
1042 colors.emplace_back(gradientColors[i].GetLinearColor().GetValue());
1043 pos.emplace_back(gradientColors[i].GetDimension().Value());
1044 }
1045
1046 RSPath path;
1047 #ifndef USE_ROSEN_DRAWING
1048 brush.SetShaderEffect(RSShaderEffect::CreateSweepGradient(ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())),
1049 colors, pos, RSTileMode::CLAMP, 0, angle + additionalAngle * INT32_TWO, nullptr));
1050 #else
1051 brush.SetShaderEffect(
1052 RSRecordingShaderEffect::CreateSweepGradient(ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())), colors, pos,
1053 RSTileMode::CLAMP, 0, angle + additionalAngle * INT32_TWO, nullptr));
1054 #endif
1055 path.ArcTo(centerPt.GetX() + cosPointStart - halfThickness, centerPt.GetY() + sinPointStart - halfThickness,
1056 centerPt.GetX() + cosPointStart + halfThickness, centerPt.GetY() + sinPointStart + halfThickness,
1057 ANGLE_180 + additionalAngle, ANGLE_180);
1058 path.ArcTo(centerPt.GetX() - radius - halfThickness, centerPt.GetY() - radius - halfThickness,
1059 centerPt.GetX() + radius + halfThickness, centerPt.GetY() + radius + halfThickness, additionalAngle, angle);
1060 path.ArcTo(halfThickness, halfThickness, 0.0f, RSPathDirection::CW_DIRECTION, centerPt.GetX() + cosPointOutside,
1061 centerPt.GetY() + sinPointOutside);
1062 path.ArcTo(centerPt.GetX() - radius + halfThickness, centerPt.GetY() - radius + halfThickness,
1063 centerPt.GetX() + radius - halfThickness, centerPt.GetY() + radius - halfThickness, additionalAngle + angle,
1064 -angle);
1065 path.Close();
1066 canvas.Save();
1067 canvas.Rotate(-ANGLE_90 - additionalAngle, centerPt.GetX(), centerPt.GetY());
1068 canvas.AttachBrush(brush);
1069 canvas.DrawPath(path);
1070 canvas.DetachBrush();
1071 canvas.Restore();
1072 }
1073
PaintBeginHalf(RSCanvas & canvas,RSBrush & brush,const RingProgressData & ringProgressData,std::vector<GradientColor> & gradientColors) const1074 void ProgressModifier::PaintBeginHalf(RSCanvas& canvas, RSBrush& brush, const RingProgressData& ringProgressData,
1075 std::vector<GradientColor>& gradientColors) const
1076 {
1077 PointF centerPt = ringProgressData.centerPt;
1078 auto radius = ringProgressData.radius;
1079 auto angle = ringProgressData.angle;
1080 auto thickness = ringProgressData.thickness;
1081 double halfThickness = thickness / 2;
1082 float additionalAngle = CalcRingProgressAdditionalAngle();
1083
1084 std::vector<RSColorQuad> colors;
1085 std::vector<float> pos;
1086 for (size_t i = 0; i < gradientColors.size(); i++) {
1087 colors.emplace_back(gradientColors[i].GetLinearColor().GetValue());
1088 pos.emplace_back(gradientColors[i].GetDimension().Value());
1089 }
1090 colors.emplace_back(gradientColors[0].GetLinearColor().GetValue());
1091 pos.emplace_back((ANGLE_360 - additionalAngle) / ANGLE_360);
1092
1093 RSPath beginPath;
1094 RSPath path;
1095 #ifndef USE_ROSEN_DRAWING
1096 brush.SetShaderEffect(RSShaderEffect::CreateSweepGradient(ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())),
1097 colors, pos, RSTileMode::CLAMP, 0, angle, nullptr));
1098 #else
1099 brush.SetShaderEffect(RSRecordingShaderEffect::CreateSweepGradient(
1100 ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())), colors, pos, RSTileMode::CLAMP, 0, angle, nullptr));
1101 #endif
1102 float drawAngle = ANGLE_180 + FLOAT_ZERO_FIVE;
1103 beginPath.MoveTo(centerPt.GetX() + radius - halfThickness, centerPt.GetY());
1104 beginPath.ArcTo(centerPt.GetX() + radius - halfThickness, centerPt.GetY() - halfThickness,
1105 centerPt.GetX() + radius + halfThickness, centerPt.GetY() + halfThickness, ANGLE_180, ANGLE_180);
1106 beginPath.ArcTo(centerPt.GetX() - radius - halfThickness, centerPt.GetY() - radius - halfThickness,
1107 centerPt.GetX() + radius + halfThickness, centerPt.GetY() + radius + halfThickness, 0, drawAngle);
1108 beginPath.ArcTo(centerPt.GetX() - radius + halfThickness, centerPt.GetY() - radius + halfThickness,
1109 centerPt.GetX() + radius - halfThickness, centerPt.GetY() + radius - halfThickness, drawAngle, -drawAngle);
1110 beginPath.Close();
1111
1112 canvas.Save();
1113 canvas.Rotate(-ANGLE_90, centerPt.GetX(), centerPt.GetY());
1114 canvas.AttachBrush(brush);
1115 canvas.DrawPath(beginPath);
1116 canvas.DetachBrush();
1117 canvas.Restore();
1118 }
1119
PaintEndHalf(RSCanvas & canvas,RSBrush & brush,const RingProgressData & ringProgressData,std::vector<GradientColor> & gradientColors) const1120 void ProgressModifier::PaintEndHalf(RSCanvas& canvas, RSBrush& brush, const RingProgressData& ringProgressData,
1121 std::vector<GradientColor>& gradientColors) const
1122 {
1123 PointF centerPt = ringProgressData.centerPt;
1124 auto radius = ringProgressData.radius;
1125 auto angle = ringProgressData.angle;
1126 auto thickness = ringProgressData.thickness;
1127 double halfThickness = thickness / 2;
1128 float additionalAngle = CalcRingProgressAdditionalAngle();
1129 double radArc = (angle - ANGLE_180) / ANGLE_180 * PI_NUM;
1130 double sinPointOutside = std::sin(radArc) * (radius - halfThickness);
1131 double cosPointOutside = std::cos(radArc) * (radius - halfThickness);
1132
1133 std::vector<RSColorQuad> colors;
1134 std::vector<float> pos;
1135 if (gradientColors.size() != 0) {
1136 colors.emplace_back(gradientColors[gradientColors.size() - 1].GetLinearColor().GetValue());
1137 }
1138 pos.emplace_back(additionalAngle / ANGLE_360);
1139 for (size_t i = 0; i < gradientColors.size(); i++) {
1140 colors.emplace_back(gradientColors[i].GetLinearColor().GetValue());
1141 pos.emplace_back(gradientColors[i].GetDimension().Value());
1142 }
1143
1144 RSPath endPath;
1145 #ifndef USE_ROSEN_DRAWING
1146 brush.SetShaderEffect(RSShaderEffect::CreateSweepGradient(
1147 ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())), colors, pos, RSTileMode::CLAMP, 0, angle, nullptr));
1148 #else
1149 brush.SetShaderEffect(RSRecordingShaderEffect::CreateSweepGradient(
1150 ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())), colors, pos, RSTileMode::CLAMP, 0, angle, nullptr));
1151 #endif
1152 endPath.MoveTo(centerPt.GetX() - radius + halfThickness, centerPt.GetY());
1153 endPath.LineTo(centerPt.GetX() - radius - halfThickness, centerPt.GetY());
1154 endPath.ArcTo(centerPt.GetX() - radius - halfThickness, centerPt.GetY() - radius - halfThickness,
1155 centerPt.GetX() + radius + halfThickness, centerPt.GetY() + radius + halfThickness, ANGLE_180,
1156 angle - ANGLE_180);
1157 endPath.ArcTo(halfThickness, halfThickness, 0.0f, RSPathDirection::CW_DIRECTION, centerPt.GetX() - cosPointOutside,
1158 centerPt.GetY() - sinPointOutside);
1159 endPath.ArcTo(centerPt.GetX() - radius + halfThickness, centerPt.GetY() - radius + halfThickness,
1160 centerPt.GetX() + radius - halfThickness, centerPt.GetY() + radius - halfThickness, angle, ANGLE_180 - angle);
1161 endPath.Close();
1162 canvas.Save();
1163 canvas.Rotate(-ANGLE_90, centerPt.GetX(), centerPt.GetY());
1164 canvas.AttachBrush(brush);
1165 canvas.DrawPath(endPath);
1166 canvas.DetachBrush();
1167 canvas.Restore();
1168 }
1169
SortGradientColorsByOffset(const Gradient & gradient) const1170 Gradient ProgressModifier::SortGradientColorsByOffset(const Gradient& gradient) const
1171 {
1172 auto srcGradientColors = gradient.GetColors();
1173 std::sort(
1174 srcGradientColors.begin(), srcGradientColors.end(), [](const GradientColor& left, const GradientColor& right) {
1175 return left.GetDimension().Value() < right.GetDimension().Value();
1176 });
1177
1178 Gradient sortedGradient;
1179 for (const auto& item : srcGradientColors) {
1180 sortedGradient.AddColor(item);
1181 }
1182
1183 return sortedGradient;
1184 }
1185
PaintRingSweeping(RSCanvas & canvas,const RingProgressData & ringProgressData) const1186 void ProgressModifier::PaintRingSweeping(RSCanvas& canvas, const RingProgressData& ringProgressData) const
1187 {
1188 if (NearZero(value_->Get()) || NearZero(maxValue_->Get())) {
1189 return;
1190 }
1191
1192 // If the progress reaches 100%, stop sweeping.
1193 if (NearEqual(value_->Get(), maxValue_->Get())) {
1194 return;
1195 }
1196
1197 auto centerPt = ringProgressData.centerPt;
1198 auto radius = ringProgressData.radius;
1199 auto thickness = ringProgressData.thickness;
1200 double halfThickness = thickness / 2;
1201
1202 RSPen pen;
1203 pen.SetAntiAlias(true);
1204 pen.SetWidth(thickness);
1205 pen.SetCapStyle(ToRSCapStyle(LineCap::ROUND));
1206
1207 std::vector<RSColorQuad> colors;
1208 std::vector<float> pos;
1209 GenerateRingSweepingGradientInfo(colors, pos);
1210
1211 float date = sweepingDate_->Get();
1212 float additionalAngle = CalcRingProgressAdditionalAngle();
1213 float startSweepAngle = date - ANGLE_45 - additionalAngle;
1214 #ifndef USE_ROSEN_DRAWING
1215 pen.SetShaderEffect(RSShaderEffect::CreateSweepGradient(
1216 ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())), colors, pos,
1217 RSTileMode::CLAMP, 0, ANGLE_45, nullptr));
1218
1219 RSPath path;
1220 #else
1221 pen.SetShaderEffect(RSRecordingShaderEffect::CreateSweepGradient(
1222 ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())), colors, pos,
1223 RSTileMode::CLAMP, 0, ANGLE_45, nullptr));
1224
1225 RSRecordingPath path;
1226 #endif
1227 double totalDegree = ANGLE_360;
1228 double angleArc = (value_->Get() / maxValue_->Get()) * totalDegree;
1229 double radArc = angleArc / totalDegree * 2 * PI_NUM;
1230 double sinPointInside = std::sin(radArc) * (radius - halfThickness);
1231 double cosPointInside = std::cos(radArc) * (radius - halfThickness);
1232 if (LessOrEqual(startSweepAngle, ANGLE_90)) {
1233 path.MoveTo(centerPt.GetX(), centerPt.GetY() - radius + halfThickness);
1234 path.ArcTo(centerPt.GetX() - halfThickness, centerPt.GetY() - radius - halfThickness,
1235 centerPt.GetX() + halfThickness, centerPt.GetY() - radius + halfThickness,
1236 ANGLE_90, ANGLE_180);
1237 if (GreatNotEqual(angleArc + additionalAngle * INT32_TWO, ANGLE_360)) {
1238 path.ArcTo(centerPt.GetX() - radius - halfThickness, centerPt.GetY() - radius - halfThickness,
1239 centerPt.GetX() + radius + halfThickness, centerPt.GetY() + radius + halfThickness,
1240 -ANGLE_90, ANGLE_180);
1241 path.LineTo(centerPt.GetX(), centerPt.GetY() + radius - halfThickness);
1242 path.ArcTo(centerPt.GetX() - radius + halfThickness, centerPt.GetY() - radius + halfThickness,
1243 centerPt.GetX() + radius - halfThickness, centerPt.GetY() + radius - halfThickness,
1244 ANGLE_90, -ANGLE_180);
1245 #ifndef USE_ROSEN_DRAWING
1246 RSPath path2;
1247 RSPath path3;
1248 #else
1249 RSRecordingPath path2;
1250 RSRecordingPath path3;
1251 #endif
1252 float x = centerPt.GetX() + sin(radArc) * radius;
1253 float y = centerPt.GetY() - cos(radArc) * radius;
1254 path2.AddCircle(x, y, halfThickness);
1255 path3.Op(path, path2, RSPathOp::INTERSECT);
1256 path.Op(path, path3, RSPathOp::DIFFERENCE);
1257 } else if (GreatNotEqual(angleArc, ANGLE_180)) {
1258 path.ArcTo(centerPt.GetX() - radius - halfThickness, centerPt.GetY() - radius - halfThickness,
1259 centerPt.GetX() + radius + halfThickness, centerPt.GetY() + radius + halfThickness,
1260 -ANGLE_90, ANGLE_180);
1261 path.LineTo(centerPt.GetX(), centerPt.GetY() + radius - halfThickness);
1262 path.ArcTo(centerPt.GetX() - radius + halfThickness, centerPt.GetY() - radius + halfThickness,
1263 centerPt.GetX() + radius - halfThickness, centerPt.GetY() + radius - halfThickness,
1264 ANGLE_90, -ANGLE_180);
1265 } else {
1266 path.ArcTo(centerPt.GetX() - radius - halfThickness, centerPt.GetY() - radius - halfThickness,
1267 centerPt.GetX() + radius + halfThickness, centerPt.GetY() + radius + halfThickness,
1268 -ANGLE_90, angleArc);
1269 path.ArcTo(halfThickness, halfThickness, 0.0f, RSPathDirection::CW_DIRECTION,
1270 centerPt.GetX() + sinPointInside, centerPt.GetY() - cosPointInside);
1271 path.ArcTo(centerPt.GetX() - radius + halfThickness, centerPt.GetY() - radius + halfThickness,
1272 centerPt.GetX() + radius - halfThickness, centerPt.GetY() + radius - halfThickness,
1273 -ANGLE_90 + angleArc, -angleArc);
1274 }
1275 } else {
1276 path.MoveTo(centerPt.GetX() + radius - halfThickness, centerPt.GetY());
1277 path.LineTo(centerPt.GetX() + radius + halfThickness, centerPt.GetY());
1278 path.ArcTo(centerPt.GetX() - radius - halfThickness, centerPt.GetY() - radius - halfThickness,
1279 centerPt.GetX() + radius + halfThickness, centerPt.GetY() + radius + halfThickness,
1280 0, angleArc - ANGLE_90);
1281 path.ArcTo(halfThickness, halfThickness, 0.0f, RSPathDirection::CW_DIRECTION,
1282 centerPt.GetX() + sinPointInside, centerPt.GetY() - cosPointInside);
1283 path.ArcTo(centerPt.GetX() - radius + halfThickness, centerPt.GetY() - radius + halfThickness,
1284 centerPt.GetX() + radius - halfThickness, centerPt.GetY() + radius - halfThickness,
1285 angleArc - ANGLE_90, -angleArc + ANGLE_90);
1286 }
1287
1288 canvas.Save();
1289 canvas.ClipPath(path, RSClipOp::INTERSECT, true);
1290
1291 float rotateAngle = -ANGLE_90 + startSweepAngle;
1292 canvas.Rotate(rotateAngle, centerPt.GetX(), centerPt.GetY());
1293 canvas.AttachPen(pen);
1294 canvas.DrawArc(
1295 { centerPt.GetX() - radius, centerPt.GetY() - radius, centerPt.GetX() + radius, centerPt.GetY() + radius },
1296 0, ANGLE_45);
1297 canvas.DetachPen();
1298 canvas.Restore();
1299 }
1300
GenerateRingSweepingGradientInfo(std::vector<RSColorQuad> & colors,std::vector<float> & pos) const1301 void ProgressModifier::GenerateRingSweepingGradientInfo(
1302 std::vector<RSColorQuad>& colors, std::vector<float>& pos) const
1303 {
1304 Gradient gradient;
1305 Color sweepingColorBase = Color::WHITE;
1306 Color sweepingColorEnd = sweepingColorBase.ChangeOpacity(0.0f);
1307 GradientColor gradientColorEnd;
1308 gradientColorEnd.SetColor(sweepingColorEnd);
1309 gradientColorEnd.SetDimension(Dimension(0.0, DimensionUnit::PERCENT));
1310 gradient.AddColor(gradientColorEnd);
1311
1312 // The sweep layer is a 45-degree white gradient with an opacity of 0.4 at 35 degrees and 0 at both ends.
1313 Color sweepingColorMiddle = sweepingColorBase.ChangeOpacity(0.4f);
1314 GradientColor gradientColorMiddle;
1315 gradientColorMiddle.SetColor(sweepingColorMiddle);
1316 gradientColorMiddle.SetDimension(Dimension(35.0f / ANGLE_45, DimensionUnit::PERCENT));
1317 gradient.AddColor(gradientColorMiddle);
1318
1319 Color sweepingColorStart = sweepingColorBase.ChangeOpacity(0.0f);
1320 GradientColor gradientColorStart;
1321 gradientColorStart.SetColor(sweepingColorStart);
1322 gradientColorStart.SetDimension(Dimension(1.0, DimensionUnit::PERCENT));
1323 gradient.AddColor(gradientColorStart);
1324
1325 auto gradientColors = gradient.GetColors();
1326 for (size_t i = 0; i < gradientColors.size(); i++) {
1327 colors.emplace_back(gradientColors[i].GetColor().GetValue());
1328 pos.emplace_back(gradientColors[i].GetDimension().Value());
1329 }
1330 }
1331
PaintTrailing(RSCanvas & canvas,const RingProgressData & ringProgressData) const1332 void ProgressModifier::PaintTrailing(RSCanvas& canvas, const RingProgressData& ringProgressData) const
1333 {
1334 PointF centerPt = ringProgressData.centerPt;
1335 double radius = ringProgressData.radius;
1336 double thickness = ringProgressData.thickness;
1337 float head = trailingHeadDate_->Get();
1338 float tail = trailingTailDate_->Get();
1339 float additionalAngle = CalcRingProgressAdditionalAngle();
1340 float rotateAngle = 0.0f;
1341 if (GreatOrEqual(head, ANGLE_360 - additionalAngle * FLOAT_TWO_ZERO)) {
1342 rotateAngle = -ANGLE_360 + head - tail + additionalAngle * FLOAT_TWO_ZERO;
1343 }
1344 head += (additionalAngle + rotateAngle);
1345 tail += (additionalAngle + rotateAngle);
1346
1347 RSPen pen;
1348 pen.SetAntiAlias(true);
1349 pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
1350 pen.SetWidth(thickness);
1351 canvas.Save();
1352
1353 std::vector<GradientColor> gradientColors = GetRingProgressGradientColors();
1354 std::vector<RSColorQuad> colors;
1355 std::vector<float> pos;
1356
1357 for (size_t i = 0; i < gradientColors.size(); i++) {
1358 double dimension = gradientColors[i].GetDimension().Value();
1359 Color color = gradientColors[i].GetLinearColor().BlendOpacity(dimension);
1360 colors.emplace_back(color.GetValue());
1361 pos.emplace_back(gradientColors[i].GetDimension().Value());
1362 }
1363
1364 RSPath path;
1365 #ifndef USE_ROSEN_DRAWING
1366 pen.SetShaderEffect(RSShaderEffect::CreateSweepGradient(ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())), colors,
1367 pos, RSTileMode::CLAMP, tail - additionalAngle, head + additionalAngle, nullptr));
1368 #else
1369 pen.SetShaderEffect(
1370 RSRecordingShaderEffect::CreateSweepGradient(ToRSPoint(PointF(centerPt.GetX(), centerPt.GetY())), colors, pos,
1371 RSTileMode::CLAMP, tail - additionalAngle, head + additionalAngle, nullptr));
1372 #endif
1373 RSRect rRect(
1374 centerPt.GetX() - radius, centerPt.GetY() - radius, centerPt.GetX() + radius, centerPt.GetY() + radius);
1375 path.AddArc(rRect, tail, head - tail);
1376 canvas.Rotate(-ANGLE_90 - rotateAngle - additionalAngle, centerPt.GetX(), centerPt.GetY());
1377 canvas.AttachPen(pen);
1378 canvas.DrawPath(path);
1379 canvas.DetachPen();
1380 canvas.Restore();
1381 }
1382
PaintScaleRing(RSCanvas & canvas,const OffsetF & offset,const SizeF & contentSize) const1383 void ProgressModifier::PaintScaleRing(RSCanvas& canvas, const OffsetF& offset, const SizeF& contentSize) const
1384 {
1385 PointF centerPt = PointF(contentSize.Width() / INT32_TWO, contentSize.Height() / INT32_TWO) + offset;
1386 double radius = std::min(contentSize.Width() / INT32_TWO, contentSize.Height() / INT32_TWO);
1387 double lengthOfScale = strokeWidth_->Get();
1388 double pathDistance = FLOAT_TWO_ZERO * M_PI * radius / scaleCount_->Get();
1389 if (scaleWidth_->Get() > pathDistance) {
1390 PaintRing(canvas, offset, contentSize);
1391 return;
1392 }
1393 double widthOfLine = scaleWidth_->Get();
1394 RSPen pen;
1395 #ifndef USE_ROSEN_DRAWING
1396 RSPath path;
1397 #else
1398 RSRecordingPath path;
1399 #endif
1400 pen.SetWidth(widthOfLine);
1401 path.AddRoundRect(
1402 { 0, 0, widthOfLine, lengthOfScale }, widthOfLine / INT32_TWO, widthOfLine / INT32_TWO,
1403 RSPathDirection::CW_DIRECTION);
1404 pen.SetAntiAlias(true);
1405 pen.SetCapStyle(ToRSCapStyle(LineCap::ROUND));
1406 #ifndef USE_ROSEN_DRAWING
1407 pen.SetPathEffect(RSPathEffect::CreatePathDashEffect(path, pathDistance, 0.0f, RSPathDashStyle::ROTATE));
1408 #else
1409 pen.SetPathEffect(RSRecordingPathEffect::CreatePathDashEffect(path, pathDistance, 0.0f, RSPathDashStyle::ROTATE));
1410 #endif
1411 pen.SetColor(ToRSColor(bgColor_->Get()));
1412 canvas.AttachPen(pen);
1413 if (isRightToLeft_->Get()) {
1414 canvas.Scale(-1, 1);
1415 canvas.Translate(-(radius + ringProgressLeftPadding_.ConvertToPx()) * INT32_TWO, 0);
1416 }
1417 canvas.DrawArc(
1418 { centerPt.GetX() - radius, centerPt.GetY() - radius, centerPt.GetX() + radius, centerPt.GetY() + radius },
1419 ANGLE_270, ANGLE_360);
1420 canvas.DetachPen();
1421 // start to draw cur value progress
1422 pen.SetColor(ToRSColor((color_->Get())));
1423 canvas.AttachPen(pen);
1424 double angle = std::min((value_->Get() / maxValue_->Get()) * ANGLE_360, static_cast<float>(ANGLE_360));
1425 canvas.DrawArc(
1426 { centerPt.GetX() - radius, centerPt.GetY() - radius, centerPt.GetX() + radius, centerPt.GetY() + radius },
1427 ANGLE_270, angle);
1428 canvas.DetachPen();
1429 canvas.Restore();
1430 }
1431
PaintMoon(RSCanvas & canvas,const OffsetF & offset,const SizeF & contentSize) const1432 void ProgressModifier::PaintMoon(RSCanvas& canvas, const OffsetF& offset, const SizeF& contentSize) const
1433 {
1434 static int32_t totalDegree = 1;
1435 PointF centerPt = PointF(contentSize.Width() / INT32_TWO, contentSize.Height() / INT32_TWO) + offset;
1436 double radius = std::min(contentSize.Width() / INT32_TWO, contentSize.Height() / INT32_TWO);
1437 RSBrush brush;
1438 brush.SetAntiAlias(true);
1439 brush.SetAlpha(true);
1440 brush.SetColor(ToRSColor(bgColor_->Get()));
1441 double angle = std::min((value_->Get() / maxValue_->Get()) * totalDegree, static_cast<float>(totalDegree));
1442 #ifndef USE_ROSEN_DRAWING
1443 RSPath path;
1444 #else
1445 RSRecordingPath path;
1446 #endif
1447 canvas.AttachBrush(brush);
1448 canvas.DrawCircle(ToRSPoint(centerPt), radius);
1449 canvas.DetachBrush();
1450 brush.SetColor(ToRSColor((color_->Get())));
1451 canvas.AttachBrush(brush);
1452 path.AddArc(
1453 { centerPt.GetX() - radius, centerPt.GetY() - radius, centerPt.GetX() + radius, centerPt.GetY() + radius },
1454 ANGLE_90, !isRightToLeft_->Get() ? ANGLE_180 : -ANGLE_180);
1455 if (angle <= FLOAT_ZERO_FIVE) {
1456 double progressOffset = radius - radius * angle / FLOAT_ZERO_FIVE;
1457 path.MoveTo(centerPt.GetX(), centerPt.GetY() - radius);
1458 // startAngle:270 sweepAngle:-180
1459 path.AddArc({ centerPt.GetX() - progressOffset, centerPt.GetY() - radius, centerPt.GetX() + progressOffset,
1460 centerPt.GetY() + radius },
1461 ANGLE_270, !isRightToLeft_->Get() ? -ANGLE_180 : ANGLE_180);
1462 canvas.DrawPath(path);
1463 } else {
1464 double progressOffset = radius * (angle - FLOAT_ZERO_FIVE) / FLOAT_ZERO_FIVE;
1465 path.MoveTo(centerPt.GetX(), centerPt.GetY() - radius);
1466 // startAngle:270 sweepAngle:180
1467 path.AddArc({ centerPt.GetX() - progressOffset, centerPt.GetY() - radius, centerPt.GetX() + progressOffset,
1468 centerPt.GetY() + radius },
1469 ANGLE_270, !isRightToLeft_->Get() ? ANGLE_180 : -ANGLE_180);
1470 canvas.DrawPath(path);
1471 }
1472 canvas.DetachBrush();
1473 }
1474
PaintCapsule(RSCanvas & canvas,const OffsetF & offset,const SizeF & contentSize,const float borderRadius) const1475 void ProgressModifier::PaintCapsule(
1476 RSCanvas& canvas, const OffsetF& offset, const SizeF& contentSize, const float borderRadius) const
1477 {
1478 auto borderWidth = capsuleBorderWidth_->Get();
1479 if (GreatNotEqual(2 * borderWidth, contentSize.Height())) {
1480 borderWidth = contentSize.Height() / 2;
1481 }
1482 float radiusBig = borderRadius - (borderWidth / INT32_TWO);
1483 float offsetXBig = offset.GetX() + borderWidth / INT32_TWO;
1484 float offsetYBig = offset.GetY() + borderWidth / INT32_TWO;
1485 float offsetX = offset.GetX();
1486 float offsetY = offset.GetY();
1487 RSBrush brush;
1488 brush.SetAntiAlias(true);
1489 RSPen pen;
1490 brush.SetAlpha(true);
1491 brush.SetColor(ToRSColor(bgColor_->Get()));
1492 pen.SetWidth(borderWidth);
1493 pen.SetAntiAlias(true);
1494 pen.SetColor(ToRSColor(borderColor_->Get()));
1495 #ifndef USE_ROSEN_DRAWING
1496 RSPath path;
1497 #else
1498 RSRecordingPath path;
1499 #endif
1500 canvas.AttachBrush(brush);
1501 canvas.DrawRoundRect({ { offsetX, offsetY, contentSize.Width() + offsetX, contentSize.Height() + offsetY },
1502 borderRadius, borderRadius });
1503 canvas.DetachBrush();
1504 canvas.AttachPen(pen);
1505 if (!NearZero(borderWidth)) {
1506 canvas.DrawRoundRect({ { offsetXBig, offsetYBig, contentSize.Width() - borderWidth + offsetXBig,
1507 contentSize.Height() - borderWidth + offsetYBig },
1508 radiusBig, radiusBig });
1509 }
1510 canvas.DetachPen();
1511 brush.SetColor(ToRSColor((color_->Get())));
1512 canvas.AttachBrush(brush);
1513 PaintCapsuleLeftBorder(path, offset, contentSize, borderRadius);
1514 PaintCapsuleRightBorder(path, offset, contentSize, borderRadius);
1515 canvas.DrawPath(path);
1516 canvas.DetachBrush();
1517 canvas.Restore();
1518
1519 PaintCapsuleLightSweep(canvas, contentSize, offset, path, false);
1520 }
1521
PaintCapsuleLeftBorder(RSPath & path,const OffsetF & offset,const SizeF & contentSize,const float borderRadius) const1522 void ProgressModifier::PaintCapsuleLeftBorder(
1523 RSPath& path, const OffsetF& offset, const SizeF& contentSize, const float borderRadius) const
1524 {
1525 float offsetX = offset.GetX();
1526 float offsetY = offset.GetY();
1527 bool isDefault = GreatOrEqual(borderRadius, contentSize.Height() / INT32_TWO);
1528 if (isDefault) {
1529 if (!isRightToLeft_->Get()) {
1530 path.AddArc({ offsetX, offsetY, INT32_TWO * borderRadius + offsetX, contentSize.Height() + offsetY },
1531 ANGLE_90, ANGLE_180);
1532 } else {
1533 path.AddArc({ offsetX + contentSize.Width() - INT32_TWO * borderRadius, offsetY,
1534 offsetX + contentSize.Width(), contentSize.Height() + offsetY },
1535 ANGLE_270, ANGLE_180);
1536 }
1537 } else {
1538 RSRoundRect roundRect;
1539 if (!isRightToLeft_->Get()) {
1540 roundRect.SetRect({ offsetX, offsetY, borderRadius + offsetX, contentSize.Height() + offsetY });
1541 roundRect.SetCornerRadius(RSRoundRect::TOP_LEFT_POS, borderRadius, borderRadius);
1542 roundRect.SetCornerRadius(RSRoundRect::BOTTOM_LEFT_POS, borderRadius, borderRadius);
1543 } else {
1544 roundRect.SetRect({ offsetX + contentSize.Width() - borderRadius, offsetY, offsetX + contentSize.Width(),
1545 contentSize.Height() + offsetY });
1546 roundRect.SetCornerRadius(RSRoundRect::TOP_RIGHT_POS, borderRadius, borderRadius);
1547 roundRect.SetCornerRadius(RSRoundRect::BOTTOM_RIGHT_POS, borderRadius, borderRadius);
1548 }
1549 path.AddRoundRect(roundRect);
1550 }
1551 }
1552
PaintCapsuleRightBorder(RSPath & path,const OffsetF & offset,const SizeF & contentSize,const float borderRadius) const1553 void ProgressModifier::PaintCapsuleRightBorder(
1554 RSPath& path, const OffsetF& offset, const SizeF& contentSize, const float borderRadius) const
1555 {
1556 static int32_t totalDegree = 1;
1557 float offsetX = offset.GetX();
1558 float offsetY = offset.GetY();
1559 float progressWidth =
1560 std::min((value_->Get() / maxValue_->Get()) * totalDegree * contentSize.Width(), contentSize.Width());
1561 if (LessNotEqual(progressWidth, borderRadius)) {
1562 PaintCapsuleProgressLessRadiusScene(path, offset, contentSize, borderRadius);
1563 } else if (GreatNotEqual(progressWidth, contentSize.Width() - borderRadius)) {
1564 path.AddRect({ offsetX + borderRadius, offsetY, contentSize.Width() + offsetX - borderRadius,
1565 contentSize.Height() + offsetY });
1566 PaintCapsuleProgressGreaterRadiusScene(path, offset, contentSize, borderRadius);
1567 } else {
1568 if (!isRightToLeft_->Get()) {
1569 path.AddRect({ borderRadius + offsetX, offsetY, progressWidth + offsetX, contentSize.Height() + offsetY });
1570 } else {
1571 path.AddRect({ offsetX + contentSize.Width() - progressWidth, offsetY,
1572 contentSize.Width() + offsetX - borderRadius, contentSize.Height() + offsetY });
1573 }
1574 }
1575 }
1576
PaintCapsuleProgressLessRadiusScene(RSPath & path,const OffsetF & offset,const SizeF & contentSize,const float borderRadius) const1577 void ProgressModifier::PaintCapsuleProgressLessRadiusScene(
1578 RSPath& path, const OffsetF& offset, const SizeF& contentSize, const float borderRadius) const
1579 {
1580 static int32_t totalDegree = 1;
1581 float offsetX = offset.GetX();
1582 float offsetY = offset.GetY();
1583 float progressWidth =
1584 std::min((value_->Get() / maxValue_->Get()) * totalDegree * contentSize.Width(), contentSize.Width());
1585 progressWidth = std::max(progressWidth, DEFAULT_MIN_PROGRESS_WIDTH);
1586 bool isDefault = GreatOrEqual(borderRadius, contentSize.Height() / INT32_TWO);
1587 if (isDefault) {
1588 if (!isRightToLeft_->Get()) {
1589 // startAngle:270 sweepAngle:-180
1590 path.AddArc({ offsetX + progressWidth, offsetY, INT32_TWO * borderRadius - progressWidth + offsetX,
1591 contentSize.Height() + offsetY },
1592 ANGLE_270, -ANGLE_180);
1593 } else {
1594 path.AddArc({ offsetX + contentSize.Width() - INT32_TWO * borderRadius + progressWidth, offsetY,
1595 offsetX + contentSize.Width() - progressWidth, contentSize.Height() + offsetY },
1596 ANGLE_90, -ANGLE_180);
1597 }
1598 } else {
1599 float tmpRadius = borderRadius - progressWidth;
1600 RSRoundRect roundRect;
1601 if (!isRightToLeft_->Get()) {
1602 roundRect.SetRect(
1603 { offsetX + progressWidth, offsetY, borderRadius + offsetX, contentSize.Height() + offsetY });
1604 roundRect.SetCornerRadius(RSRoundRect::TOP_LEFT_POS, tmpRadius, tmpRadius);
1605 roundRect.SetCornerRadius(RSRoundRect::BOTTOM_LEFT_POS, tmpRadius, tmpRadius);
1606 } else {
1607 roundRect.SetRect({ offsetX + contentSize.Width() - borderRadius, offsetY,
1608 offsetX + contentSize.Width() - progressWidth, contentSize.Height() + offsetY });
1609 roundRect.SetCornerRadius(RSRoundRect::TOP_RIGHT_POS, tmpRadius, tmpRadius);
1610 roundRect.SetCornerRadius(RSRoundRect::BOTTOM_RIGHT_POS, tmpRadius, tmpRadius);
1611 }
1612 path.AddRoundRect(roundRect, RSPathDirection::CCW_DIRECTION);
1613 }
1614 }
1615
PaintCapsuleProgressGreaterRadiusScene(RSPath & path,const OffsetF & offset,const SizeF & contentSize,const float borderRadius) const1616 void ProgressModifier::PaintCapsuleProgressGreaterRadiusScene(
1617 RSPath& path, const OffsetF& offset, const SizeF& contentSize, const float borderRadius) const
1618 {
1619 static int32_t totalDegree = 1;
1620 float offsetX = offset.GetX();
1621 float offsetY = offset.GetY();
1622 float progressWidth =
1623 std::min((value_->Get() / maxValue_->Get()) * totalDegree * contentSize.Width(), contentSize.Width());
1624 bool isDefault = GreatOrEqual(borderRadius, contentSize.Height() / INT32_TWO);
1625 if (isDefault) {
1626 if (!isRightToLeft_->Get()) {
1627 // startAngle:270 sweepAngle:180
1628 path.AddArc({ offsetX + (contentSize.Width() - borderRadius) * FLOAT_TWO_ZERO - progressWidth, offsetY,
1629 offsetX + progressWidth, contentSize.Height() + offsetY },
1630 ANGLE_270, ANGLE_180);
1631 } else {
1632 path.AddArc({ offsetX + contentSize.Width() - progressWidth, offsetY,
1633 offsetX - contentSize.Width() + progressWidth + INT32_TWO * borderRadius,
1634 contentSize.Height() + offsetY },
1635 ANGLE_90, ANGLE_180);
1636 }
1637 } else {
1638 float tmpRadius = progressWidth - contentSize.Width() + borderRadius;
1639 RSRoundRect roundRect;
1640 if (!isRightToLeft_->Get()) {
1641 roundRect.SetRect({ contentSize.Width() + offsetX - borderRadius, offsetY, offsetX + progressWidth,
1642 contentSize.Height() + offsetY });
1643 roundRect.SetCornerRadius(RSRoundRect::TOP_RIGHT_POS, tmpRadius, tmpRadius);
1644 roundRect.SetCornerRadius(RSRoundRect::BOTTOM_RIGHT_POS, tmpRadius, tmpRadius);
1645 } else {
1646 roundRect.SetRect({ contentSize.Width() - progressWidth + offsetX, offsetY, offsetX + borderRadius,
1647 contentSize.Height() + offsetY });
1648 roundRect.SetCornerRadius(RSRoundRect::TOP_LEFT_POS, tmpRadius, tmpRadius);
1649 roundRect.SetCornerRadius(RSRoundRect::BOTTOM_LEFT_POS, tmpRadius, tmpRadius);
1650 }
1651 path.AddRoundRect(roundRect);
1652 }
1653 }
1654
PaintVerticalCapsule(RSCanvas & canvas,const OffsetF & offset,const SizeF & contentSize,const float borderRadius) const1655 void ProgressModifier::PaintVerticalCapsule(
1656 RSCanvas& canvas, const OffsetF& offset, const SizeF& contentSize, const float borderRadius) const
1657 {
1658 auto borderWidth = capsuleBorderWidth_->Get();
1659 if (GreatNotEqual(2 * borderWidth, contentSize.Width())) {
1660 borderWidth = contentSize.Width() / 2;
1661 }
1662 static int32_t totalDegree = 1;
1663 float radiusBig = borderRadius - (borderWidth / INT32_TWO);
1664 float offsetXBig = offset.GetX() + borderWidth / INT32_TWO;
1665 float offsetYBig = offset.GetY() + borderWidth / INT32_TWO;
1666 float offsetX = offset.GetX();
1667 float offsetY = offset.GetY();
1668 float progressWidth =
1669 std::min((value_->Get() / maxValue_->Get()) * totalDegree * contentSize.Height(), contentSize.Height());
1670 bool isDefault = GreatOrEqual(borderRadius, contentSize.Width() / INT32_TWO);
1671 RSBrush brush;
1672 brush.SetAntiAlias(true);
1673 RSPen pen;
1674 pen.SetWidth(borderWidth);
1675 pen.SetAntiAlias(true);
1676 pen.SetColor(ToRSColor(borderColor_->Get()));
1677 brush.SetAlpha(true);
1678 brush.SetColor(ToRSColor(bgColor_->Get()));
1679 #ifndef USE_ROSEN_DRAWING
1680 RSPath path;
1681 #else
1682 RSRecordingPath path;
1683 #endif
1684 canvas.AttachBrush(brush);
1685 canvas.DrawRoundRect({ { offsetX, offsetY, contentSize.Width() + offsetX, contentSize.Height() + offsetY },
1686 borderRadius, borderRadius });
1687 canvas.DetachBrush();
1688 canvas.AttachPen(pen);
1689 if (!NearZero(borderWidth)) {
1690 canvas.DrawRoundRect({ { offsetXBig, offsetYBig, contentSize.Width() - borderWidth + offsetXBig,
1691 contentSize.Height() - borderWidth + offsetYBig },
1692 radiusBig, radiusBig });
1693 }
1694 canvas.DetachPen();
1695 brush.SetColor(ToRSColor((color_->Get())));
1696 canvas.AttachBrush(brush);
1697 if (isDefault) {
1698 path.AddArc({ offsetX, offsetY, contentSize.Width() + offsetX, contentSize.Width() + offsetY }, 0, -ANGLE_180);
1699 } else {
1700 RSRoundRect roundRect;
1701 roundRect.SetRect({ offsetX, offsetY, contentSize.Width() + offsetX, offsetY + borderRadius });
1702 roundRect.SetCornerRadius(RSRoundRect::TOP_LEFT_POS, borderRadius, borderRadius);
1703 roundRect.SetCornerRadius(RSRoundRect::TOP_RIGHT_POS, borderRadius, borderRadius);
1704 path.AddRoundRect(roundRect);
1705 }
1706 if (LessNotEqual(progressWidth, borderRadius)) {
1707 if (isDefault) {
1708 // startAngle:180 sweepAngle:180
1709 path.AddArc({ offsetX, offsetY + progressWidth, contentSize.Width() + offsetX,
1710 contentSize.Width() - progressWidth + offsetY },
1711 ANGLE_180, ANGLE_180);
1712 } else {
1713 float tmpRadius = borderRadius - progressWidth;
1714 RSRoundRect roundRect;
1715 roundRect.SetRect(
1716 { offsetX, offsetY + progressWidth, contentSize.Width() + offsetX, offsetY + borderRadius });
1717 roundRect.SetCornerRadius(RSRoundRect::TOP_LEFT_POS, tmpRadius, tmpRadius);
1718 roundRect.SetCornerRadius(RSRoundRect::TOP_RIGHT_POS, tmpRadius, tmpRadius);
1719 path.AddRoundRect(roundRect, RSPathDirection::CCW_DIRECTION);
1720 }
1721 } else if (GreatNotEqual(progressWidth, contentSize.Height() - borderRadius)) {
1722 path.AddRect({ offsetX, offsetY + borderRadius, contentSize.Width() + offsetX,
1723 contentSize.Height() - borderRadius + offsetY });
1724 if (isDefault) {
1725 // startAngle:180 sweepAngle:-180
1726 path.AddArc({ offsetX, offsetY + (contentSize.Height() - borderRadius) * FLOAT_TWO_ZERO - progressWidth,
1727 contentSize.Width() + offsetX, progressWidth + offsetY },
1728 ANGLE_180, -ANGLE_180);
1729 } else {
1730 float tmpRadius = progressWidth - contentSize.Height() + borderRadius;
1731 RSRoundRect roundRect;
1732 roundRect.SetRect({ offsetX, contentSize.Height() - borderRadius + offsetY, contentSize.Width() + offsetX,
1733 progressWidth + offsetY });
1734 roundRect.SetCornerRadius(RSRoundRect::BOTTOM_LEFT_POS, tmpRadius, tmpRadius);
1735 roundRect.SetCornerRadius(RSRoundRect::BOTTOM_RIGHT_POS, tmpRadius, tmpRadius);
1736 path.AddRoundRect(roundRect);
1737 }
1738 } else {
1739 path.AddRect({ offsetX, borderRadius + offsetY, offsetX + contentSize.Width(), progressWidth + offsetY });
1740 }
1741 canvas.DrawPath(path);
1742 canvas.DetachBrush();
1743 canvas.Restore();
1744
1745 PaintCapsuleLightSweep(canvas, contentSize, offset, path, true);
1746 }
1747
PaintCapsuleLightSweep(RSCanvas & canvas,const SizeF & contentSize,const OffsetF & offset,const RSPath & path,bool isVertical) const1748 void ProgressModifier::PaintCapsuleLightSweep(
1749 RSCanvas& canvas, const SizeF& contentSize, const OffsetF& offset, const RSPath& path, bool isVertical) const
1750 {
1751 RSPen pen;
1752 pen.SetAntiAlias(true);
1753 pen.SetWidth(1);
1754 auto gradient = CreateCapsuleGradient();
1755 std::vector<RSColorQuad> colors;
1756 std::vector<float> pos;
1757 RSBrush brush;
1758 auto gradientColors = gradient.GetColors();
1759 for (size_t i = 0; i < gradientColors.size(); i++) {
1760 colors.emplace_back(gradientColors[i].GetColor().GetValue());
1761 pos.emplace_back(gradientColors[i].GetDimension().Value());
1762 }
1763
1764 float endPos = sweepingDate_->Get();
1765 #ifndef USE_ROSEN_DRAWING
1766 if (isVertical) {
1767 brush.SetShaderEffect(RSShaderEffect::CreateLinearGradient(
1768 ToRSPoint(
1769 PointF(offset.GetX() + contentSize.Width() / 2, offset.GetY() + endPos - SWEEP_WIDTH.ConvertToPx())),
1770 ToRSPoint(PointF(offset.GetX() + contentSize.Width() / 2, offset.GetY() + endPos)), colors, pos,
1771 RSTileMode::CLAMP));
1772 } else {
1773 brush.SetShaderEffect(RSShaderEffect::CreateLinearGradient(
1774 ToRSPoint(PointF(!isRightToLeft_->Get() ? offset.GetX() + endPos - SWEEP_WIDTH.ConvertToPx()
1775 : offset.GetX() + contentSize.Width() - endPos,
1776 offset.GetY() + contentSize.Height() / 2)),
1777 ToRSPoint(PointF(!isRightToLeft_->Get()
1778 ? offset.GetX() + endPos
1779 : offset.GetX() + contentSize.Width() - endPos + SWEEP_WIDTH.ConvertToPx(),
1780 offset.GetY() + contentSize.Height() / 2)),
1781 colors, pos, RSTileMode::CLAMP));
1782 }
1783 #else
1784 if (isVertical) {
1785 brush.SetShaderEffect(RSRecordingShaderEffect::CreateLinearGradient(
1786 ToRSPoint(PointF(offset.GetX() + contentSize.Width() / 2,
1787 offset.GetY() + endPos - SWEEP_WIDTH.ConvertToPx() + capsuleBorderWidth_->Get())),
1788 ToRSPoint(
1789 PointF(offset.GetX() + contentSize.Width() / 2, offset.GetY() + endPos - capsuleBorderWidth_->Get())),
1790 colors, pos, RSTileMode::CLAMP));
1791 } else {
1792 brush.SetShaderEffect(RSRecordingShaderEffect::CreateLinearGradient(
1793 ToRSPoint(PointF(!isRightToLeft_->Get()
1794 ? offset.GetX() + endPos - SWEEP_WIDTH.ConvertToPx() + capsuleBorderWidth_->Get()
1795 : offset.GetX() + contentSize.Width() - endPos + capsuleBorderWidth_->Get(),
1796 offset.GetY() + contentSize.Height() / 2)),
1797 ToRSPoint(PointF(!isRightToLeft_->Get() ? offset.GetX() + endPos - capsuleBorderWidth_->Get()
1798 : offset.GetX() + contentSize.Width() - endPos +
1799 SWEEP_WIDTH.ConvertToPx() - capsuleBorderWidth_->Get(),
1800 offset.GetY() + contentSize.Height() / 2)),
1801 colors, pos, RSTileMode::CLAMP));
1802 }
1803 #endif
1804
1805 auto offsetX = offset.GetX();
1806 auto offsetY = offset.GetY();
1807 canvas.Save();
1808 canvas.ClipPath(path, RSClipOp::INTERSECT, true);
1809 canvas.AttachBrush(brush);
1810 if (isVertical) {
1811 canvas.DrawRect(
1812 { offsetX, offsetY + endPos - SWEEP_WIDTH.ConvertToPx(),
1813 offsetX + contentSize.Width(), offsetY + endPos });
1814 } else {
1815 if (!isRightToLeft_->Get()) {
1816 canvas.DrawRect({ offsetX + endPos - SWEEP_WIDTH.ConvertToPx(), offsetY, offsetX + endPos,
1817 offsetY + contentSize.Height() });
1818 } else {
1819 canvas.DrawRect({ offsetX + contentSize.Width() - endPos, offsetY,
1820 offsetX + contentSize.Width() - endPos + SWEEP_WIDTH.ConvertToPx(), offsetY + contentSize.Height() });
1821 }
1822 }
1823 canvas.DetachBrush();
1824 canvas.Restore();
1825 }
1826
CreateCapsuleGradient() const1827 Gradient ProgressModifier::CreateCapsuleGradient() const
1828 {
1829 Gradient gradient;
1830 Color lightSweepColorBase = Color::WHITE;
1831 Color lightSweepColorEnd = lightSweepColorBase.ChangeOpacity(0.0);
1832 Color lightSweepColorMiddle = lightSweepColorBase.ChangeOpacity(0.2);
1833 GradientColor gradientColorEnd;
1834 isRightToLeft_->Get() ? gradientColorEnd.SetColor(lightSweepColorMiddle)
1835 : gradientColorEnd.SetColor(lightSweepColorEnd);
1836 gradientColorEnd.SetDimension(Dimension(0.0, DimensionUnit::VP));
1837 gradient.AddColor(gradientColorEnd);
1838
1839 GradientColor gradientColorMiddle;
1840 isRightToLeft_->Get() ? gradientColorMiddle.SetColor(lightSweepColorEnd)
1841 : gradientColorMiddle.SetColor(lightSweepColorMiddle);
1842 gradientColorMiddle.SetDimension(SWEEP_WIDTH);
1843 gradient.AddColor(gradientColorMiddle);
1844 return gradient;
1845 }
1846
PostTask(const TaskExecutor::Task & task,const std::string & name)1847 bool ProgressModifier::PostTask(const TaskExecutor::Task& task, const std::string& name)
1848 {
1849 auto pipeline = PipelineBase::GetCurrentContext();
1850 CHECK_NULL_RETURN(pipeline, false);
1851 auto taskExecutor = pipeline->GetTaskExecutor();
1852 CHECK_NULL_RETURN(taskExecutor, false);
1853 return taskExecutor->PostTask(task, TaskExecutor::TaskType::UI, name);
1854 }
1855
SetStrokeRadius(float strokeRaidus)1856 void ProgressModifier::SetStrokeRadius(float strokeRaidus)
1857 {
1858 strokeRadius_->Set(strokeRaidus);
1859 }
1860
SetIsRightToLeft(bool value)1861 void ProgressModifier::SetIsRightToLeft(bool value)
1862 {
1863 if (isRightToLeft_->Get() == value) {
1864 return;
1865 }
1866 isRightToLeft_->Set(value);
1867 }
1868
SetIsHovered(bool value)1869 void ProgressModifier::SetIsHovered(bool value)
1870 {
1871 isHover_ = value;
1872 }
1873
SetIsPressed(bool value)1874 void ProgressModifier::SetIsPressed(bool value)
1875 {
1876 isPress_ = value;
1877 }
1878
SetIsFocused(bool value)1879 void ProgressModifier::SetIsFocused(bool value)
1880 {
1881 isFocus_ = value;
1882 }
1883
IsFocused() const1884 bool ProgressModifier::IsFocused() const
1885 {
1886 return isFocus_;
1887 }
1888
CalculateHoverPressColor(const Color & color)1889 Color ProgressModifier::CalculateHoverPressColor(const Color& color)
1890 {
1891 if (progressType_->Get() != static_cast<int32_t>(ProgressType::CAPSULE)) {
1892 return color;
1893 }
1894
1895 Color outColor = color;
1896 if (isHover_) {
1897 outColor = color.BlendColor(hoverBlendColor_);
1898 }
1899 if (isPress_) {
1900 outColor = color.BlendColor(pressBlendColor_);
1901 }
1902 return outColor;
1903 }
1904
PaintScaleRingForApiNine(RSCanvas & canvas,const OffsetF & offset,const SizeF & frameSize) const1905 void ProgressModifier::PaintScaleRingForApiNine(RSCanvas& canvas, const OffsetF& offset, const SizeF& frameSize) const
1906 {
1907 auto scaleWidth = scaleWidth_->Get();
1908 PointF centerPt = PointF(frameSize.Width() / 2, frameSize.Height() / 2) + offset;
1909 double radius = std::min(frameSize.Width() / 2, frameSize.Height() / 2);
1910 double lengthOfScale = strokeWidth_->Get();
1911 if (lengthOfScale > radius) {
1912 lengthOfScale = radius / 2;
1913 }
1914 double pathDistance = 2.0 * M_PI * radius / scaleCount_->Get();
1915 if (scaleWidth > pathDistance) {
1916 PaintRing(canvas, offset, frameSize);
1917 return;
1918 }
1919 double widthOfLine = scaleWidth;
1920 RSPen pen;
1921 RSPath path;
1922 pen.SetWidth(widthOfLine);
1923 path.AddRoundRect({
1924 0, 0, widthOfLine, lengthOfScale }, widthOfLine / 2, widthOfLine / 2, RSPathDirection::CW_DIRECTION);
1925 pen.SetAntiAlias(true);
1926 pen.SetCapStyle(ToRSCapStyle(LineCap::ROUND));
1927 pen.SetPathEffect(RSPathEffect::CreatePathDashEffect(path, pathDistance, 0.0f, RSPathDashStyle::ROTATE));
1928 pen.SetColor(ToRSColor(bgColor_->Get()));
1929 canvas.AttachPen(pen);
1930 canvas.DrawArc({
1931 centerPt.GetX() - radius, centerPt.GetY() - radius, centerPt.GetX() + radius, centerPt.GetY() + radius },
1932 ANGLE_270, ANGLE_360);
1933 canvas.DetachPen();
1934 pen.SetColor(ToRSColor((color_->Get())));
1935 canvas.AttachPen(pen);
1936 double angle = (value_->Get() / maxValue_->Get()) * ANGLE_360;
1937 canvas.DrawArc({
1938 centerPt.GetX() - radius, centerPt.GetY() - radius, centerPt.GetX() + radius, centerPt.GetY() + radius },
1939 ANGLE_270, angle);
1940 canvas.DetachPen();
1941 }
1942
PaintCapsuleForApiNine(RSCanvas & canvas,const OffsetF & offset,const SizeF & frameSize) const1943 void ProgressModifier::PaintCapsuleForApiNine(RSCanvas& canvas, const OffsetF& offset, const SizeF& frameSize) const
1944 {
1945 double radius = std::min(frameSize.Width() / 2, frameSize.Height() / 2);
1946 double offsetX = offset.GetX();
1947 double offsetY = offset.GetY();
1948 double progressWidth = (value_->Get() / maxValue_->Get()) * frameSize.Width();
1949 RSBrush brush;
1950 brush.SetAlpha(true);
1951 brush.SetColor(ToRSColor(bgColor_->Get()));
1952 RSPath path;
1953 canvas.AttachBrush(brush);
1954 canvas.DrawRoundRect({ { offsetX, offsetY, frameSize.Width() + offsetX, frameSize.Height() + offsetY },
1955 radius, radius });
1956 canvas.DetachBrush();
1957 brush.SetColor(ToRSColor(color_->Get()));
1958 canvas.AttachBrush(brush);
1959 path.AddArc({ offsetX, offsetY, 2 * radius + offsetX, frameSize.Height() + offsetY }, ANGLE_90, ANGLE_180);
1960 if (LessNotEqual(progressWidth, radius)) {
1961 // startAngle:270 sweepAngle:-180
1962 path.AddArc({
1963 offsetX + progressWidth, offsetY, 2 * radius - progressWidth + offsetX, frameSize.Height() + offsetY },
1964 ANGLE_270, -ANGLE_180);
1965 } else if (GreatNotEqual(progressWidth, frameSize.Width() - radius)) {
1966 path.AddRect({ offsetX + radius, offsetY, frameSize.Width() + offsetX - radius,
1967 frameSize.Height() + offsetY });
1968 // startAngle:270 sweepAngle:180
1969 path.AddArc({ offsetX + (frameSize.Width() - radius) * 2.0 - progressWidth, offsetY, offsetX + progressWidth,
1970 frameSize.Height() + offsetY }, ANGLE_270, ANGLE_180);
1971 } else {
1972 path.AddRect({ radius + offsetX, offsetY, progressWidth + offsetX, frameSize.Height() + offsetY });
1973 }
1974 canvas.DrawPath(path);
1975 canvas.DetachBrush();
1976 }
1977
PaintVerticalCapsuleForApiNine(RSCanvas & canvas,const OffsetF & offset,const SizeF & frameSize) const1978 void ProgressModifier::PaintVerticalCapsuleForApiNine(
1979 RSCanvas& canvas, const OffsetF& offset, const SizeF& frameSize) const
1980 {
1981 double radius = std::min(frameSize.Width() / 2, frameSize.Height() / 2);
1982 double offsetX = offset.GetX();
1983 double offsetY = offset.GetY();
1984 double progressWidth = (value_->Get() / maxValue_->Get()) * frameSize.Height();
1985 RSBrush brush;
1986 brush.SetAlpha(true);
1987 brush.SetColor(ToRSColor(bgColor_->Get()));
1988 RSPath path;
1989 canvas.AttachBrush(brush);
1990 canvas.DrawRoundRect({ {
1991 offsetX, offsetY, frameSize.Width() + offsetX, frameSize.Height() + offsetY }, radius, radius });
1992 canvas.DetachBrush();
1993 brush.SetColor(ToRSColor((color_->Get())));
1994 canvas.AttachBrush(brush);
1995 path.AddArc({ offsetX, offsetY, frameSize.Width() + offsetX, frameSize.Width() + offsetY }, 0, -ANGLE_180);
1996 if (LessNotEqual(progressWidth, radius)) {
1997 // startAngle:180 sweepAngle:180
1998 path.AddArc({ offsetX, offsetY + progressWidth, frameSize.Width() + offsetX,
1999 frameSize.Width() - progressWidth + offsetY },
2000 ANGLE_180, ANGLE_180);
2001 } else if (GreatNotEqual(progressWidth, frameSize.Height() - radius)) {
2002 path.AddRect({
2003 offsetX, offsetY + radius, frameSize.Width() + offsetX, frameSize.Height() - radius + offsetY });
2004 // startAngle:180 sweepAngle:-180
2005 path.AddArc({ offsetX, offsetY + (frameSize.Height() - radius) * 2.0 - progressWidth,
2006 frameSize.Width() + offsetX, progressWidth + offsetY }, ANGLE_180, -ANGLE_180);
2007 } else {
2008 path.AddRect({ offsetX, radius + offsetY, offsetX + frameSize.Width(), progressWidth + offsetY });
2009 }
2010 canvas.DrawPath(path);
2011 canvas.DetachBrush();
2012 }
2013
GetThemeScopeId() const2014 uint32_t ProgressModifier::GetThemeScopeId() const
2015 {
2016 auto host = host_.Upgrade();
2017 return host ? host->GetThemeScopeId() : 0;
2018 }
2019 } // namespace OHOS::Ace::NG
2020