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 ) );
}
QSizeF ButtonBar::contentsSizeHint() const
QSizeF ButtonBar::layoutSizeHint(
Qt::SizeHint which, const QSizeF& ) const
{
return QSizeF( -1, 20 );
if ( which == Qt::PreferredSize )
return QSizeF( -1, 20 );
return QSizeF();
}

View File

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

View File

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

View File

@ -19,11 +19,11 @@ namespace
Control( const char* colorName, QQuickItem* parent = nullptr );
Control( const char* colorName, qreal aspectRatio, QQuickItem* parent = nullptr );
qreal heightForWidth( qreal width ) const override;
qreal widthForHeight( qreal height ) const override;
void transpose();
protected:
QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override;
private:
qreal m_aspectRatio;
};
@ -65,14 +65,19 @@ Control::Control( const char* colorName, qreal aspectRatio, QQuickItem* parent )
setPreferredHeight( 100 );
}
qreal Control::heightForWidth( qreal width ) const
QSizeF Control::contentsSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
return width / m_aspectRatio;
}
if ( which == Qt::PreferredSize )
{
if ( constraint.width() >= 0.0 )
return QSizeF( -1.0, constraint.width() / m_aspectRatio );
qreal Control::widthForHeight( qreal height ) const
{
return height * m_aspectRatio;
if ( constraint.height() >= 0.0 )
return QSizeF( constraint.height() * m_aspectRatio, -1.0 );
}
return QSizeF();
}
void Control::transpose()

View File

@ -179,26 +179,33 @@ QskGraphic MyToggleButton::graphicAt( int index ) const
return data.icon;
}
QSizeF MyToggleButton::contentsSizeHint() const
QSizeF MyToggleButton::contentsSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
const qreal width = metric( Panel | QskAspect::MinimumWidth );
const qreal height = metric( Panel | QskAspect::MinimumHeight );
if ( which != Qt::PreferredSize )
return QSizeF();
return QSizeF( width, height );
}
qreal w = constraint.width();
qreal h = constraint.height();
// better use Minimum Width/Height hints TODO ...
// better use Minimum Width/Height hints TODO ...
constexpr qreal aspectRatio = 4.0 / 3.0;
static constexpr qreal aspectRatio = 4.0 / 3.0;
if ( w >= 0.0 )
{
h = w / aspectRatio;
}
else if ( h >= 0.0 )
{
w = h * aspectRatio;
}
else
{
w = metric( Panel | QskAspect::MinimumWidth );
h = metric( Panel | QskAspect::MinimumHeight );
}
qreal MyToggleButton::heightForWidth( qreal width ) const
{
return width / aspectRatio;
}
qreal MyToggleButton::widthForHeight( qreal height ) const
{
return height * aspectRatio;
return QSizeF( w, h );
}
void MyToggleButton::updateLayout()

View File

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

View File

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

View File

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

View File

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

View File

@ -19,6 +19,37 @@ void QskSizePolicy::setPolicy( Qt::Orientation orientation, Policy policy )
setVerticalPolicy( policy );
}
QskSizePolicy::ConstraintType QskSizePolicy::constraintType() const
{
if ( horizontalPolicy() & ConstrainedFlag )
return QskSizePolicy::WidthForHeight;
if ( verticalPolicy() & ConstrainedFlag )
return QskSizePolicy::HeightForWidth;
return QskSizePolicy::Unconstrained;
}
Qt::SizeHint QskSizePolicy::effectiveSizeHintType(
Qt::SizeHint which, Qt::Orientation orientation ) const
{
const auto policy = ( orientation == Qt::Horizontal )
? horizontalPolicy() : verticalPolicy();
if ( which == Qt::MinimumSize )
{
if ( !( policy & ShrinkFlag ) )
return Qt::PreferredSize;
}
else if ( which == Qt::MaximumSize )
{
if ( !( policy & ( GrowFlag | ExpandFlag ) ) )
return Qt::PreferredSize;
}
return which;
}
#ifndef QT_NO_DEBUG_STREAM
#include <qdebug.h>

View File

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

View File

@ -38,7 +38,7 @@ class QSK_EXPORT QskAnimationHint
QEasingCurve::Type type = QEasingCurve::Linear ) noexcept
: duration( duration )
, type( type )
, updateFlags( UpdateAuto )
, updateFlags( UpdateAuto )
{
}

View File

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

View File

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

View File

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

View File

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

View File

