QskLayoutElement introduced
This commit is contained in:
parent
bc5510f7ef
commit
9daf934426
@ -6,6 +6,7 @@
|
||||
#include "QskQuick.h"
|
||||
#include "QskControl.h"
|
||||
#include "QskFunctions.h"
|
||||
#include "QskLayoutElement.h"
|
||||
#include <qquickitem.h>
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
@ -419,221 +420,23 @@ QSizeF qskEffectiveSizeHint( const QQuickItem* item,
|
||||
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,
|
||||
Qt::SizeHint which, const QSizeF& constraint )
|
||||
{
|
||||
if ( item == nullptr )
|
||||
return QSizeF( 0, 0 );
|
||||
|
||||
if ( constraint.isValid() )
|
||||
return 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;
|
||||
const QskItemLayoutElement layoutElement( item );
|
||||
return layoutElement.sizeConstraint( which, constraint );
|
||||
}
|
||||
|
||||
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 );
|
||||
|
||||
QSizeF min, max;
|
||||
|
||||
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 );
|
||||
const QskItemLayoutElement layoutElement( item );
|
||||
return layoutElement.constrainedSize( size );
|
||||
}
|
||||
|
||||
QRectF qskConstrainedItemRect( const QQuickItem* item,
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "QskGridLayoutEngine.h"
|
||||
#include "QskLayoutMetrics.h"
|
||||
#include "QskLayoutChain.h"
|
||||
#include "QskLayoutElement.h"
|
||||
#include "QskSizePolicy.h"
|
||||
#include "QskQuick.h"
|
||||
|
||||
@ -162,6 +163,13 @@ namespace
|
||||
|
||||
namespace
|
||||
{
|
||||
inline QskLayoutMetrics qskItemMetrics(
|
||||
QQuickItem* item, Qt::Orientation orientation, qreal constraint )
|
||||
{
|
||||
const QskItemLayoutElement layoutItem( item );
|
||||
return layoutItem.metrics( orientation, constraint );
|
||||
}
|
||||
|
||||
class Element
|
||||
{
|
||||
public:
|
||||
@ -543,6 +551,30 @@ QQuickItem* QskGridLayoutEngine::itemAt( int index ) const
|
||||
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
|
||||
{
|
||||
if ( const auto element = m_data->elementAt( index ) )
|
||||
@ -601,7 +633,12 @@ void QskGridLayoutEngine::layoutItems()
|
||||
if ( qskIsAdjustableByLayout( item ) )
|
||||
{
|
||||
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() );
|
||||
|
||||
auto cell = element.cell( orientation );
|
||||
|
||||
if ( element.item() )
|
||||
cell.metrics = layoutMetrics( element.item(), orientation, constraint );
|
||||
cell.metrics = qskItemMetrics( element.item(), orientation, constraint );
|
||||
|
||||
chain.expandCell( grid.top(), cell );
|
||||
}
|
||||
@ -677,7 +715,7 @@ void QskGridLayoutEngine::setupChain( Qt::Orientation orientation,
|
||||
constraint = qskSegmentLength( constraints, grid.left(), grid.right() );
|
||||
|
||||
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 );
|
||||
}
|
||||
|
@ -39,12 +39,14 @@ class QskGridLayoutEngine : public QskLayoutEngine2D
|
||||
bool removeAt( int index );
|
||||
bool clear();
|
||||
|
||||
QQuickItem* itemAt( int index ) const override final;
|
||||
QQuickItem* itemAt( int index ) const;
|
||||
QSizeF spacerAt( int index ) const;
|
||||
|
||||
QQuickItem* itemAt( int row, int column ) const;
|
||||
int indexAt( int row, int column ) const;
|
||||
|
||||
int indexOf( const QQuickItem* ) const;
|
||||
|
||||
bool setGridAt( int index, const QRect& );
|
||||
QRect gridAt( int index ) const;
|
||||
|
||||
@ -53,6 +55,7 @@ class QskGridLayoutEngine : public QskLayoutEngine2D
|
||||
void transpose();
|
||||
|
||||
private:
|
||||
QskSizePolicy sizePolicyAt( int index ) const override final;
|
||||
void layoutItems() override;
|
||||
int effectiveCount( Qt::Orientation ) const override;
|
||||
|
||||
|
385
src/layouts/QskLayoutElement.cpp
Normal file
385
src/layouts/QskLayoutElement.cpp
Normal 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 );
|
||||
}
|
71
src/layouts/QskLayoutElement.h
Normal file
71
src/layouts/QskLayoutElement.h
Normal 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
|
@ -5,100 +5,11 @@
|
||||
|
||||
#include "QskLayoutEngine2D.h"
|
||||
#include "QskLayoutChain.h"
|
||||
#include "QskLayoutMetrics.h"
|
||||
#include "QskControl.h"
|
||||
#include "QskQuick.h"
|
||||
#include "QskLayoutElement.h"
|
||||
#include "QskFunctions.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
|
||||
{
|
||||
class LayoutData
|
||||
@ -289,25 +200,6 @@ bool QskLayoutEngine2D::setExtraSpacingAt( Qt::Edges edges )
|
||||
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
|
||||
{
|
||||
return static_cast< Qt::Edges >( m_data->extraSpacingAt );
|
||||
@ -343,26 +235,30 @@ void QskLayoutEngine2D::setGeometries( const QRectF& rect )
|
||||
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 )
|
||||
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 )
|
||||
if ( layoutData && element )
|
||||
{
|
||||
const auto& r = layoutData->rect;
|
||||
rect.moveRight( r.right() - ( rect.left() - r.left() ) );
|
||||
auto rect = layoutData->geometryAt( grid );
|
||||
|
||||
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
|
||||
@ -421,7 +317,7 @@ QSizeF QskLayoutEngine2D::sizeHint(
|
||||
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
|
||||
results from unconstrained requests
|
||||
*/
|
||||
@ -477,54 +373,6 @@ QSizeF QskLayoutEngine2D::sizeHint(
|
||||
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
|
||||
{
|
||||
setupChain( orientation, QskLayoutChain::Segments() );
|
||||
@ -631,7 +479,7 @@ QskSizePolicy::ConstraintType QskLayoutEngine2D::constraintType() const
|
||||
|
||||
for ( int i = 0; i < count(); i++ )
|
||||
{
|
||||
const auto type = qskSizePolicy( itemAt( i ) ).constraintType();
|
||||
const auto type = sizePolicyAt( i ).constraintType();
|
||||
|
||||
if ( type != QskSizePolicy::Unconstrained )
|
||||
{
|
||||
|
@ -13,8 +13,7 @@
|
||||
#include <qnamespace.h>
|
||||
#include <memory>
|
||||
|
||||
class QQuickItem;
|
||||
class QskLayoutMetrics;
|
||||
class QskLayoutElement;
|
||||
|
||||
class QskLayoutEngine2D
|
||||
{
|
||||
@ -24,10 +23,6 @@ class QskLayoutEngine2D
|
||||
|
||||
virtual int count() const = 0;
|
||||
|
||||
virtual QQuickItem* itemAt( int index ) const = 0;
|
||||
|
||||
int indexOf( const QQuickItem* ) const;
|
||||
|
||||
int rowCount() const;
|
||||
int columnCount() const;
|
||||
|
||||
@ -55,10 +50,7 @@ class QskLayoutEngine2D
|
||||
void setGeometries( const QRectF& );
|
||||
|
||||
protected:
|
||||
|
||||
void layoutItem( QQuickItem*, const QRect& grid ) const;
|
||||
QskLayoutMetrics layoutMetrics( const QQuickItem*,
|
||||
Qt::Orientation, qreal constraint ) const;
|
||||
QRectF geometryAt( const QskLayoutElement*, const QRect& grid ) const;
|
||||
|
||||
enum
|
||||
{
|
||||
@ -79,6 +71,8 @@ class QskLayoutEngine2D
|
||||
virtual void invalidateElementCache() = 0;
|
||||
QskSizePolicy::ConstraintType constraintType() const;
|
||||
|
||||
virtual QskSizePolicy sizePolicyAt( int index ) const = 0;
|
||||
|
||||
void setupChain( Qt::Orientation ) const;
|
||||
void setupChain( Qt::Orientation, const QskLayoutChain::Segments& ) const;
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "QskLinearLayoutEngine.h"
|
||||
#include "QskLayoutMetrics.h"
|
||||
#include "QskLayoutChain.h"
|
||||
#include "QskLayoutElement.h"
|
||||
#include "QskSizePolicy.h"
|
||||
#include "QskQuick.h"
|
||||
|
||||
@ -13,6 +14,13 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
inline QskLayoutMetrics qskItemMetrics(
|
||||
QQuickItem* item, Qt::Orientation orientation, qreal constraint )
|
||||
{
|
||||
const QskItemLayoutElement layoutItem( item );
|
||||
return layoutItem.metrics( orientation, constraint );
|
||||
}
|
||||
|
||||
class Element
|
||||
{
|
||||
public:
|
||||
@ -331,6 +339,30 @@ bool QskLinearLayoutEngine::clear()
|
||||
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
|
||||
{
|
||||
if ( const auto element = m_data->elementAt( index ) )
|
||||
@ -362,7 +394,12 @@ void QskLinearLayoutEngine::layoutItems()
|
||||
if ( qskIsAdjustableByLayout( item ) )
|
||||
{
|
||||
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 );
|
||||
|
||||
if ( element.item() )
|
||||
cell.metrics = layoutMetrics( element.item(), orientation, constraint );
|
||||
cell.metrics = qskItemMetrics( element.item(), orientation, constraint );
|
||||
|
||||
chain.expandCell( index2, cell );
|
||||
|
||||
|
@ -39,7 +39,9 @@ class QskLinearLayoutEngine : public QskLayoutEngine2D
|
||||
bool removeAt( int index );
|
||||
bool clear();
|
||||
|
||||
QQuickItem* itemAt( int index ) const override final;
|
||||
int indexOf( const QQuickItem* ) const;
|
||||
|
||||
QQuickItem* itemAt( int index ) const;
|
||||
qreal spacerAt( int index ) const;
|
||||
|
||||
bool setStretchFactorAt( int index, int stretchFactor );
|
||||
@ -48,6 +50,7 @@ class QskLinearLayoutEngine : public QskLayoutEngine2D
|
||||
private:
|
||||
Q_DISABLE_COPY(QskLinearLayoutEngine)
|
||||
|
||||
QskSizePolicy sizePolicyAt( int index ) const override final;
|
||||
void layoutItems() override;
|
||||
|
||||
int effectiveCount() const;
|
||||
|
@ -317,6 +317,7 @@ HEADERS += \
|
||||
layouts/QskIndexedLayoutBox.h \
|
||||
layouts/QskLayoutChain.h \
|
||||
layouts/QskLayoutEngine2D.h \
|
||||
layouts/QskLayoutElement.h \
|
||||
layouts/QskLayoutMetrics.h \
|
||||
layouts/QskLinearBox.h \
|
||||
layouts/QskLinearLayoutEngine.h \
|
||||
@ -329,6 +330,7 @@ SOURCES += \
|
||||
layouts/QskIndexedLayoutBox.cpp \
|
||||
layouts/QskLayoutChain.cpp \
|
||||
layouts/QskLayoutEngine2D.cpp \
|
||||
layouts/QskLayoutElement.cpp \
|
||||
layouts/QskLayoutMetrics.cpp \
|
||||
layouts/QskLinearBox.cpp \
|
||||
layouts/QskLinearLayoutEngine.cpp \
|
||||
|
Loading…
x
Reference in New Issue
Block a user