processing of all type of size constraints ( minimum/preferred/maximum )

completed
This commit is contained in:
Uwe Rathmann 2019-09-10 17:01:47 +02:00
parent 9e87cb7b23
commit 177bb699bc
76 changed files with 1179 additions and 1345 deletions

View File

@ -61,7 +61,11 @@ void ButtonBar::addIndicator( const char* name )
label->setGraphic( QskGraphicIO::read( fileName ) ); label->setGraphic( QskGraphicIO::read( fileName ) );
} }
QSizeF ButtonBar::contentsSizeHint() const QSizeF ButtonBar::layoutSizeHint(
Qt::SizeHint which, const QSizeF& ) const
{ {
if ( which == Qt::PreferredSize )
return QSizeF( -1, 20 ); return QSizeF( -1, 20 );
return QSizeF();
} }

View File

@ -17,7 +17,7 @@ class ButtonBar : public QskLinearBox
void addIndicator( const char* name ); void addIndicator( const char* name );
protected: protected:
QSizeF contentsSizeHint() const override; QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override;
}; };
#endif #endif

View File

@ -132,8 +132,11 @@ class MarkerControlButton final : public QskPushButton
} }
protected: protected:
QSizeF contentsSizeHint() const override QSizeF contentsSizeHint( Qt::SizeHint which, const QSizeF& ) const override
{ {
if ( which != Qt::PreferredSize )
return QSizeF();
const qreal dim = 100; const qreal dim = 100;
if ( m_direction == Qsk::LeftToRight || m_direction == Qsk::RightToLeft ) if ( m_direction == Qsk::LeftToRight || m_direction == Qsk::RightToLeft )
@ -167,11 +170,16 @@ class ControlButton final : public QskPushButton
return QskPushButton::effectiveSubcontrol( subControl ); return QskPushButton::effectiveSubcontrol( subControl );
} }
QSizeF contentsSizeHint() const override QSizeF contentsSizeHint( Qt::SizeHint which, const QSizeF& ) const override
{ {
qreal h = QskPushButton::contentsSizeHint().height(); if ( which == Qt::PreferredSize )
{
qreal h = QskPushButton::contentsSizeHint( which, QSizeF() ).height();
return QSizeF( h, h ); return QSizeF( h, h );
} }
return QSizeF();
}
}; };
class StackedControl final : public QskControl class StackedControl final : public QskControl

View File

@ -19,11 +19,11 @@ namespace
Control( const char* colorName, QQuickItem* parent = nullptr ); Control( const char* colorName, QQuickItem* parent = nullptr );
Control( const char* colorName, qreal aspectRatio, 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(); void transpose();
protected:
QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override;
private: private:
qreal m_aspectRatio; qreal m_aspectRatio;
}; };
@ -65,14 +65,19 @@ Control::Control( const char* colorName, qreal aspectRatio, QQuickItem* parent )
setPreferredHeight( 100 ); 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 if ( constraint.height() >= 0.0 )
{ return QSizeF( constraint.height() * m_aspectRatio, -1.0 );
return height * m_aspectRatio; }
return QSizeF();
} }
void Control::transpose() void Control::transpose()

View File

@ -179,26 +179,33 @@ QskGraphic MyToggleButton::graphicAt( int index ) const
return data.icon; return data.icon;
} }
QSizeF MyToggleButton::contentsSizeHint() const QSizeF MyToggleButton::contentsSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{ {
const qreal width = metric( Panel | QskAspect::MinimumWidth ); if ( which != Qt::PreferredSize )
const qreal height = metric( Panel | QskAspect::MinimumHeight ); 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 QSizeF( w, h );
{
return width / aspectRatio;
}
qreal MyToggleButton::widthForHeight( qreal height ) const
{
return height * aspectRatio;
} }
void MyToggleButton::updateLayout() void MyToggleButton::updateLayout()

View File

@ -29,9 +29,6 @@ class MyToggleButton : public QskAbstractButton
void setIconAt( int index, const QString& icon ); void setIconAt( int index, const QString& icon );
QString iconAt( int index ) const; QString iconAt( int index ) const;
qreal heightForWidth( qreal width ) const override;
qreal widthForHeight( qreal height ) const override;
void setTextOptions( const QskTextOptions& ); void setTextOptions( const QskTextOptions& );
QskTextOptions textOptions() const; QskTextOptions textOptions() const;
@ -45,7 +42,7 @@ class MyToggleButton : public QskAbstractButton
protected: protected:
void updateLayout() override; void updateLayout() override;
QSizeF contentsSizeHint() const override; QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override;
private: private:
class PrivateData; class PrivateData;

View File

@ -53,10 +53,15 @@ Slider::Slider( QQuickItem* parentItem )
this, &QskControl::focusIndicatorRectChanged ); this, &QskControl::focusIndicatorRectChanged );
} }
QSizeF Slider::contentsSizeHint() const QSizeF Slider::contentsSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{ {
const qreal extra = 40; auto size = Inherited::contentsSizeHint( which, constraint );
return Inherited::contentsSizeHint() + QSizeF( 0, extra );
if ( which == Qt::PreferredSize && size.height() >= 0 )
size.setHeight( size.height() + 40 );
return size;
} }
QRectF Slider::focusIndicatorRect() const QRectF Slider::focusIndicatorRect() const

View File

@ -20,7 +20,7 @@ class Slider : public QskSlider
QRectF focusIndicatorRect() const override; QRectF focusIndicatorRect() const override;
protected: protected:
QSizeF contentsSizeHint() const override; QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override;
}; };
#endif #endif

View File

@ -10,7 +10,6 @@
#include "Variable.h" #include "Variable.h"
#include "Expression.h" #include "Expression.h"
#include <QskLayoutConstraint.h>
#include <QskEvent.h> #include <QskEvent.h>
#include <QskQuick.h> #include <QskQuick.h>
@ -122,14 +121,18 @@ void AnchorBox::PrivateData::setupSolver( int type, Solver& solver )
if ( type < 0 || type == Qt::MinimumSize ) if ( type < 0 || type == Qt::MinimumSize )
{ {
const auto minSize = QskLayoutConstraint::sizeHint( item, Qt::MinimumSize ); const auto minSize = qskSizeConstraint( item, Qt::MinimumSize );
if ( minSize.width() >= 0.0 )
solver.addConstraint( r.right >= r.left + minSize.width() ); solver.addConstraint( r.right >= r.left + minSize.width() );
if ( minSize.height() >= 0.0 )
solver.addConstraint( r.bottom >= r.top + minSize.height() ); solver.addConstraint( r.bottom >= r.top + minSize.height() );
} }
if ( type < 0 || type == Qt::PreferredSize ) 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 ); Constraint c1( r.right == r.left + prefSize.width(), Strength::strong );
solver.addConstraint( c1 ); solver.addConstraint( c1 );
@ -140,11 +143,11 @@ void AnchorBox::PrivateData::setupSolver( int type, Solver& solver )
if ( type < 0 || type == Qt::MaximumSize ) if ( type < 0 || type == Qt::MaximumSize )
{ {
const auto maxSize = QskLayoutConstraint::sizeHint( item, Qt::MaximumSize ); const auto maxSize = qskSizeConstraint( item, Qt::MaximumSize );
if ( maxSize.width() < QskLayoutConstraint::unlimited ) if ( maxSize.width() >= 0.0 )
solver.addConstraint( r.right <= r.left + maxSize.width() ); 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() ); solver.addConstraint( r.bottom <= r.top + maxSize.height() );
} }
} }

View File

@ -19,6 +19,37 @@ void QskSizePolicy::setPolicy( Qt::Orientation orientation, Policy policy )
setVerticalPolicy( 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 #ifndef QT_NO_DEBUG_STREAM
#include <qdebug.h> #include <qdebug.h>

View File

@ -7,6 +7,7 @@
#define QSK_SIZE_POLICY_H_ #define QSK_SIZE_POLICY_H_
#include "QskGlobal.h" #include "QskGlobal.h"
#include <qnamespace.h>
#include <qmetatype.h> #include <qmetatype.h>
class QDebug; class QDebug;
@ -52,8 +53,17 @@ class QSK_EXPORT QskSizePolicy
ConstrainedExpanding = ConstrainedFlag | Expanding ConstrainedExpanding = ConstrainedFlag | Expanding
}; };
enum ConstraintType
{
Unconstrained = 0,
WidthForHeight = 1 << 0,
HeightForWidth = 1 << 1
};
Q_ENUM( Flag ) Q_ENUM( Flag )
Q_ENUM( Policy ) Q_ENUM( Policy )
Q_ENUM( ConstraintType )
QskSizePolicy(); QskSizePolicy();
QskSizePolicy( Policy horizontalPolicy, Policy verticalPolicy ); QskSizePolicy( Policy horizontalPolicy, Policy verticalPolicy );
@ -70,6 +80,12 @@ class QSK_EXPORT QskSizePolicy
Policy policy( Qt::Orientation ) const; Policy policy( Qt::Orientation ) const;
void setPolicy( Qt::Orientation, Policy ); void setPolicy( Qt::Orientation, Policy );
ConstraintType constraintType() const;
bool isConstrained( Qt::Orientation ) const;
Qt::SizeHint effectiveSizeHintType(
Qt::SizeHint, Qt::Orientation ) const;
private: private:
unsigned char m_horizontalPolicy; unsigned char m_horizontalPolicy;
unsigned char m_verticalPolicy; unsigned char m_verticalPolicy;
@ -119,6 +135,11 @@ inline QskSizePolicy::Policy QskSizePolicy::verticalPolicy() const
return static_cast< Policy >( m_verticalPolicy ); return static_cast< Policy >( m_verticalPolicy );
} }
inline bool QskSizePolicy::isConstrained( Qt::Orientation orientation ) const
{
return ( policy( orientation ) & ConstrainedFlag );
}
#ifndef QT_NO_DEBUG_STREAM #ifndef QT_NO_DEBUG_STREAM
QSK_EXPORT QDebug operator<<( QDebug, const QskSizePolicy& ); QSK_EXPORT QDebug operator<<( QDebug, const QskSizePolicy& );
#endif #endif