@ -5,7 +5,7 @@
#include "QskControlPrivate.h"
#include "QskSetup.h"
#include "QskLayoutConstraint.h"
#include "QskLayoutHint.h"
static inline void qskSendEventTo( QObject* object, QEvent::Type type )
{
@ -71,7 +71,7 @@ void QskControlPrivate::layoutConstraintChanged()
void QskControlPrivate::implicitSizeChanged()
{
if ( !q_func()->explicitSizeHint( Qt::PreferredSize ).isValid() )
if ( !( explicitSizeHints && explicitSizeHints[ Qt::PreferredSize ].isValid() ) )
{
// when we have no explit size, the implicit size matters
layoutConstraintChanged();
@ -79,17 +79,95 @@ void QskControlPrivate::implicitSizeChanged()
}
QSizeF QskControlPrivate::implicitSizeHint() const
{
return implicitSizeHint( Qt::PreferredSize, QSizeF() );
}
QSizeF QskControlPrivate::implicitSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
Q_Q( const QskControl );
const auto m = q->margins();
const auto dw = m.left() + m.right();
const auto dh = m.top() + m.bottom();
/*
The hint is calculated from the contents ( usually scene graph nodes )
and - when being a container - the children.
*/
QSizeF contentsHint;
const auto hint = q->contentsSizeHint();
{
const auto m = q->margins();
const auto dw = m.left() + m.right();
const auto dh = m.top() + m.bottom();
const qreal w = ( hint.width() >= 0 ) ? dw + hint.width() : -1.0;
const qreal h = ( hint.height() >= 0 ) ? dh + hint.height() : -1.0;
if ( constraint.width() >= 0.0 )
{
contentsHint.setWidth( qMax( constraint.width() - dw, 0.0 ) );
}
else if ( constraint.height() >= 0.0 )
{
contentsHint.setHeight( qMax( constraint.height() - dh, 0.0 ) );
}
contentsHint = q->contentsSizeHint( which, contentsHint );
if ( contentsHint.rwidth() >= 0 )
contentsHint.rwidth() += dw;
if ( contentsHint.rheight() >= 0 )
contentsHint.rheight() += dh;
}
QSizeF layoutHint;
{
if ( constraint.width() >= 0.0 )
{
const QSizeF boundingSize( constraint.width(), 1e6 );
const QSizeF layoutSize = q->layoutRectForSize( boundingSize ).size();
layoutHint = q->layoutSizeHint( which, QSizeF( layoutSize.width(), -1 ) );
if ( layoutHint.height() >= 0 )
layoutHint.rheight() += boundingSize.height() - layoutSize.height();
}
else if ( constraint.height() >= 0.0 )
{
const QSizeF boundingSize( 1e6, constraint.height() );
const QSizeF layoutSize = q->layoutRectForSize( boundingSize ).size();
layoutHint = q->layoutSizeHint( which, QSizeF( -1, layoutSize.height() ) );
if ( layoutHint.width() >= 0 )
layoutHint.rwidth() += boundingSize.width() - layoutSize.width();
}
else
{
/*
In situations, where layoutRectForSize depends on
the size ( f.e when using a corner radius of Qt::RelativeSize )
we will have wrong results. TODO ...
*/
const QSizeF boundingSize( 1000.0, 1000.0 );
const QSizeF layoutSize = q->layoutRectForSize( boundingSize ).size();
layoutHint = q->layoutSizeHint( which, QSizeF() );
if ( layoutHint.width() >= 0 )
layoutHint.rwidth() += boundingSize.width() - layoutSize.width();
if ( layoutHint.height() >= 0 )
layoutHint.rheight() += boundingSize.height() - layoutSize.height();
}
}
// Combining both hints
qreal w = constraint.width();
qreal h = constraint.height();
if ( w < 0.0 )
w = QskLayoutHint::combined( which, contentsHint.width(), layoutHint.width() );
if ( h < 0.0 )
h = QskLayoutHint::combined( which, contentsHint.height(), layoutHint.height() );
return QSizeF( w, h );
}
@ -98,14 +176,7 @@ void QskControlPrivate::setExplicitSizeHint(
Qt::SizeHint whichHint, const QSizeF& size )
{
if ( explicitSizeHints == nullptr )
{
using namespace QskLayoutConstraint;
explicitSizeHints = new QSizeF[3];
explicitSizeHints[0] = defaultSizeHints[0];
explicitSizeHints[1] = defaultSizeHints[1];
explicitSizeHints[2] = defaultSizeHints[2];
}
explicitSizeHints[ whichHint ] = size;
}
@ -113,10 +184,7 @@ void QskControlPrivate::setExplicitSizeHint(
void QskControlPrivate::resetExplicitSizeHint( Qt::SizeHint whichHint )
{
if ( explicitSizeHints )
{
using namespace QskLayoutConstraint;
explicitSizeHints[ whichHint ] = defaultSizeHints[ whichHint ];
}
explicitSizeHints[ whichHint ] = QSizeF();
}
QSizeF QskControlPrivate::explicitSizeHint( Qt::SizeHint whichHint ) const
@ -124,7 +192,7 @@ QSizeF QskControlPrivate::explicitSizeHint( Qt::SizeHint whichHint ) const
if ( explicitSizeHints )
return explicitSizeHints[ whichHint ];
return QskLayoutConstraint::defaultSizeHints[ whichHint ];
return QSizeF();
}
bool QskControlPrivate::maybeGesture( QQuickItem* child, QEvent* event )

View File

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

View File

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

View File

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

View File

@ -449,7 +449,7 @@ void QskGestureRecognizer::reject()
m_data->isReplayingEvents = true;
if ( window->mouseGrabberItem() == watchedItem )
watchedItem->ungrabMouse();
watchedItem->ungrabMouse();
if ( !events.isEmpty() &&
( events[ 0 ]->type() == QEvent::MouseButtonPress ) )

View File

@ -248,27 +248,29 @@ void QskGraphicLabel::updateLayout()
m_data->isSourceDirty = false;
}
qreal QskGraphicLabel::heightForWidth( qreal width ) const
QSizeF QskGraphicLabel::contentsSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
const QSizeF sz = effectiveSourceSize();
if ( sz.isEmpty() )
return 0;
if ( which != Qt::PreferredSize )
return QSizeF();
return sz.height() * width / sz.width();
}
auto sz = effectiveSourceSize();
qreal QskGraphicLabel::widthForHeight( qreal height ) const
{
const QSizeF sz = effectiveSourceSize();
if ( sz.isEmpty() )
return 0;
if ( !sz.isEmpty() )
{
if ( constraint.width() >= 0.0 )
{
sz.setHeight( sz.height() * constraint.width() / sz.width() );
sz.setWidth( constraint.width() );
}
else if ( constraint.height() >= 0.0 )
{
sz.setWidth( sz.width() * constraint.height() / sz.height() );
sz.setHeight( constraint.height() );
}
}
return sz.width() * height / sz.height();
}
QSizeF QskGraphicLabel::contentsSizeHint() const
{
return effectiveSourceSize();
return sz;
}
QSizeF QskGraphicLabel::effectiveSourceSize() const

View File

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

View File

