QskLayoutElement introduced

This commit is contained in:
Uwe Rathmann 2022-08-06 15:41:32 +02:00
parent bc5510f7ef
commit 9daf934426
10 changed files with 579 additions and 395 deletions

View File

@ -6,6 +6,7 @@
#include "QskQuick.h" #include "QskQuick.h"
#include "QskControl.h" #include "QskControl.h"
#include "QskFunctions.h" #include "QskFunctions.h"
#include "QskLayoutElement.h"
#include <qquickitem.h> #include <qquickitem.h>
QSK_QT_PRIVATE_BEGIN QSK_QT_PRIVATE_BEGIN
@ -419,221 +420,23 @@ QSizeF qskEffectiveSizeHint( const QQuickItem* item,
return hint; 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 = constraint;
if ( orientation == Qt::Horizontal )
{
if ( hintMax.width() >= 0.0 )
size.rwidth() = qMin( size.width(), hintMax.width() );
size.rwidth() = qMax( size.width(), hintMin.width() );
}
else
{
if ( hintMax.height() >= 0.0 )
size.rheight() = qMin( size.height(), hintMax.height() );
size.rheight() = qMax( size.height(), hintMin.height() );
}
return size;
}
QSizeF qskSizeConstraint( const QQuickItem* item, QSizeF qskSizeConstraint( const QQuickItem* item,
Qt::SizeHint which, const QSizeF& constraint ) Qt::SizeHint which, const QSizeF& constraint )
{ {
if ( item == nullptr ) if ( item == nullptr )
return QSizeF( 0, 0 ); return QSizeF( 0, 0 );
if ( constraint.isValid() ) const QskItemLayoutElement layoutElement( item );
return constraint; return layoutElement.sizeConstraint( which, constraint );
auto policy = qskSizePolicy( item );
bool ignoreWidth = false;
bool ignoreHeight = false;
if ( which == Qt::PreferredSize )
{
/*
First we are checking the IgnoreFlag, to avoid doing
pointless calculations.
*/
ignoreWidth = policy.policy( Qt::Horizontal ) & QskSizePolicy::IgnoreFlag;
ignoreHeight = policy.policy( Qt::Vertical ) & QskSizePolicy::IgnoreFlag;
if ( ( ignoreWidth && ignoreHeight )
|| ( ignoreWidth && constraint.height() >= 0.0 )
|| ( ignoreHeight && constraint.width() >= 0.0 ) )
{
return QSizeF();
}
}
const auto whichH = policy.effectiveSizeHintType( which, Qt::Horizontal );
const auto whichV = policy.effectiveSizeHintType( which, Qt::Vertical );
QSizeF size;
int constraintType = QskSizePolicy::Unconstrained;
/*
We apply a constraint - even, when the policy is unconstrained.
Do we really want to do this ???
*/
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:
{
if ( whichV != whichH )
{
if ( !ignoreWidth )
size.rwidth() = qskEffectiveSizeHint( item, whichH ).width();
if ( !ignoreHeight )
size.rheight() = qskEffectiveSizeHint( item, whichV ).height();
}
else
{
size = qskEffectiveSizeHint( item, whichH );
}
}
}
}
switch( constraintType )
{
case QskSizePolicy::HeightForWidth:
{
const QSizeF c( size.width(), -1.0 );
size.rheight() = qskEffectiveSizeHint( item, whichV, c ).height();
break;
}
case QskSizePolicy::WidthForHeight:
{
const QSizeF c( -1.0, size.height() );
size.rwidth() = qskEffectiveSizeHint( item, whichH, c ).width();
break;
}
}
if ( ignoreWidth || constraint.width() >= 0.0 )
size.rwidth() = -1.0;
if ( ignoreHeight || constraint.height() >= 0.0 )
size.rheight() = -1.0;
return size;
} }
QSizeF qskConstrainedItemSize( const QQuickItem* item, const QSizeF& size ) QSizeF qskConstrainedItemSize( const QQuickItem* item, const QSizeF& size )
{ {
if ( item == nullptr || ( size.width() <= 0.0 && size.height() <= 0.0 ) ) if ( item == nullptr )
return QSizeF( 0.0, 0.0 ); return QSizeF( 0.0, 0.0 );
QSizeF min, max; const QskItemLayoutElement layoutElement( item );
return layoutElement.constrainedSize( size );
const auto policy = qskSizePolicy( item );
switch( policy.constraintType() )
{
case QskSizePolicy::WidthForHeight:
{
const auto constraint = qskBoundedConstraint( item,
QSizeF( -1.0, size.height() ), policy );
min = qskSizeConstraint( item, Qt::MinimumSize, constraint );
max = qskSizeConstraint( item, Qt::MaximumSize, constraint );
min.rheight() = max.rheight() = constraint.height();
break;
}
case QskSizePolicy::HeightForWidth:
{
const auto constraint = qskBoundedConstraint( item,
QSizeF( size.width(), -1.0 ), policy );
min = qskSizeConstraint( item, Qt::MinimumSize, constraint );
max = qskSizeConstraint( item, Qt::MaximumSize, constraint );
min.rwidth() = max.rwidth() = constraint.width();
break;
}
default:
{
min = qskSizeConstraint( item, Qt::MinimumSize, QSizeF() );
max = qskSizeConstraint( item, Qt::MaximumSize, QSizeF() );
}
}
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() );
width = qMax( width, min.width() );
height = qMax( height, min.height() );
return QSizeF( width, height );
} }
QRectF qskConstrainedItemRect( const QQuickItem* item, QRectF qskConstrainedItemRect( const QQuickItem* item,

View File

@ -6,6 +6,7 @@
#include "QskGridLayoutEngine.h" #include "QskGridLayoutEngine.h"
#include "QskLayoutMetrics.h" #include "QskLayoutMetrics.h"
#include "QskLayoutChain.h" #include "QskLayoutChain.h"
#include "QskLayoutElement.h"
#include "QskSizePolicy.h" #include "QskSizePolicy.h"
#include "QskQuick.h" #include "QskQuick.h"
@ -162,6 +163,13 @@ namespace
namespace namespace
{ {
inline QskLayoutMetrics qskItemMetrics(
QQuickItem* item, Qt::Orientation orientation, qreal constraint )
{
const QskItemLayoutElement layoutItem( item );
return layoutItem.metrics( orientation, constraint );
}
class Element class Element
{ {
public: public:
@ -543,6 +551,30 @@ QQuickItem* QskGridLayoutEngine::itemAt( int index ) const
return nullptr; return nullptr;
} }
QskSizePolicy QskGridLayoutEngine::sizePolicyAt( int index ) const
{
return qskSizePolicy( itemAt( index ) );
}
int QskGridLayoutEngine::indexOf( const QQuickItem* item ) const
{
if ( item )
{
/*
indexOf is often called after inserting an item to
set additinal properties. So we search in reverse order
*/
for ( int i = count() - 1; i >= 0; --i )
{
if ( itemAt( i ) == item )
return i;
}
}
return -1;
}
QSizeF QskGridLayoutEngine::spacerAt( int index ) const QSizeF QskGridLayoutEngine::spacerAt( int index ) const
{ {
if ( const auto element = m_data->elementAt( index ) ) if ( const auto element = m_data->elementAt( index ) )
@ -601,7 +633,12 @@ void QskGridLayoutEngine::layoutItems()
if ( qskIsAdjustableByLayout( item ) ) if ( qskIsAdjustableByLayout( item ) )
{ {
const auto grid = m_data->effectiveGrid( element ); const auto grid = m_data->effectiveGrid( element );
layoutItem( item, grid );
const QskItemLayoutElement layoutElement( item );
const auto rect = geometryAt( &layoutElement, grid );
if ( rect.size().isValid() )
qskSetItemGeometry( item, rect );
} }
} }
} }
@ -650,8 +687,9 @@ void QskGridLayoutEngine::setupChain( Qt::Orientation orientation,
constraint = qskSegmentLength( constraints, grid.left(), grid.right() ); constraint = qskSegmentLength( constraints, grid.left(), grid.right() );
auto cell = element.cell( orientation ); auto cell = element.cell( orientation );
if ( element.item() ) if ( element.item() )
cell.metrics = layoutMetrics( element.item(), orientation, constraint ); cell.metrics = qskItemMetrics( element.item(), orientation, constraint );
chain.expandCell( grid.top(), cell ); chain.expandCell( grid.top(), cell );
} }
@ -677,7 +715,7 @@ void QskGridLayoutEngine::setupChain( Qt::Orientation orientation,
constraint = qskSegmentLength( constraints, grid.left(), grid.right() ); constraint = qskSegmentLength( constraints, grid.left(), grid.right() );
auto cell = element->cell( orientation ); auto cell = element->cell( orientation );
cell.metrics = layoutMetrics( element->item(), orientation, constraint ); cell.metrics = qskItemMetrics( element->item(), orientation, constraint );
chain.expandCells( grid.top(), grid.height(), cell ); chain.expandCells( grid.top(), grid.height(), cell );
} }

