~aleteoryx/muditaos

bb59805a8edfcd2c89aa369bf34c519dc840e4c3 — Maciej Janicki 5 years ago 7eebea8
[EGD-4822] Add color test window to settings app

Add new window to allow convenient display and globally
change used color intensities  for design and testing purposes.
Changes were introduced to Renderer as well as GUI service
to allow global change of used color scheme.
When using list, screen is deep refreshed each
time the color is changed.
Known issues:
Item focus borders (top,bottom) with changed black intensity
may not render properly, however it doesn't obscure the
target functionality.
M image/assets/lang/English.json => image/assets/lang/English.json +2 -0
@@ 414,6 414,8 @@
  "app_settings_apn_authtype": "Authentication type",
  "app_settings_apn_apntype": "APN Type",
  "app_settings_apn_apnprotocol" : "APN Protocol",
  "app_settings_title_color_test": "Display available colors",
  "app_settings_toolbar_reset": "RESET",
  "app_phonebook_title_main": "Contacts",
  "app_phonebook_search_win_contacts": "Contacts",
  "common_search_uc": "Search",

M module-apps/application-settings/ApplicationSettings.cpp => module-apps/application-settings/ApplicationSettings.cpp +4 -1
@@ 12,6 12,7 @@
#include "windows/Info.hpp"
#include "windows/LanguageWindow.hpp"
#include "windows/SettingsMainWindow.hpp"
#include "windows/ColorTestWindow.hpp"

#include "windows/UITestWindow.hpp"



