From ff9e9ab63cc9bd8519407624410422c2f0898d9c Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Mon, 28 Aug 2017 17:42:11 +0200 Subject: [PATCH] starting to configure box subcontrols/nodes with QskBoxColors/QskBorderMetrics --- src/common/QskBorderMetrics.cpp | 167 ++++++++++++++++ src/common/QskBorderMetrics.h | 183 +++++++++++++++++ src/common/QskBoxColors.cpp | 295 ++++++++++++++++++++++++++++ src/common/QskBoxColors.h | 72 +++++++ src/common/QskBoxOptions.cpp | 92 ++------- src/common/QskBoxOptions.h | 54 +---- src/controls/QskRgbValue.cpp | 68 ++++++- src/controls/QskRgbValue.h | 1 + src/controls/QskSkinRenderer.cpp | 39 ++-- src/controls/QskVariantAnimator.cpp | 4 + src/nodes/QskBoxMaterial.cpp | 36 ++-- src/nodes/QskBoxMaterial.h | 2 +- src/nodes/QskBoxMaterialVM.cpp | 37 ++-- src/nodes/QskBoxMaterialVM.h | 2 +- src/nodes/QskBoxNode.cpp | 80 +++++--- src/src.pro | 4 + 16 files changed, 931 insertions(+), 205 deletions(-) create mode 100644 src/common/QskBorderMetrics.cpp create mode 100644 src/common/QskBorderMetrics.h create mode 100644 src/common/QskBoxColors.cpp create mode 100644 src/common/QskBoxColors.h diff --git a/src/common/QskBorderMetrics.cpp b/src/common/QskBorderMetrics.cpp new file mode 100644 index 00000000..228cf8d8 --- /dev/null +++ b/src/common/QskBorderMetrics.cpp @@ -0,0 +1,167 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#include "QskBorderMetrics.h" + +#include + +static void qskRegisterBorderMetrics() +{ + qRegisterMetaType< QskBorderMetrics >(); +} + +Q_CONSTRUCTOR_FUNCTION( qskRegisterBorderMetrics ) + +static inline QSizeF qskInterpolatedSize( + const QSizeF& from, const QSizeF& to, qreal ratio ) +{ + return from + ( to - from ) * ratio; +} + +QskBorderMetrics::QskBorderMetrics( qreal width, qreal radiusX, qreal radiusY ): + m_widths( ( width >= 0.0 ) ? width : 0.0 ), + m_widthIsRelative( false ), + m_radiusIsRelative( false ) +{ + setRadius( radiusX, radiusY ); +} + +QskBorderMetrics::~QskBorderMetrics() +{ +} + +bool QskBorderMetrics::operator==( const QskBorderMetrics& other ) const +{ + if ( m_widthIsRelative != other.m_widthIsRelative ) + return false; + + if ( m_radiusIsRelative != other.m_radiusIsRelative ) + return false; + + if ( m_widths != other.m_widths ) + return false; + + for ( size_t i = 0; i < 4; i++ ) + { + if ( m_radii[i] != other.m_radii[i] ) + return false; + } + + return true; +} + +void QskBorderMetrics::setWidthSizeMode( Qt::SizeMode sizeMode ) +{ + m_widthIsRelative = ( sizeMode == Qt::RelativeSize ); +} + +void QskBorderMetrics::setWidths( const QskMargins& widths ) +{ + m_widths = widths; +} + +void QskBorderMetrics::setWidthAt( Qt::Edges edges, qreal width ) +{ + m_widths.setMarginsAt( edges, width ); +} + +void QskBorderMetrics::setRadiusSizeMode( Qt::SizeMode sizeMode ) +{ + m_radiusIsRelative = ( sizeMode == Qt::RelativeSize ); +} + +void QskBorderMetrics::setRadius( + qreal topLeftX, qreal topLeftY, qreal topRightX, qreal topRightY, + qreal bottomLeftX, qreal bottomLeftY, qreal bottomRightX, qreal bottomRightY ) +{ + m_radii[ Qt::TopLeftCorner ].setWidth( qMax( topLeftX, 0.0 ) ); + m_radii[ Qt::TopLeftCorner ].setHeight( qMax( topLeftY, 0.0 ) ); + + m_radii[ Qt::TopRightCorner ].setWidth( qMax( topRightX, 0.0 ) ); + m_radii[ Qt::TopRightCorner ].setHeight( qMax( topRightY, 0.0 ) ); + + m_radii[ Qt::BottomLeftCorner ].setWidth( qMax( bottomLeftX, 0.0 ) ); + m_radii[ Qt::BottomLeftCorner ].setHeight( qMax( bottomLeftY, 0.0 ) ); + + m_radii[ Qt::BottomRightCorner ].setWidth( qMax( bottomRightX, 0.0 ) ); + m_radii[ Qt::BottomRightCorner ].setHeight( qMax( bottomRightY, 0.0 ) ); +} + +void QskBorderMetrics::setRadius( Qt::Corner corner, qreal radiusX, qreal radiusY ) +{ + if ( ( corner >= Qt::TopLeftCorner ) && ( corner <= Qt::BottomRightCorner ) ) + { + m_radii[ corner ].setWidth( qMax( radiusX, 0.0 ) ); + m_radii[ corner ].setHeight( qMax( radiusY, 0.0 ) ); + } +} + +QskBorderMetrics QskBorderMetrics::interpolated( + const QskBorderMetrics& to, qreal ratio ) const +{ + if ( *this == to ) + return to; + + if ( ( m_widthIsRelative != to.m_widthIsRelative ) + && ( m_radiusIsRelative != to.m_radiusIsRelative ) ) + { + return to; + } + + QskMargins widths( to.m_widths ); + if ( m_widthIsRelative == to.m_widthIsRelative ) + { + widths = m_widths.interpolated( to.m_widths, ratio ); + } + + if ( m_radiusIsRelative == to.m_radiusIsRelative ) + { + QSizeF radii[4]; + radii[0] = qskInterpolatedSize( m_radii[0], to.m_radii[0], ratio ); + radii[1] = qskInterpolatedSize( m_radii[1], to.m_radii[1], ratio ); + radii[2] = qskInterpolatedSize( m_radii[2], to.m_radii[2], ratio ); + radii[3] = qskInterpolatedSize( m_radii[3], to.m_radii[3], ratio ); + + return QskBorderMetrics( to.m_widthIsRelative, widths, + to.m_radiusIsRelative, radii ); + } + else + { + return QskBorderMetrics( to.m_widthIsRelative, widths, + to.m_radiusIsRelative, to.m_radii ); + } +} + +QVariant QskBorderMetrics::interpolate( const QskBorderMetrics& from, + const QskBorderMetrics& to, qreal progress ) +{ + return QVariant::fromValue( from.interpolated( to, progress ) ); +} + +#ifndef QT_NO_DEBUG_STREAM + +QDebug operator<<( QDebug debug, const QskBorderMetrics& metrics ) +{ + QDebugStateSaver saver( debug ); + debug.nospace(); + + debug << "BorderMetrics" << '('; + debug << metrics.widthSizeMode() << metrics.widths(); + + debug << metrics.radiusSizeMode(); + + for ( int i = Qt::TopLeftCorner; i <= Qt::BottomRightCorner; i++ ) + { + const QSizeF r = metrics.radius( static_cast< Qt::Corner >( i ) ); + debug << "(" << r.width() << r.height() << ")"; + } + + debug << ')'; + + return debug; +} + +#endif + diff --git a/src/common/QskBorderMetrics.h b/src/common/QskBorderMetrics.h new file mode 100644 index 00000000..a6c9dce5 --- /dev/null +++ b/src/common/QskBorderMetrics.h @@ -0,0 +1,183 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#ifndef QSK_BORDER_METRICS_H +#define QSK_BORDER_HINTS_H + +#include "QskGlobal.h" +#include "QskMargins.h" + +#include +#include +#include + +class QDebug; +class QVariant; + +class QSK_EXPORT QskBorderMetrics +{ +public: + QskBorderMetrics(); + QskBorderMetrics( qreal width, qreal radius = 0.0 ); + QskBorderMetrics( qreal width, qreal radiusX, qreal radiusY ); + + ~QskBorderMetrics(); + + bool operator==( const QskBorderMetrics& ) const; + bool operator!=( const QskBorderMetrics& ) const; + + void setRadius( qreal radius ); + void setRadius( qreal radius, Qt::SizeMode ); + void setRadius( Qt::Corner, qreal radius ); + + void setRadius( qreal radiusX, qreal radiusY ); + void setRadius( const QSizeF& ); + void setRadius( Qt::Corner, qreal radiusX, qreal radiusY ); + void setRadius( Qt::Corner, const QSizeF& radius ); + + void setRadius( qreal topLeft, qreal topRight, + qreal bottomLeft, qreal bottomRight ); + + void setRadius( const QSizeF& topLeft, const QSizeF& topRight, + const QSizeF& bottomLeft, const QSizeF& bottomRight ); + + void setRadius( + qreal topLeftX, qreal topLeftY, + qreal topRightX, qreal topRightY, + qreal bottomLeftX, qreal bottomLeftY, + qreal bottomRightX, qreal bottomRightY ); + + QSizeF radius( Qt::Corner ) const; + + void setRadiusSizeMode( Qt::SizeMode ); + Qt::SizeMode radiusSizeMode() const; + + void setWidthAt( Qt::Edges, qreal width ); + qreal widthAt( Qt::Edge ) const; + + void setWidths( const QskMargins& ); + const QskMargins& widths() const; + + void setWidthSizeMode( Qt::SizeMode ); + Qt::SizeMode widthSizeMode() const; + + QskBorderMetrics interpolated( const QskBorderMetrics&, qreal value ) const; + + static QVariant interpolate( const QskBorderMetrics&, + const QskBorderMetrics&, qreal progress ); + +private: + QskBorderMetrics( bool widthIsRelative, const QskMargins& widths, + bool radiusIsRelative, const QSizeF radii[4] ): + m_widths( widths ), + m_radii( { radii[0], radii[1], radii[2], radii[3] } ), + m_widthIsRelative( widthIsRelative ), + m_radiusIsRelative( radiusIsRelative ) + { + } + + QskMargins m_widths; + QSizeF m_radii[ 4 ]; + + bool m_widthIsRelative; + bool m_radiusIsRelative; +}; + +inline QskBorderMetrics::QskBorderMetrics(): + m_widthIsRelative( false ), + m_radiusIsRelative( false ) +{ +} + +inline QskBorderMetrics::QskBorderMetrics( qreal width, qreal radius ): + QskBorderMetrics( width, radius, radius ) +{ +} + +inline bool QskBorderMetrics::operator!=( const QskBorderMetrics& other ) const +{ + return !( *this == other ); +} + +inline void QskBorderMetrics::setRadius( qreal radius ) +{ + setRadius( radius, radius ); +} + +inline void QskBorderMetrics::setRadius( qreal radius, Qt::SizeMode sizeMode ) +{ + setRadius( radius ); + setRadiusSizeMode( sizeMode ); +} + +inline void QskBorderMetrics::setRadius( qreal radiusX, qreal radiusY ) +{ + setRadius( radiusX, radiusY, radiusX, radiusY, + radiusX, radiusY, radiusX, radiusY ); +} + +inline void QskBorderMetrics::setRadius( const QSizeF& radius ) +{ + setRadius( radius.width(), radius.height() ); +} + +inline void QskBorderMetrics::setRadius( Qt::Corner corner, qreal radius ) +{ + setRadius( corner, radius, radius ); +} + +inline void QskBorderMetrics::setRadius( Qt::Corner corner, const QSizeF& radius ) +{ + setRadius( corner, radius.width(), radius.height() ); +} + +inline void QskBorderMetrics::setRadius( + const QSizeF& topLeft, const QSizeF& topRight, + const QSizeF& bottomLeft, const QSizeF& bottomRight ) +{ + setRadius( topLeft.width(), topLeft.height(), + topRight.width(), topRight.height(), + bottomLeft.width(), bottomLeft.height(), + bottomRight.width(), bottomRight.height() ); +} + +inline QSizeF QskBorderMetrics::radius( Qt::Corner corner ) const +{ + if ( ( corner >= Qt::TopLeftCorner ) && ( corner <= Qt::BottomRightCorner ) ) + return m_radii[ corner ]; + + return QSizeF(); +} + +inline Qt::SizeMode QskBorderMetrics::radiusSizeMode() const +{ + return m_radiusIsRelative ? Qt::RelativeSize : Qt::AbsoluteSize; +} + +inline const QskMargins& QskBorderMetrics::widths() const +{ + return m_widths; +} + +inline qreal QskBorderMetrics::widthAt( Qt::Edge edge ) const +{ + return m_widths.marginAt( edge ); +} + +inline Qt::SizeMode QskBorderMetrics::widthSizeMode() const +{ + return m_widthIsRelative ? Qt::RelativeSize : Qt::AbsoluteSize; +} + +#ifndef QT_NO_DEBUG_STREAM + +QSK_EXPORT QDebug operator<<( QDebug, const QskBorderMetrics& ); + +#endif + +Q_DECLARE_TYPEINFO( QskBorderMetrics, Q_MOVABLE_TYPE ); +Q_DECLARE_METATYPE( QskBorderMetrics ) + +#endif diff --git a/src/common/QskBoxColors.cpp b/src/common/QskBoxColors.cpp new file mode 100644 index 00000000..9a136df3 --- /dev/null +++ b/src/common/QskBoxColors.cpp @@ -0,0 +1,295 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#include "QskBoxColors.h" +#include "QskRgbValue.h" +#include "QskNamespace.h" + +#include + +static void qskRegisterBoxColors() +{ + qRegisterMetaType< QskBoxColors >(); +} + +Q_CONSTRUCTOR_FUNCTION( qskRegisterBoxColors ) + +static inline void qskMirrorEdges( + Qt::Orientations orientations, const QColor* from, QColor* to ) +{ + if ( orientations == Qt::Vertical ) + { + to[ Qt::TopLeftCorner ] = from[ Qt::BottomLeftCorner ]; + to[ Qt::BottomLeftCorner ] = from[ Qt::TopLeftCorner ]; + to[ Qt::TopRightCorner ] = from[ Qt::BottomRightCorner ]; + to[ Qt::BottomRightCorner ] = from[ Qt::TopRightCorner ]; + } + else if ( orientations == Qt::Horizontal ) + { + to[ Qt::TopLeftCorner ] = from[ Qt::TopRightCorner ]; + to[ Qt::BottomLeftCorner ] = from[ Qt::BottomRightCorner ]; + to[ Qt::TopRightCorner ] = from[ Qt::TopLeftCorner ]; + to[ Qt::BottomRightCorner ] = from[ Qt::BottomLeftCorner ]; + } + else if ( orientations == ( Qt::Vertical | Qt::Horizontal ) ) + { + to[ Qt::TopLeftCorner ] = from[ Qt::BottomRightCorner ]; + to[ Qt::BottomLeftCorner ] = from[ Qt::TopRightCorner ]; + to[ Qt::TopRightCorner ] = from[ Qt::BottomLeftCorner ]; + to[ Qt::BottomRightCorner ] = from[ Qt::TopLeftCorner ]; + } + else + { + to[ Qt::TopLeftCorner ] = from[ Qt::TopLeftCorner ]; + to[ Qt::BottomLeftCorner ] = from[ Qt::BottomLeftCorner ]; + to[ Qt::TopRightCorner ] = from[ Qt::TopRightCorner ]; + to[ Qt::BottomRightCorner ] = from[ Qt::BottomRightCorner ]; + } +} + +QskBoxColors::QskBoxColors() +{ +} + +QskBoxColors::QskBoxColors( const QColor& border, const QColor& fill ) +{ + setBorderColor( border ); + setFillColor( fill ); +} + +QskBoxColors::~QskBoxColors() +{ +} + +bool QskBoxColors::operator==( const QskBoxColors& other ) const +{ + for ( size_t i = 0; i < 4; i++ ) + { + if ( ( m_border[i] != other.m_border[i] ) + || ( m_fill[i] != other.m_fill[i] ) ) + { + return false; + } + } + + return true; +} + +void QskBoxColors::setBorderColor( const QColor& color ) +{ + m_border[ 0 ] = m_border[ 1 ] = m_border[ 2 ] = m_border[ 3 ] = color.toRgb(); +} + +void QskBoxColors::setBorderColor( const QColor& left, const QColor& top, + const QColor& right, const QColor& bottom ) +{ + m_border[ Qsk::Left ] = left.toRgb(); + m_border[ Qsk::Top ] = top.toRgb(); + m_border[ Qsk::Right ] = right.toRgb(); + m_border[ Qsk::Bottom ] = bottom.toRgb(); +} + +void QskBoxColors::setBorderColor( Qt::Edges edges, const QColor& color ) +{ + const QColor c = color.toRgb(); + + if ( edges & Qt::TopEdge ) + m_border[ Qsk::Top ] = c; + + if ( edges & Qt::LeftEdge ) + m_border[ Qsk::Left ] = c; + + if ( edges & Qt::RightEdge ) + m_border[ Qsk::Right ] = c; + + if ( edges & Qt::BottomEdge ) + m_border[ Qsk::Bottom ] = c; +} + +QColor QskBoxColors::borderColor( Qt::Edge edge ) const +{ + switch( edge ) + { + case Qt::TopEdge: + return m_border[ Qsk::Top ]; + + case Qt::LeftEdge: + return m_border[ Qsk::Left ]; + + case Qt::RightEdge: + return m_border[ Qsk::Right ]; + + case Qt::BottomEdge: + return m_border[ Qsk::Bottom ]; + } + + return QColor(); +} + +void QskBoxColors::setFillColor( const QColor& color ) +{ + m_fill[ 0 ] = m_fill[ 1 ] = m_fill[ 2 ] = m_fill[ 3 ] = color.toRgb(); +} + +void QskBoxColors::setFillColor( + const QColor& topLeft, const QColor& topRight, + const QColor& bottomLeft, const QColor& bottomRight ) +{ + m_fill[ Qt::TopLeftCorner ] = topLeft.toRgb(); + m_fill[ Qt::TopRightCorner ] = topRight.toRgb(); + m_fill[ Qt::BottomLeftCorner ] = bottomLeft.toRgb(); + m_fill[ Qt::BottomRightCorner ] = bottomRight.toRgb(); +} + +void QskBoxColors::setFillColor( Qt::Corner corner, const QColor& color ) +{ + if ( corner >= 0 && corner < 4 ) + m_fill[ corner ] = color.toRgb(); +} + +void QskBoxColors::setFillColor( Qt::Edge edge, const QColor& color ) +{ + switch( edge ) + { + case Qt::TopEdge: + { + m_fill[ Qt::TopLeftCorner ] = color; + m_fill[ Qt::TopRightCorner ] = color; + + break; + } + case Qt::LeftEdge: + { + m_fill[ Qt::TopLeftCorner ] = color; + m_fill[ Qt::BottomLeftCorner ] = color; + + break; + } + case Qt::RightEdge: + { + m_fill[ Qt::TopRightCorner ] = color; + m_fill[ Qt::BottomRightCorner ] = color; + + break; + } + case Qt::BottomEdge: + { + m_fill[ Qt::BottomLeftCorner ] = color; + m_fill[ Qt::BottomRightCorner ] = color; + + break; + } + } +} + +QColor QskBoxColors::fillColor( Qt::Corner corner ) const +{ + if ( corner >= 0 && corner < 4 ) + return m_fill[ corner ]; + + return QColor(); +} + +QskBoxColors QskBoxColors::shaded( uint alpha ) const +{ + QskBoxColors colors = *this; + + for ( int i = 0; i < 4; i++ ) + { + colors.m_border[i].setAlpha( alpha ); + colors.m_fill[i].setAlpha( alpha ); + } + + return colors; +} + +QskBoxColors QskBoxColors::mirrored( Qt::Orientations orientations ) const +{ + if ( orientations == 0 ) + return *this; + + QskBoxColors c; + qskMirrorEdges( orientations, m_border, c.m_border ); + qskMirrorEdges( orientations, m_fill, c.m_fill ); + + return c; +} + +QskBoxColors QskBoxColors::interpolated( const QskBoxColors& to, qreal ratio ) const +{ + QskBoxColors colors; + + for ( size_t i = 0; i < 4; i++ ) + { + colors.m_border[i] = QskRgbValue::interpolated( m_border[i], to.m_border[i], ratio ); + colors.m_fill[i] = QskRgbValue::interpolated( m_fill[i], to.m_fill[i], ratio ); + } + + return colors; +} + +QVariant QskBoxColors::interpolate( + const QskBoxColors& from, const QskBoxColors& to, qreal ratio ) +{ + return QVariant::fromValue( from.interpolated( to, ratio ) ); +} + +#ifndef QT_NO_DEBUG_STREAM + +static inline void qskDebugColor( QDebug debug, const QColor& c ) +{ + debug << '(' + << c.red() << ',' + << c.green() << ',' + << c.blue() << ',' + << c.alpha() << ')'; +} + +QDebug operator<<( QDebug debug, const QskBoxColors& colors ) +{ + QDebugStateSaver saver( debug ); + debug.nospace(); + + debug << "BoxColors" << '('; + + debug << "\n Border" << '('; + + debug << " L"; + qskDebugColor( debug, colors.borderColor( Qt::LeftEdge ) ); + + debug << ", T"; + qskDebugColor( debug, colors.borderColor( Qt::TopEdge ) ); + + debug << ", R"; + qskDebugColor( debug, colors.borderColor( Qt::RightEdge ) ); + + debug << ", B"; + qskDebugColor( debug, colors.borderColor( Qt::BottomEdge ) ); + + debug << " )"; + + debug << "\n Fill" << '('; + + debug << " TL"; + qskDebugColor( debug, colors.fillColor( Qt::TopLeftCorner ) ); + + debug << ", TR"; + qskDebugColor( debug, colors.fillColor( Qt::TopRightCorner ) ); + + debug << ", BL"; + qskDebugColor( debug, colors.fillColor( Qt::BottomLeftCorner ) ); + + debug << ", BR"; + qskDebugColor( debug, colors.fillColor( Qt::BottomRightCorner ) ); + + debug << " )"; + + debug << "\n)"; + + return debug; +} + +#endif + diff --git a/src/common/QskBoxColors.h b/src/common/QskBoxColors.h new file mode 100644 index 00000000..0fa5cbeb --- /dev/null +++ b/src/common/QskBoxColors.h @@ -0,0 +1,72 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#ifndef QSK_BOX_COLORS_H +#define QSK_BOX_COLORS_H + +#include "QskGlobal.h" + +#include +#include +#include +#include + +class QDebug; + +class QSK_EXPORT QskBoxColors +{ +public: + QskBoxColors(); + QskBoxColors( const QColor& border, const QColor& fill ); + + ~QskBoxColors(); + + bool operator==( const QskBoxColors& ) const; + bool operator!=( const QskBoxColors& ) const; + + void setBorderColor( const QColor& ); + void setBorderColor( Qt::Edges, const QColor& ); + + void setBorderColor( const QColor& left, const QColor& top, + const QColor& right, const QColor& bottom ); + + QColor borderColor( Qt::Edge ) const; + + // will be a QskGradient later + void setFillColor( const QColor& ); + void setFillColor( Qt::Corner, const QColor& ); + void setFillColor( Qt::Edge, const QColor& ); + + void setFillColor( const QColor& topLeft, const QColor& topRight, + const QColor& bottomLeft, const QColor& bottomRight ); + + QColor fillColor( Qt::Corner ) const; + + QskBoxColors interpolated( const QskBoxColors&, qreal value ) const; + QskBoxColors mirrored( Qt::Orientations ) const; + QskBoxColors shaded( uint alpha ) const; + + static QVariant interpolate( const QskBoxColors&, + const QskBoxColors&, qreal ratio ); + +private: + QColor m_border[ 4 ]; + QColor m_fill[ 4 ]; // should be QskGradient later +}; + +inline bool QskBoxColors::operator!=( const QskBoxColors& other ) const +{ + return !( *this == other ); +} + +#ifndef QT_NO_DEBUG_STREAM + +QSK_EXPORT QDebug operator<<( QDebug, const QskBoxColors& ); + +#endif + +Q_DECLARE_METATYPE( QskBoxColors ) + +#endif diff --git a/src/common/QskBoxOptions.cpp b/src/common/QskBoxOptions.cpp index 458eee58..985b2e4e 100644 --- a/src/common/QskBoxOptions.cpp +++ b/src/common/QskBoxOptions.cpp @@ -4,85 +4,30 @@ *****************************************************************************/ #include "QskBoxOptions.h" -#include -QskBoxOptions::QskBoxOptions(): - radius( { 0, 0, 0, 0, 0, 0, 0, 0 } ), - color( { 0, 0, 0, 0, 0, 0, 0, 0 } ) +static inline bool qskIsVisible( const QColor& color ) { + return color.isValid() && color.alpha() > 0; } -uint QskBoxOptions::metricsHash( uint seed ) const +QskBoxOptions::QskBoxOptions() { - return qHashBits( this, 2 * sizeof( QMarginsF ) + 8 * sizeof( qreal ), seed ); -} - -uint QskBoxOptions::colorsHash( uint seed ) const -{ - return qHashBits( &color, 8 * sizeof( QRgb ), seed ); -} - -void QskBoxOptions::setBorder( qreal width ) -{ - borders = QMarginsF( width, width, width, width ); -} - -void QskBoxOptions::setBorder( qreal left, qreal top, qreal right, qreal bottom ) -{ - borders = QMarginsF( left, top, right, bottom ); -} - -void QskBoxOptions::setRadius( qreal radius ) -{ - this->radius = { radius, radius, radius, radius, radius, radius, radius, radius }; -} - -void QskBoxOptions::setBorderRgb( QRgb rgb ) -{ - color.borderLeft = color.borderTop = - color.borderRight = color.borderBottom = rgb; -} - -void QskBoxOptions::setBorderRgb( QRgb rgbLeft, QRgb rgbTop, - QRgb rgbRight, QRgb rgbBottom ) -{ - color.borderLeft = rgbLeft; - color.borderTop = rgbTop; - color.borderRight = rgbRight; - color.borderBottom = rgbBottom; -} - -void QskBoxOptions::setFillRgb( QRgb rgb ) -{ - color.fillTopLeft = color.fillTopRight = - color.fillBottomRight = color.fillBottomLeft = rgb; -} - -void QskBoxOptions::setFillRgb( QRgb rgbTopLeft, QRgb rgbTopRight, - QRgb rgbBottomRight, QRgb rgbBottomLeft ) -{ - color.fillTopLeft = rgbTopLeft; - color.fillTopRight = rgbTopRight; - color.fillBottomRight = rgbBottomRight; - color.fillBottomLeft = rgbBottomLeft; } bool QskBoxOptions::isVisible() const { - if ( qAlpha( color.fillTopLeft ) || - qAlpha( color.fillTopRight ) || - qAlpha( color.fillBottomRight ) || - qAlpha( color.fillBottomLeft ) ) + if ( qskIsVisible( colors.fillColor( Qt::TopLeftCorner ) ) + || qskIsVisible( colors.fillColor( Qt::TopRightCorner ) ) + || qskIsVisible( colors.fillColor( Qt::BottomLeftCorner ) ) + || qskIsVisible( colors.fillColor( Qt::BottomRightCorner ) ) ) { return true; } - if ( ( borders.left() && qAlpha( color.borderLeft ) ) || - ( borders.top() && qAlpha( color.borderTop ) ) || - ( borders.right() && qAlpha( color.borderRight ) ) || - ( borders.bottom() && qAlpha( color.borderBottom ) ) ) + for ( auto edge : { Qt::LeftEdge, Qt::TopEdge, Qt::RightEdge, Qt::BottomEdge } ) { - return true; + if ( metrics.widthAt( edge ) && qskIsVisible( colors.borderColor( edge ) ) ) + return true; } return false; @@ -90,13 +35,16 @@ bool QskBoxOptions::isVisible() const QMarginsF QskBoxOptions::padding() const { - const qreal left = std::max( radius.topLeftX, radius.bottomLeftX ); - const qreal top = std::max( radius.topLeftY, radius.topRightY ); - const qreal right = std::max( radius.topRightX, radius.bottomRightX ); - const qreal bottom = std::max( radius.bottomRightY, radius.bottomLeftY ); + const QSizeF topLeft = metrics.radius( Qt::TopLeftCorner ); + const QSizeF topRight = metrics.radius( Qt::TopRightCorner ); + const QSizeF bottomLeft = metrics.radius( Qt::BottomLeftCorner ); + const QSizeF bottomRight = metrics.radius( Qt::BottomRightCorner ); - return QMarginsF( std::max( 0.0, left ), std::max( 0.0, top ), - std::max( 0.0, right ), std::max( 0.0, bottom ) ); + return QMarginsF( + std::max( topLeft.width(), bottomLeft.width() ), + std::max( topLeft.height(), topRight.height() ), + std::max( topRight.width(), bottomRight.width() ), + std::max( bottomLeft.height(), bottomRight.height() ) ); } QMarginsF QskBoxOptions::unitedMargins() const @@ -111,5 +59,5 @@ QMarginsF QskBoxOptions::unitedMargins() const std::max( 0.0, pad.bottom() - shadows.bottom() ) + 0.5 ); - return borders + shadows + pad + extra; + return metrics.widths() + shadows + pad + extra; } diff --git a/src/common/QskBoxOptions.h b/src/common/QskBoxOptions.h index e922360a..604e59ba 100644 --- a/src/common/QskBoxOptions.h +++ b/src/common/QskBoxOptions.h @@ -7,70 +7,26 @@ #define QSK_BOX_OPTIONS_H #include "QskGlobal.h" +#include "QskBoxColors.h" +#include "QskBorderMetrics.h" #include -#include class QSK_EXPORT QskBoxOptions { public: QskBoxOptions(); - void setBorder( qreal width ); - void setBorder( qreal left, qreal top, qreal right, qreal bottom ); - - void setRadius( qreal radius ); - - void setBorderRgb( QRgb rgb ); - void setBorderRgb( QRgb rgbLeft, QRgb rgbTop, QRgb rgbRight, QRgb rgbBottom ); - - void setFillRgb( QRgb rgb ); - void setFillRgb( QRgb rgbTopLeft, QRgb rgbTopRight, - QRgb rgbBottomRight, QRgb rgbBottomLeft ); - bool isVisible() const; QMarginsF unitedMargins() const; QMarginsF padding() const; - uint metricsHash( uint seed = 0 ) const; - uint colorsHash( uint seed = 0 ) const; - public: - QMarginsF shadows; - QMarginsF borders; + QskMargins shadows; - struct Radius - { - qreal topLeftX; - qreal topLeftY; - - qreal topRightX; - qreal topRightY; - - qreal bottomRightX; - qreal bottomRightY; - - qreal bottomLeftX; - qreal bottomLeftY; - - } radius; - - struct Colors - { - // borders - QRgb borderLeft; - QRgb borderTop; - QRgb borderRight; - QRgb borderBottom; - - // background - QRgb fillTopLeft; - QRgb fillTopRight; - QRgb fillBottomRight; - QRgb fillBottomLeft; - - } color; + QskBorderMetrics metrics; + QskBoxColors colors; }; #endif diff --git a/src/controls/QskRgbValue.cpp b/src/controls/QskRgbValue.cpp index 5e36f759..251d944c 100644 --- a/src/controls/QskRgbValue.cpp +++ b/src/controls/QskRgbValue.cpp @@ -7,12 +7,61 @@ namespace { - inline int value( int from, int to, qreal progress ) + inline int value( int from, int to, qreal ratio ) { - return int( from + ( to - from ) * progress ); + return int( from + ( to - from ) * ratio ); } } +static inline QColor qskInterpolatedColor( + const QColor& c1, const QColor& c2, qreal ratio ) +{ + switch( c1.spec() ) + { + case QColor::Rgb: + { + const int r = value( c1.red(), c2.red(), ratio ); + const int g = value( c1.green(), c2.green(), ratio ); + const int b = value( c1.blue(), c2.blue(), ratio ); + const int a = value( c1.alpha(), c2.alpha(), ratio ); + + return QColor::fromRgb( r, g, b, a ); + } + case QColor::Hsv: + { + const int h = value( c1.hue(), c2.hue(), ratio ); + const int s = value( c1.saturation(), c2.saturation(), ratio ); + const int v = value( c1.value(), c2.value(), ratio ); + const int a = value( c1.alpha(), c2.alpha(), ratio ); + + return QColor::fromHsv( h, s, v, a ); + } + case QColor::Cmyk: + { + const int c = value( c1.cyan(), c2.cyan(), ratio ); + const int m = value( c1.magenta(), c2.magenta(), ratio ); + const int y = value( c1.yellow(), c2.yellow(), ratio ); + const int k = value( c1.black(), c2.black(), ratio ); + const int a = value( c1.alpha(), c2.alpha(), ratio ); + + return QColor::fromCmykF( c, m, y, k, a ); + } + case QColor::Hsl: + { + const int h = value( c1.hue(), c2.hue(), ratio ); + const int s = value( c1.saturation(), c2.saturation(), ratio ); + const int l = value( c1.lightness(), c2.lightness(), ratio ); + const int a = value( c1.alpha(), c2.alpha(), ratio ); + + return QColor::fromHsl( h, s, l, a ); + } + case QColor::Invalid: + break; + } + + return c2; +} + QRgb QskRgbValue::interpolated( QRgb rgb1, QRgb rgb2, qreal ratio ) { // interpolating in HSV usually provides better results !! @@ -20,8 +69,6 @@ QRgb QskRgbValue::interpolated( QRgb rgb1, QRgb rgb2, qreal ratio ) if ( rgb1 == rgb2 ) return rgb1; - ratio = qBound( 0.0, ratio, 1.0 ); - const int r = value( qRed( rgb1 ), qRed( rgb2 ), ratio ); const int g = value( qGreen( rgb1 ), qGreen( rgb2 ), ratio ); const int b = value( qBlue( rgb1 ), qBlue( rgb2 ), ratio ); @@ -29,3 +76,16 @@ QRgb QskRgbValue::interpolated( QRgb rgb1, QRgb rgb2, qreal ratio ) return qRgba( r, g, b, a ); } + +QColor QskRgbValue::interpolated( const QColor& c1, const QColor& c2, qreal ratio ) +{ + if ( c1 != c2 && c1.isValid() && c2.isValid() ) + { + if ( c1.spec() == c2.spec() ) + return qskInterpolatedColor( c1, c2, ratio ); + else + return qskInterpolatedColor( c1.convertTo( c2.spec() ), c2, ratio ); + } + + return c2; +} diff --git a/src/controls/QskRgbValue.h b/src/controls/QskRgbValue.h index 366322dd..f3a3b25b 100644 --- a/src/controls/QskRgbValue.h +++ b/src/controls/QskRgbValue.h @@ -434,6 +434,7 @@ QSK_RGB_VALUES #undef RGB QRgb interpolated( QRgb rgb1, QRgb rgb2, qreal ratio ); + QColor interpolated( const QColor& c1, const QColor& c2, qreal ratio ); } #endif diff --git a/src/controls/QskSkinRenderer.cpp b/src/controls/QskSkinRenderer.cpp index 9ae3b238..607033af 100644 --- a/src/controls/QskSkinRenderer.cpp +++ b/src/controls/QskSkinRenderer.cpp @@ -249,8 +249,8 @@ QskBoxOptions QskSkinRenderer::boxOptions( const QskSkinnable* skinnable, QskBoxOptions options; - options.borders = qskRotatedMargins( - skinnable->borderMetrics( subControl ), rotation ); + options.metrics.setWidths( qskRotatedMargins( + skinnable->borderMetrics( subControl ), rotation ) ); options.shadows = qskRotatedMargins( skinnable->marginsHint( subControl | Shadow ), rotation ); @@ -267,26 +267,29 @@ QskBoxOptions QskSkinRenderer::boxOptions( const QskSkinnable* skinnable, const auto bottomLeft = static_cast( bottomEdge ); // corner radii - options.radius.topLeftX = qskRadius( skinnable, rect, subControl | RadiusX | topLeft ); - options.radius.topLeftY = qskRadius( skinnable, rect, subControl | RadiusY | topLeft ); - options.radius.topRightX = qskRadius( skinnable, rect, subControl | RadiusX | topRight ); - options.radius.topRightY = qskRadius( skinnable, rect, subControl | RadiusY | topRight ); - options.radius.bottomRightX = qskRadius( skinnable, rect, subControl | RadiusX | bottomRight ); - options.radius.bottomRightY = qskRadius( skinnable, rect, subControl | RadiusY | bottomRight ); - options.radius.bottomLeftX = qskRadius( skinnable, rect, subControl | RadiusX | bottomLeft ); - options.radius.bottomLeftY = qskRadius( skinnable, rect, subControl | RadiusY | bottomLeft ); + options.metrics.setRadius( + qskRadius( skinnable, rect, subControl | RadiusX | topLeft ), + qskRadius( skinnable, rect, subControl | RadiusY | topLeft ), + qskRadius( skinnable, rect, subControl | RadiusX | topRight ), + qskRadius( skinnable, rect, subControl | RadiusY | topRight ), + qskRadius( skinnable, rect, subControl | RadiusX | bottomLeft ), + qskRadius( skinnable, rect, subControl | RadiusY | bottomLeft ), + qskRadius( skinnable, rect, subControl | RadiusX | bottomRight ), + qskRadius( skinnable, rect, subControl | RadiusY | bottomRight ) ); // border colors - options.color.borderLeft = skinnable->color( subControl | Border | leftEdge ).rgba(); - options.color.borderTop = skinnable->color( subControl | Border | topEdge ).rgba(); - options.color.borderRight = skinnable->color( subControl | Border | rightEdge ).rgba(); - options.color.borderBottom = skinnable->color( subControl | Border | bottomEdge ).rgba(); + options.colors.setBorderColor( + skinnable->color( subControl | Border | leftEdge ), + skinnable->color( subControl | Border | topEdge ), + skinnable->color( subControl | Border | rightEdge ), + skinnable->color( subControl | Border | bottomEdge ) ); // background colors - options.color.fillTopLeft = skinnable->color( subControl | leftEdge ).rgba(); - options.color.fillTopRight = skinnable->color( subControl | topEdge ).rgba(); - options.color.fillBottomRight = skinnable->color( subControl | rightEdge ).rgba(); - options.color.fillBottomLeft = skinnable->color( subControl | bottomEdge ).rgba(); + options.colors.setFillColor( + skinnable->color( subControl | topLeft ), + skinnable->color( subControl | topRight ), + skinnable->color( subControl | bottomLeft ), + skinnable->color( subControl | bottomRight ) ); return options; } diff --git a/src/controls/QskVariantAnimator.cpp b/src/controls/QskVariantAnimator.cpp index 33f10be9..5e709338 100644 --- a/src/controls/QskVariantAnimator.cpp +++ b/src/controls/QskVariantAnimator.cpp @@ -6,6 +6,8 @@ #include "QskVariantAnimator.h" #include "QskColorFilter.h" #include "QskMargins.h" +#include "QskBorderMetrics.h" +#include "QskBoxColors.h" // Even if we don't use the standard Qt animation system we // use its registry of interpolators: why adding our own ... @@ -18,6 +20,8 @@ static void qskRegisterInterpolator() { qRegisterAnimationInterpolator( QskColorFilter::interpolate ); qRegisterAnimationInterpolator( QskMargins::interpolate ); + qRegisterAnimationInterpolator( QskBorderMetrics::interpolate ); + qRegisterAnimationInterpolator( QskBoxColors::interpolate ); } Q_CONSTRUCTOR_FUNCTION( qskRegisterInterpolator ) diff --git a/src/nodes/QskBoxMaterial.cpp b/src/nodes/QskBoxMaterial.cpp index 02ab6175..d3537e55 100644 --- a/src/nodes/QskBoxMaterial.cpp +++ b/src/nodes/QskBoxMaterial.cpp @@ -164,14 +164,19 @@ namespace static QPainterPath qskBorderPath( QMarginsF borders, QMarginsF marginsExtra, const QskBoxOptions& options, bool inner ) { - qreal topLeftX = options.radius.topLeftX; - qreal topRightX = options.radius.topRightX; - qreal bottomRightX = options.radius.bottomRightX; - qreal bottomLeftX = options.radius.bottomLeftX; - qreal topLeftY = options.radius.topLeftY; - qreal topRightY = options.radius.topRightY; - qreal bottomRightY = options.radius.bottomRightY; - qreal bottomLeftY = options.radius.bottomLeftY; + const auto& metrics = options.metrics; + + qreal topLeftX = metrics.radius( Qt::TopLeftCorner ).width(); + qreal topRightX = metrics.radius( Qt::TopRightCorner ).width(); + + qreal bottomRightX = metrics.radius( Qt::BottomRightCorner ).width(); + qreal bottomLeftX = metrics.radius( Qt::BottomLeftCorner ).width(); + + qreal topLeftY = metrics.radius( Qt::TopLeftCorner ).height(); + qreal topRightY = metrics.radius( Qt::TopRightCorner ).height(); + + qreal bottomRightY = metrics.radius( Qt::BottomRightCorner ).height(); + qreal bottomLeftY = metrics.radius( Qt::BottomLeftCorner).height(); const auto spacingX = marginsExtra.left() + marginsExtra.right(); const auto spacingY = marginsExtra.top() + marginsExtra.bottom(); @@ -288,8 +293,9 @@ namespace const QMarginsF allMargins = options.unitedMargins(); const QMarginsF padding = options.padding(); + const QMarginsF borders = options.metrics.widths(); - const QMarginsF extra = allMargins - options.borders - options.shadows - padding; + const QMarginsF extra = allMargins - borders - options.shadows - padding; const auto width = allMargins.left() + allMargins.right(); const auto height = allMargins.top() + allMargins.bottom(); @@ -299,15 +305,15 @@ namespace const auto translateY = options.shadows.top() + ( size.height() - height ) * 0.5f; { - auto outerPath = qskBorderPath( options.borders, extra, options, false ); + auto outerPath = qskBorderPath( borders, extra, options, false ); outerPath = outerPath.translated( translateX, translateY ); paths.append( outerPath ); } - if ( !options.borders.isNull() ) + if ( !borders.isNull() ) { - auto innerPath = qskBorderPath( options.borders, extra, options, true ); + auto innerPath = qskBorderPath( borders, extra, options, true ); innerPath = innerPath.translated( translateX, translateY ); paths.append( innerPath ); @@ -320,7 +326,7 @@ namespace if ( !options.shadows.isNull() ) { auto shadowPath = qskBorderPath( - options.borders + options.shadows, extra, options, false ); + borders + options.shadows, extra, options, false ); shadowPath = shadowPath.translated( translateX - options.shadows.left(), translateY - options.shadows.top() ); @@ -440,10 +446,8 @@ bool QskBoxMaterial::isValid() const return m_data != nullptr; } -void QskBoxMaterial::setBoxOptions( const QskBoxOptions& options ) +void QskBoxMaterial::setBoxOptions( const QskBoxOptions& options, uint key ) { - const auto key = options.metricsHash(); - auto it = qskTextureCache.find( key ); if ( it != qskTextureCache.cend() ) { diff --git a/src/nodes/QskBoxMaterial.h b/src/nodes/QskBoxMaterial.h index 05a0ffe3..e4bdc812 100644 --- a/src/nodes/QskBoxMaterial.h +++ b/src/nodes/QskBoxMaterial.h @@ -22,7 +22,7 @@ public: QskBoxMaterial(); virtual ~QskBoxMaterial(); - void setBoxOptions( const QskBoxOptions& ); + void setBoxOptions( const QskBoxOptions&, uint key ); QSizeF textureSize() const; QRectF textureCoordinates() const; diff --git a/src/nodes/QskBoxMaterialVM.cpp b/src/nodes/QskBoxMaterialVM.cpp index bad73878..f29bd15a 100644 --- a/src/nodes/QskBoxMaterialVM.cpp +++ b/src/nodes/QskBoxMaterialVM.cpp @@ -76,14 +76,19 @@ namespace static QPainterPath qskBorderPath( QMarginsF borders, QMarginsF marginsExtra, const QskBoxOptions& options, bool inner ) { - qreal topLeftX = options.radius.topLeftX; - qreal topRightX = options.radius.topRightX; - qreal bottomRightX = options.radius.bottomRightX; - qreal bottomLeftX = options.radius.bottomLeftX; - qreal topLeftY = options.radius.topLeftY; - qreal topRightY = options.radius.topRightY; - qreal bottomRightY = options.radius.bottomRightY; - qreal bottomLeftY = options.radius.bottomLeftY; + const auto& metrics = options.metrics; + + qreal topLeftX = metrics.radius( Qt::TopLeftCorner ).width(); + qreal topRightX = metrics.radius( Qt::TopRightCorner ).width(); + + qreal bottomRightX = metrics.radius( Qt::BottomRightCorner ).width(); + qreal bottomLeftX = metrics.radius( Qt::BottomLeftCorner ).width(); + + qreal topLeftY = metrics.radius( Qt::TopLeftCorner ).height(); + qreal topRightY = metrics.radius( Qt::TopRightCorner ).height(); + + qreal bottomRightY = metrics.radius( Qt::BottomRightCorner ).height(); + qreal bottomLeftY = metrics.radius( Qt::BottomLeftCorner).height(); const auto spacingX = marginsExtra.left() + marginsExtra.right(); const auto spacingY = marginsExtra.top() + marginsExtra.bottom(); @@ -200,8 +205,9 @@ namespace const QMarginsF allMargins = options.unitedMargins(); const QMarginsF padding = options.padding(); + const QMarginsF borders = options.metrics.widths(); - const QMarginsF extra = allMargins - options.borders - options.shadows - padding; + const QMarginsF extra = allMargins - borders - options.shadows - padding; const auto width = allMargins.left() + allMargins.right(); const auto height = allMargins.top() + allMargins.bottom(); @@ -211,15 +217,15 @@ namespace const auto translateY = options.shadows.top() + ( size.height() - height ) * 0.5f; { - auto outerPath = qskBorderPath( options.borders, extra, options, false ); + auto outerPath = qskBorderPath( borders, extra, options, false ); outerPath = outerPath.translated( translateX, translateY ); paths.append( outerPath ); } - if ( !options.borders.isNull() ) + if ( !borders.isNull() ) { - auto innerPath = qskBorderPath( options.borders, extra, options, true ); + auto innerPath = qskBorderPath( borders, extra, options, true ); innerPath = innerPath.translated( translateX, translateY ); paths.append( innerPath ); @@ -232,7 +238,7 @@ namespace if ( !options.shadows.isNull() ) { auto shadowPath = qskBorderPath( - options.borders + options.shadows, extra, options, false ); + borders + options.shadows, extra, options, false ); shadowPath = shadowPath.translated( translateX - options.shadows.left(), translateY - options.shadows.top() ); @@ -356,11 +362,8 @@ QskBoxMaterialVM::~QskBoxMaterialVM() releaseTextures(); } -void QskBoxMaterialVM::setBoxOptions( const QskBoxOptions& options ) +void QskBoxMaterialVM::setBoxOptions( const QskBoxOptions& options, uint key ) { - auto key = options.metricsHash(); - key = qHash( QOpenGLContext::currentContext(), key ); - auto it = qskTextureCache.find( key ); if ( it != qskTextureCache.cend() ) { diff --git a/src/nodes/QskBoxMaterialVM.h b/src/nodes/QskBoxMaterialVM.h index 43bfe856..f41627f4 100644 --- a/src/nodes/QskBoxMaterialVM.h +++ b/src/nodes/QskBoxMaterialVM.h @@ -25,7 +25,7 @@ public: QskBoxMaterialVM(); virtual ~QskBoxMaterialVM(); - void setBoxOptions( const QskBoxOptions& ); + void setBoxOptions( const QskBoxOptions&, uint key ); QSizeF textureSize() const; QRectF textureCoordinates() const; diff --git a/src/nodes/QskBoxNode.cpp b/src/nodes/QskBoxNode.cpp index afe323d8..ed655b28 100644 --- a/src/nodes/QskBoxNode.cpp +++ b/src/nodes/QskBoxNode.cpp @@ -7,28 +7,48 @@ #include "QskBoxOptions.h" #include "QskAspect.h" +#include #include -static inline Qt::Edge qskAspectToEdge( QskAspect::Edge edge ) +// hashes based on CRC32 -> not necessarily unique: TODO + +static inline uint qskMetricsHash( const QskBoxOptions& options ) { - switch ( edge ) + uint hash = qHash( QOpenGLContext::currentContext() ); + + hash = qHashBits( &options.shadows, sizeof( options.shadows ), hash ); + + const auto& m = options.metrics; + hash = qHashBits( &m.widths(), sizeof( QskMargins ), hash ); + + QSizeF radius[4]; + for ( int i = 0; i < 4; i++ ) + radius[i] = m.radius( static_cast( i ) ); + + hash = qHashBits( radius, sizeof( radius ), hash ); + + uint flags[2]; + flags[0] = m.radiusSizeMode(); + flags[1] = m.widthSizeMode(); + + return qHashBits( flags, sizeof( flags ), hash ); +} + +static inline uint qskColorsHash( const QskBoxOptions& options ) +{ + const auto& colors = options.colors; + + QRgb rgb[8]; + for ( int i = 0; i < 4; i++ ) { - case QskAspect::LeftEdge: - return Qt::LeftEdge; + const QColor c1 = colors.borderColor( static_cast< Qt::Edge >( i ) ); + rgb[i] = c1.isValid() ? c1.rgba() : 0; - case QskAspect::TopEdge: - return Qt::TopEdge; - - case QskAspect::RightEdge: - return Qt::RightEdge; - - case QskAspect::BottomEdge: - return Qt::BottomEdge; - - default: - break; + const QColor c2 = colors.fillColor( static_cast< Qt::Corner >( i ) ); + rgb[2*i] = c2.isValid() ? c2.rgba() : 0; } - return static_cast< Qt::Edge >( 0 ); + + return qHashBits( rgb, sizeof( rgb ), 17000 ); } QskBoxNode::QskBoxNode(): @@ -51,8 +71,8 @@ void QskBoxNode::setBoxData( const QRectF& rect, const QskBoxOptions& options ) { using namespace QskAspect; - const uint metricsHash = options.metricsHash(); - const uint colorsHash = options.colorsHash(); + const uint metricsHash = qskMetricsHash( options ); + const uint colorsHash = qskColorsHash( options ); QSGNode::DirtyState dirtyState = 0; @@ -62,7 +82,7 @@ void QskBoxNode::setBoxData( const QRectF& rect, const QskBoxOptions& options ) if ( m_metricsHash > 0 ) m_material.release( m_metricsHash ); #endif - m_material.setBoxOptions( options ); + m_material.setBoxOptions( options, metricsHash ); dirtyState |= QSGNode::DirtyMaterial; } @@ -79,22 +99,28 @@ void QskBoxNode::setBoxData( const QRectF& rect, const QskBoxOptions& options ) if ( colorsHash != m_colorsHash ) { + const auto& c = options.colors; + m_geometry.setEdgeBackground( Qt::LeftEdge, - options.color.fillTopLeft, options.color.fillBottomLeft ); + c.fillColor( Qt::TopLeftCorner ).rgba(), + c.fillColor( Qt::BottomLeftCorner ).rgba() ); m_geometry.setEdgeBackground( Qt::TopEdge, - options.color.fillTopLeft, options.color.fillTopRight ); + c.fillColor( Qt::TopLeftCorner ).rgba(), + c.fillColor( Qt::TopRightCorner ).rgba() ); m_geometry.setEdgeBackground( Qt::RightEdge, - options.color.fillTopRight, options.color.fillBottomRight ); + c.fillColor( Qt::TopRightCorner ).rgba(), + c.fillColor( Qt::BottomRightCorner ).rgba() ); m_geometry.setEdgeBackground( Qt::BottomEdge, - options.color.fillBottomLeft, options.color.fillBottomRight ); + c.fillColor( Qt::BottomLeftCorner ).rgba(), + c.fillColor( Qt::BottomRightCorner ).rgba() ); - m_geometry.setEdgeForeground( qskAspectToEdge( LeftEdge ), options.color.borderLeft ); - m_geometry.setEdgeForeground( qskAspectToEdge( TopEdge ), options.color.borderTop ); - m_geometry.setEdgeForeground( qskAspectToEdge( RightEdge ), options.color.borderRight ); - m_geometry.setEdgeForeground( qskAspectToEdge( BottomEdge ), options.color.borderBottom ); + m_geometry.setEdgeForeground( Qt::LeftEdge, c.borderColor( Qt::LeftEdge ).rgba() ); + m_geometry.setEdgeForeground( Qt::TopEdge, c.borderColor( Qt::TopEdge ).rgba() ); + m_geometry.setEdgeForeground( Qt::RightEdge, c.borderColor( Qt::RightEdge ).rgba() ); + m_geometry.setEdgeForeground( Qt::BottomEdge, c.borderColor( Qt::BottomEdge ).rgba() ); dirtyState |= QSGNode::DirtyGeometry; m_colorsHash = colorsHash; diff --git a/src/src.pro b/src/src.pro index 406006c1..3358936e 100644 --- a/src/src.pro +++ b/src/src.pro @@ -31,6 +31,8 @@ DEPENDPATH *= $${QSK_SUBDIRS} HEADERS += \ common/QskAspect.h \ + common/QskBorderMetrics.h \ + common/QskBoxColors.h \ common/QskBoxOptions.h \ common/QskCorner.h \ common/QskFlags.h \ @@ -46,6 +48,8 @@ HEADERS += \ SOURCES += \ common/QskAspect.cpp \ + common/QskBorderMetrics.cpp \ + common/QskBoxColors.cpp \ common/QskBoxOptions.cpp \ common/QskCorner.cpp \ common/QskFunctions.cpp \