qskinny/src/layouts/QskLayoutBox.cpp

399 lines
8.5 KiB
C++
Raw Normal View History

2017-07-21 16:21:34 +00:00
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
2019-04-08 11:08:58 +00:00
#include "QskLayoutBox.h"
2017-07-21 16:21:34 +00:00
#include "QskEvent.h"
2018-08-03 06:15:28 +00:00
#include "QskLayoutEngine.h"
#include "QskLayoutItem.h"
2017-07-21 16:21:34 +00:00
2019-04-08 11:08:58 +00:00
class QskLayoutBox::PrivateData
2017-07-21 16:21:34 +00:00
{
2018-08-03 06:15:28 +00:00
public:
PrivateData()
: isActive( true )
2017-07-21 16:21:34 +00:00
{
}
bool isActive : 1;
QskLayoutEngine engine;
};
2019-04-08 11:08:58 +00:00
QskLayoutBox::QskLayoutBox( QQuickItem* parent )
2018-08-03 06:15:28 +00:00
: QskControl( parent )
, m_data( new PrivateData() )
2017-07-21 16:21:34 +00:00
{
}
2019-04-08 11:08:58 +00:00
QskLayoutBox::~QskLayoutBox()
2017-07-21 16:21:34 +00:00
{
disconnect( this, 0, this, 0 ); // destructor runs on invalidate else
setActive( false );
}
2019-04-08 11:08:58 +00:00
void QskLayoutBox::setActive( bool on )
2017-07-21 16:21:34 +00:00
{
if ( on == m_data->isActive )
return;
m_data->isActive = on;
for ( int i = 0; i < itemCount(); ++i )
{
2019-04-26 09:56:09 +00:00
if( auto item = itemAtIndex( i ) )
2017-07-21 16:21:34 +00:00
setItemActive( item, on );
}
if ( on )
{
resetImplicitSize();
polish();
}
}
2019-04-08 11:08:58 +00:00
bool QskLayoutBox::isActive() const
2017-07-21 16:21:34 +00:00
{
return m_data->isActive;
}
2019-04-08 11:08:58 +00:00
int QskLayoutBox::itemCount() const
2017-07-21 16:21:34 +00:00
{
return m_data->engine.itemCount();
}
2019-04-08 11:08:58 +00:00
QQuickItem* QskLayoutBox::itemAtIndex( int index ) const
2017-07-21 16:21:34 +00:00
{
2019-04-26 09:56:09 +00:00
if ( auto layoutItem = m_data->engine.layoutItemAt( index ) )
2017-07-21 16:21:34 +00:00
return layoutItem->item();
return nullptr;
}
2019-04-08 11:08:58 +00:00
int QskLayoutBox::indexOf( const QQuickItem* item ) const
2017-07-21 16:21:34 +00:00
{
if ( item != nullptr )
return m_data->engine.indexOf( item );
return -1;
}
2019-04-08 11:08:58 +00:00
void QskLayoutBox::insertItemInternal( QskLayoutItem* layoutItem, int index )
2017-07-21 16:21:34 +00:00
{
// check if item is already inserted ???
2019-04-26 09:56:09 +00:00
auto item = layoutItem->item();
2017-07-21 16:21:34 +00:00
if ( index > itemCount() )
index = -1; // append
2019-04-26 09:56:09 +00:00
auto& engine = this->engine();
2017-07-21 16:21:34 +00:00
if ( item )
{
if ( item->parent() == nullptr )
item->setParent( this );
if ( item->parentItem() != this )
item->setParentItem( this );
/*
Re-ordering the child items to have a a proper focus tab chain
*/
bool reordered = false;
if ( ( index >= 0 ) && ( index < itemCount() - 1 ) )
{
for ( int i = index; i < engine.itemCount(); i++ )
{
auto layoutItem = engine.layoutItemAt( i );
if ( layoutItem && layoutItem->item() )
{
item->stackBefore( layoutItem->item() );
reordered = true;
break;
}
}
}
if ( !reordered )
{
const auto children = childItems();
if ( item != children.last() )
item->stackAfter( children.last() );
}
}
2017-07-21 16:21:34 +00:00
engine.insertLayoutItem( layoutItem, index );
2017-07-21 16:21:34 +00:00
if ( m_data->isActive )
{
setItemActive( item, true );
resetImplicitSize();
polish();
}
}
2019-04-08 11:08:58 +00:00
void QskLayoutBox::removeAt( int index )
2017-07-21 16:21:34 +00:00
{
2019-04-26 09:56:09 +00:00
auto& engine = this->engine();
2017-07-21 16:21:34 +00:00
2019-04-26 09:56:09 +00:00
auto layoutItem = engine.layoutItemAt( index );
2017-07-21 16:21:34 +00:00
if ( layoutItem == nullptr )
return;
setItemActive( layoutItem->item(), false );
engine.removeItem( layoutItem );
layoutItemRemoved( layoutItem, index );
delete layoutItem;
if ( m_data->isActive )
{
resetImplicitSize();
polish();
}
}
2019-04-08 11:08:58 +00:00
void QskLayoutBox::removeItem( QQuickItem* item )
2017-07-21 16:21:34 +00:00
{
removeAt( indexOf( item ) );
}
2019-04-08 11:08:58 +00:00
void QskLayoutBox::clear( bool autoDelete )
2017-07-21 16:21:34 +00:00
{
const bool isActive = m_data->isActive;
setActive( false );
for ( int i = itemCount() - 1; i >= 0; i-- )
{
auto item = itemAtIndex( i );
2017-07-21 16:21:34 +00:00
removeAt( i );
if( item )
{
if( autoDelete && ( item->parent() == this ) )
delete item;
else
item->setParentItem( nullptr );
}
}
2017-07-21 16:21:34 +00:00
setActive( isActive );
}
2019-04-08 11:08:58 +00:00
void QskLayoutBox::setupLayoutItem( QskLayoutItem* layoutItem, int index )
2017-07-21 16:21:34 +00:00
{
Q_UNUSED( layoutItem )
Q_UNUSED( index )
}
2019-04-08 11:08:58 +00:00
void QskLayoutBox::layoutItemInserted( QskLayoutItem* layoutItem, int index )
2017-07-21 16:21:34 +00:00
{
Q_UNUSED( layoutItem )
Q_UNUSED( index )
}
2019-04-08 11:08:58 +00:00
void QskLayoutBox::layoutItemRemoved( QskLayoutItem* layoutItem, int index )
2017-07-21 16:21:34 +00:00
{
Q_UNUSED( layoutItem )
Q_UNUSED( index )
}
2019-04-08 11:08:58 +00:00
void QskLayoutBox::activate()
2017-07-21 16:21:34 +00:00
{
if ( m_data->isActive )
polish();
}
2019-04-08 11:08:58 +00:00
void QskLayoutBox::invalidate()
2017-07-21 16:21:34 +00:00
{
engine().invalidate();
activate();
resetImplicitSize();
}
2019-04-08 11:08:58 +00:00
void QskLayoutBox::adjustItem( const QQuickItem* item )
2017-07-21 16:21:34 +00:00
{
adjustItemAt( indexOf( item ) );
}
2019-04-08 11:08:58 +00:00
void QskLayoutBox::adjustItemAt( int index )
2017-07-21 16:21:34 +00:00
{
QskLayoutItem* layoutItem = engine().layoutItemAt( index );
if ( layoutItem == nullptr )
return;
// setting UpdateNone to all others ???
layoutItem->setUpdateMode( QskLayoutItem::UpdateAlways );
engine().setGeometries( alignedLayoutRect( layoutRect() ) );
layoutItem->setUpdateMode( QskLayoutItem::UpdateWhenVisible );
}
2019-04-08 11:08:58 +00:00
void QskLayoutBox::updateLayout()
2017-07-21 16:21:34 +00:00
{
if ( m_data->isActive )
engine().setGeometries( alignedLayoutRect( layoutRect() ) );
}
2019-04-08 11:08:58 +00:00
QRectF QskLayoutBox::alignedLayoutRect( const QRectF& rect ) const
2017-07-21 16:21:34 +00:00
{
return rect;
}
2019-04-08 11:25:06 +00:00
QSizeF QskLayoutBox::contentsSizeHint() const
{
if ( !isActive() )
return QSizeF( -1, -1 );
if ( itemCount() == 0 )
return QSizeF( 0, 0 );
return layoutItemsSizeHint();
}
QSizeF QskLayoutBox::layoutItemsSizeHint() const
{
return engine().sizeHint( Qt::PreferredSize );
}
qreal QskLayoutBox::heightForWidth( qreal width ) const
{
const auto m = margins();
width -= m.left() + m.right();
qreal height = engine().heightForWidth( width );
height += m.top() + m.bottom();
return height;
}
qreal QskLayoutBox::widthForHeight( qreal height ) const
{
const auto m = margins();
height -= m.top() + m.bottom();
qreal width = engine().widthForHeight( height );
width += m.left() + m.right();
return width;
}
2019-04-08 11:08:58 +00:00
void QskLayoutBox::geometryChangeEvent( QskGeometryChangeEvent* event )
2017-07-21 16:21:34 +00:00
{
Inherited::geometryChangeEvent( event );
if ( event->isResized() )
activate();
}
2019-04-08 11:08:58 +00:00
void QskLayoutBox::setItemActive( const QQuickItem* item, bool on )
2017-07-21 16:21:34 +00:00
{
if ( item == nullptr )
return;
// QskControl sends QEvent::LayoutRequest
2019-04-26 09:56:09 +00:00
const bool hasLayoutRequests = qskControlCast( item );
2017-07-21 16:21:34 +00:00
if ( !hasLayoutRequests )
{
if ( on )
{
connect( item, &QQuickItem::implicitWidthChanged,
2019-04-08 11:08:58 +00:00
this, &QskLayoutBox::invalidate );
2017-07-21 16:21:34 +00:00
connect( item, &QQuickItem::implicitHeightChanged,
2019-04-08 11:08:58 +00:00
this, &QskLayoutBox::invalidate );
2017-07-21 16:21:34 +00:00
}
else
{
disconnect( item, &QQuickItem::implicitWidthChanged,
2019-04-08 11:08:58 +00:00
this, &QskLayoutBox::invalidate );
2017-07-21 16:21:34 +00:00
disconnect( item, &QQuickItem::implicitHeightChanged,
2019-04-08 11:08:58 +00:00
this, &QskLayoutBox::invalidate );
2017-07-21 16:21:34 +00:00
}
}
if ( on )
2019-04-08 11:08:58 +00:00
connect( item, &QQuickItem::visibleChanged, this, &QskLayoutBox::activate );
2017-07-21 16:21:34 +00:00
else
2019-04-08 11:08:58 +00:00
disconnect( item, &QQuickItem::visibleChanged, this, &QskLayoutBox::activate );
2017-07-21 16:21:34 +00:00
}
2019-04-08 11:08:58 +00:00
QskLayoutEngine& QskLayoutBox::engine()
2017-07-21 16:21:34 +00:00
{
return m_data->engine;
}
2019-04-08 11:08:58 +00:00
const QskLayoutEngine& QskLayoutBox::engine() const
2017-07-21 16:21:34 +00:00
{
return m_data->engine;
}
2019-04-08 11:08:58 +00:00
void QskLayoutBox::itemChange( ItemChange change, const ItemChangeData& value )
2017-07-21 16:21:34 +00:00
{
Inherited::itemChange( change, value );
2018-08-03 06:15:28 +00:00
switch ( change )
2017-07-21 16:21:34 +00:00
{
case ItemChildRemovedChange:
{
removeItem( value.item );
break;
}
case QQuickItem::ItemVisibleHasChanged:
{
if ( value.boolValue )
activate();
break;
}
case QQuickItem::ItemSceneChange:
{
if ( value.window )
activate();
break;
}
default:
break;
}
}
2019-04-08 11:08:58 +00:00
bool QskLayoutBox::event( QEvent* event )
2017-07-21 16:21:34 +00:00
{
2018-08-03 06:15:28 +00:00
switch ( event->type() )
2017-07-21 16:21:34 +00:00
{
case QEvent::LayoutRequest:
{
invalidate();
break;
}
case QEvent::LayoutDirectionChange:
{
m_data->engine.setVisualDirection(
layoutMirroring() ? Qt::RightToLeft : Qt::LeftToRight );
activate();
break;
}
case QEvent::ContentsRectChange:
{
activate();
break;
}
default:
break;
}
return Inherited::event( event );
}
2019-04-08 11:08:58 +00:00
#include "moc_QskLayoutBox.cpp"