QGridLayoutEngine replaced by QskGridLayoutEngine also for QskGridBox
This commit is contained in:
parent
beb44e4004
commit
f5ee8a3853
|
|
@ -7,6 +7,7 @@
|
|||
#include "QskGridLayoutEngine.h"
|
||||
#include "QskLayoutConstraint.h"
|
||||
#include "QskEvent.h"
|
||||
#include <algorithm>
|
||||
|
||||
static void qskSetItemActive( QObject* receiver, const QQuickItem* item, bool on )
|
||||
{
|
||||
|
|
@ -44,10 +45,44 @@ static void qskSetItemActive( QObject* receiver, const QQuickItem* item, bool on
|
|||
}
|
||||
}
|
||||
|
||||
static void qskUpdateFocusChain(
|
||||
QskGridBox* box, const QskGridLayoutEngine* engine,
|
||||
QQuickItem* item, const QRect& grid )
|
||||
{
|
||||
auto comparePosition =
|
||||
[item, engine]( const QPoint& pos, const QQuickItem* child )
|
||||
{
|
||||
if ( item != child )
|
||||
{
|
||||
const int index = engine->indexOf( child );
|
||||
if ( index >= 0 )
|
||||
{
|
||||
const auto grid = engine->gridAt( index );
|
||||
if ( pos.y() < grid.y() )
|
||||
return true;
|
||||
|
||||
if ( pos.y() == grid.y() && pos.x() < grid.x() )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const auto children = box->childItems();
|
||||
|
||||
auto it = std::upper_bound( children.begin(), children.end(),
|
||||
grid.topLeft(), comparePosition );
|
||||
|
||||
if ( it != children.end() )
|
||||
item->stackBefore( *it );
|
||||
}
|
||||
|
||||
class QskGridBox::PrivateData
|
||||
{
|
||||
public:
|
||||
QskGridLayoutEngine engine;
|
||||
bool blockAutoRemove = false;
|
||||
};
|
||||
|
||||
QskGridBox::QskGridBox( QQuickItem* parent )
|
||||
|
|
@ -60,13 +95,38 @@ QskGridBox::~QskGridBox()
|
|||
{
|
||||
}
|
||||
|
||||
void QskGridBox::addItem( QQuickItem* item,
|
||||
int QskGridBox::addItem( QQuickItem* item,
|
||||
int row, int column, int rowSpan, int columnSpan,
|
||||
Qt::Alignment alignment )
|
||||
{
|
||||
if ( item == nullptr )
|
||||
return;
|
||||
if ( item == nullptr || row < 0 || column < 0 )
|
||||
return -1;
|
||||
|
||||
rowSpan = qMax( rowSpan, -1 );
|
||||
columnSpan = qMax( columnSpan, -1 );
|
||||
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
const QRect itemGrid( column, row, columnSpan, rowSpan );
|
||||
int index = -1;
|
||||
|
||||
if ( item->parentItem() == this )
|
||||
{
|
||||
index = indexOf( item );
|
||||
if ( index >= 0 )
|
||||
{
|
||||
if ( engine.gridAt( index ) == itemGrid )
|
||||
{
|
||||
if ( engine.setAlignmentAt( index, alignment ) )
|
||||
polish();
|
||||
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( index < 0 )
|
||||
{
|
||||
if ( item->parent() == nullptr )
|
||||
item->setParent( this );
|
||||
|
||||
|
|
@ -74,16 +134,28 @@ void QskGridBox::addItem( QQuickItem* item,
|
|||
item->setParentItem( this );
|
||||
|
||||
qskSetItemActive( this, item, true );
|
||||
index = engine.insertItem( item, itemGrid, alignment );
|
||||
}
|
||||
|
||||
// What about the focus tab chain - TODO ... ????
|
||||
// check if item is already inserted ???
|
||||
|
||||
m_data->engine.insertItem(
|
||||
item, row, column, rowSpan, columnSpan, alignment );
|
||||
if ( engine.count() > 1 )
|
||||
qskUpdateFocusChain( this, &engine, item, itemGrid );
|
||||
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int QskGridBox::addSpacer( qreal spacing,
|
||||
int row, int column, int rowSpan, int columnSpan )
|
||||
{
|
||||
const int index = m_data->engine.insertSpacer(
|
||||
spacing, QRect( column, row, columnSpan, rowSpan ) );
|
||||
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void QskGridBox::removeAt( int index )
|
||||
|
|
@ -106,25 +178,29 @@ void QskGridBox::removeItem( const QQuickItem* item )
|
|||
|
||||
void QskGridBox::clear( bool autoDelete )
|
||||
{
|
||||
for ( int i = count() - 1; i >= 0; i-- )
|
||||
{
|
||||
auto item = itemAtIndex( i );
|
||||
m_data->blockAutoRemove = true;
|
||||
|
||||
removeAt( i );
|
||||
|
||||
if( item )
|
||||
for ( int i = 0; i < count(); i++ )
|
||||
{
|
||||
if ( auto item = itemAtIndex( i ) )
|
||||
{
|
||||
qskSetItemActive( this, item, false );
|
||||
|
||||
if( autoDelete && ( item->parent() == this ) )
|
||||
delete item;
|
||||
else
|
||||
item->setParentItem( nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
m_data->blockAutoRemove = false;
|
||||
|
||||
m_data->engine.clear();
|
||||
}
|
||||
|
||||
int QskGridBox::count() const
|
||||
{
|
||||
return m_data->engine.itemCount();
|
||||
return m_data->engine.count();
|
||||
}
|
||||
|
||||
int QskGridBox::rowCount() const
|
||||
|
|
@ -157,47 +233,30 @@ int QskGridBox::indexAt( int row, int column ) const
|
|||
return m_data->engine.indexAt( row, column );
|
||||
}
|
||||
|
||||
int QskGridBox::rowOfIndex( int index ) const
|
||||
QRect QskGridBox::gridOfIndex( int index ) const
|
||||
{
|
||||
return m_data->engine.rowOfIndex( index );
|
||||
return m_data->engine.gridAt( index );
|
||||
}
|
||||
|
||||
int QskGridBox::rowSpanOfIndex( int index ) const
|
||||
QRect QskGridBox::effectiveGridOfIndex( int index ) const
|
||||
{
|
||||
return m_data->engine.rowSpanOfIndex( index );
|
||||
return m_data->engine.effectiveGridAt( index );
|
||||
}
|
||||
|
||||
int QskGridBox::columnOfIndex( int index ) const
|
||||
void QskGridBox::setDefaultAlignment( Qt::Alignment alignment )
|
||||
{
|
||||
return m_data->engine.columnOfIndex( index );
|
||||
if ( m_data->engine.setDefaultAlignment( alignment ) )
|
||||
Q_EMIT defaultAlignmentChanged();
|
||||
}
|
||||
|
||||
int QskGridBox::columnSpanOfIndex( int index ) const
|
||||
Qt::Alignment QskGridBox::defaultAlignment() const
|
||||
{
|
||||
return m_data->engine.columnSpanOfIndex( index );
|
||||
return m_data->engine.defaultAlignment();
|
||||
}
|
||||
|
||||
void QskGridBox::setSpacing( Qt::Orientations orientations, qreal spacing )
|
||||
{
|
||||
spacing = qMax( spacing, 0.0 );
|
||||
|
||||
bool doUpdate = false;
|
||||
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
for ( const auto o : { Qt::Horizontal, Qt::Vertical } )
|
||||
{
|
||||
if ( orientations & o )
|
||||
{
|
||||
if ( spacing != engine.spacing( o ) )
|
||||
{
|
||||
engine.setSpacing( o, spacing );
|
||||
doUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( doUpdate )
|
||||
if ( m_data->engine.setSpacing( spacing, orientations ) )
|
||||
{
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
|
|
@ -209,7 +268,7 @@ void QskGridBox::resetSpacing( Qt::Orientations orientations )
|
|||
for ( const auto o : { Qt::Horizontal, Qt::Vertical } )
|
||||
{
|
||||
if ( orientations & o )
|
||||
setSpacing( o, QskGridLayoutEngine::defaultSpacing( o ) );
|
||||
setSpacing( o, m_data->engine.defaultSpacing( o ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -218,72 +277,26 @@ qreal QskGridBox::spacing( Qt::Orientation orientation ) const
|
|||
return m_data->engine.spacing( orientation );
|
||||
}
|
||||
|
||||
void QskGridBox::setRowSpacing( int row, qreal spacing )
|
||||
{
|
||||
spacing = qMax( spacing, 0.0 );
|
||||
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( spacing != engine.spacingAt( Qt::Vertical, row ) )
|
||||
{
|
||||
engine.setSpacingAt( Qt::Vertical, row, spacing );
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
qreal QskGridBox::rowSpacing( int row ) const
|
||||
{
|
||||
return m_data->engine.spacingAt( Qt::Vertical, row );
|
||||
}
|
||||
|
||||
void QskGridBox::setColumnSpacing( int column, qreal spacing )
|
||||
{
|
||||
spacing = qMax( spacing, 0.0 );
|
||||
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( spacing != engine.spacingAt( Qt::Horizontal, column ) )
|
||||
{
|
||||
engine.setSpacingAt( Qt::Horizontal, column, spacing );
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
qreal QskGridBox::columnSpacing( int column ) const
|
||||
{
|
||||
return m_data->engine.spacingAt( Qt::Horizontal, column );
|
||||
}
|
||||
|
||||
void QskGridBox::setRowStretchFactor( int row, int stretch )
|
||||
{
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( stretch != engine.stretchFactorAt( Qt::Vertical, row ) )
|
||||
{
|
||||
engine.setStretchFactorAt( Qt::Vertical, row, stretch );
|
||||
if ( m_data->engine.setStretchFactor( row, stretch, Qt::Vertical ) )
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
int QskGridBox::rowStretchFactor( int row ) const
|
||||
{
|
||||
return m_data->engine.stretchFactorAt( Qt::Vertical, row );
|
||||
return m_data->engine.stretchFactor( row, Qt::Vertical );
|
||||
}
|
||||
|
||||
void QskGridBox::setColumnStretchFactor( int column, int stretch )
|
||||
{
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( stretch != engine.stretchFactorAt( Qt::Horizontal, column ) )
|
||||
{
|
||||
engine.setStretchFactorAt( Qt::Horizontal, column, stretch );
|
||||
if ( m_data->engine.setStretchFactor( column, stretch, Qt::Horizontal ) )
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
int QskGridBox::columnStretchFactor( int column ) const
|
||||
{
|
||||
return m_data->engine.stretchFactorAt( Qt::Horizontal, column );
|
||||
return m_data->engine.stretchFactor( column, Qt::Horizontal );
|
||||
}
|
||||
|
||||
void QskGridBox::setRowFixedHeight( int row, qreal height )
|
||||
|
|
@ -298,79 +311,46 @@ void QskGridBox::setColumnFixedWidth( int column, qreal width )
|
|||
setColumnSizeHint( column, Qt::MaximumSize, width );
|
||||
}
|
||||
|
||||
void QskGridBox::setRowAlignment( int row, Qt::Alignment alignment )
|
||||
{
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( engine.alignmentAt( Qt::Vertical, row ) != alignment )
|
||||
{
|
||||
engine.setAlignmentAt( Qt::Vertical, row, alignment );
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
Qt::Alignment QskGridBox::rowAlignment( int row ) const
|
||||
{
|
||||
return m_data->engine.alignmentAt( Qt::Vertical, row );
|
||||
}
|
||||
|
||||
void QskGridBox::setColumnAlignment( int column, Qt::Alignment alignment )
|
||||
{
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( engine.alignmentAt( Qt::Horizontal, column ) != alignment )
|
||||
{
|
||||
engine.setAlignmentAt( Qt::Horizontal, column, alignment );
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
Qt::Alignment QskGridBox::columnAlignment( int column ) const
|
||||
{
|
||||
return m_data->engine.alignmentAt( Qt::Horizontal, column );
|
||||
}
|
||||
|
||||
void QskGridBox::setAlignment( const QQuickItem* item, Qt::Alignment alignment )
|
||||
{
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( engine.alignmentOf( item ) != alignment )
|
||||
const int index = engine.indexOf( item );
|
||||
if ( index >= 0 )
|
||||
{
|
||||
engine.setAlignmentOf( item, alignment );
|
||||
if ( engine.setAlignmentAt( index, alignment ) )
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
Qt::Alignment QskGridBox::alignment( const QQuickItem* item ) const
|
||||
{
|
||||
return m_data->engine.alignmentOf( item );
|
||||
const auto& engine = m_data->engine;
|
||||
return engine.alignmentAt( engine.indexOf( item ) );
|
||||
}
|
||||
|
||||
void QskGridBox::setRetainSizeWhenHidden( const QQuickItem* item, bool on )
|
||||
{
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( engine.retainSizeWhenHiddenOf( item ) != on )
|
||||
const int index = engine.indexOf( item );
|
||||
if ( index >= 0 )
|
||||
{
|
||||
engine.setRetainSizeWhenHiddenOf( item, on );
|
||||
if ( engine.setRetainSizeWhenHiddenAt( index, on ) )
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
bool QskGridBox::retainSizeWhenHidden( const QQuickItem* item ) const
|
||||
{
|
||||
return m_data->engine.retainSizeWhenHiddenOf( item );
|
||||
const auto& engine = m_data->engine;
|
||||
return engine.retainSizeWhenHiddenAt( engine.indexOf( item ) );
|
||||
}
|
||||
|
||||
void QskGridBox::setRowSizeHint( int row, Qt::SizeHint which, qreal height )
|
||||
{
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( height != engine.rowSizeHint( row, which ) )
|
||||
{
|
||||
engine.setRowSizeHint( row, which, height );
|
||||
if ( m_data->engine.setRowSizeHint( row, which, height ) )
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
qreal QskGridBox::rowSizeHint( int row, Qt::SizeHint which ) const
|
||||
|
|
@ -380,13 +360,8 @@ qreal QskGridBox::rowSizeHint( int row, Qt::SizeHint which ) const
|
|||
|
||||
void QskGridBox::setColumnSizeHint( int column, Qt::SizeHint which, qreal width )
|
||||
{
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( width != engine.columnSizeHint( column, which ) )
|
||||
{
|
||||
engine.setColumnSizeHint( column, which, width );
|
||||
if ( m_data->engine.setColumnSizeHint( column, which, width ) )
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
qreal QskGridBox::columnSizeHint( int column, Qt::SizeHint which ) const
|
||||
|
|
@ -421,7 +396,8 @@ qreal QskGridBox::heightForWidth( qreal width ) const
|
|||
auto constrainedHeight =
|
||||
[this]( QskLayoutConstraint::Type, const QskControl*, qreal width )
|
||||
{
|
||||
return m_data->engine.heightForWidth( width );
|
||||
const QSizeF constraint( width, -1 );
|
||||
return m_data->engine.sizeHint( Qt::PreferredSize, constraint ).height();
|
||||
};
|
||||
|
||||
return QskLayoutConstraint::constrainedMetric(
|
||||
|
|
@ -433,7 +409,8 @@ qreal QskGridBox::widthForHeight( qreal height ) const
|
|||
auto constrainedWidth =
|
||||
[this]( QskLayoutConstraint::Type, const QskControl*, qreal height )
|
||||
{
|
||||
return m_data->engine.widthForHeight( height );
|
||||
const QSizeF constraint( -1, height );
|
||||
return m_data->engine.sizeHint( Qt::PreferredSize, constraint ).width();
|
||||
};
|
||||
|
||||
return QskLayoutConstraint::constrainedMetric(
|
||||
|
|
@ -456,6 +433,7 @@ void QskGridBox::itemChange( ItemChange change, const ItemChangeData& value )
|
|||
{
|
||||
case ItemChildRemovedChange:
|
||||
{
|
||||
if ( !m_data->blockAutoRemove )
|
||||
removeItem( value.item );
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ class QSK_EXPORT QskGridBox : public QskBox
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY( Qt::Alignment defaultAlignment READ defaultAlignment
|
||||
WRITE setDefaultAlignment NOTIFY defaultAlignmentChanged )
|
||||
|
||||
Q_PROPERTY( bool empty READ isEmpty() )
|
||||
Q_PROPERTY( int count READ count )
|
||||
|
||||
|
|
@ -21,14 +24,17 @@ class QSK_EXPORT QskGridBox : public QskBox
|
|||
explicit QskGridBox( QQuickItem* parent = nullptr );
|
||||
~QskGridBox() override;
|
||||
|
||||
Q_INVOKABLE void addItem(
|
||||
Q_INVOKABLE int addItem(
|
||||
QQuickItem*, int row, int column, int rowSpan, int columnSpan,
|
||||
Qt::Alignment alignment = Qt::Alignment() );
|
||||
|
||||
Q_INVOKABLE void addItem(
|
||||
Q_INVOKABLE int addItem(
|
||||
QQuickItem*, int row, int column,
|
||||
Qt::Alignment alignment = Qt::Alignment() );
|
||||
|
||||
Q_INVOKABLE int addSpacer( qreal spacing,
|
||||
int row, int column, int columnSpan = 1, int rowSpan = 1 );
|
||||
|
||||
void removeItem( const QQuickItem* );
|
||||
void removeAt( int index );
|
||||
|
||||
|
|
@ -48,13 +54,11 @@ class QSK_EXPORT QskGridBox : public QskBox
|
|||
Q_INVOKABLE QQuickItem* itemAt( int row, int column ) const;
|
||||
Q_INVOKABLE int indexAt( int row, int column ) const;
|
||||
|
||||
Q_INVOKABLE int rowOfIndex( int index ) const;
|
||||
Q_INVOKABLE int rowSpanOfIndex( int index ) const;
|
||||
Q_INVOKABLE QRect gridOfIndex( int index ) const;
|
||||
Q_INVOKABLE QRect effectiveGridOfIndex( int index ) const;
|
||||
|
||||
Q_INVOKABLE int columnOfIndex( int index ) const;
|
||||
Q_INVOKABLE int columnSpanOfIndex( int index ) const;
|
||||
|
||||
// spacings
|
||||
void setDefaultAlignment( Qt::Alignment );
|
||||
Qt::Alignment defaultAlignment() const;
|
||||
|
||||
void setSpacing( Qt::Orientations, qreal spacing );
|
||||
void resetSpacing( Qt::Orientations );
|
||||
|
|
@ -70,24 +74,16 @@ class QSK_EXPORT QskGridBox : public QskBox
|
|||
void setHorizontalSpacing( qreal spacing ) { setSpacing( Qt::Horizontal, spacing ); }
|
||||
qreal horizontalSpacing() const { return spacing( Qt::Horizontal ); }
|
||||
|
||||
void setSpacing( qreal spacing ) { setSpacing( Qt::Horizontal | Qt::Vertical, spacing ); }
|
||||
|
||||
void setActive( bool ) {}
|
||||
bool isActive() const { return true; }
|
||||
|
||||
void setRowMinimumHeight( int column, qreal height )
|
||||
{ setRowSizeHint( column, Qt::MinimumSize, height ); }
|
||||
void setRowMinimumHeight( int row, qreal height )
|
||||
{ setRowSizeHint( row, Qt::MinimumSize, height ); }
|
||||
|
||||
void setColumnMaximumWidth( int column, qreal width )
|
||||
{ setColumnSizeHint( column, Qt::MaximumSize, width ); }
|
||||
#endif
|
||||
|
||||
Q_INVOKABLE void setRowSpacing( int row, qreal spacing );
|
||||
Q_INVOKABLE qreal rowSpacing( int row ) const;
|
||||
|
||||
Q_INVOKABLE void setColumnSpacing( int column, qreal spacing );
|
||||
Q_INVOKABLE qreal columnSpacing( int column ) const;
|
||||
|
||||
// stretch factors
|
||||
Q_INVOKABLE void setRowStretchFactor( int row, int stretch );
|
||||
Q_INVOKABLE int rowStretchFactor( int row ) const;
|
||||
|
|
@ -108,12 +104,6 @@ class QSK_EXPORT QskGridBox : public QskBox
|
|||
|
||||
// alignments
|
||||
|
||||
Q_INVOKABLE void setRowAlignment( int row, Qt::Alignment alignment );
|
||||
Q_INVOKABLE Qt::Alignment rowAlignment( int row ) const;
|
||||
|
||||
Q_INVOKABLE void setColumnAlignment( int column, Qt::Alignment alignment );
|
||||
Q_INVOKABLE Qt::Alignment columnAlignment( int column ) const;
|
||||
|
||||
void setAlignment( const QQuickItem* item, Qt::Alignment alignment );
|
||||
Qt::Alignment alignment( const QQuickItem* item ) const;
|
||||
|
||||
|
|
@ -129,6 +119,9 @@ class QSK_EXPORT QskGridBox : public QskBox
|
|||
void invalidate();
|
||||
void clear( bool autoDelete = false );
|
||||
|
||||
Q_SIGNALS:
|
||||
void defaultAlignmentChanged();
|
||||
|
||||
protected:
|
||||
bool event( QEvent* ) override;
|
||||
void geometryChangeEvent( QskGeometryChangeEvent* ) override;
|
||||
|
|
@ -141,10 +134,10 @@ class QSK_EXPORT QskGridBox : public QskBox
|
|||
std::unique_ptr< PrivateData > m_data;
|
||||
};
|
||||
|
||||
inline void QskGridBox::addItem(
|
||||
inline int QskGridBox::addItem(
|
||||
QQuickItem* item, int row, int column, Qt::Alignment alignment )
|
||||
{
|
||||
addItem( item, row, column, 1, 1, alignment );
|
||||
return addItem( item, row, column, 1, 1, alignment );
|
||||
}
|
||||
|
||||
inline bool QskGridBox::isEmpty() const
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -7,89 +7,68 @@
|
|||
#define QSK_GRID_LAYOUT_ENGINE_H
|
||||
|
||||
#include "QskGlobal.h"
|
||||
#include "QskLayoutEngine2D.h"
|
||||
|
||||
#include <qnamespace.h>
|
||||
#include <qrect.h>
|
||||
#include <memory>
|
||||
|
||||
class QQuickItem;
|
||||
class QSizeF;
|
||||
class QRectF;
|
||||
|
||||
class QskGridLayoutEngine
|
||||
class QskGridLayoutEngine : public QskLayoutEngine2D
|
||||
{
|
||||
public:
|
||||
QskGridLayoutEngine();
|
||||
~QskGridLayoutEngine();
|
||||
~QskGridLayoutEngine() override;
|
||||
|
||||
void setGeometries( const QRectF );
|
||||
void invalidate();
|
||||
int count() const override final;
|
||||
|
||||
void setVisualDirection( Qt::LayoutDirection );
|
||||
Qt::LayoutDirection visualDirection() const;
|
||||
bool setStretchFactor( int pos, int stretch, Qt::Orientation );
|
||||
int stretchFactor( int pos, Qt::Orientation ) const;
|
||||
|
||||
int itemCount() const;
|
||||
|
||||
int rowCount() const;
|
||||
int columnCount() const;
|
||||
|
||||
void insertItem( QQuickItem* item,
|
||||
int row, int column, int rowSpan, int columnSpan,
|
||||
Qt::Alignment );
|
||||
|
||||
void removeAt( int index );
|
||||
|
||||
int indexAt( int row, int column ) const;
|
||||
int indexOf( const QQuickItem* item ) const;
|
||||
|
||||
QQuickItem* itemAt( int index ) const;
|
||||
QQuickItem* itemAt( int row, int column ) const;
|
||||
|
||||
int rowOfIndex( int index ) const;
|
||||
int rowSpanOfIndex( int index ) const;
|
||||
|
||||
int columnOfIndex( int index ) const;
|
||||
int columnSpanOfIndex( int index ) const;
|
||||
|
||||
void setSpacing( Qt::Orientation, qreal spacing );
|
||||
qreal spacing( Qt::Orientation ) const;
|
||||
|
||||
void setSpacingAt( Qt::Orientation, int cell, qreal spacing );
|
||||
qreal spacingAt( Qt::Orientation, int cell ) const;
|
||||
|
||||
void setStretchFactorAt( Qt::Orientation, int cell, int stretch );
|
||||
int stretchFactorAt( Qt::Orientation, int cell );
|
||||
|
||||
void setAlignmentAt( Qt::Orientation, int cell, Qt::Alignment );
|
||||
Qt::Alignment alignmentAt( Qt::Orientation, int cell ) const;
|
||||
|
||||
void setAlignmentOf( const QQuickItem*, Qt::Alignment );
|
||||
Qt::Alignment alignmentOf( const QQuickItem* ) const;
|
||||
|
||||
void setRetainSizeWhenHiddenOf( const QQuickItem*, bool on );
|
||||
bool retainSizeWhenHiddenOf( const QQuickItem* ) const;
|
||||
|
||||
void setRowSizeHint( int row, Qt::SizeHint, qreal height );
|
||||
bool setRowSizeHint( int row, Qt::SizeHint, qreal height );
|
||||
qreal rowSizeHint( int row, Qt::SizeHint ) const;
|
||||
|
||||
void setColumnSizeHint( int column, Qt::SizeHint, qreal width );
|
||||
bool setColumnSizeHint( int column, Qt::SizeHint, qreal width );
|
||||
qreal columnSizeHint( int column, Qt::SizeHint ) const;
|
||||
|
||||
QSizeF sizeHint( Qt::SizeHint, const QSizeF& constraint = QSizeF() ) const;
|
||||
int insertItem( QQuickItem*, const QRect& grid, Qt::Alignment );
|
||||
int insertSpacer( qreal spacing, const QRect& grid );
|
||||
|
||||
qreal widthForHeight( qreal height ) const;
|
||||
qreal heightForWidth( qreal width ) const;
|
||||
bool removeAt( int index );
|
||||
bool clear();
|
||||
|
||||
static qreal defaultSpacing( Qt::Orientation );
|
||||
QQuickItem* itemAt( int index ) const override final;
|
||||
qreal spacerAt( int index ) const override final;
|
||||
|
||||
#if 1
|
||||
QSize requiredCells() const;
|
||||
void adjustSpans( int numRows, int numColumns );
|
||||
#endif
|
||||
QQuickItem* itemAt( int row, int column ) const;
|
||||
int indexAt( int row, int column ) const;
|
||||
|
||||
bool setGridAt( int index, const QRect& );
|
||||
QRect gridAt( int index ) const;
|
||||
|
||||
QRect effectiveGridAt( int index ) const;
|
||||
|
||||
bool setRetainSizeWhenHiddenAt( int index, bool on );
|
||||
bool retainSizeWhenHiddenAt( int index ) const;
|
||||
|
||||
bool setAlignmentAt( int index, Qt::Alignment );
|
||||
Qt::Alignment alignmentAt( int index ) const;
|
||||
|
||||
void transpose();
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QskGridLayoutEngine)
|
||||
void layoutItems() override;
|
||||
int effectiveCount( Qt::Orientation ) const override;
|
||||
|
||||
void invalidateElementCache() override;
|
||||
|
||||
void setupChain( Qt::Orientation,
|
||||
const QskLayoutChain::Segments&, QskLayoutChain& ) const override;
|
||||
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
PrivateData* m_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@
|
|||
#include <cmath>
|
||||
#endif
|
||||
|
||||
#include <qdebug.h>
|
||||
|
||||
QskLayoutChain::QskLayoutChain()
|
||||
{
|
||||
}
|
||||
|
|
@ -29,13 +31,13 @@ void QskLayoutChain::invalidate()
|
|||
|
||||
void QskLayoutChain::reset( int count, qreal constraint )
|
||||
{
|
||||
m_cells.assign( count, Cell() );
|
||||
m_cells.fill( CellData(), count );
|
||||
m_constraint = constraint;
|
||||
m_sumStretches = 0;
|
||||
m_validCells = 0;
|
||||
}
|
||||
|
||||
void QskLayoutChain::expandTo( int index, const Cell& newCell )
|
||||
void QskLayoutChain::narrowCell( int index, const CellData& newCell )
|
||||
{
|
||||
if ( !newCell.isValid )
|
||||
return;
|
||||
|
|
@ -45,12 +47,109 @@ void QskLayoutChain::expandTo( int index, const Cell& newCell )
|
|||
if ( !cell.isValid )
|
||||
{
|
||||
cell = newCell;
|
||||
cell.stretch = qMax( cell.stretch, 0 );
|
||||
m_validCells++;
|
||||
}
|
||||
else
|
||||
{
|
||||
cell.canGrow &= newCell.canGrow;
|
||||
if ( newCell.stretch >= 0 )
|
||||
cell.stretch = qMax( cell.stretch, newCell.stretch );
|
||||
|
||||
if ( !newCell.hint.isDefault() )
|
||||
{
|
||||
cell.hint.setSizes(
|
||||
qMax( cell.hint.minimum(), newCell.hint.minimum() ),
|
||||
qMax( cell.hint.preferred(), newCell.hint.preferred() ),
|
||||
qMin( cell.hint.maximum(), newCell.hint.maximum() )
|
||||
);
|
||||
|
||||
cell.hint.normalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QskLayoutChain::expandCell( int index, const CellData& newCell )
|
||||
{
|
||||
if ( !newCell.isValid )
|
||||
return;
|
||||
|
||||
auto& cell = m_cells[ index ];
|
||||
|
||||
if ( !cell.isValid )
|
||||
{
|
||||
cell = newCell;
|
||||
cell.stretch = qMax( cell.stretch, 0 );
|
||||
m_validCells++;
|
||||
}
|
||||
else
|
||||
{
|
||||
cell.canGrow |= newCell.canGrow;
|
||||
cell.stretch = qMax( cell.stretch, newCell.stretch );
|
||||
cell.hint.expandTo( newCell.hint );
|
||||
|
||||
cell.hint.setSizes(
|
||||
qMax( cell.hint.minimum(), newCell.hint.minimum() ),
|
||||
qMax( cell.hint.preferred(), newCell.hint.preferred() ),
|
||||
qMax( cell.hint.maximum(), newCell.hint.maximum() )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void QskLayoutChain::expandCells(
|
||||
int index, int count, const CellData& multiCell )
|
||||
{
|
||||
QskLayoutChain chain;
|
||||
chain.reset( count, -1 );
|
||||
|
||||
for ( int i = 0; i < count; i++ )
|
||||
{
|
||||
chain.expandCell( i, m_cells[ index + i ] );
|
||||
|
||||
auto& cell = chain.m_cells[ i ];
|
||||
#if 1
|
||||
// what to do now ??
|
||||
if ( !cell.isValid )
|
||||
{
|
||||
cell.isValid = true;
|
||||
cell.canGrow = multiCell.canGrow;
|
||||
cell.stretch = qMax( cell.stretch, 0 );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
chain.m_validCells = count;
|
||||
|
||||
QVarLengthArray< QskLayoutHint > hints( count );
|
||||
|
||||
const auto& hint = multiCell.hint;
|
||||
const auto chainHint = chain.boundingHint();
|
||||
|
||||
if ( hint.minimum() > chainHint.minimum() )
|
||||
{
|
||||
const auto segments = chain.segments( hint.minimum() );
|
||||
for ( int i = 0; i < count; i++ )
|
||||
hints[i].setMinimum( segments[i].length );
|
||||
}
|
||||
|
||||
if ( hint.preferred() > chainHint.preferred() )
|
||||
{
|
||||
const auto segments = chain.segments( hint.preferred() );
|
||||
for ( int i = 0; i < count; i++ )
|
||||
hints[i].setPreferred( segments[i].length );
|
||||
}
|
||||
|
||||
if ( hint.maximum() < chainHint.maximum() )
|
||||
{
|
||||
const auto segments = chain.segments( hint.maximum() );
|
||||
for ( int i = 0; i < count; i++ )
|
||||
hints[i].setMaximum( segments[i].length );
|
||||
}
|
||||
|
||||
for ( int i = 0; i < count; i++ )
|
||||
{
|
||||
auto cell = multiCell;
|
||||
cell.hint = hints[i];
|
||||
|
||||
expandCell( index + i, cell );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -119,24 +218,24 @@ bool QskLayoutChain::setSpacing( qreal spacing )
|
|||
return false;
|
||||
}
|
||||
|
||||
QVector< QskLayoutChain::Range > QskLayoutChain::geometries( qreal size ) const
|
||||
QskLayoutChain::Segments QskLayoutChain::segments( qreal size ) const
|
||||
{
|
||||
if ( m_validCells == 0 )
|
||||
return QVector< Range >();
|
||||
return Segments();
|
||||
|
||||
QVector< Range > ranges;
|
||||
Segments segments;
|
||||
|
||||
if ( size <= m_boundingHint.minimum() )
|
||||
{
|
||||
ranges = distributed( Qt::MinimumSize, 0.0, 0.0 );
|
||||
segments = distributed( Qt::MinimumSize, 0.0, 0.0 );
|
||||
}
|
||||
else if ( size < m_boundingHint.preferred() )
|
||||
{
|
||||
ranges = minimumExpanded( size );
|
||||
segments = minimumExpanded( size );
|
||||
}
|
||||
else if ( size <= m_boundingHint.maximum() )
|
||||
{
|
||||
ranges = preferredStretched( size );
|
||||
segments = preferredStretched( size );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -145,70 +244,70 @@ QVector< QskLayoutChain::Range > QskLayoutChain::geometries( qreal size ) const
|
|||
qreal offset = 0.0;
|
||||
qreal extra = 0.0;;
|
||||
|
||||
if ( m_extraSpacingAt == Qt::LeftEdge )
|
||||
switch( m_extraSpacingAt )
|
||||
{
|
||||
case Leading:
|
||||
offset = padding;
|
||||
}
|
||||
else if ( m_extraSpacingAt == Qt::RightEdge )
|
||||
{
|
||||
offset = 0.0;
|
||||
}
|
||||
else if ( m_extraSpacingAt == ( Qt::LeftEdge | Qt::RightEdge ) )
|
||||
{
|
||||
break;
|
||||
|
||||
case Trailing:
|
||||
break;
|
||||
|
||||
case Leading | Trailing:
|
||||
offset = 0.5 * padding;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
|
||||
default:
|
||||
extra = padding / m_validCells;
|
||||
}
|
||||
|
||||
ranges = distributed( Qt::MaximumSize, offset, extra );
|
||||
segments = distributed( Qt::MaximumSize, offset, extra );
|
||||
}
|
||||
|
||||
return ranges;
|
||||
return segments;
|
||||
}
|
||||
|
||||
QVector< QskLayoutChain::Range > QskLayoutChain::distributed(
|
||||
QskLayoutChain::Segments QskLayoutChain::distributed(
|
||||
int which, qreal offset, const qreal extra ) const
|
||||
{
|
||||
qreal fillSpacing = 0.0;
|
||||
|
||||
QVector< Range > ranges( m_cells.size() );
|
||||
Segments segments( m_cells.size() );
|
||||
|
||||
for ( int i = 0; i < ranges.count(); i++ )
|
||||
for ( int i = 0; i < segments.count(); i++ )
|
||||
{
|
||||
const auto& cell = m_cells[i];
|
||||
auto& range = ranges[i];
|
||||
auto& segment = segments[i];
|
||||
|
||||
if ( !cell.isValid )
|
||||
{
|
||||
range.start = offset;
|
||||
range.length = 0.0;
|
||||
segment.start = offset;
|
||||
segment.length = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset += fillSpacing;
|
||||
fillSpacing = m_spacing;
|
||||
|
||||
range.start = offset;
|
||||
range.length = cell.hint.size( which ) + extra;
|
||||
segment.start = offset;
|
||||
segment.length = cell.hint.size( which ) + extra;
|
||||
|
||||
offset += range.length;
|
||||
offset += segment.length;
|
||||
}
|
||||
}
|
||||
|
||||
return ranges;
|
||||
return segments;
|
||||
}
|
||||
|
||||
QVector< QskLayoutChain::Range > QskLayoutChain::minimumExpanded( qreal size ) const
|
||||
QskLayoutChain::Segments QskLayoutChain::minimumExpanded( qreal size ) const
|
||||
{
|
||||
QVector< Range > ranges( m_cells.size() );
|
||||
Segments segments( m_cells.size() );
|
||||
|
||||
qreal fillSpacing = 0.0;
|
||||
qreal offset = 0.0;
|
||||
|
||||
/*
|
||||
We have different options how to distribute the availabe space
|
||||
We have different options how to distribute the available space
|
||||
|
||||
- according to the preferred sizes
|
||||
|
||||
|
|
@ -231,7 +330,7 @@ QVector< QskLayoutChain::Range > QskLayoutChain::minimumExpanded( qreal size ) c
|
|||
const qreal desired = m_boundingHint.preferred() - m_boundingHint.minimum();
|
||||
const qreal available = size - m_boundingHint.minimum();
|
||||
|
||||
for ( uint i = 0; i < m_cells.size(); i++ )
|
||||
for ( int i = 0; i < m_cells.size(); i++ )
|
||||
{
|
||||
const auto& cell = m_cells[i];
|
||||
if ( !cell.isValid )
|
||||
|
|
@ -247,67 +346,67 @@ QVector< QskLayoutChain::Range > QskLayoutChain::minimumExpanded( qreal size ) c
|
|||
}
|
||||
}
|
||||
|
||||
for ( uint i = 0; i < m_cells.size(); i++ )
|
||||
for ( int i = 0; i < m_cells.size(); i++ )
|
||||
{
|
||||
const auto& cell = m_cells[i];
|
||||
auto& range = ranges[i];
|
||||
auto& segment = segments[i];
|
||||
|
||||
if ( !cell.isValid )
|
||||
{
|
||||
range.start = offset;
|
||||
range.length = 0.0;
|
||||
segment.start = offset;
|
||||
segment.length = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset += fillSpacing;
|
||||
fillSpacing = m_spacing;
|
||||
|
||||
range.start = offset;
|
||||
range.length = cell.hint.minimum()
|
||||
segment.start = offset;
|
||||
segment.length = cell.hint.minimum()
|
||||
+ available * ( factors[i] / sumFactors );
|
||||
|
||||
offset += range.length;
|
||||
offset += segment.length;
|
||||
}
|
||||
}
|
||||
#else
|
||||
const qreal factor = ( size - m_boundingHint.minimum() ) /
|
||||
( m_boundingHint.preferred() - m_boundingHint.minimum() );
|
||||
|
||||
for ( uint i = 0; i < m_cells.size(); i++ )
|
||||
for ( int i = 0; i < m_cells.count(); i++ )
|
||||
{
|
||||
const auto& cell = m_cells[i];
|
||||
auto& range = ranges[i];
|
||||
auto& segment = segments[i];
|
||||
|
||||
if ( !cell.isValid )
|
||||
{
|
||||
range.start = offset;
|
||||
range.length = 0.0;
|
||||
segment.start = offset;
|
||||
segment.length = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset += fillSpacing;
|
||||
fillSpacing = m_spacing;
|
||||
|
||||
range.start = offset;
|
||||
range.length = cell.hint.minimum()
|
||||
segment.start = offset;
|
||||
segment.length = cell.hint.minimum()
|
||||
+ factor * ( cell.hint.preferred() - cell.hint.minimum() );
|
||||
|
||||
offset += range.length;
|
||||
offset += segment.length;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return ranges;
|
||||
return segments;
|
||||
}
|
||||
|
||||
QVector< QskLayoutChain::Range > QskLayoutChain::preferredStretched( qreal size ) const
|
||||
QskLayoutChain::Segments QskLayoutChain::preferredStretched( qreal size ) const
|
||||
{
|
||||
const int count = m_cells.size();
|
||||
|
||||
qreal sumFactors = 0.0;
|
||||
|
||||
QVarLengthArray< qreal > factors( count );
|
||||
QVector< Range > ranges( count );
|
||||
Segments segments( count );
|
||||
|
||||
for ( int i = 0; i < count; i++ )
|
||||
{
|
||||
|
|
@ -315,7 +414,7 @@ QVector< QskLayoutChain::Range > QskLayoutChain::preferredStretched( qreal size
|
|||
|
||||
if ( !cell.isValid )
|
||||
{
|
||||
ranges[i].length = 0.0;
|
||||
segments[i].length = 0.0;
|
||||
factors[i] = -1.0;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -355,7 +454,7 @@ QVector< QskLayoutChain::Range > QskLayoutChain::preferredStretched( qreal size
|
|||
|
||||
if ( boundedSize != size )
|
||||
{
|
||||
ranges[i].length = boundedSize;
|
||||
segments[i].length = boundedSize;
|
||||
sumSizes -= boundedSize;
|
||||
sumFactors -= factors[i];
|
||||
factors[i] = -1.0;
|
||||
|
|
@ -374,7 +473,7 @@ QVector< QskLayoutChain::Range > QskLayoutChain::preferredStretched( qreal size
|
|||
for ( int i = 0; i < count; i++ )
|
||||
{
|
||||
const auto& cell = m_cells[i];
|
||||
auto& range = ranges[i];
|
||||
auto& segment = segments[i];
|
||||
|
||||
const auto& factor = factors[i];
|
||||
|
||||
|
|
@ -384,37 +483,37 @@ QVector< QskLayoutChain::Range > QskLayoutChain::preferredStretched( qreal size
|
|||
fillSpacing = m_spacing;
|
||||
}
|
||||
|
||||
range.start = offset;
|
||||
segment.start = offset;
|
||||
|
||||
if ( factor >= 0.0 )
|
||||
{
|
||||
if ( factor > 0.0 )
|
||||
range.length = sumSizes * factor / sumFactors;
|
||||
segment.length = sumSizes * factor / sumFactors;
|
||||
else
|
||||
range.length = cell.hint.preferred();
|
||||
segment.length = cell.hint.preferred();
|
||||
}
|
||||
|
||||
offset += range.length;
|
||||
offset += segment.length;
|
||||
}
|
||||
|
||||
return ranges;
|
||||
return segments;
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
|
||||
#include <qdebug.h>
|
||||
|
||||
QDebug operator<<( QDebug debug, const QskLayoutChain::Range& range )
|
||||
QDebug operator<<( QDebug debug, const QskLayoutChain::Segment& segment )
|
||||
{
|
||||
QDebugStateSaver saver( debug );
|
||||
debug.nospace();
|
||||
|
||||
debug << "( " << range.start << ", " << range.end() << " )";
|
||||
debug << "( " << segment.start << ", " << segment.end() << " )";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
QDebug operator<<( QDebug debug, const QskLayoutChain::Cell& cell )
|
||||
QDebug operator<<( QDebug debug, const QskLayoutChain::CellData& cell )
|
||||
{
|
||||
QDebugStateSaver saver( debug );
|
||||
debug.nospace();
|
||||
|
|
|
|||
|
|
@ -7,16 +7,15 @@
|
|||
#define QSK_LAYOUT_CHAIN_H
|
||||
|
||||
#include <QskLayoutHint.h>
|
||||
#include <qglobal.h>
|
||||
#include <qrect.h>
|
||||
#include <qvector.h>
|
||||
#include <vector>
|
||||
|
||||
class QDebug;
|
||||
|
||||
class QskLayoutChain
|
||||
{
|
||||
public:
|
||||
class Range
|
||||
class Segment
|
||||
{
|
||||
public:
|
||||
inline qreal end() const { return start + length; }
|
||||
|
|
@ -25,21 +24,12 @@ class QskLayoutChain
|
|||
qreal length = 0.0;
|
||||
};
|
||||
|
||||
class Cell
|
||||
typedef QVector< Segment > Segments;
|
||||
|
||||
class CellData
|
||||
{
|
||||
public:
|
||||
Cell()
|
||||
{
|
||||
}
|
||||
|
||||
Cell( QskLayoutHint hint, int stretch )
|
||||
: hint( hint )
|
||||
, stretch( stretch )
|
||||
, isValid( true )
|
||||
{
|
||||
}
|
||||
|
||||
inline bool operator==( const Cell& other ) const
|
||||
inline bool operator==( const CellData& other ) const
|
||||
{
|
||||
return ( isValid == other.isValid )
|
||||
&& ( canGrow == other.canGrow )
|
||||
|
|
@ -47,65 +37,83 @@ class QskLayoutChain
|
|||
&& ( hint == other.hint );
|
||||
}
|
||||
|
||||
inline bool operator!=( const Cell& other ) const
|
||||
inline bool operator!=( const CellData& other ) const
|
||||
{
|
||||
return !( *this == other );
|
||||
}
|
||||
|
||||
inline qreal size( int which ) const
|
||||
{
|
||||
return hint.size( which );
|
||||
}
|
||||
|
||||
inline void setSize( int which, qreal size )
|
||||
{
|
||||
hint.setSize( which, size );
|
||||
}
|
||||
|
||||
QskLayoutHint hint;
|
||||
|
||||
int stretch = 0;
|
||||
bool canGrow = false;
|
||||
bool isValid = false;
|
||||
};
|
||||
|
||||
enum ExtraSpacing
|
||||
{
|
||||
Leading = 1 << 0,
|
||||
Trailing = 1 << 1
|
||||
};
|
||||
|
||||
QskLayoutChain();
|
||||
~QskLayoutChain();
|
||||
|
||||
void invalidate();
|
||||
|
||||
void reset( int count, qreal constraint );
|
||||
void expandTo( int index, const Cell& );
|
||||
void expandCell( int index, const CellData& );
|
||||
void expandCells( int start, int end, const CellData& );
|
||||
void narrowCell( int index, const CellData& );
|
||||
void finish();
|
||||
|
||||
const Cell& cell( int index ) const { return m_cells[ index ]; }
|
||||
const CellData& cell( int index ) const { return m_cells[ index ]; }
|
||||
|
||||
bool setSpacing( qreal spacing );
|
||||
qreal spacing() const { return m_spacing; }
|
||||
|
||||
void setExtraSpacingAt( Qt::Edges edges ) { m_extraSpacingAt = edges; }
|
||||
void setExtraSpacingAt( int extraSpacingAt ) { m_extraSpacingAt = extraSpacingAt; }
|
||||
|
||||
QVector< Range > geometries( qreal size ) const;
|
||||
Segments segments( qreal size ) const;
|
||||
QskLayoutHint boundingHint() const { return m_boundingHint; }
|
||||
|
||||
inline qreal constraint() const { return m_constraint; }
|
||||
inline int count() const { return m_cells.size(); }
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY( QskLayoutChain )
|
||||
|
||||
QVector< Range > distributed( int which, qreal offset, qreal extra ) const;
|
||||
QVector< Range > minimumExpanded( qreal size ) const;
|
||||
QVector< Range > preferredStretched( qreal size ) const;
|
||||
Segments distributed( int which, qreal offset, qreal extra ) const;
|
||||
Segments minimumExpanded( qreal size ) const;
|
||||
Segments preferredStretched( qreal size ) const;
|
||||
|
||||
QskLayoutHint m_boundingHint;
|
||||
qreal m_constraint = -2.0;
|
||||
|
||||
qreal m_spacing = 0;
|
||||
Qt::Edges m_extraSpacingAt;
|
||||
int m_extraSpacingAt;
|
||||
|
||||
int m_sumStretches = 0;
|
||||
int m_validCells = 0;
|
||||
std::vector< Cell > m_cells;
|
||||
|
||||
QVector< CellData > m_cells;
|
||||
};
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
|
||||
QDebug operator<<( QDebug, const QskLayoutChain::Range& );
|
||||
QDebug operator<<( QDebug, const QskLayoutChain::Cell& );
|
||||
QDebug operator<<( QDebug, const QskLayoutChain::Segment& );
|
||||
QDebug operator<<( QDebug, const QskLayoutChain::CellData& );
|
||||
|
||||
#endif
|
||||
|
||||
Q_DECLARE_TYPEINFO( QskLayoutChain::Range, Q_MOVABLE_TYPE );
|
||||
Q_DECLARE_TYPEINFO( QskLayoutChain::Cell, Q_MOVABLE_TYPE );
|
||||
Q_DECLARE_TYPEINFO( QskLayoutChain::Segment, Q_MOVABLE_TYPE );
|
||||
Q_DECLARE_TYPEINFO( QskLayoutChain::CellData, Q_MOVABLE_TYPE );
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,455 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskLayoutEngine2D.h"
|
||||
#include "QskLayoutChain.h"
|
||||
#include "QskQuick.h"
|
||||
#include <qguiapplication.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
class LayoutData
|
||||
{
|
||||
public:
|
||||
|
||||
QRectF geometryAt( const QRect& grid ) const
|
||||
{
|
||||
const auto x1 = columns[ grid.left() ].start;
|
||||
const auto x2 = columns[ grid.right() ].end();
|
||||
const auto y1 = rows[ grid.top() ].start;
|
||||
const auto y2 = rows[ grid.bottom() ].end();
|
||||
|
||||
return QRectF( rect.x() + x1, rect.y() + y1, x2 - x1, y2 - y1 );
|
||||
}
|
||||
|
||||
Qt::LayoutDirection direction;
|
||||
|
||||
QRectF rect;
|
||||
QskLayoutChain::Segments rows;
|
||||
QskLayoutChain::Segments columns;
|
||||
};
|
||||
}
|
||||
|
||||
class QskLayoutEngine2D::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData()
|
||||
: defaultAlignment( Qt::AlignLeft | Qt::AlignVCenter )
|
||||
, extraSpacingAt( 0 )
|
||||
, visualDirection( Qt::LeftToRight )
|
||||
, constraintType( -1 )
|
||||
, blockInvalidate( false )
|
||||
{
|
||||
}
|
||||
|
||||
inline QskLayoutChain& layoutChain( Qt::Orientation orientation )
|
||||
{
|
||||
return ( orientation == Qt::Horizontal ) ? columnChain : rowChain;
|
||||
}
|
||||
|
||||
inline Qt::Alignment effectiveAlignment( Qt::Alignment alignment ) const
|
||||
{
|
||||
const auto align = static_cast< Qt::Alignment >( defaultAlignment );
|
||||
|
||||
if ( !( alignment & Qt::AlignVertical_Mask ) )
|
||||
alignment |= ( align & Qt::AlignVertical_Mask );
|
||||
|
||||
if ( !( alignment & Qt::AlignHorizontal_Mask ) )
|
||||
alignment |= ( align & Qt::AlignHorizontal_Mask );
|
||||
|
||||
return alignment;
|
||||
}
|
||||
|
||||
QskLayoutChain columnChain;
|
||||
QskLayoutChain rowChain;
|
||||
|
||||
QSizeF layoutSize;
|
||||
|
||||
QskLayoutChain::Segments rows;
|
||||
QskLayoutChain::Segments columns;
|
||||
|
||||
const LayoutData* layoutData = nullptr;
|
||||
|
||||
unsigned int defaultAlignment : 8;
|
||||
unsigned int extraSpacingAt : 4;
|
||||
unsigned int visualDirection : 4;
|
||||
|
||||
int constraintType : 3;
|
||||
|
||||
/*
|
||||
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;
|
||||
};
|
||||
|
||||
QskLayoutEngine2D::QskLayoutEngine2D()
|
||||
: m_data( new PrivateData )
|
||||
{
|
||||
m_data->columnChain.setSpacing( defaultSpacing( Qt::Horizontal ) );
|
||||
m_data->rowChain.setSpacing( defaultSpacing( Qt::Vertical ) );
|
||||
}
|
||||
|
||||
QskLayoutEngine2D::~QskLayoutEngine2D()
|
||||
{
|
||||
}
|
||||
|
||||
bool QskLayoutEngine2D::setVisualDirection( Qt::LayoutDirection direction )
|
||||
{
|
||||
if ( m_data->visualDirection != direction )
|
||||
{
|
||||
m_data->visualDirection = direction;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Qt::LayoutDirection QskLayoutEngine2D::visualDirection() const
|
||||
{
|
||||
return static_cast< Qt::LayoutDirection >( m_data->visualDirection );
|
||||
}
|
||||
|
||||
bool QskLayoutEngine2D::setDefaultAlignment( Qt::Alignment alignment )
|
||||
{
|
||||
if ( defaultAlignment() != alignment )
|
||||
{
|
||||
m_data->defaultAlignment = alignment;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Qt::Alignment QskLayoutEngine2D::defaultAlignment() const
|
||||
{
|
||||
return static_cast< Qt::Alignment >( m_data->defaultAlignment );
|
||||
}
|
||||
|
||||
|
||||
qreal QskLayoutEngine2D::defaultSpacing( Qt::Orientation ) const
|
||||
{
|
||||
return 5.0; // should be from the skin
|
||||
}
|
||||
|
||||
bool QskLayoutEngine2D::setSpacing(
|
||||
qreal spacing, Qt::Orientations orientations )
|
||||
{
|
||||
if ( spacing < 0.0 )
|
||||
spacing = 0.0;
|
||||
|
||||
bool isModified = false;
|
||||
|
||||
for ( auto o : { Qt::Horizontal, Qt::Vertical } )
|
||||
{
|
||||
if ( orientations & o )
|
||||
isModified |= m_data->layoutChain( o ).setSpacing( spacing );
|
||||
}
|
||||
|
||||
if ( isModified )
|
||||
invalidate( LayoutCache );
|
||||
|
||||
return isModified;
|
||||
}
|
||||
|
||||
qreal QskLayoutEngine2D::spacing( Qt::Orientation orientation ) const
|
||||
{
|
||||
return m_data->layoutChain( orientation ).spacing();
|
||||
}
|
||||
|
||||
bool QskLayoutEngine2D::setExtraSpacingAt( Qt::Edges edges )
|
||||
{
|
||||
if ( edges == extraSpacingAt() )
|
||||
return false;
|
||||
|
||||
m_data->extraSpacingAt = edges;
|
||||
|
||||
int value = 0;
|
||||
|
||||
if ( edges & Qt::LeftEdge )
|
||||
value |= QskLayoutChain::Leading;
|
||||
|
||||
if ( edges & Qt::RightEdge )
|
||||
value |= QskLayoutChain::Trailing;
|
||||
|
||||
m_data->columnChain.setExtraSpacingAt( value );
|
||||
|
||||
value = 0;
|
||||
|
||||
if ( edges & Qt::TopEdge )
|
||||
value |= QskLayoutChain::Leading;
|
||||
|
||||
if ( edges & Qt::BottomEdge )
|
||||
value |= QskLayoutChain::Trailing;
|
||||
|
||||
m_data->rowChain.setExtraSpacingAt( value );
|
||||
|
||||
invalidate();
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
void QskLayoutEngine2D::setGeometries( const QRectF& rect )
|
||||
{
|
||||
if ( rowCount() < 1 || columnCount() < 1 )
|
||||
return;
|
||||
|
||||
if ( m_data->layoutSize != rect.size() )
|
||||
{
|
||||
m_data->layoutSize = rect.size();
|
||||
updateSegments( rect.size() );
|
||||
}
|
||||
|
||||
/*
|
||||
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 rows/columns.
|
||||
*/
|
||||
LayoutData data;
|
||||
data.rows = m_data->rows;
|
||||
data.columns = m_data->columns;
|
||||
data.rect = rect;
|
||||
|
||||
data.direction = visualDirection();
|
||||
if ( data.direction == Qt::LayoutDirectionAuto )
|
||||
data.direction = QGuiApplication::layoutDirection();
|
||||
|
||||
m_data->layoutData = &data;
|
||||
layoutItems();
|
||||
m_data->layoutData = nullptr;
|
||||
}
|
||||
|
||||
void QskLayoutEngine2D::layoutItem( QQuickItem* item,
|
||||
const QRect& grid, Qt::Alignment alignment ) const
|
||||
{
|
||||
auto layoutData = m_data->layoutData;
|
||||
|
||||
if ( layoutData == nullptr || item == nullptr )
|
||||
return;
|
||||
|
||||
alignment = m_data->effectiveAlignment( alignment );
|
||||
|
||||
QRectF rect = layoutData->geometryAt( grid );
|
||||
rect = QskLayoutConstraint::itemRect(item, rect, alignment );
|
||||
|
||||
if ( layoutData->direction == Qt::RightToLeft )
|
||||
{
|
||||
const auto& r = layoutData->rect;
|
||||
rect.moveRight( r.right() - ( rect.left() - r.left() ) );
|
||||
}
|
||||
|
||||
qskSetItemGeometry( item, rect );
|
||||
}
|
||||
|
||||
qreal QskLayoutEngine2D::widthForHeight( qreal height ) const
|
||||
{
|
||||
const QSizeF constraint( -1, height );
|
||||
return sizeHint( Qt::PreferredSize, constraint ).width();
|
||||
}
|
||||
|
||||
qreal QskLayoutEngine2D::heightForWidth( qreal width ) const
|
||||
{
|
||||
const QSizeF constraint( width, -1 );
|
||||
return sizeHint( Qt::PreferredSize, constraint ).height();
|
||||
}
|
||||
|
||||
QSizeF QskLayoutEngine2D::sizeHint(
|
||||
Qt::SizeHint which, const QSizeF& constraint ) const
|
||||
{
|
||||
if ( effectiveCount( Qt::Horizontal ) <= 0 )
|
||||
return QSizeF( 0.0, 0.0 );
|
||||
|
||||
auto& rowChain = m_data->rowChain;
|
||||
auto& columnChain = m_data->columnChain;
|
||||
|
||||
m_data->blockInvalidate = true;
|
||||
|
||||
if ( ( constraint.width() >= 0 ) &&
|
||||
( constraintType() == QskLayoutConstraint::HeightForWidth ) )
|
||||
{
|
||||
setupChain( Qt::Horizontal );
|
||||
|
||||
const auto constraints = columnChain.segments( constraint.width() );
|
||||
setupChain( Qt::Vertical, constraints );
|
||||
}
|
||||
else if ( ( constraint.height() >= 0 ) &&
|
||||
( constraintType() == QskLayoutConstraint::WidthForHeight ) )
|
||||
{
|
||||
setupChain( Qt::Vertical );
|
||||
|
||||
const auto constraints = rowChain.segments( constraint.height() );
|
||||
setupChain( Qt::Horizontal, constraints );
|
||||
}
|
||||
else
|
||||
{
|
||||
setupChain( Qt::Horizontal );
|
||||
setupChain( Qt::Vertical );
|
||||
}
|
||||
|
||||
m_data->blockInvalidate = false;
|
||||
|
||||
const qreal width = columnChain.boundingHint().size( which );
|
||||
const qreal height = rowChain.boundingHint().size( which );
|
||||
|
||||
return QSizeF( width, height );
|
||||
}
|
||||
|
||||
void QskLayoutEngine2D::setupChain( Qt::Orientation orientation ) const
|
||||
{
|
||||
setupChain( orientation, QskLayoutChain::Segments() );
|
||||
}
|
||||
|
||||
void QskLayoutEngine2D::setupChain( Qt::Orientation orientation,
|
||||
const QskLayoutChain::Segments& constraints ) const
|
||||
{
|
||||
const auto count = effectiveCount( orientation );
|
||||
const qreal constraint =
|
||||
constraints.isEmpty() ? -1.0 : constraints.last().end();
|
||||
|
||||
auto& chain = m_data->layoutChain( orientation );
|
||||
|
||||
if ( ( chain.constraint() == constraint )
|
||||
&& ( chain.count() == count ) )
|
||||
{
|
||||
return; // already up to date
|
||||
}
|
||||
|
||||
chain.reset( count, constraint );
|
||||
setupChain( orientation, constraints, chain );
|
||||
chain.finish();
|
||||
|
||||
#if 0
|
||||
qDebug() << "==" << this << orientation << chain.count();
|
||||
|
||||
for ( int i = 0; i < chain.count(); i++ )
|
||||
qDebug() << i << ":" << chain.cell( i );
|
||||
#endif
|
||||
}
|
||||
|
||||
void QskLayoutEngine2D::updateSegments( const QSizeF& size ) const
|
||||
{
|
||||
auto& rowChain = m_data->rowChain;
|
||||
auto& colLine = m_data->columnChain;
|
||||
|
||||
auto& rows = m_data->rows;
|
||||
auto& columns = m_data->columns;
|
||||
|
||||
m_data->blockInvalidate = true;
|
||||
|
||||
switch( constraintType() )
|
||||
{
|
||||
case QskLayoutConstraint::WidthForHeight:
|
||||
{
|
||||
setupChain( Qt::Vertical );
|
||||
rows = rowChain.segments( size.height() );
|
||||
|
||||
setupChain( Qt::Horizontal, rows );
|
||||
columns = colLine.segments( size.width() );
|
||||
|
||||
break;
|
||||
}
|
||||
case QskLayoutConstraint::HeightForWidth:
|
||||
{
|
||||
setupChain( Qt::Horizontal );
|
||||
columns = colLine.segments( size.width() );
|
||||
|
||||
setupChain( Qt::Vertical, m_data->columns );
|
||||
rows = rowChain.segments( size.height() );
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
setupChain( Qt::Horizontal );
|
||||
columns = colLine.segments( size.width() );
|
||||
|
||||
setupChain( Qt::Vertical );
|
||||
rows = rowChain.segments( size.height() );
|
||||
}
|
||||
}
|
||||
|
||||
m_data->blockInvalidate = false;
|
||||
}
|
||||
|
||||
void QskLayoutEngine2D::invalidate( int what )
|
||||
{
|
||||
if ( m_data->blockInvalidate )
|
||||
return;
|
||||
|
||||
if ( what & ElementCache )
|
||||
{
|
||||
m_data->constraintType = -1;
|
||||
invalidateElementCache();
|
||||
}
|
||||
|
||||
if ( what & LayoutCache )
|
||||
{
|
||||
m_data->rowChain.invalidate();
|
||||
m_data->columnChain.invalidate();
|
||||
|
||||
m_data->layoutSize = QSize();
|
||||
m_data->rows.clear();
|
||||
m_data->columns.clear();
|
||||
}
|
||||
}
|
||||
|
||||
QskLayoutConstraint::Type QskLayoutEngine2D::constraintType() const
|
||||
{
|
||||
if ( m_data->constraintType < 0 )
|
||||
{
|
||||
auto constraintType = QskLayoutConstraint::Unconstrained;
|
||||
|
||||
for ( int i = 0; i < count(); i++ )
|
||||
{
|
||||
const auto type = QskLayoutConstraint::constraintType( itemAt( i ) );
|
||||
|
||||
using namespace QskLayoutConstraint;
|
||||
|
||||
if ( type != Unconstrained )
|
||||
{
|
||||
if ( constraintType == Unconstrained )
|
||||
{
|
||||
constraintType = type;
|
||||
}
|
||||
else if ( constraintType != type )
|
||||
{
|
||||
qWarning( "QskLayoutEngine2D: conflicting constraints");
|
||||
constraintType = Unconstrained;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_data->constraintType = constraintType;
|
||||
}
|
||||
|
||||
return static_cast< QskLayoutConstraint::Type >( m_data->constraintType );
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_LAYOUT_ENGINE_2D_H
|
||||
#define QSK_LAYOUT_ENGINE_2D_H
|
||||
|
||||
#include "QskGlobal.h"
|
||||
#include "QskLayoutChain.h"
|
||||
#include "QskLayoutConstraint.h"
|
||||
|
||||
#include <qnamespace.h>
|
||||
#include <memory>
|
||||
|
||||
class QskLayoutEngine2D
|
||||
{
|
||||
public:
|
||||
QskLayoutEngine2D();
|
||||
virtual ~QskLayoutEngine2D();
|
||||
|
||||
virtual int count() const = 0;
|
||||
|
||||
virtual QQuickItem* itemAt( int index ) const = 0;
|
||||
virtual qreal spacerAt( int index ) const = 0;
|
||||
|
||||
int indexOf( const QQuickItem* ) const;
|
||||
|
||||
int rowCount() const;
|
||||
int columnCount() const;
|
||||
|
||||
bool setVisualDirection( Qt::LayoutDirection );
|
||||
Qt::LayoutDirection visualDirection() const;
|
||||
|
||||
bool setDefaultAlignment( Qt::Alignment );
|
||||
Qt::Alignment defaultAlignment() const;
|
||||
|
||||
bool setExtraSpacingAt( Qt::Edges edges );
|
||||
Qt::Edges extraSpacingAt() const;
|
||||
|
||||
bool setSpacing( qreal spacing, Qt::Orientations );
|
||||
qreal spacing( Qt::Orientation ) const;
|
||||
|
||||
qreal defaultSpacing( Qt::Orientation ) const;
|
||||
|
||||
void invalidate();
|
||||
|
||||
qreal widthForHeight( qreal height ) const;
|
||||
qreal heightForWidth( qreal width ) const;
|
||||
|
||||
QSizeF sizeHint( Qt::SizeHint, const QSizeF& constraint ) const;
|
||||
|
||||
void setGeometries( const QRectF& );
|
||||
|
||||
protected:
|
||||
|
||||
void layoutItem( QQuickItem*,
|
||||
const QRect& grid, Qt::Alignment ) const;
|
||||
|
||||
enum
|
||||
{
|
||||
ElementCache = 1 << 0,
|
||||
LayoutCache = 1 << 1
|
||||
};
|
||||
|
||||
void invalidate( int what );
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY( QskLayoutEngine2D )
|
||||
|
||||
void updateSegments( const QSizeF& ) const;
|
||||
|
||||
virtual void layoutItems() = 0;
|
||||
virtual int effectiveCount( Qt::Orientation ) const = 0;
|
||||
|
||||
virtual void invalidateElementCache() = 0;
|
||||
QskLayoutConstraint::Type constraintType() const;
|
||||
|
||||
void setupChain( Qt::Orientation ) const;
|
||||
void setupChain( Qt::Orientation, const QskLayoutChain::Segments& ) const;
|
||||
|
||||
virtual void setupChain( Qt::Orientation,
|
||||
const QskLayoutChain::Segments&, QskLayoutChain& ) const = 0;
|
||||
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
};
|
||||
|
||||
inline void QskLayoutEngine2D::invalidate()
|
||||
{
|
||||
invalidate( ElementCache | LayoutCache );
|
||||
}
|
||||
|
||||
inline int QskLayoutEngine2D::rowCount() const
|
||||
{
|
||||
return effectiveCount( Qt::Vertical );
|
||||
}
|
||||
|
||||
inline int QskLayoutEngine2D::columnCount() const
|
||||
{
|
||||
return effectiveCount( Qt::Horizontal );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -58,15 +58,6 @@ void QskLayoutHint::setSize( int which, qreal size )
|
|||
}
|
||||
}
|
||||
|
||||
void QskLayoutHint::expandTo( const QskLayoutHint& other )
|
||||
{
|
||||
const auto hint = other.normalized();
|
||||
|
||||
m_minimum = qMax( m_minimum, hint.m_minimum );
|
||||
m_preferred = qMax( m_preferred, hint.m_preferred );
|
||||
m_maximum = qMax( m_maximum, hint.m_maximum );
|
||||
}
|
||||
|
||||
void QskLayoutHint::normalize()
|
||||
{
|
||||
m_minimum = qMax( m_minimum, qreal( 0.0 ) );
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ class QSK_EXPORT QskLayoutHint
|
|||
QskLayoutHint();
|
||||
QskLayoutHint( qreal minimum, qreal preferred, qreal maximum );
|
||||
|
||||
void expandTo( const QskLayoutHint& );
|
||||
void normalize();
|
||||
|
||||
QskLayoutHint normalized() const;
|
||||
|
|
@ -38,6 +37,8 @@ class QSK_EXPORT QskLayoutHint
|
|||
void setMaximum( qreal value );
|
||||
qreal maximum() const;
|
||||
|
||||
void setSizes( qreal minimum, qreal preferred, qreal maximum );
|
||||
|
||||
private:
|
||||
qreal m_minimum;
|
||||
qreal m_preferred;
|
||||
|
|
@ -74,6 +75,14 @@ inline void QskLayoutHint::setMaximum( qreal value )
|
|||
m_maximum = value;
|
||||
}
|
||||
|
||||
inline void QskLayoutHint::setSizes(
|
||||
qreal minimum, qreal preferred, qreal maximum )
|
||||
{
|
||||
m_minimum = minimum;
|
||||
m_preferred = preferred;
|
||||
m_maximum = maximum;
|
||||
}
|
||||
|
||||
inline bool QskLayoutHint::operator==( const QskLayoutHint& other ) const
|
||||
{
|
||||
return ( m_preferred == other.m_preferred )
|
||||
|
|
|
|||
|
|
@ -94,26 +94,7 @@ QQuickItem* QskLinearBox::itemAtIndex( int index ) const
|
|||
|
||||
int QskLinearBox::indexOf( const QQuickItem* item ) const
|
||||
{
|
||||
if ( item )
|
||||
{
|
||||
/*
|
||||
Linear search might become slow for many items,
|
||||
better introduce some sort of hash table TODO ...
|
||||
|
||||
indexOf is often used for configuring an item
|
||||
after inserting it. So we iterate in reverse order
|
||||
*/
|
||||
|
||||
const auto& engine = m_data->engine;
|
||||
|
||||
for ( int i = engine.count() - 1; i >= 0; --i )
|
||||
{
|
||||
if ( engine.itemAt( i ) == item )
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return m_data->engine.indexOf( item );
|
||||
}
|
||||
|
||||
void QskLinearBox::removeAt( int index )
|
||||
|
|
@ -398,16 +379,16 @@ Qt::Edges QskLinearBox::extraSpacingAt() const
|
|||
return m_data->engine.extraSpacingAt();
|
||||
}
|
||||
|
||||
void QskLinearBox::addItem( QQuickItem* item, Qt::Alignment alignment )
|
||||
int QskLinearBox::addItem( QQuickItem* item, Qt::Alignment alignment )
|
||||
{
|
||||
insertItem( -1, item, alignment );
|
||||
return insertItem( -1, item, alignment );
|
||||
}
|
||||
|
||||
void QskLinearBox::insertItem(
|
||||
int QskLinearBox::insertItem(
|
||||
int index, QQuickItem* item, Qt::Alignment alignment )
|
||||
{
|
||||
if ( item == nullptr )
|
||||
return;
|
||||
return -1;
|
||||
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
|
|
@ -424,7 +405,7 @@ void QskLinearBox::insertItem(
|
|||
( doAppend && oldIndex == engine.count() - 1 ) )
|
||||
{
|
||||
// already at its position, nothing to do
|
||||
return;
|
||||
return oldIndex;
|
||||
}
|
||||
|
||||
removeAt( oldIndex );
|
||||
|
|
@ -433,11 +414,7 @@ void QskLinearBox::insertItem(
|
|||
|
||||
reparentItem( item );
|
||||
|
||||
const int numItems = engine.count();
|
||||
if ( index < 0 || index > numItems )
|
||||
index = numItems;
|
||||
|
||||
engine.insertItem( item, index );
|
||||
index = engine.insertItem( item, index );
|
||||
engine.setAlignmentAt( index, alignment );
|
||||
|
||||
// Re-ordering the child items to have a a proper focus tab chain
|
||||
|
|
@ -472,14 +449,16 @@ void QskLinearBox::insertItem(
|
|||
resetImplicitSize();
|
||||
polish();
|
||||
#endif
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void QskLinearBox::addSpacer( qreal spacing, int stretchFactor )
|
||||
int QskLinearBox::addSpacer( qreal spacing, int stretchFactor )
|
||||
{
|
||||
insertSpacer( -1, spacing, stretchFactor );
|
||||
return insertSpacer( -1, spacing, stretchFactor );
|
||||
}
|
||||
|
||||
void QskLinearBox::insertSpacer( int index, qreal spacing, int stretchFactor )
|
||||
int QskLinearBox::insertSpacer( int index, qreal spacing, int stretchFactor )
|
||||
{
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
|
|
@ -487,7 +466,7 @@ void QskLinearBox::insertSpacer( int index, qreal spacing, int stretchFactor )
|
|||
if ( index < 0 || index > numItems )
|
||||
index = numItems;
|
||||
|
||||
engine.insertSpacerAt( index, spacing );
|
||||
index = engine.insertSpacerAt( index, spacing );
|
||||
|
||||
stretchFactor = qMax( stretchFactor, 0 );
|
||||
engine.setStretchFactorAt( index, stretchFactor );
|
||||
|
|
@ -497,16 +476,18 @@ void QskLinearBox::insertSpacer( int index, qreal spacing, int stretchFactor )
|
|||
resetImplicitSize();
|
||||
polish();
|
||||
#endif
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void QskLinearBox::addStretch( int stretchFactor )
|
||||
int QskLinearBox::addStretch( int stretchFactor )
|
||||
{
|
||||
insertSpacer( -1, 0, stretchFactor );
|
||||
return insertSpacer( -1, 0, stretchFactor );
|
||||
}
|
||||
|
||||
void QskLinearBox::insertStretch( int index, int stretchFactor )
|
||||
int QskLinearBox::insertStretch( int index, int stretchFactor )
|
||||
{
|
||||
insertSpacer( index, 0, stretchFactor );
|
||||
return insertSpacer( index, 0, stretchFactor );
|
||||
}
|
||||
|
||||
void QskLinearBox::setAlignment( int index, Qt::Alignment alignment )
|
||||
|
|
|
|||
|
|
@ -75,17 +75,17 @@ class QSK_EXPORT QskLinearBox : public QskIndexedLayoutBox
|
|||
void resetSpacing();
|
||||
qreal spacing() const;
|
||||
|
||||
Q_INVOKABLE void addItem(
|
||||
Q_INVOKABLE int addItem(
|
||||
QQuickItem*, Qt::Alignment alignment = Qt::Alignment() );
|
||||
|
||||
Q_INVOKABLE void insertItem(
|
||||
Q_INVOKABLE int insertItem(
|
||||
int index, QQuickItem*, Qt::Alignment alignment = Qt::Alignment() );
|
||||
|
||||
Q_INVOKABLE void addSpacer( qreal spacing, int stretchFactor = 0 );
|
||||
Q_INVOKABLE void insertSpacer( int index, qreal spacing, int stretchFactor = 0 );
|
||||
Q_INVOKABLE int addSpacer( qreal spacing, int stretchFactor = 0 );
|
||||
Q_INVOKABLE int insertSpacer( int index, qreal spacing, int stretchFactor = 0 );
|
||||
|
||||
Q_INVOKABLE void addStretch( int stretchFactor = 0 );
|
||||
Q_INVOKABLE void insertStretch( int index, int stretchFactor = 0 );
|
||||
Q_INVOKABLE int addStretch( int stretchFactor = 0 );
|
||||
Q_INVOKABLE int insertStretch( int index, int stretchFactor = 0 );
|
||||
|
||||
Q_INVOKABLE void setStretchFactor( int index, int stretchFactor );
|
||||
Q_INVOKABLE int stretchFactor( int index ) const;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -7,6 +7,7 @@
|
|||
#define QSK_LINEAR_LAYOUT_ENGINE_H
|
||||
|
||||
#include "QskGlobal.h"
|
||||
#include "QskLayoutEngine2D.h"
|
||||
|
||||
#include <qnamespace.h>
|
||||
#include <memory>
|
||||
|
|
@ -15,11 +16,11 @@ class QQuickItem;
|
|||
class QSizeF;
|
||||
class QRectF;
|
||||
|
||||
class QskLinearLayoutEngine
|
||||
class QskLinearLayoutEngine : public QskLayoutEngine2D
|
||||
{
|
||||
public:
|
||||
QskLinearLayoutEngine( Qt::Orientation, uint dimension );
|
||||
~QskLinearLayoutEngine();
|
||||
~QskLinearLayoutEngine() override;
|
||||
|
||||
Qt::Orientation orientation() const;
|
||||
bool setOrientation( Qt::Orientation );
|
||||
|
|
@ -27,36 +28,19 @@ class QskLinearLayoutEngine
|
|||
bool setDimension( uint dimension );
|
||||
uint dimension() const;
|
||||
|
||||
bool setDefaultAlignment( Qt::Alignment );
|
||||
Qt::Alignment defaultAlignment() const;
|
||||
int count() const override final;
|
||||
|
||||
bool setExtraSpacingAt( Qt::Edges );
|
||||
Qt::Edges extraSpacingAt() const;
|
||||
int insertItem( QQuickItem*, int index );
|
||||
int addItem( QQuickItem* );
|
||||
|
||||
bool setVisualDirection( Qt::LayoutDirection );
|
||||
Qt::LayoutDirection visualDirection() const;
|
||||
int insertSpacerAt( int index, qreal spacing );
|
||||
int addSpacer( qreal spacing );
|
||||
|
||||
bool setSpacing( qreal spacing, Qt::Orientations );
|
||||
qreal spacing( Qt::Orientation ) const;
|
||||
bool removeAt( int index );
|
||||
bool clear();
|
||||
|
||||
qreal defaultSpacing( Qt::Orientation ) const;
|
||||
|
||||
int count() const;
|
||||
|
||||
int rowCount() const;
|
||||
int columnCount() const;
|
||||
|
||||
void insertItem( QQuickItem*, int index );
|
||||
void addItem( QQuickItem* );
|
||||
|
||||
void insertSpacerAt( int index, qreal spacing );
|
||||
void addSpacer( qreal spacing );
|
||||
|
||||
void removeAt( int index );
|
||||
void clear();
|
||||
|
||||
QQuickItem* itemAt( int index ) const;
|
||||
int spacerAt( int index ) const;
|
||||
QQuickItem* itemAt( int index ) const override final;
|
||||
qreal spacerAt( int index ) const override final;
|
||||
|
||||
bool setRetainSizeWhenHiddenAt( int index, bool on );
|
||||
bool retainSizeWhenHiddenAt( int index ) const;
|
||||
|
|
@ -67,30 +51,31 @@ class QskLinearLayoutEngine
|
|||
bool setStretchFactorAt( int index, int stretchFactor );
|
||||
int stretchFactorAt( int index ) const;
|
||||
|
||||
void setGeometries( const QRectF& );
|
||||
|
||||
qreal widthForHeight( qreal height ) const;
|
||||
qreal heightForWidth( qreal width ) const;
|
||||
|
||||
QSizeF sizeHint( Qt::SizeHint, const QSizeF& contraint ) const;
|
||||
|
||||
enum
|
||||
{
|
||||
EntryCache = 1 << 0,
|
||||
CellCache = 1 << 1,
|
||||
LayoutCache = 1 << 2
|
||||
};
|
||||
|
||||
void invalidate( int what = EntryCache | CellCache | LayoutCache );
|
||||
|
||||
private:
|
||||
void updateCellGeometries( const QSizeF& );
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QskLinearLayoutEngine)
|
||||
|
||||
void layoutItems() override;
|
||||
|
||||
int effectiveCount() const;
|
||||
int effectiveCount( Qt::Orientation ) const override;
|
||||
|
||||
void invalidateElementCache() override;
|
||||
|
||||
virtual void setupChain( Qt::Orientation,
|
||||
const QskLayoutChain::Segments&, QskLayoutChain& ) const override;
|
||||
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
};
|
||||
|
||||
inline int QskLinearLayoutEngine::addItem( QQuickItem* item )
|
||||
{
|
||||
return insertItem( item, -1 );
|
||||
}
|
||||
|
||||
inline int QskLinearLayoutEngine::addSpacer( qreal spacing )
|
||||
{
|
||||
return insertSpacerAt( -1, spacing );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
10
src/src.pro
10
src/src.pro
|
|
@ -9,6 +9,8 @@ QSK_SUBDIRS = common graphic nodes controls layouts dialogs inputpanel
|
|||
INCLUDEPATH *= $${QSK_SUBDIRS}
|
||||
DEPENDPATH *= $${QSK_SUBDIRS}
|
||||
|
||||
# DEFINES += QSK_LAYOUT_COMPAT
|
||||
|
||||
HEADERS += \
|
||||
common/QskAspect.h \
|
||||
common/QskBoxBorderColors.h \
|
||||
|
|
@ -236,8 +238,9 @@ HEADERS += \
|
|||
layouts/QskGridLayoutEngine.h \
|
||||
layouts/QskIndexedLayoutBox.h \
|
||||
layouts/QskLayoutConstraint.h \
|
||||
layouts/QskLayoutHint.h \
|
||||
layouts/QskLayoutChain.h \
|
||||
layouts/QskLayoutEngine2D.cpp \
|
||||
layouts/QskLayoutHint.h \
|
||||
layouts/QskLinearBox.h \
|
||||
layouts/QskLinearLayoutEngine.h \
|
||||
layouts/QskStackBoxAnimator.h \
|
||||
|
|
@ -247,9 +250,10 @@ SOURCES += \
|
|||
layouts/QskGridBox.cpp \
|
||||
layouts/QskGridLayoutEngine.cpp \
|
||||
layouts/QskIndexedLayoutBox.cpp \
|
||||
layouts/QskLayoutConstraint.cpp \
|
||||
layouts/QskLayoutHint.cpp \
|
||||
layouts/QskLayoutChain.cpp \
|
||||
layouts/QskLayoutConstraint.cpp \
|
||||
layouts/QskLayoutEngine2D.cpp \
|
||||
layouts/QskLayoutHint.cpp \
|
||||
layouts/QskLinearBox.cpp \
|
||||
layouts/QskLinearLayoutEngine.cpp \
|
||||
layouts/QskStackBoxAnimator.cpp \
|
||||
|
|
|
|||
Loading…
Reference in New Issue