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