QskArcMetrics::isProprtional added

This commit is contained in:
Uwe Rathmann 2024-05-21 17:19:24 +02:00
parent 16c9ea2161
commit a327084c3f
4 changed files with 67 additions and 29 deletions

View File

@ -27,7 +27,7 @@ CircularChart::CircularChart( QQuickItem* parentItem )
setGradientHint( Panel, QskGradient() ); setGradientHint( Panel, QskGradient() );
setBoxBorderMetricsHint( Panel, 0 ); 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 ) ); setGradientHint( Arc, QskRgb::toTransparent( QskRgb::LightGray, 100 ) );
setColor( Arc | QskAspect::Border, QskRgb::LightGray ); setColor( Arc | QskAspect::Border, QskRgb::LightGray );

View File

@ -334,8 +334,7 @@ QSGNode* CircularChartSkinlet::updateSampleNode( const QskSkinnable* skinnable,
return nullptr; return nullptr;
} }
QSGNode* CircularChartSkinlet::updateArcSegmentNode( QSGNode* CircularChartSkinlet::updateArcSegmentNode( const QskSkinnable* skinnable,
const QskSkinnable* skinnable,
QSGNode* node, qreal borderWidth, const QColor& borderColor, QSGNode* node, qreal borderWidth, const QColor& borderColor,
const QskGradient& gradient, const QskArcMetrics& metrics ) const const QskGradient& gradient, const QskArcMetrics& metrics ) const
{ {

View File

@ -48,7 +48,12 @@ void QskArcMetrics::setSpanAngle( qreal spanAngle ) noexcept
void QskArcMetrics::setSizeMode( Qt::SizeMode sizeMode ) 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 bool QskArcMetrics::isClosed() const
@ -79,7 +84,7 @@ bool QskArcMetrics::containsAngle( qreal angle ) const
QskArcMetrics QskArcMetrics::interpolated( QskArcMetrics QskArcMetrics::interpolated(
const QskArcMetrics& to, qreal ratio ) const noexcept 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; return to;
const qreal thickness = qskInterpolated( m_thickness, to.m_thickness, ratio ); 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 s1 = qskInterpolated( m_startAngle, to.m_startAngle, ratio );
const qreal s2 = qskInterpolated( endAngle(), to.endAngle(), 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( QVariant QskArcMetrics::interpolate(
@ -110,26 +115,37 @@ QskArcMetrics QskArcMetrics::toAbsolute( qreal radiusX, qreal radiusY ) const no
QskArcMetrics QskArcMetrics::toAbsolute( qreal radius ) const noexcept QskArcMetrics QskArcMetrics::toAbsolute( qreal radius ) const noexcept
{ {
if ( m_sizeMode != Qt::RelativeSize ) if ( !m_relativeSize )
return *this; return *this;
const qreal t = qskEffectiveThickness( radius, m_thickness ); 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 QPainterPath QskArcMetrics::painterPath( const QRectF& ellipseRect ) const
{ {
const auto sz = qMin( ellipseRect.width(), ellipseRect.height() );
qreal t = m_thickness; 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 ); t = qskEffectiveThickness( 0.5 * sz, t );
}
if ( t <= 0.0 || qFuzzyIsNull( m_spanAngle ) ) if ( t <= 0.0 || qFuzzyIsNull( m_spanAngle ) )
return QPainterPath(); return QPainterPath();
const auto tx = t * ellipseRect.width() / sz; auto tx = t;
const auto ty = t * ellipseRect.height() / sz; 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 ); 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 ); auto hash = qHash( m_thickness, seed );
hash = qHash( m_startAngle, hash ); hash = qHash( m_startAngle, hash );
hash = qHash( m_spanAngle, hash ); hash = qHash( m_spanAngle, hash );
hash = qHash( m_relativeSize, hash );
const int mode = m_sizeMode; return qHash( m_proportional, hash );
return qHashBits( &mode, sizeof( mode ), hash );
} }
#ifndef QT_NO_DEBUG_STREAM #ifndef QT_NO_DEBUG_STREAM
@ -226,7 +242,8 @@ QDebug operator<<( QDebug debug, const QskArcMetrics& metrics )
debug.nospace(); debug.nospace();
debug << "QskArcMetrics" << '('; debug << "QskArcMetrics" << '(';
debug << metrics.thickness() << ',' << metrics.sizeMode(); debug << metrics.thickness() << ',' << metrics.sizeMode() << ','
<< metrics.isProportional();
debug << ",[" << metrics.startAngle() << ',' << metrics.spanAngle() << ']'; debug << ",[" << metrics.startAngle() << ',' << metrics.spanAngle() << ']';
debug << ')'; debug << ')';

View File

@ -22,15 +22,16 @@ class QSK_EXPORT QskArcMetrics
Q_PROPERTY( qreal thickness READ thickness WRITE setThickness ) Q_PROPERTY( qreal thickness READ thickness WRITE setThickness )
Q_PROPERTY( Qt::SizeMode sizeMode READ sizeMode WRITE setSizeMode ) Q_PROPERTY( Qt::SizeMode sizeMode READ sizeMode WRITE setSizeMode )
Q_PROPERTY( bool proportional READ isProportional WRITE setProportional )
public: public:
constexpr QskArcMetrics() noexcept = default; constexpr QskArcMetrics() noexcept = default;
constexpr QskArcMetrics( qreal thickness, constexpr QskArcMetrics( qreal thickness,
Qt::SizeMode = Qt::AbsoluteSize ) noexcept; Qt::SizeMode = Qt::AbsoluteSize, bool proportional = false ) noexcept;
constexpr QskArcMetrics( qreal startAngle, qreal spanAngle, constexpr QskArcMetrics( qreal startAngle, qreal spanAngle, qreal thickness,
qreal thickness, Qt::SizeMode = Qt::AbsoluteSize ) noexcept; Qt::SizeMode = Qt::AbsoluteSize, bool proportional = false ) noexcept;
bool operator==( const QskArcMetrics& ) const noexcept; bool operator==( const QskArcMetrics& ) const 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; void setThickness( qreal ) noexcept;
constexpr qreal thickness() const 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; void setSizeMode( Qt::SizeMode ) noexcept;
constexpr Qt::SizeMode sizeMode() const noexcept; constexpr Qt::SizeMode sizeMode() const noexcept;
@ -76,32 +90,35 @@ class QSK_EXPORT QskArcMetrics
qreal m_spanAngle = 0.0; qreal m_spanAngle = 0.0;
qreal m_thickness = 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( inline constexpr QskArcMetrics::QskArcMetrics(
qreal thickness, Qt::SizeMode sizeMode ) noexcept qreal thickness, Qt::SizeMode sizeMode, bool proportional ) noexcept
: QskArcMetrics( 0.0, 360.0, thickness, sizeMode ) : QskArcMetrics( 0.0, 360.0, thickness, sizeMode, proportional )
{ {
} }
inline constexpr QskArcMetrics::QskArcMetrics( inline constexpr QskArcMetrics::QskArcMetrics( qreal startAngle, qreal spanAngle,
qreal startAngle, qreal spanAngle, qreal thickness, Qt::SizeMode sizeMode, bool proportional ) noexcept
qreal thickness, Qt::SizeMode sizeMode ) noexcept
: m_startAngle( startAngle ) : m_startAngle( startAngle )
, m_spanAngle( spanAngle ) , m_spanAngle( spanAngle )
, m_thickness( thickness ) , m_thickness( thickness )
, m_sizeMode( sizeMode ) , m_relativeSize( sizeMode == Qt::RelativeSize )
, m_proportional( proportional )
{ {
} }
inline bool QskArcMetrics::operator==( inline bool QskArcMetrics::operator==(
const QskArcMetrics& other ) const noexcept 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_startAngle, other.m_startAngle )
&& qskFuzzyCompare( m_spanAngle, other.m_spanAngle ) && 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!=( 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 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 #ifndef QT_NO_DEBUG_STREAM