View File

@ -39,12 +39,14 @@ class QskGridLayoutEngine : public QskLayoutEngine2D
bool removeAt( int index ); bool removeAt( int index );
bool clear(); bool clear();
QQuickItem* itemAt( int index ) const override final; QQuickItem* itemAt( int index ) const;
QSizeF spacerAt( int index ) const; QSizeF spacerAt( int index ) const;
QQuickItem* itemAt( int row, int column ) const; QQuickItem* itemAt( int row, int column ) const;
int indexAt( int row, int column ) const; int indexAt( int row, int column ) const;
int indexOf( const QQuickItem* ) const;
bool setGridAt( int index, const QRect& ); bool setGridAt( int index, const QRect& );
QRect gridAt( int index ) const; QRect gridAt( int index ) const;
@ -53,6 +55,7 @@ class QskGridLayoutEngine : public QskLayoutEngine2D
void transpose(); void transpose();
private: private:
QskSizePolicy sizePolicyAt( int index ) const override final;
void layoutItems() override; void layoutItems() override;
int effectiveCount( Qt::Orientation ) const override; int effectiveCount( Qt::Orientation ) const override;

View File

@ -0,0 +1,385 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskLayoutElement.h"
#include "QskLayoutMetrics.h"
#include "QskSizePolicy.h"
static inline bool qskCanGrow(
const QskLayoutElement* element, Qt::Orientation orientation )
{
const quint32 growFlags = QskSizePolicy::GrowFlag | QskSizePolicy::ExpandFlag;
return element->sizePolicy().policy( orientation ) & growFlags;
}
QskLayoutElement::QskLayoutElement()
{
}
QskLayoutElement::~QskLayoutElement()
{
}
QSizeF QskLayoutElement::sizeConstraint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
if ( constraint.isValid() )
return constraint;
auto policy = sizePolicy();
bool ignoreWidth = false;
bool ignoreHeight = false;
if ( which == Qt::PreferredSize )
{
/*
First we are checking the IgnoreFlag, to avoid doing
pointless calculations.
*/
ignoreWidth = policy.policy( Qt::Horizontal ) & QskSizePolicy::IgnoreFlag;
ignoreHeight = policy.policy( Qt::Vertical ) & QskSizePolicy::IgnoreFlag;
if ( ( ignoreWidth && ignoreHeight )
|| ( ignoreWidth && constraint.height() >= 0.0 )
|| ( ignoreHeight && constraint.width() >= 0.0 ) )
{
return QSizeF();
}
}
const auto whichH = policy.effectiveSizeHintType( which, Qt::Horizontal );
const auto whichV = policy.effectiveSizeHintType( which, Qt::Vertical );
QSizeF size;
int constraintType = QskSizePolicy::Unconstrained;
/*
We apply a constraint - even, when the policy is unconstrained.
Do we really want to do this ???
*/
if ( constraint.height() >= 0.0 )
{
const auto h = boundedSize( Qt::Vertical, constraint.height() );
size = sizeHint( whichV, QSizeF( -1.0, h ) );
if ( ( whichH != whichV ) || ( size.height() != h ) )
constraintType = QskSizePolicy::WidthForHeight;
}
else if ( constraint.width() >= 0.0 )
{
const auto w = boundedSize( Qt::Horizontal, constraint.width() );
size = sizeHint( whichH, QSizeF( w, -1.0 ) );
if ( ( whichV != whichH ) || ( size.width() != w ) )
constraintType = QskSizePolicy::HeightForWidth;
}
else
{
constraintType = policy.constraintType();
switch( constraintType )
{
case QskSizePolicy::WidthForHeight:
{
size = sizeHint( whichV );
break;
}
case QskSizePolicy::HeightForWidth:
{
size = sizeHint( whichH );
break;
}
default:
{
if ( whichV != whichH )
{
if ( !ignoreWidth )
size.rwidth() = sizeHint( whichH ).width();
if ( !ignoreHeight )
size.rheight() = sizeHint( whichV ).height();
}
else
{
size = sizeHint( whichH );
}
}
}
}
switch( constraintType )
{
case QskSizePolicy::HeightForWidth:
{
const QSizeF c( size.width(), -1.0 );
size.rheight() = sizeHint( whichV, c ).height();
break;
}
case QskSizePolicy::WidthForHeight:
{
const QSizeF c( -1.0, size.height() );
size.rwidth() = sizeHint( whichH, c ).width();
break;
}
}
if ( ignoreWidth || constraint.width() >= 0.0 )
size.rwidth() = -1.0;
if ( ignoreHeight || constraint.height() >= 0.0 )
size.rheight() = -1.0;
return size;
}
QSizeF QskLayoutElement::constrainedSize( const QSizeF& size ) const
{
if ( size.width() <= 0.0 && size.height() <= 0.0 )
return QSizeF( 0.0, 0.0 );
QSizeF min, max;
const auto policy = sizePolicy();
switch( policy.constraintType() )
{
case QskSizePolicy::WidthForHeight:
{
const qreal h = boundedSize( Qt::Vertical, size.height() );
min = sizeConstraint( Qt::MinimumSize, QSizeF( -1.0, h ) );
max = sizeConstraint( Qt::MaximumSize, QSizeF( -1.0, h ) );
min.rheight() = max.rheight() = h;
break;
}
case QskSizePolicy::HeightForWidth:
{
const qreal w = boundedSize( Qt::Horizontal, size.width() );
min = sizeConstraint( Qt::MinimumSize, QSizeF( w, -1.0 ) );
max = sizeConstraint( Qt::MaximumSize, QSizeF( w, -1.0 ) );
min.rwidth() = max.rwidth() = w;
break;
}
default:
{
min = sizeConstraint( Qt::MinimumSize, QSizeF() );
max = sizeConstraint( Qt::MaximumSize, QSizeF() );
}
}
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() );
width = qMax( width, min.width() );
height = qMax( height, min.height() );
return QSizeF( width, height );
}
QskLayoutMetrics QskLayoutElement::metrics(
Qt::Orientation orientation, qreal constraint ) const
{
const auto policy = sizePolicy().policy( orientation );
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 = metric( orientation, Qt::MinimumSize, -1.0 );
maximum = metric( orientation, Qt::MaximumSize, -1.0 );
preferred = minimum;
}
else
{
if ( constraint >= 0.0 )
{
if ( !( policy & QskSizePolicy::ConstrainedFlag ) )
constraint = -1.0;
}
preferred = metric( orientation, Qt::PreferredSize, constraint );
if ( policy & QskSizePolicy::ShrinkFlag )
minimum = metric( orientation, Qt::MinimumSize, -1.0 );
else
minimum = preferred;
if ( policy & expandFlags )
maximum = metric( orientation, Qt::MaximumSize, -1.0 );
else
maximum = preferred;
if ( policy & QskSizePolicy::IgnoreFlag )
preferred = minimum;
}
return QskLayoutMetrics( minimum, preferred, maximum );
}
qreal QskLayoutElement::metric( Qt::Orientation orientation,
Qt::SizeHint which, qreal constraint ) const
{
qreal metric = 0.0;
if ( which == Qt::MinimumSize )
{
const auto hint = sizeHint( Qt::MinimumSize );
if ( orientation == Qt::Horizontal )
metric = hint.width();
else
metric = hint.height();
if ( metric < 0.0 )
metric = 0.0;
}
else if ( which == Qt::MaximumSize )
{
const auto hint = sizeHint( Qt::MaximumSize );
if ( orientation == Qt::Horizontal )
metric = hint.width();
else
metric = hint.height();
if ( metric < 0.0 )
metric = QskLayoutMetrics::unlimited;
}
else if ( which == Qt::PreferredSize )
{
const auto constraintType = sizePolicy().constraintType();
if ( constraintType == QskSizePolicy::Unconstrained )
{
const auto hint = sizeHint( Qt::PreferredSize );
if ( orientation == Qt::Horizontal )
metric = hint.width();
else
metric = hint.height();
}
else
{
if ( constraint < 0.0 )
{
auto hint = sizeHint( Qt::PreferredSize );
if ( orientation == Qt::Horizontal )
{
if ( constraintType == QskSizePolicy::WidthForHeight )
hint.setWidth( widthForHeight( hint.height() ) );
metric = hint.width();
}
else
{
if ( constraintType == QskSizePolicy::HeightForWidth )
hint.setHeight( heightForWidth( hint.width() ) );
metric = hint.height();
}
}
else
{
if ( orientation == Qt::Horizontal )
{
if ( !qskCanGrow( this, Qt::Vertical ) )
{
const auto maxH = sizeHint( Qt::PreferredSize ).height();
if ( maxH >= 0.0 )
constraint = qMin( constraint, maxH );
}
metric = widthForHeight( constraint );
}
else
{
if ( !qskCanGrow( this, Qt::Horizontal ) )
{
const auto maxW = sizeHint( Qt::PreferredSize ).width();
if ( maxW >= 0.0 )
constraint = qMin( constraint, maxW );
}
metric = heightForWidth( constraint );
}
}
}
if ( metric < 0.0 )
metric = 0.0;
}
return metric;
}
qreal QskLayoutElement::boundedSize( Qt::Orientation orientation, qreal size ) const
{
const auto policy = sizePolicy();
const auto whichMin = policy.effectiveSizeHintType( Qt::MinimumSize, orientation );
const auto whichMax = policy.effectiveSizeHintType( Qt::MaximumSize, orientation );
const auto hintMin = sizeHint( whichMin );
const auto hintMax = ( whichMax == whichMin ) ? hintMin : sizeHint( whichMax );
if ( orientation == Qt::Horizontal )
{
if ( hintMax.width() >= 0.0 )
size = qMin( size, hintMax.width() );
size = qMax( size, hintMin.width() );
}
else
{
if ( hintMax.height() >= 0.0 )
size = qMin( size, hintMax.height() );
size = qMax( size, hintMin.height() );
}
return size;
}
#include "QskQuick.h"
QskItemLayoutElement::QskItemLayoutElement( const QQuickItem* item )
: m_item( item )
{
}
QskSizePolicy QskItemLayoutElement::sizePolicy() const
{
return qskSizePolicy( m_item );
}
QSizeF QskItemLayoutElement::sizeHint( Qt::SizeHint which,
const QSizeF& constraint ) const
{
return qskEffectiveSizeHint( m_item, which, constraint );
}
Qt::Alignment QskItemLayoutElement::alignment() const
{
return qskLayoutAlignmentHint( m_item );
}

