~aleteoryx/muditaos

fbfd08cfeaaf7860ecbcc372b743010879ee617c — Przemyslaw Brudny 5 years ago e4462dc
[EGD-5523] ListView OnPageElement and Options refresh

Added new OnPageElement listView rebuild type. Created new
options refresh. Refactored DisplayLight Setting. BarGraph rector.
Added step render limit for small radius arcs.
M module-apps/GuiTimer.cpp => module-apps/GuiTimer.cpp +1 -1
@@ 1,4 1,4 @@
// 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

#include "GuiTimer.hpp"

M module-apps/application-settings-new/widgets/SpinBox.cpp => module-apps/application-settings-new/widgets/SpinBox.cpp +3 -1
@@ 2,6 2,7 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "SpinBox.hpp"
#include "OptionStyle.hpp"
#include "widgets/BarGraph.hpp"

#include <InputEvent.hpp>


@@ 71,7 72,7 @@ namespace gui
        auto label = new Label(parent);
        label->setMinimumHeight(style::window::label::default_h);
        label->setMaximumWidth(style::window::default_body_width);

        label->setMargins(Margins(option::window::option_left_margin, 0, 0, 0));
        label->setEdges(RectangleEdge::None);
        label->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center));
        label->setFont(style::window::font::big);


@@ 85,6 86,7 @@ namespace gui
    {
        auto barGraph = new HBarGraph(parent, 0, 0, maxValue);
        barGraph->setAlignment(Alignment(gui::Alignment::Horizontal::Right, gui::Alignment::Vertical::Center));
        barGraph->setMargins(Margins(0, 0, option::window::option_right_margin, 0));
        barGraph->setValue(startValue);
        barGraph->activeItem = false;


M module-apps/application-settings-new/widgets/SpinBoxOptionSetting.cpp => module-apps/application-settings-new/widgets/SpinBoxOptionSetting.cpp +1 -4
@@ 24,10 24,7 @@ namespace gui
        auto optionItem = new gui::ListItem();
        optionItem->setMinimumSize(style::window::default_body_width, style::window::label::big_h);
        optionItem->inputCallback        = spinBox->inputCallback;
        optionItem->focusChangedCallback = [spinBox, this](Item &item) {
            spinBox->focusChangedCallback(item);
            return focusChangedCallback(item);
        };
        optionItem->focusChangedCallback     = [spinBox](Item &item) { return spinBox->focusChangedCallback(item); };
        optionItem->dimensionChangedCallback = [spinBox](gui::Item &, const BoundingBox &newDim) -> bool {
            spinBox->setPosition(0, 0);
            spinBox->setSize(newDim.w, newDim.h);

M module-apps/application-settings-new/windows/BaseSettingsWindow.cpp => module-apps/application-settings-new/windows/BaseSettingsWindow.cpp +14 -15
@@ 1,4 1,4 @@
// 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

#include "BaseSettingsWindow.hpp"


@@ 6,22 6,12 @@

namespace gui
{

    BaseSettingsWindow::BaseSettingsWindow(app::Application *app, std::string name) : OptionWindow(app, name)
    {}

    void BaseSettingsWindow::buildInterface()
    {
        OptionWindow::buildInterface();

        bottomBar->setActive(BottomBar::Side::RIGHT, true);
        bottomBar->setText(BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
    }

    void BaseSettingsWindow::destroyInterface()
    {
        erase();
        invalidate();
        optionsList->prepareRebuildCallback = [this]() {
            clearOptions();
            optionsModel->createData(options);
        };
    }

    void BaseSettingsWindow::rebuild()


@@ 41,4 31,13 @@ namespace gui
        addOptions(buildOptionsList());
    }

    void BaseSettingsWindow::refreshOptionsList()
    {
        refreshOptions(buildOptionsList());
    }

    void BaseSettingsWindow::refreshOptionsList(unsigned int pageIndex)
    {
        refreshOptions(buildOptionsList(), pageIndex);
    }
} // namespace gui

M module-apps/application-settings-new/windows/BaseSettingsWindow.hpp => module-apps/application-settings-new/windows/BaseSettingsWindow.hpp +4 -5
@@ 1,4 1,4 @@
// 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

#pragma once


@@ 10,21 10,20 @@

namespace gui
{

    class BaseSettingsWindow : public OptionWindow
    {
      public:
        BaseSettingsWindow(app::Application *app, std::string name);

        void rebuild() override;
        void buildInterface() override;
        void destroyInterface() override;

        void rebuildOptionList();
        void refreshOptionsList();
        void refreshOptionsList(unsigned int pageIndex);

        void onBeforeShow(ShowMode mode, SwitchData *data) override;

      protected:
        virtual void invalidate() noexcept {};
        virtual auto buildOptionsList() -> std::list<gui::Option> = 0;
    };
} // namespace gui

M module-apps/application-settings-new/windows/DisplayLightWindow.cpp => module-apps/application-settings-new/windows/DisplayLightWindow.cpp +5 -4
@@ 1,4 1,4 @@
// 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

#include "DisplayLightWindow.hpp"


@@ 42,7 42,8 @@ namespace gui
    auto DisplayLightWindow::onTimerTimeout(Item &self, Timer &task) -> bool
    {
        ambientLight = bsp::light_sensor::readout();
        rebuildOptionList();
        refreshOptionsList();

        application->refreshWindow(gui::RefreshModes::GUI_REFRESH_FAST);
        return true;
    }


@@ 51,10 52,10 @@ namespace gui
    {
        onOffSwitch = !onOffSwitch;

        rebuildOptionList();

        screenLightSettings->setStatus(isDisplayLightSwitchOn);
        screenLightSettings->setMode(isAutoLightSwitchOn);

        refreshOptionsList();
    }

    auto DisplayLightWindow::buildOptionsList() -> std::list<gui::Option>

M module-apps/application-settings-new/windows/DisplayLightWindow.hpp => module-apps/application-settings-new/windows/DisplayLightWindow.hpp +1 -1
@@ 1,4 1,4 @@
// 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

#pragma once

M module-apps/application-settings-new/windows/InputLanguageWindow.cpp => module-apps/application-settings-new/windows/InputLanguageWindow.cpp +2 -2
@@ 1,4 1,4 @@
// 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

#include "InputLanguageWindow.hpp"


@@ 27,7 27,7 @@ namespace gui
                [=](gui::Item &item) {
                    selectedLang = lang;
                    app::manager::Controller::changeInputLanguage(application, lang);
                    rebuildOptionList();
                    refreshOptionsList();
                    return true;
                },
                [=](gui::Item &item) {

M module-apps/application-settings-new/windows/LanguagesWindow.cpp => module-apps/application-settings-new/windows/LanguagesWindow.cpp +3 -3
@@ 17,10 17,9 @@ namespace gui
        languagesModel.requestCurrentDisplayLanguage();
    }

    void LanguagesWindow::addOptions(std::list<Option> &optionList)
    void LanguagesWindow::onBeforeShow(ShowMode mode, SwitchData *data)
    {
        OptionWindow::addOptions(optionList);
        optionsList->setFocusOnElement(selectedLanguageIndex);
        refreshOptionsList(selectedLanguageIndex);
    }

    auto LanguagesWindow::buildOptionsList() -> std::list<gui::Option>


@@ 49,6 48,7 @@ namespace gui
        if (languagesData == nullptr) {
            return false;
        }

        selectedLanguage = languagesData->getCurrentDisplayLanguage();
        setLanguageIndex();


M module-apps/application-settings-new/windows/LanguagesWindow.hpp => module-apps/application-settings-new/windows/LanguagesWindow.hpp +1 -1
@@ 15,9 15,9 @@ namespace gui
        explicit LanguagesWindow(app::Application *app);

      private:
        void addOptions(std::list<Option> &optionList) override;
        auto buildOptionsList() -> std::list<Option> override;
        auto handleSwitchData(SwitchData *data) -> bool override;
        void onBeforeShow(ShowMode mode, SwitchData *data) override;
        void setLanguageIndex();

        utils::LangLoader loader;

M module-apps/widgets/BarGraph.cpp => module-apps/widgets/BarGraph.cpp +22 -17
@@ 1,4 1,4 @@
// 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

#include "BarGraph.hpp"


@@ 20,7 20,8 @@ namespace gui

    auto BarGraph::createRectangle(uint32_t width, uint32_t height) const -> Rect *
    {
        auto rectangle = new Rect(nullptr, 0, 0, width, height);
        auto rectangle = new Rect(nullptr, 0, 0, 0, 0);
        rectangle->setMinimumSize(width, height);
        rectangle->setFillColor(ColorFullBlack);
        rectangle->setBorderColor(ColorFullBlack);
        rectangle->setFilled(false);


@@ 29,13 30,6 @@ namespace gui
        return rectangle;
    }

    auto BarGraph::createSpace(uint32_t width, uint32_t height) const -> Rect *
    {
        auto space = new Rect(nullptr, 0, 0, width, height);
        space->setEdges(RectangleEdge::None);
        return space;
    }

    auto BarGraph::incrementWith(uint32_t levels) -> bool
    {
        if ((currentLevel + levels) <= numberOfRectangles) {


@@ 94,7 88,7 @@ namespace gui
    VBarGraph::VBarGraph(Item *parent, Position x, Position y, uint32_t numberOfRectangles)
        : VBox(parent, x, y, style::bargraph::rect_axis_length_lrg, rectAxisLenghtFrom(numberOfRectangles))
    {
        setRadius(style::bargraph::radius);
        setMinimumSize(style::bargraph::rect_axis_length_lrg, rectAxisLenghtFrom(numberOfRectangles));
        setEdges(RectangleEdge::None);
        setMaximum(numberOfRectangles);
        std::reverse(std::begin(rectangles), std::end(rectangles));


@@ 103,7 97,7 @@ namespace gui
    void VBarGraph::setMaximum(unsigned int value)
    {
        numberOfRectangles = value;
        setSize(rectAxisLenghtFrom(numberOfRectangles), Axis::Y);

        if (currentLevel > numberOfRectangles) {
            currentLevel = numberOfRectangles;
        }


@@ 111,19 105,24 @@ namespace gui
            erase();
            rectangles.clear();
        }
        for (uint32_t i = 0; i < numberOfRectangles; ++i) {

        for (unsigned int i = 0; i <= numberOfRectangles; i++) {

            auto rectangle =
                createRectangle(style::bargraph::rect_axis_length_lrg, style::bargraph::rect_axis_length_sml);

            if ((i + 1) != numberOfRectangles) {
                rectangle->setMargins(Margins(0, 0, 0, style::bargraph::spacing));
            }

            addWidget(rectangle);
            rectangles.push_back(rectangle);
            addWidget(createSpace(style::bargraph::rect_axis_length_lrg, style::bargraph::spacing));
        }
    }

    HBarGraph::HBarGraph(Item *parent, Position x, Position y, uint32_t numberOfRectangles) : HBox(parent)
    {
        setMinimumSize(rectAxisLenghtFrom(numberOfRectangles), style::bargraph::rect_axis_length_lrg);
        setRadius(style::bargraph::radius);
        setEdges(RectangleEdge::None);
        setMaximum(numberOfRectangles);
    }


@@ 131,20 130,26 @@ namespace gui
    void HBarGraph::setMaximum(unsigned int value)
    {
        numberOfRectangles = value;
        setSize(rectAxisLenghtFrom(numberOfRectangles), Axis::X);
        if (currentLevel > numberOfRectangles) {
            currentLevel = numberOfRectangles;
        }

        if (!rectangles.empty()) {
            erase();
            rectangles.clear();
        }
        for (uint32_t i = 0; i < numberOfRectangles; ++i) {

        for (unsigned int i = 0; i <= numberOfRectangles; i++) {

            auto rectangle =
                createRectangle(style::bargraph::rect_axis_length_sml, style::bargraph::rect_axis_length_lrg);

            if ((i + 1) != numberOfRectangles) {
                rectangle->setMargins(Margins(0, 0, style::bargraph::spacing, 0));
            }

            addWidget(rectangle);
            rectangles.push_back(rectangle);
            addWidget(createSpace(style::bargraph::spacing, style::bargraph::rect_axis_length_lrg));
        }
    }


M module-apps/widgets/BarGraph.hpp => module-apps/widgets/BarGraph.hpp +1 -2
@@ 1,4 1,4 @@
// 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

#pragma once


@@ 24,7 24,6 @@ namespace gui
        uint32_t currentLevel = 0;

        [[nodiscard]] auto createRectangle(uint32_t width, uint32_t height) const -> Rect *;
        [[nodiscard]] auto createSpace(uint32_t width, uint32_t height) const -> Rect *;

        auto incrementWith(uint32_t levels) -> bool;
        auto decrementWith(uint32_t levels) -> bool;

M module-apps/windows/OptionWindow.cpp => module-apps/windows/OptionWindow.cpp +13 -1
@@ 1,4 1,4 @@
// 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

#include "OptionWindow.hpp"


@@ 31,6 31,18 @@ namespace gui
        addOptions(options);
    }

    void OptionWindow::refreshOptions(std::list<Option> &&optionList)
    {
        options = std::move(optionList);
        optionsList->rebuildList(style::listview::RebuildType::InPlace);
    }

    void OptionWindow::refreshOptions(std::list<Option> &&optionList, unsigned int pageIndex)
    {
        options = std::move(optionList);
        optionsList->rebuildList(style::listview::RebuildType::OnPageElement, pageIndex);
    }

    void OptionWindow::addOptions(std::list<Option> &optionList)
    {
        optionsModel->createData(optionList);

M module-apps/windows/OptionWindow.hpp => module-apps/windows/OptionWindow.hpp +3 -1
@@ 1,4 1,4 @@
// 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

#pragma once


@@ 26,6 26,8 @@ namespace gui
        virtual void addOptions(std::list<Option> &optionList);
        void addOptions(std::list<Option> &&optionList);
        void resetOptions(std::list<Option> &&optionList);
        void refreshOptions(std::list<Option> &&optionList);
        void refreshOptions(std::list<Option> &&optionList, unsigned int pageIndex);

      public:
        OptionWindow(app::Application *app, const std::string &name);

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

#include "ArcRenderer.hpp"


@@ 6,6 6,8 @@

namespace gui::renderer
{
    constexpr Length RadiusPrecisionLimit = 5;

    auto ArcRenderer::DrawableStyle::from(const CommandArc &command) -> DrawableStyle
    {
        return DrawableStyle{command.width, command.borderColor};


@@ 41,7 43,14 @@ namespace gui::renderer

        const auto start = trigonometry::toRadians(begin);
        const auto end   = trigonometry::toRadians(begin + sweep);
        constexpr double step{0.001};
        double step;

        if (radius < RadiusPrecisionLimit) {
            step = 0.01;
        }
        else {
            step = 0.001;
        }

        double cosine, sine;
        for (double radians = start; radians <= end; radians += step) {


@@ 65,7 74,14 @@ namespace gui::renderer
    {
        const auto start = trigonometry::toRadians(begin);
        const auto end   = trigonometry::toRadians(begin + sweep);
        constexpr double step{0.001};
        double step;

        if (radius < RadiusPrecisionLimit) {
            step = 0.01;
        }
        else {
            step = 0.001;
        }

        long int x, y;
        for (double radians = start; radians <= end; radians += step) {

M module-gui/gui/widgets/ListView.cpp => module-gui/gui/widgets/ListView.cpp +44 -16
@@ 263,25 263,54 @@ namespace gui
        rebuildList(lastRebuildRequest.first, lastRebuildRequest.second, true);
    }

    void ListView::setup(style::listview::RebuildType rebuildType, unsigned int dataOffset)
    void ListView::prepareFullRebuild()
    {
        if (rebuildType == style::listview::RebuildType::Full) {
            setStartIndex();
        setStartIndex();
        storedFocusIndex = style::listview::nPos;
    }

    void ListView::prepareOnOffsetRebuild(unsigned int dataOffset)
    {
        if (dataOffset < elementsCount) {
            startIndex       = dataOffset;
            storedFocusIndex = style::listview::nPos;
        }
        else if (rebuildType == style::listview::RebuildType::OnOffset) {
            if (dataOffset < elementsCount) {
                startIndex       = dataOffset;
                storedFocusIndex = style::listview::nPos;
            }
            else {
                LOG_ERROR("Requested rebuild on index greater than elements count");
            }
        else {
            LOG_ERROR("Requested rebuild on index greater than elements count");
        }
        else if (rebuildType == style::listview::RebuildType::InPlace) {
            if (!body->empty()) {
                storedFocusIndex = getFocusItemIndex();
            }
    }

    void ListView::prepareInPlaceRebuild()
    {
        if (!body->empty()) {
            storedFocusIndex = getFocusItemIndex();
        }
    }

    void ListView::prepareOnPageElementRebuild(unsigned int dataOffset)
    {
        storedFocusIndex = dataOffset;
    }

    void ListView::setup(style::listview::RebuildType rebuildType, unsigned int dataOffset)
    {
        switch (rebuildType) {
        case style::listview::RebuildType::Full:
            prepareFullRebuild();
            break;
        case style::listview::RebuildType::OnOffset:
            prepareOnOffsetRebuild(dataOffset);
            break;
        case style::listview::RebuildType::InPlace:
            prepareInPlaceRebuild();
            break;
        case style::listview::RebuildType::OnPageElement:
            prepareOnPageElementRebuild(dataOffset);
            break;
        }

        if (prepareRebuildCallback) {
            prepareRebuildCallback();
        }

        lastRebuildRequest = {rebuildType, dataOffset};


@@ 695,5 724,4 @@ namespace gui

        return true;
    }

} /* namespace gui */

M module-gui/gui/widgets/ListView.hpp => module-gui/gui/widgets/ListView.hpp +11 -2
@@ 1,4 1,4 @@
// 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

#pragma once


@@ 84,6 84,11 @@ namespace gui
        bool renderFullList();
        void checkFullRenderRequirement();

        void prepareFullRebuild();
        void prepareOnOffsetRebuild(unsigned int dataOffset);
        void prepareInPlaceRebuild();
        void prepareOnPageElementRebuild(unsigned int dataOffset);

        void setFocus();
        void refresh();
        void resizeWithScroll();


@@ 91,6 96,7 @@ namespace gui
        void fillFirstPage();
        void setStartIndex();
        void recalculateOnBoxRequestedResize();
        void setFocusOnElement(unsigned int elementNumber);
        [[nodiscard]] unsigned int getFocusItemIndex();
        /// Default empty list to inform that there is no elements - callback should be override in applications
        void onElementsCountChanged();


@@ 115,17 121,20 @@ namespace gui

        void setElementsCount(unsigned int count);
        void setProvider(std::shared_ptr<ListItemProvider> provider);

        void rebuildList(style::listview::RebuildType rebuildType = style::listview::RebuildType::Full,
                         unsigned int dataOffset                  = 0,
                         bool forceRebuild                        = false);
        /// In case of elements count change there can be a need to resend request in case of having one async query for
        /// count and records.
        void reSendLastRebuildRequest();
        /// Callback to be called on rebuild preparation - in example to on demand clear provider data.
        std::function<void()> prepareRebuildCallback;

        void clear();
        std::shared_ptr<ListItemProvider> getProvider();
        void setOrientation(style::listview::Orientation value);
        void setBoundaries(style::listview::Boundaries value);
        void setFocusOnElement(unsigned int elementNumber);
        void setScrollTopMargin(int value);
        void setAlignment(const Alignment &value) override;
        void onProviderDataUpdate();

M module-gui/gui/widgets/Style.hpp => module-gui/gui/widgets/Style.hpp +6 -5
@@ 1,4 1,4 @@
// 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

#pragma once


@@ 200,10 200,11 @@ namespace style
        /// Possible List rebuild types
        enum class RebuildType
        {
            Full,    ///< Full rebuild - resets lists to all initial conditions and request data from beginning.
            InPlace, ///< InPlace rebuild - stores currently focused part of list and rebuild from that part.
            OnOffset ///< OnOffset rebuild - resets lists to all initial conditions and request data from provided
                     ///< offset.
            Full,          ///< Full rebuild - resets lists to all initial conditions and request data from beginning.
            InPlace,       ///< InPlace rebuild - stores currently focused part of list and rebuild from that part.
            OnPageElement, ///< OnPageElement rebuild - same page but focus changed on provided element index.
            OnOffset       ///< OnOffset rebuild - resets lists to all initial conditions and request data from provided
                           ///< offset.
        };

        /// Possible List ScrollBar types

M module-gui/test/test-google/test-gui-listview.cpp => module-gui/test/test-google/test-gui-listview.cpp +25 -1
@@ 1,4 1,4 @@
// 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

#include "gtest/gtest.h"


@@ 375,4 375,28 @@ TEST_F(ListViewTesting, Rebuild_Type_Test)
        << "Check if item 6 has focus";
    ASSERT_EQ(pointerToFocusedElement, dynamic_cast<gui::TestListItem *>(testListView->body->getFocusItem()))
        << "Focused item should be same";

    // Do full list rebuild
    testListView->rebuildList(style::listview::RebuildType::Full);

    // Do on page element rebuild on index in Page scope
    testListView->rebuildList(style::listview::RebuildType::OnPageElement, 3);

    // Check if focused item did not change
    ASSERT_EQ(3, dynamic_cast<gui::TestListItem *>(testListView->body->getFocusItem())->ID)
        << "Check if item 3 has focus";

    // Do on page element rebuild in Page scope
    testListView->rebuildList(style::listview::RebuildType::OnPageElement, 1);

    // Check if focused item did not change
    ASSERT_EQ(1, dynamic_cast<gui::TestListItem *>(testListView->body->getFocusItem())->ID)
        << "Check if item 1 has focus";

    // Do on page element rebuild on index outside Page scope (should focus on last possible)
    testListView->rebuildList(style::listview::RebuildType::OnPageElement, 10);

    // Check if focused item did not change
    ASSERT_EQ(5, dynamic_cast<gui::TestListItem *>(testListView->body->getFocusItem())->ID)
        << "Check if item 5 has focus";
}

M module-utils/math/Math.hpp => module-utils/math/Math.hpp +4 -4
@@ 25,12 25,12 @@ namespace trigonometry
    {
        static auto fromAngle(Radians angle, SideLength hypotenuse) -> SideLength
        {
            return std::lround(std::cos(angle) * hypotenuse);
            return std::round(std::cos(angle) * hypotenuse);
        }

        static auto fromCosine(double cosine, SideLength hypotenuse) -> SideLength
        {
            return std::lround(cosine * hypotenuse);
            return std::round(cosine * hypotenuse);
        }
    };



@@ 38,12 38,12 @@ namespace trigonometry
    {
        static auto fromAngle(Radians angle, SideLength hypotenuse) -> SideLength
        {
            return std::lround(std::sin(angle) * hypotenuse);
            return std::round(std::sin(angle) * hypotenuse);
        }

        static auto fromSine(double sine, SideLength hypotenuse) -> SideLength
        {
            return std::lround(sine * hypotenuse);
            return std::round(sine * hypotenuse);
        }
    };
} // namespace trigonometry