~aleteoryx/muditaos

e6fdf0e22cba3b9d8ef0ef8b463e0a0539a1048e — Maciej Janicki 5 years ago 1db3f19
[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.
M module-gui/gui/core/Context.hpp => module-gui/gui/core/Context.hpp +7 -1
@@ 13,7 13,7 @@

#include <cstdint>
#include <iostream>
#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<uint32_t>(point.x) <= w) &&
                   (point.y >= 0 && static_cast<uint32_t>(point.y) <= h);
        }

        friend std::ostream &operator<<(std::ostream &out, const Context &c);
    };


M module-gui/gui/core/DrawCommand.cpp => module-gui/gui/core/DrawCommand.cpp +284 -9
@@ 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 <renderers/PixelRenderer.hpp>
// text rendering
#include "FontManager.hpp"
#include "RawFont.hpp"
// utils
#include "log/log.hpp"
// module-utils
#include <cmath>
#include <cassert>

#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<PixMap *>(imageMap);
            assert(pixMap);
            drawPixMap(drawCtx, pixMap);
        }
        else if (imageMap->getType() == gui::ImageMap::Type::VECMAP) {
            auto vecMap = dynamic_cast<VecMap *>(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 */

M module-gui/gui/core/DrawCommand.hpp => module-gui/gui/core/DrawCommand.hpp +101 -149
@@ 10,218 10,170 @@
#include <gui/Common.hpp>

#include "Color.hpp"
#include "Context.hpp"
#include <FontGlyph.hpp>

// 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 */

M module-gui/gui/core/RawFont.cpp => module-gui/gui/core/RawFont.cpp +6 -7
@@ 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<CommandRectangle>();
        commandRect->x        = 0;
        commandRect->y        = 0;
        commandRect->w        = unsupported->width;
        commandRect->h        = unsupported->height;
        auto commandRect      = std::make_unique<DrawRectangle>();
        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<Context>(unsupported->width, unsupported->height);
        auto renderCtx = std::make_unique<Context>(unsupported->width, unsupported->height);
        std::list<std::unique_ptr<gui::DrawCommand>> commands;
        commands.emplace_back(std::move(commandRect));
        Renderer().render(renderCtx.get(), commands);

M module-gui/gui/core/Renderer.cpp => module-gui/gui/core/Renderer.cpp +4 -307
@@ 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 <string.h>
#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 <cmath>
#include <cassert>
#include <FontManager.hpp>
#include <FontGlyph.hpp>
#include <RawFont.hpp>
#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<PixMap *>(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<VecMap *>(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<std::unique_ptr<DrawCommand>> &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<CommandLine *>(cmd.get()));
                break;
            case DrawCommandID::GUI_DRAW_RECT:
                drawRectangle(ctx, static_cast<CommandRectangle *>(cmd.get()));
                break;
            case DrawCommandID::GUI_DRAW_ARC:
                drawArc(ctx, static_cast<CommandArc *>(cmd.get()));
                break;
            case DrawCommandID::GUI_DRAW_CIRCLE:
                drawCircle(ctx, static_cast<CommandCircle *>(cmd.get()));
                break;
            case DrawCommandID::GUI_DRAW_TEXT:
                drawText(ctx, static_cast<CommandText *>(cmd.get()));
                break;
            case DrawCommandID::GUI_DRAW_IMAGE:
                drawImage(ctx, static_cast<CommandImage *>(cmd.get()));
                break;
            default:
                break;
            };

            cmd->draw(ctx);
        }
    }


M module-gui/gui/core/Renderer.hpp => module-gui/gui/core/Renderer.hpp +0 -14
@@ 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;

M module-gui/gui/core/renderers/ArcRenderer.cpp => module-gui/gui/core/renderers/ArcRenderer.cpp +1 -1
@@ 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};
    }

M module-gui/gui/core/renderers/ArcRenderer.hpp => module-gui/gui/core/renderers/ArcRenderer.hpp +1 -1
@@ 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,