@@ 149,10 150,12 @@ namespace app
        windowsFactory.attach(gui::window::name::fota_window, [](Application *app, const std::string &name) {
            return std::make_unique<gui::FotaWindow>(app);
        });

        windowsFactory.attach(gui::window::name::eink, [](Application *app, const std::string &name) {
            return std::make_unique<gui::EinkModeWindow>(app);
        });
        windowsFactory.attach(gui::window::name::color_test_window, [](Application *app, const std::string &name) {
            return std::make_unique<gui::ColorTestWindow>(app);
        });

        if (board == bsp::Board::T4) {
            windowsFactory.attach(gui::window::cellular_passthrough::window_name,

M module-apps/application-settings/CMakeLists.txt => module-apps/application-settings/CMakeLists.txt +4 -0
@@ 27,6 27,10 @@ target_sources( ${PROJECT_NAME}
        windows/FotaWindow.cpp
        windows/Fota.cpp
        windows/EinkModeWindow.cpp
        windows/ColorTestWindow.cpp
        widgets/ColorTestListItem.cpp
        widgets/ColorTestListView.cpp
        models/ColorTestModel.cpp

    PUBLIC
        ApplicationSettings.hpp

A module-apps/application-settings/models/ColorTestModel.cpp => module-apps/application-settings/models/ColorTestModel.cpp +60 -0
@@ 0,0 1,60 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "application-settings/widgets/ColorTestListStyle.hpp"
#include "ColorTestModel.hpp"

namespace gui
{

    ColorTestModel::ColorTestModel(app::Application *app) : application{app}
    {
        createData();
    }

    auto ColorTestModel::requestRecordsCount() -> unsigned int
    {
        return internalData.size();
    }

    unsigned int ColorTestModel::getMinimalItemHeight() const
    {
        return style::colorTest::item::color::height;
    }

    gui::ListItem *ColorTestModel::getItem(gui::Order order)
    {
        return getRecord(order);
    }

    void ColorTestModel::requestRecords(const uint32_t offset, const uint32_t limit)
    {
        setupModel(offset, limit);
        list->onProviderDataUpdate();
    }

    void ColorTestModel::createData()
    {
        internalData.clear();

        for (Color color = gui::ColorFullBlack; color.intensity != (gui::ColorFullWhite.intensity + 1);
             ++color.intensity) {
            auto newColorListItem          = new ColorTestListItem(application, color);
            newColorListItem->deleteByList = false;
            internalData.push_back(newColorListItem);
        }
    }

    gui::ColorScheme ColorTestModel::getColorScheme()
    {
        gui::ColorScheme scheme = gui::Color::defaultColorScheme;
        int i                   = 0;

        for (auto const &item : internalData) {
            scheme.intensity[i] = item->getColorIntensity();
            ++i;
        }

        return scheme;
    }
} // namespace gui

A module-apps/application-settings/models/ColorTestModel.hpp => module-apps/application-settings/models/ColorTestModel.hpp +30 -0
@@ 0,0 1,30 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "Application.hpp"
#include "InternalModel.hpp"
#include "module-apps/application-settings/widgets/ColorTestListItem.hpp"
#include <ListView.hpp>
#include <ListItemProvider.hpp>

namespace gui
{
    class ColorTestModel : public app::InternalModel<gui::ColorTestListItem *>, public gui::ListItemProvider
    {
      private:
        app::Application *application = nullptr;

      public:
        explicit ColorTestModel(app::Application *app);

        [[nodiscard]] auto requestRecordsCount() -> unsigned int override;
        [[nodiscard]] auto getMinimalItemHeight() const -> unsigned int override;
        gui::ListItem *getItem(gui::Order order) override;
        void requestRecords(const uint32_t offset, const uint32_t limit) override;
        void createData();

        [[nodiscard]] gui::ColorScheme getColorScheme();
    };
} // namespace gui

A module-apps/application-settings/widgets/ColorTestListItem.cpp => module-apps/application-settings/widgets/ColorTestListItem.cpp +72 -0
@@ 0,0 1,72 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <string>

#include "ColorTestListStyle.hpp"
#include "ColorTestListItem.hpp"

namespace gui
{

    ColorTestListItem::ColorTestListItem(app::Application *app, const Color color) : app{app}
    {
        setMinimumSize(style::listview::item_width_with_scroll, style::colorTest::item::color::height);
        setMargins(Margins(style::margins::very_big, 0, 0, 0));

        vBox = new VBox(this, 0, 0, 0, 0);
        vBox->setEdges(RectangleEdge::None);
        vBox->setMinimumSize(style::colorTest::item::color::width, style::colorTest::listview::height);
        vBox->setFillColor(color);

        colorLabel = new Label(vBox, 0, 0, 0, 0);
        colorLabel->setEdges(gui::RectangleEdge::None);
        colorLabel->setMinimumSize(style::colorTest::item::color::width, style::colorTest::item::color::height);
        colorLabel->setAlignment(Alignment{gui::Alignment::Horizontal::Right, gui::Alignment::Vertical::Top});
        colorLabel->setText(std::to_string(color.intensity) + " ");

        if (color.intensity > ColorGrey.intensity) {
            colorLabel->setTextColor(ColorFullBlack);
        }
        else {
            colorLabel->setTextColor(ColorFullWhite);
        }
    }

    bool ColorTestListItem::onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim)
    {
        vBox->setPosition(0, 0);
        vBox->setSize(newDim.w, newDim.h);
        return true;
    }

    bool ColorTestListItem::onInput(const InputEvent &inputEvent)
    {
        bool handled = false;

        if (inputEvent.isShortPress()) {
            if (inputEvent.is(KeyCode::KEY_LEFT)) {
                if (auto color = vBox->fillColor; color.intensity != ::gui::ColorFullBlack.intensity) {
                    color.intensity--;
                    vBox->setFillColor(color);
                    app->refreshWindow(RefreshModes::GUI_REFRESH_DEEP);
                }
                handled = true;
            }
            else if (inputEvent.is(KeyCode::KEY_RIGHT)) {
                if (auto color = vBox->fillColor; color.intensity != ::gui::ColorFullWhite.intensity) {
                    color.intensity++;
                    vBox->setFillColor(color);
                    app->refreshWindow(RefreshModes::GUI_REFRESH_DEEP);
                }
                handled = true;
            }
        }
        return handled;
    }

    uint8_t ColorTestListItem::getColorIntensity()
    {
        return vBox->fillColor.intensity;
    }
} // namespace gui

A module-apps/application-settings/widgets/ColorTestListItem.hpp => module-apps/application-settings/widgets/ColorTestListItem.hpp +31 -0
@@ 0,0 1,31 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <memory>

#include <BoxLayout.hpp>
#include <Label.hpp>
#include <ListItem.hpp>
#include <InputEvent.hpp>

#include "Application.hpp"

namespace gui
{
    class ColorTestListItem : public ListItem
    {
      private:
        VBox *vBox        = nullptr;
        Label *colorLabel = nullptr;
        app::Application *app;

      public:
        explicit ColorTestListItem(app::Application *app, const Color color);

        bool onInput(const InputEvent &inputEvent) override;
        bool onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) override;
        [[nodiscard]] uint8_t getColorIntensity();
    };
} /* namespace gui */

A module-apps/application-settings/widgets/ColorTestListStyle.hpp => module-apps/application-settings/widgets/ColorTestListStyle.hpp +36 -0
@@ 0,0 1,36 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <Style.hpp>

namespace style::colorTest
{
    namespace listview
    {
        inline constexpr auto x      = style::window::default_left_margin;
        inline constexpr auto y      = style::header::height;
        inline constexpr auto width  = style::listview::body_width_with_scroll;
        inline constexpr auto height = style::window_height - y - style::footer::height;
    } // namespace listview

    namespace item
    {
        namespace label
        {
            inline constexpr auto height       = 30;
            inline constexpr auto width        = style::listview::item_width_with_scroll;
            inline constexpr auto bottomMargin = 4;
            inline constexpr auto leftMargin   = 10;
        } // namespace label

        namespace color
        {
            inline constexpr auto height       = listview::height - label::height;
            inline constexpr auto width        = style::listview::item_width_with_scroll;
            inline constexpr auto bottomMargin = 4;
            inline constexpr auto leftMargin   = 10;
        } // namespace color
    }     // namespace item
} // namespace style::colorTest

A module-apps/application-settings/widgets/ColorTestListView.cpp => module-apps/application-settings/widgets/ColorTestListView.cpp +38 -0
@@ 0,0 1,38 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "ColorTestListView.hpp"
#include "InputEvent.hpp"

namespace gui
{
    ColorTestListView::ColorTestListView(app::Application *application,
                                         Item *parent,
                                         uint32_t x,
                                         uint32_t y,
                                         uint32_t w,
                                         uint32_t h,
                                         std::shared_ptr<ListItemProvider> prov,
                                         style::listview::ScrollBarType scrollBarType)
        : ListView(parent, x, y, w, h, prov, scrollBarType), app{application}
    {
        body->borderCallback = [this](const InputEvent &inputEvent) -> bool {
            if (inputEvent.state != InputEvent::State::keyReleasedShort) {
                return false;
            }
            if (inputEvent.keyCode == KeyCode::KEY_UP && pageLoaded) {
                auto result = this->requestPreviousPage();
                app->refreshWindow(RefreshModes::GUI_REFRESH_DEEP);
                return result;
            }
            else if (inputEvent.keyCode == KeyCode::KEY_DOWN && pageLoaded) {
                auto result = this->requestNextPage();
                app->refreshWindow(RefreshModes::GUI_REFRESH_DEEP);
                return result;
            }
            else {
                return false;
            }
        };
    }
} // namespace gui

A module-apps/application-settings/widgets/ColorTestListView.hpp => module-apps/application-settings/widgets/ColorTestListView.hpp +26 -0
@@ 0,0 1,26 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "ListView.hpp"
#include "Application.hpp"

namespace gui
{
    class ColorTestListView : public ListView
    {
      private:
        app::Application *app;

      public:
        ColorTestListView(app::Application *application,
                          Item *parent,
                          uint32_t x,
                          uint32_t y,
                          uint32_t w,
                          uint32_t h,
                          std::shared_ptr<ListItemProvider> prov,
                          style::listview::ScrollBarType scrollType = style::listview::ScrollBarType::Proportional);
    };
} // namespace gui

A module-apps/application-settings/windows/ColorTestWindow.cpp => module-apps/application-settings/windows/ColorTestWindow.cpp +90 -0
@@ 0,0 1,90 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <memory>

#include <service-appmgr/Controller.hpp>
#include <service-gui/Common.hpp>
#include <Style.hpp>
#include <ChangeColorScheme.hpp>

#include "application-settings/ApplicationSettings.hpp"
#include "application-settings/widgets/ColorTestListStyle.hpp"
#include "ColorTestWindow.hpp"

namespace gui
{
    static gui::ColorScheme currentColorScheme = gui::Color::defaultColorScheme;

    ColorTestWindow::ColorTestWindow(app::Application *app)
        : AppWindow{app, window::name::color_test_window}, colorTestModel{std::make_shared<ColorTestModel>(app)}
    {
        buildInterface();
    }

    void ColorTestWindow::buildInterface()
    {
        AppWindow::buildInterface();

        setTitle(utils::localize.get("app_settings_title_color_test"));

        colorListView = new ColorTestListView(application,
                                              this,
                                              style::colorTest::listview::x,
                                              style::colorTest::listview::y,
                                              style::colorTest::listview::width,
                                              style::colorTest::listview::height,
                                              colorTestModel);

        colorListView->rebuildList();

        bottomBar->setActive(BottomBar::Side::LEFT, true);
        bottomBar->setText(BottomBar::Side::LEFT, utils::localize.get("app_settings_toolbar_reset"));
        bottomBar->setActive(BottomBar::Side::CENTER, true);
        bottomBar->setText(BottomBar::Side::CENTER, utils::localize.get(style::strings::common::save));
        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));

        applyInputCallback();

        setFocusItem(colorListView);
    }

    void ColorTestWindow::applyInputCallback()
    {
        this->inputCallback = [&](Item &item, const InputEvent &event) -> bool {
            if (event.isShortPress()) {
                if (event.is(KeyCode::KEY_ENTER)) {
                    setGlobalColorScheme(colorTestModel->getColorScheme());
                    return true;
                }
                else if (event.is(KeyCode::KEY_LF)) {
                    resetGlobalColorScheme();
                    return true;
                }
            }
            return false;
        };
    }

    void ColorTestWindow::resetGlobalColorScheme()
    {
        colorTestModel->createData();
        colorListView->rebuildList();
        setGlobalColorScheme(gui::Color::defaultColorScheme);
    }

    void ColorTestWindow::setGlobalColorScheme(const ColorScheme &scheme)
    {
        if (scheme != currentColorScheme) {
            currentColorScheme = scheme;
            sys::Bus::SendUnicast(std::make_shared<service::gui::ChangeColorScheme>(std::move(scheme)),
                                  service::name::gui,
                                  this->application,
                                  100);
            LOG_INFO("Updated color scheme");

            application->refreshWindow(RefreshModes::GUI_REFRESH_DEEP);
        }
    }
} /* namespace gui */

