1 /*
2 * Copyright (c) 2022 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_layout_algorithm.h"
17
18 #include <algorithm>
19
20 #include "base/geometry/dimension.h"
21 #include "base/log/log_wrapper.h"
22 #include "base/utils/utils.h"
23 #include "core/components/common/properties/color.h"
24 #include "core/components/progress/progress_component.h"
25 #include "core/components/progress/progress_theme.h"
26 #include "core/components_ng/pattern/progress/progress_date.h"
27 #include "core/components_ng/pattern/progress/progress_layout_property.h"
28 #include "core/components_ng/pattern/progress/progress_paint_property.h"
29 #include "core/components_ng/pattern/progress/progress_pattern.h"
30 #include "core/components_ng/pattern/text/text_layout_property.h"
31 #include "core/components_ng/pattern/text/text_pattern.h"
32 #include "core/components_ng/property/measure_property.h"
33 #include "core/pipeline/pipeline_base.h"
34
35 namespace OHOS::Ace::NG {
36 namespace {
37 const Dimension DEFALT_RING_DIAMETER = 72.0_vp;
38 const Dimension DEFALT_CAPSULE_WIDTH = 28.0_vp;
39 } // namespace
40 ProgressLayoutAlgorithm::ProgressLayoutAlgorithm() = default;
41
MeasureContent(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)42 std::optional<SizeF> ProgressLayoutAlgorithm::MeasureContent(
43 const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
44 {
45 auto host = layoutWrapper->GetHostNode();
46 CHECK_NULL_RETURN(host, std::nullopt);
47 auto pattern = host->GetPattern<ProgressPattern>();
48 CHECK_NULL_RETURN(pattern, std::nullopt);
49 if (pattern->UseContentModifier()) {
50 host->GetGeometryNode()->Reset();
51 return std::nullopt;
52 }
53 auto pipeline = PipelineBase::GetCurrentContext();
54 CHECK_NULL_RETURN(pipeline, std::nullopt);
55 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
56 return MeasureContentForApiNine(contentConstraint, layoutWrapper);
57 }
58 auto progressTheme = pipeline->GetTheme<ProgressTheme>();
59 auto progressLayoutProperty = DynamicCast<ProgressLayoutProperty>(layoutWrapper->GetLayoutProperty());
60 CHECK_NULL_RETURN(progressLayoutProperty, std::nullopt);
61 type_ = progressLayoutProperty->GetType().value_or(ProgressType::LINEAR);
62 strokeWidth_ = progressLayoutProperty->GetStrokeWidth().
63 value_or(progressTheme ? progressTheme->GetTrackThickness() : Dimension(strokeWidth_)).
64 ConvertToPx();
65 float diameter =
66 progressTheme ? progressTheme->GetRingDiameter().ConvertToPx() : DEFALT_RING_DIAMETER.ConvertToPx();
67 auto selfIdealWidth = contentConstraint.selfIdealSize.Width();
68 auto selfIdealHeight = contentConstraint.selfIdealSize.Height();
69 float width_ = selfIdealWidth.value_or(contentConstraint.percentReference.Width());
70 float height_ = selfIdealHeight.value_or(strokeWidth_);
71 if (type_ == ProgressType::RING || type_ == ProgressType::SCALE || type_ == ProgressType::MOON) {
72 if (!selfIdealHeight) {
73 if (!selfIdealWidth) {
74 width_ = diameter;
75 }
76 height_ = width_;
77 } else {
78 if (selfIdealWidth) {
79 height_ = std::min(width_, height_);
80 }
81 width_ = height_;
82 }
83 } else if (type_ == ProgressType::CAPSULE) {
84 if (!selfIdealWidth) {
85 width_ = contentConstraint.percentReference.Width();
86 }
87 if (!selfIdealHeight) {
88 height_ = contentConstraint.parentIdealSize.Height().value_or(GetChildHeight(layoutWrapper, width_));
89 }
90 } else if (type_ == ProgressType::LINEAR) {
91 if (width_ >= height_) {
92 height_ = std::min(height_, strokeWidth_);
93 } else {
94 width_ = std::min(width_, strokeWidth_);
95 }
96 }
97 return SizeF(width_, height_);
98 }
99
MeasureContentForApiNine(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)100 std::optional<SizeF> ProgressLayoutAlgorithm::MeasureContentForApiNine(
101 const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
102 {
103 auto pipeline = PipelineBase::GetCurrentContext();
104 CHECK_NULL_RETURN(pipeline, std::nullopt);
105 auto progressTheme = pipeline->GetTheme<ProgressTheme>();
106 auto progressLayoutProperty = DynamicCast<ProgressLayoutProperty>(layoutWrapper->GetLayoutProperty());
107 CHECK_NULL_RETURN(progressLayoutProperty, std::nullopt);
108 type_ = progressLayoutProperty->GetType().value_or(ProgressType::LINEAR);
109 strokeWidth_ = progressLayoutProperty->GetStrokeWidth().
110 value_or(progressTheme ? (type_ == ProgressType::SCALE ? progressTheme->GetScaleLength() :
111 progressTheme->GetTrackThickness()): Dimension(strokeWidth_)).ConvertToPx();
112 float diameter =
113 progressTheme ? progressTheme->GetRingDiameter().ConvertToPx() : DEFALT_RING_DIAMETER.ConvertToPx();
114 float width_ = progressTheme ? progressTheme->GetTrackWidth().ConvertToPx() : contentConstraint.maxSize.Width();
115 auto selfIdealWidth = contentConstraint.selfIdealSize.Width();
116 auto selfIdealHeight = contentConstraint.selfIdealSize.Height();
117 if (selfIdealWidth) {
118 width_ = selfIdealWidth.value();
119 }
120 float height_ = strokeWidth_ * 2.0f;
121 if (selfIdealHeight) {
122 height_ = selfIdealHeight.value();
123 }
124 if (type_ == ProgressType::RING || type_ == ProgressType::SCALE || type_ == ProgressType::MOON) {
125 if (!selfIdealWidth && !selfIdealHeight) {
126 width_ = diameter;
127 height_ = width_;
128 } else if (selfIdealWidth && !selfIdealHeight) {
129 height_ = width_;
130 } else if (selfIdealHeight && !selfIdealWidth) {
131 width_ = height_;
132 }
133 } else if (type_ == ProgressType::CAPSULE) {
134 if (!selfIdealHeight) {
135 height_ = diameter;
136 }
137 if (!selfIdealWidth) {
138 width_ = diameter;
139 }
140 }
141 height_ = std::min(height_, static_cast<float>(contentConstraint.maxSize.Height()));
142 width_ = std::min(width_, static_cast<float>(contentConstraint.maxSize.Width()));
143 if (type_ == ProgressType::LINEAR) {
144 strokeWidth_ = std::min(strokeWidth_, height_ / 2.0f);
145 strokeWidth_ = std::min(strokeWidth_, width_ / 2.0f);
146 }
147 return SizeF(width_, height_);
148 }
149
GetType() const150 ProgressType ProgressLayoutAlgorithm::GetType() const
151 {
152 return type_;
153 }
154
GetStrokeWidth() const155 float ProgressLayoutAlgorithm::GetStrokeWidth() const
156 {
157 return strokeWidth_;
158 }
159
GetChildHeight(LayoutWrapper * layoutWrapper,float width) const160 float ProgressLayoutAlgorithm::GetChildHeight(LayoutWrapper* layoutWrapper, float width) const
161 {
162 auto host = layoutWrapper->GetHostNode();
163 CHECK_NULL_RETURN(host, DEFALT_CAPSULE_WIDTH.ConvertToPx());
164 auto paintProperty = host->GetPaintProperty<ProgressPaintProperty>();
165 CHECK_NULL_RETURN(paintProperty, DEFALT_CAPSULE_WIDTH.ConvertToPx());
166 auto pipeline = PipelineBase::GetCurrentContext();
167 CHECK_NULL_RETURN(pipeline, DEFALT_CAPSULE_WIDTH.ConvertToPx());
168 auto progressTheme = pipeline->GetTheme<ProgressTheme>();
169 Dimension margin = progressTheme->GetTextMargin();
170 auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(0);
171 CHECK_NULL_RETURN(childWrapper, DEFALT_CAPSULE_WIDTH.ConvertToPx());
172 auto layoutProperty = AceType::DynamicCast<ProgressLayoutProperty>(layoutWrapper->GetLayoutProperty());
173 CHECK_NULL_RETURN(layoutProperty, DEFALT_CAPSULE_WIDTH.ConvertToPx());
174
175 auto childLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(childWrapper->GetLayoutProperty());
176 CHECK_NULL_RETURN(childLayoutProperty, DEFALT_CAPSULE_WIDTH.ConvertToPx());
177 auto childConstraint = layoutProperty->CreateChildConstraint();
178 childConstraint.maxSize.SetWidth(width);
179 childWrapper->Measure(childConstraint);
180 auto childSize = childWrapper->GetGeometryNode()->GetContentSize();
181 if (childSize.Width() > (width - 2 * margin.ConvertToPx())) {
182 CalcSize defaultCalcSize((CalcLength(width - 2 * margin.ConvertToPx())), std::nullopt);
183 childLayoutProperty->UpdateUserDefinedIdealSize(defaultCalcSize);
184 } else {
185 CalcSize defaultCalcSize((CalcLength(childSize.Width())), std::nullopt);
186 childLayoutProperty->UpdateUserDefinedIdealSize(defaultCalcSize);
187 }
188 float childHeight =
189 paintProperty->GetTextSize().value_or(progressTheme->GetTextSize()).ConvertToPx() + 2 * margin.ConvertToPx();
190
191 auto fontScale = pipeline->GetFontScale();
192 if (GreatOrEqualCustomPrecision(fontScale, progressTheme->GetFontScale()) && (GetType() == ProgressType::CAPSULE)) {
193 const auto& paddingProperty = layoutProperty->GetPaddingProperty();
194 if (!(paddingProperty &&
195 ((paddingProperty->top != std::nullopt) || (paddingProperty->bottom != std::nullopt)))) {
196 childHeight = childHeight + (progressTheme->GetfontScalePadding()).ConvertToPx();
197 }
198 }
199
200 return childHeight;
201 }
202 } // namespace OHOS::Ace::NG
203