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 21namespace OHOS { 22UIBoxProgress::UIBoxProgress() 23 : progressWidth_(0), progressHeight_(0), isValidWidthSet_(false), isValidHeightSet_(false) 24{ 25 SetDirection(Direction::DIR_LEFT_TO_RIGHT); 26} 27 28void 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 72void 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 203void 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 239void 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 252void 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 293void 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