View File

@ -47,29 +47,17 @@ QRectF QskBox::layoutRectForSize( const QSizeF& size ) const
return innerBox( Panel, subControlRect( size, Panel ) ); return innerBox( Panel, subControlRect( size, Panel ) );
} }
QSizeF QskBox::contentsSizeHint() const QSizeF QskBox::contentsSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{ {
if ( !m_hasPanel ) if ( m_hasPanel && which == Qt::PreferredSize )
return Inherited::contentsSizeHint();
QSizeF size( -1, -1 );
if ( autoLayoutChildren() )
{ {
const QSizeF hint = Inherited::contentsSizeHint(); return QSizeF(
if ( hint.width() > 0 )
size.setWidth( hint.width() );
if ( hint.height() > 0 )
size.setHeight( hint.height() );
}
const QSizeF minSize(
metric( Panel | QskAspect::MinimumWidth ), metric( Panel | QskAspect::MinimumWidth ),
metric( Panel | QskAspect::MinimumHeight ) ); metric( Panel | QskAspect::MinimumHeight ) );
}
return outerBoxSize( Panel, size ).expandedTo( minSize ); return Inherited::contentsSizeHint( which, constraint );
} }
#include "moc_QskBox.cpp" #include "moc_QskBox.cpp"

View File

@ -30,12 +30,12 @@ class QSK_EXPORT QskBox : public QskControl
QRectF layoutRectForSize( const QSizeF& ) const override; QRectF layoutRectForSize( const QSizeF& ) const override;
protected:
QSizeF contentsSizeHint() const override;
Q_SIGNALS: Q_SIGNALS:
void panelChanged( bool ); void panelChanged( bool );
protected:
QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override;
private: private:
bool m_hasPanel; bool m_hasPanel;
}; };

View File

@ -14,7 +14,7 @@
#include "QskSkin.h" #include "QskSkin.h"
#include "QskSkinlet.h" #include "QskSkinlet.h"
#include "QskSkinHintTable.h" #include "QskSkinHintTable.h"
#include "QskLayoutConstraint.h" #include "QskLayoutHint.h"
#include <qlocale.h> #include <qlocale.h>
#include <qvector.h> #include <qvector.h>
@ -569,17 +569,17 @@ void QskControl::setExplicitSizeHint(
QSizeF QskControl::explicitSizeHint( Qt::SizeHint whichHint ) const QSizeF QskControl::explicitSizeHint( Qt::SizeHint whichHint ) const
{ {
if ( whichHint >= Qt::MinimumSize && whichHint <= Qt::MaximumSize ) if ( whichHint < Qt::MinimumSize || whichHint > Qt::MaximumSize )
return d_func()->explicitSizeHint( whichHint ); return QSizeF();
return QSizeF( -1, -1 ); return d_func()->explicitSizeHint( whichHint );
} }
QSizeF QskControl::implicitSizeHint( QSizeF QskControl::implicitSizeHint(
Qt::SizeHint whichHint, const QSizeF& constraint ) const Qt::SizeHint whichHint, const QSizeF& constraint ) const
{ {
if ( whichHint < Qt::MinimumSize || whichHint > Qt::MaximumSize ) if ( whichHint < Qt::MinimumSize || whichHint > Qt::MaximumSize )
return QSizeF( -1, -1 ); return QSizeF();
if ( constraint.isValid() ) if ( constraint.isValid() )
{ {
@ -587,108 +587,94 @@ QSizeF QskControl::implicitSizeHint(
return constraint; 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
{ {
// this one might be cached
hint = implicitSize(); hint = implicitSize();
} }
}
else else
{ {
// TODO ... hint = d_func()->implicitSizeHint( whichHint, constraint );
} }
return hint; return hint;
} }
QSizeF QskControl::effectiveSizeHint( 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 ); return QSizeF( 0, 0 );
if ( constraint.isValid() )
return constraint;
const bool isConstrained =
constraint.width() >= 0 || constraint.height() >= 0;
Q_D( const QskControl ); Q_D( const QskControl );
d->blockLayoutRequestEvents = false; d->blockLayoutRequestEvents = false;
/* QSizeF hint;
The explicit size has always precedence over te implicit size.
Implicit sizes are currently only implemented for preferred and /*
explicitSizeHint returns valid explicit hints for minimum/maximum The explicit size has always precedence over the implicit size,
even if not being set by application code. and will kill the effect of the constraint
*/ */
QSizeF hint = d->explicitSizeHint( whichHint ); hint = d->explicitSizeHint( which );
if ( !hint.isValid() ) if ( !hint.isValid() )
{ {
#if 0 const auto implicitHint = implicitSizeHint( which, constraint );
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 );
if ( hint.width() < 0 ) if ( hint.width() < 0 )
hint.setWidth( implicit.width() ); hint.setWidth( implicitHint.width() );
if ( hint.height() < 0 ) 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. we always have: minimum <= preferred <= maximum.
*/ */
if ( whichHint == Qt::MaximumSize ) if ( which == Qt::MaximumSize )
{ {
const auto minimumHint = d->explicitSizeHint( Qt::MinimumSize ); const auto minimumHint = d->explicitSizeHint( Qt::MinimumSize );
if ( hint.width() >= 0 ) if ( hint.width() >= 0 )
hint.setWidth( qMax( hint.width(), minimumHint.width() ) ); hint.rwidth() = qMax( hint.width(), minimumHint.width() );
if ( hint.height() >= 0 ) 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 minimumHint = d->explicitSizeHint( Qt::MinimumSize );
const auto maximumHint = d->explicitSizeHint( Qt::MaximumSize ); const auto maximumHint = d->explicitSizeHint( Qt::MaximumSize );
if ( hint.width() >= 0 ) if ( hint.width() >= 0 )
{ {
const auto minW = minimumHint.width(); if ( maximumHint.width() >= 0 )
const auto maxW = qMax( minW, maximumHint.width() ); 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 ) if ( hint.height() >= 0 )
{ {
const auto minH = minimumHint.height(); if ( maximumHint.height() >= 0 )
const auto maxH = qMax( minH, maximumHint.height() ); 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 qreal QskControl::heightForWidth( qreal width ) const
{ {
Q_D( const QskControl ); const auto hint = effectiveSizeHint(
Qt::PreferredSize, QSizeF( width, -1.0 ) );
d->blockLayoutRequestEvents = false; return hint.height();
if ( d->autoLayoutChildren )
{
using namespace QskLayoutConstraint;
return constrainedMetric( HeightForWidth, this, width, constrainedChildrenMetric );
}
return -1.0;
} }
qreal QskControl::widthForHeight( qreal height ) const qreal QskControl::widthForHeight( qreal height ) const
{ {
Q_D( const QskControl ); const auto hint = effectiveSizeHint(
Qt::PreferredSize, QSizeF( -1.0, height ) );
d->blockLayoutRequestEvents = false; return hint.width();
if ( d->autoLayoutChildren )
{
using namespace QskLayoutConstraint;
return constrainedMetric( WidthForHeight, this, height, constrainedChildrenMetric );
}
return -1.0;
} }
bool QskControl::event( QEvent* event ) bool QskControl::event( QEvent* event )
@ -918,10 +890,8 @@ void QskControl::updateItemPolish()
// checking qskIsVisibleToParent ??? // checking qskIsVisibleToParent ???
if ( !qskIsTransparentForPositioner( child ) ) if ( !qskIsTransparentForPositioner( child ) )
{ {
const auto itemRect = QskLayoutConstraint::boundedRect( const auto r = qskConstrainedItemRect( child, rect );
child, rect, QskLayoutConstraint::layoutAlignmentHint( child ) ); qskSetItemGeometry( child, r );
qskSetItemGeometry( child, itemRect );
} }
} }
} }
@ -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 return constraint;
qreal h = -1; }
QSizeF QskControl::layoutSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
if ( !d_func()->autoLayoutChildren )
return QSizeF();
qreal w = constraint.width();
qreal h = constraint.height();
if ( d_func()->autoLayoutChildren )
{
const auto children = childItems(); const auto children = childItems();
for ( const auto child : children ) for ( const auto child : children )
{ {
if ( auto control = qskControlCast( child ) ) if ( qskIsVisibleToLayout( child ) )
{ {
if ( !control->isTransparentForPositioner() ) const auto hint = qskEffectiveSizeHint( child, which, constraint );
{
const QSizeF hint = control->sizeHint();
w = qMax( w, hint.width() ); w = QskLayoutHint::combined( which, w, hint.width() );
h = qMax( h, hint.height() ); h = QskLayoutHint::combined( which, h, hint.height() );
}
}
} }
} }

View File

@ -152,12 +152,12 @@ class QSK_EXPORT QskControl : public QskQuickItem, public QskSkinnable
QSizeF implicitSizeHint( Qt::SizeHint, const QSizeF& constraint ) const; QSizeF implicitSizeHint( Qt::SizeHint, const QSizeF& constraint ) const;
QSizeF sizeHint() const; QSizeF sizeHint() const;
qreal heightForWidth( qreal width ) const;
qreal widthForHeight( qreal height ) const;
QSizeF effectiveSizeHint( Qt::SizeHint, QSizeF effectiveSizeHint( Qt::SizeHint,
const QSizeF& constraint = QSizeF() ) const; const QSizeF& constraint = QSizeF() ) const;
virtual qreal heightForWidth( qreal width ) const;
virtual qreal widthForHeight( qreal height ) const;
QLocale locale() const; QLocale locale() const;
void resetLocale(); void resetLocale();
@ -195,8 +195,8 @@ class QSK_EXPORT QskControl : public QskQuickItem, public QskSkinnable
virtual void updateResources(); virtual void updateResources();
virtual void updateLayout(); virtual void updateLayout();
protected: virtual QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const;
virtual QSizeF contentsSizeHint() const; virtual QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const;
private: private:
void setActiveFocusOnTab( bool ) = delete; // use setFocusPolicy void setActiveFocusOnTab( bool ) = delete; // use setFocusPolicy

View File

@ -5,7 +5,7 @@
#include "QskControlPrivate.h" #include "QskControlPrivate.h"
#include "QskSetup.h" #include "QskSetup.h"
#include "QskLayoutConstraint.h" #include "QskLayoutHint.h"
static inline void qskSendEventTo( QObject* object, QEvent::Type type ) static inline void qskSendEventTo( QObject* object, QEvent::Type type )
{ {
@ -71,7 +71,7 @@ void QskControlPrivate::layoutConstraintChanged()
void QskControlPrivate::implicitSizeChanged() 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 // when we have no explit size, the implicit size matters
layoutConstraintChanged(); layoutConstraintChanged();
@ -79,17 +79,95 @@ void QskControlPrivate::implicitSizeChanged()
} }
QSizeF QskControlPrivate::implicitSizeHint() const QSizeF QskControlPrivate::implicitSizeHint() const
{
return implicitSizeHint( Qt::PreferredSize, QSizeF() );
}
QSizeF QskControlPrivate::implicitSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{ {
Q_Q( const QskControl ); Q_Q( const QskControl );
/*
The hint is calculated from the contents ( usually scene graph nodes )
and - when being a container - the children.
*/
QSizeF contentsHint;
{
const auto m = q->margins(); const auto m = q->margins();
const auto dw = m.left() + m.right(); const auto dw = m.left() + m.right();
const auto dh = m.top() + m.bottom(); const auto dh = m.top() + m.bottom();
const auto hint = q->contentsSizeHint(); 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 ) );
}
const qreal w = ( hint.width() >= 0 ) ? dw + hint.width() : -1.0; contentsHint = q->contentsSizeHint( which, contentsHint );
const qreal h = ( hint.height() >= 0 ) ? dh + hint.height() : -1.0;
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 ); return QSizeF( w, h );
} }
@ -98,14 +176,7 @@ void QskControlPrivate::setExplicitSizeHint(
Qt::SizeHint whichHint, const QSizeF& size ) Qt::SizeHint whichHint, const QSizeF& size )
{ {
if ( explicitSizeHints == nullptr ) if ( explicitSizeHints == nullptr )
{
using namespace QskLayoutConstraint;
explicitSizeHints = new QSizeF[3]; explicitSizeHints = new QSizeF[3];
explicitSizeHints[0] = defaultSizeHints[0];
explicitSizeHints[1] = defaultSizeHints[1];
explicitSizeHints[2] = defaultSizeHints[2];
}
explicitSizeHints[ whichHint ] = size; explicitSizeHints[ whichHint ] = size;
} }
@ -113,10 +184,7 @@ void QskControlPrivate::setExplicitSizeHint(
void QskControlPrivate::resetExplicitSizeHint( Qt::SizeHint whichHint ) void QskControlPrivate::resetExplicitSizeHint( Qt::SizeHint whichHint )
{ {
if ( explicitSizeHints ) if ( explicitSizeHints )
{ explicitSizeHints[ whichHint ] = QSizeF();
using namespace QskLayoutConstraint;
explicitSizeHints[ whichHint ] = defaultSizeHints[ whichHint ];
}
} }
QSizeF QskControlPrivate::explicitSizeHint( Qt::SizeHint whichHint ) const QSizeF QskControlPrivate::explicitSizeHint( Qt::SizeHint whichHint ) const
@ -124,7 +192,7 @@ QSizeF QskControlPrivate::explicitSizeHint( Qt::SizeHint whichHint ) const
if ( explicitSizeHints ) if ( explicitSizeHints )
return explicitSizeHints[ whichHint ]; return explicitSizeHints[ whichHint ];
return QskLayoutConstraint::defaultSizeHints[ whichHint ]; return QSizeF();
} }
bool QskControlPrivate::maybeGesture( QQuickItem* child, QEvent* event ) bool QskControlPrivate::maybeGesture( QQuickItem* child, QEvent* event )

