Skip to content

Commit 47fb873

Browse files
[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.
1 parent c12490f commit 47fb873

File tree

6 files changed

+127
-17
lines changed

6 files changed

+127
-17
lines changed

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
* `[GUI][messages]` Fixed not showing number on deleting temporary contact
2323
* `[GUI]` Fixed filling Label with color
24+
* `[calculator]` Fix phone hanging when pressing '='.
2425

2526
## [0.44.1 2020-10-30]
2627

module-apps/application-calculator/data/CalculatorUtility.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "application-calculator/widgets/CalculatorStyle.hpp"
66
#include <module-utils/tinyexpr/tinyexpr.h>
77
#include <module-utils/i18/i18.hpp>
8+
#include <Utils.hpp>
89
#include <cmath>
910

1011
Result Calculator::calculate(std::string source)
@@ -13,13 +14,7 @@ Result Calculator::calculate(std::string source)
1314
int error;
1415
double result = te_interp(source.c_str(), &error);
1516
if (error == 0 && !std::isinf(result) && !std::isnan(result)) {
16-
auto output = std::to_string(result);
17-
if (output.find_last_not_of('0') != std::string::npos) {
18-
output.erase(output.find_last_not_of('0') + 1);
19-
}
20-
if (output.find_last_not_of(style::calculator::symbols::strings::full_stop) != std::string::npos) {
21-
output.erase(output.find_last_not_of(style::calculator::symbols::strings::full_stop) + 1);
22-
}
17+
auto output = utils::to_string(result);
2318
if (utils::localize.get("app_calculator_decimal_separator") == style::calculator::symbols::strings::comma) {
2419
output.replace(output.find(style::calculator::symbols::strings::full_stop),
2520
style::calculator::symbols::strings::full_stop.length(),

module-apps/application-calculator/windows/CalculatorMainWindow.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,16 +108,16 @@ namespace gui
108108
if (!mathOperationInput->getText().empty()) {
109109

110110
if (lastCharIsSymbol && symbol != style::calculator::symbols::strings::minus) {
111-
mathOperationInput->setText(
111+
mathOperationInput->setRichText(
112112
std::string(mathOperationInput->getText()).erase(mathOperationInput->getText().length() - 1) +
113113
symbol.c_str());
114114
}
115115
else {
116-
mathOperationInput->setText(mathOperationInput->getText() + symbol);
116+
mathOperationInput->setRichText(mathOperationInput->getText() + symbol);
117117
}
118118
}
119119
else if (symbol == style::calculator::symbols::strings::minus) {
120-
mathOperationInput->setText(mathOperationInput->getText() + symbol);
120+
mathOperationInput->setRichText(mathOperationInput->getText() + symbol);
121121
}
122122
}
123123

@@ -156,7 +156,7 @@ namespace gui
156156

157157
if (inputEvent.keyCode == gui::KeyCode::KEY_ENTER) {
158158
auto result = Calculator().calculate(std::string(mathOperationInput->getText()));
159-
mathOperationInput->setText(result.value);
159+
mathOperationInput->setRichText(result.value);
160160
clearInput = result.isError;
161161
return true;
162162
}

module-utils/Utils.hpp

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <log/log.hpp>
88
#include <sstream>
99
#include <iomanip>
10+
#include <cmath>
1011

1112
#define MAGIC_ENUM_RANGE_MAX 256
1213
#include <magic_enum.hpp>
@@ -89,14 +90,62 @@ namespace utils
8990
return rtrim(ltrim(s));
9091
}
9192

92-
template <typename T> std::string to_string(T t, size_t minStringLength = 0)
93+
static inline std::string addLeadingZeros(std::string base, size_t minStringLength = 0)
9394
{
95+
if (base.length() >= minStringLength) {
96+
return base;
97+
}
9498
constexpr auto leadingDigit = '0';
99+
base.insert(0, minStringLength - base.length(), leadingDigit);
100+
return base;
101+
}
102+
103+
template <typename T> std::string to_string(T t)
104+
{
95105
std::ostringstream ss;
96-
ss << std::setfill(leadingDigit) << std::setw(minStringLength) << t;
106+
ss << t;
97107
return ss.str();
98108
}
99109

110+
template <> inline std::string to_string<long double>(long double t)
111+
{
112+
uint32_t precision = 6;
113+
int base = static_cast<int>(t);
114+
long double frac = (t - base) * pow(10, precision);
115+
auto baseAsStr = std::to_string(base);
116+
if (t < 0) {
117+
frac *= -1;
118+
if (base == 0) {
119+
baseAsStr = "-0";
120+
}
121+
}
122+
auto fractionalPart = static_cast<unsigned long int>(roundl(frac));
123+
if (fractionalPart == 0) {
124+
if (baseAsStr == "-0") {
125+
return "0";
126+
}
127+
return baseAsStr;
128+
}
129+
auto fractionalAsStr = std::to_string(fractionalPart);
130+
if (fractionalAsStr.size() < precision) {
131+
fractionalAsStr.insert(0, precision - fractionalAsStr.size(), '0');
132+
}
133+
if (fractionalAsStr.find_last_not_of('0') != std::string::npos) {
134+
fractionalAsStr.erase(fractionalAsStr.find_last_not_of('0') + 1);
135+
}
136+
return baseAsStr + "." + fractionalAsStr;
137+
}
138+
139+
template <> inline std::string to_string<float>(float t)
140+
{
141+
return to_string((long double)(t));
142+
}
143+
144+
template <> inline std::string to_string<double>(double t)
145+
{
146+
return to_string((long double)(t));
147+
}
148+
100149
template <typename T>[[nodiscard]] const std::string enumToString(const T &t)
101150
{
102151
static_assert(std::is_enum_v<T>);

module-utils/test/unittest_utils.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,3 +208,64 @@ TEST_CASE("Swap endianness")
208208
REQUIRE(((as_long >> 8 * 0) & 0xFF) == ((as_long_swapped >> 8 * 3) & 0xFF));
209209
}
210210
}
211+
212+
TEST_CASE("Floating point to string")
213+
{
214+
SECTION("Double")
215+
{
216+
double test = 15.0965432456321;
217+
REQUIRE(utils::to_string(test) == "15.096543");
218+
}
219+
220+
SECTION("Negative double")
221+
{
222+
double test = -15.0965432456321;
223+
REQUIRE(utils::to_string(test) == "-15.096543");
224+
}
225+
226+
SECTION("Double between 0 and 1")
227+
{
228+
double test = 0.08654328765876;
229+
REQUIRE(utils::to_string(test) == "0.086543");
230+
}
231+
232+
SECTION("Double between -1 and 0")
233+
{
234+
double test = -0.08654328765876;
235+
REQUIRE(utils::to_string(test) == "-0.086543");
236+
}
237+
238+
SECTION("Float")
239+
{
240+
float test = 15.0543212;
241+
REQUIRE(utils::to_string(test) == "15.054321");
242+
}
243+
244+
SECTION("Negative float")
245+
{
246+
float test = -15.0543212;
247+
REQUIRE(utils::to_string(test) == "-15.054321");
248+
}
249+
250+
SECTION("Float between 0 and 1")
251+
{
252+
float test = 0.0453212;
253+
REQUIRE(utils::to_string(test) == "0.045321");
254+
}
255+
256+
SECTION("Float between -1 and 0")
257+
{
258+
float test = -0.0453212;
259+
REQUIRE(utils::to_string(test) == "-0.045321");
260+
}
261+
}
262+
263+
TEST_CASE("Fill leading digit in string")
264+
{
265+
std::string test = "45";
266+
REQUIRE(utils::addLeadingZeros(test) == "45");
267+
REQUIRE(utils::addLeadingZeros(test, 1) == "45");
268+
REQUIRE(utils::addLeadingZeros(test, 2) == "45");
269+
REQUIRE(utils::addLeadingZeros(test, 3) == "045");
270+
REQUIRE(utils::addLeadingZeros(test, 4) == "0045");
271+
}

module-utils/time/time_conversion.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,14 @@ namespace utils
264264
utils::findAndReplaceAll(format, "%M", utils::to_string(minutes));
265265
utils::findAndReplaceAll(format, "%N", utils::to_string(hmminutes));
266266
utils::findAndReplaceAll(format, "%S", utils::to_string(seconds));
267-
utils::findAndReplaceAll(format, "%0H", utils::to_string(hours, numberOfLeadingDigits));
268-
utils::findAndReplaceAll(format, "%0M", utils::to_string(minutes, numberOfLeadingDigits));
269-
utils::findAndReplaceAll(format, "%0N", utils::to_string(hmminutes, numberOfLeadingDigits));
270-
utils::findAndReplaceAll(format, "%0S", utils::to_string(seconds, numberOfLeadingDigits));
267+
utils::findAndReplaceAll(
268+
format, "%0H", utils::addLeadingZeros(utils::to_string(hours), numberOfLeadingDigits));
269+
utils::findAndReplaceAll(
270+
format, "%0M", utils::addLeadingZeros(utils::to_string(minutes), numberOfLeadingDigits));
271+
utils::findAndReplaceAll(
272+
format, "%0N", utils::addLeadingZeros(utils::to_string(hmminutes), numberOfLeadingDigits));
273+
utils::findAndReplaceAll(
274+
format, "%0S", utils::addLeadingZeros(utils::to_string(seconds), numberOfLeadingDigits));
271275
}
272276

273277
void Duration::calculate()

0 commit comments

Comments
 (0)