@ -153,13 +153,18 @@ QskAspect::Subcontrol QskListView::textSubControlAt( int row, int col ) const
return ( row == selectedRow() ) ? TextSelected : Text;
}
QSizeF QskListView::contentsSizeHint() const
QSizeF QskListView::contentsSizeHint(
Qt::SizeHint which, const QSizeF& ) const
{
qreal w = -1.0; // shouldn't we return something ???
if ( m_data->preferredWidthFromColumns )
if ( which != Qt::MaximumSize )
{
w = scrollableSize().width();
w += metric( QskScrollView::VerticalScrollBar );
if ( m_data->preferredWidthFromColumns )
{
w = scrollableSize().width();
w += metric( QskScrollView::VerticalScrollBar );
}
}
return QSizeF( w, -1.0 );

View File

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

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

View File

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

View File

@ -256,7 +256,7 @@ void QskPopup::updateInputGrabber()
/*
In QQuickWindowPrivate::deliverPressOrReleaseEvent ( 5.12 )
might crash, when we delete the grabber as a result of a
mouse event somewehere below the popup.
mouse event somewehere below the popup.
*/
m_data->inputGrabber->setParentItem( nullptr );
m_data->inputGrabber->setParent( nullptr );

View File

@ -250,8 +250,11 @@ QRectF QskPushButton::layoutRectForSize( const QSizeF& size ) const
return innerBox( Panel, subControlRect( size, Panel ) );
}
QSizeF QskPushButton::contentsSizeHint() const
QSizeF QskPushButton::contentsSizeHint( Qt::SizeHint which, const QSizeF& ) const
{
if ( which != Qt::PreferredSize )
return QSizeF();
QSizeF size( 0, 0 );
const QFontMetricsF fm( font() );

View File

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

View File

@ -5,6 +5,7 @@
#include "QskQuick.h"
#include "QskControl.h"
#include "QskFunctions.h"
#include <qquickitem.h>
QSK_QT_PRIVATE_BEGIN
@ -142,11 +143,68 @@ bool qskIsTransparentForPositioner( const QQuickItem* item )
return QQuickItemPrivate::get( item )->isTransparentForPositioner();
}
bool qskIsVisibleToLayout( const QQuickItem* item )
{
if ( item )
{
const auto d = QQuickItemPrivate::get( item );
return !d->isTransparentForPositioner()
&& ( d->explicitVisible || qskRetainSizeWhenHidden( item ) );
}
return false;
}
QskSizePolicy qskSizePolicy( const QQuickItem* item )
{
if ( auto control = qskControlCast( item ) )
return control->sizePolicy();
if ( item )
{
const QVariant v = item->property( "sizePolicy" );
if ( v.canConvert< QskSizePolicy >() )
return qvariant_cast< QskSizePolicy >( v );
}
return QskSizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Preferred );
}
Qt::Alignment qskLayoutAlignmentHint( const QQuickItem* item )
{
if ( auto control = qskControlCast( item ) )
return control->layoutAlignmentHint();
if ( item )
{
const QVariant v = item->property( "layoutAlignmentHint" );
if ( v.canConvert< Qt::Alignment >() )
return v.value< Qt::Alignment >();
}
return Qt::Alignment();
}
bool qskRetainSizeWhenHidden( const QQuickItem* item )
{
if ( auto control = qskControlCast( item ) )
return control->layoutHints() & QskControl::RetainSizeWhenHidden;
if ( item )
{
const QVariant v = item->property( "retainSizeWhenHidden" );
if ( v.canConvert< bool >() )
return v.value< bool >();
}
return false;
}
QQuickItem* qskNearestFocusScope( const QQuickItem* item )
{
if ( item )
{
for ( QQuickItem* scope = item->parentItem();
for ( auto scope = item->parentItem();
scope != nullptr; scope = scope->parentItem() )
{
if ( scope->isFocusScope() )
@ -290,3 +348,224 @@ const QSGNode* qskPaintNode( const QQuickItem* item )
return QQuickItemPrivate::get( item )->paintNode;
}
QSizeF qskEffectiveSizeHint( const QQuickItem* item,
Qt::SizeHint whichHint, const QSizeF& constraint )
{
if ( auto control = qskControlCast( item ) )
return control->effectiveSizeHint( whichHint, constraint );
if ( constraint.width() >= 0.0 || constraint.height() >= 0.0 )
{
// QQuickItem does not support dynamic constraints
return constraint;
}
if ( item == nullptr )
return QSizeF();
/*
Trying to retrieve something useful for non QskControls:
First are checking some properties, that usually match the
names for the explicit hints. For the implicit hints we only
have the implicitSize, what is interpreted as the implicit
preferred size.
*/
QSizeF hint;
static const char* properties[] =
{
"minimumSize",
"preferredSize",
"maximumSize"
};
const QVariant v = item->property( properties[ whichHint ] );
if ( v.canConvert( QMetaType::QSizeF ) )
hint = v.toSizeF();
if ( whichHint == Qt::PreferredSize )
{
if ( hint.width() < 0 )
hint.setWidth( item->implicitWidth() );
if ( hint.height() < 0 )
hint.setHeight( item->implicitHeight() );
}
return hint;
}
static QSizeF qskBoundedConstraint( const QQuickItem* item,
const QSizeF& constraint, QskSizePolicy policy )
{
Qt::Orientation orientation;
if ( constraint.width() >= 0.0 )
{
orientation = Qt::Horizontal;
}
else if ( constraint.height() >= 0.0 )
{
orientation = Qt::Vertical;
}
else
{
return constraint;
}
const auto whichMin = policy.effectiveSizeHintType( Qt::MinimumSize, orientation );
const auto whichMax = policy.effectiveSizeHintType( Qt::MaximumSize, orientation );
const auto hintMin = qskEffectiveSizeHint( item, whichMin );
const auto hintMax = ( whichMax == whichMin )
? hintMin : qskEffectiveSizeHint( item, whichMax );
QSizeF size;
if ( orientation == Qt::Horizontal )
{
if ( hintMax.width() >= 0.0 )
size.rwidth() = qMin( constraint.width(), hintMax.width() );
size.rwidth() = qMax( constraint.width(), hintMin.width() );
}
else
{
if ( hintMax.height() >= 0.0 )
size.rheight() = qMin( constraint.height(), hintMax.height() );
size.rheight() = qMax( constraint.height(), hintMin.height() );
}
return size;
}
QSizeF qskSizeConstraint( const QQuickItem* item,
Qt::SizeHint which, const QSizeF& constraint )
{
if ( item == nullptr )
return QSizeF( 0, 0 );
if ( constraint.isValid() )
return constraint;
const auto policy = qskSizePolicy( item );
const auto whichH = policy.effectiveSizeHintType( which, Qt::Horizontal );
const auto whichV = policy.effectiveSizeHintType( which, Qt::Vertical );
QSizeF size;
int constraintType = QskSizePolicy::Unconstrained;
if ( constraint.height() >= 0.0 )
{
const auto c = qskBoundedConstraint( item, constraint, policy );
size = qskEffectiveSizeHint( item, whichV, c );
if ( ( whichH != whichV ) || ( size.height() != c.height() ) )
constraintType = QskSizePolicy::WidthForHeight;
}
else if ( constraint.width() >= 0.0 )
{
const auto c = qskBoundedConstraint( item, constraint, policy );
size = qskEffectiveSizeHint( item, whichH, c );
if ( ( whichV != whichH ) || ( size.width() != c.height() ) )
constraintType = QskSizePolicy::HeightForWidth;
}
else
{
constraintType = policy.constraintType();
switch( constraintType )
{
case QskSizePolicy::WidthForHeight:
{
size = qskEffectiveSizeHint( item, whichV );
break;
}
case QskSizePolicy::HeightForWidth:
{
size = qskEffectiveSizeHint( item, whichH );
break;
}
default:
{
size = qskEffectiveSizeHint( item, whichH );
if ( whichV != whichH )
constraintType = QskSizePolicy::HeightForWidth;
}
}
}
switch( constraintType )
{
case QskSizePolicy::HeightForWidth:
{
const QSizeF c( size.width(), -1.0 );
size.setHeight( qskEffectiveSizeHint( item, whichV, c ).height() );
break;
}
case QskSizePolicy::WidthForHeight:
{
const QSizeF c( -1.0, size.height() );
size.setWidth( qskEffectiveSizeHint( item, whichH, c ).width() );
break;
}
}
return size;
}
QSizeF qskConstrainedItemSize( const QQuickItem* item, const QSizeF& size )
{
QSizeF constraint;
switch( static_cast< int >( qskSizePolicy( item ).constraintType() ) )
{
case QskSizePolicy::WidthForHeight:
{
constraint.setHeight( size.height() );
break;
}
case QskSizePolicy::HeightForWidth:
{
constraint.setWidth( size.width() );
break;
}
}
const auto max = qskSizeConstraint( item, Qt::MaximumSize, constraint );
qreal width = size.width();
qreal height = size.height();
if ( max.width() >= 0.0 )
width = qMin( width, max.width() );
if ( max.height() >= 0.0 )
height = qMin( height, max.height() );
#if 1
const auto min = qskSizeConstraint( item, Qt::MinimumSize, constraint );
width = qMax( width, min.width() );
height = qMax( height, min.height() );
#endif
return QSizeF( width, height );
}
QRectF qskConstrainedItemRect( const QQuickItem* item,
const QRectF& rect, Qt::Alignment alignment )
{
const auto size = qskConstrainedItemSize( item, rect.size() );
return qskAlignedRectF( rect, size.width(), size.height(), alignment );
}

View File

@ -10,6 +10,8 @@
#include <qnamespace.h>
#include <qquickitem.h>
class QskSizePolicy;
class QQuickItem;
class QSGNode;
class QRectF;
@ -30,6 +32,21 @@ QSK_EXPORT bool qskIsPolishScheduled( const QQuickItem* );
QSK_EXPORT void qskSetTransparentForPositioner( QQuickItem*, bool );
QSK_EXPORT bool qskIsTransparentForPositioner( const QQuickItem* );
QSK_EXPORT bool qskIsVisibleToLayout( const QQuickItem* );
QSK_EXPORT QSizeF qskEffectiveSizeHint( const QQuickItem*,
Qt::SizeHint, const QSizeF& constraint = QSizeF() );
QSK_EXPORT QSizeF qskSizeConstraint( const QQuickItem*,
Qt::SizeHint, const QSizeF& constraint = QSizeF() );
QSK_EXPORT QSizeF qskConstrainedItemSize( const QQuickItem*, const QSizeF& );
QSK_EXPORT QRectF qskConstrainedItemRect(
const QQuickItem*, const QRectF&, Qt::Alignment );
QSK_EXPORT QskSizePolicy qskSizePolicy( const QQuickItem* );
QSK_EXPORT Qt::Alignment qskLayoutAlignmentHint( const QQuickItem* );
QSK_EXPORT bool qskRetainSizeWhenHidden( const QQuickItem* );
QSK_EXPORT QRectF qskItemRect( const QQuickItem* );
@ -69,7 +86,26 @@ template< typename T >
inline T qskFindAncestorOf( const QQuickItem* item )
{
return qskFindAncestorOf< std::remove_const< T > >(
const_cast< QQuickItem * >( item ) );
const_cast< QQuickItem* >( item ) );
}
inline qreal qskHeightForWidth(
const QQuickItem* item, Qt::SizeHint which, qreal width )
{
return qskEffectiveSizeHint(
item, which, QSizeF( width, -1.0 ) ).height();
}
inline qreal qskWidthForHeight(
const QQuickItem* item, Qt::SizeHint which, qreal height )
{
return qskEffectiveSizeHint(
item, which, QSizeF( -1.0, height ) ).width();
}
inline QRectF qskConstrainedItemRect( const QQuickItem* item, const QRectF& rect )
{
return qskConstrainedItemRect( item, rect, qskLayoutAlignmentHint( item ) );
}
#endif

View File

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

View File

@ -70,8 +70,12 @@ qreal QskSeparator::thickness() const
return metric( QskSeparator::Panel | QskAspect::Size );
}
QSizeF QskSeparator::contentsSizeHint() const
QSizeF QskSeparator::contentsSizeHint(
Qt::SizeHint which, const QSizeF& ) const
{
if ( which != Qt::PreferredSize )
return QSizeF();
const qreal m = thickness();
if ( m_orientation == Qt::Horizontal )

View File

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

View File

@ -74,21 +74,21 @@ QSK_QT_PRIVATE_END
#include "QskStatusIndicator.h"
#include "QskStatusIndicatorSkinlet.h"
static inline QskSkinlet *qskNewSkinlet( const QMetaObject* metaObject, QskSkin* skin )
static inline QskSkinlet* qskNewSkinlet( const QMetaObject* metaObject, QskSkin* skin )
{
const QByteArray signature = metaObject->className() + QByteArrayLiteral( "(QskSkin*)" );
QskSkinlet *skinlet = nullptr;
QskSkinlet* skinlet = nullptr;
const int index = metaObject->indexOfConstructor( signature.constData() );
if ( index >= 0 )
{
void *param[] = { &skinlet, &skin };
void* param[] = { &skinlet, &skin };
metaObject->static_metacall( QMetaObject::CreateInstance, index, param );
}
return skinlet;
}
}
namespace
{

View File

@ -108,8 +108,12 @@ bool QskSlider::isTracking() const
return m_data->tracking;
}
QSizeF QskSlider::contentsSizeHint() const
QSizeF QskSlider::contentsSizeHint(
Qt::SizeHint which, const QSizeF& ) const
{
if ( which != Qt::PreferredSize )
return QSizeF();
const qreal dim = metric( QskSlider::Panel | QskAspect::Size );
return ( m_data->orientation == Qt::Horizontal )
? QSizeF( 4 * dim, dim ) : QSizeF( dim, 4 * dim );

View File

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

View File

@ -153,23 +153,13 @@ QskColorFilter QskStatusIndicator::graphicFilter( int status ) const
return effectiveGraphicFilter( QskStatusIndicator::Graphic );
}
qreal QskStatusIndicator::heightForWidth( qreal width ) const
QSizeF QskStatusIndicator::contentsSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
return sizeConstraint( Qt::Horizontal, width );
}
if ( which != Qt::PreferredSize )
return QSizeF();
qreal QskStatusIndicator::widthForHeight( qreal height ) const
{
return sizeConstraint( Qt::Vertical, height );
}
qreal QskStatusIndicator::sizeConstraint(
Qt::Orientation orientation, qreal constraint ) const
{
if ( constraint <= 0.0 )
return 0.0;
qreal value = 0.0;
QSizeF sz;
for ( auto& statusData : m_data->map )
{
@ -177,36 +167,24 @@ qreal QskStatusIndicator::sizeConstraint(
if ( !statusData.graphic.isEmpty() )
{
const QSizeF sz = statusData.graphic.defaultSize();
if ( !sz.isEmpty() )
auto hint = statusData.graphic.defaultSize();
if ( !hint.isEmpty() )
{
qreal v;
if ( orientation == Qt::Horizontal )
v = sz.height() * constraint / sz.width();
else
v = sz.width() * constraint / sz.height();
if ( v > value )
value = v;
if ( constraint.width() >= 0.0 )
{
hint.setHeight( sz.height() * constraint.width() / sz.width() );
}
else if ( constraint.height() >= 0.0 )
{
hint.setWidth( sz.width() * constraint.height() / sz.height() );
}
}
sz = sz.expandedTo( hint );
}
}
return value;
}
QSizeF QskStatusIndicator::contentsSizeHint() const
{
QSizeF sz( 0, 0 );
for ( auto& statusData : m_data->map )
{
statusData.ensureGraphic( this );
if ( !statusData.graphic.isEmpty() )
sz = sz.expandedTo( statusData.graphic.defaultSize() );
}
return sz;
}

View File

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

View File

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

View File

@ -77,6 +77,7 @@ class QSK_EXPORT QskSubWindow : public QskPopup
bool testWindowButton( WindowButton ) const;
QRectF titleBarRect() const;
QRectF layoutRectForSize( const QSizeF& ) const override;
Q_SIGNALS:
@ -89,9 +90,9 @@ class QSK_EXPORT QskSubWindow : public QskPopup
protected:
bool event( QEvent* ) override;
void updateLayout() override;
QSizeF contentsSizeHint() const override;
void updateLayout() override;
QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override;
void itemChange( QQuickItem::ItemChange,
const QQuickItem::ItemChangeData& ) override;

View File

@ -261,9 +261,9 @@ void QskTabBar::removeTab( int index )
nextButton->setChecked( true );
m_data->connectButton( nextButton, this, true );
}
m_data->currentIndex = nextIndex;
Q_EMIT countChanged( count() );
Q_EMIT currentIndexChanged( nextIndex );
}