A module-apps/application-settings/windows/ColorTestWindow.hpp => module-apps/application-settings/windows/ColorTestWindow.hpp +40 -0
@@ 0,0 1,40 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <memory>
#include <functional>

#include "module-apps/application-settings/models/ColorTestModel.hpp"
#include "AppWindow.hpp"
#include "application-settings/widgets/ColorTestListView.hpp"

#include <gui/widgets/Label.hpp>
#include <gui/widgets/Image.hpp>
#include <gui/widgets/Window.hpp>
#include <gui/widgets/BottomBar.hpp>
#include <gui/widgets/TopBar.hpp>

namespace gui
{
    namespace window::name
    {
        inline constexpr auto color_test_window = "ColorTestWindow";
    } // namespace window::name

    class ColorTestWindow : public AppWindow
    {
      private:
        std::shared_ptr<ColorTestModel> colorTestModel = nullptr;
        gui::ColorTestListView *colorListView          = nullptr;

      public:
        explicit ColorTestWindow(app::Application *app);

        void applyInputCallback();
        void buildInterface() override;
        void setGlobalColorScheme(const ColorScheme &scheme);
        void resetGlobalColorScheme();
    };
} /* namespace gui */

M module-apps/application-settings/windows/SettingsMainWindow.cpp => module-apps/application-settings/windows/SettingsMainWindow.cpp +2 -0
@@ 9,6 9,7 @@
#include "CellularPassthroughWindow.hpp"
#include "FotaWindow.hpp"
#include "EinkModeWindow.hpp"
#include "ColorTestWindow.hpp"