M module-gui/gui/core/renderers/CircleRenderer.cpp => module-gui/gui/core/renderers/CircleRenderer.cpp +1 -1
@@ 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};
    }

M module-gui/gui/core/renderers/CircleRenderer.hpp => module-gui/gui/core/renderers/CircleRenderer.hpp +1 -1
@@ 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);

M module-gui/gui/core/renderers/LineRenderer.cpp => module-gui/gui/core/renderers/LineRenderer.cpp +1 -1
@@ 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;

M module-gui/gui/core/renderers/LineRenderer.hpp => module-gui/gui/core/renderers/LineRenderer.hpp +1 -1
@@ 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
            {

M module-gui/gui/core/renderers/PixelRenderer.cpp => module-gui/gui/core/renderers/PixelRenderer.cpp +0 -1
@@ 2,7 2,6 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "PixelRenderer.hpp"

#include "Context.hpp"

#include <cstring>

M module-gui/gui/core/renderers/RectangleRenderer.cpp => module-gui/gui/core/renderers/RectangleRenderer.cpp +1 -1
@@ 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,

M module-gui/gui/core/renderers/RectangleRenderer.hpp => module-gui/gui/core/renderers/RectangleRenderer.hpp +1 -1
@@ 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);

M module-gui/gui/widgets/Arc.cpp => module-gui/gui/widgets/Arc.cpp +1 -1
@@ 106,7 106,7 @@ namespace gui

    void Arc::buildDrawListImplementation(std::list<Command> &commands)
    {
        auto arc = std::make_unique<CommandArc>(center, radius, start, sweep, focus ? focusPenWidth : penWidth, color);
        auto arc   = std::make_unique<DrawArc>(center, radius, start, sweep, focus ? focusPenWidth : penWidth, color);
        arc->areaX = widgetArea.x;
        arc->areaY = widgetArea.y;
        arc->areaW = widgetArea.w;

M module-gui/gui/widgets/Circle.cpp => module-gui/gui/widgets/Circle.cpp +1 -1
@@ 77,7 77,7 @@ namespace gui

    void Circle::buildDrawListImplementation(std::list<Command> &commands)
    {
        auto circle = std::make_unique<CommandCircle>(
        auto circle = std::make_unique<DrawCircle>(
            center, radius, focus ? focusPenWidth : penWidth, focus ? focusBorderColor : color, isFilled, fillColor);
        circle->areaX = widgetArea.x;
        circle->areaY = widgetArea.y;

M module-gui/gui/widgets/Image.cpp => module-gui/gui/widgets/Image.cpp +6 -9
@@ 52,17 52,14 @@ namespace gui

    void Image::buildDrawListImplementation(std::list<Command> &commands)
    {
        auto img = std::make_unique<CommandImage>();
        auto img = std::make_unique<DrawImage>();
        // 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();


M module-gui/gui/widgets/Label.cpp => module-gui/gui/widgets/Label.cpp +6 -10
@@ 219,20 219,16 @@ namespace gui
    {
        Rect::buildDrawListImplementation(commands);
        if (font != nullptr) {
            auto cmd    = std::make_unique<CommandText>();
            auto cmd    = std::make_unique<DrawText>();
            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;

M module-gui/gui/widgets/Rect.cpp => module-gui/gui/widgets/Rect.cpp +4 -5
@@ 96,12 96,11 @@ namespace gui

    void Rect::buildDrawListImplementation(std::list<Command> &commands)
    {
        auto rect = std::make_unique<CommandRectangle>();
        auto rect = std::make_unique<DrawRectangle>();

        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;

M module-gui/gui/widgets/Window.cpp => module-gui/gui/widgets/Window.cpp +5 -6
@@ 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<Command> &commands)
    {
        auto clearCommand         = std::make_unique<DrawCommand>();
        clearCommand->id          = DrawCommandID::GUI_DRAW_CLEAR;
        auto clearCommand = std::make_unique<Clear>();
        commands.emplace_back(std::move(clearCommand));
    }