View File

@ -86,8 +86,12 @@ QskTextOptions QskTabButton::textOptions() const
return m_data->textOptions;
}
QSizeF QskTabButton::contentsSizeHint() const
QSizeF QskTabButton::contentsSizeHint(
Qt::SizeHint which, const QSizeF& ) const
{
if ( which != Qt::PreferredSize )
return QSizeF();
QSizeF size( metric( Panel | QskAspect::MinimumWidth ),
metric( Panel | QskAspect::MinimumHeight ) );

View File

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

View File

@ -198,13 +198,14 @@ int QskTabView::count() const
return m_data->tabBar->count();
}
QSizeF QskTabView::contentsSizeHint() const
QSizeF QskTabView::layoutSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
if ( m_data->tabBar == nullptr || m_data->tabBar->count() == 0 )
return Inherited::contentsSizeHint();
if ( which != Qt::PreferredSize )
return constraint;
const QSizeF barHint = m_data->tabBar->sizeHint();
const QSizeF boxHint = m_data->stackBox->sizeHint();
const auto barHint = m_data->tabBar->sizeHint();
const auto boxHint = m_data->stackBox->sizeHint();
qreal w, h;
@ -229,16 +230,10 @@ void QskTabView::setCurrentIndex( int index )
bool QskTabView::event( QEvent* event )
{
switch ( event->type() )
if ( event->type() == QEvent::LayoutRequest )
{
case QEvent::LayoutRequest:
{
resetImplicitSize();
polish();
break;
}
default:
break;
resetImplicitSize();
polish();
}
return Inherited::event( event );
@ -247,7 +242,7 @@ bool QskTabView::event( QEvent* event )
void QskTabView::updateLayout()
{
if ( maybeUnresized() )
return;
return;
m_data->tabBar->setGeometry( subControlRect( TabBar ) );

View File

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

View File

@ -441,8 +441,11 @@ void QskTextInput::focusOutEvent( QFocusEvent* event )
Inherited::focusOutEvent( event );
}
QSizeF QskTextInput::contentsSizeHint() const
QSizeF QskTextInput::contentsSizeHint( Qt::SizeHint which, const QSizeF& ) const
{
if ( which != Qt::PreferredSize )
return QSizeF();
using namespace QskAspect;
auto input = m_data->textInput;

View File

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

View File

@ -208,81 +208,67 @@ QFont QskTextLabel::font() const
return effectiveFont( QskTextLabel::Text );
}
QSizeF QskTextLabel::contentsSizeHint() const
QSizeF QskTextLabel::contentsSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
if ( which != Qt::PreferredSize )
return QSizeF();
const auto font = effectiveFont( Text );
if ( !m_data->text.isEmpty() )
{
return QskTextRenderer::textSize(
m_data->text, font, m_data->effectiveOptions() );
}
QSizeF hint;
return QSizeF( 0, QFontMetricsF( font ).height() );
}
qreal QskTextLabel::heightForWidth( qreal width ) const
{
const auto font = effectiveFont( Text );
const qreal lineHeight = QFontMetricsF( font ).height();
qreal h = 0;
const auto m = margins();
if ( m_data->text.isEmpty() )
{
h = lineHeight;
if ( constraint.height() < 0.0 )
hint.setHeight( qCeil( lineHeight ) );
}
else if ( m_data->textOptions.effectiveElideMode() != Qt::ElideNone )
else if ( constraint.width() >= 0.0 )
{
h = lineHeight;
if ( m_data->textOptions.effectiveElideMode() != Qt::ElideNone )
{
hint.setHeight( qCeil( lineHeight ) );
}
else
{
/*
In case of QskTextOptions::NoWrap we could count
the line numbers and calculate the height from
lineHeight. TODO ...
*/
qreal maxHeight = std::numeric_limits< qreal >::max();
if ( maxHeight / lineHeight > m_data->textOptions.maximumLineCount() )
{
// be careful with overflows
maxHeight = m_data->textOptions.maximumLineCount() * lineHeight;
}
QSizeF size( constraint.width(), maxHeight );
size = QskTextRenderer::textSize(
m_data->text, font, m_data->effectiveOptions(), size );
hint.setHeight( qCeil( size.height() ) );
}
}
else if ( constraint.height() >= 0.0 )
{
const qreal maxWidth = std::numeric_limits< qreal >::max();
QSizeF size( maxWidth, constraint.height() );
size = QskTextRenderer::textSize( m_data->text, font,
m_data->effectiveOptions(), size );
hint.setWidth( qCeil( size.width() ) );
}
else
{
/*
In case of QskTextOptions::NoWrap we could count
the line numbers and calculate the height from
lineHeight. TODO ...
*/
qreal maxHeight = std::numeric_limits< qreal >::max();
if ( maxHeight / lineHeight > m_data->textOptions.maximumLineCount() )
{
// be careful with overflows
maxHeight = m_data->textOptions.maximumLineCount() * lineHeight;
}
qreal w = width - m.left() + m.right();
QSizeF size( w, maxHeight );
size = QskTextRenderer::textSize(
m_data->text, font, m_data->effectiveOptions(), size );
h = size.height();
hint = QskTextRenderer::textSize(
m_data->text, font, m_data->effectiveOptions() );
}
h += m.top() + m.bottom();
return qCeil( h );
}
qreal QskTextLabel::widthForHeight( qreal height ) const
{
if ( m_data->text.isEmpty() )
{
return Inherited::widthForHeight( height );
}
const auto font = effectiveFont( Text );
const qreal maxWidth = std::numeric_limits< qreal >::max();
const auto m = margins();
QSizeF size( maxWidth, height - m.top() + m.bottom() );
size = QskTextRenderer::textSize( m_data->text, font,
m_data->effectiveOptions(), size );
return qCeil( size.width() + m.left() + m.right() );
return hint;
}
void QskTextLabel::changeEvent( QEvent* event )

