1 /*
2 * Copyright (c) 2021-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 "frameworks/bridge/common/dom/dom_progress.h"
17
18 #include "base/utils/utils.h"
19 #include "core/components/common/properties/decoration.h"
20 #include "core/components/progress/progress_theme.h"
21 #include "core/components/theme/theme_manager.h"
22 #include "frameworks/bridge/common/utils/utils.h"
23
24 namespace OHOS::Ace::Framework {
25
26
IsGradient(const std::string & value)27 bool IsGradient(const std::string& value)
28 {
29 auto gradientJson = JsonUtil::ParseJsonString(value);
30 if (!gradientJson->IsObject()) {
31 return false;
32 }
33 return true;
34 }
35
ParseGradient(const DOMProgress & progress,const std::string & value)36 Gradient ParseGradient(const DOMProgress& progress, const std::string& value)
37 {
38 // only support linear gradient
39 auto gradientJson = JsonUtil::ParseJsonString(value);
40 Gradient gradient = Gradient();
41 if (!gradientJson->IsObject()) {
42 LOGW("gradientJson json param error");
43 return gradient;
44 }
45 auto gradientValue = gradientJson->GetValue(DOM_VALUES);
46 if ((gradientValue == nullptr) || (!gradientValue->IsArray()) || (gradientValue->GetArraySize() <= 0)) {
47 LOGW("gradientValue json param error");
48 return gradient;
49 }
50 auto values = gradientValue->GetArrayItem(0);
51 gradient.SetDirection(GradientDirection::START_TO_END);
52 auto colors = values->GetValue(DOM_GRADIENT_VALUES);
53 if (colors != nullptr && colors->IsArray()) {
54 for (int32_t index = 0; index < colors->GetArraySize(); index++) {
55 // remove the " at front and end. check the color string longer than ""
56 // "#FFFFFF" -> #FFFFFF
57 if (colors->GetArrayItem(index)->ToString().length() > 2) {
58 gradient.AddColor(GradientColor(progress.ParseColor(colors->GetArrayItem(index)->ToString().substr(
59 1, colors->GetArrayItem(index)->ToString().length() - 2))));
60 }
61 }
62 }
63 return gradient;
64 }
65
CreateProgressComponent(double min,double percent,double cachedValue,double max,ProgressType type)66 RefPtr<ProgressComponent> DOMProgress::CreateProgressComponent(
67 double min, double percent, double cachedValue, double max, ProgressType type)
68 {
69 if (type == ProgressType::CIRCLE) {
70 return AceType::MakeRefPtr<ProgressComponent>(min, percent, cachedValue, max, ProgressType::LINEAR);
71 }
72 return AceType::MakeRefPtr<ProgressComponent>(min, percent, cachedValue, max, type);
73 }
74
DOMProgress(NodeId nodeId,const std::string & nodeName)75 DOMProgress::DOMProgress(NodeId nodeId, const std::string& nodeName) : DOMNode(nodeId, nodeName) {}
76
SetSpecializedAttr(const std::pair<std::string,std::string> & attr)77 bool DOMProgress::SetSpecializedAttr(const std::pair<std::string, std::string>& attr)
78 {
79 static const LinearMapNode<void (*)(const std::string&, DOMProgress&)> progressAttrsOperators[] = {
80 { DOM_RING_CLOCKWISH_DIRECTION,
81 [](const std::string& val, DOMProgress& progress) { progress.clockwiseDirection_ = StringToBool(val); } },
82 { DOM_EFFECTS_ON,
83 [](const std::string& val, DOMProgress& progress) { progress.showAnimationEffect_ = StringToBool(val); } },
84 { DOM_PROGRESS_PERCENT,
85 [](const std::string& val, DOMProgress& progress) {
86 progress.percent_ = StringToDouble(val);
87 if (progress.percent_ > progress.max_) {
88 progress.percent_ = progress.max_;
89 }
90 if (progress.percent_ < progress.min_) {
91 progress.percent_ = progress.min_;
92 }
93 } },
94 { DOM_PROGRESS_SECONDARY_PERCENT,
95 [](const std::string& val, DOMProgress& progress) {
96 progress.cachedValue_ = StringToDouble(val);
97 if (progress.cachedValue_ > progress.max_) {
98 progress.cachedValue_ = progress.max_;
99 }
100 if (progress.cachedValue_ < progress.min_) {
101 progress.cachedValue_ = progress.min_;
102 }
103 } },
104 { DOM_PROGRESS_TYPE,
105 [](const std::string& val, DOMProgress& progress) {
106 if (val == DOM_PROGRESS_TYPE_CIRCULAR) {
107 progress.type_ = ProgressType::CIRCLE;
108 } else if (val == DOM_PROGRESS_TYPE_RING) {
109 progress.type_ = ProgressType::RING;
110 } else if (val == DOM_PROGRESS_TYPE_HORIZONTAL) {
111 progress.type_ = ProgressType::LINEAR;
112 } else if (val == DOM_PROGRESS_TYPE_SCALE) {
113 progress.type_ = ProgressType::SCALE;
114 } else if (val == DOM_PROGRESS_TYPE_MOON) {
115 progress.type_ = ProgressType::MOON;
116 } else if ((val == DOM_PROGRESS_TYPE_ARC)) {
117 progress.type_ = ProgressType::ARC;
118 } else if ((val == DOM_PROGRESS_TYPE_BUBBLE)) {
119 progress.type_ = ProgressType::BUBBLE;
120 } else {
121 progress.type_ = ProgressType::LINEAR;
122 }
123 } },
124 };
125 auto operatorIter =
126 BinarySearchFindIndex(progressAttrsOperators, ArraySize(progressAttrsOperators), attr.first.c_str());
127 if (operatorIter != -1) {
128 progressAttrsOperators[operatorIter].value(attr.second, *this);
129 return true;
130 }
131 return false;
132 }
133
SetSpecializedStyle(const std::pair<std::string,std::string> & style)134 bool DOMProgress::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
135 {
136 // static linear map must be sorted by key.
137 static const LinearMapNode<void (*)(const std::string&, DOMProgress&)> progressStylesOperators[] = {
138 { DOM_PROGRESS_BACKGROUND_COLOR,
139 [](const std::string& val, DOMProgress& progress) {
140 progress.backgroundColor_.first = progress.ParseColor(val);
141 progress.backgroundColor_.second = true;
142 } },
143 { DOM_PROGRESS_BUBBLE_RADIUS,
144 [](const std::string& val, DOMProgress& progress) {
145 progress.diameter_ = progress.ParseDimension(val);
146 } },
147 { DOM_CENTER_X,
148 [](const std::string& val, DOMProgress& progress) {
149 progress.centerX_.first = StringToDouble(val);
150 progress.centerX_.second = true;
151 } },
152 { DOM_CENTER_Y,
153 [](const std::string& val, DOMProgress& progress) {
154 progress.centerY_.first = StringToDouble(val);
155 progress.centerY_.second = true;
156 } },
157 { DOM_PROGRESS_COLOR,
158 [](const std::string& val, DOMProgress& progress) {
159 if (IsGradient(val)) {
160 progress.gradient_ = ParseGradient(progress, val);
161 } else {
162 progress.color_.first = progress.ParseColor(val);
163 progress.color_.second = true;
164 }
165 } },
166 { DOM_PROGRESS_DIAMETER,
167 [](const std::string& val, DOMProgress& progress) {
168 progress.bubbleRadius_ = progress.ParseDimension(val);
169 } },
170 { DOM_DIRECTION,
171 [](const std::string& val, DOMProgress& progress) { progress.isStartToEnd_ = val == DOM_START_TO_END; } },
172 { DOM_PROGRESS_RADIUS,
173 [](const std::string& val, DOMProgress& progress) {
174 progress.radius_.first = StringToDouble(val);
175 progress.radius_.second = true;
176 } },
177 { DOM_SCALE_NUMBER,
178 [](const std::string& val, DOMProgress& progress) {
179 progress.scaleNumber_.first = StringUtils::StringToInt(val);
180 progress.scaleNumber_.second = true;
181 } },
182 { DOM_SCALE_WIDTH,
183 [](const std::string& val, DOMProgress& progress) {
184 progress.scaleWidth_.first = progress.ParseDimension(val);
185 progress.scaleWidth_.second = true;
186 } },
187 { DOM_PROGRESS_SECONDARY_COLOR,
188 [](const std::string& val, DOMProgress& progress) {
189 progress.cachedColor_.first = progress.ParseColor(val);
190 progress.cachedColor_.second = true;
191 } },
192 { DOM_START_DEGREE,
193 [](const std::string& val, DOMProgress& progress) { progress.startDegree_ = StringToDouble(val); } },
194 { DOM_PROGRESS_STROKE_WIDTH,
195 [](const std::string& val, DOMProgress& progress) {
196 progress.strokeWidth_.first = progress.ParseDimension(val);
197 progress.strokeWidth_.second = true;
198 } },
199 { DOM_SWEEP_DEGREE,
200 [](const std::string& val, DOMProgress& progress) { progress.sweepDegree_ = StringToDouble(val); } },
201 };
202 auto operatorIter =
203 BinarySearchFindIndex(progressStylesOperators, ArraySize(progressStylesOperators), style.first.c_str());
204 if (operatorIter != -1) {
205 progressStylesOperators[operatorIter].value(style.second, *this);
206 return true;
207 }
208 return false;
209 }
210
PrepareSpecializedComponent()211 void DOMProgress::PrepareSpecializedComponent()
212 {
213 InitProgressIfNeed();
214 if (type_ == ProgressType::CIRCLE) {
215 loadingProgressChild_->SetProgressColor(color_.first);
216 return;
217 }
218 if (type_ == ProgressType::BUBBLE) {
219 bubbleProgressChild_->SetBubbleRadius(bubbleRadius_);
220 bubbleProgressChild_->SetDiameter(diameter_);
221 return;
222 }
223 progressChild_->SetMaxValue(max_);
224 progressChild_->SetMinValue(min_);
225 progressChild_->SetValue(percent_);
226 progressChild_->SetCachedValue(cachedValue_);
227 progressChild_->GetTrack()->SetSelectColor(color_.first);
228 progressChild_->GetTrack()->SetCachedColor(cachedColor_.first);
229 progressChild_->GetTrack()->SetBackgroundColor(backgroundColor_.first);
230 progressChild_->GetTrack()->SetTrackThickness(strokeWidth_.first);
231 progressChild_->GetTrack()->SetShowAnimation(showAnimationEffect_);
232 progressChild_->SetAnimationPlay(showAnimationEffect_);
233 progressChild_->GetTrack()->SetTextDirection(
234 IsRightToLeft() && isStartToEnd_ ? TextDirection::RTL : TextDirection::LTR);
235 if (gradient_.IsValid()) {
236 progressChild_->GetTrack()->SetSelectGradient(gradient_);
237 }
238 if (type_ == ProgressType::RING) {
239 auto info = progressChild_->GetTrack()->GetTrackInfo();
240 info->SetClockwise(clockwiseDirection_);
241 } else if (type_ == ProgressType::SCALE) {
242 auto info = progressChild_->GetTrack()->GetTrackInfo();
243 info->SetScaleWidth(scaleWidth_.first);
244 info->SetScaleNumber(scaleNumber_.first);
245 info->SetClockwise(clockwiseDirection_);
246 } else if (type_ == ProgressType::ARC) {
247 // draw arc progress
248 progressChild_->GetTrack()->GetTrackInfo()->SetStartDegree(startDegree_);
249 progressChild_->GetTrack()->GetTrackInfo()->SetSweepDegree(sweepDegree_);
250 if (radius_.second) {
251 progressChild_->GetTrack()->SetRadius(radius_.first);
252 }
253 if (centerX_.second) {
254 progressChild_->GetTrack()->SetCenterX(centerX_.first);
255 }
256 if (centerY_.second) {
257 progressChild_->GetTrack()->SetCenterY(centerY_.first);
258 }
259 }
260 }
261
OnSetStyleFinished()262 void DOMProgress::OnSetStyleFinished()
263 {
264 // the range is from -360 to 360 degree
265 static constexpr double defaultStartDegree = -120;
266 static constexpr double defaultSweepDegree = 240;
267 if (startDegree_ > 360.0 || startDegree_ < -360.0) {
268 startDegree_ = defaultStartDegree;
269 sweepDegree_ = defaultSweepDegree;
270 return;
271 }
272 if (sweepDegree_ > 360.0 || sweepDegree_ < -360.0) {
273 startDegree_ = defaultStartDegree;
274 sweepDegree_ = defaultSweepDegree;
275 return;
276 }
277 }
278
GetSpecializedComponent()279 RefPtr<Component> DOMProgress::GetSpecializedComponent()
280 {
281 if (type_ == ProgressType::CIRCLE) {
282 return loadingProgressChild_;
283 } else if (type_ == ProgressType::BUBBLE) {
284 return bubbleProgressChild_;
285 } else {
286 return progressChild_;
287 }
288 }
289
InitProgressIfNeed()290 void DOMProgress::InitProgressIfNeed()
291 {
292 auto theme = GetTheme<ProgressTheme>();
293 if (type_ == ProgressType::CIRCLE) {
294 // Width_ and height_ in circular progress are usually the same with diameter in loading progress component.
295 // If width_ and height_ are different, choose smaller one as diameter.
296 if (!loadingProgressChild_) {
297 loadingProgressChild_ = AceType::MakeRefPtr<LoadingProgressComponent>();
298 }
299 if (theme) {
300 if (!color_.second) {
301 color_.first = theme->GetProgressColor();
302 }
303 loadingProgressChild_->SetMoveRatio(theme->GetMoveRatio());
304 loadingProgressChild_->SetRingRadius(theme->GetRingRadius());
305 loadingProgressChild_->SetOrbitRadius(theme->GetOrbitRadius());
306 loadingProgressChild_->SetCometTailLen(theme->GetCometTailLen());
307 }
308 return;
309 }
310
311 if (type_ == ProgressType::BUBBLE) {
312 if (!bubbleProgressChild_) {
313 bubbleProgressChild_ = AceType::MakeRefPtr<BubbleProgressComponent>();
314 }
315 return;
316 }
317
318 if (!progressChild_ || progressChild_->GetType() != type_) {
319 progressChild_ = CreateProgressComponent(min_, percent_, cachedValue_, max_, type_);
320 }
321 if (!theme) {
322 return;
323 }
324 if (!color_.second) {
325 color_.first = type_ == ProgressType::MOON ? theme->GetMoonFrontColor() : theme->GetTrackSelectedColor();
326 }
327 if (!backgroundColor_.second) {
328 backgroundColor_.first =
329 type_ == ProgressType::MOON ? theme->GetMoonBackgroundColor() : theme->GetTrackBgColor();
330 }
331 if (!cachedColor_.second) {
332 cachedColor_.first = theme->GetTrackCachedColor();
333 }
334 if (!strokeWidth_.second) {
335 if (type_ == ProgressType::SCALE) {
336 strokeWidth_.first = theme->GetScaleLength();
337 } else if (type_ == ProgressType::RING) {
338 strokeWidth_.first = theme->GetRingThickness();
339 } else {
340 strokeWidth_.first = theme->GetTrackThickness();
341 }
342 }
343 if (!scaleWidth_.second) {
344 scaleWidth_.first = theme->GetScaleWidth();
345 }
346 if (!scaleNumber_.second) {
347 scaleNumber_.first = theme->GetScaleNumber();
348 }
349 }
350
351 } // namespace OHOS::Ace::Framework
352