View File

@ -30,12 +30,14 @@ class QskControlPrivate : public QskQuickItemPrivate
void resetExplicitSizeHint( Qt::SizeHint ); void resetExplicitSizeHint( Qt::SizeHint );
QSizeF explicitSizeHint( Qt::SizeHint ) const; QSizeF explicitSizeHint( Qt::SizeHint ) const;
bool maybeGesture( QQuickItem*, QEvent* ); QSizeF implicitSizeHint( Qt::SizeHint, const QSizeF& ) const;
QSizeF implicitSizeHint() const override final; QSizeF implicitSizeHint() const override final;
void implicitSizeChanged() override final; void implicitSizeChanged() override final;
void layoutConstraintChanged() override final; void layoutConstraintChanged() override final;
bool maybeGesture( QQuickItem*, QEvent* );
private: private:
Q_DECLARE_PUBLIC( QskControl ) Q_DECLARE_PUBLIC( QskControl )

View File

@ -50,7 +50,7 @@ QskFocusIndicator::~QskFocusIndicator()
{ {
} }
bool QskFocusIndicator::contains( const QPointF & ) const bool QskFocusIndicator::contains( const QPointF& ) const
{ {
return false; return false;
} }

View File

@ -22,7 +22,7 @@ class QSK_EXPORT QskFocusIndicator : public QskControl
QskFocusIndicator( QQuickItem* parent = nullptr ); QskFocusIndicator( QQuickItem* parent = nullptr );
~QskFocusIndicator() override; ~QskFocusIndicator() override;
bool contains( const QPointF & ) const override; bool contains( const QPointF& ) const override;
protected: protected:
void windowChangeEvent( QskWindowChangeEvent* ) override; void windowChangeEvent( QskWindowChangeEvent* ) override;

View File

@ -248,27 +248,29 @@ void QskGraphicLabel::updateLayout()
m_data->isSourceDirty = false; 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 ( which != Qt::PreferredSize )
if ( sz.isEmpty() ) return QSizeF();
return 0;
return sz.height() * width / sz.width(); auto sz = effectiveSourceSize();
}
qreal QskGraphicLabel::widthForHeight( qreal height ) const if ( !sz.isEmpty() )
{ {
const QSizeF sz = effectiveSourceSize(); if ( constraint.width() >= 0.0 )
if ( sz.isEmpty() ) {
return 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(); return sz;
}
QSizeF QskGraphicLabel::contentsSizeHint() const
{
return effectiveSourceSize();
} }
QSizeF QskGraphicLabel::effectiveSourceSize() const QSizeF QskGraphicLabel::effectiveSourceSize() const

View File

@ -77,9 +77,6 @@ class QSK_EXPORT QskGraphicLabel : public QskControl
void setFillMode( FillMode ); void setFillMode( FillMode );
FillMode fillMode() const; FillMode fillMode() const;
qreal heightForWidth( qreal width ) const override;
qreal widthForHeight( qreal height ) const override;
bool isEmpty() const; bool isEmpty() const;
void setGraphicRole( int role ); void setGraphicRole( int role );
@ -99,10 +96,11 @@ class QSK_EXPORT QskGraphicLabel : public QskControl
protected: protected:
void changeEvent( QEvent* ) override; void changeEvent( QEvent* ) override;
void updateLayout() override; void updateLayout() override;
QSizeF contentsSizeHint() const override;
virtual QskGraphic loadSource( const QUrl& ) const; virtual QskGraphic loadSource( const QUrl& ) const;
QSizeF contentsSizeHint(
Qt::SizeHint, const QSizeF& constraint ) const override;
private: private:
class PrivateData; class PrivateData;
std::unique_ptr< PrivateData > m_data; std::unique_ptr< PrivateData > m_data;

View File

@ -153,14 +153,19 @@ QskAspect::Subcontrol QskListView::textSubControlAt( int row, int col ) const
return ( row == selectedRow() ) ? TextSelected : Text; 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 ??? qreal w = -1.0; // shouldn't we return something ???
if ( which != Qt::MaximumSize )
{
if ( m_data->preferredWidthFromColumns ) if ( m_data->preferredWidthFromColumns )
{ {
w = scrollableSize().width(); w = scrollableSize().width();
w += metric( QskScrollView::VerticalScrollBar ); w += metric( QskScrollView::VerticalScrollBar );
} }
}
return QSizeF( w, -1.0 ); return QSizeF( w, -1.0 );
} }

View File

@ -98,8 +98,8 @@ class QSK_EXPORT QskListView : public QskScrollView
void mouseReleaseEvent( QMouseEvent* ) override; void mouseReleaseEvent( QMouseEvent* ) override;
void updateScrollableSize(); void updateScrollableSize();
QSizeF contentsSizeHint() const override;
QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override;
void componentComplete() override; void componentComplete() override;
private: private:

View File

@ -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; using namespace QskAspect;
const qreal sizeBullet = metric( Bullet | Size ); const qreal sizeBullet = metric( Bullet | Size );

View File

@ -50,7 +50,7 @@ class QSK_EXPORT QskPageIndicator : public QskControl
void setCurrentIndex( qreal index ); void setCurrentIndex( qreal index );
protected: protected:
QSizeF contentsSizeHint() const override; QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override;
private: private:
class PrivateData; class PrivateData;

View File

@ -250,8 +250,11 @@ QRectF QskPushButton::layoutRectForSize( const QSizeF& size ) const
return innerBox( Panel, subControlRect( size, Panel ) ); 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 ); QSizeF size( 0, 0 );
const QFontMetricsF fm( font() ); const QFontMetricsF fm( font() );

View File