View File

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

View File

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

View File

@ -77,12 +77,11 @@ class QSK_EXPORT QskDialogButtonBox : public QskBox
protected:
bool event( QEvent* event ) override;
void updateLayout() override;
QSizeF contentsSizeHint() const override;
void updateLayout() override;
QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override;
virtual QskPushButton* createButton( QskDialog::Action ) const;
void invalidateLayout();
private:

View File

@ -5,7 +5,6 @@
#include "QskDialogSubWindow.h"
#include "QskDialogButtonBox.h"
#include "QskLayoutConstraint.h"
#include "QskPushButton.h"
#include "QskQuick.h"
@ -27,75 +26,6 @@ static inline void qskSetRejectOnClose( QskDialogSubWindow* subWindow, bool on )
}
}
static inline qreal qskConstrainedValue( QskLayoutConstraint::Type type,
const QskControl* control, qreal widthOrHeight )
{
auto subWindow = static_cast< const QskDialogSubWindow* >( control );
if ( type == QskLayoutConstraint::WidthForHeight )
{
qreal width = -1.0;
qreal height = widthOrHeight;
if ( auto buttonBox = subWindow->buttonBox() )
{
if ( buttonBox->isVisibleTo( subWindow ) )
{
const auto hint = buttonBox->sizeHint();
width = hint.width();
height -= hint.height();
}
}
if ( auto contentItem = qskControlCast( subWindow->contentItem() ) )
{
if ( contentItem->isVisibleTo( subWindow ) )
{
const auto m = subWindow->contentPadding();
height -= m.top() + m.bottom();
qreal w = contentItem->widthForHeight( height );
if ( w >= 0 )
{
w += m.left() + m.right();
width = qMax( width, w );
}
}
}
return width;
}
else
{
qreal width = widthOrHeight;
qreal height = -1.0;
if ( auto buttonBox = subWindow->buttonBox() )
{
if ( buttonBox->isVisibleTo( subWindow ) )
height += buttonBox->sizeHint().height();
}
if ( auto contentItem = qskControlCast( subWindow->contentItem() ) )
{
if ( qskIsVisibleTo( contentItem, subWindow ) )
{
const auto& m = subWindow->contentPadding();
width -= m.left() + m.right();
const qreal h = contentItem->heightForWidth( width );
if ( h >= 0 )
height += h + m.top() + m.bottom();
}
}
return height;
}
}
class QskDialogSubWindow::PrivateData
{
public:
@ -438,7 +368,7 @@ void QskDialogSubWindow::updateLayout()
auto rect = layoutRect();
if ( m_data->buttonBox && m_data->buttonBox->isVisibleTo( this ) )
if ( m_data->buttonBox && m_data->buttonBox->isVisibleToParent() )
{
const auto h = m_data->buttonBox->sizeHint().height();
rect.setBottom( rect.bottom() - h );
@ -453,49 +383,68 @@ void QskDialogSubWindow::updateLayout()
}
}
qreal QskDialogSubWindow::heightForWidth( qreal width ) const
QSizeF QskDialogSubWindow::layoutSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
return QskLayoutConstraint::constrainedMetric(
QskLayoutConstraint::HeightForWidth, this, width, qskConstrainedValue );
}
if ( which != Qt::PreferredSize )
return QSizeF();
qreal QskDialogSubWindow::widthForHeight( qreal height ) const
{
return QskLayoutConstraint::constrainedMetric(
QskLayoutConstraint::WidthForHeight, this, height, qskConstrainedValue );
}
QSizeF buttonBoxHint;
qreal constraintHeight = constraint.height();
if ( auto buttonBox = m_data->buttonBox )
{
if ( buttonBox->isVisibleToLayout() )
{
buttonBoxHint = buttonBox->effectiveSizeHint(
which, QSizeF( constraint.width(), -1 ) );
if ( constraint.width() >= 0.0 )
buttonBoxHint.rwidth() = constraint.width();
if ( constraintHeight >= 0.0 && buttonBoxHint.height() >= 0.0 )
{
constraintHeight -= buttonBoxHint.height();
constraintHeight = qMax( constraintHeight, 0.0 );
}
}
}
QSizeF contentHint;
if ( qskIsVisibleToLayout( m_data->contentItem ) )
{
const auto& m = m_data->contentPadding;
const qreal dw = m.left() + m.right();
const qreal dh = m.top() + m.bottom();
qreal constraintWidth = constraint.width();
if ( constraintWidth > 0.0 )
constraintWidth = qMax( constraintWidth - dw, 0.0 );
if ( constraintHeight > 0.0 )
constraintHeight = qMax( constraintHeight - dh, 0.0 );
contentHint = qskEffectiveSizeHint( m_data->contentItem,
which, QSizeF( constraintWidth, constraintHeight ) );
if ( contentHint.width() >= 0 )
contentHint.rwidth() += dw;
if ( contentHint.height() >= 0 )
contentHint.rheight() += dh;
}
QSizeF QskDialogSubWindow::contentsSizeHint() const
{
qreal w = -1;
w = qMax( w, buttonBoxHint.width() );
w = qMax( w, contentHint.width() );
qreal h = -1;
if ( m_data->buttonBox && m_data->buttonBox->isVisibleTo( this ) )
{
const auto hint = m_data->buttonBox->sizeHint();
w = hint.width();
h = hint.height();
}
if ( auto* control = qskControlCast( m_data->contentItem ) )
{
const auto hint = control->sizeHint();
const auto& m = m_data->contentPadding;
if ( hint.width() >= 0 )
w = qMax( w, hint.width() + m.left() + m.right() );
if ( hint.height() >= 0 )
h += hint.height() + m.top() + m.bottom();
}
const qreal sz = 400.0; // something
const auto innerSize = layoutRectForSize( QSizeF( sz, sz ) ).size();
w += sz - innerSize.width();
h += sz - innerSize.height();
if ( buttonBoxHint.height() > 0.0 && contentHint.height() > 0.0 )
h = buttonBoxHint.height() + contentHint.height();
return QSizeF( w, h );
}