std::list<gui::Option> mainWindowOptions(app::Application *app)
{


@@ 40,6 41,7 @@ std::list<gui::Option> mainWindowOptions(app::Application *app)
    }
    addMenu(i18("Fota update"), gui::window::name::fota_window);
    addMenu("Eink Mode", gui::window::name::eink);
    addMenu(i18("Color test"), gui::window::name::color_test_window);
    addMenu(i18("app_settings_display"));
    addMenu(i18("app_settings_phone_modes"));
    addMenu(i18("app_settings_security"));

M module-gui/gui/core/Color.hpp => module-gui/gui/core/Color.hpp +24 -0
@@ 4,9 4,16 @@
#pragma once

#include <cstdint>
#include <array>

namespace gui
{
    struct ColorScheme
    {
        static constexpr inline std::uint8_t numberOfColors = 16;
        std::array<std::uint8_t, numberOfColors> intensity;
    };

    struct Color
    {
        constexpr Color() noexcept = default;


@@ 22,6 29,8 @@ namespace gui
        static constexpr inline std::uint8_t Black           = 0x0U;
        static constexpr inline std::uint8_t FullTransparent = 0x0FU;
        static constexpr inline std::uint8_t Opaque          = 0x0U;

        static constexpr inline ColorScheme defaultColorScheme{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
    };