@ -63,6 +63,7 @@ class QSK_EXPORT QskPushButton : public QskAbstractButton
bool isFlat() const; bool isFlat() const;
QFont font() const; QFont font() const;
QRectF layoutRectForSize( const QSizeF& ) const override; QRectF layoutRectForSize( const QSizeF& ) const override;
public Q_SLOTS: public Q_SLOTS:
@ -90,10 +91,10 @@ class QSK_EXPORT QskPushButton : public QskAbstractButton
void changeEvent( QEvent* ) override; void changeEvent( QEvent* ) override;
void updateLayout() override; void updateLayout() override;
QSizeF contentsSizeHint() const override;
virtual QskGraphic loadGraphic( const QUrl& ) const; virtual QskGraphic loadGraphic( const QUrl& ) const;
QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override;
private: private:
class PrivateData; class PrivateData;
std::unique_ptr< PrivateData > m_data; std::unique_ptr< PrivateData > m_data;

View File

@ -5,6 +5,7 @@
#include "QskQuick.h" #include "QskQuick.h"
#include "QskControl.h" #include "QskControl.h"
#include "QskFunctions.h"
#include <qquickitem.h> #include <qquickitem.h>
QSK_QT_PRIVATE_BEGIN QSK_QT_PRIVATE_BEGIN
@ -142,11 +143,68 @@ bool qskIsTransparentForPositioner( const QQuickItem* item )
return QQuickItemPrivate::get( item )->isTransparentForPositioner(); 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 ) QQuickItem* qskNearestFocusScope( const QQuickItem* item )
{ {
if ( item ) if ( item )
{ {
for ( QQuickItem* scope = item->parentItem(); for ( auto scope = item->parentItem();
scope != nullptr; scope = scope->parentItem() ) scope != nullptr; scope = scope->parentItem() )
{ {
if ( scope->isFocusScope() ) if ( scope->isFocusScope() )
@ -290,3 +348,224 @@ const QSGNode* qskPaintNode( const QQuickItem* item )
return QQuickItemPrivate::get( item )->paintNode; 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 );
}

View File

@ -10,6 +10,8 @@
#include <qnamespace.h> #include <qnamespace.h>
#include <qquickitem.h> #include <qquickitem.h>
class QskSizePolicy;
class QQuickItem; class QQuickItem;
class QSGNode; class QSGNode;
class QRectF; class QRectF;
@ -30,6 +32,21 @@ QSK_EXPORT bool qskIsPolishScheduled( const QQuickItem* );
QSK_EXPORT void qskSetTransparentForPositioner( QQuickItem*, bool ); QSK_EXPORT void qskSetTransparentForPositioner( QQuickItem*, bool );
QSK_EXPORT bool qskIsTransparentForPositioner( const QQuickItem* ); 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* ); QSK_EXPORT QRectF qskItemRect( const QQuickItem* );
@ -69,7 +86,26 @@ template< typename T >
inline T qskFindAncestorOf( const QQuickItem* item ) inline T qskFindAncestorOf( const QQuickItem* item )
{ {
return qskFindAncestorOf< std::remove_const< T > >( 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 #endif

View File

@ -5,7 +5,6 @@
#include "QskScrollArea.h" #include "QskScrollArea.h"
#include "QskEvent.h" #include "QskEvent.h"
#include "QskLayoutConstraint.h"
#include "QskQuick.h" #include "QskQuick.h"
#include "QskScrollViewSkinlet.h" #include "QskScrollViewSkinlet.h"
@ -423,7 +422,7 @@ void QskScrollArea::updateLayout()
void QskScrollArea::adjustItem() void QskScrollArea::adjustItem()
{ {
QQuickItem* item = m_data->clipItem->scrolledItem(); auto item = m_data->clipItem->scrolledItem();
if ( item == nullptr ) if ( item == nullptr )
{ {
@ -434,7 +433,7 @@ void QskScrollArea::adjustItem()
{ {
if ( m_data->isItemResizable ) if ( m_data->isItemResizable )
{ {
const QRectF rect = viewContentsRect(); auto size = viewContentsRect().size();
#if 0 #if 0
/* /*
@ -443,13 +442,13 @@ void QskScrollArea::adjustItem()
moment we ignore this and start with a simplified code. moment we ignore this and start with a simplified code.
*/ */
#endif #endif
const auto newSize = QskLayoutConstraint::boundedSize( item, rect.size() ); size = qskConstrainedItemSize( item, size );
item->setSize( newSize ); item->setSize( size );
} }
m_data->enableAutoTranslation( this, false ); m_data->enableAutoTranslation( this, false );
setScrollableSize( QSizeF( item->width(), item->height() ) ); setScrollableSize( item->size() );
setScrollPos( scrollPos() ); setScrollPos( scrollPos() );
m_data->enableAutoTranslation( this, true ); m_data->enableAutoTranslation( this, true );

View File

@ -70,8 +70,12 @@ qreal QskSeparator::thickness() const
return metric( QskSeparator::Panel | QskAspect::Size ); 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(); const qreal m = thickness();
if ( m_orientation == Qt::Horizontal ) if ( m_orientation == Qt::Horizontal )

View File

@ -41,7 +41,7 @@ class QSK_EXPORT QskSeparator : public QskControl
void thicknessChanged(); void thicknessChanged();
protected: protected:
QSizeF contentsSizeHint() const override; QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override;
private: private:
Qt::Orientation m_orientation; Qt::Orientation m_orientation;

View File

@ -74,16 +74,16 @@ QSK_QT_PRIVATE_END
#include "QskStatusIndicator.h" #include "QskStatusIndicator.h"
#include "QskStatusIndicatorSkinlet.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*)" ); const QByteArray signature = metaObject->className() + QByteArrayLiteral( "(QskSkin*)" );
QskSkinlet *skinlet = nullptr; QskSkinlet* skinlet = nullptr;
const int index = metaObject->indexOfConstructor( signature.constData() ); const int index = metaObject->indexOfConstructor( signature.constData() );
if ( index >= 0 ) if ( index >= 0 )
{ {
void *param[] = { &skinlet, &skin }; void* param[] = { &skinlet, &skin };
metaObject->static_metacall( QMetaObject::CreateInstance, index, param ); metaObject->static_metacall( QMetaObject::CreateInstance, index, param );
} }

View File

@ -108,8 +108,12 @@ bool QskSlider::isTracking() const
return m_data->tracking; 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 ); const qreal dim = metric( QskSlider::Panel | QskAspect::Size );
return ( m_data->orientation == Qt::Horizontal ) return ( m_data->orientation == Qt::Horizontal )
? QSizeF( 4 * dim, dim ) : QSizeF( dim, 4 * dim ); ? QSizeF( 4 * dim, dim ) : QSizeF( dim, 4 * dim );

View File

@ -53,7 +53,7 @@ class QSK_EXPORT QskSlider : public QskRangeControl
void mouseMoveEvent( QMouseEvent* e ) override; void mouseMoveEvent( QMouseEvent* e ) override;
void mouseReleaseEvent( QMouseEvent* e ) override; void mouseReleaseEvent( QMouseEvent* e ) override;
QSizeF contentsSizeHint() const override; QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override;
QSizeF handleSize() const; QSizeF handleSize() const;
QRectF handleRect() const; QRectF handleRect() const;

View File

@ -153,23 +153,13 @@ QskColorFilter QskStatusIndicator::graphicFilter( int status ) const
return effectiveGraphicFilter( QskStatusIndicator::Graphic ); 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 QSizeF sz;
{
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;
for ( auto& statusData : m_data->map ) for ( auto& statusData : m_data->map )
{ {
@ -177,34 +167,22 @@ qreal QskStatusIndicator::sizeConstraint(
if ( !statusData.graphic.isEmpty() ) if ( !statusData.graphic.isEmpty() )
{ {
const QSizeF sz = statusData.graphic.defaultSize(); auto hint = statusData.graphic.defaultSize();
if ( !sz.isEmpty() )
if ( !hint.isEmpty() )
{ {
qreal v; if ( constraint.width() >= 0.0 )
if ( orientation == Qt::Horizontal )
v = sz.height() * constraint / sz.width();
else
v = sz.width() * constraint / sz.height();
if ( v > value )
value = v;
}
}
}
return value;
}
QSizeF QskStatusIndicator::contentsSizeHint() const
{
QSizeF sz( 0, 0 );
for ( auto& statusData : m_data->map )
{ {
statusData.ensureGraphic( this ); hint.setHeight( sz.height() * constraint.width() / sz.width() );
}
else if ( constraint.height() >= 0.0 )
{
hint.setWidth( sz.width() * constraint.height() / sz.height() );
}
}
if ( !statusData.graphic.isEmpty() ) sz = sz.expandedTo( hint );
sz = sz.expandedTo( statusData.graphic.defaultSize() ); }
} }
return sz; return sz;

View File

@ -35,9 +35,6 @@ class QSK_EXPORT QskStatusIndicator : public QskControl
virtual QskColorFilter graphicFilter( int status ) const; virtual QskColorFilter graphicFilter( int status ) const;
virtual QskGraphic loadSource( const QUrl& ) const; virtual QskGraphic loadSource( const QUrl& ) const;
qreal heightForWidth( qreal width ) const override;
qreal widthForHeight( qreal height ) const override;
int status() const; int status() const;
bool hasStatus( int status ) const; bool hasStatus( int status ) const;
@ -51,11 +48,9 @@ class QSK_EXPORT QskStatusIndicator : public QskControl
void changeEvent( QEvent* ) override; void changeEvent( QEvent* ) override;
void updateLayout() override; void updateLayout() override;
QSizeF contentsSizeHint() const override; QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override;
private: private:
qreal sizeConstraint( Qt::Orientation, qreal ) const;
class PrivateData; class PrivateData;
std::unique_ptr< PrivateData > m_data; std::unique_ptr< PrivateData > m_data;
}; };

View File

@ -240,22 +240,21 @@ QRectF QskSubWindow::layoutRectForSize( const QSizeF& size ) const
return innerBox( Panel, rect ); 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 // the size we get from the children
auto hint = Inherited::contentsSizeHint(); auto hint = Inherited::layoutSizeHint( which, constraint );
#if 1 if ( which == Qt::PreferredSize )
// should be Minimum Width/Height from the hints {
if ( hint.width() < 0 ) // should be Minimum Width/Height from the skin hints
if ( hint.width() < 0.0 )
hint.setWidth( qskDpiScaled( 100 ) ); hint.setWidth( qskDpiScaled( 100 ) );
if ( hint.height() < 0 ) if ( hint.height() < 0.0 )
hint.setHeight( qskDpiScaled( 80 ) ); hint.setHeight( qskDpiScaled( 80 ) );
#endif }
hint = outerBoxSize( Panel, hint );
hint.setHeight( hint.height() + subControlRect( TitleBar ).height() );
return hint; return hint;
} }

View File

@ -77,6 +77,7 @@ class QSK_EXPORT QskSubWindow : public QskPopup
bool testWindowButton( WindowButton ) const; bool testWindowButton( WindowButton ) const;
QRectF titleBarRect() const; QRectF titleBarRect() const;
QRectF layoutRectForSize( const QSizeF& ) const override; QRectF layoutRectForSize( const QSizeF& ) const override;
Q_SIGNALS: Q_SIGNALS:
@ -89,9 +90,9 @@ class QSK_EXPORT QskSubWindow : public QskPopup
protected: protected:
bool event( QEvent* ) override; 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, void itemChange( QQuickItem::ItemChange,
const QQuickItem::ItemChangeData& ) override; const QQuickItem::ItemChangeData& ) override;

View File

@ -86,8 +86,12 @@ QskTextOptions QskTabButton::textOptions() const
return m_data->textOptions; 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 ), QSizeF size( metric( Panel | QskAspect::MinimumWidth ),
metric( Panel | QskAspect::MinimumHeight ) ); metric( Panel | QskAspect::MinimumHeight ) );

View File

@ -49,7 +49,7 @@ class QSK_EXPORT QskTabButton : public QskAbstractButton
protected: protected:
void changeEvent( QEvent* ) override; void changeEvent( QEvent* ) override;
QSizeF contentsSizeHint() const override; QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override;
private: private:
class PrivateData; class PrivateData;

View File

@ -198,13 +198,14 @@ int QskTabView::count() const
return m_data->tabBar->count(); 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 ) if ( which != Qt::PreferredSize )
return Inherited::contentsSizeHint(); return constraint;
const QSizeF barHint = m_data->tabBar->sizeHint(); const auto barHint = m_data->tabBar->sizeHint();
const QSizeF boxHint = m_data->stackBox->sizeHint(); const auto boxHint = m_data->stackBox->sizeHint();
qreal w, h; qreal w, h;
@ -229,16 +230,10 @@ void QskTabView::setCurrentIndex( int index )
bool QskTabView::event( QEvent* event ) bool QskTabView::event( QEvent* event )
{ {
switch ( event->type() ) if ( event->type() == QEvent::LayoutRequest )
{
case QEvent::LayoutRequest:
{ {
resetImplicitSize(); resetImplicitSize();
polish(); polish();
break;
}
default:
break;
} }
return Inherited::event( event ); return Inherited::event( event );

View File

@ -78,7 +78,7 @@ class QSK_EXPORT QskTabView : public QskControl
bool event( QEvent* event ) override; bool event( QEvent* event ) override;
void updateLayout() override; void updateLayout() override;
QSizeF contentsSizeHint() const override; QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override;
private: private:
class PrivateData; class PrivateData;

View File

@ -441,8 +441,11 @@ void QskTextInput::focusOutEvent( QFocusEvent* event )
Inherited::focusOutEvent( 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; using namespace QskAspect;
auto input = m_data->textInput; auto input = m_data->textInput;

View File

@ -197,9 +197,9 @@ class QSK_EXPORT QskTextInput : public QskControl
void keyPressEvent( QKeyEvent* ) override; void keyPressEvent( QKeyEvent* ) override;
void keyReleaseEvent( QKeyEvent* ) override; void keyReleaseEvent( QKeyEvent* ) override;
void updateLayout() override; QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override;
QSizeF contentsSizeHint() const override;
void updateLayout() override;
void updateNode( QSGNode* ) override; void updateNode( QSGNode* ) override;
private: private:

View File

@ -208,35 +208,28 @@ QFont QskTextLabel::font() const
return effectiveFont( QskTextLabel::Text ); 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 ); const auto font = effectiveFont( Text );
if ( !m_data->text.isEmpty() ) QSizeF hint;
{
return QskTextRenderer::textSize(
m_data->text, font, m_data->effectiveOptions() );
}
return QSizeF( 0, QFontMetricsF( font ).height() );
}
qreal QskTextLabel::heightForWidth( qreal width ) const
{
const auto font = effectiveFont( Text );
const qreal lineHeight = QFontMetricsF( font ).height(); const qreal lineHeight = QFontMetricsF( font ).height();
qreal h = 0;
const auto m = margins();
if ( m_data->text.isEmpty() ) 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 else
{ {
@ -252,37 +245,30 @@ qreal QskTextLabel::heightForWidth( qreal width ) const
maxHeight = m_data->textOptions.maximumLineCount() * lineHeight; maxHeight = m_data->textOptions.maximumLineCount() * lineHeight;
} }
qreal w = width - m.left() + m.right(); QSizeF size( constraint.width(), maxHeight );
QSizeF size( w, maxHeight );
size = QskTextRenderer::textSize( size = QskTextRenderer::textSize(
m_data->text, font, m_data->effectiveOptions(), size ); m_data->text, font, m_data->effectiveOptions(), size );
h = size.height(); hint.setHeight( qCeil( size.height() ) );
} }
}
h += m.top() + m.bottom(); else if ( constraint.height() >= 0.0 )
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 qreal maxWidth = std::numeric_limits< qreal >::max();
const auto m = margins(); QSizeF size( maxWidth, constraint.height() );
QSizeF size( maxWidth, height - m.top() + m.bottom() );
size = QskTextRenderer::textSize( m_data->text, font, size = QskTextRenderer::textSize( m_data->text, font,
m_data->effectiveOptions(), size ); m_data->effectiveOptions(), size );
return qCeil( size.width() + m.left() + m.right() ); hint.setWidth( qCeil( size.width() ) );
}
else
{
hint = QskTextRenderer::textSize(
m_data->text, font, m_data->effectiveOptions() );
}
return hint;
} }
void QskTextLabel::changeEvent( QEvent* event ) void QskTextLabel::changeEvent( QEvent* event )

View File

@ -60,9 +60,6 @@ class QSK_EXPORT QskTextLabel : public QskControl
void setAlignment( Qt::Alignment ); void setAlignment( Qt::Alignment );
Qt::Alignment alignment() const; Qt::Alignment alignment() const;
qreal heightForWidth( qreal width ) const override;
qreal widthForHeight( qreal height ) const override;
QFont font() const; QFont font() const;
Q_SIGNALS: Q_SIGNALS:
@ -77,7 +74,7 @@ class QSK_EXPORT QskTextLabel : public QskControl
protected: protected:
void changeEvent( QEvent* ) override; void changeEvent( QEvent* ) override;
QSizeF contentsSizeHint() const override; QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override;
private: private:
class PrivateData; class PrivateData;

View File

@ -120,7 +120,8 @@ QskAspect::Subcontrol QskDialogButtonBox::effectiveSubcontrol(
return Inherited::effectiveSubcontrol( subControl ); return Inherited::effectiveSubcontrol( subControl );
} }
QSizeF QskDialogButtonBox::contentsSizeHint() const QSizeF QskDialogButtonBox::layoutSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{ {
if ( m_data->dirtyLayout ) if ( m_data->dirtyLayout )
{ {
@ -128,7 +129,7 @@ QSizeF QskDialogButtonBox::contentsSizeHint() const
m_data->dirtyLayout = false; m_data->dirtyLayout = false;
} }
return outerBoxSize( Panel, m_data->layoutBox->sizeHint() ); return m_data->layoutBox->effectiveSizeHint( which, constraint );
} }
void QskDialogButtonBox::invalidateLayout() void QskDialogButtonBox::invalidateLayout()

