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