    inline bool operator==(const Color &r, const Color &l) noexcept


@@ 29,11 38,26 @@ namespace gui
        return r.intensity == l.intensity && r.alpha == l.alpha;
    }

    inline bool operator==(const ColorScheme &r, const ColorScheme &l) noexcept
    {
        for (int i = 0; i < ColorScheme::numberOfColors; ++i) {
            if (r.intensity[i] != l.intensity[i]) {
                return false;
            }
        }
        return true;
    }

    inline bool operator!=(const Color &r, const Color &l) noexcept
    {
        return !operator==(r, l);
    }

    inline bool operator!=(const ColorScheme &r, const ColorScheme &l) noexcept
    {
        return !operator==(r, l);
    }

    static inline constexpr Color ColorFullBlack{Color::Black, Color::Opaque};
    static inline constexpr Color ColorFullWhite{Color::White, Color::Opaque};
    static inline constexpr Color ColorNoColor{Color::White, Color::FullTransparent};

M module-gui/gui/core/Renderer.cpp => module-gui/gui/core/Renderer.cpp +8 -0
@@ 5,8 5,16 @@
#include "Renderer.hpp"
#include "Context.hpp"

// renderer
#include "renderers/PixelRenderer.hpp"

namespace gui
{
    void Renderer::changeColorScheme(const std::unique_ptr<ColorScheme> &scheme)
    {
        renderer::PixelRenderer::updateColorScheme(scheme);
    }

    void Renderer::render(Context *ctx, std::list<std::unique_ptr<DrawCommand>> &commands)
    {
        if (ctx == nullptr) {

M module-gui/gui/core/Renderer.hpp => module-gui/gui/core/Renderer.hpp +1 -0
@@ 37,6 37,7 @@ namespace gui
        virtual ~Renderer() = default;

        void render(Context *ctx, std::list<std::unique_ptr<DrawCommand>> &commands);
        void changeColorScheme(const std::unique_ptr<ColorScheme> &scheme);
    };

} /* namespace gui */

M module-gui/gui/core/renderers/PixelRenderer.cpp => module-gui/gui/core/renderers/PixelRenderer.cpp +14 -1
@@ 8,10 8,23 @@

namespace gui::renderer
{
    static ColorScheme colorScheme = ::gui::Color::defaultColorScheme;

    void PixelRenderer::draw(Context *ctx, Point point, Color color)
    {
        const auto contextWidth = ctx->getW();
        const auto position     = point.y * contextWidth + point.x;
        std::memset(ctx->getData() + position, color.intensity, 1);

        std::memset(ctx->getData() + position, colorScheme.intensity[color.intensity], 1);
    }

    void PixelRenderer::updateColorScheme(const std::unique_ptr<ColorScheme> &scheme)
    {
        colorScheme = *scheme;
    }

