From 922d81eddd193ee2ab0e2494e5327a9467a1b9e5 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Mon, 18 Oct 2021 14:05:25 +0200 Subject: [PATCH] add arc border metrics --- src/common/QskArcBorderMetrics.cpp | 169 ++++++++++++++++++++++++ src/common/QskArcBorderMetrics.h | 160 ++++++++++++++++++++++ src/common/QskNamespace.h | 9 ++ src/controls/QskSkinHintTableEditor.cpp | 27 ++++ src/controls/QskSkinHintTableEditor.h | 13 ++ src/controls/QskSkinlet.cpp | 13 +- src/controls/QskSkinnable.cpp | 19 +++ src/controls/QskSkinnable.h | 5 + src/nodes/QskArcNode.cpp | 32 ++++- src/nodes/QskArcNode.h | 6 +- src/nodes/QskArcRenderer.cpp | 28 +++- src/nodes/QskArcRenderer.h | 3 +- src/src.pro | 2 + 13 files changed, 474 insertions(+), 12 deletions(-) create mode 100644 src/common/QskArcBorderMetrics.cpp create mode 100644 src/common/QskArcBorderMetrics.h diff --git a/src/common/QskArcBorderMetrics.cpp b/src/common/QskArcBorderMetrics.cpp new file mode 100644 index 00000000..ccec372d --- /dev/null +++ b/src/common/QskArcBorderMetrics.cpp @@ -0,0 +1,169 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#include "QskArcBorderMetrics.h" + +#include +#include + +static void qskRegisterArcBorderMetrics() +{ + qRegisterMetaType< QskArcBorderMetrics >(); + + QMetaType::registerConverter< int, QskArcBorderMetrics >( + []( int width ) { return QskArcBorderMetrics( width ); } ); + + QMetaType::registerConverter< qreal, QskArcBorderMetrics >( + []( qreal width ) { return QskArcBorderMetrics( width ); } ); +} + +Q_CONSTRUCTOR_FUNCTION( qskRegisterArcBorderMetrics ) + +// copied from QskMargins.cpp, we should unify this somehwere: +static inline qreal qskInterpolated( qreal from, qreal to, qreal ratio ) +{ + return from + ( to - from ) * ratio; +} + +static inline qreal qskAbsoluted( qreal length, qreal percentage ) +{ + // 100% means -> 0.5 of length + percentage = qBound( 0.0, percentage, 100.0 ); + return percentage / 100.0 * 0.5 * length; +} + +void QskArcBorderMetrics::setSizeMode( Qt::SizeMode sizeMode ) noexcept +{ + m_sizeMode = sizeMode; +} + +void QskArcBorderMetrics::setWidth( Qsk::ArcPosition position, qreal width ) noexcept +{ + m_widths[ position ] = qMax( width, 0.0 ); +} + +void QskArcBorderMetrics::setWidths( qreal width ) noexcept +{ + m_widths[0] = m_widths[1] = m_widths[2] = m_widths[3] = width; +} + +void QskArcBorderMetrics::setWidths( qreal outer, qreal inner, qreal start, + qreal end ) noexcept +{ + m_widths[0] = outer; + m_widths[1] = inner; + m_widths[2] = start; + m_widths[3] = end; +} + +void QskArcBorderMetrics::setOuterWidth( qreal width ) noexcept +{ + m_widths[0] = width; +} + +void QskArcBorderMetrics::setInnerWidth( qreal width ) noexcept +{ + m_widths[1] = width; +} + +void QskArcBorderMetrics::setStartWidth( qreal width ) noexcept +{ + m_widths[2] = width; +} + +void QskArcBorderMetrics::setEndWidth( qreal width ) noexcept +{ + m_widths[3] = width; +} + +QskArcBorderMetrics QskArcBorderMetrics::interpolated( + const QskArcBorderMetrics& to, qreal ratio ) const noexcept +{ + if ( ( *this == to ) || ( m_sizeMode != to.m_sizeMode ) ) + return to; + + const qreal outerWidth = qskInterpolated( m_widths[0], to.m_widths[0], ratio ); + const qreal innerWidth = qskInterpolated( m_widths[1], to.m_widths[1], ratio ); + const qreal startWidth = qskInterpolated( m_widths[2], to.m_widths[2], ratio ); + const qreal endWidth = qskInterpolated( m_widths[3], to.m_widths[3], ratio ); + + return QskArcBorderMetrics( outerWidth, innerWidth, startWidth, endWidth, + m_sizeMode ); +} + +QVariant QskArcBorderMetrics::interpolate( + const QskArcBorderMetrics& from, const QskArcBorderMetrics& to, + qreal progress ) +{ + return QVariant::fromValue( from.interpolated( to, progress ) ); +} + +QskArcBorderMetrics QskArcBorderMetrics::toAbsolute( const QSizeF& size ) const noexcept +{ + if ( m_sizeMode != Qt::RelativeSize ) + return *this; + + QskArcBorderMetrics absoluted = *this; + + auto& outerWidth = absoluted.m_widths[0]; + auto& innerWidth = absoluted.m_widths[1]; + auto& startWidth = absoluted.m_widths[2]; + auto& endWidth = absoluted.m_widths[3]; + + if ( size.isEmpty() ) + { + outerWidth = 0.0; + innerWidth = 0.0; + startWidth = 0.0; + endWidth = 0.0; + } + else + { + // for now we just use the width: + outerWidth = qskAbsoluted( size.width(), outerWidth ); + innerWidth = qskAbsoluted( size.width(), innerWidth ); + startWidth = qskAbsoluted( size.width(), startWidth ); + endWidth = qskAbsoluted( size.width(), endWidth ); + } + + absoluted.m_sizeMode = Qt::AbsoluteSize; + + return absoluted; +} + +uint QskArcBorderMetrics::hash( uint seed ) const noexcept +{ + uint hash = qHash( m_widths[0], seed ); + hash = qHash( m_widths[1], hash ); + hash = qHash( m_widths[2], hash ); + hash = qHash( m_widths[3], hash ); + + const int mode = m_sizeMode; + return qHashBits( &mode, sizeof( mode ), hash ); +} + +#ifndef QT_NO_DEBUG_STREAM + +#include + +QDebug operator<<( QDebug debug, const QskArcBorderMetrics& metrics ) +{ + QDebugStateSaver saver( debug ); + debug.nospace(); + + debug << "ArcBorder" << '('; + debug << metrics.sizeMode(); + debug << ", outer width:" << metrics.width( Qsk::Outer ); + debug << ", inner width:" << metrics.width( Qsk::Inner ); + debug << ", start width:" << metrics.width( Qsk::Start ); + debug << ", end width:" << metrics.width( Qsk::End ); + debug << ')'; + + return debug; +} + +#endif + +#include "moc_QskArcBorderMetrics.cpp" diff --git a/src/common/QskArcBorderMetrics.h b/src/common/QskArcBorderMetrics.h new file mode 100644 index 00000000..fd9fc032 --- /dev/null +++ b/src/common/QskArcBorderMetrics.h @@ -0,0 +1,160 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#ifndef QSK_ARC_BORDER_METRICS_H +#define QSK_ARC_BORDER_METRICS_H + +#include "QskFunctions.h" +#include "QskNamespace.h" + +#include +#include +#include + +class QVariant; + +class QSK_EXPORT QskArcBorderMetrics +{ + Q_GADGET + + Q_PROPERTY( qreal outerWidth READ outerWidth WRITE setOuterWidth ) + Q_PROPERTY( qreal innerWidth READ innerWidth WRITE setInnerWidth ) + Q_PROPERTY( qreal startWidth READ startWidth WRITE setStartWidth ) + Q_PROPERTY( qreal endWidth READ endWidth WRITE setEndWidth ) + Q_PROPERTY( Qt::SizeMode sizeMode READ sizeMode WRITE setSizeMode ) + + public: + constexpr QskArcBorderMetrics() noexcept; + + constexpr QskArcBorderMetrics( qreal, + Qt::SizeMode = Qt::AbsoluteSize ) noexcept; + + constexpr QskArcBorderMetrics( qreal, qreal, qreal, qreal, + Qt::SizeMode = Qt::AbsoluteSize ) noexcept; + + constexpr bool operator==( const QskArcBorderMetrics& ) const noexcept; + constexpr bool operator!=( const QskArcBorderMetrics& ) const noexcept; + + constexpr bool isNull() const noexcept; + + void setWidth( Qsk::ArcPosition, qreal width ) noexcept; + constexpr qreal width( Qsk::ArcPosition ) const noexcept; + + void setWidths( qreal ) noexcept; + void setWidths( qreal, qreal, qreal, qreal ) noexcept; + + void setOuterWidth( qreal ) noexcept; + void setInnerWidth( qreal ) noexcept; + void setStartWidth( qreal ) noexcept; + void setEndWidth( qreal ) noexcept; + constexpr qreal outerWidth() const noexcept; + constexpr qreal innerWidth() const noexcept; + constexpr qreal startWidth() const noexcept; + constexpr qreal endWidth() const noexcept; + + void setSizeMode( Qt::SizeMode ) noexcept; + constexpr Qt::SizeMode sizeMode() const noexcept; + + QskArcBorderMetrics interpolated( + const QskArcBorderMetrics&, qreal value ) const noexcept; + + QskArcBorderMetrics toAbsolute( const QSizeF& ) const noexcept; + + uint hash( uint seed = 0 ) const noexcept; + + static QVariant interpolate( const QskArcBorderMetrics&, + const QskArcBorderMetrics&, qreal progress ); + + private: + qreal m_widths[ 4 ]; + Qt::SizeMode m_sizeMode; +}; + +inline constexpr QskArcBorderMetrics::QskArcBorderMetrics() noexcept + : m_widths{ 0.0, 0.0, 0.0, 0.0 } + , m_sizeMode( Qt::AbsoluteSize ) +{ +} + +inline constexpr QskArcBorderMetrics::QskArcBorderMetrics( + qreal width, Qt::SizeMode sizeMode ) noexcept + : m_widths{ width, width, width, width } + , m_sizeMode( sizeMode ) +{ +} + +inline constexpr QskArcBorderMetrics::QskArcBorderMetrics( qreal outer, + qreal inner, qreal start, qreal end, Qt::SizeMode sizeMode ) noexcept + : m_widths{ outer, inner, start, end } + , m_sizeMode( sizeMode ) +{ +} + +inline constexpr bool QskArcBorderMetrics::operator==( + const QskArcBorderMetrics& other ) const noexcept +{ + return ( m_sizeMode == other.m_sizeMode ) + && qskFuzzyCompare( m_widths[0], other.m_widths[0] ) + && qskFuzzyCompare( m_widths[1], other.m_widths[1] ) + && qskFuzzyCompare( m_widths[2], other.m_widths[2] ) + && qskFuzzyCompare( m_widths[3], other.m_widths[3] ); +} + +inline constexpr bool QskArcBorderMetrics::operator!=( + const QskArcBorderMetrics& other ) const noexcept +{ + return !( *this == other ); +} + +inline constexpr bool QskArcBorderMetrics::isNull() const noexcept +{ + return ( qFuzzyIsNull( m_widths[0] ) + && qFuzzyIsNull( m_widths[1] ) + && qFuzzyIsNull( m_widths[2] ) + && qFuzzyIsNull( m_widths[3] ) + && m_sizeMode == Qt::AbsoluteSize ); +} + +inline constexpr qreal QskArcBorderMetrics::width( Qsk::ArcPosition position ) const noexcept +{ + return m_widths[ position ]; +} + +inline constexpr qreal QskArcBorderMetrics::outerWidth() const noexcept +{ + return m_widths[ Qsk::Outer ]; +} + +inline constexpr qreal QskArcBorderMetrics::innerWidth() const noexcept +{ + return m_widths[ Qsk::Inner ]; +} + +inline constexpr qreal QskArcBorderMetrics::startWidth() const noexcept +{ + return m_widths[ Qsk::Start ]; +} + +inline constexpr qreal QskArcBorderMetrics::endWidth() const noexcept +{ + return m_widths[ Qsk::End ]; +} + +inline constexpr Qt::SizeMode QskArcBorderMetrics::sizeMode() const noexcept +{ + return m_sizeMode; +} + +#ifndef QT_NO_DEBUG_STREAM + +class QDebug; +QSK_EXPORT QDebug operator<<( QDebug, const QskArcBorderMetrics& ); + +#endif + +Q_DECLARE_TYPEINFO( QskArcBorderMetrics, Q_MOVABLE_TYPE ); +Q_DECLARE_METATYPE( QskArcBorderMetrics ) + +#endif diff --git a/src/common/QskNamespace.h b/src/common/QskNamespace.h index 73f33939..86c1687b 100644 --- a/src/common/QskNamespace.h +++ b/src/common/QskNamespace.h @@ -58,6 +58,15 @@ QSK_NAMESPACE( Qsk ) }; QSK_ENUM( Position ) + enum ArcPosition + { + Outer, + Inner, + Start, + End + }; + QSK_ENUM( ArcPosition ) + enum TextStyle { Normal, diff --git a/src/controls/QskSkinHintTableEditor.cpp b/src/controls/QskSkinHintTableEditor.cpp index f05521be..414a8af5 100644 --- a/src/controls/QskSkinHintTableEditor.cpp +++ b/src/controls/QskSkinHintTableEditor.cpp @@ -6,6 +6,7 @@ #include "QskSkinHintTableEditor.h" #include "QskSkinHintTable.h" +#include "QskArcBorderMetrics.h" #include "QskArcMetrics.h" #include "QskMargins.h" #include "QskBoxShapeMetrics.h" @@ -492,3 +493,29 @@ QskArcMetrics QskSkinHintTableEditor::arcMetrics( QskAspect aspect ) const { return metricHint< QskArcMetrics >( aspectShape( aspect ) ); } + +void QskSkinHintTableEditor::setArcBorderMetrics( QskAspect aspect, + qreal outerWidth, qreal innerWidth, qreal startWidth, qreal endWidth, + Qt::SizeMode sizeMode ) +{ + setMetricHint( aspectBorder( aspect ), + QskArcBorderMetrics( outerWidth, innerWidth, startWidth, endWidth, + sizeMode ) ); +} + +void QskSkinHintTableEditor::setArcBorderMetrics( QskAspect aspect, + const QskArcBorderMetrics& arcBorderMetrics, QskStateCombination combination ) +{ + setMetricHint( aspectBorder( aspect ), arcBorderMetrics, combination ); +} + +void QskSkinHintTableEditor::removeArcBorderMetrics( QskAspect aspect, + QskStateCombination combination ) +{ + return removeMetricHint( aspectBorder( aspect ), combination ); +} + +QskArcBorderMetrics QskSkinHintTableEditor::arcBorderMetrics( QskAspect aspect ) const +{ + return metricHint< QskArcBorderMetrics >( aspectBorder( aspect ) ); +} diff --git a/src/controls/QskSkinHintTableEditor.h b/src/controls/QskSkinHintTableEditor.h index 20073728..2161a83e 100644 --- a/src/controls/QskSkinHintTableEditor.h +++ b/src/controls/QskSkinHintTableEditor.h @@ -14,6 +14,7 @@ #include #include +class QskArcBorderMetrics; class QskArcMetrics; class QskMargins; class QskGradient; @@ -232,6 +233,18 @@ class QSK_EXPORT QskSkinHintTableEditor QskArcMetrics arcMetrics( QskAspect ) const; + // arcBorderMetrics + + void setArcBorderMetrics( QskAspect, qreal, qreal, qreal, qreal, + Qt::SizeMode = Qt::AbsoluteSize ); + + void setArcBorderMetrics( QskAspect, + const QskArcBorderMetrics&, QskStateCombination = QskStateCombination() ); + + void removeArcBorderMetrics( QskAspect, QskStateCombination = QskStateCombination() ); + + QskArcBorderMetrics arcBorderMetrics( QskAspect ) const; + private: QskSkinHintTable* m_table = nullptr; }; diff --git a/src/controls/QskSkinlet.cpp b/src/controls/QskSkinlet.cpp index 4caea2fa..4b7742a4 100644 --- a/src/controls/QskSkinlet.cpp +++ b/src/controls/QskSkinlet.cpp @@ -88,9 +88,11 @@ static inline bool qskIsBoxVisible( const QskBoxBorderMetrics& borderMetrics, } static inline bool qskIsArcVisible( const QskArcMetrics& arcMetrics, + const QskArcBorderMetrics& borderMetrics, const QskGradient& gradient ) { - return !arcMetrics.isNull() && gradient.isVisible(); + return ( !arcMetrics.isNull() && gradient.isVisible() ) + || !borderMetrics.isNull(); } static inline QskTextColors qskTextColors( @@ -360,7 +362,10 @@ QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable, auto absoluteArcMetrics = arcMetrics.toAbsolute( arcRect.size() ); - if ( !qskIsArcVisible( arcMetrics, fillGradient ) ) + auto arcBorderMetrics = skinnable->arcBorderMetricsHint( subControl ); + arcBorderMetrics = arcBorderMetrics.toAbsolute( arcRect.size() ); + + if ( !qskIsArcVisible( arcMetrics, arcBorderMetrics, fillGradient ) ) return nullptr; auto arcNode = static_cast< QskArcNode* >( node ); @@ -368,8 +373,8 @@ QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable, if ( arcNode == nullptr ) arcNode = new QskArcNode(); - arcNode->setArcData( rect, absoluteArcMetrics, fillGradient, - control->window() ); + arcNode->setArcData( rect, absoluteArcMetrics, arcBorderMetrics, + fillGradient, control->window() ); return arcNode; } diff --git a/src/controls/QskSkinnable.cpp b/src/controls/QskSkinnable.cpp index 26f0b03d..6b118246 100644 --- a/src/controls/QskSkinnable.cpp +++ b/src/controls/QskSkinnable.cpp @@ -6,6 +6,7 @@ #include "QskSkinnable.h" #include "QskAnimationHint.h" +#include "QskArcBorderMetrics.h" #include "QskArcMetrics.h" #include "QskAspect.h" #include "QskColorFilter.h" @@ -540,6 +541,24 @@ QskArcMetrics QskSkinnable::arcMetricsHint( this, aspect | QskAspect::Shape, status ); } +bool QskSkinnable::setArcBorderMetricsHint( + const QskAspect aspect, const QskArcBorderMetrics& arc ) +{ + return qskSetMetric( this, aspect | QskAspect::Border, arc ); +} + +bool QskSkinnable::resetArcBorderMetricsHint( const QskAspect aspect ) +{ + return resetMetric( aspect | QskAspect::Border ); +} + +QskArcBorderMetrics QskSkinnable::arcBorderMetricsHint( + const QskAspect aspect, QskSkinHintStatus* status ) const +{ + return qskMetric< QskArcBorderMetrics >( + this, aspect | QskAspect::Border, 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 07479797..02c04772 100644 --- a/src/controls/QskSkinnable.h +++ b/src/controls/QskSkinnable.h @@ -21,6 +21,7 @@ class QDebug; class QSGNode; +class QskArcBorderMetrics; class QskArcMetrics; class QskControl; class QskAnimationHint; @@ -194,6 +195,10 @@ class QSK_EXPORT QskSkinnable bool resetArcMetricsHint( QskAspect ); QskArcMetrics arcMetricsHint( QskAspect, QskSkinHintStatus* = nullptr ) const; + bool setArcBorderMetricsHint( QskAspect, const QskArcBorderMetrics& ); + bool resetArcBorderMetricsHint( QskAspect ); + QskArcBorderMetrics arcBorderMetricsHint( 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 edb0f92c..ada200b9 100644 --- a/src/nodes/QskArcNode.cpp +++ b/src/nodes/QskArcNode.cpp @@ -15,11 +15,37 @@ QskArcNode::~QskArcNode() } void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& metrics, - const QskGradient &gradient, QQuickWindow* window ) + const QskArcBorderMetrics& borderMetrics, const QskGradient &gradient, + QQuickWindow* window ) { m_metrics = metrics; + m_borderMetrics = borderMetrics; m_gradient = gradient; + if ( rect.isEmpty() ) + { + return; + } + + bool hasFill = gradient.isValid(); + bool hasBorder = !borderMetrics.isNull(); + + if ( hasBorder ) + { + /* + Wrong as the border width should have an + effect - even if not being visible. TODO ... + */ + + // ### implement border colors +// hasBorder = borderColors.isVisible(); + } + + if ( !hasBorder && !hasFill ) + { + return; + } + update( window, QskTextureRenderer::AutoDetect, rect.toRect() ); } @@ -29,12 +55,14 @@ void QskArcNode::paint( QPainter* painter, const QSizeF &size ) const QRectF rect( 0.5 * w, 0.5 * w, size.width() - w, size.height() - w ); QskArcRenderer renderer; - renderer.renderArc( rect, m_metrics, m_gradient, painter ); + + renderer.renderArc( rect, m_metrics, m_borderMetrics, m_gradient, painter ); } uint QskArcNode::hash() const { uint h = m_metrics.hash(); + h = m_borderMetrics.hash( h ); for( const auto& stop : m_gradient.stops() ) h = stop.hash( h ); diff --git a/src/nodes/QskArcNode.h b/src/nodes/QskArcNode.h index ce24d691..aca74184 100644 --- a/src/nodes/QskArcNode.h +++ b/src/nodes/QskArcNode.h @@ -6,6 +6,7 @@ #ifndef QSK_ARC_NODE_H #define QSK_ARC_NODE_H +#include "QskArcBorderMetrics.h" #include "QskArcMetrics.h" #include "QskGradient.h" #include "QskPaintedNode.h" @@ -16,14 +17,15 @@ class QSK_EXPORT QskArcNode : public QskPaintedNode QskArcNode(); ~QskArcNode() override; - void setArcData( const QRectF&, const QskArcMetrics&, const QskGradient&, - QQuickWindow* ); + void setArcData( const QRectF&, const QskArcMetrics&, + const QskArcBorderMetrics&, const QskGradient&, QQuickWindow* ); void paint( QPainter* painter, const QSizeF& size ) override; uint hash() const override; private: QskArcMetrics m_metrics; + QskArcBorderMetrics m_borderMetrics; QskGradient m_gradient; }; diff --git a/src/nodes/QskArcRenderer.cpp b/src/nodes/QskArcRenderer.cpp index 804e3630..3684b77e 100644 --- a/src/nodes/QskArcRenderer.cpp +++ b/src/nodes/QskArcRenderer.cpp @@ -4,15 +4,17 @@ *****************************************************************************/ #include "QskArcRenderer.h" + +#include "QskArcBorderMetrics.h" #include "QskArcMetrics.h" #include "QskGradient.h" #include #include -void QskArcRenderer::renderArc(const QRectF& rect, - const QskArcMetrics& metrics, const QskGradient& gradient, - QPainter* painter ) +void QskArcRenderer::renderArc( const QRectF& rect, + const QskArcMetrics& metrics, const QskArcBorderMetrics &borderMetrics, + const QskGradient& gradient, QPainter* painter ) { painter->setRenderHint( QPainter::Antialiasing, true ); @@ -48,4 +50,24 @@ void QskArcRenderer::renderArc(const QRectF& rect, painter->setPen( QPen( brush, metrics.width(), Qt::SolidLine, Qt::FlatCap ) ); painter->drawArc( rect, metrics.startAngle(), metrics.spanAngle() ); + + if( borderMetrics.width( Qsk::Inner ) > 0 ) + { + // draw inner border: + const qreal i = metrics.width() / 2; + const auto innerRect = rect.marginsRemoved( { i, i, i, i } ); + painter->setPen( QPen( Qt::black, borderMetrics.width( Qsk::Inner ), + Qt::SolidLine, Qt::FlatCap ) ); + painter->drawArc( innerRect, metrics.startAngle(), metrics.spanAngle() ); + } + + if( borderMetrics.width( Qsk::Outer ) > 0 ) + { + // draw outer border: + const qreal o = ( metrics.width() - borderMetrics.width( Qsk::Outer ) ) / 2; + const auto outerRect = rect.marginsAdded( { o, o, o, o } ); + painter->setPen( QPen( Qt::black, borderMetrics.width( Qsk::Outer ), + Qt::SolidLine, Qt::FlatCap ) ); + painter->drawArc( outerRect, metrics.startAngle(), metrics.spanAngle() ); + } } diff --git a/src/nodes/QskArcRenderer.h b/src/nodes/QskArcRenderer.h index 4fda474a..f64b5145 100644 --- a/src/nodes/QskArcRenderer.h +++ b/src/nodes/QskArcRenderer.h @@ -8,6 +8,7 @@ #include "QskGlobal.h" +class QskArcBorderMetrics; class QskArcMetrics; class QskGradient; @@ -18,7 +19,7 @@ class QSK_EXPORT QskArcRenderer { public: void renderArc( const QRectF&, const QskArcMetrics&, - const QskGradient&, QPainter* ); + const QskArcBorderMetrics&, const QskGradient&, QPainter* ); }; #endif diff --git a/src/src.pro b/src/src.pro index 84223fe2..387c8b8c 100644 --- a/src/src.pro +++ b/src/src.pro @@ -12,6 +12,7 @@ DEPENDPATH *= $${QSK_SUBDIRS} # DEFINES += QSK_LAYOUT_COMPAT HEADERS += \ + common/QskArcBorderMetrics.h \ common/QskArcMetrics.h \ common/QskAspect.h \ common/QskBoxBorderColors.h \ @@ -39,6 +40,7 @@ HEADERS += \ common/QskTextOptions.h SOURCES += \ + common/QskArcBorderMetrics.cpp \ common/QskArcMetrics.cpp \ common/QskAspect.cpp \ common/QskBoxBorderColors.cpp \