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