diff --git a/libs/flake/KoOdfWorkaround.cpp b/libs/flake/KoOdfWorkaround.cpp --- a/libs/flake/KoOdfWorkaround.cpp +++ b/libs/flake/KoOdfWorkaround.cpp @@ -235,7 +235,7 @@ KoOdfLoadingContext::GeneratorType type(context.odfLoadingContext().generatorType()); if (type == KoOdfLoadingContext::OpenOffice && !positionString.endsWith('%')) { const qreal pos = KoUnit::parseValue(positionString); - positionString = QString("%1%%").arg(KoUnit::toMillimeter(pos)); + positionString = QString("%1%%").arg(KoUnit(KoUnit::Millimeter).toUserValue(pos)); } } diff --git a/libs/odf/KoUnit.h b/libs/odf/KoUnit.h --- a/libs/odf/KoUnit.h +++ b/libs/odf/KoUnit.h @@ -56,6 +56,20 @@ constexpr qreal PI_TO_POINT(qreal pi) {return (pi)*12;} constexpr qreal CC_TO_POINT(qreal cc) {return (cc)*12.840103;} + +static const qreal PT_ROUNDING {1000.0}; +//static const qreal PX_ROUNDING {1000.0}; // pixel value is not to be rounded + +static const qreal CM_ROUNDING {10000.0}; +static const qreal DM_ROUNDING {10000.0}; +static const qreal MM_ROUNDING {10000.0}; + +static const qreal IN_ROUNDING {100000.0}; + +static const qreal PI_ROUNDING {100000.0}; // pico +static const qreal CC_ROUNDING {100000.0}; // cicero + + /** * %Calligra stores everything in pt (using "qreal") internally. * When displaying a value to the user, the value is converted to the user's unit @@ -125,85 +139,35 @@ void setFactor(qreal factor) { m_pixelConversion = factor; } - /** - * Prepare ptValue to be displayed in pt - * This method will round to 0.001 precision - */ - static qreal toPoint(qreal ptValue) { - // No conversion, only rounding (to 0.001 precision) - return floor(ptValue * 1000.0) / 1000.0; - } - - /** - * Prepare ptValue to be displayed in mm - * This method will round to 0.0001 precision, use POINT_TO_MM() for lossless conversion. - */ - static qreal toMillimeter(qreal ptValue) { - // "mm" values are rounded to 0.0001 millimeters - return floor(POINT_TO_MM(ptValue) * 10000.0) / 10000.0; - } - - /** - * Prepare ptValue to be displayed in cm - * This method will round to 0.0001 precision, use POINT_TO_CM() for lossless conversion. - */ - static qreal toCentimeter(qreal ptValue) { - return floor(POINT_TO_CM(ptValue) * 10000.0) / 10000.0; - } - /** - * Prepare ptValue to be displayed in dm - * This method will round to 0.0001 precision, use POINT_TO_DM() for lossless conversion. - */ - static qreal toDecimeter(qreal ptValue) { - return floor(POINT_TO_DM(ptValue) * 10000.0) / 10000.0; - } /** - * Prepare ptValue to be displayed in inch - * This method will round to 0.00001 precision, use POINT_TO_INCH() for lossless conversion. + * convert the given value directly from one unit to another */ - static qreal toInch(qreal ptValue) { - // "in" values are rounded to 0.00001 inches - return floor(POINT_TO_INCH(ptValue) * 100000.0) / 100000.0; - } + static qreal convertFromUnitToUnit(const qreal value, const KoUnit &fromUnit, const KoUnit &toUnit, qreal factor = 1.0); /** - * Prepare ptValue to be displayed in pica - * This method will round to 0.00001 precision, use POINT_TO_PI() for lossless conversion. + * Convert the value @p ptValue to the unit and round it. + * This method is meant to be used to display a value in a dialog. + * \return the converted and rounded value */ - static qreal toPica(qreal ptValue) { - // "pi" values are rounded to 0.00001 inches - return floor(POINT_TO_PI(ptValue) * 100000.0) / 100000.0; - } + qreal toUserValueRounded(const qreal value) const; /** - * Prepare ptValue to be displayed in cicero - * This method will round to 0.00001 precision, use POINT_TO_CC() for lossless conversion. + * Convert the value @p ptValue to the unit (without rounding) + * This method is meant to be used in complex calculations. + * \return the converted value */ - static qreal toCicero(qreal ptValue) { - // "cc" values are rounded to 0.00001 inches - return floor(POINT_TO_CC(ptValue) * 100000.0) / 100000.0; - } + qreal toUserValuePrecise(const qreal ptValue) const; /** - * convert the given value directly from one unit to another + * Convert the value @p ptValue with or with rounding as indicated by @p rounding. + * This method is a proxy to toUserValuePrecise and toUserValueRounded. + * \return the value @p ptValue converted to unit */ - static qreal convertFromUnitToUnit(const qreal value, const KoUnit &fromUnit, const KoUnit &toUnit, qreal factor = 1.0); + qreal toUserValue(qreal ptValue, bool rounding = true) const; - /** - * This method is the one to use to display a value in a dialog - * \return the value @p ptValue converted to unit and rounded, ready to be displayed - */ - qreal toUserValue(qreal ptValue) const; - - /** - * Convert the value @p ptValue to a given unit @p unit - * Unlike KoUnit::ptToUnit the return value remains unrounded, so that it can be used in complex calculation - * \return the converted value - */ - static qreal ptToUnit(const qreal ptValue, const KoUnit &unit); /// This method is the one to use to display a value in a dialog /// @return the value @p ptValue converted the unit and rounded, ready to be displayed diff --git a/libs/odf/KoUnit.cpp b/libs/odf/KoUnit.cpp --- a/libs/odf/KoUnit.cpp +++ b/libs/odf/KoUnit.cpp @@ -135,32 +135,46 @@ return result; } -qreal KoUnit::toUserValue(qreal ptValue) const + + +qreal KoUnit::toUserValueRounded(const qreal value) const { + qreal userValue = toUserValuePrecise(value); + qreal rounding = 1.0; + switch (m_type) { + case Pixel: + return userValue; // no rounding for Pixel value case Millimeter: - return toMillimeter(ptValue); + rounding = MM_ROUNDING; + break; case Centimeter: - return toCentimeter(ptValue); + rounding = CM_ROUNDING; + break; case Decimeter: - return toDecimeter(ptValue); + rounding = DM_ROUNDING; + break; case Inch: - return toInch(ptValue); + rounding = IN_ROUNDING; + break; case Pica: - return toPica(ptValue); + rounding = PI_ROUNDING; + break; case Cicero: - return toCicero(ptValue); - case Pixel: - return ptValue * m_pixelConversion; + rounding = CC_ROUNDING; + break; case Point: default: - return toPoint(ptValue); + rounding = PT_ROUNDING; } + + + return floor(userValue * rounding) / rounding; } -qreal KoUnit::ptToUnit(const qreal ptValue, const KoUnit &unit) +qreal KoUnit::toUserValuePrecise(const qreal ptValue) const { - switch (unit.m_type) { + switch (m_type) { case Millimeter: return POINT_TO_MM(ptValue); case Centimeter: @@ -174,13 +188,25 @@ case Cicero: return POINT_TO_CC(ptValue); case Pixel: - return ptValue * unit.m_pixelConversion; + return ptValue * m_pixelConversion; case Point: default: return ptValue; } } + + +qreal KoUnit::toUserValue(qreal ptValue, bool rounding) const +{ + if (rounding) { + return toUserValueRounded(ptValue); + } + else { + return toUserValuePrecise(ptValue); + } +} + QString KoUnit::toUserStringValue(qreal ptValue) const { return QLocale().toString(toUserValue(ptValue)); diff --git a/libs/odf/tests/TestKoUnit.h b/libs/odf/tests/TestKoUnit.h --- a/libs/odf/tests/TestKoUnit.h +++ b/libs/odf/tests/TestKoUnit.h @@ -40,6 +40,8 @@ void testFromSymbol(); void testListForUi_data(); void testListForUi(); + void testToUserValue_data(); + void testToUserValue(); }; #endif diff --git a/libs/odf/tests/TestKoUnit.cpp b/libs/odf/tests/TestKoUnit.cpp --- a/libs/odf/tests/TestKoUnit.cpp +++ b/libs/odf/tests/TestKoUnit.cpp @@ -59,7 +59,7 @@ { KoUnit unit(KoUnit::Pixel, 0.5); QCOMPARE(unit.type(), KoUnit::Pixel); - QCOMPARE(KoUnit::ptToUnit(100, unit), (qreal)50); + QCOMPARE(unit.toUserValue(100, false), (qreal)50); } void TestKoUnit::testAssignOperator_data() @@ -159,4 +159,54 @@ QCOMPARE(unit.indexInListForUi(listOptions), index); } + +void TestKoUnit::testToUserValue_data() +{ + // regression test to check whether changes in KoUnit changes the conversion output + + QTest::addColumn("type"); + QTest::addColumn("value"); + QTest::addColumn("expected"); + QTest::addColumn("expectedRounded"); + + + // 1000.0 + QTest::newRow("point 1000") << KoUnit::Point << 1000.0 << 1000.0 << 1000.0; + QTest::newRow("pica 1000") << KoUnit::Pica << 1000.0 << 83.3333330000 << 83.3333300000; + QTest::newRow("pixel 1000") << KoUnit::Pixel << 1000.0 << 1000.0 << 1000.0; + QTest::newRow("inch 1000") << KoUnit::Inch << 1000.0 << 13.8888888889 << 13.8888800000; + QTest::newRow("decimeter 1000") << KoUnit::Decimeter << 1000.0 << 3.5277716700 << 3.5277000000; + + // 1.37 + QTest::newRow("point 1.37") << KoUnit::Point << 1.37 << 1.37 << 1.37; + QTest::newRow("pica 1.37") << KoUnit::Pica << 1.37 << 0.114166666210 << 0.1141600000; + QTest::newRow("pixel 1.37") << KoUnit::Pixel << 1.37 << 1.37 << 1.37; + QTest::newRow("inch 1.37") << KoUnit::Inch << 1.37 << 0.019027777777779 << 0.019020000000; + QTest::newRow("decimeter 1.37") << KoUnit::Decimeter << 1.37 << 0.004833047187900 << 0.004800000000; + + // 0.0001111 + QTest::newRow("point 0.0001111") << KoUnit::Point << 0.0001111 << 0.000111100000 << 0.0 ; + QTest::newRow("pica 0.0001111") << KoUnit::Pica << 0.0001111 << 0.00000925833329630 << 0.0; + QTest::newRow("pixel 0.0001111") << KoUnit::Pixel << 0.0001111 << 0.000111100000 << 0.000111100000 ; + QTest::newRow("inch 0.0001111") << KoUnit::Inch << 0.0001111 << 0.00000154305555555568 << 0.0; + QTest::newRow("decimeter 0.0001111") << KoUnit::Decimeter << 0.0001111 << 0.00000039193543253700 << 0.0; +} + +void TestKoUnit::testToUserValue() +{ + QFETCH(KoUnit::Type, type); + QFETCH(qreal, value); + QFETCH(qreal, expected); + QFETCH(qreal, expectedRounded); + + KoUnit unit = KoUnit(type); + + qreal exphere = unit.toUserValue(value, false); + qreal expRound = unit.toUserValue(value, true); + + QCOMPARE(exphere, expected); + QCOMPARE(expRound, expectedRounded); + +} + QTEST_GUILESS_MAIN(TestKoUnit) diff --git a/libs/ui/widgets/kis_custom_image_widget.cc b/libs/ui/widgets/kis_custom_image_widget.cc --- a/libs/ui/widgets/kis_custom_image_widget.cc +++ b/libs/ui/widgets/kis_custom_image_widget.cc @@ -212,7 +212,7 @@ doubleWidth->setDecimals(2); } - doubleWidth->setValue(KoUnit::ptToUnit(m_width, m_widthUnit)); + doubleWidth->setValue(m_widthUnit.toUserValuePrecise(m_width)); doubleWidth->blockSignals(false); changeDocumentInfoLabel(); @@ -236,7 +236,7 @@ doubleHeight->setDecimals(2); } - doubleHeight->setValue(KoUnit::ptToUnit(m_height, m_heightUnit)); + doubleHeight->setValue(m_heightUnit.toUserValuePrecise(m_height)); doubleHeight->blockSignals(false); changeDocumentInfoLabel(); @@ -297,8 +297,8 @@ double resolution; resolution = doubleResolution->value() / 72.0; // internal resolution is in pixels per pt - width = static_cast(0.5 + KoUnit::ptToUnit(m_width, KoUnit(KoUnit::Pixel, resolution))); - height = static_cast(0.5 + KoUnit::ptToUnit(m_height, KoUnit(KoUnit::Pixel, resolution))); + width = static_cast(0.5 + KoUnit(KoUnit::Pixel, resolution).toUserValuePrecise(m_width)); + height = static_cast(0.5 + KoUnit(KoUnit::Pixel, resolution).toUserValuePrecise(m_height)); QColor qc = cmbColor->color().toQColor(); qc.setAlpha(backgroundOpacity()); @@ -499,8 +499,8 @@ double resolution; resolution = doubleResolution->value() / 72.0; // internal resolution is in pixels per pt - width = static_cast(0.5 + KoUnit::ptToUnit(m_width, KoUnit(KoUnit::Pixel, resolution))); - height = static_cast(0.5 + KoUnit::ptToUnit(m_height, KoUnit(KoUnit::Pixel, resolution))); + width = static_cast(0.5 + KoUnit(KoUnit::Pixel, resolution).toUserValuePrecise(m_width)); + height = static_cast(0.5 + KoUnit(KoUnit::Pixel, resolution).toUserValuePrecise(m_height)); qint64 layerSize = width * height; const KoColorSpace *cs = colorSpaceSelector->currentColorSpace(); diff --git a/libs/widgets/KoUnitDoubleSpinBox.cpp b/libs/widgets/KoUnitDoubleSpinBox.cpp --- a/libs/widgets/KoUnitDoubleSpinBox.cpp +++ b/libs/widgets/KoUnitDoubleSpinBox.cpp @@ -114,7 +114,7 @@ warnWidgets << "Not a number: " << number; return QValidator::Invalid; } - newVal = KoUnit::ptToUnit( newVal, d->unit ); + newVal = d->unit.toUserValuePrecise(newVal); //input = textFromValue( newVal ); // don't overwrite for now; the effect is not exactly what I expect... return QValidator::Acceptable; @@ -149,7 +149,7 @@ QDoubleSpinBox::setSingleStep( step ); d->unit = unit; - QDoubleSpinBox::setValue( KoUnit::ptToUnit( oldvalue, unit ) ); + QDoubleSpinBox::setValue(unit.toUserValuePrecise(oldvalue)); setSuffix(unit.symbol().prepend(QLatin1Char(' '))); } diff --git a/libs/widgetutils/kis_spin_box_unit_manager.cpp b/libs/widgetutils/kis_spin_box_unit_manager.cpp --- a/libs/widgetutils/kis_spin_box_unit_manager.cpp +++ b/libs/widgetutils/kis_spin_box_unit_manager.cpp @@ -368,7 +368,7 @@ if (! ok) { break; } - factor = unit.ptToUnit(1.0, unit); // use the precise function + factor = unit.toUserValuePrecise(1.0); // use the precise function } while (0) ; break; diff --git a/plugins/flake/pathshapes/enhancedpath/EnhancedPathParameter.cpp b/plugins/flake/pathshapes/enhancedpath/EnhancedPathParameter.cpp --- a/plugins/flake/pathshapes/enhancedpath/EnhancedPathParameter.cpp +++ b/plugins/flake/pathshapes/enhancedpath/EnhancedPathParameter.cpp @@ -132,11 +132,11 @@ break; case IdentifierLogwidth: // TODO: ? viewBox does not have any unit or const relation to mm - return KoUnit::toMillimeter(viewBox.width()) * 100; + return KoUnit(KoUnit::Millimeter).toUserValue(viewBox.width()) * 100; break; case IdentifierLogheight: // TODO: ? viewBox does not have any unit or const relation to mm - return KoUnit::toMillimeter(viewBox.height()) * 100; + return KoUnit(KoUnit::Millimeter).toUserValue(viewBox.height()) * 100; break; default: break; diff --git a/plugins/flake/textshape/dialogs/ParagraphBulletsNumbers.cpp b/plugins/flake/textshape/dialogs/ParagraphBulletsNumbers.cpp --- a/plugins/flake/textshape/dialogs/ParagraphBulletsNumbers.cpp +++ b/plugins/flake/textshape/dialogs/ParagraphBulletsNumbers.cpp @@ -154,7 +154,7 @@ case KoListStyle::ListTab: widget.doubleSpinBox->setEnabled(true); widget.labelFollowedBy->setCurrentIndex(0); - widget.doubleSpinBox->setValue(KoUnit::toCentimeter(llp.tabStopPosition())); + widget.doubleSpinBox->setValue(KoUnit(KoUnit::Centimeter).toUserValue(llp.tabStopPosition())); break; case KoListStyle::Space: widget.doubleSpinBox->setEnabled(false); @@ -168,8 +168,8 @@ Q_ASSERT(false); } - widget.doubleSpinBox_2->setValue(KoUnit::toCentimeter(llp.margin())); - widget.doubleSpinBox_3->setValue(KoUnit::toCentimeter(llp.margin()) + KoUnit::toCentimeter(llp.textIndent())); + widget.doubleSpinBox_2->setValue(KoUnit(KoUnit::Centimeter).toUserValue(llp.margin())); + widget.doubleSpinBox_3->setValue(KoUnit(KoUnit::Centimeter).toUserValue(llp.margin()) + KoUnit(KoUnit::Centimeter).toUserValue(llp.textIndent())); } // *** features not in GUI;