1 /*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "core/components_ng/pattern/gauge/gauge_pattern.h"
16
17 #include "core/components_ng/layout/layout_wrapper.h"
18 #include "core/components_ng/pattern/gauge/gauge_layout_algorithm.h"
19 #include "core/components_ng/pattern/gauge/gauge_theme.h"
20 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
21 #include "core/components_ng/pattern/text/text_layout_property.h"
22 #include "core/components_ng/pattern/text/text_pattern.h"
23
24 namespace OHOS::Ace::NG {
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,bool skipMeasure,bool)25 bool GaugePattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, bool skipMeasure, bool /*skipLayout*/)
26 {
27 if (skipMeasure || dirty->SkipMeasureContent()) {
28 return false;
29 }
30 return true;
31 }
32
OnModifyDone()33 void GaugePattern::OnModifyDone()
34 {
35 Pattern::OnModifyDone();
36 FireBuilder();
37 auto host = GetHost();
38 CHECK_NULL_VOID(host);
39
40 auto layoutProperty = host->GetLayoutProperty();
41 CHECK_NULL_VOID(layoutProperty);
42 if (layoutProperty->GetPositionProperty()) {
43 layoutProperty->UpdateAlignment(
44 layoutProperty->GetPositionProperty()->GetAlignment().value_or(Alignment::CENTER));
45 } else {
46 layoutProperty->UpdateAlignment(Alignment::CENTER);
47 }
48
49 if (!Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
50 InitTitleContent();
51 auto gaugePaintProperty = GetPaintProperty<GaugePaintProperty>();
52 CHECK_NULL_VOID(gaugePaintProperty);
53 if (gaugePaintProperty->GetIsShowIndicatorValue(false) && gaugePaintProperty->HasIndicatorIconSourceInfo()) {
54 InitIndicatorImage();
55 }
56
57 auto gaugeLayoutProperty = GetLayoutProperty<GaugeLayoutProperty>();
58 CHECK_NULL_VOID(gaugeLayoutProperty);
59
60 if (gaugeLayoutProperty->GetIsShowLimitValueValue(false) && gaugePaintProperty->HasGradientColors() &&
61 gaugePaintProperty->GetGradientColorsValue().size() != 0) {
62 InitLimitValueText(GetMinValueTextId(), true);
63 InitLimitValueText(GetMaxValueTextId(), false);
64 } else {
65 if (minValueTextId_.has_value()) {
66 HideLimitValueText(GetMinValueTextId(), true);
67 }
68 if (maxValueTextId_.has_value()) {
69 HideLimitValueText(GetMaxValueTextId(), false);
70 }
71 }
72 if (gaugeLayoutProperty->GetIsShowDescriptionValue(false)) {
73 InitDescriptionNode();
74 }
75 }
76 }
77
FireBuilder()78 void GaugePattern::FireBuilder()
79 {
80 auto host = GetHost();
81 CHECK_NULL_VOID(host);
82 if (!makeFunc_.has_value()) {
83 host->RemoveChildAndReturnIndex(contentModifierNode_);
84 contentModifierNode_ = nullptr;
85 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
86 return;
87 }
88 auto node = BuildContentModifierNode();
89 if (contentModifierNode_ == node) {
90 return;
91 }
92 auto renderContext = host->GetRenderContext();
93 CHECK_NULL_VOID(renderContext);
94 host->RemoveChildAndReturnIndex(contentModifierNode_);
95 contentModifierNode_ = node;
96 CHECK_NULL_VOID(contentModifierNode_);
97 host->AddChild(contentModifierNode_, 0);
98 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
99 }
100
BuildContentModifierNode()101 RefPtr<FrameNode> GaugePattern::BuildContentModifierNode()
102 {
103 if (!makeFunc_.has_value()) {
104 return nullptr;
105 }
106 CHECK_NULL_RETURN(makeFunc_, nullptr);
107 auto host = GetHost();
108 CHECK_NULL_RETURN(host, nullptr);
109 auto gaugePaintProperty = GetPaintProperty<GaugePaintProperty>();
110 CHECK_NULL_RETURN(gaugePaintProperty, nullptr);
111 auto min = gaugePaintProperty->GetMin().value_or(0.0f);
112 auto max = gaugePaintProperty->GetMax().value_or(100.0f);
113 auto value = gaugePaintProperty->GetValue().value_or(min);
114 auto eventHub = host->GetEventHub<EventHub>();
115 CHECK_NULL_RETURN(eventHub, nullptr);
116 auto enabled = eventHub->IsEnabled();
117 GaugeConfiguration gaugeConfiguration(value, min, max, enabled);
118 return (makeFunc_.value())(gaugeConfiguration);
119 }
120
InitTitleContent()121 void GaugePattern::InitTitleContent()
122 {
123 auto host = GetHost();
124 CHECK_NULL_VOID(host);
125 if ((host->TotalChildCount() > 0) && (!titleChildId_.has_value())) {
126 auto firstChild = host->GetFirstChild();
127 CHECK_NULL_VOID(firstChild);
128 if (firstChild->GetTag() == V2::GAUGE_DESCRIPTION_TAG) {
129 return;
130 }
131
132 if (minValueTextId_.has_value() && (firstChild->GetId() == minValueTextId_.value())) {
133 return;
134 }
135
136 titleChildId_ = firstChild->GetId();
137 }
138 }
139
InitDescriptionNode()140 void GaugePattern::InitDescriptionNode()
141 {
142 auto frameNode = GetHost();
143 CHECK_NULL_VOID(frameNode);
144 auto linearNode = FrameNode::GetOrCreateFrameNode(V2::GAUGE_DESCRIPTION_TAG, GetDescriptionNodeId(),
145 []() { return AceType::MakeRefPtr<LinearLayoutPattern>(true); });
146 CHECK_NULL_VOID(linearNode);
147 linearNode->Clean();
148 auto descriptionRenderContext = linearNode->GetRenderContext();
149 CHECK_NULL_VOID(descriptionRenderContext);
150 descriptionRenderContext->UpdateClipEdge(true);
151 CHECK_NULL_VOID(descriptionNode_);
152 descriptionNode_->MountToParent(linearNode);
153 auto property = linearNode->GetLayoutProperty<LinearLayoutProperty>();
154 CHECK_NULL_VOID(property);
155
156 linearNode->MountToParent(frameNode);
157 linearNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
158 linearNode->MarkModifyDone();
159 }
160
InitLimitValueText(int32_t valueTextId,bool isMin)161 void GaugePattern::InitLimitValueText(int32_t valueTextId, bool isMin)
162 {
163 auto frameNode = GetHost();
164 CHECK_NULL_VOID(frameNode);
165 auto gaugePaintProperty = GetPaintProperty<GaugePaintProperty>();
166 CHECK_NULL_VOID(gaugePaintProperty);
167 auto textNode = FrameNode::GetOrCreateFrameNode(
168 V2::TEXT_ETS_TAG, valueTextId, []() { return AceType::MakeRefPtr<TextPattern>(); });
169 CHECK_NULL_VOID(textNode);
170
171 auto limitValue =
172 isMin ? gaugePaintProperty->GetMinValue(DEFAULT_MIN_VALUE) : gaugePaintProperty->GetMaxValue(DEFAULT_MAX_VALUE);
173 auto limitValueColor = Color::BLACK;
174 if (gaugePaintProperty->HasGradientColors()) {
175 limitValueColor = isMin ? gaugePaintProperty->GetGradientColorsValue().at(0).at(0).first
176 : GetMaxValueColor(gaugePaintProperty);
177 } else {
178 limitValueColor = isMin ? (*GAUGE_DEFAULT_COLOR.begin()) : (*GAUGE_DEFAULT_COLOR.rbegin());
179 }
180 std::ostringstream out;
181 out << std::setiosflags(std::ios::fixed) << std::setprecision(0) << limitValue;
182
183 auto pipelineContext = PipelineBase::GetCurrentContext();
184 CHECK_NULL_VOID(pipelineContext);
185 auto theme = pipelineContext->GetTheme<GaugeTheme>();
186
187 auto limitValueTextProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
188 CHECK_NULL_VOID(limitValueTextProperty);
189 limitValueTextProperty->UpdateContent(out.str());
190 limitValueTextProperty->UpdateTextColor(limitValueColor);
191 limitValueTextProperty->UpdateMaxLines(1);
192 limitValueTextProperty->UpdateAdaptMaxFontSize(LIMIT_VALUE_MAX_FONTSIZE);
193 limitValueTextProperty->UpdateAdaptMinFontSize(theme->GetLimitValueMinFontSize());
194 limitValueTextProperty->UpdateFontWeight(FontWeight::MEDIUM);
195 limitValueTextProperty->UpdateTextOverflow(TextOverflow::ELLIPSIS);
196 auto textAlign = isMin ? TextAlign::LEFT : TextAlign::RIGHT;
197 limitValueTextProperty->UpdateTextAlign(textAlign);
198
199 textNode->MountToParent(frameNode);
200 textNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
201 textNode->MarkModifyDone();
202 }
203
HideLimitValueText(int32_t valueTextId,bool isMin)204 void GaugePattern::HideLimitValueText(int32_t valueTextId, bool isMin)
205 {
206 auto frameNode = GetHost();
207 CHECK_NULL_VOID(frameNode);
208 auto textNode = FrameNode::GetOrCreateFrameNode(
209 V2::TEXT_ETS_TAG, valueTextId, []() { return AceType::MakeRefPtr<TextPattern>(); });
210 CHECK_NULL_VOID(textNode);
211 auto geometryNode = textNode->GetGeometryNode();
212 CHECK_NULL_VOID(geometryNode);
213 geometryNode->SetFrameSize(SizeF(0, 0));
214 auto limitValueTextProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
215 CHECK_NULL_VOID(limitValueTextProperty);
216 limitValueTextProperty->Reset();
217 textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
218 textNode->MarkModifyDone();
219 }
220
GetMaxValueColor(const RefPtr<GaugePaintProperty> & gaugePaintProperty) const221 Color GaugePattern::GetMaxValueColor(const RefPtr<GaugePaintProperty>& gaugePaintProperty) const
222 {
223 Color color(Color::BLACK);
224 CHECK_NULL_RETURN(gaugePaintProperty, color);
225 switch (gaugePaintProperty->GetGaugeTypeValue(GaugeType::TYPE_CIRCULAR_SINGLE_SEGMENT_GRADIENT)) {
226 case GaugeType::TYPE_CIRCULAR_MULTI_SEGMENT_GRADIENT: {
227 color = gaugePaintProperty->GetGradientColorsValue().rbegin()->rbegin()->first;
228 break;
229 }
230 case GaugeType::TYPE_CIRCULAR_SINGLE_SEGMENT_GRADIENT: {
231 color = gaugePaintProperty->GetGradientColorsValue().at(0).rbegin()->first;
232 break;
233 }
234 case GaugeType::TYPE_CIRCULAR_MONOCHROME: {
235 color = gaugePaintProperty->GetGradientColorsValue().at(0).at(0).first;
236 break;
237 }
238 default:
239 // do nothing.
240 break;
241 }
242 return color;
243 }
244
InitIndicatorImage()245 void GaugePattern::InitIndicatorImage()
246 {
247 auto gaugePaintProperty = GetPaintProperty<GaugePaintProperty>();
248 CHECK_NULL_VOID(gaugePaintProperty);
249
250 ImageSourceInfo sourceInfo = gaugePaintProperty->GetIndicatorIconSourceInfo().value_or(ImageSourceInfo(""));
251 LoadNotifier iconLoadNotifier(CreateDataReadyCallback(), CreateLoadSuccessCallback(), CreateLoadFailCallback());
252 indicatorIconLoadingCtx_ = AceType::MakeRefPtr<ImageLoadingContext>(sourceInfo, std::move(iconLoadNotifier), true);
253 indicatorIconLoadingCtx_->LoadImageData();
254 }
255
CreateLoadSuccessCallback()256 LoadSuccessNotifyTask GaugePattern::CreateLoadSuccessCallback()
257 {
258 auto task = [weak = WeakClaim(this)](const ImageSourceInfo& /* sourceInfo */) {
259 auto pattern = weak.Upgrade();
260 CHECK_NULL_VOID(pattern);
261 pattern->OnImageLoadSuccess();
262 };
263 return task;
264 }
265
CreateDataReadyCallback()266 DataReadyNotifyTask GaugePattern::CreateDataReadyCallback()
267 {
268 auto task = [weak = WeakClaim(this)](const ImageSourceInfo& /* sourceInfo */) {
269 auto pattern = weak.Upgrade();
270 CHECK_NULL_VOID(pattern);
271 pattern->OnImageDataReady();
272 };
273 return task;
274 }
275
CreateLoadFailCallback()276 LoadFailNotifyTask GaugePattern::CreateLoadFailCallback()
277 {
278 auto task = [weak = WeakClaim(this)](const ImageSourceInfo& /* sourceInfo */, const std::string& msg) {
279 auto pattern = weak.Upgrade();
280 CHECK_NULL_VOID(pattern);
281 pattern->OnImageLoadFail();
282 };
283 return task;
284 }
285
OnImageLoadFail()286 void GaugePattern::OnImageLoadFail()
287 {
288 auto gaugePaintProperty = GetPaintProperty<GaugePaintProperty>();
289 CHECK_NULL_VOID(gaugePaintProperty);
290 gaugePaintProperty->ResetIndicatorIconSourceInfo();
291 }
292
OnImageDataReady()293 void GaugePattern::OnImageDataReady()
294 {
295 auto host = GetHost();
296 CHECK_NULL_VOID(host);
297 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
298 }
299
OnImageLoadSuccess()300 void GaugePattern::OnImageLoadSuccess()
301 {
302 auto host = GetHost();
303 CHECK_NULL_VOID(host);
304 host->MarkNeedRenderOnly();
305
306 ImagePaintConfig config;
307 config.isSvg_ = indicatorIconLoadingCtx_->GetSourceInfo().IsSvg();
308 if (!config.isSvg_) {
309 auto gaugePaintProperty = GetPaintProperty<GaugePaintProperty>();
310 CHECK_NULL_VOID(gaugePaintProperty);
311 gaugePaintProperty->ResetIndicatorIconSourceInfo();
312 return;
313 }
314 config.srcRect_ = indicatorIconLoadingCtx_->GetSrcRect();
315 config.dstRect_ = indicatorIconLoadingCtx_->GetDstRect();
316 indicatorIconCanvasImage_ = indicatorIconLoadingCtx_->MoveCanvasImage();
317 indicatorIconCanvasImage_->SetPaintConfig(config);
318 }
319
ObscureLimitValueText(bool isSensitive)320 void GaugePattern::ObscureLimitValueText(bool isSensitive)
321 {
322 if (minValueTextId_.has_value()) {
323 ObscureText(GetMinValueTextId(), isSensitive);
324 }
325 if (maxValueTextId_.has_value()) {
326 ObscureText(GetMaxValueTextId(), isSensitive);
327 }
328 }
329
ObscureText(int32_t valueTextId,bool isSensitive)330 void GaugePattern::ObscureText(int32_t valueTextId, bool isSensitive)
331 {
332 auto textNode = FrameNode::GetFrameNode(V2::TEXT_ETS_TAG, valueTextId);
333 CHECK_NULL_VOID(textNode);
334 auto textPattern = textNode->GetPattern<TextPattern>();
335 CHECK_NULL_VOID(textPattern);
336 textPattern->OnSensitiveStyleChange(isSensitive);
337 textNode->SetPrivacySensitive(isSensitive);
338 textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
339 }
340
OnSensitiveStyleChange(bool isSensitive)341 void GaugePattern::OnSensitiveStyleChange(bool isSensitive)
342 {
343 ObscureLimitValueText(isSensitive);
344 auto frameNode = GetHost();
345 CHECK_NULL_VOID(frameNode);
346 auto gaugePaintProperty = frameNode->GetPaintProperty<NG::GaugePaintProperty>();
347 CHECK_NULL_VOID(gaugePaintProperty);
348 gaugePaintProperty->UpdateIsSensitive(isSensitive);
349 frameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
350 }
351 } // namespace OHOS::Ace::NG
352