From a327084c3f437ec46aa464f0ad3ae42ad12901af Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Tue, 21 May 2024 17:19:24 +0200 Subject: [PATCH] QskArcMetrics::isProprtional added --- playground/charts/CircularChart.cpp | 2 +- playground/charts/CircularChartSkinlet.cpp | 3 +- src/common/QskArcMetrics.cpp | 43 +++++++++++++------ src/common/QskArcMetrics.h | 48 ++++++++++++++++------ 4 files changed, 67 insertions(+), 29 deletions(-) diff --git a/playground/charts/CircularChart.cpp b/playground/charts/CircularChart.cpp index c7f3b485..8ec289c5 100644 --- a/playground/charts/CircularChart.cpp +++ b/playground/charts/CircularChart.cpp @@ -27,7 +27,7 @@ CircularChart::CircularChart( QQuickItem* parentItem ) setGradientHint( Panel, QskGradient() ); setBoxBorderMetricsHint( Panel, 0 ); - setArcMetricsHint( Arc, { 90.0, -360.0, 100.0, Qt::RelativeSize } ); + setArcMetricsHint( Arc, { 90.0, -360.0, 100.0, Qt::RelativeSize, true } ); setGradientHint( Arc, QskRgb::toTransparent( QskRgb::LightGray, 100 ) ); setColor( Arc | QskAspect::Border, QskRgb::LightGray ); diff --git a/playground/charts/CircularChartSkinlet.cpp b/playground/charts/CircularChartSkinlet.cpp index 736479a9..1fd0a540 100644 --- a/playground/charts/CircularChartSkinlet.cpp +++ b/playground/charts/CircularChartSkinlet.cpp @@ -334,8 +334,7 @@ QSGNode* CircularChartSkinlet::updateSampleNode( const QskSkinnable* skinnable, return nullptr; } -QSGNode* CircularChartSkinlet::updateArcSegmentNode( - const QskSkinnable* skinnable, +QSGNode* CircularChartSkinlet::updateArcSegmentNode( const QskSkinnable* skinnable, QSGNode* node, qreal borderWidth, const QColor& borderColor, const QskGradient& gradient, const QskArcMetrics& metrics ) const { diff --git a/src/common/QskArcMetrics.cpp b/src/common/QskArcMetrics.cpp index a7981827..26904c81 100644 --- a/src/common/QskArcMetrics.cpp +++ b/src/common/QskArcMetrics.cpp @@ -48,7 +48,12 @@ void QskArcMetrics::setSpanAngle( qreal spanAngle ) noexcept void QskArcMetrics::setSizeMode( Qt::SizeMode sizeMode ) noexcept { - m_sizeMode = sizeMode; + m_relativeSize = ( sizeMode == Qt::RelativeSize ); +} + +void QskArcMetrics::setProportional( bool on ) noexcept +{ + m_proportional = on; } bool QskArcMetrics::isClosed() const @@ -79,7 +84,7 @@ bool QskArcMetrics::containsAngle( qreal angle ) const QskArcMetrics QskArcMetrics::interpolated( const QskArcMetrics& to, qreal ratio ) const noexcept { - if ( ( *this == to ) || ( m_sizeMode != to.m_sizeMode ) ) + if ( ( *this == to ) || ( m_relativeSize != to.m_relativeSize ) ) return to; const qreal thickness = qskInterpolated( m_thickness, to.m_thickness, ratio ); @@ -87,7 +92,7 @@ QskArcMetrics QskArcMetrics::interpolated( const qreal s1 = qskInterpolated( m_startAngle, to.m_startAngle, ratio ); const qreal s2 = qskInterpolated( endAngle(), to.endAngle(), ratio ); - return QskArcMetrics( s1, s2 - s1, thickness, m_sizeMode ); + return QskArcMetrics( s1, s2 - s1, thickness, sizeMode(), to.isProportional() ); } QVariant QskArcMetrics::interpolate( @@ -110,26 +115,37 @@ QskArcMetrics QskArcMetrics::toAbsolute( qreal radiusX, qreal radiusY ) const no QskArcMetrics QskArcMetrics::toAbsolute( qreal radius ) const noexcept { - if ( m_sizeMode != Qt::RelativeSize ) + if ( !m_relativeSize ) return *this; const qreal t = qskEffectiveThickness( radius, m_thickness ); - return QskArcMetrics( m_startAngle, m_spanAngle, t, Qt::AbsoluteSize ); + return QskArcMetrics( m_startAngle, m_spanAngle, t, + Qt::AbsoluteSize, m_proportional ); } QPainterPath QskArcMetrics::painterPath( const QRectF& ellipseRect ) const { - const auto sz = qMin( ellipseRect.width(), ellipseRect.height() ); - qreal t = m_thickness; - if ( m_sizeMode == Qt::RelativeSize ) + + if ( m_relativeSize ) + { + const auto sz = qMin( ellipseRect.width(), ellipseRect.height() ); t = qskEffectiveThickness( 0.5 * sz, t ); + } if ( t <= 0.0 || qFuzzyIsNull( m_spanAngle ) ) return QPainterPath(); - const auto tx = t * ellipseRect.width() / sz; - const auto ty = t * ellipseRect.height() / sz; + auto tx = t; + auto ty = t; + + if ( m_proportional ) + { + const auto sz = qMin( ellipseRect.width(), ellipseRect.height() ); + + tx *= ellipseRect.width() / sz; + ty *= ellipseRect.height() / sz; + } const auto innerRect = ellipseRect.adjusted( tx, ty, -tx, -ty ); @@ -211,9 +227,9 @@ QskHashValue QskArcMetrics::hash( QskHashValue seed ) const noexcept auto hash = qHash( m_thickness, seed ); hash = qHash( m_startAngle, hash ); hash = qHash( m_spanAngle, hash ); + hash = qHash( m_relativeSize, hash ); - const int mode = m_sizeMode; - return qHashBits( &mode, sizeof( mode ), hash ); + return qHash( m_proportional, hash ); } #ifndef QT_NO_DEBUG_STREAM @@ -226,7 +242,8 @@ QDebug operator<<( QDebug debug, const QskArcMetrics& metrics ) debug.nospace(); debug << "QskArcMetrics" << '('; - debug << metrics.thickness() << ',' << metrics.sizeMode(); + debug << metrics.thickness() << ',' << metrics.sizeMode() << ',' + << metrics.isProportional(); debug << ",[" << metrics.startAngle() << ',' << metrics.spanAngle() << ']'; debug << ')'; diff --git a/src/common/QskArcMetrics.h b/src/common/QskArcMetrics.h index fe80ed46..0ee551b1 100644 --- a/src/common/QskArcMetrics.h +++ b/src/common/QskArcMetrics.h @@ -22,15 +22,16 @@ class QSK_EXPORT QskArcMetrics Q_PROPERTY( qreal thickness READ thickness WRITE setThickness ) Q_PROPERTY( Qt::SizeMode sizeMode READ sizeMode WRITE setSizeMode ) + Q_PROPERTY( bool proportional READ isProportional WRITE setProportional ) public: constexpr QskArcMetrics() noexcept = default; constexpr QskArcMetrics( qreal thickness, - Qt::SizeMode = Qt::AbsoluteSize ) noexcept; + Qt::SizeMode = Qt::AbsoluteSize, bool proportional = false ) noexcept; - constexpr QskArcMetrics( qreal startAngle, qreal spanAngle, - qreal thickness, Qt::SizeMode = Qt::AbsoluteSize ) noexcept; + constexpr QskArcMetrics( qreal startAngle, qreal spanAngle, qreal thickness, + Qt::SizeMode = Qt::AbsoluteSize, bool proportional = false ) noexcept; bool operator==( const QskArcMetrics& ) const noexcept; bool operator!=( const QskArcMetrics& ) const noexcept; @@ -52,6 +53,19 @@ class QSK_EXPORT QskArcMetrics void setThickness( qreal ) noexcept; constexpr qreal thickness() const noexcept; + /* + A proportional arc scales the thickness of the arc according to the + aspect ratio of the target rectangle. F.e when having a 20x10 rectangle + the thickness in west/east direction is doubled, while for a + 10x20 rectangle the thickness in north/south direction is doubled. + This matches the lines that result from a filling with a conic gradient. + + A non proportional arc will have a fixed thickness regardless of + the aspect ratio. + */ + void setProportional( bool ) noexcept; + constexpr bool isProportional() const noexcept; + void setSizeMode( Qt::SizeMode ) noexcept; constexpr Qt::SizeMode sizeMode() const noexcept; @@ -76,32 +90,35 @@ class QSK_EXPORT QskArcMetrics qreal m_spanAngle = 0.0; qreal m_thickness = 0.0; - Qt::SizeMode m_sizeMode = Qt::AbsoluteSize; + + bool m_relativeSize = false; + bool m_proportional = false; }; inline constexpr QskArcMetrics::QskArcMetrics( - qreal thickness, Qt::SizeMode sizeMode ) noexcept - : QskArcMetrics( 0.0, 360.0, thickness, sizeMode ) + qreal thickness, Qt::SizeMode sizeMode, bool proportional ) noexcept + : QskArcMetrics( 0.0, 360.0, thickness, sizeMode, proportional ) { } -inline constexpr QskArcMetrics::QskArcMetrics( - qreal startAngle, qreal spanAngle, - qreal thickness, Qt::SizeMode sizeMode ) noexcept +inline constexpr QskArcMetrics::QskArcMetrics( qreal startAngle, qreal spanAngle, + qreal thickness, Qt::SizeMode sizeMode, bool proportional ) noexcept : m_startAngle( startAngle ) , m_spanAngle( spanAngle ) , m_thickness( thickness ) - , m_sizeMode( sizeMode ) + , m_relativeSize( sizeMode == Qt::RelativeSize ) + , m_proportional( proportional ) { } inline bool QskArcMetrics::operator==( const QskArcMetrics& other ) const noexcept { - return ( qskFuzzyCompare( m_thickness, other.m_thickness ) + return qskFuzzyCompare( m_thickness, other.m_thickness ) && qskFuzzyCompare( m_startAngle, other.m_startAngle ) && qskFuzzyCompare( m_spanAngle, other.m_spanAngle ) - && m_sizeMode == other.m_sizeMode ); + && ( m_relativeSize == other.m_relativeSize ) + && ( m_proportional == other.m_proportional ); } inline bool QskArcMetrics::operator!=( @@ -142,7 +159,12 @@ inline constexpr qreal QskArcMetrics::angleAtRatio( qreal ratio ) const noexcept inline constexpr Qt::SizeMode QskArcMetrics::sizeMode() const noexcept { - return m_sizeMode; + return m_relativeSize ? Qt::RelativeSize : Qt::AbsoluteSize; +} + +inline constexpr bool QskArcMetrics::isProportional() const noexcept +{ + return m_proportional; } #ifndef QT_NO_DEBUG_STREAM