From e6fdf0e22cba3b9d8ef0ef8b463e0a0539a1048e Mon Sep 17 00:00:00 2001 From: Maciej Janicki Date: Mon, 25 Jan 2021 13:06:29 +0100 Subject: [PATCH] [EGD-5333] Change renderer to follow command design pattern Changes draw command implementation to properly follow command design pattern. All drawing commands have been moved to separate inheriting draw commands from renderer. Other changes: - New draw methods overloads have been added to pixel renderer. Now pixel rendering methods are in one class. - Simplified draw commands naming. - Changed variable naming in draw commands to be more verbose. - Changed {x,y} pairs to Points where possible. --- module-gui/gui/core/Context.hpp | 8 +- module-gui/gui/core/DrawCommand.cpp | 293 ++++++++++++++++- module-gui/gui/core/DrawCommand.hpp | 250 ++++++-------- module-gui/gui/core/RawFont.cpp | 13 +- module-gui/gui/core/Renderer.cpp | 311 +----------------- module-gui/gui/core/Renderer.hpp | 14 - module-gui/gui/core/renderers/ArcRenderer.cpp | 2 +- module-gui/gui/core/renderers/ArcRenderer.hpp | 2 +- .../gui/core/renderers/CircleRenderer.cpp | 2 +- .../gui/core/renderers/CircleRenderer.hpp | 2 +- .../gui/core/renderers/LineRenderer.cpp | 2 +- .../gui/core/renderers/LineRenderer.hpp | 2 +- .../gui/core/renderers/PixelRenderer.cpp | 1 - .../gui/core/renderers/RectangleRenderer.cpp | 2 +- .../gui/core/renderers/RectangleRenderer.hpp | 2 +- module-gui/gui/widgets/Arc.cpp | 2 +- module-gui/gui/widgets/Circle.cpp | 2 +- module-gui/gui/widgets/Image.cpp | 15 +- module-gui/gui/widgets/Label.cpp | 16 +- module-gui/gui/widgets/Rect.cpp | 9 +- module-gui/gui/widgets/Window.cpp | 11 +- 21 files changed, 433 insertions(+), 528 deletions(-) diff --git a/module-gui/gui/core/Context.hpp b/module-gui/gui/core/Context.hpp index ed7d61090dc91849e6c940ddddc88c85338e8154..de96461beafb93f64e048fc83a1c8f12964f3710 100644 --- a/module-gui/gui/core/Context.hpp +++ b/module-gui/gui/core/Context.hpp @@ -13,7 +13,7 @@ #include #include -#include "Common.hpp" +#include "module-gui/gui/Common.hpp" namespace gui { @@ -81,6 +81,12 @@ namespace gui return (ptr >= data) && (ptr < data + w * h); } + inline bool addressInData(const Point point) const noexcept + { + return (point.x >= 0 && static_cast(point.x) <= w) && + (point.y >= 0 && static_cast(point.y) <= h); + } + friend std::ostream &operator<<(std::ostream &out, const Context &c); }; diff --git a/module-gui/gui/core/DrawCommand.cpp b/module-gui/gui/core/DrawCommand.cpp index 2e1aeec0f89b5513256b9e5cce0c7e00d9314e86..3f1cc741d7363ccb5aedade6d3729c8ebbed16ac 100644 --- a/module-gui/gui/core/DrawCommand.cpp +++ b/module-gui/gui/core/DrawCommand.cpp @@ -1,14 +1,289 @@ -// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md -/* - * DrawCommand.cpp - * - * Created on: 25 kwi 2019 - * Author: robert - */ - #include "DrawCommand.hpp" +#include "Common.hpp" + +// gui components +#include "Color.hpp" +#include "Context.hpp" +#include "ImageManager.hpp" +// renderers +#include "renderers/LineRenderer.hpp" +#include "renderers/ArcRenderer.hpp" +#include "renderers/CircleRenderer.hpp" +#include "renderers/RectangleRenderer.hpp" +#include +// text rendering +#include "FontManager.hpp" +#include "RawFont.hpp" +// utils +#include "log/log.hpp" +// module-utils +#include +#include + +#if DEBUG_FONT == 1 +#define log_warn_glyph(...) LOG_WARN(__VA_ARGS__) +#else +#define log_warn_glyph(...) +#endif namespace gui -{} /* namespace gui */ +{ + void Clear::draw(Context *ctx) const + { + ctx->fill(ColorFullWhite.intensity); + } + + void DrawLine::draw(Context *ctx) const + { + renderer::LineRenderer::draw(ctx, start, end, color); + } + + void DrawRectangle::draw(Context *ctx) const + { + using renderer::RectangleRenderer; + + // First, check if there is anything to draw + if (width == 0 || height == 0) { + return; + } + if (fillColor.alpha == Color::FullTransparent && borderColor.alpha == Color::FullTransparent) { + return; + } + if (!filled && borderColor.alpha == Color::FullTransparent) { + return; + } + + Context *drawingContext = ctx; + Point position; + + if (yaps & (RectangleYap::BottomLeft | RectangleYap::TopLeft)) { + position.x += yapSize; + } + + Length adjustedWidth = areaW; + Length adjustedHeight = areaH; + if (yaps != RectangleYap::None) { + adjustedWidth -= yapSize; + } + + if (areaW == width && areaH == height) { + position.x += origin.x; + position.y += origin.y; + } + else { + const auto xCtx = areaX < 0 ? origin.x + areaX : origin.x; + const auto yCtx = areaY < 0 ? origin.y + areaY : origin.y; + drawingContext = ctx->get(xCtx, yCtx, areaW, areaH); + } + + if (radius == 0) { + RectangleRenderer::drawFlat( + drawingContext, position, adjustedWidth, adjustedHeight, RectangleRenderer::DrawableStyle::from(*this)); + } + else { + RectangleRenderer::draw( + drawingContext, position, adjustedWidth, adjustedHeight, RectangleRenderer::DrawableStyle::from(*this)); + } + + if (drawingContext != ctx) { + ctx->insertArea(origin.x, origin.y, areaX, areaY, width, height, drawingContext); + delete drawingContext; + } + } + + void DrawArc::draw(Context *ctx) const + { + renderer::ArcRenderer::draw( + ctx, center, radius, start, sweep, renderer::ArcRenderer::DrawableStyle::from(*this)); + } + + void DrawCircle::draw(Context *ctx) const + { + renderer::CircleRenderer::draw(ctx, center, radius, renderer::CircleRenderer::DrawableStyle::from(*this)); + } + + void DrawText::drawChar(Context *ctx, const Point glyphOrigin, FontGlyph *glyph) const + { + auto *glyphPtr = glyph->data - glyphOrigin.x; + assert(glyph->data); + + Point position = glyphOrigin; + const Position glyphMaxY = glyphOrigin.y - glyph->yoffset + glyph->height; + const Position glyphMaxX = glyphOrigin.x + glyph->width; + + for (position.y = glyphOrigin.y - glyph->yoffset; position.y < glyphMaxY; ++position.y) { + for (position.x = glyphOrigin.x; position.x < glyphMaxX; ++position.x) { + if (!ctx->addressInData(position)) { + log_warn_glyph( + "drawing out of: {x=%d,y=%d} vs {w=%d,h=%d}", position.x, position.y, ctx->getW(), ctx->getH()); + return; + } + + if (*(glyphPtr + position.x) == ColorFullBlack.intensity) { + renderer::PixelRenderer::draw(ctx, position, color); + } + } + glyphPtr += glyph->width; + } + } + + void DrawText::draw(Context *ctx) const + { + // check if there are any characters to draw in the string provided with message. + if (str.length() == 0) { + return; + } + + // get copy of original context using x,y of draw coordinates and original size of the widget + Context *drawCtx; + bool copyContext = false; + Point widgetOrigin = {0, 0}; + + // check if there is a need of making copy of context to use it as background + if ((areaW == width) && (areaH == height)) { + drawCtx = ctx; + widgetOrigin = origin; + } + else { + copyContext = true; + drawCtx = ctx->get(origin.x, origin.y, areaW, areaH); + } + + // retrieve font used to draw text + RawFont *font = FontManager::getInstance().getFont(fontID); + + // draw every sign + uint32_t idLast = 0, idCurrent = 0; + Point position = textOrigin; + + for (uint32_t i = 0; i < str.length(); ++i) { + idCurrent = str[i]; // id stands for glued together utf-16 with no order bytes (0xFF 0xFE) + FontGlyph *glyph = font->getGlyph(idCurrent); + + // do not start drawing outside of draw context. + if ((widgetOrigin.x + position.x + glyph->xoffset >= drawCtx->getW()) || + (widgetOrigin.x + position.x + glyph->xoffset < 0)) { + LOG_FATAL("Drawing outside context's X boundary for glyph: %" PRIu32, glyph->id); + return; + } + if ((widgetOrigin.y + position.y >= drawCtx->getH()) || (widgetOrigin.y + position.y < 0)) { + LOG_FATAL("Drawing outside context's Y boundary for glyph: %" PRIu32, glyph->id); + return; + } + + int32_t kernValue = 0; + if (i > 0) { + kernValue = font->getKerning(idLast, idCurrent); + } + + drawChar(drawCtx, + {widgetOrigin.x + position.x + glyph->xoffset + kernValue, widgetOrigin.y + position.y}, + glyph); + position.x += glyph->xadvance + kernValue; + + idLast = idCurrent; + } + + // if drawing was performed in temporary context + // reinsert drawCtx into bast context + if (copyContext) { + ctx->insert(origin.x, origin.y, drawCtx); + delete drawCtx; + } + } + + inline void DrawImage::checkImageSize(Context *ctx, ImageMap *image) const + { + if (image->getHeight() > ctx->getH() || image->getWidth() > ctx->getW()) { + LOG_WARN("image %s {w: %d,h %d} > context {w %d,h %d}", + image->getName().c_str(), + image->getWidth(), + ctx->getW(), + image->getHeight(), + ctx->getH()); + } + } + + void DrawImage::drawPixMap(Context *ctx, PixMap *pixMap) const + { + uint32_t offsetImage = 0; + uint32_t offsetContext = 0; + uint8_t *pixData = pixMap->getData(); + const auto ctxData = ctx->getData(); + checkImageSize(ctx, pixMap); + + for (uint32_t row = 0; row < std::min(ctx->getH(), pixMap->getHeight()); row++) { + std::memcpy(ctxData + offsetContext, pixData + offsetImage, std::min(ctx->getW(), pixMap->getWidth())); + offsetImage += pixMap->getWidth(); + offsetContext += ctx->getW(); + } + } + + void DrawImage::drawVecMap(Context *ctx, VecMap *vecMap) const + { + uint32_t offsetContext = 0; + uint32_t offsetRowContext = 0; + uint32_t imageOffset = 0; + uint8_t alphaColor = vecMap->getAlphaColor(); + + for (uint32_t row = 0; row < std::min(vecMap->getHeight(), ctx->getH()); row++) { + checkImageSize(ctx, vecMap); + uint16_t vecCount = *(vecMap->getData() + imageOffset); + imageOffset += sizeof(uint16_t); + + const auto ctxData = ctx->getData(); + offsetRowContext = offsetContext; + + for (uint32_t vec = 0; vec < vecCount; ++vec) { + + uint16_t vecOffset = *(vecMap->getData() + imageOffset); + imageOffset += sizeof(uint16_t); + uint16_t vecLength = *(vecMap->getData() + imageOffset); + imageOffset += sizeof(uint8_t); + uint8_t vecColor = *(vecMap->getData() + imageOffset); + imageOffset += sizeof(uint8_t); + + offsetRowContext += vecOffset; + if (vecColor != alphaColor) { + std::memset(ctxData + offsetRowContext, vecColor, std::min(ctx->getW(), vecLength)); + } + offsetRowContext += vecLength; + } + offsetContext += ctx->getW(); + } + } + + void DrawImage::draw(Context *ctx) const + { + // retrieve pixmap from the pixmap manager + ImageMap *imageMap = ImageManager::getInstance().getImageMap(imageID); + + // if image is not found return; + if (imageMap == nullptr) { + return; + } + + // get copy of original context using x,y of draw coordinates and original size of the widget + Context *drawCtx = ctx->get(origin.x, origin.y, areaW, areaH); + + if (imageMap->getType() == gui::ImageMap::Type::PIXMAP) { + auto pixMap = dynamic_cast(imageMap); + assert(pixMap); + drawPixMap(drawCtx, pixMap); + } + else if (imageMap->getType() == gui::ImageMap::Type::VECMAP) { + auto vecMap = dynamic_cast(imageMap); + assert(vecMap); + drawVecMap(drawCtx, vecMap); + } + + // reinsert drawCtx into bast context + ctx->insert(origin.x, origin.y, drawCtx); + + // remove draw context + delete drawCtx; + } +} /* namespace gui */ diff --git a/module-gui/gui/core/DrawCommand.hpp b/module-gui/gui/core/DrawCommand.hpp index 7e9f7c43f3df30de8189cf828ff8a05c7cd6ecac..28b3413593ce6ac1214b25b1575e604515bfcb1a 100644 --- a/module-gui/gui/core/DrawCommand.hpp +++ b/module-gui/gui/core/DrawCommand.hpp @@ -10,218 +10,170 @@ #include #include "Color.hpp" +#include "Context.hpp" +#include + +// image +#include "PixMap.hpp" +#include "VecMap.hpp" namespace gui { - - enum class DrawCommandID - { - GUI_DRAW_UNDEFINED = 0, - GUI_DRAW_CLEAR = 1, - GUI_DRAW_LINE, - GUI_DRAW_TRIANGLE, - GUI_DRAW_RECT, - GUI_DRAW_TEXT, - GUI_DRAW_ARC, - GUI_DRAW_PIE, - GUI_DRAW_CIRCLE, - GUI_DRAW_IMAGE, - GUI_DRAW_COMMANDS, // blob of many - GUI_RENDER_QUICK, - GUI_RENDER_DEEP, - GUI_RENDER_REFRESH // sent to applications so they can repaint current window - }; - + /** + * @brief Draw command interface. + */ class DrawCommand { public: - DrawCommandID id; + int16_t areaX{0}; + int16_t areaY{0}; + Length areaW{0}; + Length areaH{0}; - int16_t areaX; - int16_t areaY; - int16_t areaW; - int16_t areaH; + virtual ~DrawCommand() = default; - DrawCommand() : id{DrawCommandID::GUI_DRAW_UNDEFINED}, areaX{0}, areaY{0}, areaW{0}, areaH{0} {}; - virtual ~DrawCommand(){}; + virtual void draw(Context *ctx) const = 0; }; - class CommandRender : public DrawCommand + class Clear : public DrawCommand { - public: - std::string applicationName; - CommandRender() - { - id = DrawCommandID::GUI_RENDER_DEEP; - }; - }; - - class CommandLine : public DrawCommand - { - public: - int16_t x1; - int16_t y1; - int16_t x2; - int16_t y2; - Color color; - uint8_t penWidth; - - CommandLine() : x1{0}, y1{0}, x2{0}, y2{0}, color(ColorFullBlack), penWidth{1} - { - id = DrawCommandID::GUI_DRAW_LINE; - } + void draw(Context *ctx) const override; }; /** - * @brief Draw command for triangle. + * @brief Draw command for line. */ - class CommandTriangle : DrawCommand + class DrawLine : public DrawCommand { public: - int16_t x1; - int16_t y1; - int16_t x2; - int16_t y2; - int16_t x3; - int16_t y3; - Color fillColor; - gui::Color borderColor; - uint8_t penWidth; - - CommandTriangle() - : x1{0}, y1{0}, x2{0}, y2{0}, x3{0}, y3{0}, fillColor(ColorFullBlack), - borderColor(ColorFullBlack), penWidth{1} - { - id = DrawCommandID::GUI_DRAW_TRIANGLE; - } + Point start{0, 0}; + Point end{0, 0}; + Color color{ColorFullBlack}; + uint8_t penWidth{1}; + + public: + void draw(Context *ctx) const override; }; /** * @brief Draw command for rectangle. */ - class CommandRectangle : public DrawCommand + class DrawRectangle : public DrawCommand { public: - int16_t x; - int16_t y; - uint16_t w; - uint16_t h; - uint16_t radius; + Point origin{0, 0}; + Length width{0}; + Length height{0}; + Length radius{0}; + // flags that defines whether paint given border - RectangleEdge edges; + RectangleEdge edges{RectangleEdge::All}; // flags that defines which edge should be flat. This will disable roundness on both sides of the edge. - RectangleFlatEdge flatEdges; + RectangleFlatEdge flatEdges{RectangleFlatEdge::None}; // flags that defines whether paint given corner (only for rounded corners) - RectangleRoundedCorner corners; + RectangleRoundedCorner corners{RectangleRoundedCorner::All}; // flags indicating yaps for speech bubbles, it takes precendece over other properties - RectangleYap yaps; + RectangleYap yaps{RectangleYap::None}; // defines which of the edges and corners are painted - unsigned short yapSize = 0; - bool filled; - uint8_t penWidth; - Color fillColor; - Color borderColor; - CommandRectangle() - : x{0}, y{0}, w{0}, h{0}, radius{0}, edges{RectangleEdge::All}, flatEdges{RectangleFlatEdge::None}, - corners{RectangleRoundedCorner::All}, yaps{RectangleYap::None}, yapSize{0}, filled{false}, penWidth{1}, - fillColor(ColorFullBlack), borderColor(ColorFullBlack) - { - id = DrawCommandID::GUI_DRAW_RECT; - } + unsigned short yapSize{0}; + + bool filled{false}; + uint8_t penWidth{1}; + Color fillColor{ColorFullBlack}; + Color borderColor{ColorFullBlack}; + + public: + void draw(Context *ctx) const override; }; - class CommandArc : public DrawCommand + /** + * @brief Draw command for arc. + */ + class DrawArc : public DrawCommand { public: - CommandArc(Point _center, - Length _radius, - trigonometry::Degrees _start, - trigonometry::Degrees _sweep, - uint8_t _width, - Color _color) - : center{_center}, radius{_radius}, start{_start}, sweep{_sweep}, width{_width}, borderColor{_color} - { - id = DrawCommandID::GUI_DRAW_ARC; - } - - const Point center; - const Length radius; const trigonometry::Degrees start; const trigonometry::Degrees sweep; - const uint8_t width; + const Length width; const Color borderColor; + const Point center; + const Length radius; + + DrawArc(Point _center, + Length _radius, + trigonometry::Degrees _start, + trigonometry::Degrees _sweep, + Length _width, + Color _color) + : start{_start}, sweep{_sweep}, width{_width}, borderColor{_color}, center{_center}, radius{_radius} + {} + + void draw(Context *ctx) const override; }; /** * @brief Draw command for circle. */ - class CommandCircle : public CommandArc + class DrawCircle : public DrawArc { public: - CommandCircle(Point _center, - Length _radius, - uint8_t _borderWidth, - Color _borderColor, - bool _filled = false, - Color _fillColor = {}) - : CommandArc{_center, _radius, 0, trigonometry::FullAngle, _borderWidth, _borderColor}, filled{_filled}, - fillColor{_fillColor} - { - id = DrawCommandID::GUI_DRAW_CIRCLE; - } - const bool filled; const Color fillColor; + + DrawCircle(Point _center, + Length _radius, + Length _borderWidth, + Color _borderColor, + bool _filled = false, + Color _fillColor = {}) + : DrawArc{_center, _radius, 0, trigonometry::FullAngle, _borderWidth, _borderColor}, filled{_filled}, + fillColor{_fillColor} + {} + + void draw(Context *ctx) const override; }; /** * @brief Draw command for text line. */ - class CommandText : public DrawCommand + class DrawText : public DrawCommand { public: - // area where label wil lbe drawn - int16_t x; - int16_t y; - int16_t w; - int16_t h; + // area where label wil be drawn + Point origin{0, 0}; + Length width{0}; + Length height{0}; // area occupied by text inside the label - int16_t tx; - int16_t ty; - int16_t tw; - int16_t th; - uint16_t charsWidth; // number of visible pixels calculated - UTF8 str; - uint8_t fontID; - - Color color; - - CommandText() - : x{0}, y{0}, w{0}, h{0}, tx{0}, ty{0}, tw{0}, th{0}, charsWidth{0}, str{""}, fontID{0}, - color(ColorFullBlack) - { - id = DrawCommandID::GUI_DRAW_TEXT; - } + Point textOrigin{0, 0}; + Length textHeight{0}; + + UTF8 str{}; + uint8_t fontID{0}; + Color color{ColorFullBlack}; + + void draw(Context *ctx) const override; + + private: + void drawChar(Context *ctx, const Point glyphOrigin, FontGlyph *glyph) const; }; /** * @brief Draw command for image. */ - class CommandImage : public DrawCommand + class DrawImage : public DrawCommand { public: - int16_t x; - int16_t y; - uint16_t w; - uint16_t h; + Point origin{0, 0}; // ID of the image - uint16_t imageID; + uint16_t imageID{0}; + + void draw(Context *ctx) const override; - CommandImage() : x{0}, y{0}, w{0}, h{0}, imageID{0} - { - id = DrawCommandID::GUI_DRAW_IMAGE; - } + private: + void drawPixMap(Context *ctx, PixMap *pixMap) const; + void drawVecMap(Context *ctx, VecMap *vecMap) const; + inline void checkImageSize(Context *ctx, ImageMap *image) const; }; } /* namespace gui */ diff --git a/module-gui/gui/core/RawFont.cpp b/module-gui/gui/core/RawFont.cpp index ef0c1d275bab09d3c84e8d72f2de7969891833c8..d6323db57761be97974001866334a6739f449ec9 100644 --- a/module-gui/gui/core/RawFont.cpp +++ b/module-gui/gui/core/RawFont.cpp @@ -4,7 +4,7 @@ #include "RawFont.hpp" #include "Common.hpp" // for Status, Status::GUI_SUCCESS, Status::GU... #include "Context.hpp" // for Context -#include "DrawCommand.hpp" // for CommandRectangle, DrawCommand (ptr only) +#include "DrawCommand.hpp" // for DrawRectangle, DrawCommand (ptr only) #include "FontKerning.hpp" // for FontKerning #include "Renderer.hpp" // for Renderer #include "TextConstants.hpp" // for newline @@ -294,18 +294,17 @@ namespace gui unsupported->xadvance = unsupported->width + (2 * unsupported->xoffset); // use xoffset as margins on the left/right of the glyph // populate with a bitmap (glyph) - auto commandRect = std::make_unique(); - commandRect->x = 0; - commandRect->y = 0; - commandRect->w = unsupported->width; - commandRect->h = unsupported->height; + auto commandRect = std::make_unique(); + commandRect->origin = {0, 0}; + commandRect->width = unsupported->width; + commandRect->height = unsupported->height; commandRect->areaX = 0; commandRect->areaY = 0; commandRect->areaW = unsupported->width; commandRect->areaH = unsupported->height; commandRect->penWidth = unsupported->xoffset; - auto renderCtx = std::make_unique(unsupported->width, unsupported->height); + auto renderCtx = std::make_unique(unsupported->width, unsupported->height); std::list> commands; commands.emplace_back(std::move(commandRect)); Renderer().render(renderCtx.get(), commands); diff --git a/module-gui/gui/core/Renderer.cpp b/module-gui/gui/core/Renderer.cpp index aef6e9882001899ff076485a0a0b36cfbdbf3b9c..45f0b6156a07092353696891277c766fdbec2daa 100644 --- a/module-gui/gui/core/Renderer.cpp +++ b/module-gui/gui/core/Renderer.cpp @@ -1,327 +1,24 @@ -// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md -extern "C" -{ -#include "FreeRTOS.h" -#include "task.h" -} - // for memset -#include -#include "Color.hpp" #include "Renderer.hpp" #include "Context.hpp" -#include "ImageManager.hpp" -#include "../Common.hpp" -// renderers -#include "renderers/LineRenderer.hpp" -#include "renderers/ArcRenderer.hpp" -#include "renderers/CircleRenderer.hpp" -#include "renderers/RectangleRenderer.hpp" -// utils -#include "log/log.hpp" - -#include "PixMap.hpp" -#include "VecMap.hpp" -// module-utils -#include "utf8/UTF8.hpp" -#include -#include -#include -#include -#include -#include "Style.hpp" -#include "Common.hpp" - -#if DEBUG_FONT == 1 -#define log_warn_glyph(...) LOG_WARN(__VA_ARGS__) -#else -#define log_warn_glyph(...) -#endif namespace gui { - void Renderer::drawLine(Context *ctx, CommandLine *cmd) - { - using renderer::LineRenderer; - const Point p1{cmd->x1, cmd->y1}; - const Point p2{cmd->x2, cmd->y2}; - const auto color = cmd->color; - LineRenderer::draw(ctx, p1, p2, color); - } - - void Renderer::drawRectangle(Context *ctx, CommandRectangle *cmd) - { - using renderer::RectangleRenderer; - - // First, check if there is anything to draw - if (cmd->w == 0 || cmd->h == 0) { - return; - } - if (cmd->fillColor.alpha == Color::FullTransparent && cmd->borderColor.alpha == Color::FullTransparent) { - return; - } - if (!cmd->filled && cmd->borderColor.alpha == Color::FullTransparent) { - return; - } - - Context *drawingContext = ctx; - Point position; - if (cmd->yaps & (RectangleYap::BottomLeft | RectangleYap::TopLeft)) { - position.x += cmd->yapSize; - } - Length width = cmd->areaW; - Length height = cmd->areaH; - if (cmd->yaps != RectangleYap::None) { - width -= cmd->yapSize; - } - - if (cmd->areaW == cmd->w && cmd->areaH == cmd->h) { - position.x += cmd->x; - position.y += cmd->y; - } - else { - const auto x = cmd->areaX < 0 ? cmd->x + cmd->areaX : cmd->x; - const auto y = cmd->areaY < 0 ? cmd->y + cmd->areaY : cmd->y; - drawingContext = ctx->get(x, y, cmd->areaW, cmd->areaH); - } - - Length radius = cmd->radius; - if (radius == 0) { - RectangleRenderer::drawFlat( - drawingContext, position, width, height, RectangleRenderer::DrawableStyle::from(*cmd)); - } - else { - RectangleRenderer::draw( - drawingContext, position, width, height, RectangleRenderer::DrawableStyle::from(*cmd)); - } - - if (drawingContext != ctx) { - ctx->insertArea(cmd->x, cmd->y, cmd->areaX, cmd->areaY, cmd->w, cmd->h, drawingContext); - delete drawingContext; - } - } - - void Renderer::drawArc(Context *ctx, CommandArc *cmd) - { - using renderer::ArcRenderer; - const auto center{cmd->center}; - const auto radius{cmd->radius}; - const auto startAngle{cmd->start}; - const auto sweepAngle{cmd->sweep}; - const auto style = ArcRenderer::DrawableStyle::from(*cmd); - ArcRenderer::draw(ctx, center, radius, startAngle, sweepAngle, style); - } - - void Renderer::drawCircle(Context *ctx, CommandCircle *cmd) - { - using renderer::CircleRenderer; - const auto center{cmd->center}; - const auto radius{cmd->radius}; - const auto style = CircleRenderer::DrawableStyle::from(*cmd); - CircleRenderer::draw(ctx, center, radius, style); - } - - void Renderer::drawChar(Context *context, const int16_t x, const int16_t y, FontGlyph *glyph, const Color color) - { - auto line_y_offset = (y - glyph->yoffset) * context->getW(); - auto *drawPtr = context->getData() + x + line_y_offset; - auto *glyphPtr = glyph->data; - assert(glyph->data); - - for (uint16_t yy = 0; yy < glyph->height; ++yy) { - for (uint16_t xx = 0; xx < glyph->width; ++xx) { - if (!context->addressInData(drawPtr + xx)) { - log_warn_glyph("drawing out of: %d vs %d", xx, context->getW() * context->getH()); - return; - } - if (*(glyphPtr + xx) == 0) { - *(drawPtr + xx) = 0x0F & color.intensity; - } - } - drawPtr += context->getW(); - glyphPtr += glyph->width; - } - } - - void Renderer::drawText(Context *ctx, CommandText *cmd) - { - - // check if there are any characters to draw in the string provided with message. - if (cmd->str.length() == 0) { - return; - } - - // get copy of original context using x,y of draw coordinates and original size of the widget - Context *drawCtx; - bool copyContext = false; - int16_t wgtX = 0, wgtY = 0; - // check if there is a need or making copy of context to use it as background - if ((cmd->areaW == cmd->w) && (cmd->areaH == cmd->h)) { - drawCtx = ctx; - wgtX = cmd->x; - wgtY = cmd->y; - } - else { - copyContext = true; - drawCtx = ctx->get(cmd->x, cmd->y, cmd->areaW, cmd->areaH); - } - - // retrieve font used to draw text - FontManager &fontManager = FontManager::getInstance(); - RawFont *font = fontManager.getFont(cmd->fontID); - - int16_t posX = cmd->tx; - int16_t posY = cmd->ty; - - // draw every sign - uint32_t idLast = 0, idCurrent = 0; - for (uint32_t i = 0; i < cmd->str.length(); ++i) { - idCurrent = cmd->str[i]; // id stands for glued together utf-16 with no order bytes (0xFF 0xFE) - FontGlyph *glyph = font->getGlyph(idCurrent); - - // do not start drawing outside of draw context. - if ((wgtX + posX + glyph->xoffset >= drawCtx->getW()) || (wgtX + posX + glyph->xoffset < 0)) { - LOG_FATAL("Drawing outside context's X boundary for glyph: %" PRIu32, glyph->id); - return; - } - if ((wgtY + posY >= drawCtx->getH()) || (wgtY + posY < 0)) { - LOG_FATAL("Drawing outside context's Y boundary for glyph: %" PRIu32, glyph->id); - return; - } - - int32_t kernValue = 0; - if (i > 0) { - kernValue = font->getKerning(idLast, idCurrent); - } - drawChar(drawCtx, wgtX + posX + glyph->xoffset + kernValue, wgtY + posY, glyph, cmd->color); - posX += glyph->xadvance + kernValue; - - idLast = idCurrent; - } - - // if drawing was performed in temporary context - // reinsert drawCtx into bast context - if (copyContext) { - ctx->insert(cmd->x, cmd->y, drawCtx); - delete drawCtx; - } - } - - void Renderer::drawImage(Context *ctx, CommandImage *cmd) - { - - // retrive pixmap from the pixmap manager - ImageMap *imageMap = ImageManager::getInstance().getImageMap(cmd->imageID); - - // if image is not found return; - if (imageMap == nullptr) - return; - - // get copy of original context using x,y of draw coordinates and original size of the widget - Context *drawCtx = ctx->get(cmd->x, cmd->y, cmd->areaW, cmd->areaH); - uint8_t *ctxData = drawCtx->getData(); - - auto check_wh = [&](const std::string &name, auto w, auto h) { - if (h > ctx->getH() || w > ctx->getW()) { - LOG_WARN("image %s {w: %d,h %d} > context {w %d,h %d}", - name.c_str(), - w, - drawCtx->getW(), - h, - drawCtx->getH()); - } - }; - - if (imageMap->getType() == gui::ImageMap::Type::PIXMAP) { - auto pixMap = dynamic_cast(imageMap); - assert(pixMap); - uint32_t offsetImage = 0; - uint32_t offsetContext = 0; - uint8_t *pixData = pixMap->getData(); - check_wh(pixMap->getName(), pixMap->getWidth(), pixMap->getHeight()); - - for (uint32_t row = 0; row < std::min(drawCtx->getH(), pixMap->getHeight()); row++) { - memcpy(ctxData + offsetContext, pixData + offsetImage, std::min(drawCtx->getW(), pixMap->getWidth())); - offsetImage += pixMap->getWidth(); - offsetContext += drawCtx->getW(); - } - } - else if (imageMap->getType() == gui::ImageMap::Type::VECMAP) { - auto vecMap = dynamic_cast(imageMap); - assert(vecMap); - uint32_t offsetContext = 0; - uint32_t offsetRowContext = 0; - uint32_t imageOffset = 0; - uint8_t alphaColor = vecMap->getAlphaColor(); - for (uint32_t row = 0; row < std::min(vecMap->getHeight(), drawCtx->getH()); row++) { - check_wh(vecMap->getName(), imageMap->getWidth(), imageMap->getHeight()); - uint16_t vecCount = *(vecMap->getData() + imageOffset); - imageOffset += sizeof(uint16_t); - - offsetRowContext = offsetContext; - - for (uint32_t vec = 0; vec < vecCount; ++vec) { - - uint16_t vecOffset = *(vecMap->getData() + imageOffset); - imageOffset += sizeof(uint16_t); - uint16_t vecLength = *(vecMap->getData() + imageOffset); - imageOffset += sizeof(uint8_t); - uint8_t vecColor = *(vecMap->getData() + imageOffset); - imageOffset += sizeof(uint8_t); - - offsetRowContext += vecOffset; - if (vecColor != alphaColor) { - memset(ctxData + offsetRowContext, vecColor, std::min(drawCtx->getW(), vecLength)); - } - offsetRowContext += vecLength; - } - offsetContext += drawCtx->getW(); - } - } - - // reinsert drawCtx into bast context - ctx->insert(cmd->x, cmd->y, drawCtx); - - // remove draw context - delete drawCtx; - } - void Renderer::render(Context *ctx, std::list> &commands) { if (ctx == nullptr) { return; } + for (auto &cmd : commands) { if (cmd == nullptr) { continue; } - switch (cmd->id) { - case DrawCommandID::GUI_DRAW_CLEAR: - ctx->fill(15); - break; - case DrawCommandID::GUI_DRAW_LINE: - drawLine(ctx, static_cast(cmd.get())); - break; - case DrawCommandID::GUI_DRAW_RECT: - drawRectangle(ctx, static_cast(cmd.get())); - break; - case DrawCommandID::GUI_DRAW_ARC: - drawArc(ctx, static_cast(cmd.get())); - break; - case DrawCommandID::GUI_DRAW_CIRCLE: - drawCircle(ctx, static_cast(cmd.get())); - break; - case DrawCommandID::GUI_DRAW_TEXT: - drawText(ctx, static_cast(cmd.get())); - break; - case DrawCommandID::GUI_DRAW_IMAGE: - drawImage(ctx, static_cast(cmd.get())); - break; - default: - break; - }; + + cmd->draw(ctx); } } diff --git a/module-gui/gui/core/Renderer.hpp b/module-gui/gui/core/Renderer.hpp index abd7665ab63c0e06c852b5b8dbdebce26c5bd29d..539ccf9fc56e97dbe3d9ead79929687045324993 100644 --- a/module-gui/gui/core/Renderer.hpp +++ b/module-gui/gui/core/Renderer.hpp @@ -32,20 +32,6 @@ namespace gui * 3 * */ - protected: - void drawLine(Context *ctx, CommandLine *cmd); - - void drawRectangle(Context *ctx, CommandRectangle *cmd); - - void drawArc(Context *ctx, CommandArc *cmd); - - void drawCircle(Context *ctx, CommandCircle *cmd); - - void drawText(Context *ctx, CommandText *cmd); - - void drawChar(Context *context, const int16_t x, const int16_t y, FontGlyph *glyph, const Color color); - - void drawImage(Context *ctx, CommandImage *cmd); public: virtual ~Renderer() = default; diff --git a/module-gui/gui/core/renderers/ArcRenderer.cpp b/module-gui/gui/core/renderers/ArcRenderer.cpp index def65d60434f128fe45abe81ff451da170a71475..f6386b9bcdedf6f625e5e3e595fd1d480c73ae64 100644 --- a/module-gui/gui/core/renderers/ArcRenderer.cpp +++ b/module-gui/gui/core/renderers/ArcRenderer.cpp @@ -8,7 +8,7 @@ namespace gui::renderer { constexpr Length RadiusPrecisionLimit = 5; - auto ArcRenderer::DrawableStyle::from(const CommandArc &command) -> DrawableStyle + auto ArcRenderer::DrawableStyle::from(const DrawArc &command) -> DrawableStyle { return DrawableStyle{command.width, command.borderColor}; } diff --git a/module-gui/gui/core/renderers/ArcRenderer.hpp b/module-gui/gui/core/renderers/ArcRenderer.hpp index f2d1f745866cae237b192066870927862e178e65..b7f567d7257f1a35d2a64f6f685f8b0c2488b106 100644 --- a/module-gui/gui/core/renderers/ArcRenderer.hpp +++ b/module-gui/gui/core/renderers/ArcRenderer.hpp @@ -25,7 +25,7 @@ namespace gui::renderer Length penWidth{1}; Color color{ColorFullBlack}; - static auto from(const CommandArc &command) -> DrawableStyle; + static auto from(const DrawArc &command) -> DrawableStyle; }; static void draw(Context *ctx, diff --git a/module-gui/gui/core/renderers/CircleRenderer.cpp b/module-gui/gui/core/renderers/CircleRenderer.cpp index d16d52c3b5d87b70636b1359881728c9d8db6df2..46764bc786e9b08d761819dc4449aba3c09682e8 100644 --- a/module-gui/gui/core/renderers/CircleRenderer.cpp +++ b/module-gui/gui/core/renderers/CircleRenderer.cpp @@ -8,7 +8,7 @@ namespace gui::renderer { - auto CircleRenderer::DrawableStyle::from(const CommandCircle &command) -> DrawableStyle + auto CircleRenderer::DrawableStyle::from(const DrawCircle &command) -> DrawableStyle { return DrawableStyle{command.width, command.borderColor, command.filled ? command.fillColor : ColorNoColor}; } diff --git a/module-gui/gui/core/renderers/CircleRenderer.hpp b/module-gui/gui/core/renderers/CircleRenderer.hpp index adeef4e68d0b3b998f80346de14429ae4d042312..0c4c8206394cb88c3680a48f4ef9145d21a1c457 100644 --- a/module-gui/gui/core/renderers/CircleRenderer.hpp +++ b/module-gui/gui/core/renderers/CircleRenderer.hpp @@ -24,7 +24,7 @@ namespace gui::renderer Color borderColor{ColorFullBlack}; Color fillColor{ColorNoColor}; - static auto from(const CommandCircle &command) -> DrawableStyle; + static auto from(const DrawCircle &command) -> DrawableStyle; }; static void draw(Context *ctx, Point center, Length radius, const DrawableStyle &style); diff --git a/module-gui/gui/core/renderers/LineRenderer.cpp b/module-gui/gui/core/renderers/LineRenderer.cpp index 8726526b5fd9c83bc88a396ba37cfbb891bd4aee..965876df04be5f4d3f0c8c32819983345534556d 100644 --- a/module-gui/gui/core/renderers/LineRenderer.cpp +++ b/module-gui/gui/core/renderers/LineRenderer.cpp @@ -27,7 +27,7 @@ namespace gui::renderer } } // namespace - auto LineRenderer::DrawableStyle::from(const CommandLine &command) -> DrawableStyle + auto LineRenderer::DrawableStyle::from(const DrawLine &command) -> DrawableStyle { DrawableStyle details; details.penWidth = command.penWidth; diff --git a/module-gui/gui/core/renderers/LineRenderer.hpp b/module-gui/gui/core/renderers/LineRenderer.hpp index 0ea39facdd5f42ec86daea8f7010f6b73baa584c..a3aaa784de3fafe3c21f4ab195e0ed644b374da5 100644 --- a/module-gui/gui/core/renderers/LineRenderer.hpp +++ b/module-gui/gui/core/renderers/LineRenderer.hpp @@ -32,7 +32,7 @@ namespace gui::renderer Color color{ColorFullBlack}; LineExpansionDirection direction = LineExpansionDirection::Down; - static auto from(const CommandLine &command) -> DrawableStyle; + static auto from(const DrawLine &command) -> DrawableStyle; DrawableStyle &setExpansionDirection(LineExpansionDirection value) noexcept { diff --git a/module-gui/gui/core/renderers/PixelRenderer.cpp b/module-gui/gui/core/renderers/PixelRenderer.cpp index 2419a3ebaf8cf8813ffed216972d703a63fbb2c7..47cd8511c5e8bd7b5f92be71135624f4dcbfa147 100644 --- a/module-gui/gui/core/renderers/PixelRenderer.cpp +++ b/module-gui/gui/core/renderers/PixelRenderer.cpp @@ -2,7 +2,6 @@ // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "PixelRenderer.hpp" - #include "Context.hpp" #include diff --git a/module-gui/gui/core/renderers/RectangleRenderer.cpp b/module-gui/gui/core/renderers/RectangleRenderer.cpp index 326470454e28f6845eafc8fe1b4e0a6b235e97e0..8cc761571712c9508b2448b3211f123f8f405d3a 100644 --- a/module-gui/gui/core/renderers/RectangleRenderer.cpp +++ b/module-gui/gui/core/renderers/RectangleRenderer.cpp @@ -26,7 +26,7 @@ namespace gui::renderer } } // namespace - auto RectangleRenderer::DrawableStyle::from(const CommandRectangle &command) -> DrawableStyle + auto RectangleRenderer::DrawableStyle::from(const DrawRectangle &command) -> DrawableStyle { return DrawableStyle{command.penWidth, command.radius, diff --git a/module-gui/gui/core/renderers/RectangleRenderer.hpp b/module-gui/gui/core/renderers/RectangleRenderer.hpp index 7a617adb4acb05d0d4c88aca4ab78ea22e6c82f7..c86d06b8ab5466b061b4ba095c4f95aed6f5c0ed 100644 --- a/module-gui/gui/core/renderers/RectangleRenderer.hpp +++ b/module-gui/gui/core/renderers/RectangleRenderer.hpp @@ -30,7 +30,7 @@ namespace gui::renderer Color borderColor{ColorFullBlack}; Color fillColor{ColorNoColor}; - static auto from(const CommandRectangle &command) -> DrawableStyle; + static auto from(const DrawRectangle &command) -> DrawableStyle; }; static void drawFlat(Context *ctx, Point position, Length width, Length height, const DrawableStyle &style); diff --git a/module-gui/gui/widgets/Arc.cpp b/module-gui/gui/widgets/Arc.cpp index f4b68c7d55b49972c29caebb48cf1b88ec077c3f..ea1713fadf7a46a994908588b74fa6e775853c7b 100644 --- a/module-gui/gui/widgets/Arc.cpp +++ b/module-gui/gui/widgets/Arc.cpp @@ -106,7 +106,7 @@ namespace gui void Arc::buildDrawListImplementation(std::list &commands) { - auto arc = std::make_unique(center, radius, start, sweep, focus ? focusPenWidth : penWidth, color); + auto arc = std::make_unique(center, radius, start, sweep, focus ? focusPenWidth : penWidth, color); arc->areaX = widgetArea.x; arc->areaY = widgetArea.y; arc->areaW = widgetArea.w; diff --git a/module-gui/gui/widgets/Circle.cpp b/module-gui/gui/widgets/Circle.cpp index 095ceefce14bf3a7f624c605f155464ce4f02d73..b0c421962f1409f87ced2e015107cab3a7f8079a 100644 --- a/module-gui/gui/widgets/Circle.cpp +++ b/module-gui/gui/widgets/Circle.cpp @@ -77,7 +77,7 @@ namespace gui void Circle::buildDrawListImplementation(std::list &commands) { - auto circle = std::make_unique( + auto circle = std::make_unique( center, radius, focus ? focusPenWidth : penWidth, focus ? focusBorderColor : color, isFilled, fillColor); circle->areaX = widgetArea.x; circle->areaY = widgetArea.y; diff --git a/module-gui/gui/widgets/Image.cpp b/module-gui/gui/widgets/Image.cpp index f070bc151f15409f7f96e5391c84a05396c97d4b..c4b02a1e25f8cfe844eadf0e3b838819b58ee4dc 100644 --- a/module-gui/gui/widgets/Image.cpp +++ b/module-gui/gui/widgets/Image.cpp @@ -52,17 +52,14 @@ namespace gui void Image::buildDrawListImplementation(std::list &commands) { - auto img = std::make_unique(); + auto img = std::make_unique(); // image - img->x = drawArea.x; - img->y = drawArea.y; - img->w = drawArea.w; - img->h = drawArea.h; + img->origin = {drawArea.x, drawArea.y}; // cmd part - img->areaX = img->x; - img->areaY = img->y; - img->areaW = img->w; - img->areaH = img->h; + img->areaX = img->origin.x; + img->areaY = img->origin.y; + img->areaW = drawArea.w; + img->areaH = drawArea.h; img->imageID = this->imageMap->getID(); diff --git a/module-gui/gui/widgets/Label.cpp b/module-gui/gui/widgets/Label.cpp index dcfe22d7bc3c18a9b9328f03dfcf4da21297a7b8..3d2e17ce60a2e6037c4def8db9b99215e0e4c3ca 100644 --- a/module-gui/gui/widgets/Label.cpp +++ b/module-gui/gui/widgets/Label.cpp @@ -219,20 +219,16 @@ namespace gui { Rect::buildDrawListImplementation(commands); if (font != nullptr) { - auto cmd = std::make_unique(); + auto cmd = std::make_unique(); cmd->str = textDisplayed; cmd->fontID = font->id; cmd->color = textColor; - cmd->x = drawArea.x; - cmd->y = drawArea.y; - cmd->w = drawArea.w; - cmd->h = drawArea.h; - cmd->tx = textArea.x; - cmd->ty = textArea.y; - cmd->tw = textArea.w; - cmd->th = textArea.h; - cmd->charsWidth = stringPixelWidth; + cmd->origin = {drawArea.x, drawArea.y}; + cmd->width = drawArea.w; + cmd->height = drawArea.h; + cmd->textOrigin = {textArea.x, textArea.y}; + cmd->textHeight = textArea.h; cmd->areaX = widgetArea.x; cmd->areaY = widgetArea.y; diff --git a/module-gui/gui/widgets/Rect.cpp b/module-gui/gui/widgets/Rect.cpp index 5ee09f64cd1f6ba5db94ac4e258ed1216a97532c..6665b4bc6b11f6e6a25bbfcf87de185e7aee3857 100644 --- a/module-gui/gui/widgets/Rect.cpp +++ b/module-gui/gui/widgets/Rect.cpp @@ -96,12 +96,11 @@ namespace gui void Rect::buildDrawListImplementation(std::list &commands) { - auto rect = std::make_unique(); + auto rect = std::make_unique(); - rect->x = drawArea.x; - rect->y = drawArea.y; - rect->w = drawArea.w; - rect->h = drawArea.h; + rect->origin = {drawArea.x, drawArea.y}; + rect->width = drawArea.w; + rect->height = drawArea.h; rect->areaX = widgetArea.x; rect->areaY = widgetArea.y; rect->areaW = widgetArea.w; diff --git a/module-gui/gui/widgets/Window.cpp b/module-gui/gui/widgets/Window.cpp index e3f4c3fdb385d55324161d6a6f6a8512f721a872..e8ef2743193e93c27e281bc21ca83c3f7b042b51 100644 --- a/module-gui/gui/widgets/Window.cpp +++ b/module-gui/gui/widgets/Window.cpp @@ -28,10 +28,10 @@ namespace gui void Window::getRefreshArea(uint16_t &x, uint16_t &y, uint16_t &w, uint16_t &h) { - x = widgetArea.x; - y = widgetArea.y; - w = widgetArea.w; - h = widgetArea.h; + x = widgetArea.x; + y = widgetArea.y; + w = widgetArea.w; + h = widgetArea.h; } bool Window::handleSwitchData(SwitchData *data) @@ -41,8 +41,7 @@ namespace gui void Window::buildDrawListImplementation(std::list &commands) { - auto clearCommand = std::make_unique(); - clearCommand->id = DrawCommandID::GUI_DRAW_CLEAR; + auto clearCommand = std::make_unique(); commands.emplace_back(std::move(clearCommand)); }