qskinny/src/layouts/QskLayoutElement.cpp
2022-08-06 15:41:32 +02:00

386 lines
11 KiB
C++

/******************************************************************************
* 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 );
}