From bc5510f7efef73eebe6e0cd154515d0e9db883e2 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Wed, 3 Aug 2022 18:28:53 +0200 Subject: [PATCH] temporary improvements for push buttons - until we have a general layout class for graphic/text combinations --- skins/material3/QskMaterial3Skin.cpp | 44 ++++++++- src/controls/QskPushButton.cpp | 25 +++++ src/controls/QskPushButton.h | 1 + src/controls/QskPushButtonSkinlet.cpp | 135 +++++++++++++++----------- src/controls/QskPushButtonSkinlet.h | 2 + 5 files changed, 147 insertions(+), 60 deletions(-) diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index 8e3449b8..fb7d3da7 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -45,10 +45,44 @@ #include #include +#include +#include + static const int qskDuration = 150; namespace { + // see: https://en.wikipedia.org/wiki/Device-independent_pixel + inline qreal dpToPixels( long double value ) + { + static qreal factor = -1.0; + + if ( factor < 0.0 ) + { + factor = 1.0; + +#if 0 + if ( const auto screen = QGuiApplication::primaryScreen() ) + { + // is this calculation correct ? TODO ... + factor = screen->logicalDotsPerInch() / 160.0; + } +#endif + } + + return value * factor; + } + + inline double operator ""_dp( long double value ) + { + return dpToPixels( value ); + } + + inline double operator ""_dp( unsigned long long int value ) + { + return dpToPixels( value ); + } + class Editor : private QskSkinHintTableEditor { public: @@ -453,12 +487,16 @@ void Editor::setupPushButton() setBoxShape( Q::Panel, 100, Qt::RelativeSize ); - setAlignment( Q::Graphic | A::Alignment, Qt::AlignLeft ); - setPadding( Q::Graphic, 5 ); + setAlignment( Q::Graphic | A::Alignment, Qt::AlignCenter ); + setStrutSize( Q::Graphic, 24_dp, 24_dp ); + setPadding( Q::Graphic, 0 ); setFontRole( Q::Text, QskMaterial3Skin::M3LabelLarge ); - setAlignment( Q::Text, Qt::AlignCenter ); + setPadding( Q::Text, 0 ); + setAlignment( Q::Text | A::Alignment, Qt::AlignCenter ); + setAlignment( Q::Text | A::Alignment | A::Horizontal, + Qt::AlignLeft | Qt::AlignVCenter ); // normal buttons (i.e. Filled): diff --git a/src/controls/QskPushButton.cpp b/src/controls/QskPushButton.cpp index 37565b67..16ee2a0e 100644 --- a/src/controls/QskPushButton.cpp +++ b/src/controls/QskPushButton.cpp @@ -230,6 +230,31 @@ void QskPushButton::updateResources() m_data->ensureGraphic( this ); } +QskAspect::Placement QskPushButton::effectivePlacement() const +{ + if ( hasGraphic() && !text().isEmpty() ) + { + // for the moment we only support the direction. TODO ... + + auto aspect = Panel | QskAspect::Direction; + aspect.setPlacement( QskAspect::Vertical ); // to avoid recursions TODO ... + + const auto dir = flagHint( aspect, Qsk::LeftToRight ); + switch( dir ) + { + case Qsk::LeftToRight: + case Qsk::RightToLeft: + return QskAspect::Horizontal; + + case Qsk::TopToBottom: + case Qsk::BottomToTop: + return QskAspect::Vertical; + } + } + + return Inherited::effectivePlacement(); +} + QRectF QskPushButton::layoutRectForSize( const QSizeF& size ) const { return subControlContentsRect( size, Panel ); diff --git a/src/controls/QskPushButton.h b/src/controls/QskPushButton.h index 246e457b..511e0b99 100644 --- a/src/controls/QskPushButton.h +++ b/src/controls/QskPushButton.h @@ -72,6 +72,7 @@ class QSK_EXPORT QskPushButton : public QskAbstractButton QFont font() const; QRectF layoutRectForSize( const QSizeF& ) const override; + QskAspect::Placement effectivePlacement() const override; public Q_SLOTS: void setText( const QString& ); diff --git a/src/controls/QskPushButtonSkinlet.cpp b/src/controls/QskPushButtonSkinlet.cpp index 0e4cb841..00127bc6 100644 --- a/src/controls/QskPushButtonSkinlet.cpp +++ b/src/controls/QskPushButtonSkinlet.cpp @@ -105,12 +105,12 @@ QRectF QskPushButtonSkinlet::textRect( if ( r.isEmpty() || !button->hasGraphic() ) return r; - /* - For horizontal layouts Text depends on Graphic, while - for vertical Graphic depends on Text. Confusing ... - */ if ( qskOrientation( button ) == Qt::Horizontal ) { + /* + For horizontal layouts Text depends on Graphic, while + for vertical Graphic depends on Text. Confusing ... + */ const auto graphicsRect = subControlRect( button, contentsRect, Q::Graphic ); const auto spacing = button->spacingHint( Q::Panel ); @@ -136,9 +136,17 @@ QRectF QskPushButtonSkinlet::graphicRect( return r; const auto orientation = qskOrientation( button ); + const auto maxSize = button->strutSizeHint( Q::Graphic ); + + const qreal maxW = maxSize.width(); + const qreal maxH = maxSize.height(); if ( orientation == Qt::Vertical ) { + /* + For horizontal layouts Text depends on Graphic, while + for vertical Graphic depends on Text. Confusing ... + */ const auto textRect = subControlRect( button, contentsRect, Q::Text ); const auto h = textRect.height() + button->spacingHint( Q::Panel ); @@ -146,26 +154,38 @@ QRectF QskPushButtonSkinlet::graphicRect( return QRectF(); r.setBottom( r.bottom() - h ); - } - const auto maxSize = button->strutSizeHint( Q::Graphic ); - - 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() ) + if ( maxW >= 0 || maxH >= 0 ) { - r.setX( r.center().x() - 0.5 * maxW ); - r.setWidth( maxW ); + // limiting the size by maxSize + + 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 ); + } } - - if ( maxH >= 0.0 && maxH < r.height() ) + } + else + { + if ( maxW >= 0 || maxH >= 0 ) { - r.setY( r.center().y() - 0.5 * maxH ); - r.setHeight( maxH ); + if ( maxW >= 0.0 && maxW < r.width() ) + { + r.setWidth( maxW ); + } + + if ( maxH >= 0.0 && maxH < r.height() ) + { + r.setY( r.center().y() - 0.5 * maxH ); + r.setHeight( maxH ); + } } } @@ -178,10 +198,10 @@ QRectF QskPushButtonSkinlet::graphicRect( { sz.scale( r.size(), Qt::KeepAspectRatio ); - const auto align = ( orientation == Qt::Horizontal ) - ? ( Qt::AlignLeft | Qt::AlignTop ) : Qt::AlignCenter; - - r = qskAlignedRectF( r, sz.width(), sz.height(), align ); + if ( orientation == Qt::Vertical ) + r = qskAlignedRectF( r, sz, Qt::AlignCenter ); + else + r = qskAlignedRectF( r, sz, Qt::AlignLeft | Qt::AlignVCenter ); } } @@ -267,7 +287,7 @@ QSizeF QskPushButtonSkinlet::sizeHint( const QskSkinnable* skinnable, QSizeF size( 0, 0 ); - const QFontMetricsF fm( button->effectiveFont( QskPushButton::Text ) ); + const QFontMetricsF fm( button->effectiveFont( Q::Text ) ); if ( !button->text().isEmpty() ) { @@ -278,47 +298,20 @@ QSizeF QskPushButtonSkinlet::sizeHint( const QskSkinnable* skinnable, if ( button->hasGraphic() ) { - const auto sz = button->strutSizeHint( Q::Graphic ); - - qreal w = sz.width(); - qreal h = sz.height(); - - if ( w < 0.0 || h < 0.0 ) - { - const auto graphic = button->graphic(); - - if ( !graphic.isEmpty() ) - { - - if ( ( w < 0.0 ) && ( h < 0.0 ) ) - { - // strutSizeHint( Graphic ) ??? - h = 1.5 * fm.height(); - } - - if ( w < 0 ) - { - w = graphic.widthForHeight( h ); - } - else if ( h < 0 ) - { - h = graphic.heightForWidth( w ); - } - } - } + const auto hint = graphicSizeHint( button ); const auto padding = button->paddingHint( Q::Graphic ); const auto orientation = qskOrientation( button ); if( orientation == Qt::Horizontal ) { - size.rwidth() += padding.left() + w + padding.right(); - size.rheight() = qMax( size.height(), h ); + size.rwidth() += padding.left() + hint.width() + padding.right(); + size.rheight() = qMax( size.height(), hint.height() ); } else { - size.rheight() += padding.top() + h + padding.bottom(); - size.rwidth() = qMax( size.width(), w ); + size.rheight() += padding.top() + hint.height() + padding.bottom(); + size.rwidth() = qMax( size.width(), hint.width() ); } } @@ -328,4 +321,32 @@ QSizeF QskPushButtonSkinlet::sizeHint( const QskSkinnable* skinnable, return size; } +QSizeF QskPushButtonSkinlet::graphicSizeHint( const QskPushButton* button ) const +{ + using Q = QskPushButton; + + auto size = button->strutSizeHint( Q::Graphic ); + if ( !size.isEmpty() ) + return size; + + const auto& graphic = button->graphic(); + + auto w = size.width(); + auto h = size.height(); + + if ( w > 0.0 ) + { + h = graphic.heightForWidth( w ); + } + else + { + if ( h <= 0.0 ) + h = 1.5 * button->effectiveFontHeight( Q::Text ); + + w = graphic.widthForHeight( h ); + } + + return QSizeF( w, h ); +} + #include "moc_QskPushButtonSkinlet.cpp" diff --git a/src/controls/QskPushButtonSkinlet.h b/src/controls/QskPushButtonSkinlet.h index 2147a1d1..9a85195b 100644 --- a/src/controls/QskPushButtonSkinlet.h +++ b/src/controls/QskPushButtonSkinlet.h @@ -45,6 +45,8 @@ class QSK_EXPORT QskPushButtonSkinlet : public QskSkinlet QRectF graphicRect( const QskPushButton*, const QRectF& ) const; QRectF rippleRect( const QskPushButton*, const QRectF& ) const; + QSizeF graphicSizeHint( const QskPushButton* ) const; + QSGNode* updateTextNode( const QskPushButton*, QSGNode* ) const; QSGNode* updateRippleNode( const QskPushButton*, QSGNode* ) const; };