1 /*
2 * Copyright (c) 2020-2021 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 "components/ui_box_progress.h"
17 #include "draw/draw_utils.h"
18 #include "engines/gfx/gfx_engine_manager.h"
19 #include "gfx_utils/graphic_log.h"
20
21 namespace OHOS {
UIBoxProgress()22 UIBoxProgress::UIBoxProgress()
23 : progressWidth_(0), progressHeight_(0), isValidWidthSet_(false), isValidHeightSet_(false)
24 {
25 SetDirection(Direction::DIR_LEFT_TO_RIGHT);
26 }
27
DrawValidRect(BufferInfo & gfxDstBuffer,const Image * image,const Rect & rect,const Rect & invalidatedArea,const Style & style,uint16_t radius)28 void UIBoxProgress::DrawValidRect(BufferInfo& gfxDstBuffer,
29 const Image* image,
30 const Rect& rect,
31 const Rect& invalidatedArea,
32 const Style& style,
33 uint16_t radius)
34 {
35 Rect cordsTmp;
36 if ((image != nullptr) && (image->GetSrcType() != IMG_SRC_UNKNOWN)) {
37 ImageHeader header = {0};
38 image->GetHeader(header);
39
40 Rect area(rect);
41 switch (direction_) {
42 case Direction::DIR_LEFT_TO_RIGHT:
43 cordsTmp.SetPosition(area.GetLeft() - radius, area.GetTop());
44 break;
45 case Direction::DIR_TOP_TO_BOTTOM:
46 cordsTmp.SetPosition(area.GetLeft(), area.GetTop() - radius);
47 break;
48 case Direction::DIR_RIGHT_TO_LEFT:
49 cordsTmp.SetPosition(area.GetRight() + radius - header.width, area.GetTop());
50 break;
51 case Direction::DIR_BOTTOM_TO_TOP:
52 cordsTmp.SetPosition(area.GetLeft(), area.GetBottom() + radius - header.height);
53 break;
54 default:
55 GRAPHIC_LOGE("UIBoxProgress: DrawValidRect direction Err!\n");
56 break;
57 }
58 cordsTmp.SetHeight(header.height);
59 cordsTmp.SetWidth(header.width);
60 if (area.Intersect(area, invalidatedArea)) {
61 image->DrawImage(gfxDstBuffer, cordsTmp, area, style, opaScale_);
62 }
63 } else {
64 BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, rect, invalidatedArea, style, opaScale_);
65 }
66
67 if (style.lineCap_ == CapType::CAP_ROUND) {
68 DrawRoundCap(gfxDstBuffer, image, {cordsTmp.GetX(), cordsTmp.GetY()}, rect, invalidatedArea, radius, style);
69 }
70 }
71
DrawRoundCap(BufferInfo & gfxDstBuffer,const Image * image,const Point & imgPos,const Rect & rect,const Rect & invalidatedArea,uint16_t radius,const Style & style)72 void UIBoxProgress::DrawRoundCap(BufferInfo& gfxDstBuffer,
73 const Image* image,
74 const Point& imgPos,
75 const Rect& rect,
76 const Rect& invalidatedArea,
77 uint16_t radius,
78 const Style& style)
79 {
80 Point leftTop;
81 Point leftBottom;
82 Point rightTop;
83 Point rightBottom;
84
85 switch (direction_) {
86 case Direction::DIR_LEFT_TO_RIGHT:
87 case Direction::DIR_RIGHT_TO_LEFT: {
88 leftTop.x = rect.GetLeft() - 1;
89 leftTop.y = rect.GetTop() + radius - 1;
90 leftBottom.x = leftTop.x;
91 leftBottom.y = rect.GetBottom() - radius + 1;
92 rightTop.x = rect.GetRight() + 1;
93 rightTop.y = leftTop.y;
94 rightBottom.x = rightTop.x;
95 rightBottom.y = leftBottom.y;
96 break;
97 }
98
99 case Direction::DIR_TOP_TO_BOTTOM:
100 case Direction::DIR_BOTTOM_TO_TOP: {
101 leftTop.x = rect.GetLeft() + radius - 1;
102 leftTop.y = rect.GetTop() - 1;
103 rightTop.x = rect.GetRight() - radius + 1;
104 rightTop.y = leftTop.y;
105 leftBottom.x = leftTop.x;
106 leftBottom.y = rect.GetBottom() + 1;
107 rightBottom.x = rightTop.x;
108 rightBottom.y = leftBottom.y;
109 break;
110 }
111 default:
112 GRAPHIC_LOGE("UIBoxProgress: DrawRoundCap direction Err!\n");
113 break;
114 }
115
116 Style capStyle = style;
117 capStyle.lineWidth_ = radius;
118 capStyle.lineColor_ = style.bgColor_;
119 if ((image != nullptr) && (image->GetSrcType() != IMG_SRC_UNKNOWN)) {
120 capStyle.lineOpa_ = style.imageOpa_;
121 } else {
122 capStyle.lineOpa_ = style.bgOpa_;
123 }
124
125 ArcInfo arcInfo = {{0}};
126 arcInfo.radius = radius;
127 arcInfo.imgPos = imgPos;
128 arcInfo.imgSrc = image;
129
130 bool isEvenLen = false;
131 if (direction_ == Direction::DIR_LEFT_TO_RIGHT || direction_ == Direction::DIR_RIGHT_TO_LEFT) {
132 if (rect.GetHeight() % 2 == 0) { // 2: determine the odd or even number of the height
133 isEvenLen = true;
134 }
135 } else if (rect.GetWidth() % 2 == 0) { // 2: determine the odd or even number of the width
136 isEvenLen = true;
137 }
138 BaseGfxEngine* baseGfxEngine = BaseGfxEngine::GetInstance();
139 if (isEvenLen) {
140 arcInfo.center = leftTop;
141 arcInfo.startAngle = THREE_QUARTER_IN_DEGREE;
142 arcInfo.endAngle = 0;
143 baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, invalidatedArea, capStyle, opaScale_,
144 CapType::CAP_NONE);
145
146 arcInfo.center = leftBottom;
147 arcInfo.startAngle = SEMICIRCLE_IN_DEGREE;
148 arcInfo.endAngle = THREE_QUARTER_IN_DEGREE;
149 baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, invalidatedArea, capStyle, opaScale_,
150 CapType::CAP_NONE);
151
152 arcInfo.center = rightTop;
153 arcInfo.startAngle = 0;
154 arcInfo.endAngle = QUARTER_IN_DEGREE;
155 baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, invalidatedArea, capStyle, opaScale_,
156 CapType::CAP_NONE);
157
158 arcInfo.center = rightBottom;
159 arcInfo.startAngle = QUARTER_IN_DEGREE;
160 arcInfo.endAngle = SEMICIRCLE_IN_DEGREE;
161 baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, invalidatedArea, capStyle, opaScale_,
162 CapType::CAP_NONE);
163 } else {
164 switch (direction_) {
165 case Direction::DIR_LEFT_TO_RIGHT:
166 case Direction::DIR_RIGHT_TO_LEFT: {
167 arcInfo.center = leftTop;
168 arcInfo.startAngle = SEMICIRCLE_IN_DEGREE;
169 arcInfo.endAngle = 0;
170 baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, invalidatedArea, capStyle, opaScale_,
171 CapType::CAP_NONE);
172
173 arcInfo.center = rightTop;
174 arcInfo.startAngle = 0;
175 arcInfo.endAngle = SEMICIRCLE_IN_DEGREE;
176 baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, invalidatedArea, capStyle, opaScale_,
177 CapType::CAP_NONE);
178 break;
179 }
180
181 case Direction::DIR_TOP_TO_BOTTOM:
182 case Direction::DIR_BOTTOM_TO_TOP: {
183 arcInfo.center = leftTop;
184 arcInfo.startAngle = THREE_QUARTER_IN_DEGREE;
185 arcInfo.endAngle = QUARTER_IN_DEGREE;
186 baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, invalidatedArea, capStyle, opaScale_,
187 CapType::CAP_NONE);
188
189 arcInfo.center = leftBottom;
190 arcInfo.startAngle = QUARTER_IN_DEGREE;
191 arcInfo.endAngle = THREE_QUARTER_IN_DEGREE;
192 baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, invalidatedArea, capStyle, opaScale_,
193 CapType::CAP_NONE);
194 break;
195 }
196 default:
197 GRAPHIC_LOGE("UIBoxProgress: DrawRoundCap direction Err!\n");
198 break;
199 }
200 }
201 }
202
GetBackgroundParam(Point & startPoint,int16_t & width,int16_t & height,uint16_t & radius,const Style & style)203 void UIBoxProgress::GetBackgroundParam(Point& startPoint,
204 int16_t& width,
205 int16_t& height,
206 uint16_t& radius,
207 const Style& style)
208 {
209 Rect rect = GetOrigRect();
210 // 2: Half of the gap
211 startPoint.x = rect.GetLeft() + style_->borderWidth_ + style_->paddingLeft_ + (GetWidth() - progressWidth_) / 2;
212 // 2: Half of the gap
213 startPoint.y = rect.GetTop() + style_->borderWidth_ + style_->paddingTop_ + (GetHeight() - progressHeight_) / 2;
214
215 radius = 0;
216 width = progressWidth_;
217 height = progressHeight_;
218 if (style.lineCap_ == CapType::CAP_ROUND) {
219 switch (direction_) {
220 case Direction::DIR_LEFT_TO_RIGHT:
221 case Direction::DIR_RIGHT_TO_LEFT:
222 radius = (progressHeight_ + 1) >> 1;
223 width -= radius << 1;
224 startPoint.x += radius;
225 break;
226 case Direction::DIR_TOP_TO_BOTTOM:
227 case Direction::DIR_BOTTOM_TO_TOP:
228 radius = (progressWidth_ + 1) >> 1;
229 height -= radius << 1;
230 startPoint.y += radius;
231 break;
232 default:
233 GRAPHIC_LOGE("UIBoxProgress: GetBackgroundParam direction Err!\n");
234 return;
235 }
236 }
237 }
238
DrawBackground(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea)239 void UIBoxProgress::DrawBackground(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
240 {
241 Point startPoint;
242 int16_t progressWidth;
243 int16_t progressHeight;
244 uint16_t radius;
245 GetBackgroundParam(startPoint, progressWidth, progressHeight, radius, *backgroundStyle_);
246
247 Rect coords(startPoint.x, startPoint.y, startPoint.x + progressWidth - 1, startPoint.y + progressHeight - 1);
248
249 DrawValidRect(gfxDstBuffer, backgroundImage_, coords, invalidatedArea, *backgroundStyle_, radius);
250 }
251
DrawForeground(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea,Rect & coords)252 void UIBoxProgress::DrawForeground(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea, Rect& coords)
253 {
254 Point startPoint;
255 int16_t progressWidth;
256 int16_t progressHeight;
257 uint16_t radius;
258 GetBackgroundParam(startPoint, progressWidth, progressHeight, radius, *foregroundStyle_);
259 int16_t length;
260
261 switch (direction_) {
262 case Direction::DIR_LEFT_TO_RIGHT: {
263 length = GetCurrentPos(progressWidth - 1);
264 coords.SetRect(startPoint.x, startPoint.y, startPoint.x + length, startPoint.y + progressHeight - 1);
265 break;
266 }
267 case Direction::DIR_RIGHT_TO_LEFT: {
268 length = GetCurrentPos(progressWidth - 1);
269 coords.SetRect(startPoint.x + progressWidth - 1 - length,
270 startPoint.y, startPoint.x + progressWidth - 1, startPoint.y + progressHeight - 1);
271 break;
272 }
273 case Direction::DIR_TOP_TO_BOTTOM: {
274 length = GetCurrentPos(progressHeight - 1);
275 coords.SetRect(startPoint.x, startPoint.y, startPoint.x + progressWidth - 1, startPoint.y + length);
276 break;
277 }
278 case Direction::DIR_BOTTOM_TO_TOP: {
279 length = GetCurrentPos(progressHeight - 1);
280 coords.SetRect(startPoint.x, startPoint.y + progressHeight - 1 - length,
281 startPoint.x + progressWidth - 1, startPoint.y + progressHeight - 1);
282 break;
283 }
284 default: {
285 GRAPHIC_LOGE("UIBoxProgress: DrawForeground direction Err!\n");
286 return;
287 }
288 }
289
290 DrawValidRect(gfxDstBuffer, foregroundImage_, coords, invalidatedArea, *foregroundStyle_, radius);
291 }
292
OnDraw(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea)293 void UIBoxProgress::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
294 {
295 UIView::OnDraw(gfxDstBuffer, invalidatedArea);
296 if (enableBackground_) {
297 DrawBackground(gfxDstBuffer, invalidatedArea);
298 }
299
300 if ((lastValue_ - rangeMin_ != 0) || (foregroundStyle_->lineCap_ == CapType::CAP_ROUND)) {
301 Rect coords;
302 DrawForeground(gfxDstBuffer, invalidatedArea, coords);
303 }
304 }
305 } // namespace OHOS
306