diff --git a/src/controls/QskGraphicLabel.cpp b/src/controls/QskGraphicLabel.cpp index 86c2cedb..767552cc 100644 --- a/src/controls/QskGraphicLabel.cpp +++ b/src/controls/QskGraphicLabel.cpp @@ -11,6 +11,7 @@ #include "QskSetup.h" #include "QskSkin.h" +QSK_SUBCONTROL( QskGraphicLabel, Panel ) QSK_SUBCONTROL( QskGraphicLabel, Graphic ) class QskGraphicLabel::PrivateData @@ -22,6 +23,7 @@ class QskGraphicLabel::PrivateData , fillMode( QskGraphicLabel::PreserveAspectFit ) , mirror( false ) , isSourceDirty( !sourceUrl.isEmpty() ) + , hasPanel( false ) { } @@ -33,6 +35,7 @@ class QskGraphicLabel::PrivateData uint fillMode : 2; bool mirror : 1; bool isSourceDirty : 1; + bool hasPanel : 1; }; QskGraphicLabel::QskGraphicLabel( const QUrl& source, QQuickItem* parent ) @@ -65,6 +68,24 @@ QskGraphicLabel::~QskGraphicLabel() { } +void QskGraphicLabel::setPanel( bool on ) +{ + if ( on == m_data->hasPanel ) + return; + + m_data->hasPanel = on; + + resetImplicitSize(); + update(); + + Q_EMIT panelChanged( on ); +} + +bool QskGraphicLabel::hasPanel() const +{ + return m_data->hasPanel; +} + bool QskGraphicLabel::isEmpty() const { return m_data->graphic.isNull() && m_data->source.isEmpty(); diff --git a/src/controls/QskGraphicLabel.h b/src/controls/QskGraphicLabel.h index ae1f93e7..bb8397e2 100644 --- a/src/controls/QskGraphicLabel.h +++ b/src/controls/QskGraphicLabel.h @@ -31,10 +31,13 @@ class QSK_EXPORT QskGraphicLabel : public QskControl Q_PROPERTY( FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged ) + Q_PROPERTY( bool panel READ hasPanel + WRITE setPanel NOTIFY panelChanged ) + using Inherited = QskControl; public: - QSK_SUBCONTROLS( Graphic ) + QSK_SUBCONTROLS( Panel, Graphic ) enum FillMode { @@ -84,6 +87,9 @@ class QSK_EXPORT QskGraphicLabel : public QskControl void resetGraphicRole(); int graphicRole() const; + void setPanel( bool ); + bool hasPanel() const; + Q_SIGNALS: void sourceChanged(); void mirrorChanged(); @@ -91,6 +97,7 @@ class QSK_EXPORT QskGraphicLabel : public QskControl void graphicRoleChanged( int ); void alignmentChanged( Qt::Alignment ); void fillModeChanged( FillMode ); + void panelChanged( bool ); public Q_SLOTS: void setGraphic( const QskGraphic& ); diff --git a/src/controls/QskGraphicLabelSkinlet.cpp b/src/controls/QskGraphicLabelSkinlet.cpp index dd3479ed..c37705d6 100644 --- a/src/controls/QskGraphicLabelSkinlet.cpp +++ b/src/controls/QskGraphicLabelSkinlet.cpp @@ -15,7 +15,7 @@ QskGraphicLabelSkinlet::QskGraphicLabelSkinlet( QskSkin* skin ) : Inherited( skin ) { - setNodeRoles( { GraphicRole } ); + setNodeRoles( { PanelRole, GraphicRole } ); } QskGraphicLabelSkinlet::~QskGraphicLabelSkinlet() = default; @@ -23,11 +23,23 @@ QskGraphicLabelSkinlet::~QskGraphicLabelSkinlet() = default; QRectF QskGraphicLabelSkinlet::subControlRect( const QskSkinnable* skinnable, const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const { - const auto label = static_cast< const QskGraphicLabel* >( skinnable ); - - if ( subControl == QskGraphicLabel::Graphic ) + if ( subControl == QskGraphicLabel::Panel ) { - return graphicRect( label, contentsRect ); + return contentsRect; + } + else if ( subControl == QskGraphicLabel::Graphic ) + { + auto innerRect = contentsRect; + + const auto label = static_cast< const QskGraphicLabel* >( skinnable ); + + if ( label->hasPanel() ) + { + innerRect = label->subControlContentsRect( + innerRect, QskGraphicLabel::Panel ); + } + + return graphicRect( label, innerRect ); } return Inherited::subControlRect( skinnable, contentsRect, subControl ); @@ -40,6 +52,13 @@ QSGNode* QskGraphicLabelSkinlet::updateSubNode( switch ( nodeRole ) { + case PanelRole: + { + if ( !label->hasPanel() ) + return nullptr; + + return updateBoxNode( label, node, QskGraphicLabel::Panel ); + } case GraphicRole: { return updateGraphicNode( label, node ); @@ -52,6 +71,8 @@ QSGNode* QskGraphicLabelSkinlet::updateSubNode( QRect QskGraphicLabelSkinlet::graphicRect( const QskGraphicLabel* label, const QRectF& contentsRect ) const { + using Q = QskGraphicLabel; + // textures are in integers, to avoid useless recalculations // that finally will be rounded anyway, we calculate in integers @@ -59,18 +80,18 @@ QRect QskGraphicLabelSkinlet::graphicRect( const QRect graphicRect = contentsRect.toAlignedRect(); - if ( fillMode == QskGraphicLabel::Stretch ) + if ( fillMode == Q::Stretch ) { return graphicRect; } QSizeF sz = label->effectiveSourceSize(); - if ( fillMode == QskGraphicLabel::PreserveAspectFit ) + if ( fillMode == Q::PreserveAspectFit ) { sz.scale( graphicRect.size(), Qt::KeepAspectRatio ); } - else if ( fillMode == QskGraphicLabel::PreserveAspectCrop ) + else if ( fillMode == Q::PreserveAspectCrop ) { sz.scale( graphicRect.size(), Qt::KeepAspectRatioByExpanding ); } @@ -82,14 +103,16 @@ QRect QskGraphicLabelSkinlet::graphicRect( QSGNode* QskGraphicLabelSkinlet::updateGraphicNode( const QskGraphicLabel* label, QSGNode* node ) const { + using Q = QskGraphicLabel; + const auto colorFilter = label->graphicFilter(); - const auto rect = label->subControlRect( QskGraphicLabel::Graphic ); + const auto rect = label->subControlRect( Q::Graphic ); Qt::Orientations mirrored; if ( label->mirror() ) mirrored = Qt::Horizontal; - if ( label->fillMode() == QskGraphicLabel::Stretch ) + if ( label->fillMode() == Q::Stretch ) { node = QskSkinlet::updateGraphicNode( label, node, label->graphic(), colorFilter, rect, mirrored ); @@ -106,28 +129,57 @@ QSGNode* QskGraphicLabelSkinlet::updateGraphicNode( QSizeF QskGraphicLabelSkinlet::sizeHint( const QskSkinnable* skinnable, Qt::SizeHint which, const QSizeF& constraint ) const { + using Q = QskGraphicLabel; + if ( which != Qt::PreferredSize ) return QSizeF(); + const bool hasConstraint = + ( constraint.width() >= 0.0 ) || ( constraint.height() >= 0.0 ); + const auto label = static_cast< const QskGraphicLabel* >( skinnable ); + const auto sourceSize = label->effectiveSourceSize(); - auto sz = label->effectiveSourceSize(); + auto hint = sourceSize; - if ( !sz.isEmpty() ) + if ( hasConstraint && !sourceSize.isEmpty() ) { + auto innerConstraint = constraint; + + if ( label->hasPanel() ) + { + constexpr qreal max = std::numeric_limits< int >::max(); + + QRectF r( 0.0, 0.0, max, max ); + + if ( constraint.width() >= 0.0 ) + r.setWidth( constraint.width() ); + else + r.setHeight( constraint.height() ); + + innerConstraint = label->subControlContentsRect( r, Q::Panel ).size(); + } + + const qreal aspectRatio = sourceSize.width() / sourceSize.height(); + if ( constraint.width() >= 0.0 ) - { - sz.setHeight( sz.height() * constraint.width() / sz.width() ); - sz.setWidth( -1.0 ); - } - else if ( constraint.height() >= 0.0 ) - { - sz.setWidth( sz.width() * constraint.height() / sz.height() ); - sz.setHeight( -1.0 ); - } + hint.setHeight( innerConstraint.width() / aspectRatio ); + else + hint.setWidth( innerConstraint.height() * aspectRatio ); } - return sz; + hint = hint.expandedTo( label->strutSizeHint( Q::Graphic ) ); + + if ( label->hasPanel() ) + { + hint = label->outerBoxSize( Q::Panel, hint ); + hint = hint.expandedTo( label->strutSizeHint( Q::Panel ) ); + } + + if ( hasConstraint ) + hint = hintWithoutConstraint( hint, constraint ); + + return hint; } #include "moc_QskGraphicLabelSkinlet.cpp" diff --git a/src/controls/QskGraphicLabelSkinlet.h b/src/controls/QskGraphicLabelSkinlet.h index 8034a48b..393c8647 100644 --- a/src/controls/QskGraphicLabelSkinlet.h +++ b/src/controls/QskGraphicLabelSkinlet.h @@ -19,7 +19,7 @@ class QSK_EXPORT QskGraphicLabelSkinlet : public QskSkinlet public: enum NodeRole { - GraphicRole + PanelRole, GraphicRole }; Q_INVOKABLE QskGraphicLabelSkinlet( QskSkin* = nullptr ); diff --git a/src/controls/QskSkinlet.cpp b/src/controls/QskSkinlet.cpp index 2b6259ef..ea7a82b9 100644 --- a/src/controls/QskSkinlet.cpp +++ b/src/controls/QskSkinlet.cpp @@ -448,4 +448,22 @@ QSGNode* QskSkinlet::updateGraphicNode( return qskUpdateGraphicNode( skinnable, node, graphic, colorFilter, rect, mirrored ); } +QSizeF QskSkinlet::hintWithoutConstraint( + const QSizeF& hint, const QSizeF& constraint ) const +{ + /* + This method is useful in situations, where a hint has been calculated + from a constraint and we want to return the calculated part only + */ + QSizeF h; + + if ( constraint.width() < 0.0 ) + h.setWidth( hint.width() ); + + if ( constraint.height() < 0.0 ) + h.setHeight( hint.height() ); + + return h; +} + #include "moc_QskSkinlet.cpp" diff --git a/src/controls/QskSkinlet.h b/src/controls/QskSkinlet.h index 8aa8d379..9855f099 100644 --- a/src/controls/QskSkinlet.h +++ b/src/controls/QskSkinlet.h @@ -98,6 +98,9 @@ class QSK_EXPORT QskSkinlet void replaceChildNode( quint8 nodeRole, QSGNode* parentNode, QSGNode* oldNode, QSGNode* newNode ) const; + QSizeF hintWithoutConstraint( + const QSizeF& hint, const QSizeF& constraint ) const; + private: class PrivateData; std::unique_ptr< PrivateData > m_data; diff --git a/src/controls/QskTextLabel.h b/src/controls/QskTextLabel.h index 7957ecf2..9392014e 100644 --- a/src/controls/QskTextLabel.h +++ b/src/controls/QskTextLabel.h @@ -30,7 +30,7 @@ class QSK_EXPORT QskTextLabel : public QskControl WRITE setAlignment NOTIFY alignmentChanged ) Q_PROPERTY( bool panel READ hasPanel - WRITE setPanel NOTIFY panelChanged FINAL ) + WRITE setPanel NOTIFY panelChanged ) using Inherited = QskControl; diff --git a/src/controls/QskTextLabelSkinlet.cpp b/src/controls/QskTextLabelSkinlet.cpp index 618ff788..182f9009 100644 --- a/src/controls/QskTextLabelSkinlet.cpp +++ b/src/controls/QskTextLabelSkinlet.cpp @@ -32,7 +32,10 @@ QRectF QskTextLabelSkinlet::subControlRect( const QskSkinnable* skinnable, const auto label = static_cast< const QskTextLabel* >( skinnable ); if ( label->hasPanel() ) - return label->subControlContentsRect( contentsRect, QskTextLabel::Panel ); + { + return label->subControlContentsRect( + contentsRect, QskTextLabel::Panel ); + } return contentsRect; }