7#include "QskGridLayoutEngine.h"
13static void qskSetItemActive( QObject* receiver,
const QQuickItem* item,
bool on )
22 auto sendLayoutRequest =
25 QEvent event( QEvent::LayoutRequest );
26 QCoreApplication::sendEvent( receiver, &event );
29 QObject::connect( item, &QQuickItem::implicitWidthChanged,
30 receiver, sendLayoutRequest );
32 QObject::connect( item, &QQuickItem::implicitHeightChanged,
33 receiver, sendLayoutRequest );
37 QObject::disconnect( item, &QQuickItem::implicitWidthChanged, receiver,
nullptr );
38 QObject::disconnect( item, &QQuickItem::implicitHeightChanged, receiver,
nullptr );
42static void qskUpdateFocusChain(
44 QQuickItem* item,
const QRect& grid )
51 const int cellIndex = grid.y() * engine->columnCount() + grid.x();
53 QQuickItem* itemNext =
nullptr;
56 for (
int i = 0; i < engine->count(); i++ )
58 const auto itemAt = engine->itemAt( i );
60 if ( itemAt && item != itemAt )
62 const auto gridAt = engine->gridAt( i );
63 const int delta = gridAt.y() * engine->columnCount() + gridAt.x() - cellIndex;
67 if ( itemNext ==
nullptr || delta < minDelta )
78 item->stackBefore( itemNext );
82 const auto itemLast = box->childItems().constLast();
83 if ( itemLast != item )
84 item->stackAfter( itemLast );
88class QskGridBox::PrivateData
92 bool blockAutoRemove =
false;
95QskGridBox::QskGridBox( QQuickItem* parent )
97 , m_data( new PrivateData() )
101QskGridBox::~QskGridBox()
103 auto& engine = m_data->engine;
105 for (
int i = 0; i < engine.count(); i++ )
107 if (
auto item = engine.itemAt( i ) )
108 setItemActive( item,
false );
112int QskGridBox::addItem( QQuickItem* item,
113 int row,
int column, Qt::Alignment alignment )
115 if (
auto control = qskControlCast( item ) )
116 control->setLayoutAlignmentHint( alignment );
118 return addItem( item, row, column );
121int QskGridBox::addItem( QQuickItem* item,
122 int row,
int column,
int rowSpan,
int columnSpan, Qt::Alignment alignment )
124 if (
auto control = qskControlCast( item ) )
125 control->setLayoutAlignmentHint( alignment );
127 return addItem( item, row, column, rowSpan, columnSpan );
130int QskGridBox::addItem( QQuickItem* item,
131 int row,
int column,
int rowSpan,
int columnSpan )
133 if ( item ==
nullptr || item ==
this || row < 0 || column < 0 )
136 if ( !qskPlacementPolicy( item ).isEffective() )
138 qWarning() <<
"Inserting an item that is to be ignored for layouting:"
139 << item->metaObject()->className();
144 rowSpan = qMax( rowSpan, -1 );
145 columnSpan = qMax( columnSpan, -1 );
147 auto& engine = m_data->engine;
149 const QRect itemGrid( column, row, columnSpan, rowSpan );
152 if ( item->parentItem() ==
this )
154 index = indexOf( item );
157 if ( engine.gridAt( index ) == itemGrid )
164 if ( item->parent() ==
nullptr )
165 item->setParent(
this );
167 if ( item->parentItem() !=
this )
168 item->setParentItem(
this );
170 setItemActive( item,
true );
171 index = engine.insertItem( item, itemGrid );
174 if ( engine.count() > 1 )
175 qskUpdateFocusChain(
this, &engine, item, itemGrid );
183int QskGridBox::addSpacer(
const QSizeF& spacing,
184 int row,
int column,
int rowSpan,
int columnSpan )
186 const int index = m_data->engine.insertSpacer(
187 spacing, QRect( column, row, columnSpan, rowSpan ) );
195int QskGridBox::addColumnSpacer( qreal spacing,
int column )
197 return addSpacer( QSizeF( spacing, 0.0 ), 0, column );
200int QskGridBox::addRowSpacer( qreal spacing,
int row )
202 return addSpacer( QSizeF( 0.0, spacing ), row, 0 );
205void QskGridBox::removeAt(
int index )
207 auto& engine = m_data->engine;
209 if (
auto item = engine.itemAt( index ) )
210 setItemActive( item,
false );
212 engine.removeAt( index );
218void QskGridBox::removeItem(
const QQuickItem* item )
220 removeAt( indexOf( item ) );
223void QskGridBox::clear(
bool autoDelete )
225 m_data->blockAutoRemove =
true;
227 for (
int i = 0; i < elementCount(); i++ )
229 if (
auto item = itemAtIndex( i ) )
231 setItemActive( item,
false );
233 if( autoDelete && ( item->parent() ==
this ) )
236 item->setParentItem(
nullptr );
240 m_data->blockAutoRemove =
false;
242 m_data->engine.clear();
245int QskGridBox::elementCount()
const
247 return m_data->engine.count();
250int QskGridBox::rowCount()
const
252 return m_data->engine.rowCount();
255int QskGridBox::columnCount()
const
257 return m_data->engine.columnCount();
260QQuickItem* QskGridBox::itemAtIndex(
int index )
const
262 return m_data->engine.itemAt( index );
265int QskGridBox::indexOf(
const QQuickItem* item )
const
267 return m_data->engine.indexOf( item );
270QQuickItem* QskGridBox::itemAt(
int row,
int column )
const
272 return m_data->engine.itemAt( row, column );
275int QskGridBox::indexAt(
int row,
int column )
const
277 return m_data->engine.indexAt( row, column );
280QRect QskGridBox::gridOfIndex(
int index )
const
282 return m_data->engine.gridAt( index );
285QRect QskGridBox::effectiveGridOfIndex(
int index )
const
287 return m_data->engine.effectiveGridAt( index );
290void QskGridBox::setDefaultAlignment( Qt::Alignment alignment )
292 if ( m_data->engine.setDefaultAlignment( alignment ) )
293 Q_EMIT defaultAlignmentChanged();
296Qt::Alignment QskGridBox::defaultAlignment()
const
298 return m_data->engine.defaultAlignment();
301void QskGridBox::setSpacing( Qt::Orientations orientations, qreal spacing )
303 if ( m_data->engine.setSpacing( spacing, orientations ) )
310void QskGridBox::resetSpacing( Qt::Orientations orientations )
312 for (
const auto o : { Qt::Horizontal, Qt::Vertical } )
314 if ( orientations & o )
315 setSpacing( o, m_data->engine.defaultSpacing( o ) );
319qreal QskGridBox::spacing( Qt::Orientation orientation )
const
321 return m_data->engine.spacing( orientation );
324void QskGridBox::setRowStretchFactor(
int row,
int stretch )
326 if ( m_data->engine.setStretchFactor( row, stretch, Qt::Vertical ) )
330int QskGridBox::rowStretchFactor(
int row )
const
332 return m_data->engine.stretchFactor( row, Qt::Vertical );
335void QskGridBox::setColumnStretchFactor(
int column,
int stretch )
337 if ( m_data->engine.setStretchFactor( column, stretch, Qt::Horizontal ) )
341int QskGridBox::columnStretchFactor(
int column )
const
343 return m_data->engine.stretchFactor( column, Qt::Horizontal );
346void QskGridBox::setRowFixedHeight(
int row, qreal height )
348 setRowHeightHint( row, Qt::MinimumSize, height );
349 setRowHeightHint( row, Qt::MaximumSize, height );
352void QskGridBox::setColumnFixedWidth(
int column, qreal width )
354 setColumnWidthHint( column, Qt::MinimumSize, width );
355 setColumnWidthHint( column, Qt::MaximumSize, width );
358void QskGridBox::setRowHeightHint(
int row, Qt::SizeHint which, qreal height )
360 if ( m_data->engine.setRowSizeHint( row, which, height ) )
364qreal QskGridBox::rowHeightHint(
int row, Qt::SizeHint which )
const
366 return m_data->engine.rowSizeHint( row, which );
369void QskGridBox::setColumnWidthHint(
int column, Qt::SizeHint which, qreal width )
371 if ( m_data->engine.setColumnSizeHint( column, which, width ) )
375qreal QskGridBox::columnWidthHint(
int column, Qt::SizeHint which )
const
377 return m_data->engine.columnSizeHint( column, which );
380void QskGridBox::invalidate()
382 m_data->engine.invalidate();
388void QskGridBox::setItemActive( QQuickItem* item,
bool on )
392 QObject::connect( item, &QQuickItem::visibleChanged,
393 this, &QskGridBox::invalidate );
397 QObject::disconnect( item, &QQuickItem::visibleChanged,
398 this, &QskGridBox::invalidate );
401 if ( qskControlCast( item ) ==
nullptr )
402 qskSetItemActive(
this, item, on );
405void QskGridBox::updateLayout()
411QSizeF QskGridBox::layoutSizeHint(
412 Qt::SizeHint which,
const QSizeF& constraint )
const
414 if ( which == Qt::MaximumSize )
420 return m_data->engine.sizeHint( which, constraint );
427 if ( event->isResized() )
431void QskGridBox::itemChange( ItemChange change,
const ItemChangeData& value )
437 case ItemChildRemovedChange:
439 if ( !m_data->blockAutoRemove )
440 removeItem( value.item );
443 case QQuickItem::ItemVisibleHasChanged:
445 if ( value.boolValue )
449 case QQuickItem::ItemSceneChange:
460bool QskGridBox::event( QEvent* event )
462 switch (
static_cast< int >( event->type() ) )
464 case QEvent::LayoutRequest:
469 case QEvent::LayoutDirectionChange:
471 m_data->engine.setVisualDirection(
477 case QEvent::ContentsRectChange:
484 return Inherited::event( event );
487void QskGridBox::dump()
const
489 const auto& engine = m_data->engine;
491 auto debug = qDebug();
493 QDebugStateSaver saver(
debug );
498 debug <<
"QskGridBox"
499 <<
"[" << engine.columnCount() <<
"," << engine.rowCount() <<
"] w:"
500 << constraint.width() <<
" h:" << constraint.height() <<
'\n';
502 for (
int i = 0; i < engine.count(); i++ )
504 const auto grid = engine.gridAt( i );
508 debug << grid.left();
509 if ( grid.width() > 1 )
510 debug <<
"-" << grid.right();
514 if ( grid.height() > 1 )
515 debug <<
"->" << grid.bottom();
519 if (
auto item = engine.itemAt( i ) )
521 const auto size = qskSizeConstraint( item, Qt::PreferredSize );
523 debug << item->metaObject()->className()
524 <<
" w:" << size.width() <<
" h:" << size.height();
528 const auto size = engine.spacerAt( i );
529 debug <<
"spacer w:" << size.width() <<
" h:" << size.height();
536#include "moc_QskGridBox.cpp"
void itemChange(ItemChange, const ItemChangeData &) override
QRectF layoutRect() const
void geometryChangeEvent(QskGeometryChangeEvent *) override
virtual void geometryChangeEvent(QskGeometryChangeEvent *)
bool maybeUnresized() const
bool layoutMirroring() const
void debug(QskAspect) const