View File

@ -77,12 +77,11 @@ class QSK_EXPORT QskDialogButtonBox : public QskBox
protected: protected:
bool event( QEvent* event ) override; 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; virtual QskPushButton* createButton( QskDialog::Action ) const;
void invalidateLayout(); void invalidateLayout();
private: private:

View File

@ -5,7 +5,6 @@
#include "QskDialogSubWindow.h" #include "QskDialogSubWindow.h"
#include "QskDialogButtonBox.h" #include "QskDialogButtonBox.h"
#include "QskLayoutConstraint.h"
#include "QskPushButton.h" #include "QskPushButton.h"
#include "QskQuick.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 class QskDialogSubWindow::PrivateData
{ {
public: public:
@ -438,7 +368,7 @@ void QskDialogSubWindow::updateLayout()
auto rect = layoutRect(); 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(); const auto h = m_data->buttonBox->sizeHint().height();
rect.setBottom( rect.bottom() - h ); 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( if ( which != Qt::PreferredSize )
QskLayoutConstraint::HeightForWidth, this, width, qskConstrainedValue ); return QSizeF();
}
qreal QskDialogSubWindow::widthForHeight( qreal height ) const QSizeF buttonBoxHint;
{
return QskLayoutConstraint::constrainedMetric( qreal constraintHeight = constraint.height();
QskLayoutConstraint::WidthForHeight, this, height, qskConstrainedValue );
} 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; qreal w = -1;
w = qMax( w, buttonBoxHint.width() );
w = qMax( w, contentHint.width() );
qreal h = -1; qreal h = -1;
if ( m_data->buttonBox && m_data->buttonBox->isVisibleTo( this ) ) if ( buttonBoxHint.height() > 0.0 && contentHint.height() > 0.0 )
{ h = buttonBoxHint.height() + contentHint.height();
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();
return QSizeF( w, h ); return QSizeF( w, h );
} }

