diff --git a/examples/iotdashboard/CircularProgressBarSkinlet.cpp b/examples/iotdashboard/CircularProgressBarSkinlet.cpp index 3f433ab7..3d6ed822 100644 --- a/examples/iotdashboard/CircularProgressBarSkinlet.cpp +++ b/examples/iotdashboard/CircularProgressBarSkinlet.cpp @@ -55,24 +55,25 @@ QSGNode* CircularProgressBarSkinlet::updateBarNode( arcNode = new QskArcNode(); } - const auto subControl = ( nodeRole == GrooveRole ) ? CircularProgressBar::Groove - : CircularProgressBar::Bar; + // ### for the groove case, we can just call updateArcNode directly, + // but not for the bar case, because we need to change the angles + // for the latter case, we can just set the metrics rather than having + // this method here + const auto subControl = ( nodeRole == GrooveRole ) ? + CircularProgressBar::Groove : CircularProgressBar::Bar; + + const QRectF rect = bar->contentsRect(); // ### rather call subcontrolrect + + QskArcMetrics arcMetrics = bar->arcMetricsHint( subControl ); + const int spanAngle = ( nodeRole == GrooveRole ) ? + 5760 : qRound( bar->valueAsRatio() * -5760 ); + arcMetrics.setSpanAngle( spanAngle ); + + QQuickWindow* window = bar->window(); const QskGradient gradient = bar->gradientHint( subControl ); - const QGradient::Type type = ( nodeRole == GrooveRole ) ? - QGradient::RadialGradient : QGradient::ConicalGradient; - - const double width = bar->metric( subControl | QskAspect::Size ); - const double value = ( nodeRole == GrooveRole ) ? bar->maximum() : bar->value(); - const double position = bar->metric( CircularProgressBar::Bar | QskAspect::Position ); - - arcNode->setArcData( gradient, type, width, value, bar->origin(), bar->maximum(), - bar->isIndeterminate(), position ); - - QQuickWindow* window = bar->window(); - const QRect rect = bar->contentsRect().toRect(); - arcNode->update( window, QskTextureRenderer::AutoDetect, rect ); + arcNode->setArcData( rect, arcMetrics, gradient, window ); return arcNode; } diff --git a/examples/iotdashboard/Skin.cpp b/examples/iotdashboard/Skin.cpp index a02ff359..7d05d61c 100644 --- a/examples/iotdashboard/Skin.cpp +++ b/examples/iotdashboard/Skin.cpp @@ -21,6 +21,7 @@ #include "UsageBox.h" #include "UsageDiagram.h" +#include #include #include #include @@ -108,14 +109,14 @@ void Skin::initHints( const Palette& palette ) ed.setColor( TopBarItem::Item4 | QskAspect::TextColor, "#6776ff" ); // conical gradients are counterclockwise, so specify the 2nd color first: - ed.setGradient( TopBarItem::Item1, { Qt::Horizontal, "#FF3122", "#FF5C00" } ); - ed.setGradient( TopBarItem::Item2, { Qt::Horizontal, "#6100FF", "#6776FF" } ); - ed.setGradient( TopBarItem::Item3, { Qt::Horizontal, "#FF3122", "#FFCE50" } ); - ed.setGradient( TopBarItem::Item4, { Qt::Horizontal, "#6100FF", "#6776FF" } ); + ed.setGradient( TopBarItem::Item1, { QskGradient::Conical, "#FF3122", "#FF5C00" } ); + ed.setGradient( TopBarItem::Item2, { QskGradient::Conical, "#6100FF", "#6776FF" } ); + ed.setGradient( TopBarItem::Item3, { QskGradient::Conical, "#FF3122", "#FFCE50" } ); + ed.setGradient( TopBarItem::Item4, { QskGradient::Conical, "#6100FF", "#6776FF" } ); // the bar gradient is defined through the top bar items above - ed.setMetricHint( CircularProgressBar::Groove | QskAspect::Size, 8.53 ); - ed.setMetricHint( CircularProgressBar::Bar | QskAspect::Size, 8.53 ); + ed.setArcMetrics( CircularProgressBar::Groove, { 8.53, 90 * 16, -360 * 16 } ); + ed.setArcMetrics( CircularProgressBar::Bar, { 8.53, 90 * 16, -180 * 16 } ); ed.setFontRole( TimeTitleLabel::Text, Skin::TitleFont ); diff --git a/examples/iotdashboard/Skin.h b/examples/iotdashboard/Skin.h index 733d9818..7a8c4d80 100644 --- a/examples/iotdashboard/Skin.h +++ b/examples/iotdashboard/Skin.h @@ -60,7 +60,7 @@ class DaytimeSkin : public Skin : Skin( Skin::Palette( {"#6D7BFB"}, {"#fbfbfb"}, {"#ffffff"}, "#ffffff", {"#f7f7f7"}, {"#f4f4f4"}, Qt::black, Qt::black, - { Qt::Horizontal, { { 0.0, 0xc4c4c4 }, { 0.5, 0xf8f8f8 }, { 1.0, 0xc4c4c4 } } } ) + { QskGradient::Radial, { { 0.0, 0xc4c4c4 }, { 0.5, 0xf8f8f8 }, { 1.0, 0xc4c4c4 } } } ) , parent ) { } @@ -73,7 +73,7 @@ class NighttimeSkin : public Skin : Skin( Skin::Palette( {"#2937A7"}, {"#040404"}, {"#000000"}, "#000000", {"#0a0a0a"}, {"#0c0c0c"}, Qt::white, Qt::white, - { Qt::Horizontal, { { 0.0, 0x666666 }, { 0.5, 0x222222 }, { 1.0, 0x333333 } } } ) + { QskGradient::Radial, { { 0.0, 0x666666 }, { 0.5, 0x222222 }, { 1.0, 0x333333 } } } ) , parent ) { } diff --git a/src/common/QskArcMetrics.cpp b/src/common/QskArcMetrics.cpp index 86911328..7729bf59 100644 --- a/src/common/QskArcMetrics.cpp +++ b/src/common/QskArcMetrics.cpp @@ -15,19 +15,18 @@ static void qskRegisterArcMetrics() Q_CONSTRUCTOR_FUNCTION( qskRegisterArcMetrics ) -void QskArcMetrics::setSizeMode( Qt::SizeMode sizeMode ) noexcept +// copied from QskMargins.cpp, we should unify this somehwere: +static inline qreal qskInterpolated( qreal from, qreal to, qreal ratio ) { - m_sizeMode = sizeMode; + return from + ( to - from ) * ratio; } -void QskArcMetrics::setStartAngle( qreal angle ) noexcept +// copied from QskBoxBorderMetrics.cpp, we should unify this somewhere: +static inline qreal qskAbsoluted( qreal length, qreal percentage ) { - m_startAngle = angle; -} - -void QskArcMetrics::setEndAngle( qreal angle ) noexcept -{ - m_endAngle = angle; + // 100% means -> 0.5 of length + percentage = qBound( 0.0, percentage, 100.0 ); + return percentage / 100.0 * 0.5 * length; } void QskArcMetrics::setWidth( qreal width ) noexcept @@ -35,11 +34,67 @@ void QskArcMetrics::setWidth( qreal width ) noexcept m_width = width; } +void QskArcMetrics::setStartAngle( int startAngle ) noexcept +{ + m_startAngle = startAngle; +} + +void QskArcMetrics::setSpanAngle( int spanAngle ) noexcept +{ + m_spanAngle = spanAngle; +} + +void QskArcMetrics::setSizeMode( Qt::SizeMode sizeMode ) noexcept +{ + m_sizeMode = sizeMode; +} + +QskArcMetrics QskArcMetrics::interpolated( + const QskArcMetrics& to, qreal ratio ) const noexcept +{ + if ( ( *this == to ) || ( m_sizeMode != to.m_sizeMode ) ) + return to; + + const qreal width = qskInterpolated( m_width, to.m_width, ratio ); + return QskArcMetrics( width, m_startAngle, m_spanAngle, m_sizeMode ); +} + +QVariant QskArcMetrics::interpolate( + const QskArcMetrics& from, const QskArcMetrics& to, + qreal progress ) +{ + return QVariant::fromValue( from.interpolated( to, progress ) ); +} + +QskArcMetrics QskArcMetrics::toAbsolute( const QSizeF& size ) const noexcept +{ + if ( m_sizeMode != Qt::RelativeSize ) + return *this; + + QskArcMetrics absoluted = *this; + + auto& w = absoluted.m_width; + + if ( size.isEmpty() ) + { + w = 0; + } + else + { + // for now we just use the width: + w = qskAbsoluted( size.width(), w ); + } + + absoluted.m_sizeMode = Qt::AbsoluteSize; + + return absoluted; +} + uint QskArcMetrics::hash( uint seed ) const noexcept { - uint hash = qHash( m_startAngle, seed ); - hash = qHash( m_endAngle, hash ); - hash = qHash( m_width, hash ); + uint hash = qHash( m_width, seed ); + hash = qHash( m_startAngle, hash ); + hash = qHash( m_spanAngle, hash ); const int mode = m_sizeMode; return qHashBits( &mode, sizeof( mode ), hash ); } @@ -54,10 +109,10 @@ QDebug operator<<( QDebug debug, const QskArcMetrics& metrics ) debug.nospace(); debug << "Arc" << '('; + debug << "width:" << metrics.width(); debug << "start angle:" << metrics.startAngle(); - debug << ", end angle:" << metrics.endAngle(); + debug << "span angle:" << metrics.spanAngle(); debug << ", size mode:" << metrics.sizeMode(); - debug << ", width:" << metrics.width(); debug << ')'; return debug; diff --git a/src/common/QskArcMetrics.h b/src/common/QskArcMetrics.h index 3cc4cdca..4678d714 100644 --- a/src/common/QskArcMetrics.h +++ b/src/common/QskArcMetrics.h @@ -16,70 +16,79 @@ class QSK_EXPORT QskArcMetrics { Q_GADGET - Q_PROPERTY( QskMargins widths READ widths WRITE setWidths ) + Q_PROPERTY( qreal width READ width WRITE setWidth ) + Q_PROPERTY( int startAngle READ startAngle WRITE setStartAngle ) + Q_PROPERTY( int spanAngle READ spanAngle WRITE setSpanAngle ) Q_PROPERTY( Qt::SizeMode sizeMode READ sizeMode WRITE setSizeMode ) public: constexpr QskArcMetrics() noexcept; - constexpr QskArcMetrics( qreal startAngle, qreal endAngle, - qreal width, Qt::SizeMode = Qt::AbsoluteSize ) noexcept; + constexpr QskArcMetrics( qreal width, int startAngle, int spanAngle, + Qt::SizeMode = Qt::AbsoluteSize ) noexcept; - constexpr bool operator==( const QskArcMetrics& ) const noexcept; - constexpr bool operator!=( const QskArcMetrics& ) const noexcept; + bool operator==( const QskArcMetrics& ) const noexcept; + bool operator!=( const QskArcMetrics& ) const noexcept; constexpr bool isNull() const noexcept; - void setStartAngle( qreal ) noexcept; - constexpr qreal startAngle() const noexcept; - void setEndAngle( qreal ) noexcept; - constexpr qreal endAngle() const noexcept; - void setWidth( qreal width ) noexcept; constexpr qreal width() const noexcept; + void setStartAngle( int startAngle ) noexcept; + constexpr int startAngle() const noexcept; + + void setSpanAngle( int spanAngle ) noexcept; + constexpr int spanAngle() const noexcept; + void setSizeMode( Qt::SizeMode ) noexcept; constexpr Qt::SizeMode sizeMode() const noexcept; + QskArcMetrics interpolated( const QskArcMetrics&, + qreal value ) const noexcept; + + QskArcMetrics toAbsolute( const QSizeF& ) const noexcept; + uint hash( uint seed = 0 ) const noexcept; static QVariant interpolate( const QskArcMetrics&, const QskArcMetrics&, qreal progress ); private: - qreal m_startAngle; - qreal m_endAngle; qreal m_width; + int m_startAngle; + int m_spanAngle; Qt::SizeMode m_sizeMode; }; inline constexpr QskArcMetrics::QskArcMetrics() noexcept - : m_startAngle( 0 ) - , m_endAngle( 0 ) - , m_width( 0 ) + : m_width( 0 ) + , m_startAngle( 0 ) + , m_spanAngle( 0 ) , m_sizeMode( Qt::AbsoluteSize ) { } -inline constexpr QskArcMetrics::QskArcMetrics( qreal startAngle, qreal endAngle, - qreal width, Qt::SizeMode sizeMode ) noexcept - : m_startAngle( startAngle ) - , m_endAngle( endAngle ) - , m_width( width ) +inline constexpr QskArcMetrics::QskArcMetrics( qreal width, + int startAngle, int spanAngle, + Qt::SizeMode sizeMode ) noexcept + : m_width( width ) + , m_startAngle( startAngle ) + , m_spanAngle( spanAngle ) , m_sizeMode( sizeMode ) { } -inline constexpr bool QskArcMetrics::operator==( +inline bool QskArcMetrics::operator==( const QskArcMetrics& other ) const noexcept { - return ( qskFuzzyCompare( m_startAngle, other.m_startAngle ) - && qskFuzzyCompare( m_endAngle, other.m_endAngle ) - && qskFuzzyCompare( m_width, other.m_width ) + return ( qskFuzzyCompare( m_width, other.m_width ) + && m_startAngle == other.m_startAngle + && m_spanAngle == other.m_spanAngle && m_sizeMode == other.m_sizeMode ); } -inline constexpr bool QskArcMetrics::operator!=( +inline bool QskArcMetrics::operator!=( const QskArcMetrics& other ) const noexcept { return !( *this == other ); @@ -87,10 +96,10 @@ inline constexpr bool QskArcMetrics::operator!=( inline constexpr bool QskArcMetrics::isNull() const noexcept { - return qFuzzyIsNull( m_startAngle ) - && qFuzzyIsNull( m_endAngle ) - && qFuzzyIsNull( m_width ) - && m_sizeMode == Qt::AbsoluteSize; + return ( qFuzzyIsNull( m_width ) + && m_startAngle == 0 + && m_spanAngle == 0 + && m_sizeMode == Qt::AbsoluteSize ); } inline constexpr qreal QskArcMetrics::width() const noexcept @@ -98,6 +107,16 @@ inline constexpr qreal QskArcMetrics::width() const noexcept return m_width; } +inline constexpr int QskArcMetrics::startAngle() const noexcept +{ + return m_startAngle; +} + +inline constexpr int QskArcMetrics::spanAngle() const noexcept +{ + return m_spanAngle; +} + inline constexpr Qt::SizeMode QskArcMetrics::sizeMode() const noexcept { return m_sizeMode; diff --git a/src/common/QskAspect.h b/src/common/QskAspect.h index 94e5bd42..7d8ba745 100644 --- a/src/common/QskAspect.h +++ b/src/common/QskAspect.h @@ -50,7 +50,8 @@ class QSK_EXPORT QskAspect Shadow, Shape, - Border + Border, + Arc }; Q_ENUM( Primitive ) diff --git a/src/common/QskGradient.h b/src/common/QskGradient.h index 9a84a555..3e5f0484 100644 --- a/src/common/QskGradient.h +++ b/src/common/QskGradient.h @@ -34,7 +34,9 @@ class QSK_EXPORT QskGradient { Horizontal, Vertical, - Diagonal + Diagonal, + Radial, + Conical }; Q_ENUM( Orientation ) diff --git a/src/controls/QskSkinHintTableEditor.cpp b/src/controls/QskSkinHintTableEditor.cpp index 414efac7..7eb12f46 100644 --- a/src/controls/QskSkinHintTableEditor.cpp +++ b/src/controls/QskSkinHintTableEditor.cpp @@ -6,6 +6,7 @@ #include "QskSkinHintTableEditor.h" #include "QskSkinHintTable.h" +#include "QskArcMetrics.h" #include "QskMargins.h" #include "QskBoxShapeMetrics.h" #include "QskBoxBorderMetrics.h" @@ -108,6 +109,11 @@ namespace { return aspect | QskAspect::Border; } + + inline QskAspect aspectArc( QskAspect aspect ) + { + return aspect | QskAspect::Arc; + } } QskSkinHintTableEditor::QskSkinHintTableEditor( QskSkinHintTable* table ) @@ -467,3 +473,27 @@ QskBoxBorderColors QskSkinHintTableEditor::boxBorderColors( QskAspect aspect ) c { return colorHint< QskBoxBorderColors >( aspectBorder( aspect ) ); } + +void QskSkinHintTableEditor::setArcMetrics( QskAspect aspect, qreal startAngle, + qreal endAngle, qreal width, Qt::SizeMode sizeMode ) +{ + setMetricHint( aspectArc( aspect ), + QskArcMetrics( startAngle, endAngle, width, sizeMode ) ); +} + +void QskSkinHintTableEditor::setArcMetrics( QskAspect aspect, + const QskArcMetrics& arcMetrics, QskStateCombination combination ) +{ + setMetricHint( aspectArc( aspect ), arcMetrics, combination ); +} + +void QskSkinHintTableEditor::removeArcMetrics( QskAspect aspect, + QskStateCombination combination ) +{ + return removeMetricHint( aspectArc( aspect ), combination ); +} + +QskArcMetrics QskSkinHintTableEditor::arcMetrics( QskAspect aspect ) const +{ + return metricHint< QskArcMetrics >( aspectArc( aspect ) ); +} diff --git a/src/controls/QskSkinHintTableEditor.h b/src/controls/QskSkinHintTableEditor.h index 8ba16c3d..e0bc0749 100644 --- a/src/controls/QskSkinHintTableEditor.h +++ b/src/controls/QskSkinHintTableEditor.h @@ -14,6 +14,7 @@ #include #include +class QskArcMetrics; class QskMargins; class QskGradient; class QskBoxShapeMetrics; @@ -220,6 +221,18 @@ class QSK_EXPORT QskSkinHintTableEditor void removeBoxBorderColors( QskAspect, QskStateCombination = QskStateCombination() ); QskBoxBorderColors boxBorderColors( QskAspect ) const; + // arcMetrics + + void setArcMetrics( QskAspect, + qreal, qreal, qreal, Qt::SizeMode = Qt::AbsoluteSize ); + + void setArcMetrics( QskAspect, + const QskArcMetrics&, QskStateCombination = QskStateCombination() ); + + void removeArcMetrics( QskAspect, QskStateCombination = QskStateCombination() ); + + QskArcMetrics arcMetrics( QskAspect ) const; + private: QskSkinHintTable* m_table = nullptr; }; diff --git a/src/controls/QskSkinlet.cpp b/src/controls/QskSkinlet.cpp index ea7a82b9..cf2a0891 100644 --- a/src/controls/QskSkinlet.cpp +++ b/src/controls/QskSkinlet.cpp @@ -5,6 +5,7 @@ #include "QskSkinlet.h" +#include "QskArcNode.h" #include "QskAspect.h" #include "QskBoxBorderColors.h" #include "QskBoxBorderMetrics.h" @@ -86,6 +87,12 @@ static inline bool qskIsBoxVisible( const QskBoxBorderMetrics& borderMetrics, return !borderMetrics.isNull() && borderColors.isVisible(); } +static inline bool qskIsArcVisible( const QskArcMetrics& arcMetrics, + const QskGradient& gradient ) +{ + return !arcMetrics.isNull() && gradient.isVisible(); +} + static inline QskTextColors qskTextColors( const QskSkinnable* skinnable, QskAspect::Subcontrol subControl ) { @@ -313,6 +320,49 @@ QSGNode* QskSkinlet::updateBoxNode( const QskSkinnable* skinnable, return boxNode; } +QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable, + QSGNode* node, QskAspect::Subcontrol subControl, + QQuickWindow* window ) const +{ + const auto rect = qskSubControlRect( this, skinnable, subControl ); + return updateArcNode( skinnable, node, rect, subControl, window ); +} + +QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable, + QSGNode* node, const QRectF& rect, QskAspect::Subcontrol subControl, + QQuickWindow* window ) +{ + const auto fillGradient = skinnable->gradientHint( subControl ); + return updateArcNode( skinnable, node, rect, fillGradient, subControl, + window ); +} + +QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable, + QSGNode* node, const QRectF& rect, const QskGradient& fillGradient, + QskAspect::Subcontrol subControl, QQuickWindow* window ) +{ + const auto margins = skinnable->marginHint( subControl ); + + const auto arcRect = rect.marginsRemoved( margins ); + if ( arcRect.isEmpty() ) + return nullptr; + + auto arcMetrics = skinnable->arcMetricsHint( subControl ); + arcMetrics = arcMetrics.toAbsolute( arcRect.size() ); + + if ( !qskIsArcVisible( arcMetrics, fillGradient ) ) + return nullptr; + + auto arcNode = static_cast< QskArcNode* >( node ); + + if ( arcNode == nullptr ) + arcNode = new QskArcNode(); + + arcNode->setArcData( rect, arcMetrics, fillGradient, window ); + + return arcNode; +} + QSGNode* QskSkinlet::updateBoxClipNode( const QskSkinnable* skinnable, QSGNode* node, QskAspect::Subcontrol subControl ) const { diff --git a/src/controls/QskSkinlet.h b/src/controls/QskSkinlet.h index 9855f099..d3b04b0c 100644 --- a/src/controls/QskSkinlet.h +++ b/src/controls/QskSkinlet.h @@ -22,6 +22,7 @@ class QskGraphic; class QskTextOptions; class QSGNode; +class QQuickWindow; class QSK_EXPORT QskSkinlet { @@ -52,6 +53,13 @@ class QSK_EXPORT QskSkinlet static QSGNode* updateBoxNode( const QskSkinnable*, QSGNode*, const QRectF&, const QskGradient&, QskAspect::Subcontrol ); + static QSGNode* updateArcNode( const QskSkinnable*, QSGNode*, + const QRectF&, QskAspect::Subcontrol, QQuickWindow* ); + + static QSGNode* updateArcNode( const QskSkinnable*, QSGNode*, + const QRectF&, const QskGradient&, QskAspect::Subcontrol, + QQuickWindow* ); + static QSGNode* updateTextNode( const QskSkinnable*, QSGNode*, const QRectF&, Qt::Alignment, const QString&, const QskTextOptions&, QskAspect::Subcontrol ); @@ -85,6 +93,9 @@ class QSK_EXPORT QskSkinlet QSGNode* updateBoxNode( const QskSkinnable*, QSGNode*, QskAspect::Subcontrol ) const; + QSGNode* updateArcNode( const QskSkinnable*, QSGNode*, + QskAspect::Subcontrol, QQuickWindow* ) const; + QSGNode* updateBoxClipNode( const QskSkinnable*, QSGNode*, QskAspect::Subcontrol ) const; diff --git a/src/controls/QskSkinnable.cpp b/src/controls/QskSkinnable.cpp index d264d2ef..645e3465 100644 --- a/src/controls/QskSkinnable.cpp +++ b/src/controls/QskSkinnable.cpp @@ -6,6 +6,7 @@ #include "QskSkinnable.h" #include "QskAnimationHint.h" +#include "QskArcMetrics.h" #include "QskAspect.h" #include "QskColorFilter.h" #include "QskControl.h" @@ -521,6 +522,24 @@ QskBoxBorderColors QskSkinnable::boxBorderColorsHint( this, aspect | QskAspect::Border, status ); } +bool QskSkinnable::setArcMetricsHint( + const QskAspect aspect, const QskArcMetrics& arc ) +{ + return qskSetMetric( this, aspect | QskAspect::Arc, arc ); +} + +bool QskSkinnable::resetArcMetricsHint( const QskAspect aspect ) +{ + return resetMetric( aspect | QskAspect::Arc ); +} + +QskArcMetrics QskSkinnable::arcMetricsHint( + const QskAspect aspect, QskSkinHintStatus* status ) const +{ + return qskMetric< QskArcMetrics >( + this, aspect | QskAspect::Arc, status ); +} + bool QskSkinnable::setSpacingHint( const QskAspect aspect, qreal spacing ) { return qskSetMetric( this, aspect | QskAspect::Spacing, spacing ); diff --git a/src/controls/QskSkinnable.h b/src/controls/QskSkinnable.h index 9a9ca847..07479797 100644 --- a/src/controls/QskSkinnable.h +++ b/src/controls/QskSkinnable.h @@ -21,6 +21,7 @@ class QDebug; class QSGNode; +class QskArcMetrics; class QskControl; class QskAnimationHint; class QskColorFilter; @@ -189,6 +190,10 @@ class QSK_EXPORT QskSkinnable bool resetBoxBorderColorsHint( QskAspect ); QskBoxBorderColors boxBorderColorsHint( QskAspect, QskSkinHintStatus* = nullptr ) const; + bool setArcMetricsHint( QskAspect, const QskArcMetrics& ); + bool resetArcMetricsHint( QskAspect ); + QskArcMetrics arcMetricsHint( QskAspect, QskSkinHintStatus* = nullptr ) const; + bool setSpacingHint( QskAspect, qreal ); bool resetSpacingHint( QskAspect ); qreal spacingHint( QskAspect, QskSkinHintStatus* = nullptr ) const; diff --git a/src/nodes/QskArcNode.cpp b/src/nodes/QskArcNode.cpp index 511bd020..54b7370b 100644 --- a/src/nodes/QskArcNode.cpp +++ b/src/nodes/QskArcNode.cpp @@ -16,55 +16,28 @@ QskArcNode::~QskArcNode() { } -void QskArcNode::setArcData( const QskGradient &gradient, - QGradient::Type gradientType, double width, double value, double origin, - double maximum, bool isIndeterminate, double position ) +void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& metrics, + const QskGradient &gradient, QQuickWindow* window ) { + m_rect = rect; + m_metrics = metrics; m_gradient = gradient; - m_gradientType = gradientType; - m_width = width; - m_value = value; - m_origin = origin; - m_maximum = maximum; - m_isIndeterminate = isIndeterminate; - m_position = position; + + update( window, QskTextureRenderer::AutoDetect, m_rect.toRect() ); } -void QskArcNode::paint( QPainter *painter, const QSizeF &size ) +void QskArcNode::paint( QPainter* painter, const QSizeF &size ) { - int startAngle; - int spanAngle; - - if( m_isIndeterminate ) - { - startAngle = -1 * m_position * 360; - // the other option is to just set a fixed value for the - // span angle (or do some advanced stuff with easing curves) - spanAngle = qAbs( 0.5 - m_position ) * 360; - } - else - { - startAngle = 90 + -1 * ( m_origin / m_maximum ) * 360; - spanAngle = -1 * ( m_value / m_maximum ) * 360; - } - - const QRectF r( 0.5 * m_width, 0.5 * m_width, - size.width() - m_width, size.height() - m_width ); + const qreal w = m_metrics.width(); + const QRectF rect( 0.5 * w, 0.5 * w, size.width() - w, size.height() - w ); QskArcRenderer renderer; - renderer.renderArc( r, m_gradient, m_gradientType, m_width, startAngle, spanAngle, - painter ); + renderer.renderArc( rect, m_metrics, m_gradient, painter ); } uint QskArcNode::hash() const { - uint h = qHash( m_gradientType ); - h = qHash( m_width, h ); - h = qHash( m_value, h ); - h = qHash( m_origin, h ); - h = qHash( m_maximum, h ); - h = qHash( m_isIndeterminate, h ); - h = qHash( m_position, h ); + uint h = m_metrics.hash(); for( const QskGradientStop& stop : m_gradient.stops() ) { diff --git a/src/nodes/QskArcNode.h b/src/nodes/QskArcNode.h index e87a93a6..ac981a41 100644 --- a/src/nodes/QskArcNode.h +++ b/src/nodes/QskArcNode.h @@ -6,32 +6,26 @@ #ifndef QSK_ARC_NODE_H #define QSK_ARC_NODE_H +#include "QskArcMetrics.h" #include "QskGradient.h" #include "QskPaintedNode.h" -#include - class QSK_EXPORT QskArcNode : public QskPaintedNode { public: QskArcNode(); ~QskArcNode() override; - void setArcData( const QskGradient&, QGradient::Type, double, double, - double, double, bool, double ); + void setArcData( const QRectF&, const QskArcMetrics&, const QskGradient&, + QQuickWindow* ); void paint( QPainter* painter, const QSizeF& size ) override; uint hash() const override; private: + QRectF m_rect; + QskArcMetrics m_metrics; QskGradient m_gradient; - QGradient::Type m_gradientType; - double m_width; - double m_value; - double m_origin; - double m_maximum; - bool m_isIndeterminate; - double m_position; }; #endif diff --git a/src/nodes/QskArcRenderer.h b/src/nodes/QskArcRenderer.h index b5733433..e928c939 100644 --- a/src/nodes/QskArcRenderer.h +++ b/src/nodes/QskArcRenderer.h @@ -6,6 +6,7 @@ #ifndef QSK_ARC_RENDERER_H #define QSK_ARC_RENDERER_H +#include "QskArcMetrics.h" #include "QskGlobal.h" #include "QskGradient.h" @@ -15,14 +16,13 @@ class QSK_EXPORT QskArcRenderer { public: - void renderArc( const QRectF& rect, const QskGradient& gradient, - QGradient::Type gradientType, double width, int startAngle, - int endAngle, QPainter* ); + void renderArc( const QRectF& rect, const QskArcMetrics& metrics, + const QskGradient& gradient, QPainter* ); }; -inline void QskArcRenderer::renderArc( const QRectF& rect, - const QskGradient& gradient, QGradient::Type gradientType, double width, - int startAngle, int spanAngle, QPainter* painter ) +void QskArcRenderer::renderArc(const QRectF& rect, + const QskArcMetrics& metrics, const QskGradient& gradient, + QPainter* painter ) { painter->setRenderHint( QPainter::Antialiasing, true ); @@ -34,23 +34,25 @@ inline void QskArcRenderer::renderArc( const QRectF& rect, stops.append( s ); } - if( gradientType == QGradient::RadialGradient ) + if( gradient.orientation() == QskGradient::Radial ) { - QRadialGradient radialGradient( rect.center(), qMin( rect.width(), rect.height() ) ); + QRadialGradient radialGradient( rect.center(), qMin( rect.width(), + rect.height() ) ); radialGradient.setStops( stops ); - - painter->setPen( QPen( radialGradient, width, Qt::SolidLine, Qt::FlatCap ) ); - painter->drawArc( rect, startAngle * 16, spanAngle * 16 ); + painter->setPen( QPen( radialGradient, metrics.width(), Qt::SolidLine, + Qt::FlatCap ) ); } - else + else if( gradient.orientation() == QskGradient::Conical ) { - QConicalGradient conicalGradient( rect.center(), startAngle ); + QConicalGradient conicalGradient( rect.center(), + metrics.startAngle() / 16.0 ); conicalGradient.setStops( stops ); - - painter->setPen( QPen( conicalGradient, width, Qt::SolidLine, Qt::FlatCap ) ); - painter->drawArc( rect, startAngle * 16, spanAngle * 16 ); + painter->setPen( QPen( conicalGradient, metrics.width(), Qt::SolidLine, + Qt::FlatCap ) ); } + // ### add other types + painter->drawArc( rect, metrics.startAngle(), metrics.spanAngle() ); } #endif diff --git a/src/nodes/QskBoxRendererEllipse.cpp b/src/nodes/QskBoxRendererEllipse.cpp index b55f7259..5e2f8105 100644 --- a/src/nodes/QskBoxRendererEllipse.cpp +++ b/src/nodes/QskBoxRendererEllipse.cpp @@ -11,6 +11,7 @@ #include "QskBoxRendererColorMap.h" #include "QskBoxShapeMetrics.h" +#include #include #include @@ -773,6 +774,13 @@ static inline int qskFillLineCount( break; } + case QskGradient::Radial: // fall through + case QskGradient::Conical: + { + qWarning() << "radial and conical gradients are only supported" + << "when rendering arcs"; + break; + } } // adding vertexes for the stops - beside the first/last diff --git a/src/nodes/QskBoxRendererRect.cpp b/src/nodes/QskBoxRendererRect.cpp index 990a9db8..05e8d8e5 100644 --- a/src/nodes/QskBoxRendererRect.cpp +++ b/src/nodes/QskBoxRendererRect.cpp @@ -11,6 +11,8 @@ #include "QskGradient.h" #include "QskVertex.h" +#include + using namespace QskVertex; namespace @@ -376,6 +378,13 @@ static inline void qskCreateFillOrdered( const QskBoxRenderer::Quad& rect, break; } + case QskGradient::Radial: // fall through + case QskGradient::Conical: + { + qWarning() << "radial and conical gradients are only supported" + << "when rendering arcs"; + break; + } } }