* Copyright (c) 2020-2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "components/ui_box_progress.h"
#include "draw/draw_utils.h"
#include "engines/gfx/gfx_engine_manager.h"
#include "gfx_utils/graphic_log.h"
namespace OHOS {
UIBoxProgress::UIBoxProgress()
: progressWidth_(0), progressHeight_(0), isValidWidthSet_(false), isValidHeightSet_(false)
{
SetDirection(Direction::DIR_LEFT_TO_RIGHT);
}
void UIBoxProgress::DrawValidRect(BufferInfo& gfxDstBuffer,
const Image* image,
const Rect& rect,
const Rect& invalidatedArea,
const Style& style,
uint16_t radius)
{
Rect cordsTmp;
if ((image != nullptr) && (image->GetSrcType() != IMG_SRC_UNKNOWN)) {
ImageHeader header = {};
image->GetHeader(header);
Rect area(rect);
switch (direction_) {
case Direction::DIR_LEFT_TO_RIGHT:
cordsTmp.SetPosition(area.GetLeft() - radius, area.GetTop());
break;
case Direction::DIR_TOP_TO_BOTTOM:
cordsTmp.SetPosition(area.GetLeft(), area.GetTop() - radius);
break;
case Direction::DIR_RIGHT_TO_LEFT:
cordsTmp.SetPosition(area.GetRight() + radius - header.width, area.GetTop());
break;
case Direction::DIR_BOTTOM_TO_TOP:
cordsTmp.SetPosition(area.GetLeft(), area.GetBottom() + radius - header.height);
break;
default:
GRAPHIC_LOGE("UIBoxProgress: DrawValidRect direction Err!\n");
break;
}
cordsTmp.SetHeight(header.height);
cordsTmp.SetWidth(header.width);
if (area.Intersect(area, invalidatedArea)) {
image->DrawImage(gfxDstBuffer, cordsTmp, area, style, opaScale_);
}
} else {
BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, rect, invalidatedArea, style, opaScale_);
}
if (style.lineCap_ == CapType::CAP_ROUND) {
DrawRoundCap(gfxDstBuffer, image, {cordsTmp.GetX(), cordsTmp.GetY()}, rect, invalidatedArea, radius, style);
}
}
void UIBoxProgress::DrawRoundCap(BufferInfo& gfxDstBuffer,
const Image* image,
const Point& imgPos,
const Rect& rect,
const Rect& invalidatedArea,
uint16_t radius,
const Style& style)
{
Point leftTop;
Point leftBottom;
Point rightTop;
Point rightBottom;
switch (direction_) {
case Direction::DIR_LEFT_TO_RIGHT:
case Direction::DIR_RIGHT_TO_LEFT: {
leftTop.x = rect.GetLeft() - 1;
leftTop.y = rect.GetTop() + radius - 1;
leftBottom.x = leftTop.x;
leftBottom.y = rect.GetBottom() - radius + 1;
rightTop.x = rect.GetRight() + 1;
rightTop.y = leftTop.y;
rightBottom.x = rightTop.x;
rightBottom.y = leftBottom.y;
break;
}
case Direction::DIR_TOP_TO_BOTTOM:
case Direction::DIR_BOTTOM_TO_TOP: {
leftTop.x = rect.GetLeft() + radius - 1;
leftTop.y = rect.GetTop() - 1;
rightTop.x = rect.GetRight() - radius + 1;
rightTop.y = leftTop.y;
leftBottom.x = leftTop.x;
leftBottom.y = rect.GetBottom() + 1;
rightBottom.x = rightTop.x;
rightBottom.y = leftBottom.y;
break;
}
default:
GRAPHIC_LOGE("UIBoxProgress: DrawRoundCap direction Err!\n");
break;
}
Style capStyle = style;
capStyle.lineWidth_ = radius;
capStyle.lineColor_ = style.bgColor_;
if ((image != nullptr) && (image->GetSrcType() != IMG_SRC_UNKNOWN)) {
capStyle.lineOpa_ = style.imageOpa_;
} else {
capStyle.lineOpa_ = style.bgOpa_;
}
ArcInfo arcInfo = {{0}};
arcInfo.radius = radius;
arcInfo.imgPos = imgPos;
arcInfo.imgSrc = image;
bool isEvenLen = false;
if (direction_ == Direction::DIR_LEFT_TO_RIGHT || direction_ == Direction::DIR_RIGHT_TO_LEFT) {
if (rect.GetHeight() % 2 == 0) {
isEvenLen = true;
}
} else if (rect.GetWidth() % 2 == 0) {
isEvenLen = true;
}
BaseGfxEngine* baseGfxEngine = BaseGfxEngine::GetInstance();
if (isEvenLen) {
arcInfo.center = leftTop;
arcInfo.startAngle = THREE_QUARTER_IN_DEGREE;
arcInfo.endAngle = 0;
baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, invalidatedArea, capStyle, opaScale_,
CapType::CAP_NONE);
arcInfo.center = leftBottom;
arcInfo.startAngle = SEMICIRCLE_IN_DEGREE;
arcInfo.endAngle = THREE_QUARTER_IN_DEGREE;
baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, invalidatedArea, capStyle, opaScale_,
CapType::CAP_NONE);
arcInfo.center = rightTop;
arcInfo.startAngle = 0;
arcInfo.endAngle = QUARTER_IN_DEGREE;
baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, invalidatedArea, capStyle, opaScale_,
CapType::CAP_NONE);
arcInfo.center = rightBottom;
arcInfo.startAngle = QUARTER_IN_DEGREE;
arcInfo.endAngle = SEMICIRCLE_IN_DEGREE;
baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, invalidatedArea, capStyle, opaScale_,
CapType::CAP_NONE);
} else {
switch (direction_) {
case Direction::DIR_LEFT_TO_RIGHT:
case Direction::DIR_RIGHT_TO_LEFT: {
arcInfo.center = leftTop;
arcInfo.startAngle = SEMICIRCLE_IN_DEGREE;
arcInfo.endAngle = 0;
baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, invalidatedArea, capStyle, opaScale_,
CapType::CAP_NONE);
arcInfo.center = rightTop;
arcInfo.startAngle = 0;
arcInfo.endAngle = SEMICIRCLE_IN_DEGREE;
baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, invalidatedArea, capStyle, opaScale_,
CapType::CAP_NONE);
break;
}
case Direction::DIR_TOP_TO_BOTTOM:
case Direction::DIR_BOTTOM_TO_TOP: {
arcInfo.center = leftTop;
arcInfo.startAngle = THREE_QUARTER_IN_DEGREE;
arcInfo.endAngle = QUARTER_IN_DEGREE;
baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, invalidatedArea, capStyle, opaScale_,
CapType::CAP_NONE);
arcInfo.center = leftBottom;
arcInfo.startAngle = QUARTER_IN_DEGREE;
arcInfo.endAngle = THREE_QUARTER_IN_DEGREE;
baseGfxEngine->DrawArc(gfxDstBuffer, arcInfo, invalidatedArea, capStyle, opaScale_,
CapType::CAP_NONE);
break;
}
default:
GRAPHIC_LOGE("UIBoxProgress: DrawRoundCap direction Err!\n");
break;
}
}
}
void UIBoxProgress::GetBackgroundParam(Point& startPoint,
int16_t& width,
int16_t& height,
uint16_t& radius,
const Style& style)
{
Rect rect = GetOrigRect();
startPoint.x = rect.GetLeft() + style_->borderWidth_ + style_->paddingLeft_ + (GetWidth() - progressWidth_) / 2;
startPoint.y = rect.GetTop() + style_->borderWidth_ + style_->paddingTop_ + (GetHeight() - progressHeight_) / 2;
radius = 0;
width = progressWidth_;
height = progressHeight_;
if (style.lineCap_ == CapType::CAP_ROUND) {
switch (direction_) {
case Direction::DIR_LEFT_TO_RIGHT:
case Direction::DIR_RIGHT_TO_LEFT:
radius = (progressHeight_ + 1) >> 1;
width -= radius << 1;
startPoint.x += radius;
break;
case Direction::DIR_TOP_TO_BOTTOM:
case Direction::DIR_BOTTOM_TO_TOP:
radius = (progressWidth_ + 1) >> 1;
height -= radius << 1;
startPoint.y += radius;
break;
default:
GRAPHIC_LOGE("UIBoxProgress: GetBackgroundParam direction Err!\n");
return;
}
}
}
void UIBoxProgress::DrawBackground(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
{
Point startPoint;
int16_t progressWidth;
int16_t progressHeight;
uint16_t radius;
GetBackgroundParam(startPoint, progressWidth, progressHeight, radius, *backgroundStyle_);
Rect coords(startPoint.x, startPoint.y, startPoint.x + progressWidth - 1, startPoint.y + progressHeight - 1);
DrawValidRect(gfxDstBuffer, backgroundImage_, coords, invalidatedArea, *backgroundStyle_, radius);
}
void UIBoxProgress::DrawForeground(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea, Rect& coords)
{
Point startPoint;
int16_t progressWidth;
int16_t progressHeight;
uint16_t radius;
GetBackgroundParam(startPoint, progressWidth, progressHeight, radius, *foregroundStyle_);
int16_t length;
switch (direction_) {
case Direction::DIR_LEFT_TO_RIGHT: {
length = GetCurrentPos(progressWidth - 1);
coords.SetRect(startPoint.x, startPoint.y, startPoint.x + length, startPoint.y + progressHeight - 1);
break;
}
case Direction::DIR_RIGHT_TO_LEFT: {
length = GetCurrentPos(progressWidth - 1);
coords.SetRect(startPoint.x + progressWidth - 1 - length,
startPoint.y, startPoint.x + progressWidth - 1, startPoint.y + progressHeight - 1);
break;
}
case Direction::DIR_TOP_TO_BOTTOM: {
length = GetCurrentPos(progressHeight - 1);
coords.SetRect(startPoint.x, startPoint.y, startPoint.x + progressWidth - 1, startPoint.y + length);
break;
}
case Direction::DIR_BOTTOM_TO_TOP: {
length = GetCurrentPos(progressHeight - 1);
coords.SetRect(startPoint.x, startPoint.y + progressHeight - 1 - length,
startPoint.x + progressWidth - 1, startPoint.y + progressHeight - 1);
break;
}
default: {
GRAPHIC_LOGE("UIBoxProgress: DrawForeground direction Err!\n");
return;
}
}
DrawValidRect(gfxDstBuffer, foregroundImage_, coords, invalidatedArea, *foregroundStyle_, radius);
}
void UIBoxProgress::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
{
UIView::OnDraw(gfxDstBuffer, invalidatedArea);
if (enableBackground_) {
DrawBackground(gfxDstBuffer, invalidatedArea);
}
if ((lastValue_ - rangeMin_ != 0) || (foregroundStyle_->lineCap_ == CapType::CAP_ROUND)) {
Rect coords;
DrawForeground(gfxDstBuffer, invalidatedArea, coords);
}
}
}