View File

@ -51,9 +51,6 @@ class QSK_EXPORT QskDialogSubWindow : public QskSubWindow
void setContentPadding( const QMarginsF& ); void setContentPadding( const QMarginsF& );
QMarginsF contentPadding() const; QMarginsF contentPadding() const;
qreal heightForWidth( qreal width ) const override;
qreal widthForHeight( qreal height ) const override;
Q_SIGNALS: Q_SIGNALS:
void finished( QskDialog::DialogCode ); void finished( QskDialog::DialogCode );
void accepted(); void accepted();
@ -72,7 +69,7 @@ class QSK_EXPORT QskDialogSubWindow : public QskSubWindow
void updateLayout() override; void updateLayout() override;
void aboutToShow() override; void aboutToShow() override;
QSizeF contentsSizeHint() const override; QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override;
virtual QskDialogButtonBox* createButtonBox(); virtual QskDialogButtonBox* createButtonBox();

View File

@ -48,9 +48,13 @@ namespace
#if 1 #if 1
// how to find a reasonable default size ??? // how to find a reasonable default size ???
QSizeF contentsSizeHint() const override QSizeF contentsSizeHint(
Qt::SizeHint which, const QSizeF& ) const override
{ {
if ( which == Qt::PreferredSize )
return QSizeF( 500, 500 ); return QSizeF( 500, 500 );
return QSizeF();
} }
#endif #endif
}; };

View File

@ -51,9 +51,13 @@ namespace
#if 1 #if 1
// how to find a reasonable default size ??? // how to find a reasonable default size ???
QSizeF contentsSizeHint() const override QSizeF contentsSizeHint(
Qt::SizeHint which, const QSizeF& ) const override
{ {
if ( which == Qt::PreferredSize )
return QSizeF( 500, 500 ); return QSizeF( 500, 500 );
return QSizeF();
} }
#endif #endif
}; };

View File

@ -29,8 +29,12 @@ namespace
setTextOptions( options ); 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() ); auto size = QFontMetricsF( font() ).size( Qt::TextSingleLine, text() );
const QSizeF minSize( metric( Panel | QskAspect::MinimumWidth ), const QSizeF minSize( metric( Panel | QskAspect::MinimumWidth ),

View File

@ -295,56 +295,38 @@ QskVirtualKeyboard::Mode QskVirtualKeyboard::mode() const
return m_data->mode; 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; constexpr qreal ratio = qreal( RowCount ) / ColumnCount;
const qreal w = 600; qreal w = constraint.width();
return QSizeF( w, ratio * w ); qreal h = constraint.height();
}
qreal QskVirtualKeyboard::heightForWidth( qreal width ) const if ( h >= 0 )
{ {
/* const auto padding = innerPadding( Panel, QSizeF( h, h ) );
Not necessarily correct, when const auto dw = padding.left() + padding.right();
subControlRect( Panel ) != contentsRect: TODO ... const auto dh = padding.top() + padding.bottom();
*/
constexpr qreal ratio = qreal( RowCount ) / ColumnCount;
const auto margins = this->margins();
width -= margins.left() + margins.right(); w = ( h - dh ) / ratio + dw;
}
else
{
if ( w < 0 )
w = 600;
const auto padding = innerPadding( const auto padding = innerPadding( Panel, QSizeF( w, w ) );
Panel, QSizeF( width, width ) ); 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; return QSizeF( w, h );
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;
} }
void QskVirtualKeyboard::updateLayout() void QskVirtualKeyboard::updateLayout()

View File

@ -35,9 +35,6 @@ class QSK_EXPORT QskVirtualKeyboard : public QskBox
void updateLocale( const QLocale& ); void updateLocale( const QLocale& );
qreal heightForWidth( qreal width ) const override;
qreal widthForHeight( qreal height ) const override;
QskAspect::Subcontrol effectiveSubcontrol( QskAspect::Subcontrol effectiveSubcontrol(
QskAspect::Subcontrol ) const override; QskAspect::Subcontrol ) const override;
@ -49,7 +46,7 @@ class QSK_EXPORT QskVirtualKeyboard : public QskBox
protected: protected:
void updateLayout() override; void updateLayout() override;
QSizeF contentsSizeHint() const override; QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override;
private: private:
void buttonPressed(); void buttonPressed();

View File

@ -5,7 +5,6 @@
#include "QskGridBox.h" #include "QskGridBox.h"
#include "QskGridLayoutEngine.h" #include "QskGridLayoutEngine.h"
#include "QskLayoutConstraint.h"
#include "QskEvent.h" #include "QskEvent.h"
#include <algorithm> #include <algorithm>
@ -341,38 +340,16 @@ void QskGridBox::updateLayout()
m_data->engine.setGeometries( layoutRect() ); m_data->engine.setGeometries( layoutRect() );
} }
QSizeF QskGridBox::contentsSizeHint() const QSizeF QskGridBox::layoutSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{ {
if ( count() == 0 ) if ( which == Qt::MaximumSize )
return QSizeF( 0, 0 );
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 ); // we can extend beyond the maximum size of the children
return m_data->engine.sizeHint( Qt::PreferredSize, constraint ).height(); return QSizeF();
}; }
return QskLayoutConstraint::constrainedMetric( return m_data->engine.sizeHint( which, constraint );
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 );
} }
void QskGridBox::geometryChangeEvent( QskGeometryChangeEvent* event ) void QskGridBox::geometryChangeEvent( QskGeometryChangeEvent* event )

View File

@ -99,9 +99,6 @@ class QSK_EXPORT QskGridBox : public QskBox
Q_INVOKABLE void setRowFixedHeight( int row, qreal height ); Q_INVOKABLE void setRowFixedHeight( int row, qreal height );
Q_INVOKABLE void setColumnFixedWidth( int column, qreal width ); Q_INVOKABLE void setColumnFixedWidth( int column, qreal width );
qreal heightForWidth( qreal width ) const override;
qreal widthForHeight( qreal height ) const override;
public Q_SLOTS: public Q_SLOTS:
void invalidate(); void invalidate();
void clear( bool autoDelete = false ); void clear( bool autoDelete = false );
@ -116,7 +113,7 @@ class QSK_EXPORT QskGridBox : public QskBox
void itemChange( ItemChange, const ItemChangeData& ) override; void itemChange( ItemChange, const ItemChangeData& ) override;
void updateLayout() override; void updateLayout() override;
QSizeF contentsSizeHint() const override; QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override;
private: private:
class PrivateData; class PrivateData;

View File

