6#include "QskStackBox.h"
7#include "QskStackBoxAnimator.h"
13class QskStackBox::PrivateData
16 QVector< QQuickItem* > items;
17 QPointer< QskStackBoxAnimator > animator;
19 int currentIndex = -1;
20 Qt::Alignment defaultAlignment = Qt::AlignLeft | Qt::AlignVCenter;
23QskStackBox::QskStackBox( QQuickItem* parent )
28QskStackBox::QskStackBox(
bool autoAddChildren, QQuickItem* parent )
30 , m_data( new PrivateData() )
32 setAutoAddChildren( autoAddChildren );
35QskStackBox::~QskStackBox()
39void QskStackBox::setDefaultAlignment( Qt::Alignment alignment )
41 if ( alignment != m_data->defaultAlignment )
43 m_data->defaultAlignment = alignment;
44 Q_EMIT defaultAlignmentChanged( alignment );
50Qt::Alignment QskStackBox::defaultAlignment()
const
52 return m_data->defaultAlignment;
57 if ( m_data->animator == animator )
60 if ( m_data->animator )
62 m_data->animator->stop();
63 delete m_data->animator;
69 animator->setParent(
this );
72 m_data->animator = animator;
77 return m_data->animator;
82 return m_data->animator;
87 if ( m_data->animator )
88 return m_data->animator;
95int QskStackBox::itemCount()
const
97 return m_data->items.count();
100QQuickItem* QskStackBox::itemAtIndex(
int index )
const
102 return m_data->items.value( index );
105int QskStackBox::indexOf(
const QQuickItem* item )
const
107 if ( item && ( item->parentItem() ==
this ) )
109 for (
int i = 0; i < m_data->items.count(); i++ )
111 if ( item == m_data->items[i] )
119QQuickItem* QskStackBox::currentItem()
const
121 return itemAtIndex( m_data->currentIndex );
124int QskStackBox::currentIndex()
const
126 return m_data->currentIndex;
129void QskStackBox::setCurrentIndex(
int index )
131 if ( index < 0 || index >= itemCount() )
137 if ( index == m_data->currentIndex )
141 auto animator = effectiveAnimator();
148 animator->setStartIndex( m_data->currentIndex );
149 animator->setEndIndex( index );
150 animator->setWindow( window() );
155 auto item1 = itemAtIndex( m_data->currentIndex );
156 auto item2 = itemAtIndex( index );
159 item1->setVisible(
false );
162 item2->setVisible(
true );
165 m_data->currentIndex = index;
168 Q_EMIT currentIndexChanged( m_data->currentIndex );
171qreal QskStackBox::transientIndex()
const
173 if (
auto animator = m_data->animator )
175 if ( animator->isRunning() )
176 return animator->transientIndex();
179 return currentIndex();
182void QskStackBox::setCurrentItem(
const QQuickItem* item )
184 setCurrentIndex( indexOf( item ) );
187void QskStackBox::addItem( QQuickItem* item )
189 insertItem( -1, item );
192void QskStackBox::addItem( QQuickItem* item, Qt::Alignment alignment )
194 insertItem( -1, item, alignment );
197void QskStackBox::insertItem(
int index, QQuickItem* item )
199 if ( item ==
nullptr || item ==
this )
202 reparentItem( item );
204 if ( !qskPlacementPolicy( item ).isEffective() )
206 qWarning() <<
"Inserting an item that is to be ignored for layouting"
207 << item->metaObject()->className();
212 const bool doAppend = ( index < 0 ) || ( index >= itemCount() );
214 if ( item->parentItem() == this )
216 const int oldIndex = indexOf( item );
221 if ( ( index == oldIndex ) || ( doAppend && ( oldIndex == itemCount() - 1 ) ) )
227 m_data->items.removeAt( oldIndex );
234 m_data->items.insert( index, item );
236 const int oldCurrentIndex = m_data->currentIndex;
238 if ( m_data->items.count() == 1 )
240 m_data->currentIndex = 0;
241 item->setVisible(
true );
245 item->setVisible(
false );
247 if ( index <= m_data->currentIndex )
248 m_data->currentIndex++;
251 if ( oldCurrentIndex != m_data->currentIndex )
252 Q_EMIT currentIndexChanged( m_data->currentIndex );
258void QskStackBox::insertItem(
259 int index, QQuickItem* item, Qt::Alignment alignment )
261 if (
auto control = qskControlCast( item ) )
262 control->setLayoutAlignmentHint( alignment );
264 insertItem( index, item );
267void QskStackBox::removeAt(
int index )
269 removeItemInternal( index,
true );
272void QskStackBox::removeItemInternal(
int index,
bool unparent )
274 if ( index < 0 || index >= m_data->items.count() )
279 if (
auto item = m_data->items[ index ] )
280 unparentItem( item );
283 m_data->items.removeAt( index );
285 auto& currentIndex = m_data->currentIndex;
287 if ( index <= currentIndex )
291 if ( currentIndex < 0 && !m_data->items.isEmpty() )
294 if ( currentIndex >= 0 )
295 m_data->items[ currentIndex ]->setVisible(
true );
297 Q_EMIT currentIndexChanged( currentIndex );
304void QskStackBox::removeItem(
const QQuickItem* item )
306 removeAt( indexOf( item ) );
309void QskStackBox::autoAddItem( QQuickItem* item )
311 removeAt( indexOf( item ) );
314void QskStackBox::autoRemoveItem( QQuickItem* item )
316 removeItemInternal( indexOf( item ),
false );
319void QskStackBox::clear(
bool autoDelete )
321 for (
const auto item : std::as_const( m_data->items ) )
323 if( autoDelete && ( item->parent() ==
this ) )
326 item->setParentItem(
nullptr );
329 m_data->items.clear();
331 if ( m_data->currentIndex >= 0 )
333 m_data->currentIndex = -1;
334 Q_EMIT currentIndexChanged( m_data->currentIndex );
338QRectF QskStackBox::geometryForItemAt(
int index )
const
342 if (
const auto item = m_data->items.value( index ) )
344 auto alignment = qskLayoutAlignmentHint( item );
345 if ( alignment == 0 )
346 alignment = m_data->defaultAlignment;
348 return qskConstrainedItemRect( item, r, alignment );
351 return QRectF( r.x(), r.y(), 0.0, 0.0 );
354void QskStackBox::updateLayout()
359 for (
int i = 0; i < m_data->items.count(); i++ )
361 auto item = m_data->items[ i ];
363 const auto visibility =
366 if ( qskPlacementPolicy( item ).isAdjusting( visibility ) )
368 const auto rect = geometryForItemAt( i );
369 qskSetItemGeometry( m_data->items[ i ],
rect );
374QSizeF QskStackBox::layoutSizeHint(
375 Qt::SizeHint which,
const QSizeF& constraint )
const
377 if ( which == Qt::MaximumSize )
383 for (
const auto item : std::as_const( m_data->items ) )
389 const auto policy = qskSizePolicy( item );
391 if ( constraint.width() >= 0.0 && policy.isConstrained( Qt::Vertical ) )
393 const auto hint = qskSizeConstraint( item, which, constraint );
394 h = qMax( h, hint.height() );
396 else if ( constraint.height() >= 0.0 && policy.isConstrained( Qt::Horizontal ) )
398 const auto hint = qskSizeConstraint( item, which, constraint );
399 w = qMax( w, hint.width() );
403 const auto hint = qskSizeConstraint( item, which, QSizeF() );
405 w = qMax( w, hint.width() );
406 h = qMax( h, hint.height() );
411 return QSizeF( w, h );
414bool QskStackBox::event( QEvent* event )
416 switch (
static_cast< int >( event->type() ) )
418 case QEvent::LayoutRequest:
424 case QEvent::ContentsRectChange:
425 case QskEvent::GeometryChange:
432 return Inherited::event( event );
435void QskStackBox::dump()
const
437 auto debug = qDebug();
439 QDebugStateSaver saver(
debug );
444 debug <<
"QskStackBox"
445 <<
" w:" << constraint.width() <<
" h:" << constraint.height() <<
'\n';
447 for (
int i = 0; i < m_data->items.count(); i++ )
449 const auto item = m_data->items[i];
451 debug <<
" " << i <<
": ";
453 const auto size = qskSizeConstraint( item, Qt::PreferredSize );
454 debug << item->metaObject()->className()
455 <<
" w:" << size.width() <<
" h:" << size.height();
457 if ( i == m_data->currentIndex )
464#include "moc_QskStackBox.cpp"
QRectF layoutRect() const
Base class of layouts with index ordered elements.
bool isInitiallyPainted() const
bool maybeUnresized() const
void debug(QskAspect) const