From f0fb9f51eff0b822a97019b0818c6853d3ad2e98 Mon Sep 17 00:00:00 2001 From: KacperLewandowski <40142549+KacperLewandowski@users.noreply.github.com> Date: Wed, 4 Nov 2020 13:02:09 +0100 Subject: [PATCH] [EGD-4103] Fix phone hanging when pressing '=' in calculator (#891) Crush was caused when using std::to_string() on rt1051 to convert double (result from equation) to string. Other methods f.e. using std::stringstream, sprintf also do not work. Add own floating point converter to string. --- changelog.md | 1 + .../data/CalculatorUtility.cpp | 9 +-- .../windows/CalculatorMainWindow.cpp | 8 +-- module-utils/Utils.hpp | 53 +++++++++++++++- module-utils/test/unittest_utils.cpp | 61 +++++++++++++++++++ module-utils/time/time_conversion.cpp | 12 ++-- 6 files changed, 127 insertions(+), 17 deletions(-) diff --git a/changelog.md b/changelog.md index f5c7cb31c2b2fa5941c802251aa8b023a545ffce..96254a8450bb7786f328a390adf7d885a3d3f7c1 100644 --- a/changelog.md +++ b/changelog.md @@ -21,6 +21,7 @@ * `[GUI][messages]` Fixed not showing number on deleting temporary contact * `[GUI]` Fixed filling Label with color +* `[calculator]` Fix phone hanging when pressing '='. ## [0.44.1 2020-10-30] diff --git a/module-apps/application-calculator/data/CalculatorUtility.cpp b/module-apps/application-calculator/data/CalculatorUtility.cpp index 7a06875f233aed8eadbe43d4e1c3c93a0cf2dded..577770420e07727c1864f32eebe067f93642a5a6 100644 --- a/module-apps/application-calculator/data/CalculatorUtility.cpp +++ b/module-apps/application-calculator/data/CalculatorUtility.cpp @@ -5,6 +5,7 @@ #include "application-calculator/widgets/CalculatorStyle.hpp" #include #include +#include #include Result Calculator::calculate(std::string source) @@ -13,13 +14,7 @@ Result Calculator::calculate(std::string source) int error; double result = te_interp(source.c_str(), &error); if (error == 0 && !std::isinf(result) && !std::isnan(result)) { - auto output = std::to_string(result); - if (output.find_last_not_of('0') != std::string::npos) { - output.erase(output.find_last_not_of('0') + 1); - } - if (output.find_last_not_of(style::calculator::symbols::strings::full_stop) != std::string::npos) { - output.erase(output.find_last_not_of(style::calculator::symbols::strings::full_stop) + 1); - } + auto output = utils::to_string(result); if (utils::localize.get("app_calculator_decimal_separator") == style::calculator::symbols::strings::comma) { output.replace(output.find(style::calculator::symbols::strings::full_stop), style::calculator::symbols::strings::full_stop.length(), diff --git a/module-apps/application-calculator/windows/CalculatorMainWindow.cpp b/module-apps/application-calculator/windows/CalculatorMainWindow.cpp index c95548a6b9d19fd68bb39d45aa194a1ad415e5c2..c8a7ae347ded8f4796ac64339eaa94467df55476 100644 --- a/module-apps/application-calculator/windows/CalculatorMainWindow.cpp +++ b/module-apps/application-calculator/windows/CalculatorMainWindow.cpp @@ -108,16 +108,16 @@ namespace gui if (!mathOperationInput->getText().empty()) { if (lastCharIsSymbol && symbol != style::calculator::symbols::strings::minus) { - mathOperationInput->setText( + mathOperationInput->setRichText( std::string(mathOperationInput->getText()).erase(mathOperationInput->getText().length() - 1) + symbol.c_str()); } else { - mathOperationInput->setText(mathOperationInput->getText() + symbol); + mathOperationInput->setRichText(mathOperationInput->getText() + symbol); } } else if (symbol == style::calculator::symbols::strings::minus) { - mathOperationInput->setText(mathOperationInput->getText() + symbol); + mathOperationInput->setRichText(mathOperationInput->getText() + symbol); } } @@ -156,7 +156,7 @@ namespace gui if (inputEvent.keyCode == gui::KeyCode::KEY_ENTER) { auto result = Calculator().calculate(std::string(mathOperationInput->getText())); - mathOperationInput->setText(result.value); + mathOperationInput->setRichText(result.value); clearInput = result.isError; return true; } diff --git a/module-utils/Utils.hpp b/module-utils/Utils.hpp index 18cda8d225d1b39dcde9056e8a53ac5ae87e1e84..658a0bacee94323a72ba7f854ee6093d84cb6058 100644 --- a/module-utils/Utils.hpp +++ b/module-utils/Utils.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #define MAGIC_ENUM_RANGE_MAX 256 #include @@ -89,14 +90,62 @@ namespace utils return rtrim(ltrim(s)); } - template std::string to_string(T t, size_t minStringLength = 0) + static inline std::string addLeadingZeros(std::string base, size_t minStringLength = 0) { + if (base.length() >= minStringLength) { + return base; + } constexpr auto leadingDigit = '0'; + base.insert(0, minStringLength - base.length(), leadingDigit); + return base; + } + + template std::string to_string(T t) + { std::ostringstream ss; - ss << std::setfill(leadingDigit) << std::setw(minStringLength) << t; + ss << t; return ss.str(); } + template <> inline std::string to_string(long double t) + { + uint32_t precision = 6; + int base = static_cast(t); + long double frac = (t - base) * pow(10, precision); + auto baseAsStr = std::to_string(base); + if (t < 0) { + frac *= -1; + if (base == 0) { + baseAsStr = "-0"; + } + } + auto fractionalPart = static_cast(roundl(frac)); + if (fractionalPart == 0) { + if (baseAsStr == "-0") { + return "0"; + } + return baseAsStr; + } + auto fractionalAsStr = std::to_string(fractionalPart); + if (fractionalAsStr.size() < precision) { + fractionalAsStr.insert(0, precision - fractionalAsStr.size(), '0'); + } + if (fractionalAsStr.find_last_not_of('0') != std::string::npos) { + fractionalAsStr.erase(fractionalAsStr.find_last_not_of('0') + 1); + } + return baseAsStr + "." + fractionalAsStr; + } + + template <> inline std::string to_string(float t) + { + return to_string((long double)(t)); + } + + template <> inline std::string to_string(double t) + { + return to_string((long double)(t)); + } + template [[nodiscard]] const std::string enumToString(const T &t) { static_assert(std::is_enum_v); diff --git a/module-utils/test/unittest_utils.cpp b/module-utils/test/unittest_utils.cpp index 029727659c385ad403c4d07e86058559a559dd99..a4a25f97337bdb53bab0e5b19bd7f00969c63659 100644 --- a/module-utils/test/unittest_utils.cpp +++ b/module-utils/test/unittest_utils.cpp @@ -208,3 +208,64 @@ TEST_CASE("Swap endianness") REQUIRE(((as_long >> 8 * 0) & 0xFF) == ((as_long_swapped >> 8 * 3) & 0xFF)); } } + +TEST_CASE("Floating point to string") +{ + SECTION("Double") + { + double test = 15.0965432456321; + REQUIRE(utils::to_string(test) == "15.096543"); + } + + SECTION("Negative double") + { + double test = -15.0965432456321; + REQUIRE(utils::to_string(test) == "-15.096543"); + } + + SECTION("Double between 0 and 1") + { + double test = 0.08654328765876; + REQUIRE(utils::to_string(test) == "0.086543"); + } + + SECTION("Double between -1 and 0") + { + double test = -0.08654328765876; + REQUIRE(utils::to_string(test) == "-0.086543"); + } + + SECTION("Float") + { + float test = 15.0543212; + REQUIRE(utils::to_string(test) == "15.054321"); + } + + SECTION("Negative float") + { + float test = -15.0543212; + REQUIRE(utils::to_string(test) == "-15.054321"); + } + + SECTION("Float between 0 and 1") + { + float test = 0.0453212; + REQUIRE(utils::to_string(test) == "0.045321"); + } + + SECTION("Float between -1 and 0") + { + float test = -0.0453212; + REQUIRE(utils::to_string(test) == "-0.045321"); + } +} + +TEST_CASE("Fill leading digit in string") +{ + std::string test = "45"; + REQUIRE(utils::addLeadingZeros(test) == "45"); + REQUIRE(utils::addLeadingZeros(test, 1) == "45"); + REQUIRE(utils::addLeadingZeros(test, 2) == "45"); + REQUIRE(utils::addLeadingZeros(test, 3) == "045"); + REQUIRE(utils::addLeadingZeros(test, 4) == "0045"); +} diff --git a/module-utils/time/time_conversion.cpp b/module-utils/time/time_conversion.cpp index ec7e503c0f8ca4a1ae1e9cf9f79556de4b6e4b6f..7df9db8a5a1bd5a2bd745ac8931ba2bde381fcba 100644 --- a/module-utils/time/time_conversion.cpp +++ b/module-utils/time/time_conversion.cpp @@ -264,10 +264,14 @@ namespace utils utils::findAndReplaceAll(format, "%M", utils::to_string(minutes)); utils::findAndReplaceAll(format, "%N", utils::to_string(hmminutes)); utils::findAndReplaceAll(format, "%S", utils::to_string(seconds)); - utils::findAndReplaceAll(format, "%0H", utils::to_string(hours, numberOfLeadingDigits)); - utils::findAndReplaceAll(format, "%0M", utils::to_string(minutes, numberOfLeadingDigits)); - utils::findAndReplaceAll(format, "%0N", utils::to_string(hmminutes, numberOfLeadingDigits)); - utils::findAndReplaceAll(format, "%0S", utils::to_string(seconds, numberOfLeadingDigits)); + utils::findAndReplaceAll( + format, "%0H", utils::addLeadingZeros(utils::to_string(hours), numberOfLeadingDigits)); + utils::findAndReplaceAll( + format, "%0M", utils::addLeadingZeros(utils::to_string(minutes), numberOfLeadingDigits)); + utils::findAndReplaceAll( + format, "%0N", utils::addLeadingZeros(utils::to_string(hmminutes), numberOfLeadingDigits)); + utils::findAndReplaceAll( + format, "%0S", utils::addLeadingZeros(utils::to_string(seconds), numberOfLeadingDigits)); } void Duration::calculate()