@ -5,7 +5,6 @@
#include "QskGridLayoutEngine.h" #include "QskGridLayoutEngine.h"
#include "QskLayoutHint.h" #include "QskLayoutHint.h"
#include "QskLayoutConstraint.h"
#include "QskLayoutChain.h" #include "QskLayoutChain.h"
#include "QskSizePolicy.h" #include "QskSizePolicy.h"
#include "QskQuick.h" #include "QskQuick.h"
@ -172,9 +171,7 @@ namespace
QRect minimumGrid() const; QRect minimumGrid() const;
bool isIgnored() const; bool isIgnored() const;
QskLayoutChain::CellData cell( Qt::Orientation ) const;
QskLayoutChain::CellData cell(
Qt::Orientation, qreal constraint ) const;
void transpose(); void transpose();
@ -247,17 +244,12 @@ QRect Element::minimumGrid() const
bool Element::isIgnored() const bool Element::isIgnored() const
{ {
if ( !m_isSpacer && !QskLayoutConstraint::retainSizeWhenHidden( m_item ) ) return !( m_isSpacer || qskIsVisibleToLayout( m_item ) );
return !qskIsVisibleToParent( m_item );
return false;
} }
QskLayoutChain::CellData Element::cell( QskLayoutChain::CellData Element::cell( Qt::Orientation orientation ) const
Qt::Orientation orientation, qreal constraint ) const
{ {
const auto policy = QskLayoutConstraint::sizePolicy( const auto policy = qskSizePolicy( m_item ).policy( orientation );
m_item ).policy( orientation );
QskLayoutChain::CellData cell; QskLayoutChain::CellData cell;
cell.isValid = true; cell.isValid = true;
@ -266,9 +258,6 @@ QskLayoutChain::CellData Element::cell(
if ( policy & QskSizePolicy::ExpandFlag ) if ( policy & QskSizePolicy::ExpandFlag )
cell.stretch = 1; cell.stretch = 1;
if ( !m_isSpacer )
cell.hint = QskLayoutConstraint::layoutHint( m_item, orientation, constraint );
return cell; return cell;
} }
@ -601,7 +590,10 @@ void QskGridLayoutEngine::setupChain( Qt::Orientation orientation,
if ( !constraints.isEmpty() ) if ( !constraints.isEmpty() )
constraint = qskSegmentLength( constraints, grid.left(), grid.right() ); 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 else
{ {
@ -624,7 +616,9 @@ void QskGridLayoutEngine::setupChain( Qt::Orientation orientation,
if ( !constraints.isEmpty() ) if ( !constraints.isEmpty() )
constraint = qskSegmentLength( constraints, grid.left(), grid.right() ); constraint = qskSegmentLength( constraints, grid.left(), grid.right() );
chain.expandCells( grid.top(), grid.height(), auto cell = element->cell( orientation );
element->cell( orientation, constraint ) ); cell.hint = layoutHint( element->item(), orientation, constraint );
chain.expandCells( grid.top(), grid.height(), cell );
} }
} }

View File

@ -4,7 +4,6 @@
*****************************************************************************/ *****************************************************************************/
#include "QskLayoutChain.h" #include "QskLayoutChain.h"
#include "QskLayoutConstraint.h"
#include <qvarlengtharray.h> #include <qvarlengtharray.h>
#include <qvector.h> #include <qvector.h>
@ -133,9 +132,9 @@ void QskLayoutChain::expandCells(
if ( multiCell.hint.preferred() > chainHint.preferred() ) if ( multiCell.hint.preferred() > chainHint.preferred() )
preferred = chain.segments( multiCell.hint.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() ); maximum = chain.segments( multiCell.hint.maximum() );
} }
@ -174,7 +173,7 @@ void QskLayoutChain::finish()
if ( !m_cells.empty() ) if ( !m_cells.empty() )
{ {
const auto maxMaximum = QskLayoutConstraint::unlimited; const auto maxMaximum = QskLayoutHint::unlimited;
for ( auto& cell : m_cells ) for ( auto& cell : m_cells )
{ {

View File

@ -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 <functional>
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;
}

View File

@ -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 <qnamespace.h>
#include <qsize.h>
#include <limits>
#include <functional>
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

View File

@ -5,9 +5,99 @@
#include "QskLayoutEngine2D.h" #include "QskLayoutEngine2D.h"
#include "QskLayoutChain.h" #include "QskLayoutChain.h"
#include "QskLayoutHint.h"
#include "QskQuick.h" #include "QskQuick.h"
#include <qguiapplication.h> #include <qguiapplication.h>
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 namespace
{ {
class LayoutData class LayoutData
@ -259,11 +349,11 @@ void QskLayoutEngine2D::layoutItem( QQuickItem* item, const QRect& grid ) const
if ( layoutData == nullptr || item == nullptr ) if ( layoutData == nullptr || item == nullptr )
return; return;
auto alignment = QskLayoutConstraint::layoutAlignmentHint( item ); auto alignment = qskLayoutAlignmentHint( item );
alignment = m_data->effectiveAlignment( alignment ); alignment = m_data->effectiveAlignment( alignment );
QRectF rect = layoutData->geometryAt( grid ); auto rect = layoutData->geometryAt( grid );
rect = QskLayoutConstraint::boundedRect(item, rect, alignment ); rect = qskConstrainedItemRect( item, rect, alignment );
if ( layoutData->direction == Qt::RightToLeft ) if ( layoutData->direction == Qt::RightToLeft )
{ {
@ -298,7 +388,7 @@ QSizeF QskLayoutEngine2D::sizeHint(
m_data->blockInvalidate = true; m_data->blockInvalidate = true;
if ( ( constraint.width() >= 0 ) && if ( ( constraint.width() >= 0 ) &&
( constraintType() == QskLayoutConstraint::HeightForWidth ) ) ( constraintType() == QskSizePolicy::HeightForWidth ) )
{ {
setupChain( Qt::Horizontal ); setupChain( Qt::Horizontal );
@ -306,7 +396,7 @@ QSizeF QskLayoutEngine2D::sizeHint(
setupChain( Qt::Vertical, constraints ); setupChain( Qt::Vertical, constraints );
} }
else if ( ( constraint.height() >= 0 ) && else if ( ( constraint.height() >= 0 ) &&
( constraintType() == QskLayoutConstraint::WidthForHeight ) ) ( constraintType() == QskSizePolicy::WidthForHeight ) )
{ {
setupChain( Qt::Vertical ); setupChain( Qt::Vertical );
@ -327,6 +417,54 @@ QSizeF QskLayoutEngine2D::sizeHint(
return QSizeF( width, height ); 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 void QskLayoutEngine2D::setupChain( Qt::Orientation orientation ) const
{ {
setupChain( orientation, QskLayoutChain::Segments() ); setupChain( orientation, QskLayoutChain::Segments() );
@ -371,7 +509,7 @@ void QskLayoutEngine2D::updateSegments( const QSizeF& size ) const
switch( constraintType() ) switch( constraintType() )
{ {
case QskLayoutConstraint::WidthForHeight: case QskSizePolicy::WidthForHeight:
{ {
setupChain( Qt::Vertical ); setupChain( Qt::Vertical );
rows = rowChain.segments( size.height() ); rows = rowChain.segments( size.height() );
@ -381,7 +519,7 @@ void QskLayoutEngine2D::updateSegments( const QSizeF& size ) const
break; break;
} }
case QskLayoutConstraint::HeightForWidth: case QskSizePolicy::HeightForWidth:
{ {
setupChain( Qt::Horizontal ); setupChain( Qt::Horizontal );
columns = columnChain.segments( size.width() ); 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 ) if ( m_data->constraintType < 0 )
{ {
auto constraintType = QskLayoutConstraint::Unconstrained; auto constraintType = QskSizePolicy::Unconstrained;
for ( int i = 0; i < count(); i++ ) 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 != QskSizePolicy::Unconstrained )
if ( type != Unconstrained )
{ {
if ( constraintType == Unconstrained ) if ( constraintType == QskSizePolicy::Unconstrained )
{ {
constraintType = type; constraintType = type;
} }
else if ( constraintType != type ) else if ( constraintType != type )
{ {
qWarning( "QskLayoutEngine2D: conflicting constraints"); qWarning( "QskLayoutEngine2D: conflicting constraints");
constraintType = Unconstrained; constraintType = QskSizePolicy::Unconstrained;
} }
} }
} }
@ -455,6 +591,6 @@ QskLayoutConstraint::Type QskLayoutEngine2D::constraintType() const
m_data->constraintType = constraintType; m_data->constraintType = constraintType;
} }
return static_cast< QskLayoutConstraint::Type >( m_data->constraintType ); return static_cast< QskSizePolicy::ConstraintType >( m_data->constraintType );
} }

View File

@ -8,11 +8,14 @@
#include "QskGlobal.h" #include "QskGlobal.h"
#include "QskLayoutChain.h" #include "QskLayoutChain.h"
#include "QskLayoutConstraint.h" #include "QskSizePolicy.h"
#include <qnamespace.h> #include <qnamespace.h>
#include <memory> #include <memory>
class QQuickItem;
class QskLayoutHint;
class QskLayoutEngine2D class QskLayoutEngine2D
{ {
public: public:
@ -55,6 +58,8 @@ class QskLayoutEngine2D
protected: protected:
void layoutItem( QQuickItem*, const QRect& grid ) const; void layoutItem( QQuickItem*, const QRect& grid ) const;
QskLayoutHint layoutHint( const QQuickItem*,
Qt::Orientation, qreal constraint ) const;
enum enum
{ {
@ -73,7 +78,7 @@ class QskLayoutEngine2D
virtual int effectiveCount( Qt::Orientation ) const = 0; virtual int effectiveCount( Qt::Orientation ) const = 0;
virtual void invalidateElementCache() = 0; virtual void invalidateElementCache() = 0;
QskLayoutConstraint::Type constraintType() const; QskSizePolicy::ConstraintType constraintType() const;
void setupChain( Qt::Orientation ) const; void setupChain( Qt::Orientation ) const;
void setupChain( Qt::Orientation, const QskLayoutChain::Segments& ) const; void setupChain( Qt::Orientation, const QskLayoutChain::Segments& ) const;

View File

@ -4,11 +4,11 @@
*****************************************************************************/ *****************************************************************************/
#include "QskLayoutHint.h" #include "QskLayoutHint.h"
#include "QskLayoutConstraint.h" #include "QskControl.h"
#include <qnamespace.h> #include <qnamespace.h>
QskLayoutHint::QskLayoutHint() 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 bool QskLayoutHint::isDefault() const
{ {
return ( m_minimum == 0.0 ) && ( m_preferred == 0.0 ) 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 #ifndef QT_NO_DEBUG_STREAM
@ -84,7 +98,7 @@ bool QskLayoutHint::isDefault() const
static inline QString qskHintValueString( qreal value ) static inline QString qskHintValueString( qreal value )
{ {
if ( value >= QskLayoutConstraint::unlimited ) if ( value >= QskLayoutHint::unlimited )
return QStringLiteral( "unlimited" ); return QStringLiteral( "unlimited" );
else else
return QString::number( value ); return QString::number( value );

View File

@ -8,6 +8,7 @@
#include "QskGlobal.h" #include "QskGlobal.h"
#include <qglobal.h> #include <qglobal.h>
#include <limits>
class QDebug; class QDebug;
@ -44,6 +45,9 @@ class QSK_EXPORT QskLayoutHint
void expandPreferred( qreal value ); void expandPreferred( qreal value );
void expandMaximum( 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: private:
qreal m_minimum; qreal m_minimum;
qreal m_preferred; qreal m_preferred;

View File

@ -5,8 +5,6 @@
#include "QskLinearBox.h" #include "QskLinearBox.h"
#include "QskLinearLayoutEngine.h" #include "QskLinearLayoutEngine.h"
#include "QskLayoutConstraint.h"
#include "QskEvent.h" #include "QskEvent.h"
#include "QskQuick.h" #include "QskQuick.h"
@ -188,33 +186,16 @@ void QskLinearBox::updateLayout()
m_data->engine.setGeometries( layoutRect() ); 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 )
}
qreal QskLinearBox::heightForWidth( qreal width ) const
{
auto constrainedHeight =
[this]( QskLayoutConstraint::Type, const QskControl*, qreal width )
{ {
return m_data->engine.heightForWidth( width ); // we can extend beyond the maximum size of the children
}; return QSizeF();
}
return QskLayoutConstraint::constrainedMetric( return m_data->engine.sizeHint( which, constraint );
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 );
} }
void QskLinearBox::geometryChangeEvent( QskGeometryChangeEvent* event ) void QskLinearBox::geometryChangeEvent( QskGeometryChangeEvent* event )

View File

@ -54,9 +54,6 @@ class QSK_EXPORT QskLinearBox : public QskIndexedLayoutBox
void removeItem( const QQuickItem* ); void removeItem( const QQuickItem* );
void removeAt( int index ); void removeAt( int index );
qreal heightForWidth( qreal width ) const override;
qreal widthForHeight( qreal height ) const override;
Qt::Orientation orientation() const; Qt::Orientation orientation() const;
void setOrientation( Qt::Orientation ); void setOrientation( Qt::Orientation );
@ -108,7 +105,7 @@ class QSK_EXPORT QskLinearBox : public QskIndexedLayoutBox
void itemChange( ItemChange, const ItemChangeData& ) override; void itemChange( ItemChange, const ItemChangeData& ) override;
void updateLayout() override; void updateLayout() override;
QSizeF contentsSizeHint() const override; QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override;
void autoAddItem( QQuickItem* ) override final; void autoAddItem( QQuickItem* ) override final;
void autoRemoveItem( QQuickItem* ) override final; void autoRemoveItem( QQuickItem* ) override final;

View File

@ -5,7 +5,6 @@
#include "QskLinearLayoutEngine.h" #include "QskLinearLayoutEngine.h"
#include "QskLayoutHint.h" #include "QskLayoutHint.h"
#include "QskLayoutConstraint.h"
#include "QskLayoutChain.h" #include "QskLayoutChain.h"
#include "QskSizePolicy.h" #include "QskSizePolicy.h"
#include "QskQuick.h" #include "QskQuick.h"
@ -36,8 +35,8 @@ namespace
bool isIgnored() const; bool isIgnored() const;
QskLayoutChain::CellData cell( Qt::Orientation, QskLayoutChain::CellData cell(
bool isLayoutOrientation, qreal constraint ) const; Qt::Orientation, bool isLayoutOrientation ) const;
private: private:
@ -100,14 +99,11 @@ inline void Element::setStretch( int stretch )
bool Element::isIgnored() const bool Element::isIgnored() const
{ {
if ( !m_isSpacer && !QskLayoutConstraint::retainSizeWhenHidden( m_item ) ) return !( m_isSpacer || qskIsVisibleToLayout( m_item ) );
return !qskIsVisibleToParent( m_item );
return false;
} }
QskLayoutChain::CellData Element::cell( Qt::Orientation orientation, QskLayoutChain::CellData Element::cell(
bool isLayoutOrientation, qreal constraint ) const Qt::Orientation orientation, bool isLayoutOrientation ) const
{ {
QskLayoutChain::CellData cell; QskLayoutChain::CellData cell;
cell.canGrow = true; cell.canGrow = true;
@ -115,9 +111,7 @@ QskLayoutChain::CellData Element::cell( Qt::Orientation orientation,
if ( !m_isSpacer ) if ( !m_isSpacer )
{ {
cell.hint = QskLayoutConstraint::layoutHint( m_item, orientation, constraint ); const auto policy = qskSizePolicy( m_item ).policy( orientation );
const auto policy = QskLayoutConstraint::sizePolicy( m_item ).policy( orientation );
if ( isLayoutOrientation ) if ( isLayoutOrientation )
{ {
@ -302,12 +296,11 @@ bool QskLinearLayoutEngine::removeAt( int index )
if ( element->isIgnored() ) if ( element->isIgnored() )
m_data->sumIgnored--; m_data->sumIgnored--;
const auto itemType = const auto itemType = qskSizePolicy( element->item() ).constraintType();
QskLayoutConstraint::constraintType( element->item() );
int invalidationMode = LayoutCache; int invalidationMode = LayoutCache;
if ( itemType > QskLayoutConstraint::Unconstrained ) if ( itemType > QskSizePolicy::Unconstrained )
invalidationMode |= ElementCache; invalidationMode |= ElementCache;
m_data->elements.erase( m_data->elements.begin() + index ); m_data->elements.erase( m_data->elements.begin() + index );
@ -435,8 +428,10 @@ void QskLinearLayoutEngine::setupChain( Qt::Orientation orientation,
if ( !constraints.isEmpty() ) if ( !constraints.isEmpty() )
constraint = constraints[index1].length; constraint = constraints[index1].length;
const auto cell = element.cell( auto cell = element.cell( orientation, isLayoutOrientation );
orientation, isLayoutOrientation, constraint );
if ( element.item() )
cell.hint = layoutHint( element.item(), orientation, constraint );
chain.expandCell( index2, cell ); chain.expandCell( index2, cell );

View File

@ -5,36 +5,12 @@
#include "QskStackBox.h" #include "QskStackBox.h"
#include "QskStackBoxAnimator.h" #include "QskStackBoxAnimator.h"
#include "QskLayoutConstraint.h" #include "QskLayoutHint.h"
#include "QskEvent.h" #include "QskEvent.h"
#include "QskQuick.h" #include "QskQuick.h"
#include <QPointer> #include <QPointer>
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 class QskStackBox::PrivateData
{ {
public: public:
@ -328,11 +304,11 @@ QRectF QskStackBox::geometryForItemAt( int index ) const
if ( const auto item = m_data->items.value( index ) ) if ( const auto item = m_data->items.value( index ) )
{ {
auto alignment = QskLayoutConstraint::layoutAlignmentHint( item ); auto alignment = qskLayoutAlignmentHint( item );
if ( alignment == 0 ) if ( alignment == 0 )
alignment = m_data->defaultAlignment; 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 ); 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 ) if ( itemCount() == 0 )
return QSizeF( 0, 0 ); return QSizeF();
#endif
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 width = -1;
qreal height = -1; qreal height = -1;
using namespace QskLayoutConstraint; int constraintTypes = QskSizePolicy::Unconstrained;
int constraintTypes = Unconstrained;
for ( const auto item : qskAsConst( m_data->items ) ) for ( const auto item : qskAsConst( m_data->items ) )
{ {
const auto type = constraintType( item ); const auto type = qskSizePolicy( item ).constraintType();
if ( type != Unconstrained ) if ( type != QskSizePolicy::Unconstrained )
{ {
constraintTypes |= type; constraintTypes |= type;
} continue;
else
{
const auto hint = QskLayoutConstraint::sizeHint(
item, Qt::PreferredSize, QSizeF( -1, -1 ) );
if ( hint.width() >= width )
width = hint.width();
if ( hint.height() >= height )
height = hint.height();
}
} }
#if 1 const auto hint = qskSizeConstraint( item, which, constraint );
// does this work ???
if ( constraintTypes & WidthForHeight ) width = QskLayoutHint::combined( which, width, hint.width() );
height = QskLayoutHint::combined( which, height, hint.height() );
}
if ( constraintTypes & QskSizePolicy::WidthForHeight )
{ {
const QSizeF constraint( -1, height ); const QSizeF constraint( -1, height );
for ( const auto& item : qskAsConst( m_data->items ) ) for ( const auto& item : qskAsConst( m_data->items ) )
{ {
if ( constraintType( item ) == WidthForHeight ) const auto sizePolicy = qskSizePolicy( item );
if ( sizePolicy.constraintType() == QskSizePolicy::WidthForHeight )
{ {
const auto hint = QskLayoutConstraint::sizeHint( const auto hint = qskSizeConstraint( item, which, constraint );
item, Qt::PreferredSize, constraint ); width = QskLayoutHint::combined( which, width, hint.width() );
width = qMax( width, hint.width() );
} }
} }
} }
if ( constraintTypes & HeightForWidth ) if ( constraintTypes & QskSizePolicy::HeightForWidth )
{ {
const QSizeF constraint( width, -1 ); const QSizeF constraint( width, -1 );
for ( const auto& item : qskAsConst( m_data->items ) ) for ( const auto& item : qskAsConst( m_data->items ) )
{ {
if ( constraintType( item ) == HeightForWidth ) const auto sizePolicy = qskSizePolicy( item );
{
const QSizeF hint = QskLayoutConstraint::sizeHint(
item, Qt::PreferredSize, constraint );
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 ); 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 ) bool QskStackBox::event( QEvent* event )
{ {
switch ( static_cast< int >( event->type() ) ) switch ( static_cast< int >( event->type() ) )

View File

@ -51,9 +51,6 @@ class QSK_EXPORT QskStackBox : public QskIndexedLayoutBox
const QskStackBoxAnimator* animator() const; const QskStackBoxAnimator* animator() const;
QskStackBoxAnimator* animator(); QskStackBoxAnimator* animator();
qreal heightForWidth( qreal width ) const override;
qreal widthForHeight( qreal height ) const override;
QRectF geometryForItemAt( int index ) const; QRectF geometryForItemAt( int index ) const;
Q_SIGNALS: Q_SIGNALS:
@ -72,7 +69,7 @@ class QSK_EXPORT QskStackBox : public QskIndexedLayoutBox
bool event( QEvent* ) override; bool event( QEvent* ) override;
void updateLayout() override; void updateLayout() override;
QSizeF contentsSizeHint() const override; QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override;
void autoAddItem( QQuickItem* ) override final; void autoAddItem( QQuickItem* ) override final;
void autoRemoveItem( QQuickItem* ) override final; void autoRemoveItem( QQuickItem* ) override final;

View File

@ -243,7 +243,6 @@ HEADERS += \
layouts/QskGridBox.h \ layouts/QskGridBox.h \
layouts/QskGridLayoutEngine.h \ layouts/QskGridLayoutEngine.h \
layouts/QskIndexedLayoutBox.h \ layouts/QskIndexedLayoutBox.h \
layouts/QskLayoutConstraint.h \
layouts/QskLayoutChain.h \ layouts/QskLayoutChain.h \
layouts/QskLayoutEngine2D.cpp \ layouts/QskLayoutEngine2D.cpp \
layouts/QskLayoutHint.h \ layouts/QskLayoutHint.h \
@ -257,7 +256,6 @@ SOURCES += \
layouts/QskGridLayoutEngine.cpp \ layouts/QskGridLayoutEngine.cpp \
layouts/QskIndexedLayoutBox.cpp \ layouts/QskIndexedLayoutBox.cpp \
layouts/QskLayoutChain.cpp \ layouts/QskLayoutChain.cpp \
layouts/QskLayoutConstraint.cpp \
layouts/QskLayoutEngine2D.cpp \ layouts/QskLayoutEngine2D.cpp \
layouts/QskLayoutHint.cpp \ layouts/QskLayoutHint.cpp \
layouts/QskLinearBox.cpp \ layouts/QskLinearBox.cpp \