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