diff --git a/examples/automotive/ButtonBar.cpp b/examples/automotive/ButtonBar.cpp index 31a18d1e..7bd51859 100644 --- a/examples/automotive/ButtonBar.cpp +++ b/examples/automotive/ButtonBar.cpp @@ -61,7 +61,11 @@ void ButtonBar::addIndicator( const char* name ) label->setGraphic( QskGraphicIO::read( fileName ) ); } -QSizeF ButtonBar::contentsSizeHint() const +QSizeF ButtonBar::layoutSizeHint( + Qt::SizeHint which, const QSizeF& ) const { - return QSizeF( -1, 20 ); + if ( which == Qt::PreferredSize ) + return QSizeF( -1, 20 ); + + return QSizeF(); } diff --git a/examples/automotive/ButtonBar.h b/examples/automotive/ButtonBar.h index 666beae3..84f68473 100644 --- a/examples/automotive/ButtonBar.h +++ b/examples/automotive/ButtonBar.h @@ -17,7 +17,7 @@ class ButtonBar : public QskLinearBox void addIndicator( const char* name ); protected: - QSizeF contentsSizeHint() const override; + QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override; }; #endif diff --git a/examples/automotive/SoundControl.cpp b/examples/automotive/SoundControl.cpp index 07eb77de..e6296d19 100644 --- a/examples/automotive/SoundControl.cpp +++ b/examples/automotive/SoundControl.cpp @@ -132,8 +132,11 @@ class MarkerControlButton final : public QskPushButton } protected: - QSizeF contentsSizeHint() const override + QSizeF contentsSizeHint( Qt::SizeHint which, const QSizeF& ) const override { + if ( which != Qt::PreferredSize ) + return QSizeF(); + const qreal dim = 100; if ( m_direction == Qsk::LeftToRight || m_direction == Qsk::RightToLeft ) @@ -167,10 +170,15 @@ class ControlButton final : public QskPushButton return QskPushButton::effectiveSubcontrol( subControl ); } - QSizeF contentsSizeHint() const override + QSizeF contentsSizeHint( Qt::SizeHint which, const QSizeF& ) const override { - qreal h = QskPushButton::contentsSizeHint().height(); - return QSizeF( h, h ); + if ( which == Qt::PreferredSize ) + { + qreal h = QskPushButton::contentsSizeHint( which, QSizeF() ).height(); + return QSizeF( h, h ); + } + + return QSizeF(); } }; diff --git a/examples/layouts/DynamicConstraintsPage.cpp b/examples/layouts/DynamicConstraintsPage.cpp index 55b54bb5..4acd25d1 100644 --- a/examples/layouts/DynamicConstraintsPage.cpp +++ b/examples/layouts/DynamicConstraintsPage.cpp @@ -19,11 +19,11 @@ namespace Control( const char* colorName, QQuickItem* parent = nullptr ); Control( const char* colorName, qreal aspectRatio, QQuickItem* parent = nullptr ); - qreal heightForWidth( qreal width ) const override; - qreal widthForHeight( qreal height ) const override; - void transpose(); + protected: + QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override; + private: qreal m_aspectRatio; }; @@ -65,14 +65,19 @@ Control::Control( const char* colorName, qreal aspectRatio, QQuickItem* parent ) setPreferredHeight( 100 ); } -qreal Control::heightForWidth( qreal width ) const +QSizeF Control::contentsSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const { - return width / m_aspectRatio; -} + if ( which == Qt::PreferredSize ) + { + if ( constraint.width() >= 0.0 ) + return QSizeF( -1.0, constraint.width() / m_aspectRatio ); -qreal Control::widthForHeight( qreal height ) const -{ - return height * m_aspectRatio; + if ( constraint.height() >= 0.0 ) + return QSizeF( constraint.height() * m_aspectRatio, -1.0 ); + } + + return QSizeF(); } void Control::transpose() diff --git a/examples/mycontrols/MyToggleButton.cpp b/examples/mycontrols/MyToggleButton.cpp index ef7d0d99..b464c622 100644 --- a/examples/mycontrols/MyToggleButton.cpp +++ b/examples/mycontrols/MyToggleButton.cpp @@ -179,26 +179,33 @@ QskGraphic MyToggleButton::graphicAt( int index ) const return data.icon; } -QSizeF MyToggleButton::contentsSizeHint() const +QSizeF MyToggleButton::contentsSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const { - const qreal width = metric( Panel | QskAspect::MinimumWidth ); - const qreal height = metric( Panel | QskAspect::MinimumHeight ); + if ( which != Qt::PreferredSize ) + return QSizeF(); - return QSizeF( width, height ); -} + qreal w = constraint.width(); + qreal h = constraint.height(); -// better use Minimum Width/Height hints TODO ... + // better use Minimum Width/Height hints TODO ... + constexpr qreal aspectRatio = 4.0 / 3.0; -static constexpr qreal aspectRatio = 4.0 / 3.0; + if ( w >= 0.0 ) + { + h = w / aspectRatio; + } + else if ( h >= 0.0 ) + { + w = h * aspectRatio; + } + else + { + w = metric( Panel | QskAspect::MinimumWidth ); + h = metric( Panel | QskAspect::MinimumHeight ); + } -qreal MyToggleButton::heightForWidth( qreal width ) const -{ - return width / aspectRatio; -} - -qreal MyToggleButton::widthForHeight( qreal height ) const -{ - return height * aspectRatio; + return QSizeF( w, h ); } void MyToggleButton::updateLayout() diff --git a/examples/mycontrols/MyToggleButton.h b/examples/mycontrols/MyToggleButton.h index 6ec22ec0..305f8243 100644 --- a/examples/mycontrols/MyToggleButton.h +++ b/examples/mycontrols/MyToggleButton.h @@ -29,9 +29,6 @@ class MyToggleButton : public QskAbstractButton void setIconAt( int index, const QString& icon ); QString iconAt( int index ) const; - qreal heightForWidth( qreal width ) const override; - qreal widthForHeight( qreal height ) const override; - void setTextOptions( const QskTextOptions& ); QskTextOptions textOptions() const; @@ -45,7 +42,7 @@ class MyToggleButton : public QskAbstractButton protected: void updateLayout() override; - QSizeF contentsSizeHint() const override; + QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override; private: class PrivateData; diff --git a/examples/sliders/Slider.cpp b/examples/sliders/Slider.cpp index 8a695c02..9cde8bda 100644 --- a/examples/sliders/Slider.cpp +++ b/examples/sliders/Slider.cpp @@ -53,10 +53,15 @@ Slider::Slider( QQuickItem* parentItem ) this, &QskControl::focusIndicatorRectChanged ); } -QSizeF Slider::contentsSizeHint() const +QSizeF Slider::contentsSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const { - const qreal extra = 40; - return Inherited::contentsSizeHint() + QSizeF( 0, extra ); + auto size = Inherited::contentsSizeHint( which, constraint ); + + if ( which == Qt::PreferredSize && size.height() >= 0 ) + size.setHeight( size.height() + 40 ); + + return size; } QRectF Slider::focusIndicatorRect() const diff --git a/examples/sliders/Slider.h b/examples/sliders/Slider.h index 34276b58..ca22265a 100644 --- a/examples/sliders/Slider.h +++ b/examples/sliders/Slider.h @@ -20,7 +20,7 @@ class Slider : public QskSlider QRectF focusIndicatorRect() const override; protected: - QSizeF contentsSizeHint() const override; + QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override; }; #endif diff --git a/playground/anchors/AnchorBox.cpp b/playground/anchors/AnchorBox.cpp index 74d680f4..5e0b342a 100644 --- a/playground/anchors/AnchorBox.cpp +++ b/playground/anchors/AnchorBox.cpp @@ -10,7 +10,6 @@ #include "Variable.h" #include "Expression.h" -#include #include #include @@ -122,14 +121,18 @@ void AnchorBox::PrivateData::setupSolver( int type, Solver& solver ) if ( type < 0 || type == Qt::MinimumSize ) { - const auto minSize = QskLayoutConstraint::sizeHint( item, Qt::MinimumSize ); - solver.addConstraint( r.right >= r.left + minSize.width() ); - solver.addConstraint( r.bottom >= r.top + minSize.height() ); + const auto minSize = qskSizeConstraint( item, Qt::MinimumSize ); + + if ( minSize.width() >= 0.0 ) + solver.addConstraint( r.right >= r.left + minSize.width() ); + + if ( minSize.height() >= 0.0 ) + solver.addConstraint( r.bottom >= r.top + minSize.height() ); } if ( type < 0 || type == Qt::PreferredSize ) { - const auto prefSize = QskLayoutConstraint::sizeHint( item, Qt::PreferredSize ); + const auto prefSize = qskSizeConstraint( item, Qt::PreferredSize ); Constraint c1( r.right == r.left + prefSize.width(), Strength::strong ); solver.addConstraint( c1 ); @@ -140,11 +143,11 @@ void AnchorBox::PrivateData::setupSolver( int type, Solver& solver ) if ( type < 0 || type == Qt::MaximumSize ) { - const auto maxSize = QskLayoutConstraint::sizeHint( item, Qt::MaximumSize ); - if ( maxSize.width() < QskLayoutConstraint::unlimited ) + const auto maxSize = qskSizeConstraint( item, Qt::MaximumSize ); + if ( maxSize.width() >= 0.0 ) solver.addConstraint( r.right <= r.left + maxSize.width() ); - if ( maxSize.height() < QskLayoutConstraint::unlimited ) + if ( maxSize.height() >= 0.0 ) solver.addConstraint( r.bottom <= r.top + maxSize.height() ); } } diff --git a/src/common/QskSizePolicy.cpp b/src/common/QskSizePolicy.cpp index 246cd98e..ef7a35dc 100644 --- a/src/common/QskSizePolicy.cpp +++ b/src/common/QskSizePolicy.cpp @@ -19,6 +19,37 @@ void QskSizePolicy::setPolicy( Qt::Orientation orientation, Policy policy ) setVerticalPolicy( policy ); } +QskSizePolicy::ConstraintType QskSizePolicy::constraintType() const +{ + if ( horizontalPolicy() & ConstrainedFlag ) + return QskSizePolicy::WidthForHeight; + + if ( verticalPolicy() & ConstrainedFlag ) + return QskSizePolicy::HeightForWidth; + + return QskSizePolicy::Unconstrained; +} + +Qt::SizeHint QskSizePolicy::effectiveSizeHintType( + Qt::SizeHint which, Qt::Orientation orientation ) const +{ + const auto policy = ( orientation == Qt::Horizontal ) + ? horizontalPolicy() : verticalPolicy(); + + if ( which == Qt::MinimumSize ) + { + if ( !( policy & ShrinkFlag ) ) + return Qt::PreferredSize; + } + else if ( which == Qt::MaximumSize ) + { + if ( !( policy & ( GrowFlag | ExpandFlag ) ) ) + return Qt::PreferredSize; + } + + return which; +} + #ifndef QT_NO_DEBUG_STREAM #include diff --git a/src/common/QskSizePolicy.h b/src/common/QskSizePolicy.h index 031b8e33..bf031f6b 100644 --- a/src/common/QskSizePolicy.h +++ b/src/common/QskSizePolicy.h @@ -7,6 +7,7 @@ #define QSK_SIZE_POLICY_H_ #include "QskGlobal.h" +#include #include class QDebug; @@ -52,8 +53,17 @@ class QSK_EXPORT QskSizePolicy ConstrainedExpanding = ConstrainedFlag | Expanding }; + enum ConstraintType + { + Unconstrained = 0, + + WidthForHeight = 1 << 0, + HeightForWidth = 1 << 1 + }; + Q_ENUM( Flag ) Q_ENUM( Policy ) + Q_ENUM( ConstraintType ) QskSizePolicy(); QskSizePolicy( Policy horizontalPolicy, Policy verticalPolicy ); @@ -70,6 +80,12 @@ class QSK_EXPORT QskSizePolicy Policy policy( Qt::Orientation ) const; void setPolicy( Qt::Orientation, Policy ); + ConstraintType constraintType() const; + bool isConstrained( Qt::Orientation ) const; + + Qt::SizeHint effectiveSizeHintType( + Qt::SizeHint, Qt::Orientation ) const; + private: unsigned char m_horizontalPolicy; unsigned char m_verticalPolicy; @@ -119,6 +135,11 @@ inline QskSizePolicy::Policy QskSizePolicy::verticalPolicy() const return static_cast< Policy >( m_verticalPolicy ); } +inline bool QskSizePolicy::isConstrained( Qt::Orientation orientation ) const +{ + return ( policy( orientation ) & ConstrainedFlag ); +} + #ifndef QT_NO_DEBUG_STREAM QSK_EXPORT QDebug operator<<( QDebug, const QskSizePolicy& ); #endif diff --git a/src/controls/QskAnimationHint.h b/src/controls/QskAnimationHint.h index cfdb90ec..4a1f04a7 100644 --- a/src/controls/QskAnimationHint.h +++ b/src/controls/QskAnimationHint.h @@ -38,7 +38,7 @@ class QSK_EXPORT QskAnimationHint QEasingCurve::Type type = QEasingCurve::Linear ) noexcept : duration( duration ) , type( type ) - , updateFlags( UpdateAuto ) + , updateFlags( UpdateAuto ) { } diff --git a/src/controls/QskBox.cpp b/src/controls/QskBox.cpp index 19ae5a76..bed1ed0d 100644 --- a/src/controls/QskBox.cpp +++ b/src/controls/QskBox.cpp @@ -47,29 +47,17 @@ QRectF QskBox::layoutRectForSize( const QSizeF& size ) const return innerBox( Panel, subControlRect( size, Panel ) ); } -QSizeF QskBox::contentsSizeHint() const +QSizeF QskBox::contentsSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const { - if ( !m_hasPanel ) - return Inherited::contentsSizeHint(); - - QSizeF size( -1, -1 ); - - if ( autoLayoutChildren() ) + if ( m_hasPanel && which == Qt::PreferredSize ) { - const QSizeF hint = Inherited::contentsSizeHint(); - - if ( hint.width() > 0 ) - size.setWidth( hint.width() ); - - if ( hint.height() > 0 ) - size.setHeight( hint.height() ); + return QSizeF( + metric( Panel | QskAspect::MinimumWidth ), + metric( Panel | QskAspect::MinimumHeight ) ); } - const QSizeF minSize( - metric( Panel | QskAspect::MinimumWidth ), - metric( Panel | QskAspect::MinimumHeight ) ); - - return outerBoxSize( Panel, size ).expandedTo( minSize ); + return Inherited::contentsSizeHint( which, constraint ); } #include "moc_QskBox.cpp" diff --git a/src/controls/QskBox.h b/src/controls/QskBox.h index 4eeb8985..eb5019c7 100644 --- a/src/controls/QskBox.h +++ b/src/controls/QskBox.h @@ -27,15 +27,15 @@ class QSK_EXPORT QskBox : public QskControl void setPanel( bool ); bool hasPanel() const; - - QRectF layoutRectForSize( const QSizeF& ) const override; - protected: - QSizeF contentsSizeHint() const override; + QRectF layoutRectForSize( const QSizeF& ) const override; Q_SIGNALS: void panelChanged( bool ); + protected: + QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override; + private: bool m_hasPanel; }; diff --git a/src/controls/QskControl.cpp b/src/controls/QskControl.cpp index dbf31554..34f0c1fc 100644 --- a/src/controls/QskControl.cpp +++ b/src/controls/QskControl.cpp @@ -14,7 +14,7 @@ #include "QskSkin.h" #include "QskSkinlet.h" #include "QskSkinHintTable.h" -#include "QskLayoutConstraint.h" +#include "QskLayoutHint.h" #include #include @@ -374,7 +374,7 @@ void QskControl::setLayoutHint( LayoutHint flag, bool on ) d->layoutHints |= flag; else d->layoutHints &= ~flag; - + d->layoutConstraintChanged(); } } @@ -569,17 +569,17 @@ void QskControl::setExplicitSizeHint( QSizeF QskControl::explicitSizeHint( Qt::SizeHint whichHint ) const { - if ( whichHint >= Qt::MinimumSize && whichHint <= Qt::MaximumSize ) - return d_func()->explicitSizeHint( whichHint ); + if ( whichHint < Qt::MinimumSize || whichHint > Qt::MaximumSize ) + return QSizeF(); - return QSizeF( -1, -1 ); + return d_func()->explicitSizeHint( whichHint ); } QSizeF QskControl::implicitSizeHint( Qt::SizeHint whichHint, const QSizeF& constraint ) const { if ( whichHint < Qt::MinimumSize || whichHint > Qt::MaximumSize ) - return QSizeF( -1, -1 ); + return QSizeF(); if ( constraint.isValid() ) { @@ -587,108 +587,94 @@ QSizeF QskControl::implicitSizeHint( return constraint; } - QSizeF hint( -1, -1 ); + QSizeF hint; - if ( whichHint == Qt::PreferredSize ) + if ( whichHint == Qt::PreferredSize + && constraint.width() < 0.0 && constraint.height() < 0.0 ) { - if ( constraint.width() >= 0 ) - { - hint.setWidth( constraint.width() ); - hint.setHeight( heightForWidth( constraint.width() ) ); - } - else if ( constraint.height() >= 0 ) - { - hint.setWidth( widthForHeight( constraint.height() ) ); - hint.setHeight( constraint.height() ); - } - else - { - hint = implicitSize(); - } + // this one might be cached + hint = implicitSize(); } else { - // TODO ... + hint = d_func()->implicitSizeHint( whichHint, constraint ); } return hint; } QSizeF QskControl::effectiveSizeHint( - Qt::SizeHint whichHint, const QSizeF& constraint ) const + Qt::SizeHint which, const QSizeF& constraint ) const { - if ( whichHint < Qt::MinimumSize || whichHint > Qt::MaximumSize ) + if ( which < Qt::MinimumSize || which > Qt::MaximumSize ) return QSizeF( 0, 0 ); + if ( constraint.isValid() ) + return constraint; + + const bool isConstrained = + constraint.width() >= 0 || constraint.height() >= 0; + Q_D( const QskControl ); d->blockLayoutRequestEvents = false; - /* - The explicit size has always precedence over te implicit size. + QSizeF hint; - Implicit sizes are currently only implemented for preferred and - explicitSizeHint returns valid explicit hints for minimum/maximum - even if not being set by application code. + /* + The explicit size has always precedence over the implicit size, + and will kill the effect of the constraint */ - QSizeF hint = d->explicitSizeHint( whichHint ); + hint = d->explicitSizeHint( which ); if ( !hint.isValid() ) { -#if 0 - if ( hint.width() >= 0 && constraint.width() >= 0 ) - constraint.setWidth( hint.width() ); - - if ( hint.height() >= 0 && constraint.height() >= 0 ) - constraint.setHeight( hint.height() ); -#endif - - const auto implicit = implicitSizeHint( whichHint, constraint ); + const auto implicitHint = implicitSizeHint( which, constraint ); if ( hint.width() < 0 ) - hint.setWidth( implicit.width() ); + hint.setWidth( implicitHint.width() ); if ( hint.height() < 0 ) - hint.setHeight( implicit.height() ); + hint.setHeight( implicitHint.height() ); } - if ( hint.width() >= 0 || hint.height() >= 0 ) + if ( !isConstrained && ( hint.width() >= 0 || hint.height() >= 0 ) ) { /* - We might need to normalize the hints, so that + We normalize the unconstrained hints by the explicit hints, so that we always have: minimum <= preferred <= maximum. */ - if ( whichHint == Qt::MaximumSize ) + if ( which == Qt::MaximumSize ) { const auto minimumHint = d->explicitSizeHint( Qt::MinimumSize ); if ( hint.width() >= 0 ) - hint.setWidth( qMax( hint.width(), minimumHint.width() ) ); + hint.rwidth() = qMax( hint.width(), minimumHint.width() ); if ( hint.height() >= 0 ) - hint.setHeight( qMax( hint.height(), minimumHint.height() ) ); + hint.rheight() = qMax( hint.height(), minimumHint.height() ); } - else if ( whichHint == Qt::PreferredSize ) + else if ( which == Qt::PreferredSize ) { const auto minimumHint = d->explicitSizeHint( Qt::MinimumSize ); const auto maximumHint = d->explicitSizeHint( Qt::MaximumSize ); if ( hint.width() >= 0 ) { - const auto minW = minimumHint.width(); - const auto maxW = qMax( minW, maximumHint.width() ); + if ( maximumHint.width() >= 0 ) + hint.rwidth() = qMin( hint.width(), maximumHint.width() ); - hint.setWidth( qBound( minW, hint.width(), maxW ) ); + hint.rwidth() = qMax( hint.width(), minimumHint.width() ); } if ( hint.height() >= 0 ) { - const auto minH = minimumHint.height(); - const auto maxH = qMax( minH, maximumHint.height() ); + if ( maximumHint.height() >= 0 ) + hint.rheight() = qMin( hint.height(), maximumHint.height() ); - hint.setHeight( qBound( minH, hint.height(), maxH ) ); + hint.rheight() = qMax( hint.height(), minimumHint.height() ); } } } @@ -698,32 +684,18 @@ QSizeF QskControl::effectiveSizeHint( qreal QskControl::heightForWidth( qreal width ) const { - Q_D( const QskControl ); + const auto hint = effectiveSizeHint( + Qt::PreferredSize, QSizeF( width, -1.0 ) ); - d->blockLayoutRequestEvents = false; - - if ( d->autoLayoutChildren ) - { - using namespace QskLayoutConstraint; - return constrainedMetric( HeightForWidth, this, width, constrainedChildrenMetric ); - } - - return -1.0; + return hint.height(); } qreal QskControl::widthForHeight( qreal height ) const { - Q_D( const QskControl ); + const auto hint = effectiveSizeHint( + Qt::PreferredSize, QSizeF( -1.0, height ) ); - d->blockLayoutRequestEvents = false; - - if ( d->autoLayoutChildren ) - { - using namespace QskLayoutConstraint; - return constrainedMetric( WidthForHeight, this, height, constrainedChildrenMetric ); - } - - return -1.0; + return hint.width(); } bool QskControl::event( QEvent* event ) @@ -918,10 +890,8 @@ void QskControl::updateItemPolish() // checking qskIsVisibleToParent ??? if ( !qskIsTransparentForPositioner( child ) ) { - const auto itemRect = QskLayoutConstraint::boundedRect( - child, rect, QskLayoutConstraint::layoutAlignmentHint( child ) ); - - qskSetItemGeometry( child, itemRect ); + const auto r = qskConstrainedItemRect( child, rect ); + qskSetItemGeometry( child, r ); } } } @@ -978,26 +948,30 @@ void QskControl::updateResources() { } -QSizeF QskControl::contentsSizeHint() const +QSizeF QskControl::contentsSizeHint( + Qt::SizeHint, const QSizeF& constraint ) const { - qreal w = -1; // no hint - qreal h = -1; + return constraint; +} - if ( d_func()->autoLayoutChildren ) +QSizeF QskControl::layoutSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const +{ + if ( !d_func()->autoLayoutChildren ) + return QSizeF(); + + qreal w = constraint.width(); + qreal h = constraint.height(); + + const auto children = childItems(); + for ( const auto child : children ) { - const auto children = childItems(); - for ( const auto child : children ) + if ( qskIsVisibleToLayout( child ) ) { - if ( auto control = qskControlCast( child ) ) - { - if ( !control->isTransparentForPositioner() ) - { - const QSizeF hint = control->sizeHint(); + const auto hint = qskEffectiveSizeHint( child, which, constraint ); - w = qMax( w, hint.width() ); - h = qMax( h, hint.height() ); - } - } + w = QskLayoutHint::combined( which, w, hint.width() ); + h = QskLayoutHint::combined( which, h, hint.height() ); } } diff --git a/src/controls/QskControl.h b/src/controls/QskControl.h index 36060b08..01e48661 100644 --- a/src/controls/QskControl.h +++ b/src/controls/QskControl.h @@ -152,12 +152,12 @@ class QSK_EXPORT QskControl : public QskQuickItem, public QskSkinnable QSizeF implicitSizeHint( Qt::SizeHint, const QSizeF& constraint ) const; QSizeF sizeHint() const; + qreal heightForWidth( qreal width ) const; + qreal widthForHeight( qreal height ) const; + QSizeF effectiveSizeHint( Qt::SizeHint, const QSizeF& constraint = QSizeF() ) const; - virtual qreal heightForWidth( qreal width ) const; - virtual qreal widthForHeight( qreal height ) const; - QLocale locale() const; void resetLocale(); @@ -195,8 +195,8 @@ class QSK_EXPORT QskControl : public QskQuickItem, public QskSkinnable virtual void updateResources(); virtual void updateLayout(); - protected: - virtual QSizeF contentsSizeHint() const; + virtual QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const; + virtual QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const; private: void setActiveFocusOnTab( bool ) = delete; // use setFocusPolicy diff --git a/src/controls/QskControlPrivate.cpp b/src/controls/QskControlPrivate.cpp index 8b483278..a3d3d009 100644 --- a/src/controls/QskControlPrivate.cpp +++ b/src/controls/QskControlPrivate.cpp @@ -5,7 +5,7 @@ #include "QskControlPrivate.h" #include "QskSetup.h" -#include "QskLayoutConstraint.h" +#include "QskLayoutHint.h" static inline void qskSendEventTo( QObject* object, QEvent::Type type ) { @@ -71,7 +71,7 @@ void QskControlPrivate::layoutConstraintChanged() void QskControlPrivate::implicitSizeChanged() { - if ( !q_func()->explicitSizeHint( Qt::PreferredSize ).isValid() ) + if ( !( explicitSizeHints && explicitSizeHints[ Qt::PreferredSize ].isValid() ) ) { // when we have no explit size, the implicit size matters layoutConstraintChanged(); @@ -79,17 +79,95 @@ void QskControlPrivate::implicitSizeChanged() } QSizeF QskControlPrivate::implicitSizeHint() const +{ + return implicitSizeHint( Qt::PreferredSize, QSizeF() ); +} + +QSizeF QskControlPrivate::implicitSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const { Q_Q( const QskControl ); - const auto m = q->margins(); - const auto dw = m.left() + m.right(); - const auto dh = m.top() + m.bottom(); + /* + The hint is calculated from the contents ( usually scene graph nodes ) + and - when being a container - the children. + */ + QSizeF contentsHint; - const auto hint = q->contentsSizeHint(); + { + const auto m = q->margins(); + const auto dw = m.left() + m.right(); + const auto dh = m.top() + m.bottom(); - const qreal w = ( hint.width() >= 0 ) ? dw + hint.width() : -1.0; - const qreal h = ( hint.height() >= 0 ) ? dh + hint.height() : -1.0; + if ( constraint.width() >= 0.0 ) + { + contentsHint.setWidth( qMax( constraint.width() - dw, 0.0 ) ); + } + else if ( constraint.height() >= 0.0 ) + { + contentsHint.setHeight( qMax( constraint.height() - dh, 0.0 ) ); + } + + contentsHint = q->contentsSizeHint( which, contentsHint ); + + if ( contentsHint.rwidth() >= 0 ) + contentsHint.rwidth() += dw; + + if ( contentsHint.rheight() >= 0 ) + contentsHint.rheight() += dh; + } + + QSizeF layoutHint; + { + if ( constraint.width() >= 0.0 ) + { + const QSizeF boundingSize( constraint.width(), 1e6 ); + const QSizeF layoutSize = q->layoutRectForSize( boundingSize ).size(); + + layoutHint = q->layoutSizeHint( which, QSizeF( layoutSize.width(), -1 ) ); + + if ( layoutHint.height() >= 0 ) + layoutHint.rheight() += boundingSize.height() - layoutSize.height(); + } + else if ( constraint.height() >= 0.0 ) + { + const QSizeF boundingSize( 1e6, constraint.height() ); + const QSizeF layoutSize = q->layoutRectForSize( boundingSize ).size(); + + layoutHint = q->layoutSizeHint( which, QSizeF( -1, layoutSize.height() ) ); + + if ( layoutHint.width() >= 0 ) + layoutHint.rwidth() += boundingSize.width() - layoutSize.width(); + } + else + { + /* + In situations, where layoutRectForSize depends on + the size ( f.e when using a corner radius of Qt::RelativeSize ) + we will have wrong results. TODO ... + */ + const QSizeF boundingSize( 1000.0, 1000.0 ); + const QSizeF layoutSize = q->layoutRectForSize( boundingSize ).size(); + + layoutHint = q->layoutSizeHint( which, QSizeF() ); + + if ( layoutHint.width() >= 0 ) + layoutHint.rwidth() += boundingSize.width() - layoutSize.width(); + + if ( layoutHint.height() >= 0 ) + layoutHint.rheight() += boundingSize.height() - layoutSize.height(); + } + } + + // Combining both hints + qreal w = constraint.width(); + qreal h = constraint.height(); + + if ( w < 0.0 ) + w = QskLayoutHint::combined( which, contentsHint.width(), layoutHint.width() ); + + if ( h < 0.0 ) + h = QskLayoutHint::combined( which, contentsHint.height(), layoutHint.height() ); return QSizeF( w, h ); } @@ -98,14 +176,7 @@ void QskControlPrivate::setExplicitSizeHint( Qt::SizeHint whichHint, const QSizeF& size ) { if ( explicitSizeHints == nullptr ) - { - using namespace QskLayoutConstraint; - explicitSizeHints = new QSizeF[3]; - explicitSizeHints[0] = defaultSizeHints[0]; - explicitSizeHints[1] = defaultSizeHints[1]; - explicitSizeHints[2] = defaultSizeHints[2]; - } explicitSizeHints[ whichHint ] = size; } @@ -113,10 +184,7 @@ void QskControlPrivate::setExplicitSizeHint( void QskControlPrivate::resetExplicitSizeHint( Qt::SizeHint whichHint ) { if ( explicitSizeHints ) - { - using namespace QskLayoutConstraint; - explicitSizeHints[ whichHint ] = defaultSizeHints[ whichHint ]; - } + explicitSizeHints[ whichHint ] = QSizeF(); } QSizeF QskControlPrivate::explicitSizeHint( Qt::SizeHint whichHint ) const @@ -124,7 +192,7 @@ QSizeF QskControlPrivate::explicitSizeHint( Qt::SizeHint whichHint ) const if ( explicitSizeHints ) return explicitSizeHints[ whichHint ]; - return QskLayoutConstraint::defaultSizeHints[ whichHint ]; + return QSizeF(); } bool QskControlPrivate::maybeGesture( QQuickItem* child, QEvent* event ) diff --git a/src/controls/QskControlPrivate.h b/src/controls/QskControlPrivate.h index 7c9365be..4f012b3e 100644 --- a/src/controls/QskControlPrivate.h +++ b/src/controls/QskControlPrivate.h @@ -30,12 +30,14 @@ class QskControlPrivate : public QskQuickItemPrivate void resetExplicitSizeHint( Qt::SizeHint ); QSizeF explicitSizeHint( Qt::SizeHint ) const; - bool maybeGesture( QQuickItem*, QEvent* ); - + QSizeF implicitSizeHint( Qt::SizeHint, const QSizeF& ) const; QSizeF implicitSizeHint() const override final; + void implicitSizeChanged() override final; void layoutConstraintChanged() override final; + bool maybeGesture( QQuickItem*, QEvent* ); + private: Q_DECLARE_PUBLIC( QskControl ) diff --git a/src/controls/QskFocusIndicator.cpp b/src/controls/QskFocusIndicator.cpp index 522ffe71..c5fb2355 100644 --- a/src/controls/QskFocusIndicator.cpp +++ b/src/controls/QskFocusIndicator.cpp @@ -50,7 +50,7 @@ QskFocusIndicator::~QskFocusIndicator() { } -bool QskFocusIndicator::contains( const QPointF & ) const +bool QskFocusIndicator::contains( const QPointF& ) const { return false; } diff --git a/src/controls/QskFocusIndicator.h b/src/controls/QskFocusIndicator.h index 5074bae2..a67f6c4b 100644 --- a/src/controls/QskFocusIndicator.h +++ b/src/controls/QskFocusIndicator.h @@ -22,7 +22,7 @@ class QSK_EXPORT QskFocusIndicator : public QskControl QskFocusIndicator( QQuickItem* parent = nullptr ); ~QskFocusIndicator() override; - bool contains( const QPointF & ) const override; + bool contains( const QPointF& ) const override; protected: void windowChangeEvent( QskWindowChangeEvent* ) override; diff --git a/src/controls/QskGestureRecognizer.cpp b/src/controls/QskGestureRecognizer.cpp index a2a8f084..1925bd7b 100644 --- a/src/controls/QskGestureRecognizer.cpp +++ b/src/controls/QskGestureRecognizer.cpp @@ -449,7 +449,7 @@ void QskGestureRecognizer::reject() m_data->isReplayingEvents = true; if ( window->mouseGrabberItem() == watchedItem ) - watchedItem->ungrabMouse(); + watchedItem->ungrabMouse(); if ( !events.isEmpty() && ( events[ 0 ]->type() == QEvent::MouseButtonPress ) ) diff --git a/src/controls/QskGraphicLabel.cpp b/src/controls/QskGraphicLabel.cpp index 94addfd1..6b2e999b 100644 --- a/src/controls/QskGraphicLabel.cpp +++ b/src/controls/QskGraphicLabel.cpp @@ -248,27 +248,29 @@ void QskGraphicLabel::updateLayout() m_data->isSourceDirty = false; } -qreal QskGraphicLabel::heightForWidth( qreal width ) const +QSizeF QskGraphicLabel::contentsSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const { - const QSizeF sz = effectiveSourceSize(); - if ( sz.isEmpty() ) - return 0; + if ( which != Qt::PreferredSize ) + return QSizeF(); - return sz.height() * width / sz.width(); -} + auto sz = effectiveSourceSize(); -qreal QskGraphicLabel::widthForHeight( qreal height ) const -{ - const QSizeF sz = effectiveSourceSize(); - if ( sz.isEmpty() ) - return 0; + if ( !sz.isEmpty() ) + { + if ( constraint.width() >= 0.0 ) + { + sz.setHeight( sz.height() * constraint.width() / sz.width() ); + sz.setWidth( constraint.width() ); + } + else if ( constraint.height() >= 0.0 ) + { + sz.setWidth( sz.width() * constraint.height() / sz.height() ); + sz.setHeight( constraint.height() ); + } + } - return sz.width() * height / sz.height(); -} - -QSizeF QskGraphicLabel::contentsSizeHint() const -{ - return effectiveSourceSize(); + return sz; } QSizeF QskGraphicLabel::effectiveSourceSize() const diff --git a/src/controls/QskGraphicLabel.h b/src/controls/QskGraphicLabel.h index 2c4aa93c..4a07b798 100644 --- a/src/controls/QskGraphicLabel.h +++ b/src/controls/QskGraphicLabel.h @@ -77,9 +77,6 @@ class QSK_EXPORT QskGraphicLabel : public QskControl void setFillMode( FillMode ); FillMode fillMode() const; - qreal heightForWidth( qreal width ) const override; - qreal widthForHeight( qreal height ) const override; - bool isEmpty() const; void setGraphicRole( int role ); @@ -99,10 +96,11 @@ class QSK_EXPORT QskGraphicLabel : public QskControl protected: void changeEvent( QEvent* ) override; void updateLayout() override; - - QSizeF contentsSizeHint() const override; virtual QskGraphic loadSource( const QUrl& ) const; + QSizeF contentsSizeHint( + Qt::SizeHint, const QSizeF& constraint ) const override; + private: class PrivateData; std::unique_ptr< PrivateData > m_data; diff --git a/src/controls/QskListView.cpp b/src/controls/QskListView.cpp index 3cd6287e..fc644160 100644 --- a/src/controls/QskListView.cpp +++ b/src/controls/QskListView.cpp @@ -153,13 +153,18 @@ QskAspect::Subcontrol QskListView::textSubControlAt( int row, int col ) const return ( row == selectedRow() ) ? TextSelected : Text; } -QSizeF QskListView::contentsSizeHint() const +QSizeF QskListView::contentsSizeHint( + Qt::SizeHint which, const QSizeF& ) const { qreal w = -1.0; // shouldn't we return something ??? - if ( m_data->preferredWidthFromColumns ) + + if ( which != Qt::MaximumSize ) { - w = scrollableSize().width(); - w += metric( QskScrollView::VerticalScrollBar ); + if ( m_data->preferredWidthFromColumns ) + { + w = scrollableSize().width(); + w += metric( QskScrollView::VerticalScrollBar ); + } } return QSizeF( w, -1.0 ); diff --git a/src/controls/QskListView.h b/src/controls/QskListView.h index acc17569..d76d56e7 100644 --- a/src/controls/QskListView.h +++ b/src/controls/QskListView.h @@ -98,8 +98,8 @@ class QSK_EXPORT QskListView : public QskScrollView void mouseReleaseEvent( QMouseEvent* ) override; void updateScrollableSize(); - QSizeF contentsSizeHint() const override; + QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override; void componentComplete() override; private: diff --git a/src/controls/QskPageIndicator.cpp b/src/controls/QskPageIndicator.cpp index eb68bfcb..ec5d285b 100644 --- a/src/controls/QskPageIndicator.cpp +++ b/src/controls/QskPageIndicator.cpp @@ -97,8 +97,12 @@ void QskPageIndicator::setCurrentIndex( qreal index ) } } -QSizeF QskPageIndicator::contentsSizeHint() const +QSizeF QskPageIndicator::contentsSizeHint( + Qt::SizeHint which, const QSizeF& ) const { + if ( which != Qt::PreferredSize ) + return QSizeF(); + using namespace QskAspect; const qreal sizeBullet = metric( Bullet | Size ); diff --git a/src/controls/QskPageIndicator.h b/src/controls/QskPageIndicator.h index 507329c7..690afb5c 100644 --- a/src/controls/QskPageIndicator.h +++ b/src/controls/QskPageIndicator.h @@ -50,7 +50,7 @@ class QSK_EXPORT QskPageIndicator : public QskControl void setCurrentIndex( qreal index ); protected: - QSizeF contentsSizeHint() const override; + QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override; private: class PrivateData; diff --git a/src/controls/QskPopup.cpp b/src/controls/QskPopup.cpp index 55c51618..af8b05f1 100644 --- a/src/controls/QskPopup.cpp +++ b/src/controls/QskPopup.cpp @@ -256,7 +256,7 @@ void QskPopup::updateInputGrabber() /* In QQuickWindowPrivate::deliverPressOrReleaseEvent ( 5.12 ) might crash, when we delete the grabber as a result of a - mouse event somewehere below the popup. + mouse event somewehere below the popup. */ m_data->inputGrabber->setParentItem( nullptr ); m_data->inputGrabber->setParent( nullptr ); diff --git a/src/controls/QskPushButton.cpp b/src/controls/QskPushButton.cpp index ae495655..e2b1ec58 100644 --- a/src/controls/QskPushButton.cpp +++ b/src/controls/QskPushButton.cpp @@ -250,8 +250,11 @@ QRectF QskPushButton::layoutRectForSize( const QSizeF& size ) const return innerBox( Panel, subControlRect( size, Panel ) ); } -QSizeF QskPushButton::contentsSizeHint() const +QSizeF QskPushButton::contentsSizeHint( Qt::SizeHint which, const QSizeF& ) const { + if ( which != Qt::PreferredSize ) + return QSizeF(); + QSizeF size( 0, 0 ); const QFontMetricsF fm( font() ); diff --git a/src/controls/QskPushButton.h b/src/controls/QskPushButton.h index 28b58f94..4818880f 100644 --- a/src/controls/QskPushButton.h +++ b/src/controls/QskPushButton.h @@ -63,6 +63,7 @@ class QSK_EXPORT QskPushButton : public QskAbstractButton bool isFlat() const; QFont font() const; + QRectF layoutRectForSize( const QSizeF& ) const override; public Q_SLOTS: @@ -90,10 +91,10 @@ class QSK_EXPORT QskPushButton : public QskAbstractButton void changeEvent( QEvent* ) override; void updateLayout() override; - QSizeF contentsSizeHint() const override; - virtual QskGraphic loadGraphic( const QUrl& ) const; + QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override; + private: class PrivateData; std::unique_ptr< PrivateData > m_data; diff --git a/src/controls/QskQuick.cpp b/src/controls/QskQuick.cpp index 6bc8c301..e07063f7 100644 --- a/src/controls/QskQuick.cpp +++ b/src/controls/QskQuick.cpp @@ -5,6 +5,7 @@ #include "QskQuick.h" #include "QskControl.h" +#include "QskFunctions.h" #include QSK_QT_PRIVATE_BEGIN @@ -142,11 +143,68 @@ bool qskIsTransparentForPositioner( const QQuickItem* item ) return QQuickItemPrivate::get( item )->isTransparentForPositioner(); } +bool qskIsVisibleToLayout( const QQuickItem* item ) +{ + if ( item ) + { + const auto d = QQuickItemPrivate::get( item ); + return !d->isTransparentForPositioner() + && ( d->explicitVisible || qskRetainSizeWhenHidden( item ) ); + } + + return false; +} + +QskSizePolicy qskSizePolicy( const QQuickItem* item ) +{ + if ( auto control = qskControlCast( item ) ) + return control->sizePolicy(); + + if ( item ) + { + const QVariant v = item->property( "sizePolicy" ); + if ( v.canConvert< QskSizePolicy >() ) + return qvariant_cast< QskSizePolicy >( v ); + } + + return QskSizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Preferred ); +} + +Qt::Alignment qskLayoutAlignmentHint( const QQuickItem* item ) +{ + if ( auto control = qskControlCast( item ) ) + return control->layoutAlignmentHint(); + + if ( item ) + { + const QVariant v = item->property( "layoutAlignmentHint" ); + if ( v.canConvert< Qt::Alignment >() ) + return v.value< Qt::Alignment >(); + } + + return Qt::Alignment(); +} + +bool qskRetainSizeWhenHidden( const QQuickItem* item ) +{ + if ( auto control = qskControlCast( item ) ) + return control->layoutHints() & QskControl::RetainSizeWhenHidden; + + if ( item ) + { + const QVariant v = item->property( "retainSizeWhenHidden" ); + if ( v.canConvert< bool >() ) + return v.value< bool >(); + } + + return false; +} + QQuickItem* qskNearestFocusScope( const QQuickItem* item ) { if ( item ) { - for ( QQuickItem* scope = item->parentItem(); + for ( auto scope = item->parentItem(); scope != nullptr; scope = scope->parentItem() ) { if ( scope->isFocusScope() ) @@ -290,3 +348,224 @@ const QSGNode* qskPaintNode( const QQuickItem* item ) return QQuickItemPrivate::get( item )->paintNode; } + +QSizeF qskEffectiveSizeHint( const QQuickItem* item, + Qt::SizeHint whichHint, const QSizeF& constraint ) +{ + if ( auto control = qskControlCast( item ) ) + return control->effectiveSizeHint( whichHint, constraint ); + + if ( constraint.width() >= 0.0 || constraint.height() >= 0.0 ) + { + // QQuickItem does not support dynamic constraints + return constraint; + } + + if ( item == nullptr ) + return QSizeF(); + + /* + Trying to retrieve something useful for non QskControls: + + First are checking some properties, that usually match the + names for the explicit hints. For the implicit hints we only + have the implicitSize, what is interpreted as the implicit + preferred size. + */ + QSizeF hint; + + static const char* properties[] = + { + "minimumSize", + "preferredSize", + "maximumSize" + }; + + const QVariant v = item->property( properties[ whichHint ] ); + if ( v.canConvert( QMetaType::QSizeF ) ) + hint = v.toSizeF(); + + if ( whichHint == Qt::PreferredSize ) + { + if ( hint.width() < 0 ) + hint.setWidth( item->implicitWidth() ); + + if ( hint.height() < 0 ) + hint.setHeight( item->implicitHeight() ); + } + + return hint; +} + +static QSizeF qskBoundedConstraint( const QQuickItem* item, + const QSizeF& constraint, QskSizePolicy policy ) +{ + Qt::Orientation orientation; + + if ( constraint.width() >= 0.0 ) + { + orientation = Qt::Horizontal; + } + else if ( constraint.height() >= 0.0 ) + { + orientation = Qt::Vertical; + } + else + { + return constraint; + } + + const auto whichMin = policy.effectiveSizeHintType( Qt::MinimumSize, orientation ); + const auto whichMax = policy.effectiveSizeHintType( Qt::MaximumSize, orientation ); + + const auto hintMin = qskEffectiveSizeHint( item, whichMin ); + const auto hintMax = ( whichMax == whichMin ) + ? hintMin : qskEffectiveSizeHint( item, whichMax ); + + QSizeF size; + + if ( orientation == Qt::Horizontal ) + { + if ( hintMax.width() >= 0.0 ) + size.rwidth() = qMin( constraint.width(), hintMax.width() ); + + size.rwidth() = qMax( constraint.width(), hintMin.width() ); + } + else + { + if ( hintMax.height() >= 0.0 ) + size.rheight() = qMin( constraint.height(), hintMax.height() ); + + size.rheight() = qMax( constraint.height(), hintMin.height() ); + + } + + return size; +} + +QSizeF qskSizeConstraint( const QQuickItem* item, + Qt::SizeHint which, const QSizeF& constraint ) +{ + if ( item == nullptr ) + return QSizeF( 0, 0 ); + + if ( constraint.isValid() ) + return constraint; + + const auto policy = qskSizePolicy( item ); + + const auto whichH = policy.effectiveSizeHintType( which, Qt::Horizontal ); + const auto whichV = policy.effectiveSizeHintType( which, Qt::Vertical ); + + QSizeF size; + + int constraintType = QskSizePolicy::Unconstrained; + + if ( constraint.height() >= 0.0 ) + { + const auto c = qskBoundedConstraint( item, constraint, policy ); + size = qskEffectiveSizeHint( item, whichV, c ); + + if ( ( whichH != whichV ) || ( size.height() != c.height() ) ) + constraintType = QskSizePolicy::WidthForHeight; + } + else if ( constraint.width() >= 0.0 ) + { + const auto c = qskBoundedConstraint( item, constraint, policy ); + size = qskEffectiveSizeHint( item, whichH, c ); + + if ( ( whichV != whichH ) || ( size.width() != c.height() ) ) + constraintType = QskSizePolicy::HeightForWidth; + } + else + { + constraintType = policy.constraintType(); + + switch( constraintType ) + { + case QskSizePolicy::WidthForHeight: + { + size = qskEffectiveSizeHint( item, whichV ); + break; + } + case QskSizePolicy::HeightForWidth: + { + size = qskEffectiveSizeHint( item, whichH ); + break; + } + default: + { + size = qskEffectiveSizeHint( item, whichH ); + + if ( whichV != whichH ) + constraintType = QskSizePolicy::HeightForWidth; + } + } + } + + switch( constraintType ) + { + case QskSizePolicy::HeightForWidth: + { + const QSizeF c( size.width(), -1.0 ); + size.setHeight( qskEffectiveSizeHint( item, whichV, c ).height() ); + break; + } + case QskSizePolicy::WidthForHeight: + { + const QSizeF c( -1.0, size.height() ); + size.setWidth( qskEffectiveSizeHint( item, whichH, c ).width() ); + break; + } + } + + return size; +} + +QSizeF qskConstrainedItemSize( const QQuickItem* item, const QSizeF& size ) +{ + QSizeF constraint; + + switch( static_cast< int >( qskSizePolicy( item ).constraintType() ) ) + { + case QskSizePolicy::WidthForHeight: + { + constraint.setHeight( size.height() ); + break; + } + case QskSizePolicy::HeightForWidth: + { + constraint.setWidth( size.width() ); + break; + } + } + + const auto max = qskSizeConstraint( item, Qt::MaximumSize, constraint ); + + qreal width = size.width(); + qreal height = size.height(); + + if ( max.width() >= 0.0 ) + width = qMin( width, max.width() ); + + if ( max.height() >= 0.0 ) + height = qMin( height, max.height() ); + +#if 1 + const auto min = qskSizeConstraint( item, Qt::MinimumSize, constraint ); + + width = qMax( width, min.width() ); + height = qMax( height, min.height() ); +#endif + + return QSizeF( width, height ); +} + +QRectF qskConstrainedItemRect( const QQuickItem* item, + const QRectF& rect, Qt::Alignment alignment ) +{ + const auto size = qskConstrainedItemSize( item, rect.size() ); + return qskAlignedRectF( rect, size.width(), size.height(), alignment ); +} + + diff --git a/src/controls/QskQuick.h b/src/controls/QskQuick.h index 8645b494..be5a039a 100644 --- a/src/controls/QskQuick.h +++ b/src/controls/QskQuick.h @@ -10,6 +10,8 @@ #include #include +class QskSizePolicy; + class QQuickItem; class QSGNode; class QRectF; @@ -30,6 +32,21 @@ QSK_EXPORT bool qskIsPolishScheduled( const QQuickItem* ); QSK_EXPORT void qskSetTransparentForPositioner( QQuickItem*, bool ); QSK_EXPORT bool qskIsTransparentForPositioner( const QQuickItem* ); +QSK_EXPORT bool qskIsVisibleToLayout( const QQuickItem* ); + +QSK_EXPORT QSizeF qskEffectiveSizeHint( const QQuickItem*, + Qt::SizeHint, const QSizeF& constraint = QSizeF() ); + +QSK_EXPORT QSizeF qskSizeConstraint( const QQuickItem*, + Qt::SizeHint, const QSizeF& constraint = QSizeF() ); + +QSK_EXPORT QSizeF qskConstrainedItemSize( const QQuickItem*, const QSizeF& ); +QSK_EXPORT QRectF qskConstrainedItemRect( + const QQuickItem*, const QRectF&, Qt::Alignment ); + +QSK_EXPORT QskSizePolicy qskSizePolicy( const QQuickItem* ); +QSK_EXPORT Qt::Alignment qskLayoutAlignmentHint( const QQuickItem* ); +QSK_EXPORT bool qskRetainSizeWhenHidden( const QQuickItem* ); QSK_EXPORT QRectF qskItemRect( const QQuickItem* ); @@ -69,7 +86,26 @@ template< typename T > inline T qskFindAncestorOf( const QQuickItem* item ) { return qskFindAncestorOf< std::remove_const< T > >( - const_cast< QQuickItem * >( item ) ); + const_cast< QQuickItem* >( item ) ); +} + +inline qreal qskHeightForWidth( + const QQuickItem* item, Qt::SizeHint which, qreal width ) +{ + return qskEffectiveSizeHint( + item, which, QSizeF( width, -1.0 ) ).height(); +} + +inline qreal qskWidthForHeight( + const QQuickItem* item, Qt::SizeHint which, qreal height ) +{ + return qskEffectiveSizeHint( + item, which, QSizeF( -1.0, height ) ).width(); +} + +inline QRectF qskConstrainedItemRect( const QQuickItem* item, const QRectF& rect ) +{ + return qskConstrainedItemRect( item, rect, qskLayoutAlignmentHint( item ) ); } #endif diff --git a/src/controls/QskScrollArea.cpp b/src/controls/QskScrollArea.cpp index 2fd248f6..113afd42 100644 --- a/src/controls/QskScrollArea.cpp +++ b/src/controls/QskScrollArea.cpp @@ -5,7 +5,6 @@ #include "QskScrollArea.h" #include "QskEvent.h" -#include "QskLayoutConstraint.h" #include "QskQuick.h" #include "QskScrollViewSkinlet.h" @@ -423,7 +422,7 @@ void QskScrollArea::updateLayout() void QskScrollArea::adjustItem() { - QQuickItem* item = m_data->clipItem->scrolledItem(); + auto item = m_data->clipItem->scrolledItem(); if ( item == nullptr ) { @@ -434,7 +433,7 @@ void QskScrollArea::adjustItem() { if ( m_data->isItemResizable ) { - const QRectF rect = viewContentsRect(); + auto size = viewContentsRect().size(); #if 0 /* @@ -443,13 +442,13 @@ void QskScrollArea::adjustItem() moment we ignore this and start with a simplified code. */ #endif - const auto newSize = QskLayoutConstraint::boundedSize( item, rect.size() ); - item->setSize( newSize ); + size = qskConstrainedItemSize( item, size ); + item->setSize( size ); } m_data->enableAutoTranslation( this, false ); - setScrollableSize( QSizeF( item->width(), item->height() ) ); + setScrollableSize( item->size() ); setScrollPos( scrollPos() ); m_data->enableAutoTranslation( this, true ); diff --git a/src/controls/QskSeparator.cpp b/src/controls/QskSeparator.cpp index 8e1905f4..435d2aab 100644 --- a/src/controls/QskSeparator.cpp +++ b/src/controls/QskSeparator.cpp @@ -70,8 +70,12 @@ qreal QskSeparator::thickness() const return metric( QskSeparator::Panel | QskAspect::Size ); } -QSizeF QskSeparator::contentsSizeHint() const +QSizeF QskSeparator::contentsSizeHint( + Qt::SizeHint which, const QSizeF& ) const { + if ( which != Qt::PreferredSize ) + return QSizeF(); + const qreal m = thickness(); if ( m_orientation == Qt::Horizontal ) diff --git a/src/controls/QskSeparator.h b/src/controls/QskSeparator.h index 13ca4b31..e95a3d48 100644 --- a/src/controls/QskSeparator.h +++ b/src/controls/QskSeparator.h @@ -41,7 +41,7 @@ class QSK_EXPORT QskSeparator : public QskControl void thicknessChanged(); protected: - QSizeF contentsSizeHint() const override; + QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override; private: Qt::Orientation m_orientation; diff --git a/src/controls/QskSkin.cpp b/src/controls/QskSkin.cpp index adbe31c8..0c6d9c16 100644 --- a/src/controls/QskSkin.cpp +++ b/src/controls/QskSkin.cpp @@ -74,21 +74,21 @@ QSK_QT_PRIVATE_END #include "QskStatusIndicator.h" #include "QskStatusIndicatorSkinlet.h" -static inline QskSkinlet *qskNewSkinlet( const QMetaObject* metaObject, QskSkin* skin ) +static inline QskSkinlet* qskNewSkinlet( const QMetaObject* metaObject, QskSkin* skin ) { const QByteArray signature = metaObject->className() + QByteArrayLiteral( "(QskSkin*)" ); - QskSkinlet *skinlet = nullptr; + QskSkinlet* skinlet = nullptr; const int index = metaObject->indexOfConstructor( signature.constData() ); if ( index >= 0 ) { - void *param[] = { &skinlet, &skin }; + void* param[] = { &skinlet, &skin }; metaObject->static_metacall( QMetaObject::CreateInstance, index, param ); } return skinlet; -} +} namespace { diff --git a/src/controls/QskSlider.cpp b/src/controls/QskSlider.cpp index 7c3f79fb..060591e8 100644 --- a/src/controls/QskSlider.cpp +++ b/src/controls/QskSlider.cpp @@ -108,8 +108,12 @@ bool QskSlider::isTracking() const return m_data->tracking; } -QSizeF QskSlider::contentsSizeHint() const +QSizeF QskSlider::contentsSizeHint( + Qt::SizeHint which, const QSizeF& ) const { + if ( which != Qt::PreferredSize ) + return QSizeF(); + const qreal dim = metric( QskSlider::Panel | QskAspect::Size ); return ( m_data->orientation == Qt::Horizontal ) ? QSizeF( 4 * dim, dim ) : QSizeF( dim, 4 * dim ); diff --git a/src/controls/QskSlider.h b/src/controls/QskSlider.h index 9a35765e..eaa5fb54 100644 --- a/src/controls/QskSlider.h +++ b/src/controls/QskSlider.h @@ -53,7 +53,7 @@ class QSK_EXPORT QskSlider : public QskRangeControl void mouseMoveEvent( QMouseEvent* e ) override; void mouseReleaseEvent( QMouseEvent* e ) override; - QSizeF contentsSizeHint() const override; + QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override; QSizeF handleSize() const; QRectF handleRect() const; diff --git a/src/controls/QskStatusIndicator.cpp b/src/controls/QskStatusIndicator.cpp index 24eb7839..ab61cdff 100644 --- a/src/controls/QskStatusIndicator.cpp +++ b/src/controls/QskStatusIndicator.cpp @@ -153,23 +153,13 @@ QskColorFilter QskStatusIndicator::graphicFilter( int status ) const return effectiveGraphicFilter( QskStatusIndicator::Graphic ); } -qreal QskStatusIndicator::heightForWidth( qreal width ) const +QSizeF QskStatusIndicator::contentsSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const { - return sizeConstraint( Qt::Horizontal, width ); -} + if ( which != Qt::PreferredSize ) + return QSizeF(); -qreal QskStatusIndicator::widthForHeight( qreal height ) const -{ - return sizeConstraint( Qt::Vertical, height ); -} - -qreal QskStatusIndicator::sizeConstraint( - Qt::Orientation orientation, qreal constraint ) const -{ - if ( constraint <= 0.0 ) - return 0.0; - - qreal value = 0.0; + QSizeF sz; for ( auto& statusData : m_data->map ) { @@ -177,36 +167,24 @@ qreal QskStatusIndicator::sizeConstraint( if ( !statusData.graphic.isEmpty() ) { - const QSizeF sz = statusData.graphic.defaultSize(); - if ( !sz.isEmpty() ) + auto hint = statusData.graphic.defaultSize(); + + if ( !hint.isEmpty() ) { - qreal v; - if ( orientation == Qt::Horizontal ) - v = sz.height() * constraint / sz.width(); - else - v = sz.width() * constraint / sz.height(); - - if ( v > value ) - value = v; + if ( constraint.width() >= 0.0 ) + { + hint.setHeight( sz.height() * constraint.width() / sz.width() ); + } + else if ( constraint.height() >= 0.0 ) + { + hint.setWidth( sz.width() * constraint.height() / sz.height() ); + } } + + sz = sz.expandedTo( hint ); } } - return value; -} - -QSizeF QskStatusIndicator::contentsSizeHint() const -{ - QSizeF sz( 0, 0 ); - - for ( auto& statusData : m_data->map ) - { - statusData.ensureGraphic( this ); - - if ( !statusData.graphic.isEmpty() ) - sz = sz.expandedTo( statusData.graphic.defaultSize() ); - } - return sz; } diff --git a/src/controls/QskStatusIndicator.h b/src/controls/QskStatusIndicator.h index 430c6d99..16a6dda5 100644 --- a/src/controls/QskStatusIndicator.h +++ b/src/controls/QskStatusIndicator.h @@ -35,9 +35,6 @@ class QSK_EXPORT QskStatusIndicator : public QskControl virtual QskColorFilter graphicFilter( int status ) const; virtual QskGraphic loadSource( const QUrl& ) const; - qreal heightForWidth( qreal width ) const override; - qreal widthForHeight( qreal height ) const override; - int status() const; bool hasStatus( int status ) const; @@ -51,11 +48,9 @@ class QSK_EXPORT QskStatusIndicator : public QskControl void changeEvent( QEvent* ) override; void updateLayout() override; - QSizeF contentsSizeHint() const override; + QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override; private: - qreal sizeConstraint( Qt::Orientation, qreal ) const; - class PrivateData; std::unique_ptr< PrivateData > m_data; }; diff --git a/src/controls/QskSubWindow.cpp b/src/controls/QskSubWindow.cpp index 6510bb09..4f3fe4d2 100644 --- a/src/controls/QskSubWindow.cpp +++ b/src/controls/QskSubWindow.cpp @@ -240,22 +240,21 @@ QRectF QskSubWindow::layoutRectForSize( const QSizeF& size ) const return innerBox( Panel, rect ); } -QSizeF QskSubWindow::contentsSizeHint() const +QSizeF QskSubWindow::layoutSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const { // the size we get from the children - auto hint = Inherited::contentsSizeHint(); + auto hint = Inherited::layoutSizeHint( which, constraint ); -#if 1 - // should be Minimum Width/Height from the hints - if ( hint.width() < 0 ) - hint.setWidth( qskDpiScaled( 100 ) ); + if ( which == Qt::PreferredSize ) + { + // should be Minimum Width/Height from the skin hints + if ( hint.width() < 0.0 ) + hint.setWidth( qskDpiScaled( 100 ) ); - if ( hint.height() < 0 ) - hint.setHeight( qskDpiScaled( 80 ) ); -#endif - - hint = outerBoxSize( Panel, hint ); - hint.setHeight( hint.height() + subControlRect( TitleBar ).height() ); + if ( hint.height() < 0.0 ) + hint.setHeight( qskDpiScaled( 80 ) ); + } return hint; } diff --git a/src/controls/QskSubWindow.h b/src/controls/QskSubWindow.h index e30a0dac..552e33c9 100644 --- a/src/controls/QskSubWindow.h +++ b/src/controls/QskSubWindow.h @@ -77,6 +77,7 @@ class QSK_EXPORT QskSubWindow : public QskPopup bool testWindowButton( WindowButton ) const; QRectF titleBarRect() const; + QRectF layoutRectForSize( const QSizeF& ) const override; Q_SIGNALS: @@ -89,9 +90,9 @@ class QSK_EXPORT QskSubWindow : public QskPopup protected: bool event( QEvent* ) override; - void updateLayout() override; - QSizeF contentsSizeHint() const override; + void updateLayout() override; + QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override; void itemChange( QQuickItem::ItemChange, const QQuickItem::ItemChangeData& ) override; diff --git a/src/controls/QskTabBar.cpp b/src/controls/QskTabBar.cpp index 99537a0f..6076f58f 100644 --- a/src/controls/QskTabBar.cpp +++ b/src/controls/QskTabBar.cpp @@ -261,9 +261,9 @@ void QskTabBar::removeTab( int index ) nextButton->setChecked( true ); m_data->connectButton( nextButton, this, true ); } - + m_data->currentIndex = nextIndex; - + Q_EMIT countChanged( count() ); Q_EMIT currentIndexChanged( nextIndex ); } diff --git a/src/controls/QskTabButton.cpp b/src/controls/QskTabButton.cpp index 3c5c91fa..3ef4848e 100644 --- a/src/controls/QskTabButton.cpp +++ b/src/controls/QskTabButton.cpp @@ -86,8 +86,12 @@ QskTextOptions QskTabButton::textOptions() const return m_data->textOptions; } -QSizeF QskTabButton::contentsSizeHint() const +QSizeF QskTabButton::contentsSizeHint( + Qt::SizeHint which, const QSizeF& ) const { + if ( which != Qt::PreferredSize ) + return QSizeF(); + QSizeF size( metric( Panel | QskAspect::MinimumWidth ), metric( Panel | QskAspect::MinimumHeight ) ); diff --git a/src/controls/QskTabButton.h b/src/controls/QskTabButton.h index ba594b8c..b05db510 100644 --- a/src/controls/QskTabButton.h +++ b/src/controls/QskTabButton.h @@ -49,7 +49,7 @@ class QSK_EXPORT QskTabButton : public QskAbstractButton protected: void changeEvent( QEvent* ) override; - QSizeF contentsSizeHint() const override; + QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override; private: class PrivateData; diff --git a/src/controls/QskTabView.cpp b/src/controls/QskTabView.cpp index bfae031d..082ee271 100644 --- a/src/controls/QskTabView.cpp +++ b/src/controls/QskTabView.cpp @@ -198,13 +198,14 @@ int QskTabView::count() const return m_data->tabBar->count(); } -QSizeF QskTabView::contentsSizeHint() const +QSizeF QskTabView::layoutSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const { - if ( m_data->tabBar == nullptr || m_data->tabBar->count() == 0 ) - return Inherited::contentsSizeHint(); + if ( which != Qt::PreferredSize ) + return constraint; - const QSizeF barHint = m_data->tabBar->sizeHint(); - const QSizeF boxHint = m_data->stackBox->sizeHint(); + const auto barHint = m_data->tabBar->sizeHint(); + const auto boxHint = m_data->stackBox->sizeHint(); qreal w, h; @@ -229,16 +230,10 @@ void QskTabView::setCurrentIndex( int index ) bool QskTabView::event( QEvent* event ) { - switch ( event->type() ) + if ( event->type() == QEvent::LayoutRequest ) { - case QEvent::LayoutRequest: - { - resetImplicitSize(); - polish(); - break; - } - default: - break; + resetImplicitSize(); + polish(); } return Inherited::event( event ); @@ -247,7 +242,7 @@ bool QskTabView::event( QEvent* event ) void QskTabView::updateLayout() { if ( maybeUnresized() ) - return; + return; m_data->tabBar->setGeometry( subControlRect( TabBar ) ); diff --git a/src/controls/QskTabView.h b/src/controls/QskTabView.h index 91c2ff8b..5cfa1b01 100644 --- a/src/controls/QskTabView.h +++ b/src/controls/QskTabView.h @@ -78,7 +78,7 @@ class QSK_EXPORT QskTabView : public QskControl bool event( QEvent* event ) override; void updateLayout() override; - QSizeF contentsSizeHint() const override; + QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override; private: class PrivateData; diff --git a/src/controls/QskTextInput.cpp b/src/controls/QskTextInput.cpp index 8d43d514..ca9e7c35 100644 --- a/src/controls/QskTextInput.cpp +++ b/src/controls/QskTextInput.cpp @@ -441,8 +441,11 @@ void QskTextInput::focusOutEvent( QFocusEvent* event ) Inherited::focusOutEvent( event ); } -QSizeF QskTextInput::contentsSizeHint() const +QSizeF QskTextInput::contentsSizeHint( Qt::SizeHint which, const QSizeF& ) const { + if ( which != Qt::PreferredSize ) + return QSizeF(); + using namespace QskAspect; auto input = m_data->textInput; diff --git a/src/controls/QskTextInput.h b/src/controls/QskTextInput.h index 9b13c867..713d6aa6 100644 --- a/src/controls/QskTextInput.h +++ b/src/controls/QskTextInput.h @@ -197,9 +197,9 @@ class QSK_EXPORT QskTextInput : public QskControl void keyPressEvent( QKeyEvent* ) override; void keyReleaseEvent( QKeyEvent* ) override; - void updateLayout() override; - QSizeF contentsSizeHint() const override; + QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override; + void updateLayout() override; void updateNode( QSGNode* ) override; private: diff --git a/src/controls/QskTextLabel.cpp b/src/controls/QskTextLabel.cpp index 0878b7e0..6d3d82e1 100644 --- a/src/controls/QskTextLabel.cpp +++ b/src/controls/QskTextLabel.cpp @@ -208,81 +208,67 @@ QFont QskTextLabel::font() const return effectiveFont( QskTextLabel::Text ); } -QSizeF QskTextLabel::contentsSizeHint() const +QSizeF QskTextLabel::contentsSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const { + if ( which != Qt::PreferredSize ) + return QSizeF(); + const auto font = effectiveFont( Text ); - if ( !m_data->text.isEmpty() ) - { - return QskTextRenderer::textSize( - m_data->text, font, m_data->effectiveOptions() ); - } + QSizeF hint; - return QSizeF( 0, QFontMetricsF( font ).height() ); -} - -qreal QskTextLabel::heightForWidth( qreal width ) const -{ - const auto font = effectiveFont( Text ); const qreal lineHeight = QFontMetricsF( font ).height(); - qreal h = 0; - - const auto m = margins(); - if ( m_data->text.isEmpty() ) { - h = lineHeight; + if ( constraint.height() < 0.0 ) + hint.setHeight( qCeil( lineHeight ) ); } - else if ( m_data->textOptions.effectiveElideMode() != Qt::ElideNone ) + else if ( constraint.width() >= 0.0 ) { - h = lineHeight; + if ( m_data->textOptions.effectiveElideMode() != Qt::ElideNone ) + { + hint.setHeight( qCeil( lineHeight ) ); + } + else + { + /* + In case of QskTextOptions::NoWrap we could count + the line numbers and calculate the height from + lineHeight. TODO ... + */ + qreal maxHeight = std::numeric_limits< qreal >::max(); + if ( maxHeight / lineHeight > m_data->textOptions.maximumLineCount() ) + { + // be careful with overflows + maxHeight = m_data->textOptions.maximumLineCount() * lineHeight; + } + + QSizeF size( constraint.width(), maxHeight ); + size = QskTextRenderer::textSize( + m_data->text, font, m_data->effectiveOptions(), size ); + + hint.setHeight( qCeil( size.height() ) ); + } + } + else if ( constraint.height() >= 0.0 ) + { + const qreal maxWidth = std::numeric_limits< qreal >::max(); + + QSizeF size( maxWidth, constraint.height() ); + size = QskTextRenderer::textSize( m_data->text, font, + m_data->effectiveOptions(), size ); + + hint.setWidth( qCeil( size.width() ) ); } else { - /* - In case of QskTextOptions::NoWrap we could count - the line numbers and calculate the height from - lineHeight. TODO ... - */ - qreal maxHeight = std::numeric_limits< qreal >::max(); - if ( maxHeight / lineHeight > m_data->textOptions.maximumLineCount() ) - { - // be careful with overflows - maxHeight = m_data->textOptions.maximumLineCount() * lineHeight; - } - - qreal w = width - m.left() + m.right(); - - QSizeF size( w, maxHeight ); - size = QskTextRenderer::textSize( - m_data->text, font, m_data->effectiveOptions(), size ); - - h = size.height(); + hint = QskTextRenderer::textSize( + m_data->text, font, m_data->effectiveOptions() ); } - h += m.top() + m.bottom(); - - return qCeil( h ); -} - -qreal QskTextLabel::widthForHeight( qreal height ) const -{ - if ( m_data->text.isEmpty() ) - { - return Inherited::widthForHeight( height ); - } - - const auto font = effectiveFont( Text ); - const qreal maxWidth = std::numeric_limits< qreal >::max(); - - const auto m = margins(); - - QSizeF size( maxWidth, height - m.top() + m.bottom() ); - size = QskTextRenderer::textSize( m_data->text, font, - m_data->effectiveOptions(), size ); - - return qCeil( size.width() + m.left() + m.right() ); + return hint; } void QskTextLabel::changeEvent( QEvent* event ) diff --git a/src/controls/QskTextLabel.h b/src/controls/QskTextLabel.h index d616bed7..ab1ffb32 100644 --- a/src/controls/QskTextLabel.h +++ b/src/controls/QskTextLabel.h @@ -60,9 +60,6 @@ class QSK_EXPORT QskTextLabel : public QskControl void setAlignment( Qt::Alignment ); Qt::Alignment alignment() const; - qreal heightForWidth( qreal width ) const override; - qreal widthForHeight( qreal height ) const override; - QFont font() const; Q_SIGNALS: @@ -77,7 +74,7 @@ class QSK_EXPORT QskTextLabel : public QskControl protected: void changeEvent( QEvent* ) override; - QSizeF contentsSizeHint() const override; + QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override; private: class PrivateData; diff --git a/src/dialogs/QskDialogButtonBox.cpp b/src/dialogs/QskDialogButtonBox.cpp index 6b4e9e0a..60fe7c55 100644 --- a/src/dialogs/QskDialogButtonBox.cpp +++ b/src/dialogs/QskDialogButtonBox.cpp @@ -120,7 +120,8 @@ QskAspect::Subcontrol QskDialogButtonBox::effectiveSubcontrol( return Inherited::effectiveSubcontrol( subControl ); } -QSizeF QskDialogButtonBox::contentsSizeHint() const +QSizeF QskDialogButtonBox::layoutSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const { if ( m_data->dirtyLayout ) { @@ -128,7 +129,7 @@ QSizeF QskDialogButtonBox::contentsSizeHint() const m_data->dirtyLayout = false; } - return outerBoxSize( Panel, m_data->layoutBox->sizeHint() ); + return m_data->layoutBox->effectiveSizeHint( which, constraint ); } void QskDialogButtonBox::invalidateLayout() diff --git a/src/dialogs/QskDialogButtonBox.h b/src/dialogs/QskDialogButtonBox.h index c658d9fb..0ec5cbb3 100644 --- a/src/dialogs/QskDialogButtonBox.h +++ b/src/dialogs/QskDialogButtonBox.h @@ -77,12 +77,11 @@ class QSK_EXPORT QskDialogButtonBox : public QskBox protected: bool event( QEvent* event ) override; - void updateLayout() override; - QSizeF contentsSizeHint() const override; + void updateLayout() override; + QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override; virtual QskPushButton* createButton( QskDialog::Action ) const; - void invalidateLayout(); private: diff --git a/src/dialogs/QskDialogSubWindow.cpp b/src/dialogs/QskDialogSubWindow.cpp index 5869c0ba..52478eeb 100644 --- a/src/dialogs/QskDialogSubWindow.cpp +++ b/src/dialogs/QskDialogSubWindow.cpp @@ -5,7 +5,6 @@ #include "QskDialogSubWindow.h" #include "QskDialogButtonBox.h" -#include "QskLayoutConstraint.h" #include "QskPushButton.h" #include "QskQuick.h" @@ -27,75 +26,6 @@ static inline void qskSetRejectOnClose( QskDialogSubWindow* subWindow, bool on ) } } -static inline qreal qskConstrainedValue( QskLayoutConstraint::Type type, - const QskControl* control, qreal widthOrHeight ) -{ - auto subWindow = static_cast< const QskDialogSubWindow* >( control ); - - if ( type == QskLayoutConstraint::WidthForHeight ) - { - qreal width = -1.0; - qreal height = widthOrHeight; - - if ( auto buttonBox = subWindow->buttonBox() ) - { - if ( buttonBox->isVisibleTo( subWindow ) ) - { - const auto hint = buttonBox->sizeHint(); - - width = hint.width(); - height -= hint.height(); - } - } - - if ( auto contentItem = qskControlCast( subWindow->contentItem() ) ) - { - if ( contentItem->isVisibleTo( subWindow ) ) - { - const auto m = subWindow->contentPadding(); - height -= m.top() + m.bottom(); - - qreal w = contentItem->widthForHeight( height ); - - if ( w >= 0 ) - { - w += m.left() + m.right(); - width = qMax( width, w ); - } - } - } - - return width; - } - else - { - qreal width = widthOrHeight; - qreal height = -1.0; - - if ( auto buttonBox = subWindow->buttonBox() ) - { - if ( buttonBox->isVisibleTo( subWindow ) ) - height += buttonBox->sizeHint().height(); - } - - if ( auto contentItem = qskControlCast( subWindow->contentItem() ) ) - { - if ( qskIsVisibleTo( contentItem, subWindow ) ) - { - const auto& m = subWindow->contentPadding(); - width -= m.left() + m.right(); - - const qreal h = contentItem->heightForWidth( width ); - - if ( h >= 0 ) - height += h + m.top() + m.bottom(); - } - } - - return height; - } -} - class QskDialogSubWindow::PrivateData { public: @@ -438,7 +368,7 @@ void QskDialogSubWindow::updateLayout() auto rect = layoutRect(); - if ( m_data->buttonBox && m_data->buttonBox->isVisibleTo( this ) ) + if ( m_data->buttonBox && m_data->buttonBox->isVisibleToParent() ) { const auto h = m_data->buttonBox->sizeHint().height(); rect.setBottom( rect.bottom() - h ); @@ -453,49 +383,68 @@ void QskDialogSubWindow::updateLayout() } } -qreal QskDialogSubWindow::heightForWidth( qreal width ) const +QSizeF QskDialogSubWindow::layoutSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const { - return QskLayoutConstraint::constrainedMetric( - QskLayoutConstraint::HeightForWidth, this, width, qskConstrainedValue ); -} + if ( which != Qt::PreferredSize ) + return QSizeF(); -qreal QskDialogSubWindow::widthForHeight( qreal height ) const -{ - return QskLayoutConstraint::constrainedMetric( - QskLayoutConstraint::WidthForHeight, this, height, qskConstrainedValue ); -} + QSizeF buttonBoxHint; + + qreal constraintHeight = constraint.height(); + + if ( auto buttonBox = m_data->buttonBox ) + { + if ( buttonBox->isVisibleToLayout() ) + { + buttonBoxHint = buttonBox->effectiveSizeHint( + which, QSizeF( constraint.width(), -1 ) ); + + if ( constraint.width() >= 0.0 ) + buttonBoxHint.rwidth() = constraint.width(); + + if ( constraintHeight >= 0.0 && buttonBoxHint.height() >= 0.0 ) + { + constraintHeight -= buttonBoxHint.height(); + constraintHeight = qMax( constraintHeight, 0.0 ); + } + } + } + + QSizeF contentHint; + + if ( qskIsVisibleToLayout( m_data->contentItem ) ) + { + const auto& m = m_data->contentPadding; + const qreal dw = m.left() + m.right(); + const qreal dh = m.top() + m.bottom(); + + qreal constraintWidth = constraint.width(); + + if ( constraintWidth > 0.0 ) + constraintWidth = qMax( constraintWidth - dw, 0.0 ); + + if ( constraintHeight > 0.0 ) + constraintHeight = qMax( constraintHeight - dh, 0.0 ); + + contentHint = qskEffectiveSizeHint( m_data->contentItem, + which, QSizeF( constraintWidth, constraintHeight ) ); + + if ( contentHint.width() >= 0 ) + contentHint.rwidth() += dw; + + if ( contentHint.height() >= 0 ) + contentHint.rheight() += dh; + } -QSizeF QskDialogSubWindow::contentsSizeHint() const -{ qreal w = -1; + w = qMax( w, buttonBoxHint.width() ); + w = qMax( w, contentHint.width() ); + qreal h = -1; - if ( m_data->buttonBox && m_data->buttonBox->isVisibleTo( this ) ) - { - const auto hint = m_data->buttonBox->sizeHint(); - - w = hint.width(); - h = hint.height(); - } - - if ( auto* control = qskControlCast( m_data->contentItem ) ) - { - const auto hint = control->sizeHint(); - - const auto& m = m_data->contentPadding; - - if ( hint.width() >= 0 ) - w = qMax( w, hint.width() + m.left() + m.right() ); - - if ( hint.height() >= 0 ) - h += hint.height() + m.top() + m.bottom(); - } - - const qreal sz = 400.0; // something - const auto innerSize = layoutRectForSize( QSizeF( sz, sz ) ).size(); - - w += sz - innerSize.width(); - h += sz - innerSize.height(); + if ( buttonBoxHint.height() > 0.0 && contentHint.height() > 0.0 ) + h = buttonBoxHint.height() + contentHint.height(); return QSizeF( w, h ); } diff --git a/src/dialogs/QskDialogSubWindow.h b/src/dialogs/QskDialogSubWindow.h index ce35e297..8d66471d 100644 --- a/src/dialogs/QskDialogSubWindow.h +++ b/src/dialogs/QskDialogSubWindow.h @@ -51,9 +51,6 @@ class QSK_EXPORT QskDialogSubWindow : public QskSubWindow void setContentPadding( const QMarginsF& ); QMarginsF contentPadding() const; - qreal heightForWidth( qreal width ) const override; - qreal widthForHeight( qreal height ) const override; - Q_SIGNALS: void finished( QskDialog::DialogCode ); void accepted(); @@ -72,7 +69,7 @@ class QSK_EXPORT QskDialogSubWindow : public QskSubWindow void updateLayout() override; void aboutToShow() override; - QSizeF contentsSizeHint() const override; + QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override; virtual QskDialogButtonBox* createButtonBox(); diff --git a/src/dialogs/QskSelectionSubWindow.cpp b/src/dialogs/QskSelectionSubWindow.cpp index 13c6648c..5341cb89 100644 --- a/src/dialogs/QskSelectionSubWindow.cpp +++ b/src/dialogs/QskSelectionSubWindow.cpp @@ -48,9 +48,13 @@ namespace #if 1 // how to find a reasonable default size ??? - QSizeF contentsSizeHint() const override + QSizeF contentsSizeHint( + Qt::SizeHint which, const QSizeF& ) const override { - return QSizeF( 500, 500 ); + if ( which == Qt::PreferredSize ) + return QSizeF( 500, 500 ); + + return QSizeF(); } #endif }; diff --git a/src/dialogs/QskSelectionWindow.cpp b/src/dialogs/QskSelectionWindow.cpp index c9f7f8ab..c321ac6b 100644 --- a/src/dialogs/QskSelectionWindow.cpp +++ b/src/dialogs/QskSelectionWindow.cpp @@ -51,9 +51,13 @@ namespace #if 1 // how to find a reasonable default size ??? - QSizeF contentsSizeHint() const override + QSizeF contentsSizeHint( + Qt::SizeHint which, const QSizeF& ) const override { - return QSizeF( 500, 500 ); + if ( which == Qt::PreferredSize ) + return QSizeF( 500, 500 ); + + return QSizeF(); } #endif }; diff --git a/src/inputpanel/QskInputPredictionBar.cpp b/src/inputpanel/QskInputPredictionBar.cpp index 79d54307..2d6d3991 100644 --- a/src/inputpanel/QskInputPredictionBar.cpp +++ b/src/inputpanel/QskInputPredictionBar.cpp @@ -29,8 +29,12 @@ namespace setTextOptions( options ); } - QSizeF contentsSizeHint() const override + QSizeF contentsSizeHint( + Qt::SizeHint which, const QSizeF& ) const override { + if ( which != Qt::PreferredSize ) + return QSizeF(); + auto size = QFontMetricsF( font() ).size( Qt::TextSingleLine, text() ); const QSizeF minSize( metric( Panel | QskAspect::MinimumWidth ), diff --git a/src/inputpanel/QskVirtualKeyboard.cpp b/src/inputpanel/QskVirtualKeyboard.cpp index ba1662cc..4828801e 100644 --- a/src/inputpanel/QskVirtualKeyboard.cpp +++ b/src/inputpanel/QskVirtualKeyboard.cpp @@ -295,56 +295,38 @@ QskVirtualKeyboard::Mode QskVirtualKeyboard::mode() const return m_data->mode; } -QSizeF QskVirtualKeyboard::contentsSizeHint() const +QSizeF QskVirtualKeyboard::layoutSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const { + if ( which != Qt::PreferredSize ) + return QSizeF(); + constexpr qreal ratio = qreal( RowCount ) / ColumnCount; - const qreal w = 600; - return QSizeF( w, ratio * w ); -} + qreal w = constraint.width(); + qreal h = constraint.height(); -qreal QskVirtualKeyboard::heightForWidth( qreal width ) const -{ - /* - Not necessarily correct, when - subControlRect( Panel ) != contentsRect: TODO ... - */ - constexpr qreal ratio = qreal( RowCount ) / ColumnCount; - const auto margins = this->margins(); + if ( h >= 0 ) + { + const auto padding = innerPadding( Panel, QSizeF( h, h ) ); + const auto dw = padding.left() + padding.right(); + const auto dh = padding.top() + padding.bottom(); - width -= margins.left() + margins.right(); + w = ( h - dh ) / ratio + dw; + } + else + { + if ( w < 0 ) + w = 600; - const auto padding = innerPadding( - Panel, QSizeF( width, width ) ); + const auto padding = innerPadding( Panel, QSizeF( w, w ) ); + const auto dw = padding.left() + padding.right(); + const auto dh = padding.top() + padding.bottom(); - width -= padding.left() + padding.right(); + h = ( w - dw ) * ratio + dh; + } - qreal height = width * ratio; - - height += padding.top() + padding.bottom(); - height += margins.top() + margins.bottom(); - - return height; -} - -qreal QskVirtualKeyboard::widthForHeight( qreal height ) const -{ - constexpr qreal ratio = qreal( RowCount ) / ColumnCount; - const auto margins = this->margins(); - - height -= margins.top() + margins.bottom(); - - const auto padding = innerPadding( - Panel, QSizeF( height, height ) ); - - height -= padding.top() + padding.bottom(); - - qreal width = height / ratio; - - width += padding.left() + padding.right(); - width += margins.left() + margins.right(); - - return width; + return QSizeF( w, h ); } void QskVirtualKeyboard::updateLayout() diff --git a/src/inputpanel/QskVirtualKeyboard.h b/src/inputpanel/QskVirtualKeyboard.h index 7f5a35a9..d76a13d7 100644 --- a/src/inputpanel/QskVirtualKeyboard.h +++ b/src/inputpanel/QskVirtualKeyboard.h @@ -35,9 +35,6 @@ class QSK_EXPORT QskVirtualKeyboard : public QskBox void updateLocale( const QLocale& ); - qreal heightForWidth( qreal width ) const override; - qreal widthForHeight( qreal height ) const override; - QskAspect::Subcontrol effectiveSubcontrol( QskAspect::Subcontrol ) const override; @@ -49,7 +46,7 @@ class QSK_EXPORT QskVirtualKeyboard : public QskBox protected: void updateLayout() override; - QSizeF contentsSizeHint() const override; + QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override; private: void buttonPressed(); diff --git a/src/layouts/QskGridBox.cpp b/src/layouts/QskGridBox.cpp index e5b58c61..6a6044af 100644 --- a/src/layouts/QskGridBox.cpp +++ b/src/layouts/QskGridBox.cpp @@ -5,7 +5,6 @@ #include "QskGridBox.h" #include "QskGridLayoutEngine.h" -#include "QskLayoutConstraint.h" #include "QskEvent.h" #include @@ -341,38 +340,16 @@ void QskGridBox::updateLayout() m_data->engine.setGeometries( layoutRect() ); } -QSizeF QskGridBox::contentsSizeHint() const +QSizeF QskGridBox::layoutSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const { - if ( count() == 0 ) - return QSizeF( 0, 0 ); + if ( which == Qt::MaximumSize ) + { + // we can extend beyond the maximum size of the children + return QSizeF(); + } - return m_data->engine.sizeHint( Qt::PreferredSize, QSizeF() ); -} - -qreal QskGridBox::heightForWidth( qreal width ) const -{ - auto constrainedHeight = - [this]( QskLayoutConstraint::Type, const QskControl*, qreal width ) - { - const QSizeF constraint( width, -1 ); - return m_data->engine.sizeHint( Qt::PreferredSize, constraint ).height(); - }; - - return QskLayoutConstraint::constrainedMetric( - QskLayoutConstraint::HeightForWidth, this, width, constrainedHeight ); -} - -qreal QskGridBox::widthForHeight( qreal height ) const -{ - auto constrainedWidth = - [this]( QskLayoutConstraint::Type, const QskControl*, qreal height ) - { - const QSizeF constraint( -1, height ); - return m_data->engine.sizeHint( Qt::PreferredSize, constraint ).width(); - }; - - return QskLayoutConstraint::constrainedMetric( - QskLayoutConstraint::WidthForHeight, this, height, constrainedWidth ); + return m_data->engine.sizeHint( which, constraint ); } void QskGridBox::geometryChangeEvent( QskGeometryChangeEvent* event ) diff --git a/src/layouts/QskGridBox.h b/src/layouts/QskGridBox.h index b86a3079..10ad21fe 100644 --- a/src/layouts/QskGridBox.h +++ b/src/layouts/QskGridBox.h @@ -99,9 +99,6 @@ class QSK_EXPORT QskGridBox : public QskBox Q_INVOKABLE void setRowFixedHeight( int row, qreal height ); Q_INVOKABLE void setColumnFixedWidth( int column, qreal width ); - qreal heightForWidth( qreal width ) const override; - qreal widthForHeight( qreal height ) const override; - public Q_SLOTS: void invalidate(); void clear( bool autoDelete = false ); @@ -116,7 +113,7 @@ class QSK_EXPORT QskGridBox : public QskBox void itemChange( ItemChange, const ItemChangeData& ) override; void updateLayout() override; - QSizeF contentsSizeHint() const override; + QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override; private: class PrivateData; diff --git a/src/layouts/QskGridLayoutEngine.cpp b/src/layouts/QskGridLayoutEngine.cpp index 98ef49b6..888510e1 100644 --- a/src/layouts/QskGridLayoutEngine.cpp +++ b/src/layouts/QskGridLayoutEngine.cpp @@ -5,7 +5,6 @@ #include "QskGridLayoutEngine.h" #include "QskLayoutHint.h" -#include "QskLayoutConstraint.h" #include "QskLayoutChain.h" #include "QskSizePolicy.h" #include "QskQuick.h" @@ -172,9 +171,7 @@ namespace QRect minimumGrid() const; bool isIgnored() const; - - QskLayoutChain::CellData cell( - Qt::Orientation, qreal constraint ) const; + QskLayoutChain::CellData cell( Qt::Orientation ) const; void transpose(); @@ -247,17 +244,12 @@ QRect Element::minimumGrid() const bool Element::isIgnored() const { - if ( !m_isSpacer && !QskLayoutConstraint::retainSizeWhenHidden( m_item ) ) - return !qskIsVisibleToParent( m_item ); - - return false; + return !( m_isSpacer || qskIsVisibleToLayout( m_item ) ); } -QskLayoutChain::CellData Element::cell( - Qt::Orientation orientation, qreal constraint ) const +QskLayoutChain::CellData Element::cell( Qt::Orientation orientation ) const { - const auto policy = QskLayoutConstraint::sizePolicy( - m_item ).policy( orientation ); + const auto policy = qskSizePolicy( m_item ).policy( orientation ); QskLayoutChain::CellData cell; cell.isValid = true; @@ -266,9 +258,6 @@ QskLayoutChain::CellData Element::cell( if ( policy & QskSizePolicy::ExpandFlag ) cell.stretch = 1; - if ( !m_isSpacer ) - cell.hint = QskLayoutConstraint::layoutHint( m_item, orientation, constraint ); - return cell; } @@ -601,7 +590,10 @@ void QskGridLayoutEngine::setupChain( Qt::Orientation orientation, if ( !constraints.isEmpty() ) constraint = qskSegmentLength( constraints, grid.left(), grid.right() ); - chain.expandCell( grid.top(), element.cell( orientation, constraint ) ); + auto cell = element.cell( orientation ); + cell.hint = layoutHint( element.item(), orientation, constraint ); + + chain.expandCell( grid.top(), cell ); } else { @@ -624,7 +616,9 @@ void QskGridLayoutEngine::setupChain( Qt::Orientation orientation, if ( !constraints.isEmpty() ) constraint = qskSegmentLength( constraints, grid.left(), grid.right() ); - chain.expandCells( grid.top(), grid.height(), - element->cell( orientation, constraint ) ); + auto cell = element->cell( orientation ); + cell.hint = layoutHint( element->item(), orientation, constraint ); + + chain.expandCells( grid.top(), grid.height(), cell ); } } diff --git a/src/layouts/QskLayoutChain.cpp b/src/layouts/QskLayoutChain.cpp index 28d92abb..6ea8ea90 100644 --- a/src/layouts/QskLayoutChain.cpp +++ b/src/layouts/QskLayoutChain.cpp @@ -4,7 +4,6 @@ *****************************************************************************/ #include "QskLayoutChain.h" -#include "QskLayoutConstraint.h" #include #include @@ -133,9 +132,9 @@ void QskLayoutChain::expandCells( if ( multiCell.hint.preferred() > chainHint.preferred() ) preferred = chain.segments( multiCell.hint.preferred() ); - if ( chainHint.maximum() == QskLayoutConstraint::unlimited ) + if ( chainHint.maximum() == QskLayoutHint::unlimited ) { - if ( multiCell.hint.maximum() < QskLayoutConstraint::unlimited ) + if ( multiCell.hint.maximum() < QskLayoutHint::unlimited ) maximum = chain.segments( multiCell.hint.maximum() ); } @@ -174,7 +173,7 @@ void QskLayoutChain::finish() if ( !m_cells.empty() ) { - const auto maxMaximum = QskLayoutConstraint::unlimited; + const auto maxMaximum = QskLayoutHint::unlimited; for ( auto& cell : m_cells ) { diff --git a/src/layouts/QskLayoutConstraint.cpp b/src/layouts/QskLayoutConstraint.cpp deleted file mode 100644 index 0bcc1b14..00000000 --- a/src/layouts/QskLayoutConstraint.cpp +++ /dev/null @@ -1,507 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann - * This file may be used under the terms of the QSkinny License, Version 1.0 - *****************************************************************************/ - -#include "QskLayoutConstraint.h" -#include "QskControl.h" -#include "QskSizePolicy.h" -#include "QskLayoutHint.h" -#include "QskQuick.h" -#include "QskFunctions.h" - -#include - -static inline qreal qskHintFor( - const QQuickItem* item, const char* method, qreal widthOrHeight ) -{ - if ( item->metaObject()->indexOfMethod( method ) >= 0 ) - { - qreal value; - - ( void ) QMetaObject::invokeMethod( - const_cast< QQuickItem* >( item ), method, Qt::DirectConnection, - Q_RETURN_ARG( qreal, value ), Q_ARG( qreal, widthOrHeight ) ); - - return value; - } - - return -1; -} - -static inline bool qskHasHintFor( const QQuickItem* item, const char* method ) -{ - if ( item->metaObject()->indexOfMethod( method ) >= 0 ) - { - bool enabled; - - ( void ) QMetaObject::invokeMethod( const_cast< QQuickItem* >( item ), - method, Qt::DirectConnection, Q_RETURN_ARG( bool, enabled ) ); - - return enabled; - } - - return false; -} - -static inline QSizeF qskEffectiveSizeHint( - const QQuickItem* item, Qt::SizeHint whichHint ) -{ - if ( auto control = qskControlCast( item ) ) - return control->effectiveSizeHint( whichHint ); - - QSizeF hint( -1.0, -1.0 ); // no hint - - const char* properties[] = - { - "minimumSize", - "preferredSize", - "maximumSize" - }; - - const QVariant v = item->property( properties[ whichHint ] ); - if ( v.canConvert( QMetaType::QSizeF ) ) - hint = v.toSizeF(); - - switch ( whichHint ) - { - case Qt::MinimumSize: - { - if ( hint.width() < 0 ) - hint.setWidth( 0.0 ); - - if ( hint.height() < 0 ) - hint.setHeight( 0.0 ); - - break; - } - - case Qt::PreferredSize: - { - if ( hint.width() < 0 ) - hint.setWidth( item->implicitWidth() ); - - if ( hint.height() < 0 ) - hint.setHeight( item->implicitHeight() ); - - break; - } - case Qt::MaximumSize: - { - if ( hint.width() < 0 ) - hint.setWidth( QskLayoutConstraint::unlimited ); - - if ( hint.height() < 0 ) - hint.setHeight( QskLayoutConstraint::unlimited ); - - break; - } - default: - break; - } - - return hint; -} - -QskLayoutConstraint::Type QskLayoutConstraint::constraintType( const QQuickItem* item ) -{ - if ( item == nullptr ) - return Unconstrained; - - Type constraintType = Unconstrained; - - if ( auto control = qskControlCast( item ) ) - { - const auto policy = control->sizePolicy(); - if ( policy.horizontalPolicy() == QskSizePolicy::Constrained ) - { - constraintType = WidthForHeight; - } - else if ( policy.verticalPolicy() == QskSizePolicy::Constrained ) - { - constraintType = HeightForWidth; - } - } - else - { - if ( qskHasHintFor( item, "hasWidthForHeight" ) ) - { - constraintType = WidthForHeight; - } - else if ( qskHasHintFor( item, "hasHeightForWidth" ) ) - { - constraintType = HeightForWidth; - } - } - - return constraintType; -} - -bool QskLayoutConstraint::isConstrained( - const QQuickItem* item, Qt::Orientation orientation ) -{ - switch( constraintType( item ) ) - { - case QskLayoutConstraint::WidthForHeight: - return orientation == Qt::Horizontal; - - case QskLayoutConstraint::HeightForWidth: - return orientation == Qt::Vertical; - - default: - return false; - } -} - -qreal QskLayoutConstraint::heightForWidth( const QQuickItem* item, qreal width ) -{ - if ( auto control = qskControlCast( item ) ) - return control->heightForWidth( width ); - - return qskHintFor( item, "heightForWidth", width ); -} - -qreal QskLayoutConstraint::widthForHeight( const QQuickItem* item, qreal height ) -{ - if ( auto control = qskControlCast( item ) ) - return control->widthForHeight( height ); - - return qskHintFor( item, "widthForHeight", height ); -} - -qreal QskLayoutConstraint::constrainedMetric( - Type type, const QskControl* control, qreal widthOrHeight, - std::function< qreal( Type, const QskControl*, qreal ) > constrainFunction ) -{ -#if 1 - /* - In case of having a corner radius of Qt::RelativeSize - we might have a wrong result when using QskLayoutConstraint::unlimited. - No idea how to solve this in a generic way: TODO ... - */ -#endif - - const qreal upperLimit = 1e6; - - if ( type == WidthForHeight ) - { - const QSizeF outer( upperLimit, widthOrHeight ); - const QSizeF inner = control->layoutRectForSize( outer ).size(); - - qreal width = constrainFunction( type, control, inner.height() ); - - if ( width >= 0.0 ) - width += outer.width() - inner.width(); - - return width; - } - else - { - const QSizeF outer( widthOrHeight, upperLimit ); - const QSizeF inner = control->layoutRectForSize( outer ).size(); - - qreal height = constrainFunction( type, control, inner.width() ); - - if ( height >= 0.0 ) - height += outer.height() - inner.height(); - - return height; - } -} - -qreal QskLayoutConstraint::constrainedChildrenMetric( - Type type, const QskControl* control, qreal constraint ) -{ - auto constrainFunction = - ( type == WidthForHeight ) ? widthForHeight : heightForWidth; - - qreal constrainedValue = -1.0; - - const auto children = control->childItems(); - for ( auto child : children ) - { - if ( !qskIsTransparentForPositioner( child ) ) - { - if ( qskIsVisibleToParent( child ) || retainSizeWhenHidden( child ) ) - { - const auto v = constrainFunction( child, constraint ); - if ( v > constrainedValue ) - constrainedValue = v; - } - } - } - - return constrainedValue; -} - -QskSizePolicy QskLayoutConstraint::sizePolicy( const QQuickItem* item ) -{ - if ( item ) - { - if ( auto control = qskControlCast( item ) ) - return control->sizePolicy(); - - const QVariant v = item->property( "sizePolicy" ); - if ( v.canConvert< QskSizePolicy >() ) - return qvariant_cast< QskSizePolicy >( v ); - } - - return QskSizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Preferred ); -} - -QSizeF QskLayoutConstraint::boundedSize( const QQuickItem* item, const QSizeF& size ) -{ - qreal width, height; - - switch( constraintType( item ) ) - { - case WidthForHeight: - { - const auto hintV = layoutHint( item, Qt::Vertical, -1 ); - height = qBound( hintV.minimum(), size.height(), hintV.maximum() ); - - const auto hintH = layoutHint( item, Qt::Horizontal, height ); - width = qBound( hintH.minimum(), size.width(), hintH.maximum() ); - - break; - } - case HeightForWidth: - { - const auto hintH = layoutHint( item, Qt::Horizontal, -1 ); - width = qBound( hintH.minimum(), size.width(), hintH.maximum() ); - - const auto hintV = layoutHint( item, Qt::Vertical, width ); - height = qBound( hintV.minimum(), size.height(), hintV.maximum() ); - - break; - } - default: - { - const auto hintH = layoutHint( item, Qt::Horizontal, -1 ); - const auto hintV = layoutHint( item, Qt::Vertical, -1 ); - - width = qBound( hintH.minimum(), size.width(), hintH.maximum() ); - height = qBound( hintV.minimum(), size.height(), hintV.maximum() ); - } - } - - return QSizeF( width, height ); - -} - -qreal QskLayoutConstraint::sizeHint( const QQuickItem* item, - Qt::SizeHint whichHint, Qt::Orientation orientation, qreal constraint ) -{ - if ( orientation == Qt::Horizontal ) - return sizeHint( item, whichHint, QSizeF( -1.0, constraint ) ).width(); - else - return sizeHint( item, whichHint, QSizeF( constraint, -1.0 ) ).height(); -} - -QSizeF QskLayoutConstraint::sizeHint( const QQuickItem* item, - Qt::SizeHint whichHint, const QSizeF& constraint ) -{ - if ( item == nullptr || whichHint < Qt::MinimumSize || whichHint > Qt::MaximumSize ) - return QSizeF( 0, 0 ); - - if ( constraint.isValid() ) - return constraint; - - QSizeF hint( 0, 0 ); - - Type constraintType = Unconstrained; - - if ( whichHint == Qt::PreferredSize ) - constraintType = QskLayoutConstraint::constraintType( item ); - - if ( constraintType != Unconstrained ) - { - const quint32 growFlags = QskSizePolicy::GrowFlag | QskSizePolicy::ExpandFlag; - - if ( constraint.width() > 0 ) // && constrainedType == HeightForWidth ?? - { - qreal w = constraint.width(); - - if ( !( sizePolicy( item ).policy( Qt::Horizontal ) & growFlags ) ) - { - const auto maxW = qskEffectiveSizeHint( item, Qt::PreferredSize ).width(); - - if ( maxW >= 0.0 ) - w = qMin( w, maxW ); - } - - hint.setWidth( w ); - hint.setHeight( heightForWidth( item, w ) ); - } - else if ( constraint.height() > 0 ) // && constrainedType == WidthForHeight ?? - { - qreal h = constraint.height(); - - if ( !( sizePolicy( item ).policy( Qt::Vertical ) & growFlags ) ) - { - const auto maxH = qskEffectiveSizeHint( item, Qt::PreferredSize ).height(); - - if ( maxH >= 0.0 ) - h = qMin( h, maxH ); - } - - hint.setWidth( widthForHeight( item, h ) ); - hint.setHeight( h ); - } - else - { - hint = qskEffectiveSizeHint( item, Qt::PreferredSize ); - - if ( constraintType == WidthForHeight ) - hint.setWidth( widthForHeight( item, hint.height() ) ); - else - hint.setHeight( heightForWidth( item, hint.width() ) ); - } - } - else - { - hint = qskEffectiveSizeHint( item, whichHint ); - } - - hint = hint.expandedTo( QSizeF( 0.0, 0.0 ) ); - - return hint; -} - -QRectF QskLayoutConstraint::boundedRect( const QQuickItem* item, - const QRectF& rect, Qt::Alignment alignment ) -{ - auto size = boundedSize( item, rect.size() ); -#if 0 - size = size.boundedTo( rect.size() ); // ignoring minimumSize -#endif - - return qskAlignedRectF( rect, size.width(), size.height(), alignment ); -} - -QskLayoutHint QskLayoutConstraint::layoutHint( - const QQuickItem* item, Qt::Orientation orientation, qreal constraint ) -{ - if ( item == nullptr ) - return QskLayoutHint(); - - const auto policy = sizePolicy( item ).policy( orientation ); - - if ( constraint >= 0.0 ) - { - if ( !isConstrained( item, orientation ) ) - constraint = -1.0; - } - - qreal minimum, preferred, maximum; - - const auto expandFlags = QskSizePolicy::GrowFlag | QskSizePolicy::ExpandFlag; - - if ( ( policy & QskSizePolicy::ShrinkFlag ) && - ( policy & expandFlags ) && ( policy & QskSizePolicy::IgnoreFlag ) ) - { - // we don't need to calculate the preferred size - - minimum = sizeHint( item, Qt::MinimumSize, orientation, constraint ); - maximum = sizeHint( item, Qt::MaximumSize, orientation, constraint ); - preferred = minimum; - } - else - { - preferred = sizeHint( item, Qt::PreferredSize, orientation, constraint ); - - if ( policy & QskSizePolicy::ShrinkFlag ) - minimum = sizeHint( item, Qt::MinimumSize, orientation, constraint ); - else - minimum = preferred; - - if ( policy & expandFlags ) - maximum = sizeHint( item, Qt::MaximumSize, orientation, constraint ); - else - maximum = preferred; - - if ( policy & QskSizePolicy::IgnoreFlag ) - preferred = minimum; - } - - return QskLayoutHint( minimum, preferred, maximum ); -} - -static const char s_alignmentProperty[] = "layoutAlignmentHint"; -static const char s_retainSizeWhenHiddenProperty[] = "layoutRetainSizeWhenHidden"; - -Qt::Alignment QskLayoutConstraint::layoutAlignmentHint( const QQuickItem* item ) -{ - if ( auto control = qskControlCast( item ) ) - { - return control->layoutAlignmentHint(); - } - else if ( item ) - { - const QVariant v = item->property( s_alignmentProperty ); - if ( v.canConvert< Qt::Alignment >() ) - return v.value< Qt::Alignment >(); - } - - return Qt::Alignment(); -} - -void QskLayoutConstraint::setLayoutAlignmentHint( - QQuickItem* item, Qt::Alignment alignment ) -{ - if ( auto control = qskControlCast( item ) ) - { - control->setLayoutAlignmentHint( alignment ); - } - else if ( item ) - { - QVariant v; - if ( alignment ) - v.setValue( alignment ); - - item->setProperty( s_alignmentProperty, v ); - } -} - -bool QskLayoutConstraint::retainSizeWhenHidden( const QQuickItem* item ) -{ - if ( auto control = qskControlCast( item ) ) - { - return control->layoutHints() & QskControl::RetainSizeWhenHidden; - } - else if ( item ) - { - const QVariant v = item->property( s_retainSizeWhenHiddenProperty ); - if ( v.canConvert< bool >() ) - return v.toBool(); - } - - return false; -} - -void QskLayoutConstraint::setRetainSizeWhenHidden( QQuickItem* item, bool on ) -{ - if ( auto control = qskControlCast( item ) ) - { - control->setLayoutHint( QskControl::RetainSizeWhenHidden, on ); - } - else if ( item ) - { - QVariant v; - if ( on ) - v.setValue( on ); - - item->setProperty( s_retainSizeWhenHiddenProperty, v ); - } -} - -bool QskLayoutConstraint::isVisibleToLayout( const QQuickItem* item ) -{ - if ( item ) - { - if ( !qskIsTransparentForPositioner( item ) ) - return qskIsVisibleToParent( item ) || retainSizeWhenHidden( item ); - } - - return false; -} diff --git a/src/layouts/QskLayoutConstraint.h b/src/layouts/QskLayoutConstraint.h deleted file mode 100644 index 26c4747a..00000000 --- a/src/layouts/QskLayoutConstraint.h +++ /dev/null @@ -1,74 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann - * This file may be used under the terms of the QSkinny License, Version 1.0 - *****************************************************************************/ - -#ifndef QSK_LAYOUT_CONSTRAINT_H -#define QSK_LAYOUT_CONSTRAINT_H - -#include "QskGlobal.h" - -#include -#include -#include -#include - -class QskSizePolicy; -class QskControl; -class QskLayoutHint; -class QQuickItem; -class QSizeF; -class QRectF; - -namespace QskLayoutConstraint -{ - enum Type - { - Unconstrained = 0, - - WidthForHeight = 1 << 0, - HeightForWidth = 1 << 1 - }; - - QSK_EXPORT qreal heightForWidth( const QQuickItem*, qreal width ); - QSK_EXPORT qreal widthForHeight( const QQuickItem*, qreal height ); - - QSK_EXPORT Type constraintType( const QQuickItem* ); - QSK_EXPORT bool isConstrained( const QQuickItem*, Qt::Orientation ); - - QSK_EXPORT qreal constrainedMetric( - Type, const QskControl*, qreal value, - std::function< qreal( Type, const QskControl*, qreal ) > ); - - QSK_EXPORT qreal constrainedChildrenMetric( - Type, const QskControl*, qreal constraint ); - - QSK_EXPORT QskSizePolicy sizePolicy( const QQuickItem* ); - - // size/rect bounded by the layout hints - QSK_EXPORT QSizeF boundedSize( const QQuickItem*, const QSizeF& ); - QSK_EXPORT QRectF boundedRect( - const QQuickItem*, const QRectF&, Qt::Alignment ); - - QSK_EXPORT QSizeF sizeHint( const QQuickItem*, - Qt::SizeHint, const QSizeF& constraint = QSizeF() ); - - QSK_EXPORT qreal sizeHint( - const QQuickItem*, Qt::SizeHint, Qt::Orientation, qreal constraint ); - - QSK_EXPORT QskLayoutHint layoutHint( - const QQuickItem*, Qt::Orientation, qreal constraint ); - - QSK_EXPORT Qt::Alignment layoutAlignmentHint( const QQuickItem* ); - QSK_EXPORT void setLayoutAlignmentHint( QQuickItem*, Qt::Alignment ); - - QSK_EXPORT bool retainSizeWhenHidden( const QQuickItem* ); - QSK_EXPORT void setRetainSizeWhenHidden( QQuickItem*, bool ); - - QSK_EXPORT bool isVisibleToLayout( const QQuickItem* ); - - const qreal unlimited = std::numeric_limits< float >::max(); - const QSizeF defaultSizeHints[] = { { 0, 0 }, { -1, -1 }, { unlimited, unlimited } }; -} - -#endif diff --git a/src/layouts/QskLayoutEngine2D.cpp b/src/layouts/QskLayoutEngine2D.cpp index 45df97d8..2001ed0f 100644 --- a/src/layouts/QskLayoutEngine2D.cpp +++ b/src/layouts/QskLayoutEngine2D.cpp @@ -5,9 +5,99 @@ #include "QskLayoutEngine2D.h" #include "QskLayoutChain.h" +#include "QskLayoutHint.h" #include "QskQuick.h" + #include +static QSizeF qskItemConstraint( const QQuickItem* item, const QSizeF& constraint ) +{ + QSizeF hint( 0, 0 ); + + const auto sizePolicy = qskSizePolicy( item ); + + const auto constraintType = sizePolicy.constraintType(); + const auto which = Qt::PreferredSize; + + if ( constraintType != QskSizePolicy::Unconstrained ) + { + const quint32 growFlags = QskSizePolicy::GrowFlag | QskSizePolicy::ExpandFlag; + + if ( constraint.width() > 0 ) // && constrainedType == HeightForWidth ?? + { + qreal w = constraint.width(); + + if ( !( sizePolicy.policy( Qt::Horizontal ) & growFlags ) ) + { + const auto maxW = qskEffectiveSizeHint( item, which ).width(); + + if ( maxW >= 0.0 ) + w = qMin( w, maxW ); + } + + hint.setWidth( w ); + hint.setHeight( qskHeightForWidth( item, which, w ) ); + } + else if ( constraint.height() > 0 ) // && constrainedType == WidthForHeight ?? + { + qreal h = constraint.height(); + + if ( !( sizePolicy.policy( Qt::Vertical ) & growFlags ) ) + { + const auto maxH = qskEffectiveSizeHint( item, which ).height(); + + if ( maxH >= 0.0 ) + h = qMin( h, maxH ); + } + + hint.setWidth( qskWidthForHeight( item, which, h ) ); + hint.setHeight( h ); + } + else + { + hint = qskEffectiveSizeHint( item, which ); + + if ( constraintType == QskSizePolicy::WidthForHeight ) + hint.setWidth( qskWidthForHeight( item, which, hint.height() ) ); + else + hint.setHeight( qskHeightForWidth( item, which, hint.width() ) ); + } + } + else + { + hint = qskEffectiveSizeHint( item, which ); + } + + hint = hint.expandedTo( QSizeF( 0.0, 0.0 ) ); + + return hint; +} + +static inline qreal qskLayoutConstraint( const QQuickItem* item, + Qt::Orientation orientation, qreal constraint ) +{ + if ( orientation == Qt::Horizontal ) + return qskItemConstraint( item, QSizeF( -1.0, constraint ) ).width(); + else + return qskItemConstraint( item, QSizeF( constraint, -1.0 ) ).height(); +} + +static inline qreal qskEffectiveConstraint( const QQuickItem* item, + Qt::SizeHint which, Qt::Orientation orientation ) +{ + qreal value; + + if ( orientation == Qt::Horizontal ) + value = qskEffectiveSizeHint( item, which ).width(); + else + value = qskEffectiveSizeHint( item, which ).height(); + + if ( value < 0.0 ) + value = ( which == Qt::MaximumSize ) ? QskLayoutHint::unlimited : 0.0; + + return value; +} + namespace { class LayoutData @@ -259,11 +349,11 @@ void QskLayoutEngine2D::layoutItem( QQuickItem* item, const QRect& grid ) const if ( layoutData == nullptr || item == nullptr ) return; - auto alignment = QskLayoutConstraint::layoutAlignmentHint( item ); + auto alignment = qskLayoutAlignmentHint( item ); alignment = m_data->effectiveAlignment( alignment ); - QRectF rect = layoutData->geometryAt( grid ); - rect = QskLayoutConstraint::boundedRect(item, rect, alignment ); + auto rect = layoutData->geometryAt( grid ); + rect = qskConstrainedItemRect( item, rect, alignment ); if ( layoutData->direction == Qt::RightToLeft ) { @@ -298,7 +388,7 @@ QSizeF QskLayoutEngine2D::sizeHint( m_data->blockInvalidate = true; if ( ( constraint.width() >= 0 ) && - ( constraintType() == QskLayoutConstraint::HeightForWidth ) ) + ( constraintType() == QskSizePolicy::HeightForWidth ) ) { setupChain( Qt::Horizontal ); @@ -306,7 +396,7 @@ QSizeF QskLayoutEngine2D::sizeHint( setupChain( Qt::Vertical, constraints ); } else if ( ( constraint.height() >= 0 ) && - ( constraintType() == QskLayoutConstraint::WidthForHeight ) ) + ( constraintType() == QskSizePolicy::WidthForHeight ) ) { setupChain( Qt::Vertical ); @@ -327,6 +417,54 @@ QSizeF QskLayoutEngine2D::sizeHint( return QSizeF( width, height ); } +QskLayoutHint QskLayoutEngine2D::layoutHint( const QQuickItem* item, + Qt::Orientation orientation, qreal constraint ) const +{ + if ( item == nullptr ) + return QskLayoutHint(); + + const auto policy = qskSizePolicy( item ).policy( orientation ); + + if ( constraint >= 0.0 ) + { + if ( !( policy & QskSizePolicy::ConstrainedFlag ) ) + constraint = -1.0; + } + + qreal minimum, preferred, maximum; + + const auto expandFlags = QskSizePolicy::GrowFlag | QskSizePolicy::ExpandFlag; + + if ( ( policy & QskSizePolicy::ShrinkFlag ) && + ( policy & expandFlags ) && ( policy & QskSizePolicy::IgnoreFlag ) ) + { + // we don't need to calculate the preferred size + + minimum = qskEffectiveConstraint( item, Qt::MinimumSize, orientation ); + maximum = qskEffectiveConstraint( item, Qt::MaximumSize, orientation ); + preferred = minimum; + } + else + { + preferred = qskLayoutConstraint( item, orientation, constraint ); + + if ( policy & QskSizePolicy::ShrinkFlag ) + minimum = qskEffectiveConstraint( item, Qt::MinimumSize, orientation ); + else + minimum = preferred; + + if ( policy & expandFlags ) + maximum = qskEffectiveConstraint( item, Qt::MaximumSize, orientation ); + else + maximum = preferred; + + if ( policy & QskSizePolicy::IgnoreFlag ) + preferred = minimum; + } + + return QskLayoutHint( minimum, preferred, maximum ); +} + void QskLayoutEngine2D::setupChain( Qt::Orientation orientation ) const { setupChain( orientation, QskLayoutChain::Segments() ); @@ -371,7 +509,7 @@ void QskLayoutEngine2D::updateSegments( const QSizeF& size ) const switch( constraintType() ) { - case QskLayoutConstraint::WidthForHeight: + case QskSizePolicy::WidthForHeight: { setupChain( Qt::Vertical ); rows = rowChain.segments( size.height() ); @@ -381,7 +519,7 @@ void QskLayoutEngine2D::updateSegments( const QSizeF& size ) const break; } - case QskLayoutConstraint::HeightForWidth: + case QskSizePolicy::HeightForWidth: { setupChain( Qt::Horizontal ); columns = columnChain.segments( size.width() ); @@ -426,28 +564,26 @@ void QskLayoutEngine2D::invalidate( int what ) } } -QskLayoutConstraint::Type QskLayoutEngine2D::constraintType() const +QskSizePolicy::ConstraintType QskLayoutEngine2D::constraintType() const { if ( m_data->constraintType < 0 ) { - auto constraintType = QskLayoutConstraint::Unconstrained; + auto constraintType = QskSizePolicy::Unconstrained; for ( int i = 0; i < count(); i++ ) { - const auto type = QskLayoutConstraint::constraintType( itemAt( i ) ); + const auto type = qskSizePolicy( itemAt( i ) ).constraintType(); - using namespace QskLayoutConstraint; - - if ( type != Unconstrained ) + if ( type != QskSizePolicy::Unconstrained ) { - if ( constraintType == Unconstrained ) + if ( constraintType == QskSizePolicy::Unconstrained ) { constraintType = type; } else if ( constraintType != type ) { qWarning( "QskLayoutEngine2D: conflicting constraints"); - constraintType = Unconstrained; + constraintType = QskSizePolicy::Unconstrained; } } } @@ -455,6 +591,6 @@ QskLayoutConstraint::Type QskLayoutEngine2D::constraintType() const m_data->constraintType = constraintType; } - return static_cast< QskLayoutConstraint::Type >( m_data->constraintType ); + return static_cast< QskSizePolicy::ConstraintType >( m_data->constraintType ); } diff --git a/src/layouts/QskLayoutEngine2D.h b/src/layouts/QskLayoutEngine2D.h index 2d9214ac..bedb44ce 100644 --- a/src/layouts/QskLayoutEngine2D.h +++ b/src/layouts/QskLayoutEngine2D.h @@ -8,11 +8,14 @@ #include "QskGlobal.h" #include "QskLayoutChain.h" -#include "QskLayoutConstraint.h" +#include "QskSizePolicy.h" #include #include +class QQuickItem; +class QskLayoutHint; + class QskLayoutEngine2D { public: @@ -55,6 +58,8 @@ class QskLayoutEngine2D protected: void layoutItem( QQuickItem*, const QRect& grid ) const; + QskLayoutHint layoutHint( const QQuickItem*, + Qt::Orientation, qreal constraint ) const; enum { @@ -73,7 +78,7 @@ class QskLayoutEngine2D virtual int effectiveCount( Qt::Orientation ) const = 0; virtual void invalidateElementCache() = 0; - QskLayoutConstraint::Type constraintType() const; + QskSizePolicy::ConstraintType constraintType() const; void setupChain( Qt::Orientation ) const; void setupChain( Qt::Orientation, const QskLayoutChain::Segments& ) const; diff --git a/src/layouts/QskLayoutHint.cpp b/src/layouts/QskLayoutHint.cpp index 98fffff7..2f9e919c 100644 --- a/src/layouts/QskLayoutHint.cpp +++ b/src/layouts/QskLayoutHint.cpp @@ -4,11 +4,11 @@ *****************************************************************************/ #include "QskLayoutHint.h" -#include "QskLayoutConstraint.h" +#include "QskControl.h" #include QskLayoutHint::QskLayoutHint() - : QskLayoutHint( 0.0, 0.0, QskLayoutConstraint::unlimited ) + : QskLayoutHint( 0.0, 0.0, QskLayoutHint::unlimited ) { } @@ -75,7 +75,21 @@ void QskLayoutHint::normalize() bool QskLayoutHint::isDefault() const { return ( m_minimum == 0.0 ) && ( m_preferred == 0.0 ) - && ( m_maximum == QskLayoutConstraint::unlimited ); + && ( m_maximum == QskLayoutHint::unlimited ); +} + +qreal QskLayoutHint::combined( int which, qreal value1, qreal value2 ) +{ + if ( value1 < 0.0 ) + return value2; + + if ( value2 < 0.0 ) + return value1; + + if ( which == Qt::MaximumSize ) + return qMin( value1, value2 ); + else + return qMax( value1, value2 ); } #ifndef QT_NO_DEBUG_STREAM @@ -84,7 +98,7 @@ bool QskLayoutHint::isDefault() const static inline QString qskHintValueString( qreal value ) { - if ( value >= QskLayoutConstraint::unlimited ) + if ( value >= QskLayoutHint::unlimited ) return QStringLiteral( "unlimited" ); else return QString::number( value ); diff --git a/src/layouts/QskLayoutHint.h b/src/layouts/QskLayoutHint.h index 4a04550f..2733f7e7 100644 --- a/src/layouts/QskLayoutHint.h +++ b/src/layouts/QskLayoutHint.h @@ -8,6 +8,7 @@ #include "QskGlobal.h" #include +#include class QDebug; @@ -44,6 +45,9 @@ class QSK_EXPORT QskLayoutHint void expandPreferred( qreal value ); void expandMaximum( qreal value ); + static qreal combined( int which, qreal value1, qreal value2 ); + static constexpr qreal unlimited = std::numeric_limits< float >::max(); + private: qreal m_minimum; qreal m_preferred; diff --git a/src/layouts/QskLinearBox.cpp b/src/layouts/QskLinearBox.cpp index 48e26a3e..8001ca30 100644 --- a/src/layouts/QskLinearBox.cpp +++ b/src/layouts/QskLinearBox.cpp @@ -5,8 +5,6 @@ #include "QskLinearBox.h" #include "QskLinearLayoutEngine.h" - -#include "QskLayoutConstraint.h" #include "QskEvent.h" #include "QskQuick.h" @@ -188,33 +186,16 @@ void QskLinearBox::updateLayout() m_data->engine.setGeometries( layoutRect() ); } -QSizeF QskLinearBox::contentsSizeHint() const +QSizeF QskLinearBox::layoutSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const { - return m_data->engine.sizeHint( Qt::PreferredSize, QSizeF() ); -} + if ( which == Qt::MaximumSize ) + { + // we can extend beyond the maximum size of the children + return QSizeF(); + } -qreal QskLinearBox::heightForWidth( qreal width ) const -{ - auto constrainedHeight = - [this]( QskLayoutConstraint::Type, const QskControl*, qreal width ) - { - return m_data->engine.heightForWidth( width ); - }; - - return QskLayoutConstraint::constrainedMetric( - QskLayoutConstraint::HeightForWidth, this, width, constrainedHeight ); -} - -qreal QskLinearBox::widthForHeight( qreal height ) const -{ - auto constrainedWidth = - [this]( QskLayoutConstraint::Type, const QskControl*, qreal height ) - { - return m_data->engine.widthForHeight( height ); - }; - - return QskLayoutConstraint::constrainedMetric( - QskLayoutConstraint::WidthForHeight, this, height, constrainedWidth ); + return m_data->engine.sizeHint( which, constraint ); } void QskLinearBox::geometryChangeEvent( QskGeometryChangeEvent* event ) diff --git a/src/layouts/QskLinearBox.h b/src/layouts/QskLinearBox.h index 13a79d76..f625fc6e 100644 --- a/src/layouts/QskLinearBox.h +++ b/src/layouts/QskLinearBox.h @@ -54,9 +54,6 @@ class QSK_EXPORT QskLinearBox : public QskIndexedLayoutBox void removeItem( const QQuickItem* ); void removeAt( int index ); - qreal heightForWidth( qreal width ) const override; - qreal widthForHeight( qreal height ) const override; - Qt::Orientation orientation() const; void setOrientation( Qt::Orientation ); @@ -108,7 +105,7 @@ class QSK_EXPORT QskLinearBox : public QskIndexedLayoutBox void itemChange( ItemChange, const ItemChangeData& ) override; void updateLayout() override; - QSizeF contentsSizeHint() const override; + QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override; void autoAddItem( QQuickItem* ) override final; void autoRemoveItem( QQuickItem* ) override final; diff --git a/src/layouts/QskLinearLayoutEngine.cpp b/src/layouts/QskLinearLayoutEngine.cpp index 957cf0aa..5609e027 100644 --- a/src/layouts/QskLinearLayoutEngine.cpp +++ b/src/layouts/QskLinearLayoutEngine.cpp @@ -5,7 +5,6 @@ #include "QskLinearLayoutEngine.h" #include "QskLayoutHint.h" -#include "QskLayoutConstraint.h" #include "QskLayoutChain.h" #include "QskSizePolicy.h" #include "QskQuick.h" @@ -36,8 +35,8 @@ namespace bool isIgnored() const; - QskLayoutChain::CellData cell( Qt::Orientation, - bool isLayoutOrientation, qreal constraint ) const; + QskLayoutChain::CellData cell( + Qt::Orientation, bool isLayoutOrientation ) const; private: @@ -100,14 +99,11 @@ inline void Element::setStretch( int stretch ) bool Element::isIgnored() const { - if ( !m_isSpacer && !QskLayoutConstraint::retainSizeWhenHidden( m_item ) ) - return !qskIsVisibleToParent( m_item ); - - return false; + return !( m_isSpacer || qskIsVisibleToLayout( m_item ) ); } -QskLayoutChain::CellData Element::cell( Qt::Orientation orientation, - bool isLayoutOrientation, qreal constraint ) const +QskLayoutChain::CellData Element::cell( + Qt::Orientation orientation, bool isLayoutOrientation ) const { QskLayoutChain::CellData cell; cell.canGrow = true; @@ -115,9 +111,7 @@ QskLayoutChain::CellData Element::cell( Qt::Orientation orientation, if ( !m_isSpacer ) { - cell.hint = QskLayoutConstraint::layoutHint( m_item, orientation, constraint ); - - const auto policy = QskLayoutConstraint::sizePolicy( m_item ).policy( orientation ); + const auto policy = qskSizePolicy( m_item ).policy( orientation ); if ( isLayoutOrientation ) { @@ -302,12 +296,11 @@ bool QskLinearLayoutEngine::removeAt( int index ) if ( element->isIgnored() ) m_data->sumIgnored--; - const auto itemType = - QskLayoutConstraint::constraintType( element->item() ); + const auto itemType = qskSizePolicy( element->item() ).constraintType(); int invalidationMode = LayoutCache; - if ( itemType > QskLayoutConstraint::Unconstrained ) + if ( itemType > QskSizePolicy::Unconstrained ) invalidationMode |= ElementCache; m_data->elements.erase( m_data->elements.begin() + index ); @@ -435,8 +428,10 @@ void QskLinearLayoutEngine::setupChain( Qt::Orientation orientation, if ( !constraints.isEmpty() ) constraint = constraints[index1].length; - const auto cell = element.cell( - orientation, isLayoutOrientation, constraint ); + auto cell = element.cell( orientation, isLayoutOrientation ); + + if ( element.item() ) + cell.hint = layoutHint( element.item(), orientation, constraint ); chain.expandCell( index2, cell ); diff --git a/src/layouts/QskStackBox.cpp b/src/layouts/QskStackBox.cpp index 0af4ee92..443f2889 100644 --- a/src/layouts/QskStackBox.cpp +++ b/src/layouts/QskStackBox.cpp @@ -5,36 +5,12 @@ #include "QskStackBox.h" #include "QskStackBoxAnimator.h" -#include "QskLayoutConstraint.h" +#include "QskLayoutHint.h" #include "QskEvent.h" #include "QskQuick.h" #include -static qreal qskConstrainedValue( QskLayoutConstraint::Type type, - const QskControl* control, qreal widthOrHeight ) -{ - using namespace QskLayoutConstraint; - - auto constrainFunction = - ( type == WidthForHeight ) ? widthForHeight : heightForWidth; - - qreal constrainedValue = -1; - auto stackBox = static_cast< const QskStackBox* >( control ); - - for ( int i = 0; i < stackBox->itemCount(); i++ ) - { - if ( const auto item = stackBox->itemAtIndex( i ) ) - { - const qreal v = constrainFunction( item, widthOrHeight ); - if ( v > constrainedValue ) - constrainedValue = v; - } - } - - return constrainedValue; -} - class QskStackBox::PrivateData { public: @@ -328,11 +304,11 @@ QRectF QskStackBox::geometryForItemAt( int index ) const if ( const auto item = m_data->items.value( index ) ) { - auto alignment = QskLayoutConstraint::layoutAlignmentHint( item ); + auto alignment = qskLayoutAlignmentHint( item ); if ( alignment == 0 ) alignment = m_data->defaultAlignment; - return QskLayoutConstraint::boundedRect( item, r, alignment ); + return qskConstrainedItemRect( item, r, alignment ); } return QRectF( r.x(), r.y(), 0.0, 0.0 ); @@ -352,91 +328,93 @@ void QskStackBox::updateLayout() } } -QSizeF QskStackBox::contentsSizeHint() const +QSizeF QskStackBox::layoutSizeHint( + Qt::SizeHint which, const QSizeF& constraint ) const { -#if 1 + // needs to reimplemented TODO ... + + if ( which != Qt::PreferredSize ) + return QSizeF(); + if ( itemCount() == 0 ) - return QSizeF( 0, 0 ); -#endif + return QSizeF(); + + if ( constraint.width() >= 0 || constraint.height() >= 0 ) + { + qreal value = -1; + + for ( const auto& item : qskAsConst( m_data->items ) ) + { + const auto hint = qskEffectiveSizeHint( + item, Qt::PreferredSize, constraint ); + + if ( constraint.width() >= 0 ) + value = qMax( hint.height(), value ); + else + value = qMax( hint.width(), value ); + } + + if ( constraint.width() >= 0 ) + return QSizeF( constraint.width(), value ); + else + return QSizeF( value, constraint.height() ); + } qreal width = -1; qreal height = -1; - using namespace QskLayoutConstraint; - - int constraintTypes = Unconstrained; + int constraintTypes = QskSizePolicy::Unconstrained; for ( const auto item : qskAsConst( m_data->items ) ) { - const auto type = constraintType( item ); - if ( type != Unconstrained ) + const auto type = qskSizePolicy( item ).constraintType(); + if ( type != QskSizePolicy::Unconstrained ) { constraintTypes |= type; + continue; } - else - { - const auto hint = QskLayoutConstraint::sizeHint( - item, Qt::PreferredSize, QSizeF( -1, -1 ) ); - if ( hint.width() >= width ) - width = hint.width(); + const auto hint = qskSizeConstraint( item, which, constraint ); - if ( hint.height() >= height ) - height = hint.height(); - } + width = QskLayoutHint::combined( which, width, hint.width() ); + height = QskLayoutHint::combined( which, height, hint.height() ); } -#if 1 - // does this work ??? - - if ( constraintTypes & WidthForHeight ) + if ( constraintTypes & QskSizePolicy::WidthForHeight ) { const QSizeF constraint( -1, height ); for ( const auto& item : qskAsConst( m_data->items ) ) { - if ( constraintType( item ) == WidthForHeight ) - { - const auto hint = QskLayoutConstraint::sizeHint( - item, Qt::PreferredSize, constraint ); + const auto sizePolicy = qskSizePolicy( item ); - width = qMax( width, hint.width() ); + if ( sizePolicy.constraintType() == QskSizePolicy::WidthForHeight ) + { + const auto hint = qskSizeConstraint( item, which, constraint ); + width = QskLayoutHint::combined( which, width, hint.width() ); } } } - if ( constraintTypes & HeightForWidth ) + if ( constraintTypes & QskSizePolicy::HeightForWidth ) { const QSizeF constraint( width, -1 ); for ( const auto& item : qskAsConst( m_data->items ) ) { - if ( constraintType( item ) == HeightForWidth ) - { - const QSizeF hint = QskLayoutConstraint::sizeHint( - item, Qt::PreferredSize, constraint ); + const auto sizePolicy = qskSizePolicy( item ); - height = qMax( height, hint.height() ); + if ( sizePolicy.constraintType() == QskSizePolicy::HeightForWidth ) + { + const auto hint = qskSizeConstraint( item, which, constraint ); + height = QskLayoutHint::combined( which, height, hint.height() ); } } } -#endif return QSizeF( width, height ); } -qreal QskStackBox::heightForWidth( qreal width ) const -{ - return QskLayoutConstraint::constrainedMetric( - QskLayoutConstraint::HeightForWidth, this, width, qskConstrainedValue ); -} - -qreal QskStackBox::widthForHeight( qreal height ) const -{ - return QskLayoutConstraint::constrainedMetric( - QskLayoutConstraint::WidthForHeight, this, height, qskConstrainedValue ); -} - bool QskStackBox::event( QEvent* event ) { switch ( static_cast< int >( event->type() ) ) diff --git a/src/layouts/QskStackBox.h b/src/layouts/QskStackBox.h index a9284e3e..eecad1ba 100644 --- a/src/layouts/QskStackBox.h +++ b/src/layouts/QskStackBox.h @@ -51,9 +51,6 @@ class QSK_EXPORT QskStackBox : public QskIndexedLayoutBox const QskStackBoxAnimator* animator() const; QskStackBoxAnimator* animator(); - qreal heightForWidth( qreal width ) const override; - qreal widthForHeight( qreal height ) const override; - QRectF geometryForItemAt( int index ) const; Q_SIGNALS: @@ -72,7 +69,7 @@ class QSK_EXPORT QskStackBox : public QskIndexedLayoutBox bool event( QEvent* ) override; void updateLayout() override; - QSizeF contentsSizeHint() const override; + QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override; void autoAddItem( QQuickItem* ) override final; void autoRemoveItem( QQuickItem* ) override final; diff --git a/src/src.pro b/src/src.pro index b187faaa..feb8a7a1 100644 --- a/src/src.pro +++ b/src/src.pro @@ -243,7 +243,6 @@ HEADERS += \ layouts/QskGridBox.h \ layouts/QskGridLayoutEngine.h \ layouts/QskIndexedLayoutBox.h \ - layouts/QskLayoutConstraint.h \ layouts/QskLayoutChain.h \ layouts/QskLayoutEngine2D.cpp \ layouts/QskLayoutHint.h \ @@ -257,7 +256,6 @@ SOURCES += \ layouts/QskGridLayoutEngine.cpp \ layouts/QskIndexedLayoutBox.cpp \ layouts/QskLayoutChain.cpp \ - layouts/QskLayoutConstraint.cpp \ layouts/QskLayoutEngine2D.cpp \ layouts/QskLayoutHint.cpp \ layouts/QskLinearBox.cpp \