    auto PixelRenderer::getColor(const uint8_t intensity) -> uint8_t
    {
        return colorScheme.intensity[intensity];
    }
} // namespace gui::renderer

M module-gui/gui/core/renderers/PixelRenderer.hpp => module-gui/gui/core/renderers/PixelRenderer.hpp +7 -0
@@ 6,6 6,8 @@
#include "Color.hpp"
#include "Common.hpp"

#include <memory>

namespace gui
{
    class Context;


@@ 15,7 17,12 @@ namespace gui::renderer
{
    class PixelRenderer
    {

      public:
        PixelRenderer() = delete;

        static void draw(Context *ctx, Point point, Color color);
        static void updateColorScheme(const std::unique_ptr<ColorScheme> &scheme);
        [[nodiscard]] static auto getColor(const uint8_t intensity) -> uint8_t;
    };
} // namespace gui::renderer

M module-gui/gui/core/renderers/RectangleRenderer.cpp => module-gui/gui/core/renderers/RectangleRenderer.cpp +3 -2
@@ 183,8 183,9 @@ namespace gui::renderer
        while (!q.empty()) {
            const auto currPoint = q.front();
            q.pop();
            if (const auto color = getPixelColor(ctx, currPoint, borderColor.intensity);
                color == borderColor.intensity || color == fillColor.intensity) {
            if (const auto color = getPixelColor(ctx, currPoint, PixelRenderer::getColor(borderColor.intensity));
                color == PixelRenderer::getColor(borderColor.intensity) ||
                color == PixelRenderer::getColor(fillColor.intensity)) {
                continue;
            }


M module-services/service-gui/ServiceGUI.cpp => module-services/service-gui/ServiceGUI.cpp +18 -0
@@ 5,7 5,9 @@
#include "WorkerGUI.hpp"

#include "messages/DrawMessage.hpp"

#include "messages/EinkInitialized.hpp"
#include "messages/ChangeColorScheme.hpp"

#include <DrawCommand.hpp>
#include <FontManager.hpp>


@@ 63,6 65,9 @@ namespace service::gui
        connect(typeid(RenderingFinished),
                [this](sys::Message *request) -> sys::MessagePointer { return handleGUIRenderingFinished(request); });

        connect(typeid(ChangeColorScheme),
                [this](sys::Message *request) -> sys::MessagePointer { return handleChangeColorScheme(request); });

        connect(typeid(eink::ImageDisplayedNotification), [this](sys::Message *request) -> sys::MessagePointer {
            return handleImageDisplayedNotification(request);
        });


@@ 129,6 134,13 @@ namespace service::gui
        return sys::MessageNone{};
    }

    sys::MessagePointer ServiceGUI::handleChangeColorScheme(sys::Message *message)
    {
        const auto msg = static_cast<ChangeColorScheme *>(message);
        notifyRenderColorSchemeChange(msg->getColorScheme());
        return sys::MessageNone{};
    }

    void ServiceGUI::prepareDisplayEarly(::gui::RefreshModes refreshMode)
    {
        auto msg = std::make_shared<service::eink::PrepareDisplayEarlyRequest>(refreshMode);


@@ 142,6 154,12 @@ namespace service::gui
        worker->notify(WorkerGUI::Signal::Render);
    }

    void ServiceGUI::notifyRenderColorSchemeChange(::gui::ColorScheme &&scheme)
    {
        colorSchemeUpdate = std::make_unique<::gui::ColorScheme>(scheme);
        worker->notify(WorkerGUI::Signal::ChangeColorScheme);
    }

    void ServiceGUI::enqueueDrawCommands(DrawCommandsQueue::QueueItem &&item)
    {
        // Clear all queue elements for now to keep only the latest command in the queue.

M module-services/service-gui/ServiceGUI.hpp => module-services/service-gui/ServiceGUI.hpp +3 -0
@@ 63,6 63,7 @@ namespace service::gui

        void prepareDisplayEarly(::gui::RefreshModes refreshMode);
        void notifyRenderer(std::list<std::unique_ptr<::gui::DrawCommand>> &&commands, ::gui::RefreshModes refreshMode);
        void notifyRenderColorSchemeChange(::gui::ColorScheme &&scheme);
        void enqueueDrawCommands(DrawCommandsQueue::QueueItem &&item);
        void sendOnDisplay(::gui::Context *context, int contextId, ::gui::RefreshModes refreshMode);
        void scheduleContextRelease(int contextId);


@@ 76,10 77,12 @@ namespace service::gui
        sys::MessagePointer handleGUIRenderingFinished(sys::Message *message);
        sys::MessagePointer handleEinkInitialized(sys::Message *message);
        sys::MessagePointer handleImageDisplayedNotification(sys::Message *message);
        sys::MessagePointer handleChangeColorScheme(sys::Message *message);

        std::unique_ptr<ContextPool> contextPool;
        std::unique_ptr<WorkerGUI> worker;
        std::unique_ptr<DrawCommandsQueue> commandsQueue;
        std::unique_ptr<::gui::ColorScheme> colorSchemeUpdate;
        std::optional<CachedRender> cachedRender;
        std::unique_ptr<sys::Timer> contextReleaseTimer;
        State currentState;

M module-services/service-gui/WorkerGUI.cpp => module-services/service-gui/WorkerGUI.cpp +16 -2
@@ 38,19 38,33 @@ namespace service::gui

    void WorkerGUI::handleCommand(Signal command)
    {
        if (command == Signal::Render) {
        switch (command) {
        case Signal::Render: {
            auto item = guiService->commandsQueue->dequeue();
            render(item.commands, item.refreshMode);
            break;
        }
        case Signal::ChangeColorScheme: {
            changeColorScheme(guiService->colorSchemeUpdate);
            break;
        }
        default:
            LOG_ERROR("Command not valid.");
        }
    }

    void WorkerGUI::render(std::list<std::unique_ptr<::gui::DrawCommand>> &commands, ::gui::RefreshModes refreshMode)
    void WorkerGUI::render(DrawCommandsQueue::CommandList &commands, ::gui::RefreshModes refreshMode)
    {
        const auto [contextId, context] = guiService->contextPool->borrowContext(); // Waits for the context.
        renderer.render(context, commands);
        onRenderingFinished(contextId, refreshMode);
    }

    void WorkerGUI::changeColorScheme(const std::unique_ptr<::gui::ColorScheme> &scheme)
    {
        renderer.changeColorScheme(scheme);
    }

    void WorkerGUI::onRenderingFinished(int contextId, ::gui::RefreshModes refreshMode)
    {
        auto msg = std::make_shared<service::gui::RenderingFinished>(contextId, refreshMode);

M module-services/service-gui/WorkerGUI.hpp => module-services/service-gui/WorkerGUI.hpp +4 -2
@@ 21,7 21,8 @@ namespace service::gui
      public:
        enum class Signal
        {
            Render
            Render,
            ChangeColorScheme,
        };
        static constexpr auto SignallingQueueName     = "SignallingQueue";
        static constexpr auto SignallingQueueCapacity = 1;


@@ 34,7 35,8 @@ namespace service::gui

      private:
        void handleCommand(Signal command);
        void render(std::list<std::unique_ptr<::gui::DrawCommand>> &commands, ::gui::RefreshModes refreshMode);
        void render(DrawCommandsQueue::CommandList &commands, ::gui::RefreshModes refreshMode);
        void changeColorScheme(const std::unique_ptr<::gui::ColorScheme> &scheme);
        void onRenderingFinished(int contextId, ::gui::RefreshModes refreshMode);

        ServiceGUI *guiService;

A module-services/service-gui/messages/ChangeColorScheme.hpp => module-services/service-gui/messages/ChangeColorScheme.hpp +26 -0
@@ 0,0 1,26 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "GUIMessage.hpp"

#include <gui/Common.hpp>

namespace service::gui
{
    class ChangeColorScheme : public GUIMessage
    {
      public:
        explicit ChangeColorScheme(::gui::ColorScheme colorScheme) : scheme{colorScheme}
        {}

        [[nodiscard]] auto getColorScheme() const noexcept -> ::gui::ColorScheme
        {
            return scheme;
        }

      private:
        ::gui::ColorScheme scheme;
    };
} // namespace service::gui