View File

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

View File

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

View File

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

View File

@ -29,8 +29,12 @@ namespace
setTextOptions( options );
}
QSizeF contentsSizeHint() const override
QSizeF contentsSizeHint(
Qt::SizeHint which, const QSizeF& ) const override
{
if ( which != Qt::PreferredSize )
return QSizeF();
auto size = QFontMetricsF( font() ).size( Qt::TextSingleLine, text() );
const QSizeF minSize( metric( Panel | QskAspect::MinimumWidth ),

View File

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

View File

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

View File

@ -5,7 +5,6 @@
#include "QskGridBox.h"
#include "QskGridLayoutEngine.h"
#include "QskLayoutConstraint.h"
#include "QskEvent.h"
#include <algorithm>
@ -341,38 +340,16 @@ void QskGridBox::updateLayout()
m_data->engine.setGeometries( layoutRect() );
}
QSizeF QskGridBox::contentsSizeHint() const
QSizeF QskGridBox::layoutSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
if ( count() == 0 )
return QSizeF( 0, 0 );
if ( which == Qt::MaximumSize )
{
// we can extend beyond the maximum size of the children
return QSizeF();
}
return m_data->engine.sizeHint( Qt::PreferredSize, QSizeF() );
}
qreal QskGridBox::heightForWidth( qreal width ) const
{
auto constrainedHeight =
[this]( QskLayoutConstraint::Type, const QskControl*, qreal width )
{
const QSizeF constraint( width, -1 );
return m_data->engine.sizeHint( Qt::PreferredSize, constraint ).height();
};
return QskLayoutConstraint::constrainedMetric(
QskLayoutConstraint::HeightForWidth, this, width, constrainedHeight );
}
qreal QskGridBox::widthForHeight( qreal height ) const
{
auto constrainedWidth =
[this]( QskLayoutConstraint::Type, const QskControl*, qreal height )
{
const QSizeF constraint( -1, height );
return m_data->engine.sizeHint( Qt::PreferredSize, constraint ).width();
};
return QskLayoutConstraint::constrainedMetric(
QskLayoutConstraint::WidthForHeight, this, height, constrainedWidth );
return m_data->engine.sizeHint( which, constraint );
}
void QskGridBox::geometryChangeEvent( QskGeometryChangeEvent* event )

