~aleteoryx/muditaos

ef12b04748e97489e909a6782904865dfd22907a — Artur Śleszyński 4 years ago bedb95e
[EGD-5849] Make calculator compute previous operations

Modify calculator behavior according to PO input:
* Compute existing equation before entering next operation
* Limit digit input to 7 digits
* Start each number input from empty input
M module-apps/application-calculator/data/CalculatorInputProcessor.cpp => module-apps/application-calculator/data/CalculatorInputProcessor.cpp +20 -2
@@ 3,7 3,7 @@

#include "CalculatorInputProcessor.hpp"

bool calc::InputProcessor::isSymbol(uint32_t code)
bool calc::InputProcessor::isSymbol(uint32_t code) noexcept
{
    using namespace symbols::codes;



@@ 25,7 25,25 @@ bool calc::InputProcessor::isSymbol(uint32_t code)
    }
}

bool calc::InputProcessor::isDecimalSeparator(uint32_t code)
bool calc::InputProcessor::isOperation(uint32_t code) noexcept
{
    using namespace symbols::codes;

    switch (code) {
    case plus:
        [[fallthrough]];
    case minus:
        [[fallthrough]];
    case division:
        [[fallthrough]];
    case multiplication:
        return true;
    default:
        return false;
    }
}

bool calc::InputProcessor::isDecimalSeparator(uint32_t code) noexcept
{
    using namespace symbols::codes;


M module-apps/application-calculator/data/CalculatorInputProcessor.hpp => module-apps/application-calculator/data/CalculatorInputProcessor.hpp +35 -5
@@ 3,6 3,7 @@

#pragma once

#include <i18n/i18n.hpp>
#include <utf8/UTF8.hpp>

namespace gui


@@ 37,20 38,49 @@ namespace calc
            inline constexpr auto comma          = "\u002C";
            inline constexpr auto asterisk       = "\u002A";
            inline constexpr auto solidus        = "\u002F";

            inline const std::string &equals_str()
            {
                return utils::translate("app_calculator_equals");
            }

            inline const std::string &decimal_separator_str()
            {
                return utils::translate("app_calculator_decimal_separator");
            }

            inline const std::string &error_str()
            {
                return utils::translate("app_calculator_error");
            }
        } // namespace strings
    }     // namespace symbols

    } // namespace symbols

    namespace limits
    {
        inline constexpr auto MaxInputLength   = 7u;
        inline constexpr auto MaxDecimalDigits = 6u;

        inline constexpr auto VeryLowPrecision = 4;
        inline constexpr auto LowPrecision     = 5;
        inline constexpr auto Precision        = 6;
        inline constexpr auto HighPrecision    = 8;
        inline constexpr auto ExpLength        = 1;
        inline constexpr auto MinusExpLength   = 2;
        inline constexpr auto MaxStringLength  = 7;
    } // namespace limits

    class InputProcessor
    {
      public:
        static inline constexpr auto DecimalDigitsLimit = 6;

        virtual ~InputProcessor() = default;

        virtual bool handle(const gui::InputEvent &event) = 0;
        virtual void clear()                              = 0;

        static bool isSymbol(std::uint32_t code);
        static bool isDecimalSeparator(std::uint32_t c);
        static bool isSymbol(std::uint32_t code) noexcept;
        static bool isOperation(std::uint32_t code) noexcept;
        static bool isDecimalSeparator(std::uint32_t c) noexcept;
    };
} // namespace calc

M module-apps/application-calculator/data/CalculatorInputProcessorText.cpp => module-apps/application-calculator/data/CalculatorInputProcessorText.cpp +187 -41
@@ 7,6 7,15 @@
#include <gui/input/InputEvent.hpp>
#include <gui/widgets/Text.hpp>
#include <i18n/i18n.hpp>
#include <module-utils/gsl/gsl_assert>

namespace
{
    bool isDigit(gui::KeyCode code)
    {
        return gui::toNumeric(code) != gui::InvalidNumericKeyCode;
    }
} // namespace

calc::InputProcessorText::InputProcessorText(gsl::strict_not_null<gui::Text *> inputField) : inputField{inputField}
{}