View File

@ -0,0 +1,71 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#ifndef QSK_LAYOUT_ELEMENT_H
#define QSK_LAYOUT_ELEMENT_H
#include "QskGlobal.h"
#include <qnamespace.h>
#include <qrect.h>
class QskSizePolicy;
class QskLayoutMetrics;
class QskLayoutElement
{
public:
QskLayoutElement();
virtual ~QskLayoutElement();
QskLayoutMetrics metrics( Qt::Orientation, qreal constraint ) const;
virtual QskSizePolicy sizePolicy() const = 0;
virtual Qt::Alignment alignment() const = 0;
QSizeF constrainedSize( const QSizeF& ) const;
QSizeF sizeConstraint( Qt::SizeHint, const QSizeF& constraint ) const;
private:
Q_DISABLE_COPY( QskLayoutElement )
qreal metric( Qt::Orientation, Qt::SizeHint, qreal constraint ) const;
virtual QSizeF sizeHint( Qt::SizeHint,
const QSizeF& constraint = QSizeF() ) const = 0;
qreal heightForWidth( qreal ) const;
qreal widthForHeight( qreal ) const;
qreal boundedSize( Qt::Orientation, qreal ) const;
};
inline qreal QskLayoutElement::heightForWidth( qreal width ) const
{
return sizeHint( Qt::PreferredSize, QSizeF( width, -1.0 ) ).height();
}
inline qreal QskLayoutElement::widthForHeight( qreal height ) const
{
return sizeHint( Qt::PreferredSize, QSizeF( -1.0, height ) ).width();
}
class QQuickItem;
class QskItemLayoutElement final : public QskLayoutElement
{
public:
QskItemLayoutElement( const QQuickItem* );
QskSizePolicy sizePolicy() const override;
Qt::Alignment alignment() const override;
private:
QSizeF sizeHint( Qt::SizeHint, const QSizeF& ) const override;
const QQuickItem* m_item = nullptr;
};
#endif

