From d5b3fe0dba5f2a2cf85445c998d7b612b665bcac Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Tue, 19 Oct 2021 12:17:37 +0200 Subject: [PATCH] add arc border colors --- src/common/QskArcBorderColors.cpp | 171 ++++++++++++++++++++++++ src/common/QskArcBorderColors.h | 90 +++++++++++++ src/controls/QskSkinHintTableEditor.cpp | 28 ++++ src/controls/QskSkinHintTableEditor.h | 13 ++ src/controls/QskSkinlet.cpp | 11 +- src/controls/QskSkinnable.cpp | 19 +++ src/controls/QskSkinnable.h | 5 + src/nodes/QskArcNode.cpp | 10 +- src/nodes/QskArcNode.h | 5 +- src/nodes/QskArcRenderer.cpp | 12 +- src/nodes/QskArcRenderer.h | 4 +- src/src.pro | 2 + 12 files changed, 357 insertions(+), 13 deletions(-) create mode 100644 src/common/QskArcBorderColors.cpp create mode 100644 src/common/QskArcBorderColors.h diff --git a/src/common/QskArcBorderColors.cpp b/src/common/QskArcBorderColors.cpp new file mode 100644 index 00000000..97dc52c0 --- /dev/null +++ b/src/common/QskArcBorderColors.cpp @@ -0,0 +1,171 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#include "QskArcBorderColors.h" +#include "QskRgbValue.h" + +#include +#include + +static void qskRegisterArcBorderColors() +{ + qRegisterMetaType< QskArcBorderColors >(); + + QMetaType::registerConverter< QColor, QskArcBorderColors >( + []( const QColor& color ) { return QskArcBorderColors( color ); } ); +} + +Q_CONSTRUCTOR_FUNCTION( qskRegisterArcBorderColors ) + +static inline bool qskIsVisble( const QColor& c ) +{ + return c.isValid() && ( c.alpha() > 0 ); +} + +static inline void qskSetColors( const QColor& c, QColor* colors ) +{ + colors[ 0 ] = colors[ 1 ] = c.toRgb(); +} + +static inline void qskSetColors( + const QColor& outer, const QColor& inner, QColor* colors ) +{ + colors[ Qsk::Outer ] = outer.toRgb(); + colors[ Qsk::Inner ] = inner.toRgb(); +} + +QskArcBorderColors::QskArcBorderColors() +{ +} + +QskArcBorderColors::QskArcBorderColors( + const QColor& outer, const QColor& inner ) +{ + qskSetColors( outer, inner, m_colors ); +} + +QskArcBorderColors::QskArcBorderColors( const QColor& color ) +{ + qskSetColors( color, m_colors ); +} + +QskArcBorderColors::~QskArcBorderColors() +{ +} + +bool QskArcBorderColors::operator==( const QskArcBorderColors& other ) const +{ + return ( m_colors[ 0 ] == other.m_colors[ 0 ] ) && + ( m_colors[ 1 ] == other.m_colors[ 1 ] ); +} + +void QskArcBorderColors::setAlpha( int alpha ) +{ + for ( int i = 0; i < 2; i++ ) + { + if ( m_colors[ i ].isValid() && m_colors[ i ].alpha() ) + m_colors[ i ].setAlpha( alpha ); + } +} + +void QskArcBorderColors::setColors( const QColor& color ) +{ + qskSetColors( color, m_colors ); +} + +void QskArcBorderColors::setColors( + const QColor& outer, const QColor& inner ) +{ + qskSetColors( outer, inner, m_colors ); +} + +void QskArcBorderColors::setColor( + Qsk::ArcPosition position, const QColor& color ) +{ + m_colors[ position ] = color.toRgb(); +} + +bool QskArcBorderColors::isVisible() const +{ + if ( qskIsVisble( m_colors[ 0 ] ) ) + return true; + + if ( qskIsVisble( m_colors[ 1 ] ) ) + return true; + + return false; +} + +bool QskArcBorderColors::isMonochrome() const +{ + if ( m_colors[ 1 ] != m_colors[ 0 ] ) + return false; + + return true; +} + +QskArcBorderColors QskArcBorderColors::interpolated( + const QskArcBorderColors& to, qreal ratio ) const +{ + QskArcBorderColors colors; + + for ( size_t i = 0; i < 2; i++ ) + { + colors.m_colors[ i ] = QskRgb::interpolated( + m_colors[ i ], to.m_colors[ i ], ratio ); + } + + return colors; +} + +QVariant QskArcBorderColors::interpolate( + const QskArcBorderColors& from, const QskArcBorderColors& to, qreal ratio ) +{ + return QVariant::fromValue( from.interpolated( to, ratio ) ); +} + +uint QskArcBorderColors::hash( uint seed ) const +{ + const QRgb rgb[] = + { + m_colors[ 0 ].rgba(), + m_colors[ 1 ].rgba(), + }; + + return qHashBits( rgb, sizeof( rgb ), seed ); +} + +#ifndef QT_NO_DEBUG_STREAM + +#include + +static inline void qskDebugColor( QDebug debug, const QColor& c ) +{ + debug << '(' + << c.red() << ',' + << c.green() << ',' + << c.blue() << ',' + << c.alpha() << ')'; +} + +QDebug operator<<( QDebug debug, const QskArcBorderColors& colors ) +{ + QDebugStateSaver saver( debug ); + debug.nospace(); + + debug << "ArcBorderColors" << '('; + + debug << " outer"; + qskDebugColor( debug, colors.color( Qsk::Outer ) ); + + debug << ", inner"; + qskDebugColor( debug, colors.color( Qsk::Inner ) ); + + debug << " )"; + + return debug; +} + +#endif diff --git a/src/common/QskArcBorderColors.h b/src/common/QskArcBorderColors.h new file mode 100644 index 00000000..1ed7ef9c --- /dev/null +++ b/src/common/QskArcBorderColors.h @@ -0,0 +1,90 @@ +/****************************************************************************** + * 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_COLORS_H +#define QSK_ARC_BORDER_COLORS_H + +#include "QskNamespace.h" + +#include +#include + +class QDebug; + +class QSK_EXPORT QskArcBorderColors +{ + public: + QskArcBorderColors(); + + QskArcBorderColors( const QColor& outer, const QColor& inner ); + + QskArcBorderColors( Qt::GlobalColor ); + QskArcBorderColors( QRgb ); + QskArcBorderColors( const QColor& ); + + ~QskArcBorderColors(); + + bool operator==( const QskArcBorderColors& ) const; + bool operator!=( const QskArcBorderColors& ) const; + + void setAlpha( int alpha ); + + void setColors( const QColor& ); + void setColors( const QColor& outer, const QColor& inner ); + + void setColor( Qsk::ArcPosition, const QColor& ); + QColor color( Qsk::ArcPosition ) const; + + QRgb rgb( Qsk::ArcPosition ) const; + + QskArcBorderColors interpolated( const QskArcBorderColors&, qreal value ) const; + + static QVariant interpolate( const QskArcBorderColors&, + const QskArcBorderColors&, qreal ratio ); + + uint hash( uint seed = 0 ) const; + + bool isMonochrome() const; + bool isVisible() const; + + private: + // should be stored as QRgb + QColor m_colors[ 2 ]; +}; + +inline QskArcBorderColors::QskArcBorderColors( Qt::GlobalColor color ) + : QskArcBorderColors( QColor( color ) ) +{ +} + +inline QskArcBorderColors::QskArcBorderColors( QRgb rgb ) + : QskArcBorderColors( QColor::fromRgba( rgb ) ) +{ +} + +inline bool QskArcBorderColors::operator!=( const QskArcBorderColors& other ) const +{ + return !( *this == other ); +} + +inline QColor QskArcBorderColors::color( Qsk::ArcPosition position ) const +{ + return m_colors[ position ]; +} + +inline QRgb QskArcBorderColors::rgb( Qsk::ArcPosition position ) const +{ + return m_colors[ position ].rgba(); +} + +#ifndef QT_NO_DEBUG_STREAM + +QSK_EXPORT QDebug operator<<( QDebug, const QskArcBorderColors& ); + +#endif + +Q_DECLARE_METATYPE( QskArcBorderColors ) + +#endif diff --git a/src/controls/QskSkinHintTableEditor.cpp b/src/controls/QskSkinHintTableEditor.cpp index 414a8af5..5c813792 100644 --- a/src/controls/QskSkinHintTableEditor.cpp +++ b/src/controls/QskSkinHintTableEditor.cpp @@ -6,6 +6,7 @@ #include "QskSkinHintTableEditor.h" #include "QskSkinHintTable.h" +#include "QskArcBorderColors.h" #include "QskArcBorderMetrics.h" #include "QskArcMetrics.h" #include "QskMargins.h" @@ -519,3 +520,30 @@ QskArcBorderMetrics QskSkinHintTableEditor::arcBorderMetrics( QskAspect aspect ) { return metricHint< QskArcBorderMetrics >( aspectBorder( aspect ) ); } + +void QskSkinHintTableEditor::setArcBorderColors( + QskAspect aspect, const QskArcBorderColors& borderColors, + QskStateCombination combination ) +{ + setColorHint( aspectBorder( aspect ), borderColors, combination ); +} + +void QskSkinHintTableEditor::setArcBorderColors( QskAspect aspect, + const QColor& outer, const QColor& inner, + QskStateCombination combination ) +{ + setColorHint( aspectBorder( aspect ), + QskArcBorderColors( outer, inner ), + combination ); +} + +void QskSkinHintTableEditor::removeArcBorderColors( + QskAspect aspect, QskStateCombination combination ) +{ + return removeColorHint( aspectBorder( aspect ), combination ); +} + +QskArcBorderColors QskSkinHintTableEditor::arcBorderColors( QskAspect aspect ) const +{ + return colorHint< QskArcBorderColors >( aspectBorder( aspect ) ); +} diff --git a/src/controls/QskSkinHintTableEditor.h b/src/controls/QskSkinHintTableEditor.h index 2161a83e..c361c4c0 100644 --- a/src/controls/QskSkinHintTableEditor.h +++ b/src/controls/QskSkinHintTableEditor.h @@ -14,6 +14,7 @@ #include #include +class QskArcBorderColors; class QskArcBorderMetrics; class QskArcMetrics; class QskMargins; @@ -245,6 +246,18 @@ class QSK_EXPORT QskSkinHintTableEditor QskArcBorderMetrics arcBorderMetrics( QskAspect ) const; + // arcBorderColors + + void setArcBorderColors( QskAspect, + const QskArcBorderColors&, QskStateCombination = QskStateCombination() ); + + void setArcBorderColors( QskAspect, + const QColor&, const QColor&, + QskStateCombination = QskStateCombination() ); + + void removeArcBorderColors( QskAspect, QskStateCombination = QskStateCombination() ); + QskArcBorderColors arcBorderColors( QskAspect ) const; + private: QskSkinHintTable* m_table = nullptr; }; diff --git a/src/controls/QskSkinlet.cpp b/src/controls/QskSkinlet.cpp index 4b7742a4..eb4110f0 100644 --- a/src/controls/QskSkinlet.cpp +++ b/src/controls/QskSkinlet.cpp @@ -89,10 +89,10 @@ static inline bool qskIsBoxVisible( const QskBoxBorderMetrics& borderMetrics, static inline bool qskIsArcVisible( const QskArcMetrics& arcMetrics, const QskArcBorderMetrics& borderMetrics, - const QskGradient& gradient ) + const QskArcBorderColors& borderColors, const QskGradient& gradient ) { return ( !arcMetrics.isNull() && gradient.isVisible() ) - || !borderMetrics.isNull(); + || ( !borderMetrics.isNull() && borderColors.isVisible() ); } static inline QskTextColors qskTextColors( @@ -365,7 +365,10 @@ QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable, auto arcBorderMetrics = skinnable->arcBorderMetricsHint( subControl ); arcBorderMetrics = arcBorderMetrics.toAbsolute( arcRect.size() ); - if ( !qskIsArcVisible( arcMetrics, arcBorderMetrics, fillGradient ) ) + const auto arcBorderColors = skinnable->arcBorderColorsHint( subControl ); + + if ( !qskIsArcVisible( arcMetrics, arcBorderMetrics, arcBorderColors, + fillGradient ) ) return nullptr; auto arcNode = static_cast< QskArcNode* >( node ); @@ -374,7 +377,7 @@ QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable, arcNode = new QskArcNode(); arcNode->setArcData( rect, absoluteArcMetrics, arcBorderMetrics, - fillGradient, control->window() ); + arcBorderColors, fillGradient, control->window() ); return arcNode; } diff --git a/src/controls/QskSkinnable.cpp b/src/controls/QskSkinnable.cpp index 6b118246..60635df3 100644 --- a/src/controls/QskSkinnable.cpp +++ b/src/controls/QskSkinnable.cpp @@ -6,6 +6,7 @@ #include "QskSkinnable.h" #include "QskAnimationHint.h" +#include "QskArcBorderColors.h" #include "QskArcBorderMetrics.h" #include "QskArcMetrics.h" #include "QskAspect.h" @@ -559,6 +560,24 @@ QskArcBorderMetrics QskSkinnable::arcBorderMetricsHint( this, aspect | QskAspect::Border, status ); } +bool QskSkinnable::setArcBorderColorsHint( + const QskAspect aspect, const QskArcBorderColors& colors ) +{ + return qskSetColor( this, aspect | QskAspect::Border, colors ); +} + +bool QskSkinnable::resetArcBorderColorsHint( const QskAspect aspect ) +{ + return resetColor( aspect | QskAspect::Border ); +} + +QskArcBorderColors QskSkinnable::arcBorderColorsHint( + const QskAspect aspect, QskSkinHintStatus* status ) const +{ + return qskColor< QskArcBorderColors >( + 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 02c04772..dbb0984b 100644 --- a/src/controls/QskSkinnable.h +++ b/src/controls/QskSkinnable.h @@ -21,6 +21,7 @@ class QDebug; class QSGNode; +class QskArcBorderColors; class QskArcBorderMetrics; class QskArcMetrics; class QskControl; @@ -199,6 +200,10 @@ class QSK_EXPORT QskSkinnable bool resetArcBorderMetricsHint( QskAspect ); QskArcBorderMetrics arcBorderMetricsHint( QskAspect, QskSkinHintStatus* = nullptr ) const; + bool setArcBorderColorsHint( QskAspect, const QskArcBorderColors& ); + bool resetArcBorderColorsHint( QskAspect ); + QskArcBorderColors arcBorderColorsHint( 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 ada200b9..c8e3c199 100644 --- a/src/nodes/QskArcNode.cpp +++ b/src/nodes/QskArcNode.cpp @@ -15,11 +15,13 @@ QskArcNode::~QskArcNode() } void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& metrics, - const QskArcBorderMetrics& borderMetrics, const QskGradient &gradient, + const QskArcBorderMetrics& borderMetrics, + const QskArcBorderColors& borderColors, const QskGradient &gradient, QQuickWindow* window ) { m_metrics = metrics; m_borderMetrics = borderMetrics; + m_borderColors = borderColors; m_gradient = gradient; if ( rect.isEmpty() ) @@ -37,8 +39,7 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& metrics, effect - even if not being visible. TODO ... */ - // ### implement border colors -// hasBorder = borderColors.isVisible(); + hasBorder = borderColors.isVisible(); } if ( !hasBorder && !hasFill ) @@ -56,7 +57,8 @@ void QskArcNode::paint( QPainter* painter, const QSizeF &size ) QskArcRenderer renderer; - renderer.renderArc( rect, m_metrics, m_borderMetrics, m_gradient, painter ); + renderer.renderArc( rect, m_metrics, m_borderMetrics, m_borderColors, + m_gradient, painter ); } uint QskArcNode::hash() const diff --git a/src/nodes/QskArcNode.h b/src/nodes/QskArcNode.h index aca74184..6b00d79b 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 "QskArcBorderColors.h" #include "QskArcBorderMetrics.h" #include "QskArcMetrics.h" #include "QskGradient.h" @@ -18,7 +19,8 @@ class QSK_EXPORT QskArcNode : public QskPaintedNode ~QskArcNode() override; void setArcData( const QRectF&, const QskArcMetrics&, - const QskArcBorderMetrics&, const QskGradient&, QQuickWindow* ); + const QskArcBorderMetrics&, const QskArcBorderColors&, + const QskGradient&, QQuickWindow* ); void paint( QPainter* painter, const QSizeF& size ) override; uint hash() const override; @@ -26,6 +28,7 @@ class QSK_EXPORT QskArcNode : public QskPaintedNode private: QskArcMetrics m_metrics; QskArcBorderMetrics m_borderMetrics; + QskArcBorderColors m_borderColors; QskGradient m_gradient; }; diff --git a/src/nodes/QskArcRenderer.cpp b/src/nodes/QskArcRenderer.cpp index 3684b77e..6fc656c1 100644 --- a/src/nodes/QskArcRenderer.cpp +++ b/src/nodes/QskArcRenderer.cpp @@ -5,6 +5,7 @@ #include "QskArcRenderer.h" +#include "QskArcBorderColors.h" #include "QskArcBorderMetrics.h" #include "QskArcMetrics.h" #include "QskGradient.h" @@ -14,7 +15,8 @@ void QskArcRenderer::renderArc( const QRectF& rect, const QskArcMetrics& metrics, const QskArcBorderMetrics &borderMetrics, - const QskGradient& gradient, QPainter* painter ) + const QskArcBorderColors& borderColors, const QskGradient& gradient, + QPainter* painter ) { painter->setRenderHint( QPainter::Antialiasing, true ); @@ -56,7 +58,9 @@ void QskArcRenderer::renderArc( const QRectF& rect, // 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 ), + const QColor innerColor = borderColors.color( Qsk::Inner ); + + painter->setPen( QPen( innerColor, borderMetrics.width( Qsk::Inner ), Qt::SolidLine, Qt::FlatCap ) ); painter->drawArc( innerRect, metrics.startAngle(), metrics.spanAngle() ); } @@ -66,7 +70,9 @@ void QskArcRenderer::renderArc( const QRectF& rect, // 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 ), + const QColor outerColor = borderColors.color( Qsk::Outer ); + + painter->setPen( QPen( outerColor, 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 f64b5145..e26bf7a9 100644 --- a/src/nodes/QskArcRenderer.h +++ b/src/nodes/QskArcRenderer.h @@ -8,6 +8,7 @@ #include "QskGlobal.h" +class QskArcBorderColors; class QskArcBorderMetrics; class QskArcMetrics; class QskGradient; @@ -19,7 +20,8 @@ class QSK_EXPORT QskArcRenderer { public: void renderArc( const QRectF&, const QskArcMetrics&, - const QskArcBorderMetrics&, const QskGradient&, QPainter* ); + const QskArcBorderMetrics&, const QskArcBorderColors&, + const QskGradient&, QPainter* ); }; #endif diff --git a/src/src.pro b/src/src.pro index 387c8b8c..fc71466a 100644 --- a/src/src.pro +++ b/src/src.pro @@ -12,6 +12,7 @@ DEPENDPATH *= $${QSK_SUBDIRS} # DEFINES += QSK_LAYOUT_COMPAT HEADERS += \ + common/QskArcBorderColors.h \ common/QskArcBorderMetrics.h \ common/QskArcMetrics.h \ common/QskAspect.h \ @@ -40,6 +41,7 @@ HEADERS += \ common/QskTextOptions.h SOURCES += \ + common/QskArcBorderColors.cpp \ common/QskArcBorderMetrics.cpp \ common/QskArcMetrics.cpp \ common/QskAspect.cpp \