@@ 30,43 39,52 @@ bool calc::InputProcessorText::handle(const gui::InputEvent &event)
        return true;
    }

    const auto lastChar         = inputField->getText()[inputField->getText().length() - 1];
    const bool lastCharIsSymbol = isSymbol(lastChar);
    if (lastChar == symbols::codes::zero && isSymbol(getPenultimate()) && !isDecimalSeparator(getPenultimate()) &&
    if (shouldRestoreInput(event)) {
        restoreHiddenInput();
        return true;
    }

    if (shouldHideInput(event)) {
        hideCurrentInput();
    }

    const auto lastChar                          = lastCharacter();
    const auto penultimateCharIsSymbol           = penultimateCharacterIsSymbol();
    const auto penultimateCharIsDecimalSeparator = penultimateCharacterIsDecimalSeparator();

    if (lastChar == symbols::codes::zero && penultimateCharIsSymbol && !penultimateCharIsDecimalSeparator &&
        event.is(gui::KeyCode::KEY_0)) {
        return true;
    }

    if (event.keyCode == gui::KeyCode::KEY_UP) {
        writeEquation(lastCharIsSymbol, symbols::strings::plus);
    if (event.is(gui::KeyCode::KEY_UP)) {
        handleOperation(symbols::strings::plus);
        return true;
    }

    if (event.keyCode == gui::KeyCode::KEY_DOWN) {
        if (lastChar != symbols::codes::minus) {
            writeEquation(lastCharIsSymbol, symbols::strings::minus);
        }
    if (event.is(gui::KeyCode::KEY_DOWN)) {
        handleOperation(symbols::strings::minus);
        return true;
    }

    if (event.keyCode == gui::KeyCode::KEY_LEFT) {
        writeEquation(lastCharIsSymbol, symbols::strings::multiplication);
    if (event.is(gui::KeyCode::KEY_LEFT)) {
        handleOperation(symbols::strings::multiplication);
        return true;
    }

    if (event.keyCode == gui::KeyCode::KEY_RIGHT) {
        writeEquation(lastCharIsSymbol, symbols::strings::division);
    if (event.is(gui::KeyCode::KEY_RIGHT)) {
        handleOperation(symbols::strings::division);
        return true;
    }

    if (event.keyCode == gui::KeyCode::KEY_LF) {
        if (!isPreviousNumberDecimal()) {
            writeEquation(lastCharIsSymbol, utils::translate("app_calculator_decimal_separator"));
    if (event.is(gui::KeyCode::KEY_LF)) {
        if (!isCurrentNumberDecimal()) {
            addSymbol(symbols::strings::decimal_separator_str());
        }
        return true;
    }

    if (lastChar == symbols::codes::zero && isSymbol(getPenultimate()) && !isDecimalSeparator(getPenultimate()) &&
    if (lastChar == symbols::codes::zero && penultimateCharIsSymbol && !penultimateCharIsDecimalSeparator &&
        !event.is(gui::KeyCode::KEY_0) && !event.is(gui::KeyCode::KEY_PND) && !event.is(gui::KeyCode::KEY_ENTER)) {
        inputField->removeChar();
        return false;


@@ 76,14 94,12 @@ bool calc::InputProcessorText::handle(const gui::InputEvent &event)
        clear();
    }

    if (event.keyCode == gui::KeyCode::KEY_ENTER) {
        auto result = Calculator().calculate(std::string(inputField->getText()));
        inputField->setText(result.value);
        clearInput = result.isError;
    if (event.is(gui::KeyCode::KEY_ENTER)) {
        compute();
        return true;
    }

    if (decimalLimitReached()) {
    if (prohibidInput(event)) {
        // Consume event to don't allow more decimals
        return true;
    }


@@ 94,15 110,85 @@ bool calc::InputProcessorText::handle(const gui::InputEvent &event)
void calc::InputProcessorText::clear()
{
    inputField->clear();
    hiddenPartOfEquation.clear();
    clearInput = false;
}

void calc::InputProcessorText::writeEquation(bool lastCharIsSymbol, const UTF8 &symbol)
std::optional<uint32_t> calc::InputProcessorText::lastCharacter() const
{
    const auto &txt = inputField->getText();

    if (txt.empty()) {
        return {};
    }

    return txt[txt.length() - 1];
}

bool calc::InputProcessorText::lastCharacterIsSymbol() const
{
    const auto &c = lastCharacter();
    return c ? isSymbol(*c) : false;
}

bool calc::InputProcessorText::lastCharacterIsOperation() const
{
    const auto &c = lastCharacter();
    return c ? isOperation(*c) : false;
}

std::optional<uint32_t> calc::InputProcessorText::penultimateCharacter() const
{
    const auto &text = inputField->getText();
    const auto len   = text.length();

    if (len < 2) {
        return {};
    }

    return text[len - 2];
}

bool calc::InputProcessorText::penultimateCharacterIsSymbol() const
{
    const auto &c = penultimateCharacter();
    return c ? isSymbol(*c) : false;
}

bool calc::InputProcessorText::penultimateCharacterIsDecimalSeparator() const
{
    const auto &c = penultimateCharacter();
    return c ? isDecimalSeparator(*c) : false;
}

bool calc::InputProcessorText::shouldComputeBeforeNextOperation() const
{
    if (!hasHiddenPart()) {
        return false;
    }

    if (inputField->getText().empty()) {
        return false;
    }

    return true;
}

void calc::InputProcessorText::handleOperation(const UTF8 &operation)
{
    if (shouldComputeBeforeNextOperation()) {
        compute();
    }

    addSymbol(operation);
}

void calc::InputProcessorText::addSymbol(const UTF8 &symbol)
{
    if (!inputField->getText().empty()) {

        if (lastCharIsSymbol && symbol != symbols::strings::minus) {
            if (!isSymbol(getPenultimate()) && inputField->getText().length() > 1) {
        if (lastCharacterIsSymbol() && symbol != symbols::strings::minus) {
            if (!penultimateCharacterIsSymbol() && inputField->getText().length() > 1) {
                inputField->removeChar();
                inputField->addText(symbol);
            }


@@ 116,7 202,50 @@ void calc::InputProcessorText::writeEquation(bool lastCharIsSymbol, const UTF8 &
    }
}

bool calc::InputProcessorText::isPreviousNumberDecimal() const
bool calc::InputProcessorText::shouldHideInput(const gui::InputEvent &event) const
{
    if (!lastCharacterIsOperation()) {
        return false;
    }

    if (!isDigit(event.keyCode) && !event.is(gui::KeyCode::KEY_DOWN)) {
        return false;
    }

    if (inputField->getText() == symbols::strings::minus) {
        return false;
    }

    return true;
}

bool calc::InputProcessorText::shouldRestoreInput(const gui::InputEvent &event) const
{
    return event.is(gui::KeyCode::KEY_PND) && inputField->isEmpty() && hasHiddenPart();
}

void calc::InputProcessorText::hideCurrentInput()
{
    Expects(hiddenPartOfEquation.empty());

    hiddenPartOfEquation = inputField->getText();
    inputField->clear();
}

void calc::InputProcessorText::restoreHiddenInput()
{
    Expects(!hiddenPartOfEquation.empty());

    inputField->setText(hiddenPartOfEquation);
    hiddenPartOfEquation.clear();
}

bool calc::InputProcessorText::hasHiddenPart() const
{
    return !hiddenPartOfEquation.empty();
}

bool calc::InputProcessorText::isCurrentNumberDecimal() const
{
    if (!inputField->getText().empty()) {
        std::vector<int> symbolsIndexes;


@@ 138,37 267,54 @@ bool calc::InputProcessorText::isPreviousNumberDecimal() const
        else {
            lastNumber = input.substr(*it, std::string::npos);
        }
        return lastNumber.find(utils::translate("app_calculator_decimal_separator")) != std::string::npos;
        return lastNumber.find(symbols::strings::decimal_separator_str()) != std::string::npos;
    }
    return false;
}

bool calc::InputProcessorText::decimalLimitReached() const
bool calc::InputProcessorText::inputContainsExponent() const
{
    if (!isPreviousNumberDecimal())
        return false;
    return std::string{inputField->getText()}.find('e') != std::string::npos;
}

    const auto &txt          = std::string{inputField->getText()};
    const auto separator_pos = txt.find_last_of(utils::translate("app_calculator_decimal_separator"));
bool calc::InputProcessorText::prohibidInput(const gui::InputEvent &event) const
{
    if (!isDigit(event.keyCode)) {
        return false;
    }

    if ((txt.size() - separator_pos) > DecimalDigitsLimit)
    if (charactedLimitReached() || decimalLimitReached()) {
        return true;
    }

    return false;
}

bool calc::InputProcessorText::inputContainsExponent() const
bool calc::InputProcessorText::charactedLimitReached() const
{
    return std::string{inputField->getText()}.find('e') != std::string::npos;
    return inputField->getText().length() >= limits::MaxInputLength;
}

std::uint32_t calc::InputProcessorText::getPenultimate() const
bool calc::InputProcessorText::decimalLimitReached() const
{
    const auto &text = inputField->getText();
    const auto len   = text.length();
    if (!isCurrentNumberDecimal()) {
        return false;
    }

    if (len < 2)
        return 0;
    const auto &txt          = std::string{inputField->getText()};
    const auto separator_pos = txt.find_last_of(symbols::strings::decimal_separator_str());

    return text[len - 2];
    if ((txt.size() - separator_pos) > limits::MaxDecimalDigits) {
        return true;
    }

    return false;
}

void calc::InputProcessorText::compute()
{
    auto result = Calculator().calculate(hiddenPartOfEquation + inputField->getText());
    inputField->setText(result.value);
    hiddenPartOfEquation.clear();
    clearInput = result.isError;
}

M module-apps/application-calculator/data/CalculatorInputProcessorText.hpp => module-apps/application-calculator/data/CalculatorInputProcessorText.hpp +23 -4
@@ 23,17 23,36 @@ namespace calc
        void clear() override;

      private:
        void writeEquation(bool lastCharIsSymbol, const UTF8 &symbol);
        std::optional<std::uint32_t> lastCharacter() const;
        bool lastCharacterIsSymbol() const;
        bool lastCharacterIsOperation() const;

        bool isPreviousNumberDecimal() const;
        bool decimalLimitReached() const;
        std::optional<std::uint32_t> penultimateCharacter() const;
        bool penultimateCharacterIsSymbol() const;
        bool penultimateCharacterIsDecimalSeparator() const;

        bool shouldComputeBeforeNextOperation() const;
        void handleOperation(const UTF8 &operation);
        void addSymbol(const UTF8 &symbol);

        bool shouldHideInput(const gui::InputEvent &event) const;
        bool shouldRestoreInput(const gui::InputEvent &event) const;
        void hideCurrentInput();
        void restoreHiddenInput();
        bool hasHiddenPart() const;

        bool isCurrentNumberDecimal() const;
        bool inputContainsExponent() const;

        std::uint32_t getPenultimate() const;
        bool prohibidInput(const gui::InputEvent &event) const;
        bool charactedLimitReached() const;
        bool decimalLimitReached() const;

        void compute();

        gui::Text *inputField{nullptr};
        bool clearInput{false};
        UTF8 hiddenPartOfEquation{};
    };

} // namespace calc

M module-apps/application-calculator/data/CalculatorUtility.cpp => module-apps/application-calculator/data/CalculatorUtility.cpp +25 -16
@@ 3,6 3,7 @@

#include "CalculatorUtility.hpp"
#include "application-calculator/data/CalculatorInputProcessor.hpp"
#include "application-calculator/widgets/CalculatorStyle.hpp"
#include <module-utils/tinyexpr/tinyexpr.h>
#include <i18n/i18n.hpp>
#include <Utils.hpp>


@@ 12,6 13,8 @@ namespace calc
{
    Result Calculator::calculate(std::string source)
    {
        using namespace calc::limits;

        source = prepareEquationForParser(source);

        if (source.empty()) {


@@ 22,17 25,17 @@ namespace calc
        double result = te_interp(source.c_str(), &error);
        if (error == 0 && !std::isinf(result) && !std::isnan(result)) {
            auto output = utils::to_string(result);
            if (output.length() > CalculatorConstants::maxStringLength) {
            if (output.length() > MaxStringLength) {
                output = getValueThatFitsOnScreen(result);
            }
            if (utils::translate("app_calculator_decimal_separator") == symbols::strings::comma) {
            if (symbols::strings::decimal_separator_str() == symbols::strings::comma) {
                output.replace(output.find(symbols::strings::full_stop),
                               std::size(std::string_view(symbols::strings::full_stop)),
                               symbols::strings::comma);
            }
            return Result{source, output, false};
        }
        return Result{source, utils::translate("app_calculator_error"), true};
        return Result{source, symbols::strings::error_str(), true};
    }

    std::string Calculator::prepareEquationForParser(std::string input)


@@ 58,25 61,27 @@ namespace calc

    std::string Calculator::getValueThatFitsOnScreen(double result)
    {
        using namespace calc::limits;

        auto base   = static_cast<long long>(result);
        auto length = utils::to_string(base).length();
        if (base < 0) {
            length -= 1;
        }
        if (length > CalculatorConstants::expLength + 1) {
        if (length > ExpLength + 1) {
            return convertToNumberWithPositiveExponent(result, length - 1);
        }
        else if (length == CalculatorConstants::expLength + 1) {
        else if (length == ExpLength + 1) {
            if (result < 0) {
                return utils::to_string(getCoefficient(result, CalculatorConstants::veryLowPrecision));
                return utils::to_string(getCoefficient(result, VeryLowPrecision));
            }
            return utils::to_string(getCoefficient(result, CalculatorConstants::lowPrecision));
            return utils::to_string(getCoefficient(result, LowPrecision));
        }
        else if (length == 1 && result < -1) {
            return utils::to_string(getCoefficient(result, CalculatorConstants::lowPrecision));
            return utils::to_string(getCoefficient(result, LowPrecision));
        }
        else if (result > 1) {
            return utils::to_string(getCoefficient(result, CalculatorConstants::precision));
            return utils::to_string(getCoefficient(result, Precision));
        }
        else {
            return convertToNumberWithNegativeExponent(result, base);


@@ 85,9 90,11 @@ namespace calc

    std::string Calculator::convertToNumberWithPositiveExponent(double result, uint32_t exponent)
    {
        using namespace calc::limits;

        result /= pow(10, exponent);
        auto exponentLength = utils::to_string(exponent).length();
        auto decimalPlace   = CalculatorConstants::precision - exponentLength - CalculatorConstants::expLength;
        auto decimalPlace   = Precision - exponentLength - ExpLength;
        if (result < 0) {
            decimalPlace -= 1;
        }


@@ 96,26 103,28 @@ namespace calc

    std::string Calculator::convertToNumberWithNegativeExponent(double result, long long base)
    {
        double frac = (result - base) * pow(10, CalculatorConstants::highPrecision);
        using namespace calc::limits;

        double frac = (result - base) * pow(10, HighPrecision);
        if (result < 0) {
            frac *= -1;
        }
        auto fractionalPart = static_cast<unsigned long int>(round(frac));
        auto fracLength     = utils::to_string(fractionalPart).length();
        auto exponent       = CalculatorConstants::highPrecision - fracLength + 1;
        if (exponent > CalculatorConstants::minusExpLength + 1) {
        auto exponent       = HighPrecision - fracLength + 1;
        if (exponent > MinusExpLength + 1) {
            result *= pow(10, exponent);
            auto exponentLength = utils::to_string(exponent).length();
            auto decimalPlace   = CalculatorConstants::precision - exponentLength - CalculatorConstants::minusExpLength;
            auto decimalPlace   = Precision - exponentLength - MinusExpLength;
            if (result < 0) {
                decimalPlace -= 1;
            }
            return utils::to_string(getCoefficient(result, decimalPlace)) + "e-" + utils::to_string(exponent);
        }
        else if (result < 0) {
            return utils::to_string(getCoefficient(result, CalculatorConstants::lowPrecision));
            return utils::to_string(getCoefficient(result, LowPrecision));
        }
        return utils::to_string(getCoefficient(result, CalculatorConstants::precision));
        return utils::to_string(getCoefficient(result, Precision));
    }

    long double Calculator::getCoefficient(double result, uint32_t precision)

M module-apps/application-calculator/data/CalculatorUtility.hpp => module-apps/application-calculator/data/CalculatorUtility.hpp +0 -11
@@ 6,17 6,6 @@

namespace calc
{
    namespace CalculatorConstants
    {
        inline constexpr auto veryLowPrecision = 4;
        inline constexpr auto lowPrecision     = 5;
        inline constexpr auto precision        = 6;
        inline constexpr auto highPrecision    = 8;
        inline constexpr auto expLength        = 1;
        inline constexpr auto minusExpLength   = 2;
        inline constexpr auto maxStringLength  = 7;
    } // namespace CalculatorConstants

    struct Result
    {
        std::string equation;

M module-apps/application-calculator/tests/CalculatorInput_tests.cpp => module-apps/application-calculator/tests/CalculatorInput_tests.cpp +151 -15
@@ 20,7 20,6 @@ SCENARIO("Input Processor tests")
    GIVEN("An empty input")
    {
        utils::setDisplayLanguage("English");

        auto inputField = gui::Text{};
        auto processor  = calc::InputProcessorText{gsl::make_strict_not_null(&inputField)};



@@ 111,6 110,41 @@ SCENARIO("Input Processor tests")
                    REQUIRE(inputField.isEmpty());
                }
            }

            AND_WHEN("We continue to type")
            {
                passShortKeyPresses(
                    {KeyCodes::NumericKey1, KeyCodes::NumericKey2, KeyCodes::NumericKey3, KeyCodes::NumericKey4});

                THEN("The input is limited to predefined limit")
                {
                    REQUIRE(inputField.getText().length() == calc::limits::MaxInputLength);
                }

                AND_WHEN("We try do delete input")
                {
                    passShortKeyPresses({4, KeyCodes::NumericKeyPnd});

                    THEN("Input is deleted")
                    {
                        REQUIRE(inputField.getText() == "123");
                    }
                }

                AND_WHEN("We try to compute")
                {
                    passShortKeyPresses({MinusKey,
                                         KeyCodes::NumericKey1,
                                         KeyCodes::NumericKey2,
                                         KeyCodes::NumericKey3,
                                         KeyCodes::JoystickEnter});

                    THEN("We are able to")
                    {
                        REQUIRE(inputField.getText() == "1234000");
                    }
                }
            }
        }

        WHEN("We enter leading zeros")


@@ 160,7 194,7 @@ SCENARIO("Input Processor tests")
                }
            }

            AND_WHEN("We try to enter more than 6 decimals")
            AND_WHEN("We try to enter more than 5 decimals")
            {
                passShortKeyPresses({KeyCodes::NumericKey4,
                                     KeyCodes::NumericKey5,


@@ 169,9 203,29 @@ SCENARIO("Input Processor tests")
                                     KeyCodes::NumericKey8,
                                     KeyCodes::NumericKey9});

                THEN("The input is truncated to 6 decimals")
                THEN("The input is truncated")
                {
                    REQUIRE(inputField.getText() == "0.123456");
                    REQUIRE(inputField.getText() == "0.12345");
                }

                AND_WHEN("We try do delete input")
                {
                    passShortKeyPresses({3, KeyCodes::NumericKeyPnd});

                    THEN("Input is deleted")
                    {
                        REQUIRE(inputField.getText() == "0.12");
                    }
                }

                AND_WHEN("We try to do operations")
                {
                    passShortKeyPresses({PlusKey, KeyCodes::NumericKey2, KeyCodes::JoystickEnter});

                    THEN("It is posible")
                    {
                        REQUIRE(inputField.getText() == "2.12345");
                    }
                }
            }
        }


@@ 214,6 268,17 @@ SCENARIO("Input Processor tests")
            {
                REQUIRE(inputField.getText() == "-23");
            }

            AND_WHEN("We try to subtract a negitive number")
            {
                passShortKeyPresses(
                    {MinusKey, MinusKey, KeyCodes::NumericKey1, KeyCodes::NumericKey3, KeyCodes::JoystickEnter});

                THEN("The result is computed properly")
                {
                    REQUIRE(inputField.getText() == "-10");
                }
            }
        }

        WHEN("We enter a number")


@@ 247,9 312,19 @@ SCENARIO("Input Processor tests")
                {
                    passShortKeyPresses({KeyCodes::NumericKey4, KeyCodes::NumericKey5, KeyCodes::NumericKey6});

                    THEN("It is shown")
                    THEN("Previos input is hidden")
                    {
                        REQUIRE(inputField.getText() == "123+456");
                        REQUIRE(inputField.getText() == "456");
                    }

                    AND_WHEN("We press enter")
                    {
                        passShortKeyPress(KeyCodes::JoystickEnter);

                        THEN("The result is computed")
                        {
                            REQUIRE(inputField.getText() == "579");
                        }
                    }
                }



@@ 257,9 332,39 @@ SCENARIO("Input Processor tests")
                {
                    passShortKeyPresses({MinusKey, KeyCodes::NumericKey5, KeyCodes::NumericKey6});

                    THEN("It is shown")
                    THEN("Previous input is hidden and negative number is shown")
                    {
                        REQUIRE(inputField.getText() == "-56");
                    }

                    AND_WHEN("We press enter")
                    {
                        REQUIRE(inputField.getText() == "123+-56");
                        passShortKeyPress(KeyCodes::JoystickEnter);

                        THEN("The result is computed")
                        {
                            REQUIRE(inputField.getText() == "67");
                        }
                    }

                    AND_WHEN("We delete the input")
                    {
                        passShortKeyPresses({3, KeyCodes::NumericKeyPnd});

                        THEN("Input is deleted")
                        {
                            REQUIRE(inputField.getText().empty());
                        }

                        AND_WHEN("We press # again")
                        {
                            passShortKeyPress(KeyCodes::NumericKeyPnd);

                            THEN("Previous input is restored")
                            {
                                REQUIRE(inputField.getText() == "123+");
                            }
                        }
                    }
                }



@@ 290,7 395,7 @@ SCENARIO("Input Processor tests")

                    THEN("It is shown")
                    {
                        REQUIRE(inputField.getText() == "123+4.56");
                        REQUIRE(inputField.getText() == "4.56");
                    }

                    AND_WHEN("We press the fraction key again")


@@ 300,11 405,11 @@ SCENARIO("Input Processor tests")

                        THEN("It is ignored")
                        {
                            REQUIRE(inputField.getText() == "123+4.56456");
                            REQUIRE(inputField.getText() == "4.56456");
                        }
                    }

                    AND_WHEN("We try to enter more than 6 decimals")
                    AND_WHEN("We try to enter more than 5 decimals")
                    {
                        passShortKeyPresses({KeyCodes::NumericKey4,
                                             KeyCodes::NumericKey5,


@@ 313,9 418,9 @@ SCENARIO("Input Processor tests")
                                             KeyCodes::NumericKey8,
                                             KeyCodes::NumericKey9});

                        THEN("The input is truncated to 6 decimals")
                        THEN("The input is truncated")
                        {
                            REQUIRE(inputField.getText() == "123+4.564567");
                            REQUIRE(inputField.getText() == "4.56456");
                        }
                    }
                }


@@ 354,7 459,9 @@ SCENARIO("Input Processor tests")

        WHEN("We do BIG math")
        {
            inputField.setText("99999×99999");
            passShortKeyPresses({5, KeyCodes::NumericKey9});
            passShortKeyPress(MultiplicationKey);
            passShortKeyPresses({5, KeyCodes::NumericKey9});
            passShortKeyPress(KeyCodes::JoystickEnter);

            THEN("Output contains exponent")


@@ 368,7 475,36 @@ SCENARIO("Input Processor tests")

                THEN("Input is cleared before typing")
                {
                    REQUIRE(inputField.getText() == "4-56");
                    REQUIRE(inputField.getText() == "56");
                }
            }
        }

        WHEN("We enter an equation")
        {
            passShortKeyPresses({3, KeyCodes::NumericKey1});
            passShortKeyPress(MultiplicationKey);
            passShortKeyPress(KeyCodes::NumericKey4);

            AND_WHEN("We press another operation")
            {
                passShortKeyPress(PlusKey);

                THEN("The previous operation is computed first")
                {
                    REQUIRE(inputField.getText() == "444+");
                }

                AND_WHEN("We continue input")
                {
                    passShortKeyPress(MinusKey);
                    passShortKeyPresses({3, KeyCodes::NumericKey1});
                    passShortKeyPress(KeyCodes::JoystickEnter);

                    THEN("The following equation is computed properly")
                    {
                        REQUIRE(inputField.getText() == "333");
                    }
                }
            }
        }

M module-apps/application-calculator/tests/CalculatorUtility_tests.cpp => module-apps/application-calculator/tests/CalculatorUtility_tests.cpp +4 -3
@@ 3,6 3,7 @@

#include <catch2/catch.hpp>
#include "application-calculator/data/CalculatorUtility.hpp"
#include "application-calculator/data/CalculatorInputProcessor.hpp"
#include <i18n/i18n.hpp>
#include <cstring>



@@ 97,7 98,7 @@ TEST_CASE("Calculator utilities")
    SECTION("Division by 0")
    {
        auto result = calculator.calculate("15+5÷0");
        REQUIRE(result.value == utils::translate("app_calculator_error"));
        REQUIRE(result.value == calc::symbols::strings::error_str());
        REQUIRE(result.equation == "15+5/0");
        REQUIRE(result.isError);
    }


@@ 105,7 106,7 @@ TEST_CASE("Calculator utilities")
    SECTION("Division 0 by 0")
    {
        auto result = calculator.calculate("0÷0");
        REQUIRE(result.value == utils::translate("app_calculator_error"));
        REQUIRE(result.value == calc::symbols::strings::error_str());
        REQUIRE(result.equation == "0/0");
        REQUIRE(result.isError);
    }


@@ 113,7 114,7 @@ TEST_CASE("Calculator utilities")
    SECTION("Result exceeds maximum number")
    {
        auto result = calculator.calculate("1.79769e+308×2");
        REQUIRE(result.value == utils::translate("app_calculator_error"));
        REQUIRE(result.value == calc::symbols::strings::error_str());
        REQUIRE(result.equation == "1.79769e+308*2");
        REQUIRE(result.isError);
    }

M module-apps/application-calculator/widgets/CalculatorStyle.hpp => module-apps/application-calculator/widgets/CalculatorStyle.hpp +3 -4
@@ 8,8 8,6 @@
namespace style::calculator
{
    inline constexpr auto grid_cells        = 9;
    inline constexpr auto equals            = "app_calculator_equals";
    inline constexpr auto decimal_separator = "app_calculator_decimal_separator";

    namespace window
    {


@@ 19,7 17,8 @@ namespace style::calculator
        inline constexpr auto math_box_cell_width  = style::window::default_body_width / 3;
        inline constexpr auto input_offset_top     = style::header::height + 20;
        inline constexpr auto input_height         = 100;
        inline constexpr auto input_width          = 380;
        inline constexpr auto input_margin         = 50;
        inline constexpr auto input_width          = 400;
        inline constexpr auto input_margin         = 40;
    } // namespace window

} // namespace style::calculator

M module-apps/application-calculator/windows/CalculatorMainWindow.cpp => module-apps/application-calculator/windows/CalculatorMainWindow.cpp +2 -3
@@ 4,7 4,6 @@
#include "CalculatorMainWindow.hpp"
#include "application-calculator/widgets/CalculatorStyle.hpp"
#include "application-calculator/data/CalculatorInputProcessorText.hpp"
#include <i18n/i18n.hpp>

namespace gui
{


@@ 24,8 23,8 @@ namespace gui
        bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
        bottomBar->setActive(gui::BottomBar::Side::LEFT, true);
        bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::translate(style::strings::common::back));
        bottomBar->setText(gui::BottomBar::Side::CENTER, utils::translate(style::calculator::equals));
        bottomBar->setText(gui::BottomBar::Side::LEFT, utils::translate(style::calculator::decimal_separator));
        bottomBar->setText(gui::BottomBar::Side::CENTER, calc::symbols::strings::equals_str());
        bottomBar->setText(gui::BottomBar::Side::LEFT, calc::symbols::strings::decimal_separator_str());
        bottomBar->setFont(BottomBar::Side::LEFT, style::window::font::largelight);

        mathOperationInput = new gui::Text(this,