From 9a1e46e0ba7bf6c681a6b7daa1ee8565bd34a338 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Mon, 26 Nov 2018 17:52:16 +0100 Subject: [PATCH] QskPushButton::graphicSourceSize added to prevent raster graphics from being scaled --- src/controls/QskPushButton.cpp | 69 +++++++++++++++++++++++---- src/controls/QskPushButton.h | 9 ++++ src/controls/QskPushButtonSkinlet.cpp | 47 +++++++++++++----- 3 files changed, 105 insertions(+), 20 deletions(-) diff --git a/src/controls/QskPushButton.cpp b/src/controls/QskPushButton.cpp index f0962a70..4c5e3201 100644 --- a/src/controls/QskPushButton.cpp +++ b/src/controls/QskPushButton.cpp @@ -25,6 +25,7 @@ class QskPushButton::PrivateData public: PrivateData( const QString& txt ) : text( txt ) + , graphicSourceSize( -1, -1 ) , isGraphicSourceDirty( false ) { textOptions.setElideMode( Qt::ElideMiddle ); @@ -36,6 +37,8 @@ class QskPushButton::PrivateData QUrl graphicSource; QskGraphic graphic; + QSizeF graphicSourceSize; + bool isGraphicSourceDirty : 1; }; @@ -141,6 +144,37 @@ QFont QskPushButton::font() const return effectiveFont( QskPushButton::Text ); } +void QskPushButton::resetGraphicSourceSize() +{ + setGraphicSourceSize( QSizeF( -1.0, -1.0 ) ); +} + +void QskPushButton::setGraphicSourceSize( const QSizeF& size ) +{ + auto newSize = size; + if ( newSize.width() < 0.0 ) + newSize.setWidth( -1.0 ); + + if ( newSize.height() < 0.0 ) + newSize.setHeight( -1.0 ); + + if ( size != m_data->graphicSourceSize ) + { + m_data->graphicSourceSize = size; + + resetImplicitSize(); + polish(); + update(); + + Q_EMIT graphicSourceSizeChanged(); + } +} + +QSizeF QskPushButton::graphicSourceSize() const +{ + return m_data->graphicSourceSize; +} + void QskPushButton::setGraphicSource( const QUrl& url ) { if ( m_data->graphicSource == url ) @@ -205,10 +239,7 @@ void QskPushButton::updateLayout() if ( m_data->isGraphicSourceDirty ) { if ( !m_data->graphicSource.isEmpty() ) - { m_data->graphic = loadGraphic( m_data->graphicSource ); - Q_EMIT graphicChanged(); - } m_data->isGraphicSourceDirty = false; } @@ -223,20 +254,40 @@ QSizeF QskPushButton::contentsSizeHint() const { QSizeF size( 0, 0 ); + const QFontMetricsF fm( font() ); + if ( !m_data->text.isEmpty() ) { // in elide mode we might want to ignore the text width ??? - const QFontMetricsF fm( font() ); size += fm.size( Qt::TextShowMnemonic, m_data->text ); } - if ( !m_data->graphicSource.isEmpty() ) + if ( m_data->isGraphicSourceDirty ) { - const double dim = 1.5 * size.height(); - size.rheight() += 4 + dim; - const QSizeF graphicSize = m_data->graphic.defaultSize(); - size.rwidth() += graphicSize.width() * dim / graphicSize.height(); + if ( !m_data->graphicSource.isEmpty() ) + m_data->graphic = loadGraphic( m_data->graphicSource ); + + m_data->isGraphicSourceDirty = false; + } + + if ( !m_data->graphic.isEmpty() ) + { + qreal w = m_data->graphicSourceSize.width(); + qreal h = m_data->graphicSourceSize.height(); + + if ( ( w < 0.0 ) && ( h < 0.0 ) ) + h = 1.5 * fm.height(); + + if ( w < 0 ) + w = m_data->graphic.widthForHeight( h ); + else if ( h < 0 ) + h = m_data->graphic.heightForWidth( w ); + + const qreal padding = 2.0; // Graphic::Padding ??? + + size.rheight() += 2 * padding + h; + size.rwidth() = qMax( size.width(), w ); } const QSizeF minSize( metric( Panel | QskAspect::MinimumWidth ), diff --git a/src/controls/QskPushButton.h b/src/controls/QskPushButton.h index 1c1fa155..248e17b7 100644 --- a/src/controls/QskPushButton.h +++ b/src/controls/QskPushButton.h @@ -27,6 +27,10 @@ class QSK_EXPORT QskPushButton : public QskAbstractButton Q_PROPERTY( QskGraphic graphic READ graphic WRITE setGraphic NOTIFY graphicChanged FINAL ) + Q_PROPERTY( QSizeF graphicSourceSize READ graphicSourceSize + WRITE setGraphicSourceSize RESET resetGraphicSourceSize + NOTIFY graphicSourceSizeChanged FINAL ) + Q_PROPERTY( bool flat READ isFlat WRITE setFlat NOTIFY flatChanged FINAL ) Q_PROPERTY( QskCorner corner READ corner WRITE setCorner NOTIFY cornerChanged ) @@ -49,9 +53,12 @@ class QSK_EXPORT QskPushButton : public QskAbstractButton QskTextOptions textOptions() const; QUrl graphicSource() const; + QSizeF graphicSourceSize() const; QskGraphic graphic() const; bool hasGraphic() const; + void resetGraphicSourceSize(); + void setFlat( bool ); bool isFlat() const; @@ -65,6 +72,7 @@ class QSK_EXPORT QskPushButton : public QskAbstractButton void setGraphicSource( const QUrl& url ); void setGraphicSource( const QString& source ); void setGraphic( const QskGraphic& ); + void setGraphicSourceSize( const QSizeF & ); Q_SIGNALS: void cornerChanged(); @@ -74,6 +82,7 @@ class QSK_EXPORT QskPushButton : public QskAbstractButton void flatChanged(); void graphicChanged(); void graphicSourceChanged(); + void graphicSourceSizeChanged(); void hovered( bool ); diff --git a/src/controls/QskPushButtonSkinlet.cpp b/src/controls/QskPushButtonSkinlet.cpp index f9393723..12f1257a 100644 --- a/src/controls/QskPushButtonSkinlet.cpp +++ b/src/controls/QskPushButtonSkinlet.cpp @@ -103,22 +103,47 @@ QRectF QskPushButtonSkinlet::graphicRect( const QskPushButton* button ) const r.setHeight( 0 ); } + const auto maxSize = button->graphicSourceSize(); + if ( maxSize.width() >= 0 || maxSize.height() >= 0 ) + { + // limiting the size by graphicSize + const qreal maxW = maxSize.width(); + const qreal maxH = maxSize.height(); + + if ( maxW >= 0.0 && maxW < r.width() ) + { + r.setX( r.center().x() - 0.5 * maxW ); + r.setWidth( maxW ); + } + + if ( maxH >= 0.0 && maxH < r.height() ) + { + r.setY( r.center().y() - 0.5 * maxH ); + r.setHeight( maxH ); + } + } + const QSizeF sz = button->graphic().defaultSize(); - if ( r.isEmpty() || sz.isEmpty() ) - return r; - const double scaleFactor = - qMin( r.width() / sz.width(), r.height() / sz.height() ); + if ( !( r.isEmpty() || sz.isEmpty() ) ) + { + // inner rectangle according to the aspect ratio - // early aligning to avoid pointless operations, that finally will - // have no effect, when drawing to an integer based paint device + const double scaleFactor = + qMin( r.width() / sz.width(), r.height() / sz.height() ); - const int w = qFloor( scaleFactor * sz.width() ); - const int h = qFloor( scaleFactor * sz.height() ); - const int x = qFloor( r.center().x() - 0.5 * w ); - const int y = qFloor( r.center().y() - 0.5 * h ); + // early aligning to avoid pointless operations, that finally will + // have no effect, when drawing to an integer based paint device - return QRectF( x, y, w, h ); + const int w = qFloor( scaleFactor * sz.width() ); + const int h = qFloor( scaleFactor * sz.height() ); + const int x = qFloor( r.center().x() - 0.5 * w ); + const int y = qFloor( r.center().y() - 0.5 * h ); + + r = QRectF( x, y, w, h ); + } + + return r; } QSGNode* QskPushButtonSkinlet::updateTextNode(