View File

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

View File

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

View File

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

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 "QskLayoutChain.h"
#include "QskLayoutHint.h"
#include "QskQuick.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
{
class LayoutData
@ -259,11 +349,11 @@ void QskLayoutEngine2D::layoutItem( QQuickItem* item, const QRect& grid ) const
if ( layoutData == nullptr || item == nullptr )
return;
auto alignment = QskLayoutConstraint::layoutAlignmentHint( item );
auto alignment = qskLayoutAlignmentHint( item );
alignment = m_data->effectiveAlignment( alignment );
QRectF rect = layoutData->geometryAt( grid );
rect = QskLayoutConstraint::boundedRect(item, rect, alignment );
auto rect = layoutData->geometryAt( grid );
rect = qskConstrainedItemRect( item, rect, alignment );
if ( layoutData->direction == Qt::RightToLeft )
{
@ -298,7 +388,7 @@ QSizeF QskLayoutEngine2D::sizeHint(
m_data->blockInvalidate = true;
if ( ( constraint.width() >= 0 ) &&
( constraintType() == QskLayoutConstraint::HeightForWidth ) )
( constraintType() == QskSizePolicy::HeightForWidth ) )
{
setupChain( Qt::Horizontal );
@ -306,7 +396,7 @@ QSizeF QskLayoutEngine2D::sizeHint(
setupChain( Qt::Vertical, constraints );
}
else if ( ( constraint.height() >= 0 ) &&
( constraintType() == QskLayoutConstraint::WidthForHeight ) )
( constraintType() == QskSizePolicy::WidthForHeight ) )
{
setupChain( Qt::Vertical );
@ -327,6 +417,54 @@ QSizeF QskLayoutEngine2D::sizeHint(
return QSizeF( width, height );
}
QskLayoutHint QskLayoutEngine2D::layoutHint( const QQuickItem* item,
Qt::Orientation orientation, qreal constraint ) const
{
if ( item == nullptr )
return QskLayoutHint();
const auto policy = qskSizePolicy( item ).policy( orientation );
if ( constraint >= 0.0 )
{
if ( !( policy & QskSizePolicy::ConstrainedFlag ) )
constraint = -1.0;
}
qreal minimum, preferred, maximum;
const auto expandFlags = QskSizePolicy::GrowFlag | QskSizePolicy::ExpandFlag;
if ( ( policy & QskSizePolicy::ShrinkFlag ) &&
( policy & expandFlags ) && ( policy & QskSizePolicy::IgnoreFlag ) )
{
// we don't need to calculate the preferred size
minimum = qskEffectiveConstraint( item, Qt::MinimumSize, orientation );
maximum = qskEffectiveConstraint( item, Qt::MaximumSize, orientation );
preferred = minimum;
}
else
{
preferred = qskLayoutConstraint( item, orientation, constraint );
if ( policy & QskSizePolicy::ShrinkFlag )
minimum = qskEffectiveConstraint( item, Qt::MinimumSize, orientation );
else
minimum = preferred;
if ( policy & expandFlags )
maximum = qskEffectiveConstraint( item, Qt::MaximumSize, orientation );
else
maximum = preferred;
if ( policy & QskSizePolicy::IgnoreFlag )
preferred = minimum;
}
return QskLayoutHint( minimum, preferred, maximum );
}
void QskLayoutEngine2D::setupChain( Qt::Orientation orientation ) const
{
setupChain( orientation, QskLayoutChain::Segments() );
@ -371,7 +509,7 @@ void QskLayoutEngine2D::updateSegments( const QSizeF& size ) const
switch( constraintType() )
{
case QskLayoutConstraint::WidthForHeight:
case QskSizePolicy::WidthForHeight:
{
setupChain( Qt::Vertical );
rows = rowChain.segments( size.height() );
@ -381,7 +519,7 @@ void QskLayoutEngine2D::updateSegments( const QSizeF& size ) const
break;
}
case QskLayoutConstraint::HeightForWidth:
case QskSizePolicy::HeightForWidth:
{
setupChain( Qt::Horizontal );
columns = columnChain.segments( size.width() );
@ -426,28 +564,26 @@ void QskLayoutEngine2D::invalidate( int what )
}
}
QskLayoutConstraint::Type QskLayoutEngine2D::constraintType() const
QskSizePolicy::ConstraintType QskLayoutEngine2D::constraintType() const
{
if ( m_data->constraintType < 0 )
{
auto constraintType = QskLayoutConstraint::Unconstrained;
auto constraintType = QskSizePolicy::Unconstrained;
for ( int i = 0; i < count(); i++ )
{
const auto type = QskLayoutConstraint::constraintType( itemAt( i ) );
const auto type = qskSizePolicy( itemAt( i ) ).constraintType();
using namespace QskLayoutConstraint;
if ( type != Unconstrained )
if ( type != QskSizePolicy::Unconstrained )
{
if ( constraintType == Unconstrained )
if ( constraintType == QskSizePolicy::Unconstrained )
{
constraintType = type;
}
else if ( constraintType != type )
{
qWarning( "QskLayoutEngine2D: conflicting constraints");
constraintType = Unconstrained;
constraintType = QskSizePolicy::Unconstrained;
}
}
}
@ -455,6 +591,6 @@ QskLayoutConstraint::Type QskLayoutEngine2D::constraintType() const
m_data->constraintType = constraintType;
}
return static_cast< QskLayoutConstraint::Type >( m_data->constraintType );
return static_cast< QskSizePolicy::ConstraintType >( m_data->constraintType );
}

View File

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

View File

@ -4,11 +4,11 @@
*****************************************************************************/
#include "QskLayoutHint.h"
#include "QskLayoutConstraint.h"
#include "QskControl.h"
#include <qnamespace.h>
QskLayoutHint::QskLayoutHint()
: QskLayoutHint( 0.0, 0.0, QskLayoutConstraint::unlimited )
: QskLayoutHint( 0.0, 0.0, QskLayoutHint::unlimited )
{
}
@ -75,7 +75,21 @@ void QskLayoutHint::normalize()
bool QskLayoutHint::isDefault() const
{
return ( m_minimum == 0.0 ) && ( m_preferred == 0.0 )
&& ( m_maximum == QskLayoutConstraint::unlimited );
&& ( m_maximum == QskLayoutHint::unlimited );
}
qreal QskLayoutHint::combined( int which, qreal value1, qreal value2 )
{
if ( value1 < 0.0 )
return value2;
if ( value2 < 0.0 )
return value1;
if ( which == Qt::MaximumSize )
return qMin( value1, value2 );
else
return qMax( value1, value2 );
}
#ifndef QT_NO_DEBUG_STREAM
@ -84,7 +98,7 @@ bool QskLayoutHint::isDefault() const
static inline QString qskHintValueString( qreal value )
{
if ( value >= QskLayoutConstraint::unlimited )
if ( value >= QskLayoutHint::unlimited )
return QStringLiteral( "unlimited" );
else
return QString::number( value );

View File

@ -8,6 +8,7 @@
#include "QskGlobal.h"
#include <qglobal.h>
#include <limits>
class QDebug;
@ -44,6 +45,9 @@ class QSK_EXPORT QskLayoutHint
void expandPreferred( qreal value );
void expandMaximum( qreal value );
static qreal combined( int which, qreal value1, qreal value2 );
static constexpr qreal unlimited = std::numeric_limits< float >::max();
private:
qreal m_minimum;
qreal m_preferred;

View File

@ -5,8 +5,6 @@
#include "QskLinearBox.h"
#include "QskLinearLayoutEngine.h"
#include "QskLayoutConstraint.h"
#include "QskEvent.h"
#include "QskQuick.h"
@ -188,33 +186,16 @@ void QskLinearBox::updateLayout()
m_data->engine.setGeometries( layoutRect() );
}
QSizeF QskLinearBox::contentsSizeHint() const
QSizeF QskLinearBox::layoutSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
return m_data->engine.sizeHint( Qt::PreferredSize, QSizeF() );
}
if ( which == Qt::MaximumSize )
{
// we can extend beyond the maximum size of the children
return QSizeF();
}
qreal QskLinearBox::heightForWidth( qreal width ) const
{
auto constrainedHeight =
[this]( QskLayoutConstraint::Type, const QskControl*, qreal width )
{
return m_data->engine.heightForWidth( width );
};
return QskLayoutConstraint::constrainedMetric(
QskLayoutConstraint::HeightForWidth, this, width, constrainedHeight );
}
qreal QskLinearBox::widthForHeight( qreal height ) const
{
auto constrainedWidth =
[this]( QskLayoutConstraint::Type, const QskControl*, qreal height )
{
return m_data->engine.widthForHeight( height );
};
return QskLayoutConstraint::constrainedMetric(
QskLayoutConstraint::WidthForHeight, this, height, constrainedWidth );
return m_data->engine.sizeHint( which, constraint );
}
void QskLinearBox::geometryChangeEvent( QskGeometryChangeEvent* event )

View File

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

View File

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

View File

@ -5,36 +5,12 @@
#include "QskStackBox.h"
#include "QskStackBoxAnimator.h"
#include "QskLayoutConstraint.h"
#include "QskLayoutHint.h"
#include "QskEvent.h"
#include "QskQuick.h"
#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
{
public:
@ -328,11 +304,11 @@ QRectF QskStackBox::geometryForItemAt( int index ) const
if ( const auto item = m_data->items.value( index ) )
{
auto alignment = QskLayoutConstraint::layoutAlignmentHint( item );
auto alignment = qskLayoutAlignmentHint( item );
if ( alignment == 0 )
alignment = m_data->defaultAlignment;
return QskLayoutConstraint::boundedRect( item, r, alignment );
return qskConstrainedItemRect( item, r, alignment );
}
return QRectF( r.x(), r.y(), 0.0, 0.0 );
@ -352,91 +328,93 @@ void QskStackBox::updateLayout()
}
}
QSizeF QskStackBox::contentsSizeHint() const
QSizeF QskStackBox::layoutSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
#if 1
// needs to reimplemented TODO ...
if ( which != Qt::PreferredSize )
return QSizeF();
if ( itemCount() == 0 )
return QSizeF( 0, 0 );
#endif
return QSizeF();
if ( constraint.width() >= 0 || constraint.height() >= 0 )
{
qreal value = -1;
for ( const auto& item : qskAsConst( m_data->items ) )
{
const auto hint = qskEffectiveSizeHint(
item, Qt::PreferredSize, constraint );
if ( constraint.width() >= 0 )
value = qMax( hint.height(), value );
else
value = qMax( hint.width(), value );
}
if ( constraint.width() >= 0 )
return QSizeF( constraint.width(), value );
else
return QSizeF( value, constraint.height() );
}
qreal width = -1;
qreal height = -1;
using namespace QskLayoutConstraint;
int constraintTypes = Unconstrained;
int constraintTypes = QskSizePolicy::Unconstrained;
for ( const auto item : qskAsConst( m_data->items ) )
{
const auto type = constraintType( item );
if ( type != Unconstrained )
const auto type = qskSizePolicy( item ).constraintType();
if ( type != QskSizePolicy::Unconstrained )
{
constraintTypes |= type;
continue;
}
else
{
const auto hint = QskLayoutConstraint::sizeHint(
item, Qt::PreferredSize, QSizeF( -1, -1 ) );
if ( hint.width() >= width )
width = hint.width();
const auto hint = qskSizeConstraint( item, which, constraint );
if ( hint.height() >= height )
height = hint.height();
}
width = QskLayoutHint::combined( which, width, hint.width() );
height = QskLayoutHint::combined( which, height, hint.height() );
}
#if 1
// does this work ???
if ( constraintTypes & WidthForHeight )
if ( constraintTypes & QskSizePolicy::WidthForHeight )
{
const QSizeF constraint( -1, height );
for ( const auto& item : qskAsConst( m_data->items ) )
{
if ( constraintType( item ) == WidthForHeight )
{
const auto hint = QskLayoutConstraint::sizeHint(
item, Qt::PreferredSize, constraint );
const auto sizePolicy = qskSizePolicy( item );
width = qMax( width, hint.width() );
if ( sizePolicy.constraintType() == QskSizePolicy::WidthForHeight )
{
const auto hint = qskSizeConstraint( item, which, constraint );
width = QskLayoutHint::combined( which, width, hint.width() );
}
}
}
if ( constraintTypes & HeightForWidth )
if ( constraintTypes & QskSizePolicy::HeightForWidth )
{
const QSizeF constraint( width, -1 );
for ( const auto& item : qskAsConst( m_data->items ) )
{
if ( constraintType( item ) == HeightForWidth )
{
const QSizeF hint = QskLayoutConstraint::sizeHint(
item, Qt::PreferredSize, constraint );
const auto sizePolicy = qskSizePolicy( item );
height = qMax( height, hint.height() );
if ( sizePolicy.constraintType() == QskSizePolicy::HeightForWidth )
{
const auto hint = qskSizeConstraint( item, which, constraint );
height = QskLayoutHint::combined( which, height, hint.height() );
}
}
}
#endif
return QSizeF( width, height );
}
qreal QskStackBox::heightForWidth( qreal width ) const
{
return QskLayoutConstraint::constrainedMetric(
QskLayoutConstraint::HeightForWidth, this, width, qskConstrainedValue );
}
qreal QskStackBox::widthForHeight( qreal height ) const
{
return QskLayoutConstraint::constrainedMetric(
QskLayoutConstraint::WidthForHeight, this, height, qskConstrainedValue );
}
bool QskStackBox::event( QEvent* event )
{
switch ( static_cast< int >( event->type() ) )

View File

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

View File

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