diff --git a/playground/gradients/GradientQuickShape.cpp b/playground/gradients/GradientQuickShape.cpp index cedce13c..9bf8b9a0 100644 --- a/playground/gradients/GradientQuickShape.cpp +++ b/playground/gradients/GradientQuickShape.cpp @@ -51,67 +51,60 @@ namespace private: QQuickShapeGradient* createShapeGradient( - const QRectF& rect, const QskGradient& gradient ) const + const QRectF& rect, QskGradient gradient ) const { - QQuickShapeGradient* shapeGradient = nullptr; - const auto qtGradient = gradient.toQGradient( rect ); + gradient.stretchTo( rect ); - switch( qtGradient.type() ) + switch( static_cast< int >( gradient.type() ) ) { - case QGradient::LinearGradient: + case QskGradient::Linear: { - auto& linearGradient = - *static_cast< const QLinearGradient* >( &qtGradient ); + const auto dir = gradient.linearDirection(); auto g = new QQuickShapeLinearGradient(); - g->setX1( linearGradient.start().x() ); - g->setY1( linearGradient.start().y() ); - g->setX2( linearGradient.finalStop().x() ); - g->setY2( linearGradient.finalStop().y() ); + g->setX1( dir.x1() ); + g->setY1( dir.y1() ); + g->setX2( dir.x2() ); + g->setY2( dir.y2() ); shapeGradient = g; break; } - case QGradient::RadialGradient: + case QskGradient::Radial: { - auto& radialGradient = - *static_cast< const QRadialGradient* >( &qtGradient ); + const auto dir = gradient.radialDirection(); auto g = new QQuickShapeRadialGradient(); - g->setCenterX( radialGradient.center().x() ); - g->setCenterY( radialGradient.center().y() ); - g->setFocalX( radialGradient.center().x() ); - g->setFocalY( radialGradient.center().y() ); + g->setCenterX( dir.x() ); + g->setCenterY( dir.y() ); + g->setFocalX( dir.x() ); + g->setFocalY( dir.y() ); - g->setCenterRadius( radialGradient.radius() ); - g->setFocalRadius( radialGradient.radius() ); + g->setCenterRadius( dir.radius() ); + g->setFocalRadius( dir.radius() ); shapeGradient = g; break; } - case QGradient::ConicalGradient: + case QskGradient::Conic: { - auto& conicalGradient = - *static_cast< const QConicalGradient* >( &qtGradient ); + const auto dir = gradient.conicDirection(); auto g = new QQuickShapeConicalGradient(); - g->setCenterX( conicalGradient.center().x() ); - g->setCenterY( conicalGradient.center().y() ); - g->setAngle( conicalGradient.angle() ); + g->setCenterX( dir.x() ); + g->setCenterY( dir.y() ); + g->setAngle( dir.startAngle() ); // dir.spanAngle() is not supported shapeGradient = g; break; } - - default: - break; } shapeGradient->setSpread( diff --git a/playground/gradients/GradientView.cpp b/playground/gradients/GradientView.cpp index d7c82195..59211c24 100644 --- a/playground/gradients/GradientView.cpp +++ b/playground/gradients/GradientView.cpp @@ -58,7 +58,7 @@ namespace const auto gradient = reinterpret_cast< const QskGradient* >( nodeData ); const QRect rect( 0, 0, size.width(), size.height() ); - painter->fillRect( rect, gradient->toQGradient( rect ) ); + painter->fillRect( rect, gradient->stretchedTo( rect ).toQGradient() ); } }; diff --git a/src/common/QskGradient.cpp b/src/common/QskGradient.cpp index 749bb8bb..ae1ca2a2 100644 --- a/src/common/QskGradient.cpp +++ b/src/common/QskGradient.cpp @@ -56,6 +56,26 @@ static inline bool qskCanBeInterpolated( const QskGradient& from, const QskGradi return from.type() == to.type(); } +static inline QTransform qskTransformForRect( int stretch, const QRectF& rect ) +{ + const qreal x = rect.x(); + const qreal y = rect.y(); + const qreal w = rect.width(); + const qreal h = rect.height(); + + switch( stretch ) + { + case QskGradient::StretchToHeight: + return QTransform( h, 0, 0, h, x, y ); + + case QskGradient::StretchToWidth: + return QTransform( w, 0, 0, w, x, y ); + + default: + return QTransform( w, 0, 0, h, x, y ); + } +} + QskGradient::QskGradient( const QColor& color ) { setStops( color ); @@ -130,6 +150,27 @@ QskGradient::QskGradient( const QGradient& qGradient ) } m_spreadMode = static_cast< SpreadMode >( qGradient.spread() ); + + switch( qGradient.coordinateMode() ) + { + case QGradient::ObjectMode: + case QGradient::ObjectBoundingMode: + + m_stretchMode = StretchToSize; + break; + + case QGradient::LogicalMode: + + m_stretchMode = NoStretch; + break; + + case QGradient::StretchToDeviceMode: + { + qWarning() << "QskGradient: StretchToDeviceMode is not supportd."; + m_stretchMode = NoStretch; + } + } + setStops( qskBuildGradientStops( qGradient.stops() ) ); } @@ -139,6 +180,7 @@ QskGradient::QskGradient( const QskGradient& other ) noexcept other.m_values[2], other.m_values[3], } , m_type( other.m_type ) , m_spreadMode( other.m_spreadMode ) + , m_stretchMode( other.m_stretchMode ) , m_isDirty( other.m_isDirty ) , m_isValid( other.m_isValid ) , m_isMonchrome( other.m_isMonchrome ) @@ -154,6 +196,7 @@ QskGradient& QskGradient::operator=( const QskGradient& other ) noexcept { m_type = other.m_type; m_spreadMode = other.m_spreadMode; + m_stretchMode = other.m_stretchMode; m_stops = other.m_stops; m_values[0] = other.m_values[0]; @@ -173,6 +216,7 @@ bool QskGradient::operator==( const QskGradient& other ) const noexcept { return ( m_type == other.m_type ) && ( m_spreadMode == other.m_spreadMode ) + && ( m_stretchMode == other.m_stretchMode ) && ( m_values[0] == other.m_values[0] ) && ( m_values[1] == other.m_values[1] ) && ( m_values[2] == other.m_values[2] ) @@ -351,6 +395,64 @@ void QskGradient::setSpreadMode( SpreadMode spreadMode ) m_spreadMode = spreadMode; } +void QskGradient::setStretchMode( StretchMode stretchMode ) +{ + m_stretchMode = stretchMode; +} + +void QskGradient::stretchTo( const QRectF& rect ) +{ + if ( m_stretchMode == NoStretch || m_type == Stops || rect.isEmpty() ) + return; // nothing to do + + const auto transform = qskTransformForRect( m_stretchMode, rect ); + + switch( static_cast< int >( m_type ) ) + { + case Linear: + { + transform.map( m_values[0], m_values[1], &m_values[0], &m_values[1] ); + transform.map( m_values[2], m_values[3], &m_values[2], &m_values[3] ); + + break; + } + case Radial: + { + transform.map( m_values[0], m_values[1], &m_values[0], &m_values[1] ); + +#if 1 + const auto radius = transform.map( QPointF( m_values[2], m_values[2] ) ); + m_values[2] = qMin( radius.x(), radius.y() ); +#endif + + break; + } + case Conic: + { + transform.map( m_values[0], m_values[1], &m_values[0], &m_values[1] ); + break; + } + } + + m_stretchMode = NoStretch; +} + +QskGradient QskGradient::stretchedTo( const QSizeF& size ) const +{ + return stretchedTo( QRectF( 0.0, 0.0, size.width(), size.height() ) ); +} + +QskGradient QskGradient::stretchedTo( const QRectF& rect ) const +{ + if ( m_stretchMode == NoStretch ) + return *this; + + QskGradient g = *this; + g.stretchTo( rect ); + + return g; +} + void QskGradient::reverse() { if ( isMonochrome() ) @@ -622,7 +724,8 @@ QGradient QskGradient::toQGradient() const } } - g.setCoordinateMode( QGradient::ObjectMode ); + g.setCoordinateMode( m_stretchMode == NoStretch + ? QGradient::LogicalMode : QGradient::ObjectMode ); g.setSpread( static_cast< QGradient::Spread >( m_spreadMode ) ); g.setStops( qskToQGradientStops( m_stops ) ); @@ -630,58 +733,6 @@ QGradient QskGradient::toQGradient() const return g; } -QGradient QskGradient::toQGradient( const QRectF& rect ) const -{ - auto qGradient = toQGradient(); - - if ( qGradient.coordinateMode() != QGradient::ObjectMode ) - return qGradient; - - const QTransform transform( rect.width(), 0, 0, rect.height(), rect.x(), rect.y() ); - - switch( qGradient.type() ) - { - case QGradient::LinearGradient: - { - auto& g = *static_cast< QLinearGradient* >( &qGradient ); - - g.setStart( transform.map( g.start() ) ); - g.setFinalStop( transform.map( g.finalStop() ) ); - - break; - } - case QGradient::RadialGradient: - { - auto& g = *static_cast< QRadialGradient* >( &qGradient ); - - const auto center = transform.map( g.center() ); - - const qreal radius = qMin( g.radius() * rect.width(), - g.radius() * rect.height() ); - - g.setCenter( center ); - g.setFocalPoint( center ); - - g.setCenterRadius( radius ); - g.setFocalRadius( radius ); - - break; - } - case QGradient::ConicalGradient: - { - auto& g = *static_cast< QConicalGradient* >( &qGradient ); - g.setCenter( transform.map( g.center() ) ); - - break; - } - default: - break; - } - - qGradient.setCoordinateMode( QGradient::LogicalMode ); - return qGradient; -} - #ifndef QT_NO_DEBUG_STREAM #include @@ -759,6 +810,21 @@ QDebug operator<<( QDebug debug, const QskGradient& gradient ) } } + switch( static_cast< int >( gradient.stretchMode() ) ) + { + case QskGradient::StretchToSize: + debug << " SS"; + break; + + case QskGradient::StretchToHeight: + debug << " SH"; + break; + + case QskGradient::StretchToWidth: + debug << " SW"; + break; + } + switch( gradient.spreadMode() ) { case QskGradient::RepeatSpread: diff --git a/src/common/QskGradient.h b/src/common/QskGradient.h index 55d03167..ac7b96ee 100644 --- a/src/common/QskGradient.h +++ b/src/common/QskGradient.h @@ -31,6 +31,7 @@ class QSK_EXPORT QskGradient Q_PROPERTY( QskGradientStops stops READ stops WRITE setStops ) Q_PROPERTY( SpreadMode spreadMode READ spreadMode WRITE setSpreadMode ) + Q_PROPERTY( StretchMode stretchMode READ stretchMode WRITE setStretchMode ) Q_PROPERTY( bool valid READ isValid ) Q_PROPERTY( bool visible READ isVisible ) @@ -57,6 +58,17 @@ class QSK_EXPORT QskGradient }; Q_ENUM( SpreadMode ) + enum StretchMode + { + NoStretch, + + StretchToHeight, + StretchToWidth, + + StretchToSize + }; + Q_ENUM( StretchMode ) + QskGradient() noexcept = default; QskGradient( Qt::GlobalColor ); @@ -125,11 +137,18 @@ class QSK_EXPORT QskGradient void setSpreadMode( SpreadMode ); SpreadMode spreadMode() const noexcept; + void setStretchMode( StretchMode ); + StretchMode stretchMode() const noexcept; + void reverse(); QskGradient reversed() const; QskGradient interpolated( const QskGradient&, qreal value ) const; + void stretchTo( const QRectF& ); + QskGradient stretchedTo( const QSizeF& ) const; + QskGradient stretchedTo( const QRectF& ) const; + static QVariant interpolate( const QskGradient&, const QskGradient&, qreal progress ); @@ -144,7 +163,6 @@ class QSK_EXPORT QskGradient int stepCount() const noexcept; QGradient toQGradient() const; - QGradient toQGradient( const QRectF& ) const; private: void updateStatusBits() const; @@ -161,6 +179,7 @@ class QSK_EXPORT QskGradient Type m_type = Stops; SpreadMode m_spreadMode = PadSpread; + StretchMode m_stretchMode = StretchToSize; mutable bool m_isDirty = false; mutable bool m_isValid = false; @@ -239,6 +258,11 @@ inline QskGradient::SpreadMode QskGradient::spreadMode() const noexcept return m_spreadMode; } +inline QskGradient::StretchMode QskGradient::stretchMode() const noexcept +{ + return m_stretchMode; +} + #ifndef QT_NO_DEBUG_STREAM class QDebug;