mirror of
https://github.com/mudita/MuditaOS.git
synced 2026-02-07 12:52:15 -05:00
370 lines
16 KiB
C++
370 lines
16 KiB
C++
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
|
|
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
|
|
|
|
#include "RectangleRenderer.hpp"
|
|
|
|
#include "ArcRenderer.hpp"
|
|
#include "LineRenderer.hpp"
|
|
#include "PixelRenderer.hpp"
|
|
|
|
#include "Context.hpp"
|
|
|
|
#include <queue>
|
|
|
|
namespace gui::renderer
|
|
{
|
|
auto RectangleRenderer::DrawableStyle::from(const DrawRectangle &command) -> DrawableStyle
|
|
{
|
|
return DrawableStyle{command.penWidth,
|
|
command.radius,
|
|
command.yapSize,
|
|
command.edges,
|
|
command.flatEdges,
|
|
command.corners,
|
|
command.yaps,
|
|
command.borderColor,
|
|
command.filled ? command.fillColor : ColorNoColor};
|
|
}
|
|
|
|
void RectangleRenderer::drawFlat(
|
|
Context *ctx, Point position, Length width, Length height, const DrawableStyle &style)
|
|
{
|
|
if (style.fillColor != ColorNoColor) {
|
|
fillFlatRectangle(ctx, position, width, height, style.fillColor);
|
|
}
|
|
drawSides(ctx, position, width, height, style.borderWidth, style.borderColor, style.edges);
|
|
}
|
|
|
|
void RectangleRenderer::fillFlatRectangle(Context *ctx, Point position, Length width, Length height, Color color)
|
|
{
|
|
for (unsigned int y = 1; y <= height; ++y) {
|
|
LineRenderer::drawHorizontal(ctx,
|
|
Point(position.x, position.y + y),
|
|
width,
|
|
LineRenderer::DrawableStyle{1, color, LineExpansionDirection::Up});
|
|
}
|
|
}
|
|
|
|
void RectangleRenderer::drawSides(
|
|
Context *ctx, Point position, Length width, Length height, Length penWidth, Color color, RectangleEdge sides)
|
|
{
|
|
if (sides & RectangleEdge::Top) {
|
|
drawTopSide(ctx, position, width, penWidth, color);
|
|
}
|
|
if (sides & RectangleEdge::Right) {
|
|
drawRightSide(ctx, position, width, height, penWidth, color);
|
|
}
|
|
if (sides & RectangleEdge::Bottom) {
|
|
drawBottomSide(ctx, position, width, height, penWidth, color);
|
|
}
|
|
if (sides & RectangleEdge::Left) {
|
|
drawLeftSide(ctx, position, height, penWidth, color);
|
|
}
|
|
}
|
|
|
|
void RectangleRenderer::draw(Context *ctx, Point position, Length width, Length height, const DrawableStyle &style)
|
|
{
|
|
drawCorners(ctx,
|
|
position,
|
|
width,
|
|
height,
|
|
style.radius,
|
|
style.borderWidth,
|
|
style.borderColor,
|
|
style.roundedCorners,
|
|
style.flatEdges,
|
|
style.yaps);
|
|
drawSides(ctx,
|
|
position,
|
|
width,
|
|
height,
|
|
style.radius,
|
|
style.yapSize,
|
|
style.borderWidth,
|
|
style.flatEdges,
|
|
style.yaps,
|
|
style.borderColor,
|
|
style.edges);
|
|
if (style.fillColor != ColorNoColor) {
|
|
fill(ctx, Point(position.x + (width / 2), position.y + (height / 2)), style.borderColor, style.fillColor);
|
|
}
|
|
}
|
|
|
|
void RectangleRenderer::drawCorners(Context *ctx,
|
|
Point position,
|
|
Length width,
|
|
Length height,
|
|
Length radius,
|
|
Length penWidth,
|
|
Color borderColor,
|
|
RectangleRoundedCorner rounded,
|
|
RectangleFlatEdge flats,
|
|
RectangleYap yaps)
|
|
{
|
|
|
|
const ArcRenderer::DrawableStyle arcStyle{penWidth, borderColor};
|
|
|
|
const auto topRightCenter = Point(position.x + width - radius, position.y + radius);
|
|
const auto topLeftCenter = Point(position.x + radius, topRightCenter.y);
|
|
const auto bottomRightCenter = Point(topRightCenter.x, position.y + height - radius);
|
|
const auto bottomLeftCenter = Point(topLeftCenter.x, bottomRightCenter.y);
|
|
|
|
const auto topRightCornerRounded = (rounded & RectangleRoundedCorner::TopRight) &&
|
|
!(flats & RectangleFlatEdge::TopRight) && !(yaps & RectangleYap::TopRight);
|
|
if (topRightCornerRounded) {
|
|
ArcRenderer::draw(ctx, topRightCenter, radius, -90, 90, arcStyle);
|
|
}
|
|
|
|
const auto topLeftCornerRounded = (rounded & RectangleRoundedCorner::TopLeft) &&
|
|
!(flats & RectangleFlatEdge::TopLeft) && !(yaps & RectangleYap::TopLeft);
|
|
if (topLeftCornerRounded) {
|
|
ArcRenderer::draw(ctx, topLeftCenter, radius, -180, 90, arcStyle);
|
|
}
|
|
|
|
const auto bottomRightCornerRounded = (rounded & RectangleRoundedCorner::BottomRight) &&
|
|
!(flats & RectangleFlatEdge::BottomRight) &&
|
|
!(yaps & RectangleYap::BottomRight);
|
|
if (bottomRightCornerRounded) {
|
|
ArcRenderer::draw(ctx, bottomRightCenter, radius, 0, 90, arcStyle);
|
|
}
|
|
|
|
const auto bottomLeftCornerRounded = (rounded & RectangleRoundedCorner::BottomLeft) &&
|
|
!(flats & RectangleFlatEdge::BottomLeft) &&
|
|
!(yaps & RectangleYap::BottomLeft);
|
|
if (bottomLeftCornerRounded) {
|
|
ArcRenderer::draw(ctx, bottomLeftCenter, radius, -270, 90, arcStyle);
|
|
}
|
|
}
|
|
|
|
void RectangleRenderer::drawSides(Context *ctx,
|
|
Point position,
|
|
Length width,
|
|
Length height,
|
|
Length radius,
|
|
Length yapSize,
|
|
Length penWidth,
|
|
RectangleFlatEdge flats,
|
|
RectangleYap yaps,
|
|
Color borderColor,
|
|
RectangleEdge sides)
|
|
{
|
|
if (sides & RectangleEdge::Top) {
|
|
drawTopSide(ctx, position, width, radius, yapSize, penWidth, flats, yaps, borderColor);
|
|
}
|
|
if (sides & RectangleEdge::Bottom) {
|
|
drawBottomSide(ctx, position, width, height, radius, yapSize, penWidth, flats, yaps, borderColor);
|
|
}
|
|
if (sides & RectangleEdge::Left) {
|
|
drawLeftSide(ctx, position, height, radius, yapSize, penWidth, flats, yaps, borderColor);
|
|
}
|
|
if (sides & RectangleEdge::Right) {
|
|
drawRightSide(ctx, position, width, height, radius, yapSize, penWidth, flats, yaps, borderColor);
|
|
}
|
|
}
|
|
|
|
void RectangleRenderer::fill(Context *ctx, Point startPosition, Color borderColor, Color fillColor)
|
|
{
|
|
std::queue<Point> q;
|
|
q.push(startPosition);
|
|
|
|
while (!q.empty()) {
|
|
const auto currPoint = q.front();
|
|
q.pop();
|
|
if (const auto color = ctx->getPixel(currPoint, PixelRenderer::getColor(borderColor.intensity));
|
|
color == PixelRenderer::getColor(borderColor.intensity) ||
|
|
color == PixelRenderer::getColor(fillColor.intensity)) {
|
|
continue;
|
|
}
|
|
|
|
PixelRenderer::draw(ctx, currPoint, fillColor);
|
|
q.push(Point{currPoint.x + 1, currPoint.y});
|
|
q.push(Point{currPoint.x - 1, currPoint.y});
|
|
q.push(Point{currPoint.x, currPoint.y + 1});
|
|
q.push(Point{currPoint.x, currPoint.y - 1});
|
|
}
|
|
}
|
|
|
|
void RectangleRenderer::drawTopSide(Context *ctx, Point position, Length length, Length penWidth, Color color)
|
|
{
|
|
LineRenderer::drawHorizontal(
|
|
ctx, position, length, LineRenderer::DrawableStyle{penWidth, color, LineExpansionDirection::Down});
|
|
}
|
|
|
|
void RectangleRenderer::drawTopSide(Context *ctx,
|
|
Point position,
|
|
Length width,
|
|
Length radius,
|
|
Length yapSize,
|
|
Length penWidth,
|
|
RectangleFlatEdge flat,
|
|
RectangleYap yaps,
|
|
Color borderColor)
|
|
{
|
|
int x = position.x;
|
|
if (yaps & RectangleYap::TopLeft) {
|
|
x -= yapSize;
|
|
width += yapSize;
|
|
}
|
|
else if (!(flat & RectangleFlatEdge::TopLeft)) {
|
|
x += radius;
|
|
width -= radius;
|
|
}
|
|
|
|
if (yaps & RectangleYap::TopRight) {
|
|
width += yapSize;
|
|
}
|
|
else if (!(flat & RectangleFlatEdge::TopRight)) {
|
|
width -= radius;
|
|
}
|
|
LineRenderer::drawHorizontal(ctx,
|
|
Point(x, position.y),
|
|
width,
|
|
LineRenderer::DrawableStyle{penWidth, borderColor, LineExpansionDirection::Down});
|
|
}
|
|
|
|
void RectangleRenderer::drawRightSide(
|
|
Context *ctx, Point position, Length width, Length height, Length penWidth, Color color)
|
|
{
|
|
LineRenderer::drawVertical(ctx,
|
|
Point(position.x + width, position.y),
|
|
height,
|
|
LineRenderer::DrawableStyle{penWidth, color, LineExpansionDirection::Left});
|
|
}
|
|
|
|
void RectangleRenderer::drawRightSide(Context *ctx,
|
|
Point position,
|
|
Length width,
|
|
Length height,
|
|
Length radius,
|
|
Length yapSize,
|
|
Length penWidth,
|
|
RectangleFlatEdge flat,
|
|
RectangleYap yaps,
|
|
Color borderColor)
|
|
{
|
|
int x = position.x + width + 1;
|
|
int y = position.y;
|
|
int length = height;
|
|
if (yaps & RectangleYap::TopRight) {
|
|
LineRenderer::draw45deg(ctx,
|
|
Point(x + yapSize - 1, y),
|
|
yapSize,
|
|
LineRenderer::DrawableStyle{penWidth, borderColor, LineExpansionDirection::Left},
|
|
false);
|
|
y += yapSize;
|
|
length -= yapSize;
|
|
}
|
|
else if (!(flat & RectangleFlatEdge::TopRight)) {
|
|
y += radius;
|
|
length -= radius;
|
|
}
|
|
|
|
if (yaps & RectangleYap::BottomRight) {
|
|
LineRenderer::draw45deg(ctx,
|
|
Point(x, y + height),
|
|
yapSize,
|
|
LineRenderer::DrawableStyle{penWidth, borderColor, LineExpansionDirection::Left},
|
|
true);
|
|
length -= yapSize;
|
|
}
|
|
else if (!(flat & RectangleFlatEdge::BottomRight)) {
|
|
length -= radius;
|
|
}
|
|
|
|
LineRenderer::drawVertical(
|
|
ctx, Point(x, y), length, LineRenderer::DrawableStyle{penWidth, borderColor, LineExpansionDirection::Left});
|
|
}
|
|
|
|
void RectangleRenderer::drawBottomSide(
|
|
Context *ctx, Point position, Length width, Length height, Length penWidth, Color color)
|
|
{
|
|
LineRenderer::drawHorizontal(ctx,
|
|
Point(position.x, position.y + height),
|
|
width,
|
|
LineRenderer::DrawableStyle{penWidth, color, LineExpansionDirection::Up});
|
|
}
|
|
|
|
void RectangleRenderer::drawBottomSide(Context *ctx,
|
|
Point position,
|
|
Length width,
|
|
Length height,
|
|
Length radius,
|
|
Length yapSize,
|
|
Length penWidth,
|
|
RectangleFlatEdge flat,
|
|
RectangleYap yaps,
|
|
Color borderColor)
|
|
{
|
|
int x = position.x;
|
|
int y = position.y + height + 1;
|
|
int length = width;
|
|
if (yaps & RectangleYap::BottomLeft) {
|
|
x -= yapSize;
|
|
length += yapSize;
|
|
}
|
|
else if (!(flat & RectangleFlatEdge::BottomLeft)) {
|
|
x += radius;
|
|
length -= radius;
|
|
}
|
|
|
|
if (yaps & RectangleYap::BottomRight) {
|
|
length += yapSize;
|
|
}
|
|
else if (!(flat & RectangleFlatEdge::BottomRight)) {
|
|
length -= radius;
|
|
}
|
|
LineRenderer::drawHorizontal(
|
|
ctx, Point(x, y), length, LineRenderer::DrawableStyle{penWidth, borderColor, LineExpansionDirection::Up});
|
|
}
|
|
|
|
void RectangleRenderer::drawLeftSide(Context *ctx, Point position, Length height, Length penWidth, Color color)
|
|
{
|
|
LineRenderer::drawVertical(
|
|
ctx, position, height, LineRenderer::DrawableStyle{penWidth, color, LineExpansionDirection::Right});
|
|
}
|
|
|
|
void RectangleRenderer::drawLeftSide(Context *ctx,
|
|
Point position,
|
|
Length height,
|
|
Length radius,
|
|
Length yapSize,
|
|
Length penWidth,
|
|
RectangleFlatEdge flat,
|
|
RectangleYap yaps,
|
|
Color borderColor)
|
|
{
|
|
int x = position.x;
|
|
int y = position.y;
|
|
int length = height;
|
|
if (yaps & RectangleYap::TopLeft) {
|
|
LineRenderer::draw45deg(ctx,
|
|
Point(x - yapSize, y),
|
|
yapSize,
|
|
LineRenderer::DrawableStyle{penWidth, borderColor, LineExpansionDirection::Right},
|
|
true);
|
|
y += yapSize;
|
|
length -= yapSize;
|
|
}
|
|
else if (!(flat & RectangleFlatEdge::TopLeft)) {
|
|
y += radius;
|
|
length -= radius;
|
|
}
|
|
|
|
if (yaps & RectangleYap::BottomLeft) {
|
|
LineRenderer::draw45deg(ctx,
|
|
Point(x, y + height),
|
|
yapSize,
|
|
LineRenderer::DrawableStyle{penWidth, borderColor, LineExpansionDirection::Right},
|
|
false);
|
|
length -= yapSize;
|
|
}
|
|
else if (!(flat & RectangleFlatEdge::BottomLeft)) {
|
|
length -= radius;
|
|
}
|
|
LineRenderer::drawVertical(ctx,
|
|
Point(x, y),
|
|
length,
|
|
LineRenderer::DrawableStyle{penWidth, borderColor, LineExpansionDirection::Right});
|
|
}
|
|
} // namespace gui::renderer
|