| @@ -797,10 +797,10 @@ static struct ParameterAdapterTests final : public UnitTest | |||||
| expectEquals (adapter.getTextForDenormalisedValue (value), expected); | expectEquals (adapter.getTextForDenormalisedValue (value), expected); | ||||
| }; | }; | ||||
| test ({ -100, 100 }, 0, "0.0"); | |||||
| test ({ -2.5, 12.5 }, 10, "10.0"); | |||||
| test ({ -20, -10 }, -15, "-15.0"); | |||||
| test ({ 0, 7.5 }, 2.5, "2.5"); | |||||
| test ({ -100, 100 }, 0, "0.00"); | |||||
| test ({ -2.5, 12.5 }, 10, "10.00"); | |||||
| test ({ -20, -10 }, -15, "-15.00"); | |||||
| test ({ 0, 7.5 }, 2.5, "2.50"); | |||||
| } | } | ||||
| beginTest ("Text can be converted to floats"); | beginTest ("Text can be converted to floats"); | ||||
| @@ -469,30 +469,7 @@ namespace NumberToStringConverters | |||||
| o << n; | o << n; | ||||
| } | } | ||||
| return findLengthWithoutTrailingZeros (pbase(), pptr()); | |||||
| } | |||||
| static size_t findLengthWithoutTrailingZeros (const char* const start, | |||||
| const char* const end) | |||||
| { | |||||
| for (auto e = end; e > start + 1; --e) | |||||
| { | |||||
| auto lastChar = *(e - 1); | |||||
| if (lastChar != '0') | |||||
| { | |||||
| if (lastChar == '.') | |||||
| return (size_t) (e + 1 - start); | |||||
| for (auto s = start; s < e; ++s) | |||||
| if (*s == '.') | |||||
| return (size_t) (e - start); | |||||
| break; | |||||
| } | |||||
| } | |||||
| return (size_t) (end - start); | |||||
| return (size_t) (pptr() - pbase()); | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -505,14 +482,7 @@ namespace NumberToStringConverters | |||||
| auto v = (int64) (std::pow (10.0, numDecPlaces) * std::abs (n) + 0.5); | auto v = (int64) (std::pow (10.0, numDecPlaces) * std::abs (n) + 0.5); | ||||
| *--t = (char) 0; | *--t = (char) 0; | ||||
| // skip trailing zeros | |||||
| while (numDecPlaces > 1 && (v % 10) == 0) | |||||
| { | |||||
| v /= 10; | |||||
| --numDecPlaces; | |||||
| } | |||||
| while (v > 0 || numDecPlaces >= 0) | |||||
| while (numDecPlaces >= 0 || v > 0) | |||||
| { | { | ||||
| if (numDecPlaces == 0) | if (numDecPlaces == 0) | ||||
| *--t = '.'; | *--t = '.'; | ||||
| @@ -2523,14 +2493,7 @@ public: | |||||
| expect (String::toHexString (data, 8, 1).equalsIgnoreCase ("01 02 03 04 0a 0b 0c 0d")); | expect (String::toHexString (data, 8, 1).equalsIgnoreCase ("01 02 03 04 0a 0b 0c 0d")); | ||||
| expect (String::toHexString (data, 8, 2).equalsIgnoreCase ("0102 0304 0a0b 0c0d")); | expect (String::toHexString (data, 8, 2).equalsIgnoreCase ("0102 0304 0a0b 0c0d")); | ||||
| expectEquals (String (2589410.5894, 7), String ("2589410.5894")); | |||||
| expectEquals (String (2589410.5894, 4), String ("2589410.5894")); | |||||
| expectEquals (String (100000.0, 1), String ("100000.0")); | |||||
| expectEquals (String (100000.0, 10), String ("100000.0")); | |||||
| expectEquals (String (100000.001, 8), String ("100000.001")); | |||||
| expectEquals (String (100000.001, 4), String ("100000.001")); | |||||
| expectEquals (String (100000.001, 3), String ("100000.001")); | |||||
| expectEquals (String (100000.001, 2), String ("100000.0")); | |||||
| expectEquals (String (2589410.5894, 7), String ("2589410.5894000")); | |||||
| beginTest ("Subsections"); | beginTest ("Subsections"); | ||||
| String s3; | String s3; | ||||
| @@ -962,23 +962,23 @@ public: | |||||
| /** Creates a string representing this floating-point number. | /** Creates a string representing this floating-point number. | ||||
| @param floatValue the value to convert to a string | @param floatValue the value to convert to a string | ||||
| @param maxNumberOfDecimalPlaces if this is > 0, it will format the number using no more | |||||
| decimal places than this amount, and will not use exponent | |||||
| notation. If 0 or less, it will use a default format, and | |||||
| @param numberOfDecimalPlaces if this is > 0, it will format the number using that many | |||||
| decimal places, adding trailing zeros as required, and | |||||
| will not use exponent notation. If 0 or less, it will use | |||||
| exponent notation if necessary. | exponent notation if necessary. | ||||
| @see getDoubleValue, getIntValue | @see getDoubleValue, getIntValue | ||||
| */ | */ | ||||
| String (float floatValue, int maxNumberOfDecimalPlaces); | |||||
| String (float floatValue, int numberOfDecimalPlaces); | |||||
| /** Creates a string representing this floating-point number. | /** Creates a string representing this floating-point number. | ||||
| @param doubleValue the value to convert to a string | @param doubleValue the value to convert to a string | ||||
| @param maxNumberOfDecimalPlaces if this is > 0, it will format the number using no more | |||||
| decimal places than this amount, and will not use exponent | |||||
| notation. If 0 or less, it will use a default format, and | |||||
| @param numberOfDecimalPlaces if this is > 0, it will format the number using that many | |||||
| decimal places, adding trailing zeros as required, and | |||||
| will not use exponent notation. If 0 or less, it will use | |||||
| exponent notation if necessary. | exponent notation if necessary. | ||||
| @see getFloatValue, getIntValue | @see getFloatValue, getIntValue | ||||
| */ | */ | ||||
| String (double doubleValue, int maxNumberOfDecimalPlaces); | |||||
| String (double doubleValue, int numberOfDecimalPlaces); | |||||
| // Automatically creating a String from a bool opens up lots of nasty type conversion edge cases. | // Automatically creating a String from a bool opens up lots of nasty type conversion edge cases. | ||||
| // If you want a String representation of a bool you can cast the bool to an int first. | // If you want a String representation of a bool you can cast the bool to an int first. | ||||
| @@ -578,9 +578,26 @@ void XmlElement::setAttribute (const Identifier& attributeName, const int number | |||||
| setAttribute (attributeName, String (number)); | setAttribute (attributeName, String (number)); | ||||
| } | } | ||||
| static String trimTrailingZeros (const String& input) | |||||
| { | |||||
| auto pointPos = input.indexOfChar ('.'); | |||||
| if (pointPos == -1) | |||||
| return input; | |||||
| auto start = input.getCharPointer(); | |||||
| auto minPos = start + pointPos + 1; | |||||
| auto ptr = start + input.length() - 1; | |||||
| while (ptr != minPos && *ptr == '0') | |||||
| --ptr; | |||||
| return input.substring (0, (int) (ptr - start) + 1); | |||||
| } | |||||
| void XmlElement::setAttribute (const Identifier& attributeName, const double number) | void XmlElement::setAttribute (const Identifier& attributeName, const double number) | ||||
| { | { | ||||
| setAttribute (attributeName, String (number, 20)); | |||||
| setAttribute (attributeName, trimTrailingZeros ({ number, 20 })); | |||||
| } | } | ||||
| void XmlElement::removeAttribute (const Identifier& attributeName) noexcept | void XmlElement::removeAttribute (const Identifier& attributeName) noexcept | ||||
| @@ -923,4 +940,30 @@ void XmlElement::deleteAllTextElements() noexcept | |||||
| } | } | ||||
| } | } | ||||
| //============================================================================== | |||||
| #if JUCE_UNIT_TESTS | |||||
| class XmlElementTests : public UnitTest | |||||
| { | |||||
| public: | |||||
| XmlElementTests() : UnitTest ("XmlElement", "XML") {} | |||||
| void runTest() override | |||||
| { | |||||
| { | |||||
| beginTest ("Trailing zeros"); | |||||
| auto element = std::make_unique<XmlElement> ("test"); | |||||
| Identifier d ("d"); | |||||
| element->setAttribute (d, 3.0); | |||||
| expectEquals (element->getStringAttribute (d), String ("3.0")); | |||||
| } | |||||
| } | |||||
| }; | |||||
| static XmlElementTests xmlElementTests; | |||||
| #endif | |||||
| } // namespace juce | } // namespace juce | ||||