2019-07-01 14:45:25 +02:00
|
|
|
/******************************************************************************
|
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2019-06-19 14:08:45 +02:00
|
|
|
#include "QskLinearLayoutEngine.h"
|
|
|
|
#include "QskLayoutHint.h"
|
|
|
|
#include "QskLayoutConstraint.h"
|
2019-07-01 14:45:25 +02:00
|
|
|
#include "QskLayoutChain.h"
|
2019-06-19 14:08:45 +02:00
|
|
|
#include "QskSizePolicy.h"
|
|
|
|
#include "QskQuick.h"
|
|
|
|
|
|
|
|
#include <qvector.h>
|
|
|
|
|
|
|
|
static constexpr qreal qskDefaultSpacing()
|
|
|
|
{
|
|
|
|
// should be a skin hint
|
|
|
|
return 5.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
class CellGeometries
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void invalidate()
|
|
|
|
{
|
|
|
|
boundingSize = QSizeF();
|
|
|
|
rows.clear();
|
|
|
|
columns.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
QRectF geometryAt( int row, int col ) const
|
|
|
|
{
|
|
|
|
return QRectF(
|
|
|
|
columns[ col ].start, rows[ row ].start,
|
|
|
|
columns[ col ].length, rows[ row ].length );
|
|
|
|
}
|
|
|
|
|
|
|
|
QSizeF boundingSize;
|
|
|
|
|
2019-07-01 14:45:25 +02:00
|
|
|
QVector< QskLayoutChain::Range > rows;
|
|
|
|
QVector< QskLayoutChain::Range > columns;
|
2019-06-19 14:08:45 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
class EntryData
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
EntryData( QQuickItem* item );
|
|
|
|
EntryData( qreal spacing );
|
|
|
|
|
|
|
|
EntryData& operator=( const EntryData& );
|
|
|
|
|
|
|
|
bool isIgnored() const;
|
|
|
|
|
|
|
|
qreal spacer() const { return m_isSpacer ? m_spacer : -1.0; }
|
|
|
|
QQuickItem* item() const { return m_isSpacer ? nullptr : m_item; }
|
|
|
|
|
|
|
|
inline Qt::Alignment alignment() const
|
|
|
|
{ return static_cast< Qt::Alignment >( m_alignment ); }
|
|
|
|
inline void setAlignment( Qt::Alignment alignment ) { m_alignment = alignment; }
|
|
|
|
|
|
|
|
inline int stretch() const { return m_stretch; }
|
|
|
|
inline void setStretch( int stretch ) { m_stretch = stretch; }
|
|
|
|
|
|
|
|
bool retainSizeWhenHidden() const { return m_retainSizeWhenHidden; }
|
|
|
|
void setRetainSizeWhenHidden( bool on ) { m_retainSizeWhenHidden = on; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
union
|
|
|
|
{
|
|
|
|
QQuickItem* m_item;
|
|
|
|
qreal m_spacer;
|
|
|
|
};
|
|
|
|
|
|
|
|
int m_stretch;
|
|
|
|
|
|
|
|
unsigned int m_alignment : 8;
|
|
|
|
bool m_isSpacer : 1;
|
|
|
|
bool m_retainSizeWhenHidden : 1;
|
|
|
|
};
|
|
|
|
|
|
|
|
class EntryTable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
EntryTable( Qt::Orientation, uint dimension );
|
|
|
|
|
|
|
|
bool setOrientation( Qt::Orientation orientation );
|
|
|
|
Qt::Orientation orientation() const;
|
|
|
|
|
|
|
|
bool setDimension( uint dimension );
|
|
|
|
uint dimension() const;
|
|
|
|
|
|
|
|
bool setDefaultAlignment( Qt::Alignment );
|
|
|
|
Qt::Alignment defaultAlignment() const;
|
|
|
|
|
|
|
|
Qt::Alignment effectiveAlignmentAt( int index ) const;
|
|
|
|
|
|
|
|
void insertItem( int index, QQuickItem* );
|
|
|
|
void insertSpacer( int index, qreal spacing );
|
|
|
|
|
|
|
|
QQuickItem* itemAt( int index ) const;
|
|
|
|
int spacerAt( int index ) const;
|
|
|
|
|
|
|
|
bool removeAt( int index );
|
2019-07-13 10:36:12 +02:00
|
|
|
bool clear();
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
bool isIgnoredAt( int index ) const;
|
|
|
|
|
|
|
|
bool setAlignmentAt( int index, Qt::Alignment );
|
|
|
|
Qt::Alignment alignmentAt( int index ) const;
|
|
|
|
|
|
|
|
bool setStretchFactorAt( int index, int stretchFactor );
|
|
|
|
int stretchFactorAt( int index ) const;
|
|
|
|
|
|
|
|
bool setRetainSizeWhenHiddenAt( int index, bool on );
|
|
|
|
bool retainSizeWhenHiddenAt( int index ) const;
|
|
|
|
|
|
|
|
inline int count() const { return m_entries.size(); }
|
|
|
|
|
|
|
|
int effectiveCount() const;
|
|
|
|
int effectiveCount( Qt::Orientation orientation ) const;
|
|
|
|
|
2019-07-12 15:26:55 +02:00
|
|
|
void updateLayoutChain( Qt::Orientation,
|
2019-07-01 14:45:25 +02:00
|
|
|
const QVector< QskLayoutChain::Range >& constraints,
|
|
|
|
QskLayoutChain& ) const;
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
QskLayoutConstraint::Type constraintType() const;
|
|
|
|
|
|
|
|
void invalidate();
|
|
|
|
|
|
|
|
private:
|
2019-07-01 14:45:25 +02:00
|
|
|
QskLayoutChain::Cell cell( const EntryData&,
|
2019-06-19 14:08:45 +02:00
|
|
|
Qt::Orientation, qreal constraint ) const;
|
|
|
|
|
|
|
|
inline EntryData* entryAt( int index ) const
|
|
|
|
{
|
|
|
|
if ( index < 0 || index >= count() )
|
|
|
|
{
|
|
|
|
// qWarning, TODO ...
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return const_cast< EntryData* >( &m_entries[index] );
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector< EntryData > m_entries;
|
|
|
|
|
|
|
|
uint m_dimension;
|
|
|
|
mutable int m_sumIgnored : 19;
|
2019-07-01 14:45:25 +02:00
|
|
|
mutable int m_constraintType : 3;
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
unsigned int m_defaultAlignment : 8;
|
|
|
|
unsigned int m_orientation : 2;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
EntryData::EntryData( QQuickItem* item )
|
|
|
|
: m_item( item )
|
|
|
|
, m_stretch( -1 )
|
|
|
|
, m_alignment( 0 )
|
|
|
|
, m_isSpacer( false )
|
|
|
|
, m_retainSizeWhenHidden( false )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
EntryData::EntryData( qreal spacing )
|
|
|
|
: m_spacer( spacing )
|
|
|
|
, m_stretch( -1 )
|
|
|
|
, m_alignment( 0 )
|
|
|
|
, m_isSpacer( true )
|
|
|
|
, m_retainSizeWhenHidden( false )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
EntryData& EntryData::operator=( const EntryData& other )
|
|
|
|
{
|
|
|
|
m_isSpacer = other.m_isSpacer;
|
|
|
|
|
|
|
|
if ( other.m_isSpacer )
|
|
|
|
m_spacer = other.m_spacer;
|
|
|
|
else
|
|
|
|
m_item = other.m_item;
|
|
|
|
|
|
|
|
m_stretch = other.m_stretch;
|
|
|
|
m_alignment = other.m_alignment;
|
|
|
|
m_retainSizeWhenHidden = other.m_retainSizeWhenHidden;
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EntryData::isIgnored() const
|
|
|
|
{
|
|
|
|
if ( !m_isSpacer && !m_retainSizeWhenHidden )
|
|
|
|
return !qskIsVisibleToParent( m_item );
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
EntryTable::EntryTable( Qt::Orientation orientation, uint dimension )
|
|
|
|
: m_dimension( dimension )
|
|
|
|
, m_sumIgnored( -1 )
|
2019-07-01 14:45:25 +02:00
|
|
|
, m_constraintType( -1 )
|
2019-06-19 14:08:45 +02:00
|
|
|
, m_defaultAlignment( Qt::AlignLeft | Qt::AlignVCenter )
|
|
|
|
, m_orientation( orientation )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EntryTable::setOrientation( Qt::Orientation orientation )
|
|
|
|
{
|
|
|
|
if ( m_orientation != orientation )
|
|
|
|
{
|
|
|
|
m_orientation = orientation;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Qt::Orientation EntryTable::orientation() const
|
|
|
|
{
|
|
|
|
return static_cast< Qt::Orientation >( m_orientation );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EntryTable::setDimension( uint dimension )
|
|
|
|
{
|
|
|
|
if ( m_dimension != dimension )
|
|
|
|
{
|
|
|
|
m_dimension = dimension;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint EntryTable::dimension() const
|
|
|
|
{
|
|
|
|
return m_dimension;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EntryTable::setDefaultAlignment( Qt::Alignment alignment )
|
|
|
|
{
|
|
|
|
if ( defaultAlignment() != alignment )
|
|
|
|
{
|
|
|
|
m_defaultAlignment = alignment;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Qt::Alignment EntryTable::defaultAlignment() const
|
|
|
|
{
|
|
|
|
return static_cast< Qt::Alignment >( m_defaultAlignment );
|
|
|
|
}
|
|
|
|
|
|
|
|
Qt::Alignment EntryTable::effectiveAlignmentAt( int index ) const
|
|
|
|
{
|
|
|
|
Qt::Alignment alignment;
|
|
|
|
|
|
|
|
if ( const auto entry = entryAt( index ) )
|
|
|
|
alignment = entry->alignment();
|
|
|
|
|
|
|
|
if ( !( alignment & Qt::AlignVertical_Mask ) )
|
|
|
|
alignment |= ( defaultAlignment() & Qt::AlignVertical_Mask );
|
|
|
|
|
|
|
|
if ( !( alignment & Qt::AlignHorizontal_Mask ) )
|
|
|
|
alignment |= ( defaultAlignment() & Qt::AlignHorizontal_Mask );
|
|
|
|
|
|
|
|
return alignment;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EntryTable::isIgnoredAt( int index ) const
|
|
|
|
{
|
|
|
|
if ( index >= 0 && index < count() )
|
|
|
|
return m_entries[index].isIgnored();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryTable::insertItem( int index, QQuickItem* item )
|
|
|
|
{
|
|
|
|
if ( index < 0 || index > count() )
|
|
|
|
m_entries.emplace_back( item );
|
|
|
|
else
|
|
|
|
m_entries.emplace( m_entries.begin() + index, item );
|
|
|
|
|
|
|
|
invalidate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryTable::insertSpacer( int index, qreal spacing )
|
|
|
|
{
|
|
|
|
spacing = qMax( spacing, static_cast< qreal >( 0.0 ) );
|
|
|
|
|
|
|
|
if ( index < 0 || index > count() )
|
|
|
|
m_entries.emplace_back( spacing );
|
|
|
|
else
|
|
|
|
m_entries.emplace( m_entries.begin() + index, spacing );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EntryTable::removeAt( int index )
|
|
|
|
{
|
2019-07-13 10:36:12 +02:00
|
|
|
auto entry = entryAt( index );
|
|
|
|
if ( entry == nullptr )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if ( entry->isIgnored() )
|
|
|
|
m_sumIgnored--;
|
|
|
|
|
|
|
|
const auto itemType = QskLayoutConstraint::constraintType( entry->item() );
|
|
|
|
if ( itemType > QskLayoutConstraint::Unconstrained )
|
|
|
|
m_constraintType = -1;
|
|
|
|
|
|
|
|
m_entries.erase( m_entries.begin() + index );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EntryTable::clear()
|
|
|
|
{
|
|
|
|
if ( count() > 0 )
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
2019-07-13 10:36:12 +02:00
|
|
|
m_entries.clear();
|
2019-06-19 14:08:45 +02:00
|
|
|
invalidate();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
QQuickItem* EntryTable::itemAt( int index ) const
|
|
|
|
{
|
|
|
|
if ( const auto entry = entryAt( index ) )
|
|
|
|
return entry->item();
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
int EntryTable::spacerAt( int index ) const
|
|
|
|
{
|
|
|
|
if ( const auto entry = entryAt( index ) )
|
|
|
|
return entry->spacer();
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EntryTable::setAlignmentAt( int index, Qt::Alignment alignment )
|
|
|
|
{
|
|
|
|
if ( auto entry = entryAt( index ) )
|
|
|
|
{
|
|
|
|
if ( alignment != entry->alignment() )
|
|
|
|
entry->setAlignment( alignment );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Qt::Alignment EntryTable::alignmentAt( int index ) const
|
|
|
|
{
|
|
|
|
if ( const auto entry = entryAt( index ) )
|
|
|
|
return entry->alignment();
|
|
|
|
|
|
|
|
return Qt::Alignment();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EntryTable::setStretchFactorAt( int index, int stretchFactor )
|
|
|
|
{
|
|
|
|
if ( auto entry = entryAt( index ) )
|
|
|
|
{
|
|
|
|
if ( stretchFactor < 0 )
|
|
|
|
stretchFactor = -1;
|
|
|
|
|
|
|
|
if ( entry->stretch() != stretchFactor )
|
|
|
|
{
|
|
|
|
entry->setStretch( stretchFactor );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int EntryTable::stretchFactorAt( int index ) const
|
|
|
|
{
|
|
|
|
if ( const auto entry = entryAt( index ) )
|
|
|
|
return entry->stretch();
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EntryTable::setRetainSizeWhenHiddenAt( int index, bool on )
|
|
|
|
{
|
|
|
|
if ( auto entry = entryAt( index ) )
|
|
|
|
{
|
|
|
|
if ( on != entry->retainSizeWhenHidden() )
|
|
|
|
{
|
|
|
|
const bool isIgnored = entry->isIgnored();
|
|
|
|
|
|
|
|
entry->setRetainSizeWhenHidden( on );
|
|
|
|
|
|
|
|
if ( isIgnored != entry->isIgnored() )
|
|
|
|
{
|
|
|
|
if ( m_sumIgnored >= 0 )
|
|
|
|
m_sumIgnored += on ? 1 : -1;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EntryTable::retainSizeWhenHiddenAt( int index ) const
|
|
|
|
{
|
|
|
|
if ( const auto entry = entryAt( index ) )
|
|
|
|
return entry->retainSizeWhenHidden();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryTable::invalidate()
|
|
|
|
{
|
|
|
|
m_sumIgnored = -1;
|
2019-07-01 14:45:25 +02:00
|
|
|
m_constraintType = -1;
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int EntryTable::effectiveCount() const
|
|
|
|
{
|
|
|
|
if ( m_sumIgnored < 0 )
|
|
|
|
{
|
|
|
|
m_sumIgnored = 0;
|
|
|
|
|
|
|
|
for ( const auto& entry : m_entries )
|
|
|
|
{
|
|
|
|
if ( entry.isIgnored() )
|
|
|
|
m_sumIgnored++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_entries.size() - m_sumIgnored;
|
|
|
|
}
|
|
|
|
|
|
|
|
int EntryTable::effectiveCount( Qt::Orientation orientation ) const
|
|
|
|
{
|
|
|
|
const uint cellCount = effectiveCount();
|
|
|
|
|
|
|
|
if ( orientation == m_orientation )
|
|
|
|
{
|
|
|
|
return qMin( cellCount, m_dimension );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int count = cellCount / m_dimension;
|
|
|
|
if ( cellCount % m_dimension )
|
|
|
|
count++;
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QskLayoutConstraint::Type EntryTable::constraintType() const
|
|
|
|
{
|
2019-07-01 14:45:25 +02:00
|
|
|
if ( m_constraintType < 0 )
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
2019-07-01 14:45:25 +02:00
|
|
|
m_constraintType = QskLayoutConstraint::Unconstrained;
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
for ( const auto& entry : m_entries )
|
|
|
|
{
|
2019-07-13 10:36:12 +02:00
|
|
|
const auto itemType = QskLayoutConstraint::constraintType( entry.item() );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
2019-07-13 10:36:12 +02:00
|
|
|
if ( itemType != QskLayoutConstraint::Unconstrained )
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
2019-07-01 14:45:25 +02:00
|
|
|
if ( m_constraintType == QskLayoutConstraint::Unconstrained )
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
2019-07-13 10:36:12 +02:00
|
|
|
m_constraintType = itemType;
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
2019-07-13 10:36:12 +02:00
|
|
|
else if ( m_constraintType != itemType )
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
|
|
|
qWarning( "QskLinearLayoutEngine: conflicting constraints");
|
2019-07-01 14:45:25 +02:00
|
|
|
m_constraintType = QskLayoutConstraint::Unconstrained;
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-01 14:45:25 +02:00
|
|
|
return static_cast< QskLayoutConstraint::Type >( m_constraintType );
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
2019-07-01 14:45:25 +02:00
|
|
|
QskLayoutChain::Cell EntryTable::cell( const EntryData& entry,
|
2019-06-19 14:08:45 +02:00
|
|
|
Qt::Orientation orientation, qreal constraint ) const
|
|
|
|
{
|
2019-07-12 15:24:06 +02:00
|
|
|
QskLayoutChain::Cell cell;
|
|
|
|
cell.canGrow = true;
|
2019-07-13 10:03:04 +02:00
|
|
|
cell.isValid = true;
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
if ( const auto item = entry.item() )
|
|
|
|
{
|
2019-07-12 15:24:06 +02:00
|
|
|
cell.hint = QskLayoutConstraint::layoutHint( item, orientation, constraint );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
2019-07-12 15:24:06 +02:00
|
|
|
const auto policy = QskLayoutConstraint::sizePolicy( item ).policy( orientation );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
if ( orientation == m_orientation )
|
|
|
|
{
|
|
|
|
if ( entry.stretch() < 0 )
|
2019-07-12 15:24:06 +02:00
|
|
|
cell.stretch = ( policy & QskSizePolicy::ExpandFlag ) ? 1 : 0;
|
2019-06-19 14:08:45 +02:00
|
|
|
else
|
2019-07-12 15:24:06 +02:00
|
|
|
cell.stretch = entry.stretch();
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
2019-07-12 15:24:06 +02:00
|
|
|
cell.canGrow = policy & QskSizePolicy::GrowFlag;
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( orientation == m_orientation )
|
|
|
|
{
|
2019-07-12 15:24:06 +02:00
|
|
|
cell.hint.setMinimum( entry.spacer() );
|
|
|
|
cell.hint.setPreferred( entry.spacer() );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
2019-07-12 15:24:06 +02:00
|
|
|
if ( entry.stretch() <= 0 )
|
|
|
|
cell.hint.setMaximum( entry.spacer() );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
2019-07-12 15:24:06 +02:00
|
|
|
cell.stretch = qMax( entry.stretch(), 0 );
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-01 14:45:25 +02:00
|
|
|
return cell;
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
2019-07-12 15:26:55 +02:00
|
|
|
void EntryTable::updateLayoutChain( Qt::Orientation orientation,
|
2019-07-01 14:45:25 +02:00
|
|
|
const QVector< QskLayoutChain::Range >& constraints,
|
|
|
|
QskLayoutChain& chain ) const
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
|
|
|
const auto count = effectiveCount( orientation );
|
|
|
|
const qreal constraint =
|
|
|
|
constraints.isEmpty() ? -1.0 : constraints.last().end();
|
|
|
|
|
2019-07-01 14:45:25 +02:00
|
|
|
if ( ( chain.constraint() == constraint )
|
|
|
|
&& ( chain.count() == count ) )
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
|
|
|
return; // already up to date
|
|
|
|
}
|
|
|
|
|
2019-07-01 14:45:25 +02:00
|
|
|
chain.reset( count, constraint );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
uint index1 = 0;
|
|
|
|
uint index2 = 0;
|
|
|
|
|
|
|
|
for ( const auto& entry : m_entries )
|
|
|
|
{
|
|
|
|
if ( entry.isIgnored() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const qreal cellConstraint =
|
|
|
|
constraints.isEmpty() ? -1.0 : constraints[index1].length;
|
|
|
|
|
2019-07-01 14:45:25 +02:00
|
|
|
const auto cell = this->cell( entry, orientation, cellConstraint );
|
2019-07-09 14:52:43 +02:00
|
|
|
chain.expandTo( index2, cell );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
if ( m_orientation != orientation )
|
|
|
|
{
|
|
|
|
if ( ++index1 == m_dimension )
|
|
|
|
{
|
|
|
|
index1 = 0;
|
|
|
|
index2++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( ++index2 == m_dimension )
|
|
|
|
{
|
|
|
|
index2 = 0;
|
|
|
|
index1++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-01 14:45:25 +02:00
|
|
|
chain.finish();
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ---------
|
|
|
|
|
2019-07-12 15:26:55 +02:00
|
|
|
static inline void qskUpdateLayoutChain( Qt::Orientation orientation,
|
2019-07-01 14:45:25 +02:00
|
|
|
const QVector< QskLayoutChain::Range >& constraints,
|
|
|
|
const EntryTable& entryTable, QskLayoutChain& chain )
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
2019-07-12 15:26:55 +02:00
|
|
|
entryTable.updateLayoutChain( orientation, constraints, chain );
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
2019-07-12 15:26:55 +02:00
|
|
|
static inline void qskUpdateLayoutChain( Qt::Orientation orientation,
|
2019-07-01 14:45:25 +02:00
|
|
|
const EntryTable& entryTable, QskLayoutChain& chain )
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
2019-07-01 14:45:25 +02:00
|
|
|
const QVector< QskLayoutChain::Range > constraints;
|
2019-07-12 15:26:55 +02:00
|
|
|
entryTable.updateLayoutChain( orientation, constraints, chain );
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
class QskLinearLayoutEngine::PrivateData
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
PrivateData( Qt::Orientation orientation, uint dimension )
|
|
|
|
: entryTable( orientation, dimension )
|
|
|
|
, blockInvalidate( false )
|
|
|
|
{
|
2019-07-01 14:45:25 +02:00
|
|
|
rowChain.setSpacing( qskDefaultSpacing() );
|
|
|
|
colChain.setSpacing( qskDefaultSpacing() );
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
EntryTable entryTable;
|
|
|
|
|
2019-07-01 14:45:25 +02:00
|
|
|
QskLayoutChain colChain;
|
|
|
|
QskLayoutChain rowChain;
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
CellGeometries geometries;
|
|
|
|
|
2019-07-13 11:01:48 +02:00
|
|
|
Qt::LayoutDirection visualDirection = Qt::LeftToRight;
|
|
|
|
Qt::Edges extraSpacingAt;
|
|
|
|
|
2019-06-19 14:08:45 +02:00
|
|
|
/*
|
|
|
|
Some weired controls do lazy updates inside of their sizeHint calculation
|
|
|
|
that lead to LayoutRequest events. While being in the process of
|
|
|
|
updating the tables we can't - and don't need to - handle invalidations
|
|
|
|
because of them.
|
|
|
|
*/
|
|
|
|
bool blockInvalidate : 1;
|
|
|
|
};
|
|
|
|
|
|
|
|
QskLinearLayoutEngine::QskLinearLayoutEngine( Qt::Orientation orientation, uint dimension )
|
|
|
|
: m_data( new PrivateData( orientation, dimension ) )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QskLinearLayoutEngine::~QskLinearLayoutEngine()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-07-12 15:37:42 +02:00
|
|
|
bool QskLinearLayoutEngine::setOrientation( Qt::Orientation orientation )
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
2019-07-12 15:37:42 +02:00
|
|
|
const bool isModified = m_data->entryTable.setOrientation( orientation );
|
|
|
|
if ( isModified )
|
2019-06-19 14:08:45 +02:00
|
|
|
invalidate( CellCache | LayoutCache );
|
2019-07-12 15:37:42 +02:00
|
|
|
|
|
|
|
return isModified;
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Qt::Orientation QskLinearLayoutEngine::orientation() const
|
|
|
|
{
|
|
|
|
return m_data->entryTable.orientation();
|
|
|
|
}
|
|
|
|
|
2019-07-12 15:37:42 +02:00
|
|
|
bool QskLinearLayoutEngine::setDimension( uint dimension )
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
|
|
|
if ( dimension < 1 )
|
|
|
|
dimension = 1;
|
|
|
|
|
2019-07-12 15:37:42 +02:00
|
|
|
const bool isModified =
|
|
|
|
m_data->entryTable.setDimension( dimension );
|
|
|
|
|
|
|
|
if ( isModified )
|
2019-06-19 14:08:45 +02:00
|
|
|
invalidate( CellCache | LayoutCache );
|
2019-07-12 15:37:42 +02:00
|
|
|
|
|
|
|
return isModified;
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
uint QskLinearLayoutEngine::dimension() const
|
|
|
|
{
|
|
|
|
return m_data->entryTable.dimension();
|
|
|
|
}
|
|
|
|
|
|
|
|
int QskLinearLayoutEngine::count() const
|
|
|
|
{
|
|
|
|
return m_data->entryTable.count();
|
|
|
|
}
|
|
|
|
|
|
|
|
int QskLinearLayoutEngine::rowCount() const
|
|
|
|
{
|
|
|
|
return m_data->entryTable.effectiveCount( Qt::Vertical );
|
|
|
|
}
|
|
|
|
|
|
|
|
int QskLinearLayoutEngine::columnCount() const
|
|
|
|
{
|
|
|
|
return m_data->entryTable.effectiveCount( Qt::Horizontal );
|
|
|
|
}
|
|
|
|
|
2019-07-12 15:37:42 +02:00
|
|
|
bool QskLinearLayoutEngine::setRetainSizeWhenHiddenAt( int index, bool on )
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
2019-07-12 15:37:42 +02:00
|
|
|
const bool isModified =
|
|
|
|
m_data->entryTable.setRetainSizeWhenHiddenAt( index, on );
|
|
|
|
|
|
|
|
if ( isModified )
|
2019-06-19 14:08:45 +02:00
|
|
|
invalidate( CellCache | LayoutCache );
|
2019-07-12 15:37:42 +02:00
|
|
|
|
|
|
|
return isModified;
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool QskLinearLayoutEngine::retainSizeWhenHiddenAt( int index ) const
|
|
|
|
{
|
|
|
|
return m_data->entryTable.retainSizeWhenHiddenAt( index );
|
|
|
|
}
|
|
|
|
|
2019-07-12 15:37:42 +02:00
|
|
|
bool QskLinearLayoutEngine::setStretchFactorAt( int index, int stretchFactor )
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
2019-07-12 15:37:42 +02:00
|
|
|
const bool isModified =
|
|
|
|
m_data->entryTable.setStretchFactorAt( index, stretchFactor );
|
|
|
|
|
|
|
|
if ( isModified )
|
2019-06-19 14:08:45 +02:00
|
|
|
invalidate( CellCache | LayoutCache );
|
2019-07-12 15:37:42 +02:00
|
|
|
|
|
|
|
return isModified;
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int QskLinearLayoutEngine::stretchFactorAt( int index ) const
|
|
|
|
{
|
|
|
|
return m_data->entryTable.stretchFactorAt( index );
|
|
|
|
}
|
|
|
|
|
2019-07-12 15:37:42 +02:00
|
|
|
bool QskLinearLayoutEngine::setAlignmentAt( int index, Qt::Alignment alignment )
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
2019-07-12 15:37:42 +02:00
|
|
|
return m_data->entryTable.setAlignmentAt( index, alignment );
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Qt::Alignment QskLinearLayoutEngine::alignmentAt( int index ) const
|
|
|
|
{
|
|
|
|
return m_data->entryTable.alignmentAt( index );
|
|
|
|
}
|
|
|
|
|
2019-07-12 15:37:42 +02:00
|
|
|
bool QskLinearLayoutEngine::setSpacing( qreal spacing, Qt::Orientations orientations )
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
|
|
|
if ( spacing < 0.0 )
|
|
|
|
spacing = 0.0;
|
|
|
|
|
2019-07-12 15:37:42 +02:00
|
|
|
bool isModified = false;
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
if ( orientations & Qt::Horizontal )
|
2019-07-12 15:37:42 +02:00
|
|
|
isModified |= m_data->colChain.setSpacing( spacing );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
if ( orientations & Qt::Vertical )
|
2019-07-12 15:37:42 +02:00
|
|
|
isModified |= m_data->rowChain.setSpacing( spacing );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
2019-07-12 15:37:42 +02:00
|
|
|
if ( isModified )
|
2019-06-19 14:08:45 +02:00
|
|
|
invalidate( CellCache | LayoutCache );
|
2019-07-12 15:37:42 +02:00
|
|
|
|
|
|
|
return isModified;
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
qreal QskLinearLayoutEngine::spacing( Qt::Orientation orientation ) const
|
|
|
|
{
|
|
|
|
if ( orientation == Qt::Horizontal )
|
2019-07-01 14:45:25 +02:00
|
|
|
return m_data->colChain.spacing();
|
2019-06-19 14:08:45 +02:00
|
|
|
else
|
2019-07-01 14:45:25 +02:00
|
|
|
return m_data->rowChain.spacing();
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
2019-07-12 15:37:42 +02:00
|
|
|
bool QskLinearLayoutEngine::setExtraSpacingAt( Qt::Edges edges )
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
|
|
|
if ( edges == m_data->extraSpacingAt )
|
2019-07-12 15:37:42 +02:00
|
|
|
return false;
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
m_data->extraSpacingAt = edges;
|
|
|
|
|
|
|
|
Qt::Edges colEdges = edges & ~( Qt::TopEdge | Qt::BottomEdge );
|
2019-07-01 14:45:25 +02:00
|
|
|
m_data->colChain.setExtraSpacingAt( colEdges );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
FlowLayoutInfo does not have an orientation, so we always
|
|
|
|
set the position for potential fill spaces using Left/Right.
|
|
|
|
Maybe introducing another enum might be a good idea. TODO ...
|
|
|
|
*/
|
|
|
|
|
|
|
|
Qt::Edges rowEdges;
|
|
|
|
if ( edges & Qt::TopEdge )
|
|
|
|
rowEdges |= Qt::LeftEdge;
|
|
|
|
|
|
|
|
if ( edges & Qt::BottomEdge )
|
|
|
|
rowEdges |= Qt::RightEdge;
|
|
|
|
|
2019-07-01 14:45:25 +02:00
|
|
|
m_data->rowChain.setExtraSpacingAt( rowEdges );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
invalidate( LayoutCache );
|
2019-07-12 15:37:42 +02:00
|
|
|
return true;
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Qt::Edges QskLinearLayoutEngine::extraSpacingAt() const
|
|
|
|
{
|
|
|
|
return m_data->extraSpacingAt;
|
|
|
|
}
|
|
|
|
|
2019-07-12 15:37:42 +02:00
|
|
|
bool QskLinearLayoutEngine::setDefaultAlignment( Qt::Alignment alignment )
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
2019-07-12 15:37:42 +02:00
|
|
|
return m_data->entryTable.setDefaultAlignment( alignment );
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Qt::Alignment QskLinearLayoutEngine::defaultAlignment() const
|
|
|
|
{
|
|
|
|
return m_data->entryTable.defaultAlignment();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskLinearLayoutEngine::insertItem( QQuickItem* item, int index )
|
|
|
|
{
|
|
|
|
m_data->entryTable.insertItem( index, item );
|
|
|
|
invalidate( CellCache | LayoutCache );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskLinearLayoutEngine::addItem( QQuickItem* item )
|
|
|
|
{
|
|
|
|
insertItem( item, -1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskLinearLayoutEngine::insertSpacerAt( int index, qreal spacing )
|
|
|
|
{
|
|
|
|
m_data->entryTable.insertSpacer( index, spacing );
|
|
|
|
invalidate( CellCache | LayoutCache );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskLinearLayoutEngine::addSpacer( qreal spacing )
|
|
|
|
{
|
|
|
|
insertSpacerAt( -1, spacing );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskLinearLayoutEngine::removeAt( int index )
|
|
|
|
{
|
|
|
|
if ( m_data->entryTable.removeAt( index ) )
|
|
|
|
invalidate( CellCache | LayoutCache );
|
|
|
|
}
|
|
|
|
|
2019-07-13 10:36:12 +02:00
|
|
|
void QskLinearLayoutEngine::clear()
|
|
|
|
{
|
|
|
|
if ( m_data->entryTable.clear() )
|
|
|
|
invalidate( CellCache | LayoutCache );
|
|
|
|
}
|
|
|
|
|
2019-06-19 14:08:45 +02:00
|
|
|
QQuickItem* QskLinearLayoutEngine::itemAt( int index ) const
|
|
|
|
{
|
|
|
|
return m_data->entryTable.itemAt( index );
|
|
|
|
}
|
|
|
|
|
|
|
|
int QskLinearLayoutEngine::spacerAt( int index ) const
|
|
|
|
{
|
|
|
|
return m_data->entryTable.spacerAt( index );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskLinearLayoutEngine::invalidate( int what )
|
|
|
|
{
|
|
|
|
if ( m_data->blockInvalidate )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( what & EntryCache )
|
|
|
|
m_data->entryTable.invalidate();
|
|
|
|
|
|
|
|
if ( what & CellCache )
|
|
|
|
{
|
2019-07-01 14:45:25 +02:00
|
|
|
m_data->rowChain.invalidate();
|
|
|
|
m_data->colChain.invalidate();
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( what & LayoutCache )
|
|
|
|
m_data->geometries.invalidate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskLinearLayoutEngine::setGeometries( const QRectF& rect )
|
|
|
|
{
|
2019-07-13 11:01:48 +02:00
|
|
|
if ( m_data->entryTable.effectiveCount() == 0 )
|
2019-06-19 14:08:45 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
if ( m_data->geometries.boundingSize != rect.size() )
|
|
|
|
{
|
|
|
|
m_data->blockInvalidate = true;
|
|
|
|
updateCellGeometries( rect.size() );
|
|
|
|
m_data->blockInvalidate = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
In case we have items that send LayoutRequest events on
|
|
|
|
geometry changes - what doesn't make much sense - we
|
|
|
|
better make a ( implicitely shared ) copy of the geometries.
|
|
|
|
*/
|
|
|
|
const auto geometries = m_data->geometries;
|
|
|
|
|
|
|
|
uint row = 0;
|
|
|
|
uint col = 0;
|
|
|
|
|
|
|
|
const auto& entryTable = m_data->entryTable;
|
|
|
|
|
|
|
|
for ( int i = 0; i < entryTable.count(); i++ )
|
|
|
|
{
|
|
|
|
if ( entryTable.isIgnoredAt( i ) )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ( auto item = entryTable.itemAt( i ) )
|
|
|
|
{
|
|
|
|
QRectF r = geometries.geometryAt( row, col );
|
|
|
|
r.translate( rect.x(), rect.y() );
|
|
|
|
|
|
|
|
const auto alignment = entryTable.effectiveAlignmentAt( i );
|
|
|
|
|
|
|
|
r = QskLayoutConstraint::itemRect( item, r, alignment );
|
|
|
|
|
|
|
|
if ( m_data->visualDirection == Qt::RightToLeft )
|
|
|
|
r.moveRight( rect.right() - ( r.left() - rect.left() ) );
|
|
|
|
|
|
|
|
qskSetItemGeometry( item, r );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( entryTable.orientation() == Qt::Horizontal )
|
|
|
|
{
|
|
|
|
if ( ++col == entryTable.dimension() )
|
|
|
|
{
|
|
|
|
col = 0;
|
|
|
|
row++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( ++row == entryTable.dimension() )
|
|
|
|
{
|
|
|
|
row = 0;
|
|
|
|
col++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QSizeF QskLinearLayoutEngine::sizeHint( Qt::SizeHint which, const QSizeF& constraint ) const
|
|
|
|
{
|
|
|
|
const auto& entryTable = m_data->entryTable;
|
|
|
|
|
|
|
|
if ( entryTable.effectiveCount() == 0 )
|
|
|
|
return QSizeF( 0.0, 0.0 );
|
|
|
|
|
|
|
|
const auto constraintType = m_data->entryTable.constraintType();
|
|
|
|
|
2019-07-01 14:45:25 +02:00
|
|
|
auto& colChain = m_data->colChain;
|
|
|
|
auto& rowChain = m_data->rowChain;
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
m_data->blockInvalidate = true;
|
|
|
|
|
|
|
|
if ( ( constraint.width() >= 0 ) &&
|
|
|
|
( constraintType == QskLayoutConstraint::HeightForWidth ) )
|
|
|
|
{
|
2019-07-12 15:26:55 +02:00
|
|
|
qskUpdateLayoutChain( Qt::Horizontal, entryTable, colChain );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
2019-07-01 14:45:25 +02:00
|
|
|
const auto cellConstraints = colChain.geometries( constraint.width() );
|
2019-07-12 15:26:55 +02:00
|
|
|
qskUpdateLayoutChain( Qt::Vertical, cellConstraints, entryTable, rowChain );
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
else if ( ( constraint.height() >= 0 ) &&
|
|
|
|
( constraintType == QskLayoutConstraint::WidthForHeight ) )
|
|
|
|
{
|
2019-07-12 15:26:55 +02:00
|
|
|
qskUpdateLayoutChain( Qt::Vertical, entryTable, rowChain );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
2019-07-01 14:45:25 +02:00
|
|
|
const auto cellConstraints = rowChain.geometries( constraint.height() );
|
2019-07-12 15:26:55 +02:00
|
|
|
qskUpdateLayoutChain( Qt::Horizontal, cellConstraints, entryTable, colChain );
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-07-12 15:26:55 +02:00
|
|
|
qskUpdateLayoutChain( Qt::Horizontal, entryTable, colChain );
|
|
|
|
qskUpdateLayoutChain( Qt::Vertical, entryTable, rowChain );
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
m_data->blockInvalidate = false;
|
|
|
|
|
2019-07-01 14:45:25 +02:00
|
|
|
const qreal width = colChain.boundingHint().size( which );
|
|
|
|
const qreal height = rowChain.boundingHint().size( which );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
return QSizeF( width, height );
|
|
|
|
}
|
|
|
|
|
|
|
|
qreal QskLinearLayoutEngine::widthForHeight( qreal height ) const
|
|
|
|
{
|
|
|
|
const QSizeF constraint( -1, height );
|
|
|
|
return sizeHint( Qt::PreferredSize, constraint ).width();
|
|
|
|
}
|
|
|
|
|
|
|
|
qreal QskLinearLayoutEngine::heightForWidth( qreal width ) const
|
|
|
|
{
|
|
|
|
const QSizeF constraint( width, -1 );
|
|
|
|
return sizeHint( Qt::PreferredSize, constraint ).height();
|
|
|
|
}
|
|
|
|
|
2019-07-12 15:37:42 +02:00
|
|
|
bool QskLinearLayoutEngine::setVisualDirection(Qt::LayoutDirection direction)
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
2019-07-12 15:37:42 +02:00
|
|
|
if ( m_data->visualDirection != direction )
|
|
|
|
{
|
|
|
|
m_data->visualDirection = direction;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Qt::LayoutDirection QskLinearLayoutEngine::visualDirection() const
|
|
|
|
{
|
|
|
|
return m_data->visualDirection;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskLinearLayoutEngine::updateCellGeometries( const QSizeF& size )
|
|
|
|
{
|
|
|
|
auto& geometries = m_data->geometries;
|
|
|
|
geometries.boundingSize = size;
|
|
|
|
|
2019-07-01 14:45:25 +02:00
|
|
|
auto& colChain = m_data->colChain;
|
|
|
|
auto& rowChain = m_data->rowChain;
|
2019-06-19 14:08:45 +02:00
|
|
|
auto& entryTable = m_data->entryTable;
|
|
|
|
|
2019-07-01 14:45:25 +02:00
|
|
|
const QVector< QskLayoutChain::Range > noConstraints;
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
switch( entryTable.constraintType() )
|
|
|
|
{
|
|
|
|
case QskLayoutConstraint::WidthForHeight:
|
|
|
|
{
|
2019-07-12 15:26:55 +02:00
|
|
|
qskUpdateLayoutChain( Qt::Vertical, entryTable, rowChain );
|
2019-07-01 14:45:25 +02:00
|
|
|
geometries.rows = rowChain.geometries( size.height() );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
2019-07-12 15:26:55 +02:00
|
|
|
qskUpdateLayoutChain( Qt::Horizontal, geometries.rows, entryTable, colChain );
|
2019-07-01 14:45:25 +02:00
|
|
|
geometries.columns = colChain.geometries( size.width() );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QskLayoutConstraint::HeightForWidth:
|
|
|
|
{
|
2019-07-12 15:26:55 +02:00
|
|
|
qskUpdateLayoutChain( Qt::Horizontal, entryTable, colChain );
|
2019-07-01 14:45:25 +02:00
|
|
|
geometries.columns = colChain.geometries( size.width() );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
2019-07-12 15:26:55 +02:00
|
|
|
qskUpdateLayoutChain( Qt::Vertical, geometries.columns, entryTable, rowChain );
|
2019-07-01 14:45:25 +02:00
|
|
|
geometries.rows = rowChain.geometries( size.height() );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
2019-07-12 15:26:55 +02:00
|
|
|
qskUpdateLayoutChain( Qt::Horizontal, entryTable, colChain );
|
2019-07-01 14:45:25 +02:00
|
|
|
geometries.columns = colChain.geometries( size.width() );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
2019-07-12 15:26:55 +02:00
|
|
|
qskUpdateLayoutChain( Qt::Vertical, entryTable, rowChain );
|
2019-07-01 14:45:25 +02:00
|
|
|
geometries.rows = rowChain.geometries( size.height() );
|
2019-06-19 14:08:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qreal QskLinearLayoutEngine::defaultSpacing( Qt::Orientation ) const
|
|
|
|
{
|
|
|
|
return qskDefaultSpacing();
|
|
|
|
}
|