View File

@ -5,100 +5,11 @@
#include "QskLayoutEngine2D.h" #include "QskLayoutEngine2D.h"
#include "QskLayoutChain.h" #include "QskLayoutChain.h"
#include "QskLayoutMetrics.h" #include "QskLayoutElement.h"
#include "QskControl.h" #include "QskFunctions.h"
#include "QskQuick.h"
#include <qguiapplication.h> #include <qguiapplication.h>
static QSizeF qskItemConstraint( const QQuickItem* item, const QSizeF& constraint )
{
QSizeF hint( 0, 0 );
const auto sizePolicy = qskSizePolicy( item );
const auto constraintType = sizePolicy.constraintType();
const auto which = Qt::PreferredSize;
if ( constraintType != QskSizePolicy::Unconstrained )
{
const quint32 growFlags = QskSizePolicy::GrowFlag | QskSizePolicy::ExpandFlag;
if ( constraint.width() > 0 ) // && constrainedType == HeightForWidth ??
{
qreal w = constraint.width();
if ( !( sizePolicy.policy( Qt::Horizontal ) & growFlags ) )
{
const auto maxW = qskEffectiveSizeHint( item, which ).width();
if ( maxW >= 0.0 )
w = qMin( w, maxW );
}
hint.setWidth( w );
hint.setHeight( qskHeightForWidth( item, which, w ) );
}
else if ( constraint.height() > 0 ) // && constrainedType == WidthForHeight ??
{
qreal h = constraint.height();
if ( !( sizePolicy.policy( Qt::Vertical ) & growFlags ) )
{
const auto maxH = qskEffectiveSizeHint( item, which ).height();
if ( maxH >= 0.0 )
h = qMin( h, maxH );
}
hint.setWidth( qskWidthForHeight( item, which, h ) );
hint.setHeight( h );
}
else
{
hint = qskEffectiveSizeHint( item, which );
if ( constraintType == QskSizePolicy::WidthForHeight )
hint.setWidth( qskWidthForHeight( item, which, hint.height() ) );
else
hint.setHeight( qskHeightForWidth( item, which, hint.width() ) );
}
}
else
{
hint = qskEffectiveSizeHint( item, which );
}
hint = hint.expandedTo( QSizeF( 0.0, 0.0 ) );
return hint;
}
static inline qreal qskLayoutConstraint( const QQuickItem* item,
Qt::Orientation orientation, qreal constraint )
{
if ( orientation == Qt::Horizontal )
return qskItemConstraint( item, QSizeF( -1.0, constraint ) ).width();
else
return qskItemConstraint( item, QSizeF( constraint, -1.0 ) ).height();
}
static inline qreal qskEffectiveConstraint( const QQuickItem* item,
Qt::SizeHint which, Qt::Orientation orientation )
{
qreal value;
if ( orientation == Qt::Horizontal )
value = qskEffectiveSizeHint( item, which ).width();
else
value = qskEffectiveSizeHint( item, which ).height();
if ( value < 0.0 )
value = ( which == Qt::MaximumSize ) ? QskLayoutMetrics::unlimited : 0.0;
return value;
}
namespace namespace
{ {
class LayoutData class LayoutData
@ -289,25 +200,6 @@ bool QskLayoutEngine2D::setExtraSpacingAt( Qt::Edges edges )
return true; return true;
} }
int QskLayoutEngine2D::indexOf( const QQuickItem* item ) const
{
if ( item )
{
/*
indexOf is often called after inserting an item to
set additinal properties. So we search in reverse order
*/
for ( int i = count() - 1; i >= 0; --i )
{
if ( itemAt( i ) == item )
return i;
}
}
return -1;
}
Qt::Edges QskLayoutEngine2D::extraSpacingAt() const Qt::Edges QskLayoutEngine2D::extraSpacingAt() const
{ {
return static_cast< Qt::Edges >( m_data->extraSpacingAt ); return static_cast< Qt::Edges >( m_data->extraSpacingAt );
@ -343,26 +235,30 @@ void QskLayoutEngine2D::setGeometries( const QRectF& rect )
m_data->layoutData = nullptr; m_data->layoutData = nullptr;
} }
void QskLayoutEngine2D::layoutItem( QQuickItem* item, const QRect& grid ) const QRectF QskLayoutEngine2D::geometryAt(
const QskLayoutElement* element, const QRect& grid ) const
{ {
auto layoutData = m_data->layoutData; const auto layoutData = m_data->layoutData;
if ( layoutData == nullptr || item == nullptr ) if ( layoutData && element )
return;
auto alignment = qskLayoutAlignmentHint( item );
alignment = m_data->effectiveAlignment( alignment );
auto rect = layoutData->geometryAt( grid );
rect = qskConstrainedItemRect( item, rect, alignment );
if ( layoutData->direction == Qt::RightToLeft )
{ {
const auto& r = layoutData->rect; auto rect = layoutData->geometryAt( grid );
rect.moveRight( r.right() - ( rect.left() - r.left() ) );
const auto size = element->constrainedSize( rect.size() );
const auto alignment = m_data->effectiveAlignment( element->alignment() );
rect = qskAlignedRectF( rect, size, alignment );
if ( layoutData->direction == Qt::RightToLeft )
{
const auto& r = layoutData->rect;
rect.moveRight( r.right() - ( rect.left() - r.left() ) );
}
return rect;
} }
qskSetItemGeometry( item, rect ); return QRectF( 0, 0, -1, -1 );
} }
qreal QskLayoutEngine2D::widthForHeight( qreal height ) const qreal QskLayoutEngine2D::widthForHeight( qreal height ) const
@ -421,7 +317,7 @@ QSizeF QskLayoutEngine2D::sizeHint(
if ( constraint.height() >= 0 || constraint.width() >= 0 ) if ( constraint.height() >= 0 || constraint.width() >= 0 )
{ {
/* /*
As none of the items have the Constrained flag the constraint As none of the elements has the Constrained flag the constraint
will have no effect and we ignore it to make use of the cached will have no effect and we ignore it to make use of the cached
results from unconstrained requests results from unconstrained requests
*/ */
@ -477,54 +373,6 @@ QSizeF QskLayoutEngine2D::sizeHint(
return hint; return hint;
} }
QskLayoutMetrics QskLayoutEngine2D::layoutMetrics( const QQuickItem* item,
Qt::Orientation orientation, qreal constraint ) const
{
if ( item == nullptr )
return QskLayoutMetrics();
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 QskLayoutMetrics( minimum, preferred, maximum );
}
void QskLayoutEngine2D::setupChain( Qt::Orientation orientation ) const void QskLayoutEngine2D::setupChain( Qt::Orientation orientation ) const
{ {
setupChain( orientation, QskLayoutChain::Segments() ); setupChain( orientation, QskLayoutChain::Segments() );
@ -631,7 +479,7 @@ QskSizePolicy::ConstraintType QskLayoutEngine2D::constraintType() const
for ( int i = 0; i < count(); i++ ) for ( int i = 0; i < count(); i++ )
{ {
const auto type = qskSizePolicy( itemAt( i ) ).constraintType(); const auto type = sizePolicyAt( i ).constraintType();
if ( type != QskSizePolicy::Unconstrained ) if ( type != QskSizePolicy::Unconstrained )
{ {

View File

@ -13,8 +13,7 @@
#include <qnamespace.h> #include <qnamespace.h>
#include <memory> #include <memory>
class QQuickItem; class QskLayoutElement;
class QskLayoutMetrics;
class QskLayoutEngine2D class QskLayoutEngine2D
{ {
@ -24,10 +23,6 @@ class QskLayoutEngine2D
virtual int count() const = 0; virtual int count() const = 0;
virtual QQuickItem* itemAt( int index ) const = 0;
int indexOf( const QQuickItem* ) const;
int rowCount() const; int rowCount() const;
int columnCount() const; int columnCount() const;
@ -55,10 +50,7 @@ class QskLayoutEngine2D
void setGeometries( const QRectF& ); void setGeometries( const QRectF& );
protected: protected:
QRectF geometryAt( const QskLayoutElement*, const QRect& grid ) const;
void layoutItem( QQuickItem*, const QRect& grid ) const;
QskLayoutMetrics layoutMetrics( const QQuickItem*,
Qt::Orientation, qreal constraint ) const;
enum enum
{ {
@ -79,6 +71,8 @@ class QskLayoutEngine2D
virtual void invalidateElementCache() = 0; virtual void invalidateElementCache() = 0;
QskSizePolicy::ConstraintType constraintType() const; QskSizePolicy::ConstraintType constraintType() const;
virtual QskSizePolicy sizePolicyAt( int index ) const = 0;
void setupChain( Qt::Orientation ) const; void setupChain( Qt::Orientation ) const;
void setupChain( Qt::Orientation, const QskLayoutChain::Segments& ) const; void setupChain( Qt::Orientation, const QskLayoutChain::Segments& ) const;

View File

@ -6,6 +6,7 @@
#include "QskLinearLayoutEngine.h" #include "QskLinearLayoutEngine.h"
#include "QskLayoutMetrics.h" #include "QskLayoutMetrics.h"
#include "QskLayoutChain.h" #include "QskLayoutChain.h"
#include "QskLayoutElement.h"
#include "QskSizePolicy.h" #include "QskSizePolicy.h"
#include "QskQuick.h" #include "QskQuick.h"
@ -13,6 +14,13 @@
namespace namespace
{ {
inline QskLayoutMetrics qskItemMetrics(
QQuickItem* item, Qt::Orientation orientation, qreal constraint )
{
const QskItemLayoutElement layoutItem( item );
return layoutItem.metrics( orientation, constraint );
}
class Element class Element
{ {
public: public:
@ -331,6 +339,30 @@ bool QskLinearLayoutEngine::clear()
return true; return true;
} }
QskSizePolicy QskLinearLayoutEngine::sizePolicyAt( int index ) const
{
return qskSizePolicy( itemAt( index ) );
}
int QskLinearLayoutEngine::indexOf( const QQuickItem* item ) const
{
if ( item )
{
/*
indexOf is often called after inserting an item to
set additinal properties. So we search in reverse order
*/
for ( int i = count() - 1; i >= 0; --i )
{
if ( itemAt( i ) == item )
return i;
}
}
return -1;
}
QQuickItem* QskLinearLayoutEngine::itemAt( int index ) const QQuickItem* QskLinearLayoutEngine::itemAt( int index ) const
{ {
if ( const auto element = m_data->elementAt( index ) ) if ( const auto element = m_data->elementAt( index ) )
@ -362,7 +394,12 @@ void QskLinearLayoutEngine::layoutItems()
if ( qskIsAdjustableByLayout( item ) ) if ( qskIsAdjustableByLayout( item ) )
{ {
const QRect grid( col, row, 1, 1 ); const QRect grid( col, row, 1, 1 );
layoutItem( item, grid );
const QskItemLayoutElement layoutElement( item );
const auto rect = geometryAt( &layoutElement, grid );
if ( rect.size().isValid() )
qskSetItemGeometry( item, rect );
} }
} }
@ -445,7 +482,7 @@ void QskLinearLayoutEngine::setupChain( Qt::Orientation orientation,
auto cell = element.cell( orientation, isLayoutOrientation ); auto cell = element.cell( orientation, isLayoutOrientation );
if ( element.item() ) if ( element.item() )
cell.metrics = layoutMetrics( element.item(), orientation, constraint ); cell.metrics = qskItemMetrics( element.item(), orientation, constraint );
chain.expandCell( index2, cell ); chain.expandCell( index2, cell );

View File

@ -39,7 +39,9 @@ class QskLinearLayoutEngine : public QskLayoutEngine2D
bool removeAt( int index ); bool removeAt( int index );
bool clear(); bool clear();
QQuickItem* itemAt( int index ) const override final; int indexOf( const QQuickItem* ) const;
QQuickItem* itemAt( int index ) const;
qreal spacerAt( int index ) const; qreal spacerAt( int index ) const;
bool setStretchFactorAt( int index, int stretchFactor ); bool setStretchFactorAt( int index, int stretchFactor );
@ -48,6 +50,7 @@ class QskLinearLayoutEngine : public QskLayoutEngine2D
private: private:
Q_DISABLE_COPY(QskLinearLayoutEngine) Q_DISABLE_COPY(QskLinearLayoutEngine)
QskSizePolicy sizePolicyAt( int index ) const override final;
void layoutItems() override; void layoutItems() override;
int effectiveCount() const; int effectiveCount() const;

View File

@ -317,6 +317,7 @@ HEADERS += \
layouts/QskIndexedLayoutBox.h \ layouts/QskIndexedLayoutBox.h \
layouts/QskLayoutChain.h \ layouts/QskLayoutChain.h \
layouts/QskLayoutEngine2D.h \ layouts/QskLayoutEngine2D.h \
layouts/QskLayoutElement.h \
layouts/QskLayoutMetrics.h \ layouts/QskLayoutMetrics.h \
layouts/QskLinearBox.h \ layouts/QskLinearBox.h \
layouts/QskLinearLayoutEngine.h \ layouts/QskLinearLayoutEngine.h \
@ -329,6 +330,7 @@ SOURCES += \
layouts/QskIndexedLayoutBox.cpp \ layouts/QskIndexedLayoutBox.cpp \
layouts/QskLayoutChain.cpp \ layouts/QskLayoutChain.cpp \
layouts/QskLayoutEngine2D.cpp \ layouts/QskLayoutEngine2D.cpp \
layouts/QskLayoutElement.cpp \
layouts/QskLayoutMetrics.cpp \ layouts/QskLayoutMetrics.cpp \
layouts/QskLinearBox.cpp \ layouts/QskLinearBox.cpp \
layouts/QskLinearLayoutEngine.cpp \ layouts/QskLinearLayoutEngine.cpp \