From 87142708d1380f09d9238ed3f095c0330c849431 Mon Sep 17 00:00:00 2001 From: Julien Cabieces Date: Tue, 27 Aug 2024 17:55:44 +0200 Subject: [PATCH] feat(Expression): Make darker/lighter works with color object and not just string representation --- resources/function_help/json/darker | 4 +- resources/function_help/json/lighter | 4 +- src/core/expression/qgsexpressionfunction.cpp | 18 ++++++--- tests/src/core/testqgsexpression.cpp | 38 ++++++++++--------- 4 files changed, 37 insertions(+), 27 deletions(-) diff --git a/resources/function_help/json/darker b/resources/function_help/json/darker index e4e31732de6..18821d2baa2 100644 --- a/resources/function_help/json/darker +++ b/resources/function_help/json/darker @@ -2,10 +2,10 @@ "name": "darker", "type": "function", "groups": ["Color"], - "description": "Returns a darker (or lighter) color string", + "description": "Returns a darker (or lighter) color. Returned type is the same as color arguments, i.e. a color string representation or a color object.", "arguments": [{ "arg": "color", - "description": "a color string" + "description": "a color string or a color object" }, { "arg": "factor", "description": "an integer corresponding to the darkening factor:" diff --git a/resources/function_help/json/lighter b/resources/function_help/json/lighter index 604aafefbec..6b740a4cae3 100644 --- a/resources/function_help/json/lighter +++ b/resources/function_help/json/lighter @@ -2,10 +2,10 @@ "name": "lighter", "type": "function", "groups": ["Color"], - "description": "Returns a lighter (or darker) color string", + "description": "Returns a lighter (or darker) color. Returned type is the same as color arguments, i.e. a color string representation or a color object.", "arguments": [{ "arg": "color", - "description": "a color string" + "description": "a color string or a color object" }, { "arg": "factor", "description": "an integer corresponding to the lightening factor:" diff --git a/src/core/expression/qgsexpressionfunction.cpp b/src/core/expression/qgsexpressionfunction.cpp index 6af7c587cd3..230b900de6c 100644 --- a/src/core/expression/qgsexpressionfunction.cpp +++ b/src/core/expression/qgsexpressionfunction.cpp @@ -6334,30 +6334,36 @@ static QVariant fncSetColorPart( const QVariantList &values, const QgsExpression static QVariant fncDarker( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * ) { - QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() ); + const QVariant variant = values.at( 0 ); + const bool isQColor = variant.userType() == QMetaType::Type::QColor; + QColor color = isQColor ? variant.value() : QgsSymbolLayerUtils::decodeColor( variant.toString() ); if ( ! color.isValid() ) { - parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) ); + parent->setEvalErrorString( isQColor ? QObject::tr( "Input color is invalid" ) + : QObject::tr( "Cannot convert '%1' to color" ).arg( variant.toString() ) ); return QVariant(); } color = color.darker( QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent ) ); - return QgsSymbolLayerUtils::encodeColor( color ); + return isQColor ? QVariant( color ) : QVariant( QgsSymbolLayerUtils::encodeColor( color ) ); } static QVariant fncLighter( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * ) { - QColor color = QgsSymbolLayerUtils::decodeColor( values.at( 0 ).toString() ); + const QVariant variant = values.at( 0 ); + const bool isQColor = variant.userType() == QMetaType::Type::QColor; + QColor color = isQColor ? variant.value() : QgsSymbolLayerUtils::decodeColor( variant.toString() ); if ( ! color.isValid() ) { - parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to color" ).arg( values.at( 0 ).toString() ) ); + parent->setEvalErrorString( isQColor ? QObject::tr( "Input color is invalid" ) + : QObject::tr( "Cannot convert '%1' to color" ).arg( variant.toString() ) ); return QVariant(); } color = color.lighter( QgsExpressionUtils::getNativeIntValue( values.at( 1 ), parent ) ); - return QgsSymbolLayerUtils::encodeColor( color ); + return isQColor ? QVariant( color ) : QVariant( QgsSymbolLayerUtils::encodeColor( color ) ); } static QVariant fcnGetGeometry( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * ) diff --git a/tests/src/core/testqgsexpression.cpp b/tests/src/core/testqgsexpression.cpp index ef013b780bc..3c43ea5056c 100644 --- a/tests/src/core/testqgsexpression.cpp +++ b/tests/src/core/testqgsexpression.cpp @@ -1943,6 +1943,10 @@ class TestQgsExpression: public QObject QTest::newRow( "color darker bad color" ) << "darker('notacolor',150)" << true << QVariant(); QTest::newRow( "color lighter" ) << "lighter('200,100,30',150)" << false << QVariant( "255,154,83,255" ); QTest::newRow( "color lighter bad color" ) << "lighter('notacolor',150)" << true << QVariant(); + QTest::newRow( "color darker object " ) << "darker(color_cmykf(0.1,0.4,0.6,0.6),150)" << false << QVariant( QColor::fromCmykF( 0, 0.333, 0.5555, 0.76 ) ); + QTest::newRow( "color darker bad color object" ) << "darker(color_cmykf(1.5,1.5,1.5,1.5),150)" << true << QVariant(); + QTest::newRow( "color lighter object" ) << "lighter(color_cmykf(0.1,0.4,0.6,0.6),150)" << false << QVariant( QColor::fromCmykF( 0, 0.333, 0.5555, 0.46 ) ); + QTest::newRow( "color lighter bad color object" ) << "lighter(color_cmykf(1.5,1.5,1.5,1.5),150)" << true << QVariant(); QTest::newRow( "color rgb float" ) << "color_rgbf(1,0.4989,0)" << false << QVariant( QColor::fromRgbF( 1., 0.4989, 0 ) ); QTest::newRow( "color rgba float" ) << "color_rgbf(1,0.4989,0,0.21)" << false << QVariant( QColor::fromRgbF( 1., 0.4989, 0, 0.21 ) ); @@ -2322,33 +2326,33 @@ class TestQgsExpression: public QObject switch ( resultColor.spec() ) { case QColor::Spec::Cmyk: - QVERIFY( qgsDoubleNear( resultColor.cyanF(), expectedColor.cyanF(), 0.001 ) ); - QVERIFY( qgsDoubleNear( resultColor.magentaF(), expectedColor.magentaF(), 0.001 ) ); - QVERIFY( qgsDoubleNear( resultColor.yellowF(), expectedColor.yellowF(), 0.001 ) ); - QVERIFY( qgsDoubleNear( resultColor.blackF(), expectedColor.blackF(), 0.001 ) ); - QVERIFY( qgsDoubleNear( resultColor.alphaF(), expectedColor.alphaF(), 0.001 ) ); + QVERIFY2( qgsDoubleNear( resultColor.cyanF(), expectedColor.cyanF(), 0.001 ), QString( "cyan: %2!=%3" ).arg( resultColor.cyanF(), 0, 'f', 3 ).arg( expectedColor.cyanF(), 0, 'f', 3 ).toLatin1() ); + QVERIFY2( qgsDoubleNear( resultColor.magentaF(), expectedColor.magentaF(), 0.001 ), QString( "magenta: %2!=%3" ).arg( resultColor.magentaF(), 0, 'f', 3 ).arg( expectedColor.magentaF(), 0, 'f', 3 ).toLatin1() ); + QVERIFY2( qgsDoubleNear( resultColor.yellowF(), expectedColor.yellowF(), 0.001 ), QString( "yellow: %2!=%3" ).arg( resultColor.yellowF(), 0, 'f', 3 ).arg( expectedColor.yellowF(), 0, 'f', 3 ).toLatin1() ); + QVERIFY2( qgsDoubleNear( resultColor.blackF(), expectedColor.blackF(), 0.001 ), QString( "black: %2!=%3" ).arg( resultColor.blackF(), 0, 'f', 3 ).arg( expectedColor.blackF(), 0, 'f', 3 ).toLatin1() ); + QVERIFY2( qgsDoubleNear( resultColor.alphaF(), expectedColor.alphaF(), 0.001 ), QString( "alpha: %2!=%3" ).arg( resultColor.alphaF(), 0, 'f', 3 ).arg( expectedColor.alphaF(), 0, 'f', 3 ).toLatin1() ); break; case QColor::Spec::Hsl: - QVERIFY( qgsDoubleNear( resultColor.hslHueF(), expectedColor.hslHueF(), 0.001 ) ); - QVERIFY( qgsDoubleNear( resultColor.hslSaturationF(), expectedColor.hslSaturationF(), 0.001 ) ); - QVERIFY( qgsDoubleNear( resultColor.lightnessF(), expectedColor.lightnessF(), 0.001 ) ); - QVERIFY( qgsDoubleNear( resultColor.alphaF(), expectedColor.alphaF(), 0.001 ) ); + QVERIFY2( qgsDoubleNear( resultColor.hslHueF(), expectedColor.hslHueF(), 0.001 ), QString( "hslHue: %2!=%3" ).arg( resultColor.hslHueF(), 0, 'f', 3 ).arg( expectedColor.hslHueF(), 0, 'f', 3 ).toLatin1() ); + QVERIFY2( qgsDoubleNear( resultColor.hslSaturationF(), expectedColor.hslSaturationF(), 0.001 ), QString( "hslSaturation: %2!=%3" ).arg( resultColor.hslSaturationF(), 0, 'f', 3 ).arg( expectedColor.hslSaturationF(), 0, 'f', 3 ).toLatin1() ); + QVERIFY2( qgsDoubleNear( resultColor.lightnessF(), expectedColor.lightnessF(), 0.001 ), QString( "lightness: %2!=%3" ).arg( resultColor.lightnessF(), 0, 'f', 3 ).arg( expectedColor.lightnessF(), 0, 'f', 3 ).toLatin1() ); + QVERIFY2( qgsDoubleNear( resultColor.alphaF(), expectedColor.alphaF(), 0.001 ), QString( "alpha: %2!=%3" ).arg( resultColor.alphaF(), 0, 'f', 3 ).arg( expectedColor.alphaF(), 0, 'f', 3 ).toLatin1() ); break; case QColor::Spec::Hsv: - QVERIFY( qgsDoubleNear( resultColor.hsvHueF(), expectedColor.hsvHueF(), 0.001 ) ); - QVERIFY( qgsDoubleNear( resultColor.hsvSaturationF(), expectedColor.hsvSaturationF(), 0.001 ) ); - QVERIFY( qgsDoubleNear( resultColor.valueF(), expectedColor.valueF(), 0.001 ) ); - QVERIFY( qgsDoubleNear( resultColor.alphaF(), expectedColor.alphaF(), 0.001 ) ); + QVERIFY2( qgsDoubleNear( resultColor.hsvHueF(), expectedColor.hsvHueF(), 0.001 ), QString( "hsvHue: %2!=%3" ).arg( resultColor.hsvHueF(), 0, 'f', 3 ).arg( expectedColor.hsvHueF(), 0, 'f', 3 ).toLatin1() ); + QVERIFY2( qgsDoubleNear( resultColor.hsvSaturationF(), expectedColor.hsvSaturationF(), 0.001 ), QString( "hsvSaturation: %2!=%3" ).arg( resultColor.hsvSaturationF(), 0, 'f', 3 ).arg( expectedColor.hsvSaturationF(), 0, 'f', 3 ).toLatin1() ); + QVERIFY2( qgsDoubleNear( resultColor.valueF(), expectedColor.valueF(), 0.001 ), QString( "value: %2!=%3" ).arg( resultColor.valueF(), 0, 'f', 3 ).arg( expectedColor.valueF(), 0, 'f', 3 ).toLatin1() ); + QVERIFY2( qgsDoubleNear( resultColor.alphaF(), expectedColor.alphaF(), 0.001 ), QString( "alpha: %2!=%3" ).arg( resultColor.alphaF(), 0, 'f', 3 ).arg( expectedColor.alphaF(), 0, 'f', 3 ).toLatin1() ); break; case QColor::Spec::ExtendedRgb: case QColor::Spec::Rgb: - QVERIFY( qgsDoubleNear( resultColor.redF(), expectedColor.redF(), 0.001 ) ); - QVERIFY( qgsDoubleNear( resultColor.greenF(), expectedColor.greenF(), 0.001 ) ); - QVERIFY( qgsDoubleNear( resultColor.blueF(), expectedColor.blueF(), 0.001 ) ); - QVERIFY( qgsDoubleNear( resultColor.alphaF(), expectedColor.alphaF(), 0.001 ) ); + QVERIFY2( qgsDoubleNear( resultColor.redF(), expectedColor.redF(), 0.001 ), QString( "red: %2!=%3" ).arg( resultColor.redF(), 0, 'f', 3 ).arg( expectedColor.redF(), 0, 'f', 3 ).toLatin1() ); + QVERIFY2( qgsDoubleNear( resultColor.greenF(), expectedColor.greenF(), 0.001 ), QString( "green: %2!=%3" ).arg( resultColor.greenF(), 0, 'f', 3 ).arg( expectedColor.greenF(), 0, 'f', 3 ).toLatin1() ); + QVERIFY2( qgsDoubleNear( resultColor.blueF(), expectedColor.blueF(), 0.001 ), QString( "blue: %2!=%3" ).arg( resultColor.blueF(), 0, 'f', 3 ).arg( expectedColor.blueF(), 0, 'f', 3 ).toLatin1() ); + QVERIFY2( qgsDoubleNear( resultColor.alphaF(), expectedColor.alphaF(), 0.001 ), QString( "alpha: %2!=%3" ).arg( resultColor.alphaF(), 0, 'f', 3 ).arg( expectedColor.alphaF(), 0, 'f', 3 ).toLatin1() ); break; case QColor::Spec::Invalid: