1 /*
2 * Copyright (c) 2022-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_pattern.h"
17
18 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
19 #include "ui/base/utils/utils.h"
20
21 #include "base/log/dump_log.h"
22 #include "core/components/progress/progress_theme.h"
23 #include "core/components/theme/app_theme.h"
24 #include "core/components/theme/shadow_theme.h"
25 #include "core/components_ng/base/inspector_filter.h"
26 #include "core/components_ng/pattern/progress/progress_layout_algorithm.h"
27 #include "core/components_ng/pattern/text/text_layout_property.h"
28 #include "core/components_ng/pattern/text/text_pattern.h"
29 #include "core/pipeline/pipeline_base.h"
30
31 namespace OHOS::Ace::NG {
32 namespace {
33 constexpr float PROGRESS_DEFAULT_VALUE = 0.0f;
34 constexpr float PROGRESS_MAX_VALUE = 100.0f;
35 }
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)36 bool ProgressPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
37 {
38 if (config.skipMeasure || dirty->SkipMeasureContent()) {
39 return false;
40 }
41 auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
42 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
43 auto progressLayoutAlgorithm = DynamicCast<ProgressLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
44 CHECK_NULL_RETURN(progressLayoutAlgorithm, false);
45 strokeWidth_ = progressLayoutAlgorithm->GetStrokeWidth();
46 return true;
47 }
48
OnAttachToFrameNode()49 void ProgressPattern::OnAttachToFrameNode()
50 {
51 auto host = GetHost();
52 CHECK_NULL_VOID(host);
53 host->GetRenderContext()->SetClipToFrame(true);
54 }
55
InitAnimatableProperty(ProgressAnimatableProperty & progressAnimatableProperty)56 void ProgressPattern::InitAnimatableProperty(ProgressAnimatableProperty& progressAnimatableProperty)
57 {
58 auto pipeline = PipelineBase::GetCurrentContext();
59 CHECK_NULL_VOID(pipeline);
60 auto progressTheme = pipeline->GetTheme<ProgressTheme>(GetThemeScopeId());
61 CHECK_NULL_VOID(progressTheme);
62 auto progressLayoutProperty = GetLayoutProperty<ProgressLayoutProperty>();
63 CHECK_NULL_VOID(progressLayoutProperty);
64 auto paintProperty = GetPaintProperty<ProgressPaintProperty>();
65 CHECK_NULL_VOID(paintProperty);
66 InitColorProperty(progressAnimatableProperty, progressTheme, paintProperty);
67 auto host = GetHost();
68 CHECK_NULL_VOID(host);
69 auto geometryNode = host->GetGeometryNode();
70 CHECK_NULL_VOID(geometryNode);
71 auto contentSize = geometryNode->GetContentSize();
72 CalculateStrokeWidth(contentSize);
73 auto strokeRadius = static_cast<float>(
74 paintProperty->GetStrokeRadiusValue(Dimension(strokeWidth_ / 2, DimensionUnit::VP)).ConvertToPx());
75 strokeRadius = std::min(strokeWidth_ / 2, strokeRadius);
76 auto smoothEffect = paintProperty->GetEnableSmoothEffectValue(true);
77 if (!smoothEffect) {
78 auto value = paintProperty->GetValueValue(PROGRESS_DEFAULT_VALUE);
79 progressAnimatableProperty.value = value;
80 }
81 progressAnimatableProperty.strokeWidth = strokeWidth_;
82 progressAnimatableProperty.strokeRadius = strokeRadius;
83
84 capsuleFocusScale_ = progressTheme->GetCapsuleFocusScale();
85 defaultTextColor_ = progressTheme->GetTextColor();
86 focusedTextColor_ = progressTheme->GetCapsuleTextFocusedColor();
87 focusShadowStyle_ = static_cast<ShadowStyle>(progressTheme->GetCapsuleFocusedShadowStyle());
88 }
89
InitColorProperty(ProgressAnimatableProperty & progressAnimatableProperty,const RefPtr<ProgressTheme> & progressTheme,const RefPtr<ProgressPaintProperty> & paintProperty)90 void ProgressPattern::InitColorProperty(ProgressAnimatableProperty& progressAnimatableProperty,
91 const RefPtr<ProgressTheme>& progressTheme, const RefPtr<ProgressPaintProperty>& paintProperty)
92 {
93 auto color = progressTheme->GetTrackSelectedColor();
94 auto bgColor = progressTheme->GetTrackBgColor();
95 if (progressType_ == ProgressType::CAPSULE) {
96 color = progressTheme->GetCapsuleSelectColor();
97 bgColor = progressTheme->GetCapsuleBgColor();
98 } else if (progressType_ == ProgressType::RING) {
99 bgColor = progressTheme->GetRingProgressBgColor();
100 } else if (progressType_ == ProgressType::SCALE) {
101 color = progressTheme->GetScaleTrackSelectedColor();
102 }
103 color = paintProperty->GetColor().value_or(color);
104 bgColor = paintProperty->GetBackgroundColor().value_or(bgColor);
105 auto borderColor = paintProperty->GetBorderColor().value_or(progressTheme->GetBorderColor());
106
107 progressAnimatableProperty.color = color;
108 progressAnimatableProperty.bgColor = bgColor;
109 progressAnimatableProperty.borderColor = borderColor;
110
111 if (paintProperty->HasGradientColor()) {
112 progressAnimatableProperty.ringProgressColor = paintProperty->GetGradientColorValue();
113 } else {
114 progressAnimatableProperty.ringProgressColor = convertGradient(color);
115 }
116 }
117
CalculateStrokeWidth(const SizeF & contentSize)118 void ProgressPattern::CalculateStrokeWidth(const SizeF& contentSize)
119 {
120 auto length = std::min(contentSize.Width(), contentSize.Height());
121 auto radius = length / 2;
122 switch (progressType_) {
123 case ProgressType::LINEAR:
124 strokeWidth_ = std::min(strokeWidth_, length);
125 break;
126 case ProgressType::RING:
127 case ProgressType::SCALE:
128 if (strokeWidth_ >= radius) {
129 strokeWidth_ = radius / 2;
130 }
131 break;
132 default:
133 break;
134 }
135 }
136
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const137 void ProgressPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
138 {
139 /* no fixed attr below, just return */
140 if (filter.IsFastFilter()) {
141 ToJsonValueForRingStyleOptions(json, filter);
142 ToJsonValueForLinearStyleOptions(json, filter);
143 ToJsonValueForCapsuleStyleOptions(json, filter);
144 return;
145 }
146 auto layoutProperty = GetLayoutProperty<ProgressLayoutProperty>();
147 CHECK_NULL_VOID(layoutProperty);
148 auto paintProperty = GetPaintProperty<ProgressPaintProperty>();
149 CHECK_NULL_VOID(paintProperty);
150 auto pipeline = PipelineBase::GetCurrentContext();
151 CHECK_NULL_VOID(pipeline);
152 auto theme = pipeline->GetTheme<ProgressTheme>(GetThemeScopeId());
153 CHECK_NULL_VOID(theme);
154 auto jsonValue = JsonUtil::Create(true);
155 jsonValue->Put("strokeWidth", layoutProperty->GetStrokeWidthValue(theme->GetTrackThickness()).ToString().c_str());
156 jsonValue->Put("scaleCount", std::to_string(paintProperty->GetScaleCountValue(theme->GetScaleNumber())).c_str());
157 jsonValue->Put("scaleWidth", paintProperty->GetScaleWidthValue(theme->GetScaleWidth()).ToString().c_str());
158 json->PutExtAttr("style", jsonValue->ToString().c_str(), filter);
159 ToJsonValueForRingStyleOptions(json, filter);
160 ToJsonValueForLinearStyleOptions(json, filter);
161 ToJsonValueForCapsuleStyleOptions(json, filter);
162 json->PutExtAttr("enableSmoothEffect",
163 paintProperty->GetEnableSmoothEffectValue(true) ? "true" : "false", filter);
164 json->PutExtAttr("privacySensitive", paintProperty->GetIsSensitive().value_or(false)? "true": "false", filter);
165 }
166
InitFocusEvent()167 void ProgressPattern::InitFocusEvent()
168 {
169 auto host = GetHost();
170 CHECK_NULL_VOID(host);
171 auto focusHub = host->GetOrCreateFocusHub();
172 auto focusTask = [weak = WeakClaim(this)](FocusReason reason) {
173 auto pattern = weak.Upgrade();
174 CHECK_NULL_VOID(pattern);
175 pattern->HandleFocusEvent();
176 };
177 focusHub->SetOnFocusInternal(focusTask);
178 auto blurTask = [weak = WeakClaim(this)]() {
179 auto pattern = weak.Upgrade();
180 CHECK_NULL_VOID(pattern);
181 pattern->HandleBlurEvent();
182 };
183 focusHub->SetOnBlurInternal(blurTask);
184 }
185
HandleFocusEvent()186 void ProgressPattern::HandleFocusEvent()
187 {
188 auto host = GetHost();
189 CHECK_NULL_VOID(host);
190 auto pipeline = host->GetContext();
191 CHECK_NULL_VOID(pipeline);
192 if (pipeline->GetIsFocusActive()) {
193 SetFocusStyle();
194 }
195 AddIsFocusActiveUpdateEvent();
196 }
197
HandleBlurEvent()198 void ProgressPattern::HandleBlurEvent()
199 {
200 ClearFocusStyle();
201 RemoveIsFocusActiveUpdateEvent();
202 }
203
GetShadowFromTheme(ShadowStyle shadowStyle,Shadow & shadow)204 static bool GetShadowFromTheme(ShadowStyle shadowStyle, Shadow& shadow)
205 {
206 if (shadowStyle == ShadowStyle::None) {
207 return true;
208 }
209 auto pipelineContext = PipelineContext::GetCurrentContext();
210 CHECK_NULL_RETURN(pipelineContext, false);
211
212 auto shadowTheme = pipelineContext->GetTheme<ShadowTheme>();
213 CHECK_NULL_RETURN(shadowTheme, false);
214
215 auto colorMode = pipelineContext->GetColorMode();
216 shadow = shadowTheme->GetShadow(shadowStyle, colorMode);
217 return true;
218 }
219
SetFocusStyle()220 void ProgressPattern::SetFocusStyle()
221 {
222 CHECK_NULL_VOID(progressModifier_);
223 progressModifier_->SetIsFocused(true);
224
225 auto host = GetHost();
226 CHECK_NULL_VOID(host);
227 auto renderContext = host->GetRenderContext();
228 CHECK_NULL_VOID(renderContext);
229 auto& transform = renderContext->GetOrCreateTransform();
230 CHECK_NULL_VOID(transform);
231
232 if (!transform->HasTransformScale()) {
233 renderContext->SetScale(capsuleFocusScale_, capsuleFocusScale_);
234 isFocusScaleSet_ = true;
235 }
236
237 auto paintProperty = host->GetPaintProperty<ProgressPaintProperty>();
238 CHECK_NULL_VOID(paintProperty);
239 if (paintProperty->GetTextColorValue(defaultTextColor_) == defaultTextColor_) {
240 SetTextColor(focusedTextColor_);
241 isFocusTextColorSet_ = true;
242 }
243
244 if (!renderContext->HasBackShadow() && focusShadowStyle_ != ShadowStyle::None
245 && !renderContext->HasBorderRadius()) {
246 Shadow shadow;
247 if (!GetShadowFromTheme(focusShadowStyle_, shadow)) {
248 shadow = Shadow::CreateShadow(focusShadowStyle_);
249 }
250 renderContext->UpdateBackShadow(shadow);
251 isFocusShadowSet_ = true;
252 }
253
254 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
255 }
256
ClearFocusStyle()257 void ProgressPattern::ClearFocusStyle()
258 {
259 CHECK_NULL_VOID(progressModifier_);
260 auto host = GetHost();
261 CHECK_NULL_VOID(host);
262 auto renderContext = host->GetRenderContext();
263 CHECK_NULL_VOID(renderContext);
264
265 if (isFocusScaleSet_) {
266 renderContext->SetScale(1.0f, 1.0f);
267 isFocusScaleSet_ = false;
268 }
269
270 if (isFocusTextColorSet_) {
271 SetTextColor(defaultTextColor_);
272 isFocusTextColorSet_ = false;
273 }
274
275 if (isFocusShadowSet_) {
276 renderContext->ResetBackShadow();
277 renderContext->SetShadowRadius(0.0f);
278 renderContext->ResetBorderRadius();
279 isFocusShadowSet_ = false;
280 }
281
282 progressModifier_->SetIsFocused(false);
283 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
284 }
285
AddIsFocusActiveUpdateEvent()286 void ProgressPattern::AddIsFocusActiveUpdateEvent()
287 {
288 if (!isFocusActiveUpdateEvent_) {
289 isFocusActiveUpdateEvent_ = [weak = WeakClaim(this)](bool isFocusAcitve) {
290 auto pattern = weak.Upgrade();
291 CHECK_NULL_VOID(pattern);
292 isFocusAcitve ? pattern->SetFocusStyle() : pattern->ClearFocusStyle();
293 };
294 }
295
296 auto pipline = PipelineContext::GetCurrentContext();
297 CHECK_NULL_VOID(pipline);
298 pipline->AddIsFocusActiveUpdateEvent(GetHost(), isFocusActiveUpdateEvent_);
299 }
300
RemoveIsFocusActiveUpdateEvent()301 void ProgressPattern::RemoveIsFocusActiveUpdateEvent()
302 {
303 auto pipline = PipelineContext::GetCurrentContext();
304 CHECK_NULL_VOID(pipline);
305 pipline->RemoveIsFocusActiveUpdateEvent(GetHost());
306 }
307
InitHoverEvent()308 void ProgressPattern::InitHoverEvent()
309 {
310 if (hoverEvent_) {
311 return;
312 }
313 auto host = GetHost();
314 CHECK_NULL_VOID(host);
315 auto eventHub = host->GetOrCreateEventHub<EventHub>();
316 CHECK_NULL_VOID(eventHub);
317 auto inputHub = eventHub->GetOrCreateInputEventHub();
318
319 auto hoverEventHandler = [weak = WeakClaim(this)](bool isHover) {
320 auto pattern = weak.Upgrade();
321 CHECK_NULL_VOID(pattern);
322 pattern->OnHover(isHover);
323 };
324 hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverEventHandler));
325 inputHub->AddOnHoverEvent(hoverEvent_);
326 }
327
RemoveHoverEvent()328 void ProgressPattern::RemoveHoverEvent()
329 {
330 if (hoverEvent_) {
331 auto host = GetHost();
332 CHECK_NULL_VOID(host);
333 auto eventHub = host->GetOrCreateEventHub<EventHub>();
334 CHECK_NULL_VOID(eventHub);
335 auto inputHub = eventHub->GetOrCreateInputEventHub();
336 inputHub->RemoveOnHoverEvent(hoverEvent_);
337 hoverEvent_ = nullptr;
338 }
339 }
340
OnHover(bool isHover)341 void ProgressPattern::OnHover(bool isHover)
342 {
343 CHECK_NULL_VOID(progressModifier_);
344 auto host = GetHost();
345 CHECK_NULL_VOID(host);
346
347 progressModifier_->SetIsHovered(isHover);
348 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
349 }
350
SetTextColor(const Color & color)351 void ProgressPattern::SetTextColor(const Color& color)
352 {
353 auto host = GetHost();
354 CHECK_NULL_VOID(host);
355 auto textHost = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(0));
356 CHECK_NULL_VOID(textHost);
357 auto textLayoutProperty = textHost->GetLayoutProperty<TextLayoutProperty>();
358 CHECK_NULL_VOID(textLayoutProperty);
359
360 textLayoutProperty->UpdateTextColor(color);
361 textHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
362 }
363
InitTouchEvent()364 void ProgressPattern::InitTouchEvent()
365 {
366 if (touchListener_) {
367 return;
368 }
369 auto host = GetHost();
370 CHECK_NULL_VOID(host);
371 auto gesture = host->GetOrCreateGestureEventHub();
372 CHECK_NULL_VOID(gesture);
373 auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
374 auto buttonPattern = weak.Upgrade();
375 CHECK_NULL_VOID(buttonPattern);
376 buttonPattern->OnPress(info);
377 };
378 touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
379 gesture->AddTouchEvent(touchListener_);
380 }
381
RemoveTouchEvent()382 void ProgressPattern::RemoveTouchEvent()
383 {
384 if (touchListener_) {
385 auto host = GetHost();
386 CHECK_NULL_VOID(host);
387 auto gesture = host->GetOrCreateGestureEventHub();
388 CHECK_NULL_VOID(gesture);
389 gesture->RemoveTouchEvent(touchListener_);
390 touchListener_ = nullptr;
391 }
392 }
HandleEnabled()393 void ProgressPattern::HandleEnabled()
394 {
395 auto host = GetHost();
396 CHECK_NULL_VOID(host);
397 auto eventHub = host->GetOrCreateEventHub<EventHub>();
398 CHECK_NULL_VOID(eventHub);
399 auto enabled = eventHub->IsEnabled();
400 auto renderContext = host->GetRenderContext();
401 CHECK_NULL_VOID(renderContext);
402 auto pipeline = PipelineBase::GetCurrentContext();
403 CHECK_NULL_VOID(pipeline);
404 auto theme = pipeline->GetTheme<ProgressTheme>(GetThemeScopeId());
405 CHECK_NULL_VOID(theme);
406 auto alpha = theme->GetProgressDisable();
407 auto originalOpacity = renderContext->GetOpacityValue(1.0);
408 renderContext->OnOpacityUpdate(enabled ? originalOpacity : alpha * originalOpacity);
409 }
410
OnPress(const TouchEventInfo & info)411 void ProgressPattern::OnPress(const TouchEventInfo& info)
412 {
413 auto touchType = info.GetTouches().front().GetTouchType();
414 auto pipeline = PipelineBase::GetCurrentContext();
415 CHECK_NULL_VOID(pipeline);
416 auto theme = pipeline->GetTheme<ProgressTheme>(GetThemeScopeId());
417 CHECK_NULL_VOID(theme);
418 auto host = GetHost();
419 CHECK_NULL_VOID(host);
420 auto paintProperty = host->GetPaintProperty<ProgressPaintProperty>();
421 CHECK_NULL_VOID(paintProperty);
422 auto textHost = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(0));
423 CHECK_NULL_VOID(textHost);
424 auto textLayoutProperty = textHost->GetLayoutProperty<TextLayoutProperty>();
425 CHECK_NULL_VOID(textLayoutProperty);
426 CHECK_NULL_VOID(progressModifier_);
427
428 if (touchType == TouchType::DOWN) {
429 progressModifier_->SetIsPressed(true);
430 fontColor_ = textLayoutProperty->GetTextColor().value_or(theme->GetTextColor());
431 backgroundColorOptional_ = paintProperty->GetBackgroundColor();
432 selectColorOptional_ = paintProperty->GetColor();
433 borderColorOptional_ = paintProperty->GetBorderColor();
434 fontColor_ = textLayoutProperty->GetTextColor().value_or(theme->GetTextColor());
435 Color touchEffect = theme->GetClickEffect();
436 Color touchFontColorDown = fontColor_.BlendColor(touchEffect);
437 textLayoutProperty->UpdateTextColor(touchFontColorDown);
438 } else if (touchType == TouchType::UP || touchType == TouchType::CANCEL) {
439 progressModifier_->SetIsPressed(false);
440 if (backgroundColorOptional_) {
441 paintProperty->UpdateBackgroundColor(backgroundColorOptional_.value());
442 } else {
443 paintProperty->ResetBackgroundColor();
444 }
445 if (selectColorOptional_) {
446 paintProperty->UpdateColor(selectColorOptional_.value());
447 } else {
448 paintProperty->ResetColor();
449 }
450 if (borderColorOptional_) {
451 paintProperty->UpdateBorderColor(borderColorOptional_.value());
452 } else {
453 paintProperty->ResetBorderColor();
454 }
455 textLayoutProperty->UpdateTextColor(fontColor_);
456 }
457 textHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
458 host->MarkDirtyNode();
459 }
460
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)461 void ProgressPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
462 {
463 auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
464 auto pattern = wp.Upgrade();
465 CHECK_NULL_VOID(pattern);
466 pattern->GetInnerFocusPaintRect(paintRect);
467 };
468 focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
469 }
470
GetInnerFocusPaintRect(RoundRect & paintRect)471 void ProgressPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
472 {
473 auto host = GetHost();
474 CHECK_NULL_VOID(host);
475 const auto& content = host->GetGeometryNode()->GetContent();
476 CHECK_NULL_VOID(content);
477 auto contentOffset = content->GetRect().GetOffset();
478 auto contentSize = content->GetRect().GetSize();
479 auto currentContext = PipelineBase::GetCurrentContext();
480 CHECK_NULL_VOID(currentContext);
481 auto appTheme = currentContext->GetTheme<AppTheme>();
482 CHECK_NULL_VOID(appTheme);
483 auto paintWidth = appTheme->GetFocusWidthVp();
484 auto focusPadding = appTheme->GetFocusOutPaddingVp();
485 auto focusDistance = paintWidth / 2 + focusPadding;
486 auto focusRadius = GetBorderRadiusValues() + static_cast<float>(focusDistance.ConvertToPx());
487 paintRect.SetRect(RectF(contentOffset.GetX() - focusDistance.ConvertToPx(),
488 contentOffset.GetY() - focusDistance.ConvertToPx(), contentSize.Width() + 2 * focusDistance.ConvertToPx(),
489 contentSize.Height() + 2 * focusDistance.ConvertToPx()));
490 paintRect.SetCornerRadius(focusRadius);
491 if (isFocusShadowSet_) {
492 auto host = GetHost();
493 CHECK_NULL_VOID(host);
494 auto renderContext = host->GetRenderContext();
495 CHECK_NULL_VOID(renderContext);
496 renderContext->UpdateBorderRadius(BorderRadiusProperty(Dimension(focusRadius)));
497 }
498 }
499
OnModifyDone()500 void ProgressPattern::OnModifyDone()
501 {
502 Pattern::OnModifyDone();
503 FireBuilder();
504 auto host = GetHost();
505 CHECK_NULL_VOID(host);
506 auto progressLayoutProperty = GetLayoutProperty<ProgressLayoutProperty>();
507 CHECK_NULL_VOID(progressLayoutProperty);
508 if (progressLayoutProperty->GetType() == ProgressType::CAPSULE) {
509 auto hub = host->GetOrCreateEventHub<EventHub>();
510 HandleEnabled();
511 InitTouchEvent();
512 InitHoverEvent();
513 InitFocusEvent();
514 auto focusHub = hub->GetFocusHub();
515 CHECK_NULL_VOID(focusHub);
516 InitOnKeyEvent(focusHub);
517 } else {
518 RemoveTouchEvent();
519 RemoveHoverEvent();
520 }
521
522 if (progressLayoutProperty->GetType() == ProgressType::RING && !progressLayoutProperty->GetPaddingProperty()) {
523 auto pipeline = host->GetContext();
524 CHECK_NULL_VOID(pipeline);
525 auto theme = pipeline->GetTheme<ProgressTheme>(GetThemeScopeId());
526 CHECK_NULL_VOID(theme);
527 PaddingProperty padding;
528 padding.SetEdges(CalcLength(theme->GetRingDefaultPadding()));
529 progressLayoutProperty->UpdatePadding(padding);
530 }
531 OnAccessibilityEvent();
532 ReportProgressEvent();
533 }
534
DumpInfo()535 void ProgressPattern::DumpInfo()
536 {
537 auto layoutProperty = GetLayoutProperty<ProgressLayoutProperty>();
538 CHECK_NULL_VOID(layoutProperty);
539 auto pipeline = PipelineBase::GetCurrentContext();
540 CHECK_NULL_VOID(pipeline);
541 auto theme = pipeline->GetTheme<ProgressTheme>();
542 CHECK_NULL_VOID(theme);
543 auto paintProperty = GetPaintProperty<ProgressPaintProperty>();
544 CHECK_NULL_VOID(paintProperty);
545
546 auto value = paintProperty->GetValueValue(PROGRESS_DEFAULT_VALUE);
547 auto maxValue = paintProperty->GetMaxValue().value_or(PROGRESS_MAX_VALUE);
548 auto jsonValue = JsonUtil::Create(true);
549 auto color = paintProperty->GetColor().value_or(theme->GetCapsuleSelectColor());
550 jsonValue->Put("strokeWidth", layoutProperty->GetStrokeWidthValue(theme->GetTrackThickness()).ToString().c_str());
551 jsonValue->Put("scaleCount", std::to_string(paintProperty->GetScaleCountValue(theme->GetScaleNumber())).c_str());
552 jsonValue->Put("scaleWidth", paintProperty->GetScaleWidthValue(theme->GetScaleWidth()).ToString().c_str());
553 DumpLog::GetInstance().AddDesc(std::string("value:").append(std::to_string(value)));
554 DumpLog::GetInstance().AddDesc(std::string("maxValue:").append(std::to_string(maxValue)));
555 DumpLog::GetInstance().AddDesc(std::string("color:").append(color.ToString()));
556 DumpLog::GetInstance().AddDesc(std::string("style:").append(jsonValue->ToString()));
557 DumpLog::GetInstance().AddDesc(
558 std::string("EnableSmoothEffect: ")
559 .append(paintProperty->GetEnableSmoothEffectValue(true) ? "true" : "false"));
560 }
561
OnLanguageConfigurationUpdate()562 void ProgressPattern::OnLanguageConfigurationUpdate()
563 {
564 auto host = GetHost();
565 CHECK_NULL_VOID(host);
566 auto progressLayoutProperty = GetLayoutProperty<ProgressLayoutProperty>();
567 CHECK_NULL_VOID(progressLayoutProperty);
568 bool isRtl = progressLayoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
569 if (isRightToLeft_ == isRtl) {
570 return;
571 }
572 CHECK_NULL_VOID(progressModifier_);
573 progressModifier_->SetIsRightToLeft(isRtl);
574 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
575 isRightToLeft_ = isRtl;
576 }
577
OnVisibleChange(bool isVisible)578 void ProgressPattern::OnVisibleChange(bool isVisible)
579 {
580 auto host = GetHost();
581 CHECK_NULL_VOID(host);
582 visibilityProp_ = isVisible;
583 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
584 }
585
ToJsonValueForCapsuleStyleOptions(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const586 void ProgressPattern::ToJsonValueForCapsuleStyleOptions(
587 std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
588 {
589 /* no fixed attr below, just return */
590 if (filter.IsFastFilter()) {
591 return;
592 }
593 auto paintProperty = GetPaintProperty<ProgressPaintProperty>();
594 CHECK_NULL_VOID(paintProperty);
595 auto pipeline = PipelineBase::GetCurrentContext();
596 CHECK_NULL_VOID(pipeline);
597 auto progressTheme = pipeline->GetTheme<ProgressTheme>();
598 CHECK_NULL_VOID(progressTheme);
599 auto capsuleStyle = JsonUtil::Create(true);
600 auto font = JsonUtil::Create(true);
601 capsuleStyle->Put("borderWidth",
602 (paintProperty->GetBorderWidth().value_or(progressTheme->GetBorderWidth())).ToString().c_str());
603 capsuleStyle->Put("borderColor",
604 (paintProperty->GetBorderColor().value_or(progressTheme->GetBorderColor())).ColorToString().c_str());
605 capsuleStyle->Put("fontColor",
606 (paintProperty->GetTextColor().value_or(progressTheme->GetTextColor())).ColorToString().c_str());
607 capsuleStyle->Put("content", (paintProperty->GetText().value_or("")).c_str());
608 capsuleStyle->Put("enableScanEffect", (paintProperty->GetEnableScanEffect().value_or(false)) ? "true" : "false");
609 capsuleStyle->Put("showDefaultPercentage",
610 (paintProperty->GetEnableShowText().value_or(false)) ? "true" : "false");
611 font->Put("size", (paintProperty->GetTextSize().value_or(progressTheme->GetTextSize())).ToString().c_str());
612 font->Put("style", paintProperty->GetItalicFontStyle().value_or(Ace::FontStyle::NORMAL) == Ace::FontStyle::NORMAL ?
613 "FontStyle.Normal" : "FontStyle.Italic");
614 font->Put("weight",
615 V2::ConvertWrapFontWeightToStirng(paintProperty->GetFontWeight().value_or(FontWeight::NORMAL)).c_str());
616 std::vector<std::string> defaultFamily = { "Sans" };
617 std::vector<std::string> fontFamilyVector = paintProperty->GetFontFamily().value_or(defaultFamily);
618 if (fontFamilyVector.empty()) {
619 fontFamilyVector = defaultFamily;
620 }
621 std::string fontFamily = fontFamilyVector.at(0);
622 for (uint32_t i = 1; i < fontFamilyVector.size(); ++i) {
623 fontFamily += ',' + fontFamilyVector.at(i);
624 }
625 font->Put("family", fontFamily.c_str());
626 capsuleStyle->Put("font", font);
627 capsuleStyle->Put("borderRadius", (Dimension(GetBorderRadiusValues(), DimensionUnit::PX)).ToString().c_str());
628
629 json->PutExtAttr("capsuleStyle", capsuleStyle, filter);
630 }
631
GetBorderRadiusValues() const632 float ProgressPattern::GetBorderRadiusValues() const
633 {
634 auto host = GetHost();
635 CHECK_NULL_RETURN(host, -1);
636 auto geometryNode = host->GetGeometryNode();
637 CHECK_NULL_RETURN(geometryNode, -1);
638 auto contentSize = geometryNode->GetContentSize();
639 constexpr float HALF = 2.0f;
640 float contentMinHalf = std::min(contentSize.Height(), contentSize.Width()) / HALF;
641 auto paintProperty = GetPaintProperty<ProgressPaintProperty>();
642 CHECK_NULL_RETURN(paintProperty, -1);
643 auto borderRadiusRet = static_cast<float>(
644 paintProperty->GetBorderRadiusValue(Dimension(contentMinHalf, DimensionUnit::PX)).ConvertToPx());
645 return std::min(contentMinHalf, borderRadiusRet);
646 }
647
ToJsonValueForRingStyleOptions(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const648 void ProgressPattern::ToJsonValueForRingStyleOptions(std::unique_ptr<JsonValue>& json,
649 const InspectorFilter& filter) const
650 {
651 /* no fixed attr below, just return */
652 if (filter.IsFastFilter()) {
653 return;
654 }
655 auto layoutProperty = GetLayoutProperty<ProgressLayoutProperty>();
656 auto paintProperty = GetPaintProperty<ProgressPaintProperty>();
657 auto pipeline = PipelineBase::GetCurrentContext();
658 auto theme = pipeline->GetTheme<ProgressTheme>(GetThemeScopeId());
659
660 auto jsonValue = JsonUtil::Create(true);
661 jsonValue->Put("strokeWidth", layoutProperty->GetStrokeWidthValue(theme->GetTrackThickness()).ToString().c_str());
662 jsonValue->Put("enableScanEffect", (paintProperty->GetEnableRingScanEffect().value_or(false)) ? "true" : "false");
663 jsonValue->Put("shadow", paintProperty->GetPaintShadowValue(false) ? "true" : "false");
664 jsonValue->Put("status",
665 ConvertProgressStatusToString(paintProperty->GetProgressStatusValue(ProgressStatus::PROGRESSING)).c_str());
666 json->PutExtAttr("ringStyle", jsonValue, filter);
667 }
668
ToJsonValueForLinearStyleOptions(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const669 void ProgressPattern::ToJsonValueForLinearStyleOptions(
670 std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
671 {
672 /* no fixed attr below, just return */
673 if (filter.IsFastFilter()) {
674 return;
675 }
676 auto layoutProperty = GetLayoutProperty<ProgressLayoutProperty>();
677 auto paintProperty = GetPaintProperty<ProgressPaintProperty>();
678 auto pipeline = PipelineBase::GetCurrentContext();
679 auto theme = pipeline->GetTheme<ProgressTheme>(GetThemeScopeId());
680
681 auto jsonValue = JsonUtil::Create(true);
682 auto strokeWidth = layoutProperty->GetStrokeWidthValue(theme->GetTrackThickness());
683 jsonValue->Put("strokeWidth", strokeWidth.ToString().c_str());
684 auto strokeRadius = paintProperty->GetStrokeRadiusValue(strokeWidth / 2);
685 strokeRadius = std::min(strokeWidth / 2, strokeRadius);
686 jsonValue->Put("strokeRadius", strokeRadius.ToString().c_str());
687 jsonValue->Put("enableScanEffect", (paintProperty->GetEnableLinearScanEffect().value_or(false)) ? "true" : "false");
688 json->PutExtAttr("linearStyle", jsonValue, filter);
689 }
690
ConvertProgressStatusToString(const ProgressStatus status)691 std::string ProgressPattern::ConvertProgressStatusToString(const ProgressStatus status)
692 {
693 std::string str;
694
695 switch (status) {
696 case ProgressStatus::LOADING:
697 str = "ProgressStatus.LOADING";
698 break;
699 case ProgressStatus::PROGRESSING:
700 default:
701 str = "ProgressStatus.PROGRESSING";
702 break;
703 }
704
705 return str;
706 }
707
ObscureText(bool isSensitive)708 void ProgressPattern::ObscureText(bool isSensitive)
709 {
710 auto frameNode = GetHost();
711 CHECK_NULL_VOID(frameNode);
712 auto textHost = AceType::DynamicCast<FrameNode>(frameNode->GetChildAtIndex(0));
713 CHECK_NULL_VOID(textHost);
714 auto textPattern = textHost->GetPattern<TextPattern>();
715 CHECK_NULL_VOID(textPattern);
716 textPattern->OnSensitiveStyleChange(isSensitive);
717 textHost->SetPrivacySensitive(isSensitive);
718 textHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
719 }
720
OnSensitiveStyleChange(bool isSensitive)721 void ProgressPattern::OnSensitiveStyleChange(bool isSensitive)
722 {
723 auto frameNode = GetHost();
724 CHECK_NULL_VOID(frameNode);
725 auto progressPaintProperty = frameNode->GetPaintProperty<NG::ProgressPaintProperty>();
726 CHECK_NULL_VOID(progressPaintProperty);
727 progressPaintProperty->UpdateIsSensitive(isSensitive);
728 ObscureText(isSensitive);
729 frameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
730 }
731
FireBuilder()732 void ProgressPattern::FireBuilder()
733 {
734 auto host = GetHost();
735 CHECK_NULL_VOID(host);
736 if (!makeFunc_.has_value()) {
737 CHECK_NULL_VOID(contentModifierNode_);
738 host->RemoveChildAndReturnIndex(contentModifierNode_);
739 contentModifierNode_ = nullptr;
740 host->GetRenderContext()->SetClipToFrame(true);
741 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
742 return;
743 }
744 auto node = BuildContentModifierNode();
745 if (contentModifierNode_ == node) {
746 return;
747 }
748 host->GetRenderContext()->SetClipToFrame(false);
749 host->RemoveChildAndReturnIndex(contentModifierNode_);
750 contentModifierNode_ = node;
751 CHECK_NULL_VOID(contentModifierNode_);
752 host->AddChild(contentModifierNode_, 0);
753 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
754 }
755
BuildContentModifierNode()756 RefPtr<FrameNode> ProgressPattern::BuildContentModifierNode()
757 {
758 if (!makeFunc_.has_value()) {
759 return nullptr;
760 }
761 auto renderProperty = GetPaintProperty<ProgressPaintProperty>();
762 CHECK_NULL_RETURN(renderProperty, nullptr);
763 auto value = renderProperty->GetValue().value_or(PROGRESS_DEFAULT_VALUE);
764 auto total = renderProperty->GetMaxValue().value_or(PROGRESS_MAX_VALUE);
765 auto host = GetHost();
766 CHECK_NULL_RETURN(host, nullptr);
767 auto eventHub = host->GetOrCreateEventHub<EventHub>();
768 CHECK_NULL_RETURN(eventHub, nullptr);
769 auto enabled = eventHub->IsEnabled();
770 return (makeFunc_.value())(ProgressConfiguration{value, total, enabled});
771 }
772
DumpInfo(std::unique_ptr<JsonValue> & json)773 void ProgressPattern::DumpInfo(std::unique_ptr<JsonValue>& json)
774 {
775 auto layoutProperty = GetLayoutProperty<ProgressLayoutProperty>();
776 CHECK_NULL_VOID(layoutProperty);
777 auto pipeline = PipelineBase::GetCurrentContext();
778 CHECK_NULL_VOID(pipeline);
779 auto theme = pipeline->GetTheme<ProgressTheme>();
780 CHECK_NULL_VOID(theme);
781 auto paintProperty = GetPaintProperty<ProgressPaintProperty>();
782 CHECK_NULL_VOID(paintProperty);
783
784 auto value = paintProperty->GetValueValue(PROGRESS_DEFAULT_VALUE);
785 auto maxValue = paintProperty->GetMaxValue().value_or(PROGRESS_MAX_VALUE);
786 auto jsonValue = JsonUtil::Create(true);
787 auto color = paintProperty->GetColor().value_or(theme->GetCapsuleSelectColor());
788 jsonValue->Put("strokeWidth", layoutProperty->GetStrokeWidthValue(theme->GetTrackThickness()).ToString().c_str());
789 jsonValue->Put("scaleCount", std::to_string(paintProperty->GetScaleCountValue(theme->GetScaleNumber())).c_str());
790 jsonValue->Put("scaleWidth", paintProperty->GetScaleWidthValue(theme->GetScaleWidth()).ToString().c_str());
791 json->Put("value:", std::to_string(value).c_str());
792 json->Put("maxValue:", std::to_string(maxValue).c_str());
793 json->Put("color:", color.ToString().c_str());
794 json->Put("style:", jsonValue->ToString().c_str());
795 json->Put("EnableSmoothEffect", paintProperty->GetEnableSmoothEffectValue(true) ? "true" : "false");
796 }
797
OnAccessibilityEvent()798 void ProgressPattern::OnAccessibilityEvent()
799 {
800 if (!initFlag_) {
801 initFlag_ = true;
802 return;
803 }
804 auto paintProperty = GetPaintProperty<ProgressPaintProperty>();
805 CHECK_NULL_VOID(paintProperty);
806 auto value = paintProperty->GetValueValue(PROGRESS_DEFAULT_VALUE);
807 if (!NearEqual(value_, value)) {
808 value_ = value;
809 auto host = GetHost();
810 CHECK_NULL_VOID(host);
811 host->OnAccessibilityEvent(AccessibilityEventType::COMPONENT_CHANGE);
812 }
813 }
814
OnThemeScopeUpdate(int32_t themeScopeId)815 bool ProgressPattern::OnThemeScopeUpdate(int32_t themeScopeId)
816 {
817 bool result = false;
818 auto host = GetHost();
819 CHECK_NULL_RETURN(host, result);
820 auto paintProperty = host->GetPaintProperty<ProgressPaintProperty>();
821 CHECK_NULL_RETURN(paintProperty, result);
822 const auto& type = paintProperty->GetProgressType();
823 auto pipeline = PipelineBase::GetCurrentContext();
824 CHECK_NULL_RETURN(pipeline, result);
825 auto progressTheme = pipeline->GetTheme<ProgressTheme>(themeScopeId);
826 CHECK_NULL_RETURN(progressTheme, result);
827
828 result = !paintProperty->HasBackgroundColor() ||
829 ((type != ProgressType::RING) && (type != ProgressType::SCALE) && !paintProperty->HasColor()) ||
830 ((type == ProgressType::CAPSULE) && !paintProperty->HasBorderColor());
831
832 if (themeScopeId && !isUserInitiatedColor_) {
833 if (type == ProgressType::LINEAR || type == ProgressType::MOON) {
834 paintProperty->UpdateColor(progressTheme->GetTrackSelectedColor());
835 result = true;
836 } else if (type == ProgressType::CAPSULE) {
837 paintProperty->UpdateColor(progressTheme->GetCapsuleSelectColor());
838 result = true;
839 }
840 }
841
842 if (themeScopeId && !isUserInitiatedBgColor_ && type != ProgressType::CAPSULE) {
843 paintProperty->UpdateBackgroundColor(progressTheme->GetTrackBgColor());
844 result = true;
845 }
846 isUserInitiatedColor_ = (themeScopeId && isModifierInitiatedColor_) ? false : isUserInitiatedColor_;
847 isUserInitiatedBgColor_ = (themeScopeId && isModifierInitiatedBgColor_) ? false : isUserInitiatedBgColor_;
848
849 return result;
850 }
851
ReportProgressEvent()852 void ProgressPattern::ReportProgressEvent()
853 {
854 auto host = GetHost();
855 CHECK_NULL_VOID(host);
856 auto progressPaintProperty = host->GetPaintProperty<NG::ProgressPaintProperty>();
857 CHECK_NULL_VOID(progressPaintProperty);
858 auto value = progressPaintProperty->GetValueValue(PROGRESS_DEFAULT_VALUE);
859 if (!progressPaintProperty->GetMaxValue().has_value()) {
860 return;
861 }
862 auto maxValue = progressPaintProperty->GetMaxValue().value();
863 if (LessOrEqual(maxValue, value) && LessNotEqual(reportLastValue_, maxValue)) {
864 UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "Progress.onProgress");
865 }
866 reportLastValue_ = value;
867 }
868
UpdateColor(const Color & color,bool isFirstLoad)869 void ProgressPattern::UpdateColor(const Color& color, bool isFirstLoad)
870 {
871 auto host = GetHost();
872 CHECK_NULL_VOID(host);
873 auto paintProperty = host->GetPaintProperty<ProgressPaintProperty>();
874 CHECK_NULL_VOID(paintProperty);
875 auto pipelineContext = host->GetContext();
876 CHECK_NULL_VOID(pipelineContext);
877 if (isFirstLoad || pipelineContext->IsSystmColorChange()) {
878 paintProperty->UpdateColor(color);
879 }
880 if (host->GetRerenderable()) {
881 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
882 }
883 }
884
UpdateGradientColor(const NG::Gradient & gradient,bool isFirstLoad)885 void ProgressPattern::UpdateGradientColor(const NG::Gradient& gradient, bool isFirstLoad)
886 {
887 auto host = GetHost();
888 CHECK_NULL_VOID(host);
889 auto paintProperty = host->GetPaintProperty<ProgressPaintProperty>();
890 CHECK_NULL_VOID(paintProperty);
891 auto pipelineContext = host->GetContext();
892 CHECK_NULL_VOID(pipelineContext);
893 if (isFirstLoad || pipelineContext->IsSystmColorChange()) {
894 paintProperty->UpdateGradientColor(gradient);
895 }
896 if (host->GetRerenderable()) {
897 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
898 }
899 }
900
OnColorModeChange(uint32_t colorMode)901 void ProgressPattern::OnColorModeChange(uint32_t colorMode)
902 {
903 Pattern::OnColorModeChange(colorMode);
904 auto host = GetHost();
905 CHECK_NULL_VOID(host);
906 auto pipelineContext = host->GetContext();
907 CHECK_NULL_VOID(pipelineContext);
908 if (host->GetRerenderable()) {
909 host->MarkModifyDone();
910 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
911 }
912 }
913
OnColorConfigurationUpdate()914 void ProgressPattern::OnColorConfigurationUpdate()
915 {
916 if (!SystemProperties::ConfigChangePerform()) {
917 return;
918 }
919 auto host = GetHost();
920 CHECK_NULL_VOID(host);
921 auto pipeline = host->GetContext();
922 CHECK_NULL_VOID(pipeline);
923 auto theme = pipeline->GetTheme<ProgressTheme>();
924 CHECK_NULL_VOID(theme);
925 auto pops = host->GetPaintProperty<ProgressPaintProperty>();
926 CHECK_NULL_VOID(pops);
927 const auto& type = pops->GetProgressType();
928 if (!pops->GetGradientColorSetByUserValue(false)) {
929 Color colorVal;
930 Color endColor;
931 Color beginColor;
932 NG::Gradient gradient;
933 endColor = theme->GetRingProgressEndSideColor();
934 beginColor = theme->GetRingProgressBeginSideColor();
935 colorVal = (type == ProgressType::CAPSULE) ? theme->GetCapsuleParseFailedSelectColor()
936 : theme->GetTrackParseFailedSelectedColor();
937 NG::GradientColor endSideColor;
938 NG::GradientColor beginSideColor;
939 endSideColor.SetLinearColor(LinearColor(endColor));
940 endSideColor.SetDimension(Dimension(0.0f));
941 beginSideColor.SetLinearColor(LinearColor(beginColor));
942 beginSideColor.SetDimension(Dimension(1.0f));
943 gradient.AddColor(endSideColor);
944 gradient.AddColor(beginSideColor);
945 pops->UpdateGradientColor(gradient);
946 pops->UpdateColor(colorVal);
947 }
948 if (pops->GetCapsuleStyleSetByUserValue(false) && !pops->GetCapsuleStyleFontColorSetByUserValue(false)) {
949 auto textHost = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(0));
950 CHECK_NULL_VOID(textHost);
951 auto textLayoutProperty = textHost->GetLayoutProperty<TextLayoutProperty>();
952 CHECK_NULL_VOID(textLayoutProperty);
953 textLayoutProperty->UpdateTextColor(theme->GetTextColor());
954 textHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
955 pops->UpdateTextColor(theme->GetTextColor());
956 }
957 }
958 } // namespace OHOS::Ace::NG
959