replacing QGridLayoutEngine by QskLinearLayoutEngine, QskStackBox
without QGridLayoutEngine
This commit is contained in:
parent
f8c57f7a7e
commit
ee65ee1857
|
|
@ -33,7 +33,7 @@ MainWindow::MainWindow()
|
|||
layout->setStretchFactor( header, 1 );
|
||||
|
||||
layout->addItem( content );
|
||||
layout->setStretchFactor( content, 10 );
|
||||
layout->setStretchFactor( content, 8 );
|
||||
|
||||
layout->addItem( footer );
|
||||
layout->setStretchFactor( footer, 1 );
|
||||
|
|
|
|||
|
|
@ -389,8 +389,8 @@ SoundControl::SoundControl( QQuickItem* parent )
|
|||
|
||||
auto layout = new QskGridBox( this );
|
||||
layout->setMargins( QMarginsF( 40, 20, 40, 20 ) );
|
||||
layout->setVerticalSpacing( 10 );
|
||||
layout->setHorizontalSpacing( 60 );
|
||||
layout->setSpacing( Qt::Vertical, 10 );
|
||||
layout->setSpacing( Qt::Horizontal, 60 );
|
||||
layout->setColumnStretchFactor( 0, 1 );
|
||||
layout->setColumnStretchFactor( 1, 2 );
|
||||
|
||||
|
|
|
|||
|
|
@ -105,16 +105,13 @@ Box::Box( QQuickItem* parent )
|
|||
|
||||
void Box::flip()
|
||||
{
|
||||
setActive( false );
|
||||
|
||||
for ( int i = 0; i < itemCount(); i++ )
|
||||
for ( int i = 0; i < entryCount(); i++ )
|
||||
{
|
||||
if ( Control* control = dynamic_cast< Control* >( itemAtIndex( i ) ) )
|
||||
if ( auto control = dynamic_cast< Control* >( itemAtIndex( i ) ) )
|
||||
control->transpose();
|
||||
}
|
||||
|
||||
transpose();
|
||||
setActive( true );
|
||||
}
|
||||
|
||||
void Box::addControl( Control* control )
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ namespace
|
|||
void addRectangle( const char* colorName )
|
||||
{
|
||||
auto rect = new TestRectangle( colorName );
|
||||
rect->setText( QString::number( itemCount() + 1 ) );
|
||||
rect->setText( QString::number( entryCount() + 1 ) );
|
||||
|
||||
addItem( rect, Qt::AlignCenter );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ namespace
|
|||
void addRectangle( const char* colorName )
|
||||
{
|
||||
auto rect = new TestRectangle( colorName );
|
||||
rect->setText( QString::number( itemCount() + 1 ) );
|
||||
rect->setText( QString::number( entryCount() + 1 ) );
|
||||
|
||||
addItem( rect, Qt::AlignCenter );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ class SliderBox : public QskLinearBox
|
|||
customSlider->setStepSize( 10 );
|
||||
customSlider->setPageSize( 10 );
|
||||
|
||||
for ( int i = 0; i < itemCount(); i++ )
|
||||
for ( int i = 0; i < entryCount(); i++ )
|
||||
{
|
||||
if ( auto slider = qobject_cast< QskSlider* >( itemAtIndex( i ) ) )
|
||||
{
|
||||
|
|
@ -151,7 +151,7 @@ class SliderBox : public QskLinearBox
|
|||
{
|
||||
setOrientation( inverted( orientation() ) );
|
||||
|
||||
for ( int i = 0; i < itemCount(); i++ )
|
||||
for ( int i = 0; i < entryCount(); i++ )
|
||||
{
|
||||
if ( auto slider = qobject_cast< QskSlider* >( itemAtIndex( i ) ) )
|
||||
{
|
||||
|
|
@ -159,7 +159,7 @@ class SliderBox : public QskLinearBox
|
|||
|
||||
slider->setOrientation( orientation );
|
||||
|
||||
if ( i >= itemCount() - 1 )
|
||||
if ( i >= entryCount() - 1 )
|
||||
{
|
||||
// we didn't implement the vertical mode of the heavily
|
||||
// customized slider yet.
|
||||
|
|
|
|||
|
|
@ -61,7 +61,6 @@ void Window::flipOrientation()
|
|||
newBox->setMargins( m_layoutBox->margins() );
|
||||
|
||||
m_orientation = invertedOrientation();
|
||||
m_layoutBox->setActive( false );
|
||||
|
||||
const QVector< QskDialogButtonBox* > boxes = dialogBoxes();
|
||||
for ( QskDialogButtonBox* box : boxes )
|
||||
|
|
@ -88,7 +87,7 @@ void Window::centerButtons()
|
|||
QVector< QskDialogButtonBox* > Window::dialogBoxes() const
|
||||
{
|
||||
QVector< QskDialogButtonBox* > boxes;
|
||||
for ( int i = 0; i < m_layoutBox->itemCount(); i++ )
|
||||
for ( int i = 0; i < m_layoutBox->entryCount(); i++ )
|
||||
{
|
||||
if ( auto box = qobject_cast< QskDialogButtonBox* >( m_layoutBox->itemAtIndex( i ) ) )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskLayoutQml.h"
|
||||
|
||||
void QskGridBoxQml::setHorizontalSpacing( qreal spacing )
|
||||
{
|
||||
const auto oldSpacing = QskGridBox::spacing( Qt::Horizontal );
|
||||
QskGridBox::setSpacing( Qt::Horizontal, spacing );
|
||||
|
||||
if ( oldSpacing != QskGridBox::spacing( Qt::Horizontal ) )
|
||||
Q_EMIT verticalSpacingChanged();
|
||||
}
|
||||
|
||||
qreal QskGridBoxQml::horizontalSpacing() const
|
||||
{
|
||||
return QskGridBox::spacing( Qt::Horizontal );
|
||||
}
|
||||
|
||||
void QskGridBoxQml::resetHorizontalSpacing()
|
||||
{
|
||||
const auto orientation = Qt::Horizontal;
|
||||
|
||||
const auto oldSpacing = QskGridBox::spacing( orientation );
|
||||
QskGridBox::resetSpacing( orientation );
|
||||
|
||||
if ( oldSpacing != QskGridBox::spacing( orientation ) )
|
||||
Q_EMIT horizontalSpacingChanged();
|
||||
}
|
||||
|
||||
void QskGridBoxQml::setVerticalSpacing( qreal spacing )
|
||||
{
|
||||
const auto oldSpacing = QskGridBox::spacing( Qt::Vertical );
|
||||
QskGridBox::setSpacing( Qt::Vertical, spacing );
|
||||
|
||||
if ( oldSpacing != QskGridBox::spacing( Qt::Vertical ) )
|
||||
Q_EMIT verticalSpacingChanged();
|
||||
}
|
||||
|
||||
qreal QskGridBoxQml::verticalSpacing() const
|
||||
{
|
||||
return QskGridBox::spacing( Qt::Vertical );
|
||||
}
|
||||
|
||||
void QskGridBoxQml::resetVerticalSpacing()
|
||||
{
|
||||
const auto orientation = Qt::Vertical;
|
||||
|
||||
const auto oldSpacing = QskGridBox::spacing( orientation );
|
||||
QskGridBox::resetSpacing( orientation );
|
||||
|
||||
if ( oldSpacing != QskGridBox::spacing( orientation ) )
|
||||
Q_EMIT verticalSpacingChanged();
|
||||
}
|
||||
|
||||
#include "moc_QskLayoutQml.cpp"
|
||||
|
|
@ -36,7 +36,7 @@ class QskLayoutBoxQml : public LayoutBox
|
|||
{
|
||||
return LayoutBox::indexOf( item );
|
||||
}
|
||||
|
||||
|
||||
Q_INVOKABLE void removeAt( int index )
|
||||
{
|
||||
return LayoutBox::removeAt( index );
|
||||
|
|
@ -46,7 +46,7 @@ class QskLayoutBoxQml : public LayoutBox
|
|||
{
|
||||
// QML does not like a const version
|
||||
LayoutBox::removeItem( item );
|
||||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE void setAlignment( QQuickItem* item, Qt::Alignment alignment )
|
||||
{
|
||||
|
|
@ -63,14 +63,14 @@ class QskStackBoxQml : public QskLayoutBoxQml< QskStackBox >
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_INVOKABLE void setAlignment( int index, Qt::Alignment alignment )
|
||||
Q_INVOKABLE void setAlignmentAt( int index, Qt::Alignment alignment )
|
||||
{
|
||||
QskStackBox::setAlignment( index, alignment );
|
||||
QskStackBox::setAlignmentAt( index, alignment );
|
||||
}
|
||||
|
||||
Q_INVOKABLE Qt::Alignment alignment( int index ) const
|
||||
Q_INVOKABLE Qt::Alignment alignmentAt( int index ) const
|
||||
{
|
||||
return QskStackBox::alignment( index );
|
||||
return QskStackBox::alignmentAt( index );
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -115,7 +115,22 @@ class QskGridBoxQml : public QskLayoutBoxQml< QskGridBox >
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY( qreal horizontalSpacing READ horizontalSpacing
|
||||
WRITE setHorizontalSpacing RESET resetHorizontalSpacing
|
||||
NOTIFY horizontalSpacingChanged )
|
||||
|
||||
Q_PROPERTY( qreal verticalSpacing READ verticalSpacing
|
||||
WRITE setVerticalSpacing RESET resetVerticalSpacing
|
||||
NOTIFY verticalSpacingChanged )
|
||||
|
||||
public:
|
||||
void setHorizontalSpacing( qreal );
|
||||
void resetHorizontalSpacing();
|
||||
qreal horizontalSpacing() const;
|
||||
|
||||
void setVerticalSpacing( qreal );
|
||||
void resetVerticalSpacing();
|
||||
qreal verticalSpacing() const;
|
||||
|
||||
Q_INVOKABLE bool retainSizeWhenHidden( QQuickItem* item ) const
|
||||
{
|
||||
|
|
@ -126,6 +141,10 @@ class QskGridBoxQml : public QskLayoutBoxQml< QskGridBox >
|
|||
{
|
||||
QskGridBox::setRetainSizeWhenHidden( item, on );
|
||||
}
|
||||
|
||||
Q_SIGNALS:
|
||||
void verticalSpacingChanged();
|
||||
void horizontalSpacingChanged();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ HEADERS += \
|
|||
|
||||
SOURCES += \
|
||||
QskShortcutQml.cpp \
|
||||
QskLayoutQml.cpp \
|
||||
QskQml.cpp
|
||||
|
||||
target.path = $${QSK_INSTALL_LIBS}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ namespace
|
|||
QskControl::keyPressEvent.
|
||||
*/
|
||||
|
||||
for ( int i = 0; i < itemCount(); i++ )
|
||||
for ( int i = 0; i < entryCount(); i++ )
|
||||
{
|
||||
if ( auto button = itemAtIndex( i ) )
|
||||
button->setZ( i == currentIndex ? 0.001 : 0.0 );
|
||||
|
|
@ -179,8 +179,8 @@ int QskTabBar::insertTab( int index, QskTabButton* button )
|
|||
{
|
||||
auto buttonBox = m_data->buttonBox;
|
||||
|
||||
if ( index < 0 || index >= buttonBox->itemCount() )
|
||||
index = buttonBox->itemCount();
|
||||
if ( index < 0 || index >= buttonBox->entryCount() )
|
||||
index = buttonBox->entryCount();
|
||||
|
||||
if ( isComponentComplete() )
|
||||
{
|
||||
|
|
@ -323,7 +323,7 @@ int QskTabBar::currentIndex() const
|
|||
|
||||
int QskTabBar::count() const
|
||||
{
|
||||
return m_data->buttonBox->itemCount();
|
||||
return m_data->buttonBox->entryCount();
|
||||
}
|
||||
|
||||
QskTabButton* QskTabBar::buttonAt( int position )
|
||||
|
|
|
|||
|
|
@ -160,9 +160,6 @@ void QskDialogButtonBox::rearrangeButtons()
|
|||
|
||||
auto layoutBox = m_data->layoutBox;
|
||||
|
||||
const bool isActive = layoutBox->isActive();
|
||||
layoutBox->setActive( false );
|
||||
|
||||
layoutBox->clear();
|
||||
|
||||
const int* currentLayout = effectiveSkin()->dialogButtonLayout( orientation() );
|
||||
|
|
@ -226,8 +223,6 @@ void QskDialogButtonBox::rearrangeButtons()
|
|||
if ( m_data->centeredButtons )
|
||||
layoutBox->addStretch( 1 );
|
||||
|
||||
layoutBox->setActive( isActive );
|
||||
|
||||
// reorganizing the tab chain ???
|
||||
}
|
||||
|
||||
|
|
@ -472,7 +467,10 @@ QskDialog::Action QskDialogButtonBox::clickedAction() const
|
|||
bool QskDialogButtonBox::event( QEvent* event )
|
||||
{
|
||||
if ( event->type() == QEvent::LayoutRequest )
|
||||
resetImplicitSize();
|
||||
{
|
||||
if ( !m_data->dirtyLayout )
|
||||
resetImplicitSize();
|
||||
}
|
||||
|
||||
return Inherited::event( event );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,24 +4,54 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include "QskGridBox.h"
|
||||
#include "QskLayoutEngine.h"
|
||||
#include "QskLayoutItem.h"
|
||||
#include "QskGridLayoutEngine.h"
|
||||
#include "QskLayoutConstraint.h"
|
||||
#include "QskEvent.h"
|
||||
|
||||
static void qskSetItemActive( QObject* receiver, const QQuickItem* item, bool on )
|
||||
{
|
||||
if ( ( item == nullptr ) || ( qskControlCast( item ) != nullptr ) )
|
||||
return;
|
||||
|
||||
/*
|
||||
For QQuickItems not being derived from QskControl we manually
|
||||
send QEvent::LayoutRequest events.
|
||||
*/
|
||||
|
||||
if ( on )
|
||||
{
|
||||
auto sendLayoutRequest =
|
||||
[receiver]()
|
||||
{
|
||||
QEvent event( QEvent::LayoutRequest );
|
||||
QCoreApplication::sendEvent( receiver, &event );
|
||||
};
|
||||
|
||||
QObject::connect( item, &QQuickItem::implicitWidthChanged,
|
||||
receiver, sendLayoutRequest );
|
||||
|
||||
QObject::connect( item, &QQuickItem::implicitHeightChanged,
|
||||
receiver, sendLayoutRequest );
|
||||
|
||||
QObject::connect( item, &QQuickItem::visibleChanged,
|
||||
receiver, sendLayoutRequest );
|
||||
}
|
||||
else
|
||||
{
|
||||
QObject::disconnect( item, &QQuickItem::implicitWidthChanged, receiver, nullptr );
|
||||
QObject::disconnect( item, &QQuickItem::implicitHeightChanged, receiver, nullptr );
|
||||
QObject::disconnect( item, &QQuickItem::visibleChanged, receiver, nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
class QskGridBox::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData()
|
||||
: isExpanding( false )
|
||||
, unlimitedSpanned( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
bool isExpanding;
|
||||
unsigned int unlimitedSpanned;
|
||||
QskGridLayoutEngine engine;
|
||||
};
|
||||
|
||||
QskGridBox::QskGridBox( QQuickItem* parent )
|
||||
: QskLayoutBox( parent )
|
||||
: QskBox( false, parent )
|
||||
, m_data( new PrivateData() )
|
||||
{
|
||||
}
|
||||
|
|
@ -34,400 +64,444 @@ void QskGridBox::addItem( QQuickItem* item,
|
|||
int row, int column, int rowSpan, int columnSpan,
|
||||
Qt::Alignment alignment )
|
||||
{
|
||||
auto layoutItem = new QskLayoutItem( item, row, column, rowSpan, columnSpan );
|
||||
layoutItem->setAlignment( alignment );
|
||||
if ( item == nullptr )
|
||||
return;
|
||||
|
||||
const int index = itemCount(); // position and index doesn't match
|
||||
if ( item->parent() == nullptr )
|
||||
item->setParent( this );
|
||||
|
||||
setupLayoutItem( layoutItem, index );
|
||||
insertItemInternal( layoutItem, -1 );
|
||||
layoutItemInserted( layoutItem, index );
|
||||
if ( item->parentItem() != this )
|
||||
item->setParentItem( this );
|
||||
|
||||
qskSetItemActive( this, item, true );
|
||||
|
||||
// What about the focus tab chain - TODO ... ????
|
||||
// check if item is already inserted ???
|
||||
|
||||
m_data->engine.insertItem(
|
||||
item, row, column, rowSpan, columnSpan, alignment );
|
||||
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
|
||||
}
|
||||
|
||||
void QskGridBox::removeAt( int index )
|
||||
{
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( auto item = engine.itemAt( index ) )
|
||||
qskSetItemActive( this, item, false );
|
||||
|
||||
engine.removeAt( index );
|
||||
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
}
|
||||
|
||||
void QskGridBox::removeItem( const QQuickItem* item )
|
||||
{
|
||||
removeAt( indexOf( item ) );
|
||||
}
|
||||
|
||||
void QskGridBox::clear( bool autoDelete )
|
||||
{
|
||||
for ( int i = itemCount() - 1; i >= 0; i-- )
|
||||
{
|
||||
auto item = itemAtIndex( i );
|
||||
|
||||
removeAt( i );
|
||||
|
||||
if( item )
|
||||
{
|
||||
if( autoDelete && ( item->parent() == this ) )
|
||||
delete item;
|
||||
else
|
||||
item->setParentItem( nullptr );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int QskGridBox::itemCount() const
|
||||
{
|
||||
return m_data->engine.itemCount();
|
||||
}
|
||||
|
||||
int QskGridBox::rowCount() const
|
||||
{
|
||||
return engine().rowCount();
|
||||
return m_data->engine.rowCount();
|
||||
}
|
||||
|
||||
int QskGridBox::columnCount() const
|
||||
{
|
||||
return engine().columnCount();
|
||||
return m_data->engine.columnCount();
|
||||
}
|
||||
|
||||
QQuickItem* QskGridBox::itemAtIndex( int index ) const
|
||||
{
|
||||
return m_data->engine.itemAt( index );
|
||||
}
|
||||
|
||||
int QskGridBox::indexOf( const QQuickItem* item ) const
|
||||
{
|
||||
return m_data->engine.indexOf( item );
|
||||
}
|
||||
|
||||
QQuickItem* QskGridBox::itemAt( int row, int column ) const
|
||||
{
|
||||
if ( const auto layoutItem = engine().layoutItemAt( row, column ) )
|
||||
return layoutItem->item();
|
||||
|
||||
return nullptr;
|
||||
return m_data->engine.itemAt( row, column );
|
||||
}
|
||||
|
||||
int QskGridBox::indexAt( int row, int column ) const
|
||||
{
|
||||
return engine().indexAt( row, column );
|
||||
return m_data->engine.indexAt( row, column );
|
||||
}
|
||||
|
||||
int QskGridBox::rowOfIndex( int index ) const
|
||||
{
|
||||
if ( auto layoutItem = engine().layoutItemAt( index ) )
|
||||
return layoutItem->firstRow();
|
||||
|
||||
return -1;
|
||||
return m_data->engine.rowOfIndex( index );
|
||||
}
|
||||
|
||||
int QskGridBox::rowSpanOfIndex( int index ) const
|
||||
{
|
||||
if ( auto layoutItem = engine().layoutItemAt( index ) )
|
||||
return layoutItem->rowSpan();
|
||||
|
||||
return 0;
|
||||
return m_data->engine.rowSpanOfIndex( index );
|
||||
}
|
||||
|
||||
int QskGridBox::columnOfIndex( int index ) const
|
||||
{
|
||||
if ( auto layoutItem = engine().layoutItemAt( index ) )
|
||||
return layoutItem->firstColumn();
|
||||
|
||||
return -1;
|
||||
return m_data->engine.columnOfIndex( index );
|
||||
}
|
||||
|
||||
int QskGridBox::columnSpanOfIndex( int index ) const
|
||||
{
|
||||
if ( auto layoutItem = engine().layoutItemAt( index ) )
|
||||
return layoutItem->columnSpan();
|
||||
|
||||
return 0;
|
||||
return m_data->engine.columnSpanOfIndex( index );
|
||||
}
|
||||
|
||||
void QskGridBox::setupLayoutItem( QskLayoutItem* layoutItem, int index )
|
||||
{
|
||||
Q_UNUSED( index )
|
||||
|
||||
auto& engine = this->engine();
|
||||
|
||||
m_data->isExpanding = ( layoutItem->lastColumn() >= engine.columnCount() ) ||
|
||||
( layoutItem->lastRow() >= engine.rowCount() );
|
||||
}
|
||||
|
||||
void QskGridBox::layoutItemInserted( QskLayoutItem* layoutItem, int index )
|
||||
{
|
||||
Q_UNUSED( index )
|
||||
|
||||
if ( m_data->isExpanding )
|
||||
{
|
||||
// the new item has extended the number of rows/columns and
|
||||
// we need to adjust all items without fixed spanning
|
||||
|
||||
if ( m_data->unlimitedSpanned > 0 )
|
||||
engine().adjustSpans( columnCount(), rowCount() );
|
||||
}
|
||||
|
||||
if ( layoutItem->hasUnlimitedSpan() )
|
||||
{
|
||||
// the item itself might need to be adjusted
|
||||
|
||||
if ( layoutItem->hasUnlimitedSpan( Qt::Horizontal ) )
|
||||
{
|
||||
const int span = columnCount() - layoutItem->firstColumn();
|
||||
layoutItem->setRowSpan( span, Qt::Horizontal );
|
||||
}
|
||||
|
||||
if ( layoutItem->hasUnlimitedSpan( Qt::Vertical ) )
|
||||
{
|
||||
const int span = rowCount() - layoutItem->firstRow();
|
||||
layoutItem->setRowSpan( span, Qt::Vertical );
|
||||
}
|
||||
|
||||
m_data->unlimitedSpanned++;
|
||||
}
|
||||
}
|
||||
|
||||
void QskGridBox::layoutItemRemoved( QskLayoutItem* layoutItem, int index )
|
||||
{
|
||||
Q_UNUSED( index )
|
||||
|
||||
if ( layoutItem->hasUnlimitedSpan() )
|
||||
m_data->unlimitedSpanned--;
|
||||
|
||||
QskLayoutEngine& engine = this->engine();
|
||||
|
||||
// cleanup rows/columns
|
||||
|
||||
const QSize cells = engine.requiredCells();
|
||||
|
||||
const int numPendingColumns = engine.columnCount() - cells.width();
|
||||
const int numPendingRows = engine.rowCount() - cells.height();
|
||||
|
||||
if ( numPendingColumns > 0 || numPendingRows > 0 )
|
||||
{
|
||||
if ( m_data->unlimitedSpanned > 0 )
|
||||
engine.adjustSpans( cells.height(), cells.width() );
|
||||
|
||||
engine.removeRows( cells.width(), numPendingColumns, Qt::Horizontal );
|
||||
engine.removeRows( cells.height(), numPendingRows, Qt::Vertical );
|
||||
}
|
||||
}
|
||||
|
||||
void QskGridBox::setSpacing( qreal spacing )
|
||||
{
|
||||
setHorizontalSpacing( spacing );
|
||||
setVerticalSpacing( spacing );
|
||||
}
|
||||
|
||||
void QskGridBox::setHorizontalSpacing( qreal spacing )
|
||||
void QskGridBox::setSpacing( Qt::Orientations orientations, qreal spacing )
|
||||
{
|
||||
spacing = qMax( spacing, 0.0 );
|
||||
|
||||
if ( spacing != engine().spacing( Qt::Horizontal ) )
|
||||
{
|
||||
engine().setSpacing( spacing, Qt::Horizontal );
|
||||
activate();
|
||||
bool doUpdate = false;
|
||||
|
||||
Q_EMIT horizontalSpacingChanged();
|
||||
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 )
|
||||
{
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
qreal QskGridBox::horizontalSpacing() const
|
||||
void QskGridBox::resetSpacing( Qt::Orientations orientations )
|
||||
{
|
||||
return engine().spacing( Qt::Horizontal );
|
||||
}
|
||||
|
||||
void QskGridBox::resetHorizontalSpacing()
|
||||
{
|
||||
const qreal spacing = QskLayoutEngine::defaultSpacing( Qt::Horizontal );
|
||||
setHorizontalSpacing( spacing );
|
||||
}
|
||||
|
||||
void QskGridBox::setVerticalSpacing( qreal spacing )
|
||||
{
|
||||
spacing = qMax( spacing, 0.0 );
|
||||
|
||||
if ( spacing != engine().spacing( Qt::Vertical ) )
|
||||
for ( const auto o : { Qt::Horizontal, Qt::Vertical } )
|
||||
{
|
||||
engine().setSpacing( spacing, Qt::Vertical );
|
||||
activate();
|
||||
|
||||
Q_EMIT verticalSpacingChanged();
|
||||
if ( orientations & o )
|
||||
setSpacing( o, QskGridLayoutEngine::defaultSpacing( o ) );
|
||||
}
|
||||
}
|
||||
|
||||
qreal QskGridBox::verticalSpacing() const
|
||||
qreal QskGridBox::spacing( Qt::Orientation orientation ) const
|
||||
{
|
||||
return engine().spacing( Qt::Vertical );
|
||||
}
|
||||
|
||||
void QskGridBox::resetVerticalSpacing()
|
||||
{
|
||||
const qreal spacing = QskLayoutEngine::defaultSpacing( Qt::Vertical );
|
||||
setVerticalSpacing( spacing );
|
||||
return m_data->engine.spacing( orientation );
|
||||
}
|
||||
|
||||
void QskGridBox::setRowSpacing( int row, qreal spacing )
|
||||
{
|
||||
spacing = qMax( spacing, 0.0 );
|
||||
|
||||
if ( spacing != engine().rowSpacing( row, Qt::Vertical ) )
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( spacing != engine.spacingAt( Qt::Vertical, row ) )
|
||||
{
|
||||
engine().setRowSpacing( row, spacing, Qt::Vertical );
|
||||
activate();
|
||||
engine.setSpacingAt( Qt::Vertical, row, spacing );
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
qreal QskGridBox::rowSpacing( int row ) const
|
||||
{
|
||||
return engine().rowSpacing( row, Qt::Vertical );
|
||||
return m_data->engine.spacingAt( Qt::Vertical, row );
|
||||
}
|
||||
|
||||
void QskGridBox::setColumnSpacing( int column, qreal spacing )
|
||||
{
|
||||
spacing = qMax( spacing, 0.0 );
|
||||
|
||||
if ( spacing != engine().rowSpacing( column, Qt::Horizontal ) )
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( spacing != engine.spacingAt( Qt::Horizontal, column ) )
|
||||
{
|
||||
engine().setRowSpacing( column, spacing, Qt::Horizontal );
|
||||
activate();
|
||||
engine.setSpacingAt( Qt::Horizontal, column, spacing );
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
qreal QskGridBox::columnSpacing( int column ) const
|
||||
{
|
||||
return engine().rowSpacing( column, Qt::Horizontal );
|
||||
return m_data->engine.spacingAt( Qt::Horizontal, column );
|
||||
}
|
||||
|
||||
void QskGridBox::setRowStretchFactor( int row, int stretch )
|
||||
{
|
||||
if ( stretch != engine().rowStretchFactor( row, Qt::Vertical ) )
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( stretch != engine.stretchFactorAt( Qt::Vertical, row ) )
|
||||
{
|
||||
engine().setRowStretchFactor( row, stretch, Qt::Vertical );
|
||||
activate();
|
||||
engine.setStretchFactorAt( Qt::Vertical, row, stretch );
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
int QskGridBox::rowStretchFactor( int row ) const
|
||||
{
|
||||
return engine().rowStretchFactor( row, Qt::Vertical );
|
||||
return m_data->engine.stretchFactorAt( Qt::Vertical, row );
|
||||
}
|
||||
|
||||
void QskGridBox::setColumnStretchFactor( int column, int stretch )
|
||||
{
|
||||
if ( stretch != engine().rowStretchFactor( column, Qt::Horizontal ) )
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( stretch != engine.stretchFactorAt( Qt::Horizontal, column ) )
|
||||
{
|
||||
engine().setRowStretchFactor( column, stretch, Qt::Horizontal );
|
||||
activate();
|
||||
engine.setStretchFactorAt( Qt::Horizontal, column, stretch );
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
int QskGridBox::columnStretchFactor( int column ) const
|
||||
{
|
||||
return engine().rowStretchFactor( column, Qt::Horizontal );
|
||||
}
|
||||
|
||||
void QskGridBox::setRowMinimumHeight( int row, qreal height )
|
||||
{
|
||||
setRowSizeHint( Qt::MinimumSize, row, height, Qt::Vertical );
|
||||
}
|
||||
|
||||
qreal QskGridBox::rowMinimumHeight( int row ) const
|
||||
{
|
||||
return engine().rowSizeHint( Qt::MinimumSize, row, Qt::Vertical );
|
||||
}
|
||||
|
||||
void QskGridBox::setRowPreferredHeight( int row, qreal height )
|
||||
{
|
||||
setRowSizeHint( Qt::PreferredSize, row, height, Qt::Vertical );
|
||||
}
|
||||
|
||||
qreal QskGridBox::rowPreferredHeight( int row ) const
|
||||
{
|
||||
return engine().rowSizeHint( Qt::PreferredSize, row, Qt::Vertical );
|
||||
}
|
||||
|
||||
void QskGridBox::setRowMaximumHeight( int row, qreal height )
|
||||
{
|
||||
setRowSizeHint( Qt::MaximumSize, row, height, Qt::Vertical );
|
||||
}
|
||||
|
||||
qreal QskGridBox::rowMaximumHeight( int row ) const
|
||||
{
|
||||
return engine().rowSizeHint( Qt::MaximumSize, row, Qt::Vertical );
|
||||
return m_data->engine.stretchFactorAt( Qt::Horizontal, column );
|
||||
}
|
||||
|
||||
void QskGridBox::setRowFixedHeight( int row, qreal height )
|
||||
{
|
||||
setRowMinimumHeight( row, height );
|
||||
setRowMaximumHeight( row, height );
|
||||
}
|
||||
|
||||
void QskGridBox::setColumnMinimumWidth( int column, qreal width )
|
||||
{
|
||||
setRowSizeHint( Qt::MinimumSize, column, width, Qt::Horizontal );
|
||||
}
|
||||
|
||||
qreal QskGridBox::columnMinimumWidth( int column ) const
|
||||
{
|
||||
return engine().rowSizeHint( Qt::MinimumSize, column, Qt::Horizontal );
|
||||
}
|
||||
|
||||
void QskGridBox::setColumnPreferredWidth( int column, qreal width )
|
||||
{
|
||||
setRowSizeHint( Qt::PreferredSize, column, width, Qt::Horizontal );
|
||||
}
|
||||
|
||||
qreal QskGridBox::columnPreferredWidth( int column ) const
|
||||
{
|
||||
return engine().rowSizeHint( Qt::PreferredSize, column, Qt::Horizontal );
|
||||
}
|
||||
|
||||
void QskGridBox::setColumnMaximumWidth( int column, qreal width )
|
||||
{
|
||||
setRowSizeHint( Qt::MaximumSize, column, width, Qt::Horizontal );
|
||||
}
|
||||
|
||||
qreal QskGridBox::columnMaximumWidth( int column ) const
|
||||
{
|
||||
return engine().rowSizeHint( Qt::MaximumSize, column, Qt::Horizontal );
|
||||
setRowSizeHint( row, Qt::MinimumSize, height );
|
||||
setRowSizeHint( row, Qt::MaximumSize, height );
|
||||
}
|
||||
|
||||
void QskGridBox::setColumnFixedWidth( int column, qreal width )
|
||||
{
|
||||
setColumnMinimumWidth( column, width );
|
||||
setColumnMaximumWidth( column, width );
|
||||
setColumnSizeHint( column, Qt::MinimumSize, width );
|
||||
setColumnSizeHint( column, Qt::MaximumSize, width );
|
||||
}
|
||||
|
||||
void QskGridBox::setRowAlignment( int row, Qt::Alignment alignment )
|
||||
{
|
||||
if ( engine().rowAlignment( row, Qt::Vertical ) != alignment )
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( engine.alignmentAt( Qt::Vertical, row ) != alignment )
|
||||
{
|
||||
engine().setRowAlignment( row, alignment, Qt::Vertical );
|
||||
activate();
|
||||
engine.setAlignmentAt( Qt::Vertical, row, alignment );
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
Qt::Alignment QskGridBox::rowAlignment( int row ) const
|
||||
{
|
||||
return engine().rowAlignment( row, Qt::Vertical );
|
||||
return m_data->engine.alignmentAt( Qt::Vertical, row );
|
||||
}
|
||||
|
||||
void QskGridBox::setColumnAlignment( int column, Qt::Alignment alignment )
|
||||
{
|
||||
if ( alignment != engine().rowAlignment( column, Qt::Horizontal ) )
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( engine.alignmentAt( Qt::Horizontal, column ) != alignment )
|
||||
{
|
||||
engine().setRowAlignment( column, alignment, Qt::Horizontal );
|
||||
activate();
|
||||
engine.setAlignmentAt( Qt::Horizontal, column, alignment );
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
Qt::Alignment QskGridBox::columnAlignment( int column ) const
|
||||
{
|
||||
return engine().rowAlignment( column, Qt::Horizontal );
|
||||
return m_data->engine.alignmentAt( Qt::Horizontal, column );
|
||||
}
|
||||
|
||||
void QskGridBox::setAlignment( const QQuickItem* item, Qt::Alignment alignment )
|
||||
{
|
||||
QskLayoutItem* layoutItem = engine().layoutItemOf( item );
|
||||
if ( layoutItem && layoutItem->alignment() != alignment )
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( engine.alignmentOf( item ) != alignment )
|
||||
{
|
||||
layoutItem->setAlignment( alignment );
|
||||
activate();
|
||||
engine.setAlignmentOf( item, alignment );
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
Qt::Alignment QskGridBox::alignment( const QQuickItem* item ) const
|
||||
{
|
||||
QskLayoutItem* layoutItem = engine().layoutItemOf( item );
|
||||
if ( layoutItem )
|
||||
return layoutItem->alignment();
|
||||
|
||||
return Qt::Alignment();
|
||||
return m_data->engine.alignmentOf( item );
|
||||
}
|
||||
|
||||
void QskGridBox::setRetainSizeWhenHidden( const QQuickItem* item, bool on )
|
||||
{
|
||||
QskLayoutItem* layoutItem = engine().layoutItemOf( item );
|
||||
if ( layoutItem && on != layoutItem->retainSizeWhenHidden() )
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( engine.retainSizeWhenHiddenOf( item ) != on )
|
||||
{
|
||||
layoutItem->setRetainSizeWhenHidden( on );
|
||||
engine.setRetainSizeWhenHiddenOf( item, on );
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
bool QskGridBox::retainSizeWhenHidden( const QQuickItem* item ) const
|
||||
{
|
||||
QskLayoutItem* layoutItem = engine().layoutItemOf( item );
|
||||
if ( layoutItem )
|
||||
return layoutItem->retainSizeWhenHidden();
|
||||
|
||||
return false;
|
||||
return m_data->engine.retainSizeWhenHiddenOf( item );
|
||||
}
|
||||
|
||||
void QskGridBox::setRowSizeHint(
|
||||
Qt::SizeHint which, int row, qreal size, Qt::Orientation orientation )
|
||||
void QskGridBox::setRowSizeHint( int row, Qt::SizeHint which, qreal height )
|
||||
{
|
||||
if ( size != engine().rowSizeHint( which, row, orientation ) )
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( height != engine.rowSizeHint( row, which ) )
|
||||
{
|
||||
engine().setRowSizeHint( which, row, size, orientation );
|
||||
activate();
|
||||
engine.setRowSizeHint( row, which, height );
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
qreal QskGridBox::rowSizeHint( int row, Qt::SizeHint which ) const
|
||||
{
|
||||
return m_data->engine.rowSizeHint( row, which );
|
||||
}
|
||||
|
||||
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 );
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
qreal QskGridBox::columnSizeHint( int column, Qt::SizeHint which ) const
|
||||
{
|
||||
return m_data->engine.columnSizeHint( column, which );
|
||||
}
|
||||
|
||||
void QskGridBox::invalidate()
|
||||
{
|
||||
m_data->engine.invalidate();
|
||||
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
}
|
||||
|
||||
void QskGridBox::updateLayout()
|
||||
{
|
||||
m_data->engine.setGeometries( layoutRect() );
|
||||
}
|
||||
|
||||
QSizeF QskGridBox::contentsSizeHint() const
|
||||
{
|
||||
if ( itemCount() == 0 )
|
||||
return QSizeF( 0, 0 );
|
||||
|
||||
return m_data->engine.sizeHint( Qt::PreferredSize, QSizeF() );
|
||||
}
|
||||
|
||||
qreal QskGridBox::heightForWidth( qreal width ) const
|
||||
{
|
||||
auto constrainedHeight =
|
||||
[this]( QskLayoutConstraint::Type, const QskControl*, qreal width )
|
||||
{
|
||||
return m_data->engine.heightForWidth( width );
|
||||
};
|
||||
|
||||
return QskLayoutConstraint::constrainedMetric(
|
||||
QskLayoutConstraint::HeightForWidth, this, width, constrainedHeight );
|
||||
}
|
||||
|
||||
qreal QskGridBox::widthForHeight( qreal height ) const
|
||||
{
|
||||
auto constrainedWidth =
|
||||
[this]( QskLayoutConstraint::Type, const QskControl*, qreal height )
|
||||
{
|
||||
return m_data->engine.widthForHeight( height );
|
||||
};
|
||||
|
||||
return QskLayoutConstraint::constrainedMetric(
|
||||
QskLayoutConstraint::WidthForHeight, this, height, constrainedWidth );
|
||||
}
|
||||
|
||||
void QskGridBox::geometryChangeEvent( QskGeometryChangeEvent* event )
|
||||
{
|
||||
Inherited::geometryChangeEvent( event );
|
||||
|
||||
if ( event->isResized() )
|
||||
polish();
|
||||
}
|
||||
|
||||
void QskGridBox::itemChange( ItemChange change, const ItemChangeData& value )
|
||||
{
|
||||
Inherited::itemChange( change, value );
|
||||
|
||||
switch ( change )
|
||||
{
|
||||
case ItemChildRemovedChange:
|
||||
{
|
||||
removeItem( value.item );
|
||||
break;
|
||||
}
|
||||
case QQuickItem::ItemVisibleHasChanged:
|
||||
{
|
||||
if ( value.boolValue )
|
||||
polish();
|
||||
break;
|
||||
}
|
||||
case QQuickItem::ItemSceneChange:
|
||||
{
|
||||
if ( value.window )
|
||||
polish();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool QskGridBox::event( QEvent* event )
|
||||
{
|
||||
switch ( event->type() )
|
||||
{
|
||||
case QEvent::LayoutRequest:
|
||||
{
|
||||
invalidate();
|
||||
break;
|
||||
}
|
||||
case QEvent::LayoutDirectionChange:
|
||||
{
|
||||
m_data->engine.setVisualDirection(
|
||||
layoutMirroring() ? Qt::RightToLeft : Qt::LeftToRight );
|
||||
|
||||
polish();
|
||||
break;
|
||||
}
|
||||
case QEvent::ContentsRectChange:
|
||||
{
|
||||
polish();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return Inherited::event( event );
|
||||
}
|
||||
|
||||
#include "moc_QskGridBox.cpp"
|
||||
|
|
|
|||
|
|
@ -6,21 +6,16 @@
|
|||
#ifndef QSK_GRID_BOX_H
|
||||
#define QSK_GRID_BOX_H
|
||||
|
||||
#include "QskLayoutBox.h"
|
||||
#include "QskBox.h"
|
||||
|
||||
class QSK_EXPORT QskGridBox : public QskLayoutBox
|
||||
class QSK_EXPORT QskGridBox : public QskBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY( qreal horizontalSpacing READ horizontalSpacing
|
||||
WRITE setHorizontalSpacing RESET resetHorizontalSpacing
|
||||
NOTIFY horizontalSpacingChanged )
|
||||
Q_PROPERTY( bool empty READ isEmpty() )
|
||||
Q_PROPERTY( int itemCount READ itemCount() )
|
||||
|
||||
Q_PROPERTY( qreal verticalSpacing READ verticalSpacing
|
||||
WRITE setVerticalSpacing RESET resetVerticalSpacing
|
||||
NOTIFY verticalSpacingChanged )
|
||||
|
||||
using Inherited = QskLayoutBox;
|
||||
using Inherited = QskBox;
|
||||
|
||||
public:
|
||||
explicit QskGridBox( QQuickItem* parent = nullptr );
|
||||
|
|
@ -34,9 +29,18 @@ class QSK_EXPORT QskGridBox : public QskLayoutBox
|
|||
QQuickItem*, int row, int column,
|
||||
Qt::Alignment alignment = Qt::Alignment() );
|
||||
|
||||
void removeItem( const QQuickItem* );
|
||||
void removeAt( int index );
|
||||
|
||||
Q_INVOKABLE int rowCount() const;
|
||||
Q_INVOKABLE int columnCount() const;
|
||||
|
||||
int itemCount() const;
|
||||
QQuickItem* itemAtIndex( int index ) const;
|
||||
int indexOf( const QQuickItem* ) const;
|
||||
|
||||
bool isEmpty() const;
|
||||
|
||||
Q_INVOKABLE QQuickItem* itemAt( int row, int column ) const;
|
||||
Q_INVOKABLE int indexAt( int row, int column ) const;
|
||||
|
||||
|
|
@ -47,15 +51,29 @@ class QSK_EXPORT QskGridBox : public QskLayoutBox
|
|||
Q_INVOKABLE int columnSpanOfIndex( int index ) const;
|
||||
|
||||
// spacings
|
||||
void setSpacing( qreal spacing );
|
||||
|
||||
void setHorizontalSpacing( qreal spacing );
|
||||
void resetHorizontalSpacing();
|
||||
qreal horizontalSpacing() const;
|
||||
void setSpacing( Qt::Orientations, qreal spacing );
|
||||
void resetSpacing( Qt::Orientations );
|
||||
qreal spacing( Qt::Orientation ) const;
|
||||
|
||||
void setVerticalSpacing( qreal spacing );
|
||||
void resetVerticalSpacing();
|
||||
qreal verticalSpacing() const;
|
||||
#ifdef QSK_LAYOUT_COMPAT
|
||||
void setVerticalSpacing( qreal spacing ) { setSpacing( Qt::Vertical, spacing ); }
|
||||
qreal verticalSpacing() const { return spacing( Qt::Vertical ); }
|
||||
|
||||
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 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;
|
||||
|
|
@ -71,26 +89,14 @@ class QSK_EXPORT QskGridBox : public QskLayoutBox
|
|||
Q_INVOKABLE int columnStretchFactor( int column ) const;
|
||||
|
||||
// row/column size hints
|
||||
Q_INVOKABLE void setRowMinimumHeight( int row, qreal height );
|
||||
Q_INVOKABLE qreal rowMinimumHeight( int row ) const;
|
||||
|
||||
Q_INVOKABLE void setRowPreferredHeight( int row, qreal height );
|
||||
Q_INVOKABLE qreal rowPreferredHeight( int row ) const;
|
||||
Q_INVOKABLE void setColumnSizeHint( int column, Qt::SizeHint, qreal width );
|
||||
Q_INVOKABLE qreal columnSizeHint( int column, Qt::SizeHint ) const;
|
||||
|
||||
Q_INVOKABLE void setRowMaximumHeight( int row, qreal height );
|
||||
Q_INVOKABLE qreal rowMaximumHeight( int row ) const;
|
||||
Q_INVOKABLE void setRowSizeHint( int row, Qt::SizeHint, qreal height );
|
||||
Q_INVOKABLE qreal rowSizeHint( int row, Qt::SizeHint ) const;
|
||||
|
||||
Q_INVOKABLE void setRowFixedHeight( int row, qreal height );
|
||||
|
||||
Q_INVOKABLE void setColumnMinimumWidth( int column, qreal width );
|
||||
Q_INVOKABLE qreal columnMinimumWidth( int column ) const;
|
||||
|
||||
Q_INVOKABLE void setColumnPreferredWidth( int column, qreal width );
|
||||
Q_INVOKABLE qreal columnPreferredWidth( int column ) const;
|
||||
|
||||
Q_INVOKABLE void setColumnMaximumWidth( int column, qreal width );
|
||||
Q_INVOKABLE qreal columnMaximumWidth( int column ) const;
|
||||
|
||||
Q_INVOKABLE void setColumnFixedWidth( int column, qreal width );
|
||||
|
||||
// alignments
|
||||
|
|
@ -107,20 +113,23 @@ class QSK_EXPORT QskGridBox : public QskLayoutBox
|
|||
bool retainSizeWhenHidden( const QQuickItem* ) const;
|
||||
void setRetainSizeWhenHidden( const QQuickItem*, bool on );
|
||||
|
||||
Q_SIGNALS:
|
||||
void verticalSpacingChanged();
|
||||
void horizontalSpacingChanged();
|
||||
QSizeF contentsSizeHint() const override;
|
||||
|
||||
qreal heightForWidth( qreal width ) const override;
|
||||
qreal widthForHeight( qreal height ) const override;
|
||||
|
||||
public Q_SLOTS:
|
||||
void invalidate();
|
||||
void clear( bool autoDelete = false );
|
||||
|
||||
protected:
|
||||
void setupLayoutItem( QskLayoutItem*, int index ) override;
|
||||
void layoutItemInserted( QskLayoutItem*, int index ) override;
|
||||
void layoutItemRemoved( QskLayoutItem*, int index ) override;
|
||||
bool event( QEvent* ) override;
|
||||
void geometryChangeEvent( QskGeometryChangeEvent* ) override;
|
||||
|
||||
void itemChange( ItemChange, const ItemChangeData& ) override;
|
||||
void updateLayout() override;
|
||||
|
||||
private:
|
||||
void setRowSizeHint(
|
||||
Qt::SizeHint which, int row, qreal size,
|
||||
Qt::Orientation orientation );
|
||||
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
};
|
||||
|
|
@ -131,4 +140,9 @@ inline void QskGridBox::addItem(
|
|||
addItem( item, row, column, 1, 1, alignment );
|
||||
}
|
||||
|
||||
inline bool QskGridBox::isEmpty() const
|
||||
{
|
||||
return itemCount() <= 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,554 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskGridLayoutEngine.h"
|
||||
#include "QskLayoutConstraint.h"
|
||||
#include "QskSizePolicy.h"
|
||||
#include "QskControl.h"
|
||||
#include "QskQuick.h"
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
#include <private/qgridlayoutengine_p.h>
|
||||
QSK_QT_PRIVATE_END
|
||||
|
||||
namespace
|
||||
{
|
||||
class LayoutStyleInfo final : public QAbstractLayoutStyleInfo
|
||||
{
|
||||
public:
|
||||
qreal spacing( Qt::Orientation ) const override
|
||||
{
|
||||
// later from the theme !!
|
||||
return 5.0;
|
||||
}
|
||||
|
||||
qreal windowMargin( Qt::Orientation ) const override
|
||||
{
|
||||
// later from the theme !!
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool hasChangedCore() const override
|
||||
{
|
||||
return false; // never changes
|
||||
}
|
||||
};
|
||||
|
||||
class LayoutItem final : public QGridLayoutItem
|
||||
{
|
||||
public:
|
||||
LayoutItem( QQuickItem* item, int row, int column,
|
||||
int rowSpan, int columnSpan, Qt::Alignment alignment )
|
||||
: QGridLayoutItem( row, column,
|
||||
qMax( rowSpan, 1 ), qMax( columnSpan, 1 ), alignment )
|
||||
, m_item( item )
|
||||
, m_retainSizeWhenHidden( false )
|
||||
, m_unlimitedRowSpan( rowSpan <= 0 )
|
||||
, m_unlimitedColumnSpan( columnSpan <= 0 )
|
||||
{
|
||||
}
|
||||
|
||||
QQuickItem* item() const
|
||||
{
|
||||
return m_item;
|
||||
}
|
||||
|
||||
void setGeometry( const QRectF& rect ) override
|
||||
{
|
||||
qskSetItemGeometry( m_item, rect );
|
||||
}
|
||||
|
||||
QLayoutPolicy::Policy sizePolicy( Qt::Orientation orientation ) const override
|
||||
{
|
||||
const auto policy = QskLayoutConstraint::sizePolicy( m_item );
|
||||
return static_cast< QLayoutPolicy::Policy >( policy.policy( orientation ) );
|
||||
}
|
||||
|
||||
QSizeF sizeHint( Qt::SizeHint which, const QSizeF& constraint ) const override
|
||||
{
|
||||
return QskLayoutConstraint::sizeHint( m_item, which, constraint );
|
||||
}
|
||||
|
||||
bool hasDynamicConstraint() const override
|
||||
{
|
||||
using namespace QskLayoutConstraint;
|
||||
return constraintType( m_item ) != Unconstrained;
|
||||
}
|
||||
|
||||
Qt::Orientation dynamicConstraintOrientation() const override
|
||||
{
|
||||
Qt::Orientation orientation = Qt::Vertical;
|
||||
|
||||
if ( auto control = qskControlCast( m_item ) )
|
||||
{
|
||||
const auto policy = control->sizePolicy().horizontalPolicy();
|
||||
|
||||
return ( policy == QskSizePolicy::Constrained )
|
||||
? Qt::Horizontal : Qt::Vertical;
|
||||
}
|
||||
|
||||
return orientation;
|
||||
}
|
||||
|
||||
bool isIgnored() const override final
|
||||
{
|
||||
if ( m_item && !qskIsVisibleToParent( m_item ) )
|
||||
return !m_retainSizeWhenHidden;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QLayoutPolicy::ControlTypes controlTypes( LayoutSide ) const override
|
||||
{
|
||||
return QLayoutPolicy::DefaultType;
|
||||
}
|
||||
|
||||
bool retainSizeWhenHidden() const
|
||||
{
|
||||
return m_retainSizeWhenHidden;
|
||||
}
|
||||
|
||||
void setRetainSizeWhenHidden( bool on )
|
||||
{
|
||||
m_retainSizeWhenHidden = on;
|
||||
}
|
||||
|
||||
bool hasUnlimitedSpan() const
|
||||
{
|
||||
return m_unlimitedColumnSpan || m_unlimitedRowSpan;
|
||||
}
|
||||
|
||||
bool hasUnlimitedSpan( Qt::Orientation orientation ) const
|
||||
{
|
||||
return ( orientation == Qt::Horizontal )
|
||||
? m_unlimitedColumnSpan : m_unlimitedRowSpan;
|
||||
}
|
||||
|
||||
private:
|
||||
QQuickItem* m_item;
|
||||
|
||||
bool m_retainSizeWhenHidden : 1;
|
||||
bool m_unlimitedRowSpan : 1;
|
||||
bool m_unlimitedColumnSpan : 1;
|
||||
};
|
||||
|
||||
class LayoutEngine : public QGridLayoutEngine
|
||||
{
|
||||
public:
|
||||
LayoutEngine()
|
||||
: QGridLayoutEngine( Qt::AlignVCenter, false /*snapToPixelGrid*/ )
|
||||
{
|
||||
/*
|
||||
snapToPixelGrid rounds x/y, what might lead to losing a pixel.
|
||||
F.e. when having a text in elideMode we end up with an elided text
|
||||
because of this.
|
||||
*/
|
||||
}
|
||||
|
||||
LayoutItem* layoutItemAt( int index ) const
|
||||
{
|
||||
if ( index < 0 || index >= q_items.count() )
|
||||
return nullptr;
|
||||
|
||||
return static_cast< LayoutItem* >( q_items[ index ] );
|
||||
}
|
||||
|
||||
LayoutItem* layoutItemAt( int row, int column ) const
|
||||
{
|
||||
if ( row < 0 || row >= rowCount() || column < 0 || column >= columnCount() )
|
||||
return nullptr;
|
||||
|
||||
return static_cast< LayoutItem* >( itemAt( row, column ) );
|
||||
}
|
||||
|
||||
inline LayoutItem* layoutItemOf( const QQuickItem* item ) const
|
||||
{
|
||||
return layoutItemAt( indexOf( item ) );
|
||||
}
|
||||
|
||||
int indexAt( int row, int column ) const
|
||||
{
|
||||
const auto item = layoutItemAt( row, column );
|
||||
if ( item )
|
||||
return q_items.indexOf( item );
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int indexOf( const QQuickItem* item ) const
|
||||
{
|
||||
// linear search might become slow for many items,
|
||||
// better introduce some sort of hash table TODO ...
|
||||
|
||||
for ( int i = q_items.count() - 1; i >= 0; --i )
|
||||
{
|
||||
const auto layoutItem = static_cast< const LayoutItem* >( q_items[ i ] );
|
||||
if ( layoutItem->item() == item )
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
qreal spacing( Qt::Orientation orientation ) const
|
||||
{
|
||||
const LayoutStyleInfo styleInfo;
|
||||
return QGridLayoutEngine::spacing( orientation, &styleInfo );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class QskGridLayoutEngine::PrivateData
|
||||
{
|
||||
public:
|
||||
/*
|
||||
For the moment we use QGridLayoutEngine, but sooner and later
|
||||
it should be replaced by a new implementation, that uses
|
||||
the same backend as QskLinearLayoutEngine.
|
||||
*/
|
||||
LayoutEngine qengine;
|
||||
unsigned int unlimitedSpanned = 0;
|
||||
};
|
||||
|
||||
|
||||
QskGridLayoutEngine::QskGridLayoutEngine()
|
||||
: m_data( new PrivateData() )
|
||||
{
|
||||
}
|
||||
|
||||
QskGridLayoutEngine::~QskGridLayoutEngine()
|
||||
{
|
||||
}
|
||||
|
||||
void QskGridLayoutEngine::setGeometries( const QRectF rect )
|
||||
{
|
||||
const LayoutStyleInfo styleInfo;
|
||||
m_data->qengine.setGeometries( rect, &styleInfo );
|
||||
}
|
||||
|
||||
void QskGridLayoutEngine::invalidate()
|
||||
{
|
||||
m_data->qengine.invalidate();
|
||||
}
|
||||
|
||||
void QskGridLayoutEngine::setVisualDirection( Qt::LayoutDirection direction )
|
||||
{
|
||||
m_data->qengine.setVisualDirection( direction );
|
||||
}
|
||||
|
||||
Qt::LayoutDirection QskGridLayoutEngine::visualDirection() const
|
||||
{
|
||||
return m_data->qengine.visualDirection();
|
||||
}
|
||||
|
||||
int QskGridLayoutEngine::itemCount() const
|
||||
{
|
||||
return m_data->qengine.itemCount();
|
||||
}
|
||||
|
||||
int QskGridLayoutEngine::rowCount() const
|
||||
{
|
||||
return m_data->qengine.rowCount();
|
||||
}
|
||||
|
||||
int QskGridLayoutEngine::columnCount() const
|
||||
{
|
||||
return m_data->qengine.columnCount();
|
||||
}
|
||||
|
||||
void QskGridLayoutEngine::insertItem( QQuickItem* item,
|
||||
int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment )
|
||||
{
|
||||
auto& qengine = m_data->qengine;
|
||||
|
||||
auto layoutItem = new LayoutItem(
|
||||
item, row, column, rowSpan, columnSpan, alignment );
|
||||
|
||||
const bool isExpanding = ( layoutItem->lastColumn() >= qengine.columnCount() ) ||
|
||||
( layoutItem->lastRow() >= qengine.rowCount() );
|
||||
|
||||
qengine.insertItem( layoutItem, -1 );
|
||||
|
||||
if ( isExpanding )
|
||||
{
|
||||
// the new item has extended the number of rows/columns and
|
||||
// we need to adjust all items without fixed spanning
|
||||
|
||||
if ( m_data->unlimitedSpanned > 0 )
|
||||
adjustSpans( columnCount(), rowCount() );
|
||||
}
|
||||
|
||||
if ( layoutItem->hasUnlimitedSpan() )
|
||||
{
|
||||
// the item itself might need to be adjusted
|
||||
|
||||
if ( layoutItem->hasUnlimitedSpan( Qt::Horizontal ) )
|
||||
{
|
||||
const int span = columnCount() - layoutItem->firstColumn();
|
||||
layoutItem->setRowSpan( span, Qt::Horizontal );
|
||||
}
|
||||
|
||||
if ( layoutItem->hasUnlimitedSpan( Qt::Vertical ) )
|
||||
{
|
||||
const int span = rowCount() - layoutItem->firstRow();
|
||||
layoutItem->setRowSpan( span, Qt::Vertical );
|
||||
}
|
||||
|
||||
m_data->unlimitedSpanned++;
|
||||
}
|
||||
}
|
||||
|
||||
void QskGridLayoutEngine::removeAt( int index )
|
||||
{
|
||||
auto& qengine = m_data->qengine;
|
||||
|
||||
auto layoutItem = qengine.layoutItemAt( index );
|
||||
if ( layoutItem == nullptr )
|
||||
return;
|
||||
|
||||
qengine.removeItem( layoutItem );
|
||||
|
||||
if ( layoutItem->hasUnlimitedSpan() )
|
||||
m_data->unlimitedSpanned--;
|
||||
|
||||
// cleanup rows/columns
|
||||
|
||||
const QSize cells = requiredCells();
|
||||
|
||||
const int numPendingColumns = qengine.columnCount() - cells.width();
|
||||
const int numPendingRows = qengine.rowCount() - cells.height();
|
||||
|
||||
if ( numPendingColumns > 0 || numPendingRows > 0 )
|
||||
{
|
||||
if ( m_data->unlimitedSpanned > 0 )
|
||||
adjustSpans( cells.height(), cells.width() );
|
||||
|
||||
qengine.removeRows( cells.width(), numPendingColumns, Qt::Horizontal );
|
||||
qengine.removeRows( cells.height(), numPendingRows, Qt::Vertical );
|
||||
}
|
||||
|
||||
delete layoutItem;
|
||||
}
|
||||
|
||||
QQuickItem* QskGridLayoutEngine::itemAt( int index ) const
|
||||
{
|
||||
if ( const auto layoutItem = m_data->qengine.layoutItemAt( index ) )
|
||||
return layoutItem->item();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QQuickItem* QskGridLayoutEngine::itemAt( int row, int column ) const
|
||||
{
|
||||
if ( const auto layoutItem = m_data->qengine.layoutItemAt( row, column ) )
|
||||
return layoutItem->item();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int QskGridLayoutEngine::indexAt( int row, int column ) const
|
||||
{
|
||||
return m_data->qengine.indexAt( row, column );
|
||||
}
|
||||
|
||||
int QskGridLayoutEngine::indexOf( const QQuickItem* item ) const
|
||||
{
|
||||
if ( item == nullptr )
|
||||
return -1;
|
||||
|
||||
return m_data->qengine.indexOf( item );
|
||||
}
|
||||
|
||||
int QskGridLayoutEngine::rowOfIndex( int index ) const
|
||||
{
|
||||
if ( auto layoutItem = m_data->qengine.layoutItemAt( index ) )
|
||||
return layoutItem->firstRow();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int QskGridLayoutEngine::rowSpanOfIndex( int index ) const
|
||||
{
|
||||
if ( auto layoutItem = m_data->qengine.layoutItemAt( index ) )
|
||||
return layoutItem->rowSpan();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int QskGridLayoutEngine::columnOfIndex( int index ) const
|
||||
{
|
||||
if ( auto layoutItem = m_data->qengine.layoutItemAt( index ) )
|
||||
return layoutItem->firstColumn();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int QskGridLayoutEngine::columnSpanOfIndex( int index ) const
|
||||
{
|
||||
if ( auto layoutItem = m_data->qengine.layoutItemAt( index ) )
|
||||
return layoutItem->columnSpan();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void QskGridLayoutEngine::setSpacing(
|
||||
Qt::Orientation orientation, qreal spacing )
|
||||
{
|
||||
m_data->qengine.setSpacing( spacing, orientation );
|
||||
}
|
||||
|
||||
qreal QskGridLayoutEngine::spacing( Qt::Orientation orientation ) const
|
||||
{
|
||||
return m_data->qengine.spacing( orientation );
|
||||
}
|
||||
|
||||
void QskGridLayoutEngine::setSpacingAt(
|
||||
Qt::Orientation orientation, int cell, qreal spacing )
|
||||
{
|
||||
// is this a spacer ???
|
||||
m_data->qengine.setRowSpacing( cell, spacing, orientation );
|
||||
}
|
||||
|
||||
qreal QskGridLayoutEngine::spacingAt(
|
||||
Qt::Orientation orientation, int cell ) const
|
||||
{
|
||||
return m_data->qengine.rowSpacing( cell, orientation );
|
||||
}
|
||||
|
||||
void QskGridLayoutEngine::setStretchFactorAt(
|
||||
Qt::Orientation orientation, int cell, int stretch )
|
||||
{
|
||||
m_data->qengine.setRowStretchFactor( cell, stretch, orientation );
|
||||
}
|
||||
|
||||
int QskGridLayoutEngine::stretchFactorAt( Qt::Orientation orientation, int cell )
|
||||
{
|
||||
return m_data->qengine.rowStretchFactor( cell, orientation );
|
||||
}
|
||||
|
||||
void QskGridLayoutEngine::setAlignmentAt(
|
||||
Qt::Orientation orientation, int cell, Qt::Alignment alignment )
|
||||
{
|
||||
m_data->qengine.setRowAlignment( cell, alignment, orientation );
|
||||
}
|
||||
|
||||
Qt::Alignment QskGridLayoutEngine::alignmentAt(
|
||||
Qt::Orientation orientation, int cell ) const
|
||||
{
|
||||
return m_data->qengine.rowAlignment( cell, orientation );
|
||||
}
|
||||
|
||||
void QskGridLayoutEngine::setAlignmentOf(
|
||||
const QQuickItem* item, Qt::Alignment alignment )
|
||||
{
|
||||
if ( auto layoutItem = m_data->qengine.layoutItemOf( item ) )
|
||||
layoutItem->setAlignment( alignment );
|
||||
}
|
||||
|
||||
Qt::Alignment QskGridLayoutEngine::alignmentOf( const QQuickItem* item ) const
|
||||
{
|
||||
if ( const auto layoutItem = m_data->qengine.layoutItemOf( item ) )
|
||||
return layoutItem->alignment();
|
||||
|
||||
return Qt::Alignment();
|
||||
}
|
||||
|
||||
void QskGridLayoutEngine::setRetainSizeWhenHiddenOf( const QQuickItem* item, bool on )
|
||||
{
|
||||
if ( auto layoutItem = m_data->qengine.layoutItemOf( item ) )
|
||||
layoutItem->setRetainSizeWhenHidden( on );
|
||||
}
|
||||
|
||||
bool QskGridLayoutEngine::retainSizeWhenHiddenOf( const QQuickItem* item ) const
|
||||
{
|
||||
if ( const auto layoutItem = m_data->qengine.layoutItemOf( item ) )
|
||||
return layoutItem->retainSizeWhenHidden();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void QskGridLayoutEngine::setRowSizeHint( int row, Qt::SizeHint which, qreal height )
|
||||
{
|
||||
m_data->qengine.setRowSizeHint( which, row, height, Qt::Vertical );
|
||||
}
|
||||
|
||||
qreal QskGridLayoutEngine::rowSizeHint( int row, Qt::SizeHint which ) const
|
||||
{
|
||||
return m_data->qengine.rowSizeHint( which, row, Qt::Vertical );
|
||||
}
|
||||
|
||||
void QskGridLayoutEngine::setColumnSizeHint( int column, Qt::SizeHint which, qreal width )
|
||||
{
|
||||
m_data->qengine.setRowSizeHint( which, column, width, Qt::Horizontal );
|
||||
}
|
||||
|
||||
qreal QskGridLayoutEngine::columnSizeHint( int column, Qt::SizeHint which ) const
|
||||
{
|
||||
return m_data->qengine.rowSizeHint( which, column, Qt::Horizontal );
|
||||
}
|
||||
|
||||
QSizeF QskGridLayoutEngine::sizeHint( Qt::SizeHint which, const QSizeF& constraint ) const
|
||||
{
|
||||
const LayoutStyleInfo styleInfo;
|
||||
return m_data->qengine.sizeHint( which, constraint, &styleInfo );
|
||||
}
|
||||
|
||||
qreal QskGridLayoutEngine::widthForHeight( qreal height ) const
|
||||
{
|
||||
const QSizeF constraint( -1, height );
|
||||
return sizeHint( Qt::PreferredSize, constraint ).width();
|
||||
}
|
||||
|
||||
qreal QskGridLayoutEngine::heightForWidth( qreal width ) const
|
||||
{
|
||||
const QSizeF constraint( width, -1 );
|
||||
return sizeHint( Qt::PreferredSize, constraint ).height();
|
||||
}
|
||||
|
||||
qreal QskGridLayoutEngine::defaultSpacing( Qt::Orientation orientation )
|
||||
{
|
||||
return LayoutStyleInfo().spacing( orientation );
|
||||
}
|
||||
|
||||
QSize QskGridLayoutEngine::requiredCells() const
|
||||
{
|
||||
int lastRow = -1;
|
||||
int lastColumn = -1;
|
||||
|
||||
for ( int i = 0; i < m_data->qengine.itemCount(); i++ )
|
||||
{
|
||||
const auto layoutItem = m_data->qengine.layoutItemAt( i );
|
||||
if ( layoutItem->isIgnored() )
|
||||
continue;
|
||||
|
||||
const int col = layoutItem->hasUnlimitedSpan( Qt::Horizontal )
|
||||
? layoutItem->firstColumn() + 1 : layoutItem->lastColumn();
|
||||
|
||||
if ( col > lastColumn )
|
||||
lastColumn = col;
|
||||
|
||||
const int row = layoutItem->hasUnlimitedSpan( Qt::Vertical )
|
||||
? layoutItem->firstRow() + 1 : layoutItem->lastRow();
|
||||
|
||||
if ( row > lastRow )
|
||||
lastRow = row;
|
||||
}
|
||||
|
||||
return QSize( lastColumn + 1, lastRow + 1 );
|
||||
}
|
||||
|
||||
void QskGridLayoutEngine::adjustSpans( int numRows, int numColumns )
|
||||
{
|
||||
for ( int i = 0; i < m_data->qengine.itemCount(); i++ )
|
||||
{
|
||||
auto layoutItem = m_data->qengine.layoutItemAt( i );
|
||||
|
||||
if ( layoutItem->hasUnlimitedSpan( Qt::Horizontal ) )
|
||||
layoutItem->setRowSpan( numColumns - layoutItem->firstColumn(), Qt::Horizontal );
|
||||
|
||||
if ( layoutItem->hasUnlimitedSpan( Qt::Vertical ) )
|
||||
layoutItem->setRowSpan( numRows - layoutItem->firstRow(), Qt::Vertical );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_GRID_LAYOUT_ENGINE_H
|
||||
#define QSK_GRID_LAYOUT_ENGINE_H
|
||||
|
||||
#include "QskGlobal.h"
|
||||
|
||||
#include <qnamespace.h>
|
||||
#include <qrect.h>
|
||||
#include <memory>
|
||||
|
||||
class QQuickItem;
|
||||
|
||||
class QskGridLayoutEngine
|
||||
{
|
||||
public:
|
||||
QskGridLayoutEngine();
|
||||
~QskGridLayoutEngine();
|
||||
|
||||
void setGeometries( const QRectF );
|
||||
void invalidate();
|
||||
|
||||
void setVisualDirection( Qt::LayoutDirection );
|
||||
Qt::LayoutDirection visualDirection() 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 );
|
||||
qreal rowSizeHint( int row, Qt::SizeHint ) const;
|
||||
|
||||
void setColumnSizeHint( int column, Qt::SizeHint, qreal width );
|
||||
qreal columnSizeHint( int column, Qt::SizeHint ) const;
|
||||
|
||||
QSizeF sizeHint( Qt::SizeHint, const QSizeF& constraint = QSizeF() ) const;
|
||||
|
||||
qreal widthForHeight( qreal height ) const;
|
||||
qreal heightForWidth( qreal width ) const;
|
||||
|
||||
static qreal defaultSpacing( Qt::Orientation );
|
||||
|
||||
#if 1
|
||||
QSize requiredCells() const;
|
||||
void adjustSpans( int numRows, int numColumns );
|
||||
#endif
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QskGridLayoutEngine)
|
||||
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -4,8 +4,6 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include "QskIndexedLayoutBox.h"
|
||||
#include "QskLayoutEngine.h"
|
||||
#include "QskLayoutItem.h"
|
||||
#include "QskQuick.h"
|
||||
|
||||
class QskIndexedLayoutBox::PrivateData
|
||||
|
|
@ -14,30 +12,15 @@ class QskIndexedLayoutBox::PrivateData
|
|||
PrivateData()
|
||||
: autoAddChildren( true )
|
||||
, blockChildAdded( false )
|
||||
, defaultAlignment( Qt::AlignLeft | Qt::AlignVCenter )
|
||||
{
|
||||
}
|
||||
|
||||
bool autoAddChildren : 1;
|
||||
bool blockChildAdded : 1;
|
||||
|
||||
/*
|
||||
QGridLayoutEngine is supposed to find the alignment
|
||||
( see: QGridLayoutEngine::effectiveAlignment ) by looking up in:
|
||||
item -> row/column -> layout default.
|
||||
|
||||
Unfortunatly the layout default can't be modified without accessing
|
||||
private methods and - for some reason worse - QGridLayoutEngine::effectiveAlignment
|
||||
does not fall back to the layout default for the horizontal alignment.
|
||||
|
||||
But as we don't offer setting the row/column alignment at the public API
|
||||
of QskIndexedLayoutBox we work around by using them instead.
|
||||
*/
|
||||
Qt::Alignment defaultAlignment;
|
||||
};
|
||||
|
||||
QskIndexedLayoutBox::QskIndexedLayoutBox( QQuickItem* parent )
|
||||
: QskLayoutBox( parent )
|
||||
: QskBox( false, parent )
|
||||
, m_data( new PrivateData() )
|
||||
{
|
||||
// classBegin/componentComplete -> setActive( false/true ) ?
|
||||
|
|
@ -61,142 +44,6 @@ bool QskIndexedLayoutBox::autoAddChildren() const
|
|||
return m_data->autoAddChildren;
|
||||
}
|
||||
|
||||
void QskIndexedLayoutBox::setDefaultAlignment( Qt::Alignment alignment )
|
||||
{
|
||||
bool hasChanged = false;
|
||||
|
||||
const Qt::Alignment alignV = alignment & Qt::AlignVertical_Mask;
|
||||
if ( alignV != ( m_data->defaultAlignment & Qt::AlignVertical_Mask ) )
|
||||
{
|
||||
hasChanged = true;
|
||||
|
||||
for ( int row = 0; row < engine().rowCount(); row++ )
|
||||
engine().setRowAlignment( row, alignV, Qt::Vertical );
|
||||
}
|
||||
|
||||
const Qt::Alignment alignH = alignment & Qt::AlignHorizontal_Mask;
|
||||
if ( alignH != ( m_data->defaultAlignment & Qt::AlignHorizontal_Mask ) )
|
||||
{
|
||||
hasChanged = true;
|
||||
|
||||
for ( int col = 0; col < engine().columnCount(); col++ )
|
||||
engine().setRowAlignment( col, alignH, Qt::Horizontal );
|
||||
}
|
||||
|
||||
if ( hasChanged )
|
||||
{
|
||||
m_data->defaultAlignment = alignment;
|
||||
Q_EMIT defaultAlignmentChanged();
|
||||
}
|
||||
}
|
||||
|
||||
Qt::Alignment QskIndexedLayoutBox::defaultAlignment() const
|
||||
{
|
||||
return m_data->defaultAlignment;
|
||||
}
|
||||
|
||||
void QskIndexedLayoutBox::addItem(
|
||||
QQuickItem* item, Qt::Alignment alignment )
|
||||
{
|
||||
insertItem( -1, item, alignment );
|
||||
}
|
||||
|
||||
void QskIndexedLayoutBox::insertItem(
|
||||
int index, QQuickItem* item, Qt::Alignment alignment )
|
||||
{
|
||||
if ( item == nullptr )
|
||||
return;
|
||||
|
||||
if ( item->parentItem() == this )
|
||||
{
|
||||
const int oldIndex = indexOf( item );
|
||||
if ( oldIndex >= 0 )
|
||||
{
|
||||
// the item has been inserted before
|
||||
|
||||
const bool doAppend = index < 0 || index >= itemCount();
|
||||
|
||||
if ( ( index == oldIndex ) ||
|
||||
( doAppend && oldIndex == itemCount() - 1 ) )
|
||||
{
|
||||
// already at its position, nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
removeAt( oldIndex );
|
||||
}
|
||||
}
|
||||
|
||||
auto layoutItem = new QskLayoutItem( item, 0, 0 );
|
||||
layoutItem->setAlignment( alignment );
|
||||
|
||||
insertLayoutItem( layoutItem, index );
|
||||
}
|
||||
|
||||
void QskIndexedLayoutBox::setAlignment( int index, Qt::Alignment alignment )
|
||||
{
|
||||
auto layoutItem = engine().layoutItemAt( index );
|
||||
if ( layoutItem && ( alignment != layoutItem->alignment() ) )
|
||||
{
|
||||
layoutItem->setAlignment( alignment );
|
||||
activate(); // invalidate() ???
|
||||
}
|
||||
}
|
||||
|
||||
Qt::Alignment QskIndexedLayoutBox::alignment( int index ) const
|
||||
{
|
||||
const auto layoutItem = engine().layoutItemAt( index );
|
||||
if ( layoutItem )
|
||||
return layoutItem->alignment();
|
||||
|
||||
return Qt::Alignment();
|
||||
}
|
||||
|
||||
void QskIndexedLayoutBox::setAlignment(
|
||||
const QQuickItem* item, Qt::Alignment alignment )
|
||||
{
|
||||
setAlignment( engine().indexOf( item ), alignment );
|
||||
}
|
||||
|
||||
Qt::Alignment QskIndexedLayoutBox::alignment( const QQuickItem* item ) const
|
||||
{
|
||||
return alignment( engine().indexOf( item ) );
|
||||
}
|
||||
|
||||
void QskIndexedLayoutBox::insertLayoutItem(
|
||||
QskLayoutItem* layoutItem, int index )
|
||||
{
|
||||
const int numItems = itemCount();
|
||||
if ( index < 0 || index > numItems )
|
||||
index = numItems;
|
||||
|
||||
setupLayoutItem( layoutItem, index );
|
||||
|
||||
const int rowCount = engine().rowCount();
|
||||
const int columnCount = engine().columnCount();
|
||||
|
||||
// not exception safe !!
|
||||
m_data->blockChildAdded = true;
|
||||
insertItemInternal( layoutItem, index );
|
||||
m_data->blockChildAdded = false;
|
||||
|
||||
if ( rowCount != engine().rowCount() )
|
||||
{
|
||||
const Qt::Alignment alignV = m_data->defaultAlignment & Qt::AlignVertical_Mask;
|
||||
for ( int row = 0; row < engine().rowCount(); row++ )
|
||||
engine().setRowAlignment( row, alignV, Qt::Vertical );
|
||||
}
|
||||
|
||||
if ( columnCount != engine().columnCount() )
|
||||
{
|
||||
const Qt::Alignment alignH = m_data->defaultAlignment & Qt::AlignHorizontal_Mask;
|
||||
for ( int col = 0; col < engine().columnCount(); col++ )
|
||||
engine().setRowAlignment( col, alignH, Qt::Horizontal );
|
||||
}
|
||||
|
||||
layoutItemInserted( layoutItem, index );
|
||||
}
|
||||
|
||||
void QskIndexedLayoutBox::itemChange(
|
||||
QQuickItem::ItemChange change, const QQuickItem::ItemChangeData& value )
|
||||
{
|
||||
|
|
@ -207,16 +54,27 @@ void QskIndexedLayoutBox::itemChange(
|
|||
if ( m_data->autoAddChildren && !m_data->blockChildAdded )
|
||||
{
|
||||
if ( !qskIsTransparentForPositioner( value.item ) )
|
||||
addItem( value.item );
|
||||
autoAddItem( value.item );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case QQuickItem::ItemChildRemovedChange:
|
||||
{
|
||||
removeItem( value.item );
|
||||
autoRemoveItem( value.item );
|
||||
break;
|
||||
}
|
||||
#if 1
|
||||
case QQuickItem::ItemSceneChange:
|
||||
{
|
||||
// when changing the window we should run into polish anyway
|
||||
if ( value.window )
|
||||
polish();
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
|
|
@ -226,4 +84,17 @@ void QskIndexedLayoutBox::itemChange(
|
|||
return Inherited::itemChange( change, value );
|
||||
}
|
||||
|
||||
void QskIndexedLayoutBox::reparentItem( QQuickItem* item )
|
||||
{
|
||||
if ( item->parent() == nullptr )
|
||||
item->setParent( this );
|
||||
|
||||
if ( item->parentItem() != this )
|
||||
{
|
||||
m_data->blockChildAdded = true;
|
||||
item->setParentItem( this );
|
||||
m_data->blockChildAdded = false;
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_QskIndexedLayoutBox.cpp"
|
||||
|
|
|
|||
|
|
@ -6,19 +6,16 @@
|
|||
#ifndef QSK_INDEXED_LAYOUT_BOX_H
|
||||
#define QSK_INDEXED_LAYOUT_BOX_H
|
||||
|
||||
#include "QskLayoutBox.h"
|
||||
#include "QskBox.h"
|
||||
|
||||
class QSK_EXPORT QskIndexedLayoutBox : public QskLayoutBox
|
||||
class QSK_EXPORT QskIndexedLayoutBox : public QskBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY( bool autoAddChildren READ autoAddChildren
|
||||
WRITE setAutoAddChildren NOTIFY autoAddChildrenChanged )
|
||||
|
||||
Q_PROPERTY( Qt::Alignment defaultAlignment READ defaultAlignment
|
||||
WRITE setDefaultAlignment NOTIFY defaultAlignmentChanged )
|
||||
|
||||
using Inherited = QskLayoutBox;
|
||||
using Inherited = QskBox;
|
||||
|
||||
public:
|
||||
explicit QskIndexedLayoutBox( QQuickItem* parent = nullptr );
|
||||
|
|
@ -27,28 +24,15 @@ class QSK_EXPORT QskIndexedLayoutBox : public QskLayoutBox
|
|||
void setAutoAddChildren( bool );
|
||||
bool autoAddChildren() const;
|
||||
|
||||
void setDefaultAlignment( Qt::Alignment );
|
||||
Qt::Alignment defaultAlignment() const;
|
||||
|
||||
Q_INVOKABLE void addItem(
|
||||
QQuickItem*, Qt::Alignment alignment = Qt::Alignment() );
|
||||
|
||||
Q_INVOKABLE void insertItem(
|
||||
int index, QQuickItem*, Qt::Alignment alignment = Qt::Alignment() );
|
||||
|
||||
void setAlignment( int index, Qt::Alignment );
|
||||
Qt::Alignment alignment( int index ) const;
|
||||
|
||||
void setAlignment( const QQuickItem*, Qt::Alignment );
|
||||
Qt::Alignment alignment( const QQuickItem* ) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void autoAddChildrenChanged();
|
||||
void defaultAlignmentChanged();
|
||||
|
||||
protected:
|
||||
void itemChange( ItemChange, const ItemChangeData& ) override;
|
||||
void insertLayoutItem( QskLayoutItem*, int index );
|
||||
void reparentItem( QQuickItem* );
|
||||
|
||||
virtual void autoAddItem( QQuickItem* ) = 0;
|
||||
virtual void autoRemoveItem( QQuickItem* ) = 0;
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
|
|
|
|||
|
|
@ -1,403 +0,0 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskLayoutBox.h"
|
||||
#include "QskEvent.h"
|
||||
#include "QskLayoutEngine.h"
|
||||
#include "QskLayoutItem.h"
|
||||
#include "QskLayoutConstraint.h"
|
||||
|
||||
class QskLayoutBox::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData()
|
||||
: isActive( true )
|
||||
{
|
||||
}
|
||||
|
||||
bool isActive : 1;
|
||||
|
||||
QskLayoutEngine engine;
|
||||
};
|
||||
|
||||
QskLayoutBox::QskLayoutBox( QQuickItem* parent )
|
||||
: QskBox( false, parent )
|
||||
, m_data( new PrivateData() )
|
||||
{
|
||||
}
|
||||
|
||||
QskLayoutBox::~QskLayoutBox()
|
||||
{
|
||||
disconnect( this, 0, this, 0 ); // destructor runs on invalidate else
|
||||
setActive( false );
|
||||
}
|
||||
|
||||
void QskLayoutBox::setActive( bool on )
|
||||
{
|
||||
if ( on == m_data->isActive )
|
||||
return;
|
||||
|
||||
m_data->isActive = on;
|
||||
|
||||
for ( int i = 0; i < itemCount(); ++i )
|
||||
{
|
||||
if( auto item = itemAtIndex( i ) )
|
||||
setItemActive( item, on );
|
||||
}
|
||||
|
||||
if ( on )
|
||||
{
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
}
|
||||
|
||||
Q_EMIT activeChanged( m_data->isActive );
|
||||
}
|
||||
|
||||
bool QskLayoutBox::isActive() const
|
||||
{
|
||||
return m_data->isActive;
|
||||
}
|
||||
|
||||
int QskLayoutBox::itemCount() const
|
||||
{
|
||||
return m_data->engine.itemCount();
|
||||
}
|
||||
|
||||
QQuickItem* QskLayoutBox::itemAtIndex( int index ) const
|
||||
{
|
||||
if ( auto layoutItem = m_data->engine.layoutItemAt( index ) )
|
||||
return layoutItem->item();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int QskLayoutBox::indexOf( const QQuickItem* item ) const
|
||||
{
|
||||
if ( item != nullptr )
|
||||
return m_data->engine.indexOf( item );
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void QskLayoutBox::insertItemInternal( QskLayoutItem* layoutItem, int index )
|
||||
{
|
||||
// check if item is already inserted ???
|
||||
|
||||
auto item = layoutItem->item();
|
||||
|
||||
if ( index > itemCount() )
|
||||
index = -1; // append
|
||||
|
||||
auto& engine = this->engine();
|
||||
|
||||
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() );
|
||||
}
|
||||
}
|
||||
|
||||
engine.insertLayoutItem( layoutItem, index );
|
||||
|
||||
if ( m_data->isActive )
|
||||
{
|
||||
setItemActive( item, true );
|
||||
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
void QskLayoutBox::removeAt( int index )
|
||||
{
|
||||
auto& engine = this->engine();
|
||||
|
||||
auto layoutItem = engine.layoutItemAt( index );
|
||||
if ( layoutItem == nullptr )
|
||||
return;
|
||||
|
||||
setItemActive( layoutItem->item(), false );
|
||||
engine.removeItem( layoutItem );
|
||||
|
||||
layoutItemRemoved( layoutItem, index );
|
||||
|
||||
delete layoutItem;
|
||||
|
||||
if ( m_data->isActive )
|
||||
{
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
void QskLayoutBox::removeItem( const QQuickItem* item )
|
||||
{
|
||||
removeAt( indexOf( item ) );
|
||||
}
|
||||
|
||||
void QskLayoutBox::clear( bool autoDelete )
|
||||
{
|
||||
const bool isActive = m_data->isActive;
|
||||
setActive( false );
|
||||
|
||||
for ( int i = itemCount() - 1; i >= 0; i-- )
|
||||
{
|
||||
auto item = itemAtIndex( i );
|
||||
|
||||
removeAt( i );
|
||||
|
||||
if( item )
|
||||
{
|
||||
if( autoDelete && ( item->parent() == this ) )
|
||||
delete item;
|
||||
else
|
||||
item->setParentItem( nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
setActive( isActive );
|
||||
}
|
||||
|
||||
void QskLayoutBox::setupLayoutItem( QskLayoutItem* layoutItem, int index )
|
||||
{
|
||||
Q_UNUSED( layoutItem )
|
||||
Q_UNUSED( index )
|
||||
}
|
||||
|
||||
void QskLayoutBox::layoutItemInserted( QskLayoutItem* layoutItem, int index )
|
||||
{
|
||||
Q_UNUSED( layoutItem )
|
||||
Q_UNUSED( index )
|
||||
}
|
||||
|
||||
void QskLayoutBox::layoutItemRemoved( QskLayoutItem* layoutItem, int index )
|
||||
{
|
||||
Q_UNUSED( layoutItem )
|
||||
Q_UNUSED( index )
|
||||
}
|
||||
|
||||
void QskLayoutBox::activate()
|
||||
{
|
||||
if ( m_data->isActive )
|
||||
polish();
|
||||
}
|
||||
|
||||
void QskLayoutBox::invalidate()
|
||||
{
|
||||
engine().invalidate();
|
||||
activate();
|
||||
|
||||
resetImplicitSize();
|
||||
}
|
||||
|
||||
void QskLayoutBox::adjustItem( const QQuickItem* item )
|
||||
{
|
||||
adjustItemAt( indexOf( item ) );
|
||||
}
|
||||
|
||||
void QskLayoutBox::adjustItemAt( int index )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
void QskLayoutBox::updateLayout()
|
||||
{
|
||||
if ( m_data->isActive )
|
||||
engine().setGeometries( alignedLayoutRect( layoutRect() ) );
|
||||
}
|
||||
|
||||
QRectF QskLayoutBox::alignedLayoutRect( const QRectF& rect ) const
|
||||
{
|
||||
return rect;
|
||||
}
|
||||
|
||||
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, QSizeF() );
|
||||
}
|
||||
|
||||
qreal QskLayoutBox::heightForWidth( qreal width ) const
|
||||
{
|
||||
auto constrainedHeight =
|
||||
[this]( QskLayoutConstraint::Type, const QskControl*, qreal width )
|
||||
{
|
||||
return engine().heightForWidth( width );
|
||||
};
|
||||
|
||||
return QskLayoutConstraint::constrainedMetric(
|
||||
QskLayoutConstraint::HeightForWidth, this, width, constrainedHeight );
|
||||
}
|
||||
|
||||
qreal QskLayoutBox::widthForHeight( qreal height ) const
|
||||
{
|
||||
auto constrainedWidth =
|
||||
[this]( QskLayoutConstraint::Type, const QskControl*, qreal height )
|
||||
{
|
||||
return engine().widthForHeight( height );
|
||||
};
|
||||
|
||||
return QskLayoutConstraint::constrainedMetric(
|
||||
QskLayoutConstraint::WidthForHeight, this, height, constrainedWidth );
|
||||
}
|
||||
|
||||
void QskLayoutBox::geometryChangeEvent( QskGeometryChangeEvent* event )
|
||||
{
|
||||
Inherited::geometryChangeEvent( event );
|
||||
|
||||
if ( event->isResized() )
|
||||
activate();
|
||||
}
|
||||
|
||||
void QskLayoutBox::setItemActive( const QQuickItem* item, bool on )
|
||||
{
|
||||
if ( item == nullptr )
|
||||
return;
|
||||
|
||||
// QskControl sends QEvent::LayoutRequest
|
||||
|
||||
const bool hasLayoutRequests = qskControlCast( item );
|
||||
if ( !hasLayoutRequests )
|
||||
{
|
||||
if ( on )
|
||||
{
|
||||
connect( item, &QQuickItem::implicitWidthChanged,
|
||||
this, &QskLayoutBox::invalidate );
|
||||
|
||||
connect( item, &QQuickItem::implicitHeightChanged,
|
||||
this, &QskLayoutBox::invalidate );
|
||||
}
|
||||
else
|
||||
{
|
||||
disconnect( item, &QQuickItem::implicitWidthChanged,
|
||||
this, &QskLayoutBox::invalidate );
|
||||
|
||||
disconnect( item, &QQuickItem::implicitHeightChanged,
|
||||
this, &QskLayoutBox::invalidate );
|
||||
}
|
||||
}
|
||||
|
||||
if ( on )
|
||||
connect( item, &QQuickItem::visibleChanged, this, &QskLayoutBox::activate );
|
||||
else
|
||||
disconnect( item, &QQuickItem::visibleChanged, this, &QskLayoutBox::activate );
|
||||
}
|
||||
|
||||
QskLayoutEngine& QskLayoutBox::engine()
|
||||
{
|
||||
return m_data->engine;
|
||||
}
|
||||
|
||||
const QskLayoutEngine& QskLayoutBox::engine() const
|
||||
{
|
||||
return m_data->engine;
|
||||
}
|
||||
|
||||
void QskLayoutBox::itemChange( ItemChange change, const ItemChangeData& value )
|
||||
{
|
||||
Inherited::itemChange( change, value );
|
||||
|
||||
switch ( change )
|
||||
{
|
||||
case ItemChildRemovedChange:
|
||||
{
|
||||
removeItem( value.item );
|
||||
break;
|
||||
}
|
||||
case QQuickItem::ItemVisibleHasChanged:
|
||||
{
|
||||
if ( value.boolValue )
|
||||
activate();
|
||||
break;
|
||||
}
|
||||
case QQuickItem::ItemSceneChange:
|
||||
{
|
||||
if ( value.window )
|
||||
activate();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool QskLayoutBox::event( QEvent* event )
|
||||
{
|
||||
switch ( event->type() )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
#include "moc_QskLayoutBox.cpp"
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_LAYOUT_BOX_H
|
||||
#define QSK_LAYOUT_BOX_H
|
||||
|
||||
#include "QskBox.h"
|
||||
|
||||
class QskLayoutEngine;
|
||||
class QskLayoutItem;
|
||||
|
||||
class QSK_EXPORT QskLayoutBox : public QskBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
// signals ???
|
||||
Q_PROPERTY( int itemCount READ itemCount() )
|
||||
Q_PROPERTY( bool empty READ isEmpty() )
|
||||
|
||||
Q_PROPERTY( bool active READ isActive
|
||||
WRITE setActive NOTIFY activeChanged )
|
||||
|
||||
using Inherited = QskBox;
|
||||
|
||||
public:
|
||||
explicit QskLayoutBox( QQuickItem* parent = nullptr );
|
||||
~QskLayoutBox() override;
|
||||
|
||||
bool isEmpty() const;
|
||||
|
||||
int itemCount() const;
|
||||
QQuickItem* itemAtIndex( int index ) const;
|
||||
int indexOf( const QQuickItem* ) const;
|
||||
|
||||
void removeItem( const QQuickItem* );
|
||||
void removeAt( int index );
|
||||
|
||||
void setActive( bool );
|
||||
bool isActive() const;
|
||||
|
||||
void adjustItem( const QQuickItem* );
|
||||
void adjustItemAt( int index );
|
||||
|
||||
QSizeF contentsSizeHint() const override;
|
||||
|
||||
qreal heightForWidth( qreal width ) const override;
|
||||
qreal widthForHeight( qreal height ) const override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void activeChanged( bool );
|
||||
|
||||
public Q_SLOTS:
|
||||
void activate();
|
||||
void invalidate();
|
||||
void clear( bool autoDelete = false );
|
||||
|
||||
protected:
|
||||
bool event( QEvent* ) override;
|
||||
void geometryChangeEvent( QskGeometryChangeEvent* ) override;
|
||||
|
||||
void itemChange( ItemChange, const ItemChangeData& ) override;
|
||||
void updateLayout() override;
|
||||
|
||||
QskLayoutEngine& engine();
|
||||
const QskLayoutEngine& engine() const;
|
||||
|
||||
void setItemActive( const QQuickItem*, bool on );
|
||||
|
||||
void insertItemInternal( QskLayoutItem*, int index );
|
||||
|
||||
virtual void setupLayoutItem( QskLayoutItem*, int index );
|
||||
virtual void layoutItemInserted( QskLayoutItem*, int index );
|
||||
virtual void layoutItemRemoved( QskLayoutItem*, int index );
|
||||
|
||||
virtual QRectF alignedLayoutRect( const QRectF& ) const;
|
||||
virtual QSizeF layoutItemsSizeHint() const;
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
};
|
||||
|
||||
inline bool QskLayoutBox::isEmpty() const
|
||||
{
|
||||
return itemCount() <= 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -103,10 +103,10 @@ QskLayoutConstraint::Type QskLayoutConstraint::constraintType( const QQuickItem*
|
|||
Type constraintType = Unconstrained;
|
||||
|
||||
if ( auto control = qskControlCast( item ) )
|
||||
{
|
||||
{
|
||||
const auto policy = control->sizePolicy();
|
||||
if ( policy.horizontalPolicy() == QskSizePolicy::Constrained )
|
||||
{
|
||||
{
|
||||
constraintType = WidthForHeight;
|
||||
}
|
||||
else if ( policy.verticalPolicy() == QskSizePolicy::Constrained )
|
||||
|
|
@ -125,7 +125,7 @@ QskLayoutConstraint::Type QskLayoutConstraint::constraintType( const QQuickItem*
|
|||
constraintType = HeightForWidth;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return constraintType;
|
||||
}
|
||||
|
||||
|
|
@ -366,7 +366,7 @@ qreal QskLayoutConstraint::sizeHint( const QQuickItem* item,
|
|||
QSizeF QskLayoutConstraint::sizeHint( const QQuickItem* item,
|
||||
Qt::SizeHint whichHint, const QSizeF& constraint )
|
||||
{
|
||||
if ( item == nullptr || whichHint < Qt::MinimumSize || whichHint > Qt::MaximumSize )
|
||||
if ( item == nullptr || whichHint < Qt::MinimumSize || whichHint > Qt::MaximumSize )
|
||||
return QSizeF( 0, 0 );
|
||||
|
||||
QSizeF hint( 0, 0 );
|
||||
|
|
@ -438,7 +438,7 @@ QRectF QskLayoutConstraint::itemRect( const QQuickItem* item,
|
|||
switch( constraintType( item ) )
|
||||
{
|
||||
case HeightForWidth:
|
||||
{
|
||||
{
|
||||
if ( size.width() > rect.width() )
|
||||
size = qskExpandedSize( item, QSizeF( rect.width(), -1 ) );
|
||||
|
||||
|
|
|
|||
|
|
@ -1,239 +0,0 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskLayoutEngine.h"
|
||||
#include "QskLayoutItem.h"
|
||||
|
||||
static inline bool qskIsColliding(
|
||||
const QskLayoutEngine* engine, QskLayoutItem* item )
|
||||
{
|
||||
for ( int row = item->firstRow(); row <= item->lastRow(); row++ )
|
||||
{
|
||||
for ( int col = item->firstColumn(); col <= item->lastColumn(); col++ )
|
||||
{
|
||||
if ( engine->itemAt( row, col ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class MessageHandler
|
||||
{
|
||||
public:
|
||||
MessageHandler()
|
||||
{
|
||||
m_defaultHandler = qInstallMessageHandler( suppressWarning );
|
||||
}
|
||||
|
||||
~MessageHandler()
|
||||
{
|
||||
qInstallMessageHandler( m_defaultHandler );
|
||||
}
|
||||
|
||||
private:
|
||||
static void suppressWarning( QtMsgType type,
|
||||
const QMessageLogContext& context, const QString& message )
|
||||
{
|
||||
if ( type == QtWarningMsg )
|
||||
return;
|
||||
|
||||
if ( m_defaultHandler )
|
||||
( *m_defaultHandler )( type, context, message );
|
||||
}
|
||||
|
||||
static QtMessageHandler m_defaultHandler;
|
||||
};
|
||||
|
||||
QtMessageHandler MessageHandler::m_defaultHandler;
|
||||
|
||||
class LayoutStyleInfo final : public QAbstractLayoutStyleInfo
|
||||
{
|
||||
public:
|
||||
LayoutStyleInfo()
|
||||
{
|
||||
}
|
||||
|
||||
qreal spacing( Qt::Orientation ) const override
|
||||
{
|
||||
// later from the theme !!
|
||||
return 5.0;
|
||||
}
|
||||
|
||||
qreal windowMargin( Qt::Orientation ) const override
|
||||
{
|
||||
// later from the theme !!
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool hasChangedCore() const override
|
||||
{
|
||||
return false; // never changes
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
QskLayoutEngine::QskLayoutEngine()
|
||||
: QGridLayoutEngine( Qt::AlignVCenter, false /*snapToPixelGrid*/ )
|
||||
{
|
||||
/*
|
||||
snapToPixelGrid rounds x/y, what might lead to losing a pixel.
|
||||
F.e. when having a text in elideMode we end up with an elided text
|
||||
because of this.
|
||||
*/
|
||||
}
|
||||
|
||||
QskLayoutEngine::~QskLayoutEngine()
|
||||
{
|
||||
}
|
||||
|
||||
void QskLayoutEngine::setGeometries( const QRectF rect )
|
||||
{
|
||||
const LayoutStyleInfo styleInfo;
|
||||
QGridLayoutEngine::setGeometries( rect, &styleInfo );
|
||||
}
|
||||
|
||||
void QskLayoutEngine::insertLayoutItem( QskLayoutItem* item, int index )
|
||||
{
|
||||
if ( qskIsColliding( this, item ) )
|
||||
{
|
||||
// It is totally valid to have more than one item in the same cell
|
||||
// and we make use of it f.e in QskStackLayout. So we better
|
||||
// suppress the corresponding warning to avoid confusion.
|
||||
|
||||
MessageHandler suppressWarning;
|
||||
insertItem( item, index );
|
||||
}
|
||||
else
|
||||
{
|
||||
insertItem( item, index );
|
||||
}
|
||||
}
|
||||
|
||||
int QskLayoutEngine::indexAt( int row, int column ) const
|
||||
{
|
||||
const auto item = layoutItemAt( row, column );
|
||||
if ( item )
|
||||
return q_items.indexOf( item );
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
QskLayoutItem* QskLayoutEngine::layoutItemAt( int index ) const
|
||||
{
|
||||
if ( index < 0 || index >= q_items.count() )
|
||||
return nullptr;
|
||||
|
||||
return static_cast< QskLayoutItem* >( q_items[ index ] );
|
||||
}
|
||||
|
||||
QskLayoutItem* QskLayoutEngine::layoutItemAt( int row, int column ) const
|
||||
{
|
||||
if ( row < 0 || row >= rowCount() || column < 0 || column >= columnCount() )
|
||||
return nullptr;
|
||||
|
||||
return static_cast< QskLayoutItem* >( itemAt( row, column ) );
|
||||
}
|
||||
|
||||
QskLayoutItem* QskLayoutEngine::layoutItemAt(
|
||||
int row, int column, Qt::Orientation orientation ) const
|
||||
{
|
||||
if ( orientation == Qt::Horizontal )
|
||||
return layoutItemAt( row, column );
|
||||
else
|
||||
return layoutItemAt( column, row );
|
||||
}
|
||||
|
||||
int QskLayoutEngine::indexOf( const QQuickItem* item ) const
|
||||
{
|
||||
// linear search might become slow for many items,
|
||||
// better introduce some sort of hash table TODO ...
|
||||
|
||||
for ( int i = q_items.count() - 1; i >= 0; --i )
|
||||
{
|
||||
const auto layoutItem = static_cast< const QskLayoutItem* >( q_items[ i ] );
|
||||
if ( layoutItem->item() == item )
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
QSizeF QskLayoutEngine::sizeHint( Qt::SizeHint which, const QSizeF& constraint ) const
|
||||
{
|
||||
const LayoutStyleInfo styleInfo;
|
||||
return QGridLayoutEngine::sizeHint( which, constraint, &styleInfo );
|
||||
}
|
||||
|
||||
qreal QskLayoutEngine::widthForHeight( qreal height ) const
|
||||
{
|
||||
const QSizeF constraint( -1, height );
|
||||
return sizeHint( Qt::PreferredSize, constraint ).width();
|
||||
}
|
||||
|
||||
qreal QskLayoutEngine::heightForWidth( qreal width ) const
|
||||
{
|
||||
const QSizeF constraint( width, -1 );
|
||||
return sizeHint( Qt::PreferredSize, constraint ).height();
|
||||
}
|
||||
|
||||
qreal QskLayoutEngine::spacing( Qt::Orientation orientation ) const
|
||||
{
|
||||
const LayoutStyleInfo styleInfo;
|
||||
return QGridLayoutEngine::spacing( orientation, &styleInfo );
|
||||
}
|
||||
|
||||
qreal QskLayoutEngine::defaultSpacing( Qt::Orientation orientation )
|
||||
{
|
||||
return LayoutStyleInfo().spacing( orientation );
|
||||
}
|
||||
|
||||
#if 1
|
||||
// QGridLayout or here ???
|
||||
QSize QskLayoutEngine::requiredCells() const
|
||||
{
|
||||
int lastRow = -1;
|
||||
int lastColumn = -1;
|
||||
|
||||
for ( int i = 0; i < itemCount(); i++ )
|
||||
{
|
||||
const auto layoutItem = layoutItemAt( i );
|
||||
if ( layoutItem->isIgnored() )
|
||||
continue;
|
||||
|
||||
const int col = layoutItem->hasUnlimitedSpan( Qt::Horizontal )
|
||||
? layoutItem->firstColumn() + 1 : layoutItem->lastColumn();
|
||||
|
||||
if ( col > lastColumn )
|
||||
lastColumn = col;
|
||||
|
||||
const int row = layoutItem->hasUnlimitedSpan( Qt::Vertical )
|
||||
? layoutItem->firstRow() + 1 : layoutItem->lastRow();
|
||||
|
||||
if ( row > lastRow )
|
||||
lastRow = row;
|
||||
}
|
||||
|
||||
return QSize( lastColumn + 1, lastRow + 1 );
|
||||
}
|
||||
|
||||
void QskLayoutEngine::adjustSpans( int numRows, int numColumns )
|
||||
{
|
||||
for ( int i = 0; i < itemCount(); i++ )
|
||||
{
|
||||
auto layoutItem = layoutItemAt( i );
|
||||
|
||||
if ( layoutItem->hasUnlimitedSpan( Qt::Horizontal ) )
|
||||
layoutItem->setRowSpan( numColumns - layoutItem->firstColumn(), Qt::Horizontal );
|
||||
|
||||
if ( layoutItem->hasUnlimitedSpan( Qt::Vertical ) )
|
||||
layoutItem->setRowSpan( numRows - layoutItem->firstRow(), Qt::Vertical );
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
/******************************************************************************
|
||||
* 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_H
|
||||
#define QSK_LAYOUT_ENGINE_H
|
||||
|
||||
#include "QskGlobal.h"
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
/*
|
||||
QskLayoutEngine.h should be hidden into some cpp file
|
||||
as it needs private headers. TODO
|
||||
*/
|
||||
|
||||
#include <private/qgridlayoutengine_p.h>
|
||||
QSK_QT_PRIVATE_END
|
||||
|
||||
class QskLayoutItem;
|
||||
class QQuickItem;
|
||||
|
||||
class QskLayoutEngine : public QGridLayoutEngine
|
||||
{
|
||||
public:
|
||||
QskLayoutEngine();
|
||||
~QskLayoutEngine();
|
||||
|
||||
void setGeometries( const QRectF );
|
||||
|
||||
void insertLayoutItem( QskLayoutItem* item, int index );
|
||||
|
||||
QskLayoutItem* layoutItemAt( int index ) const;
|
||||
QskLayoutItem* layoutItemAt( int row, int column ) const;
|
||||
QskLayoutItem* layoutItemAt( int row, int column, Qt::Orientation ) const;
|
||||
|
||||
int indexAt( int row, int column ) const;
|
||||
|
||||
QskLayoutItem* layoutItemOf( const QQuickItem* ) const;
|
||||
int indexOf( const QQuickItem* item ) const;
|
||||
|
||||
QSizeF sizeHint( Qt::SizeHint, const QSizeF& constraint = QSizeF() ) const;
|
||||
|
||||
qreal widthForHeight( qreal height ) const;
|
||||
qreal heightForWidth( qreal width ) const;
|
||||
|
||||
qreal spacing( Qt::Orientation ) const;
|
||||
static qreal defaultSpacing( Qt::Orientation );
|
||||
|
||||
#if 1
|
||||
QSize requiredCells() const;
|
||||
void adjustSpans( int numRows, int numColumns );
|
||||
#endif
|
||||
};
|
||||
|
||||
inline QskLayoutItem* QskLayoutEngine::layoutItemOf( const QQuickItem* item ) const
|
||||
{
|
||||
return layoutItemAt( indexOf( item ) );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,187 +0,0 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskLayoutItem.h"
|
||||
#include "QskControl.h"
|
||||
#include "QskLayoutConstraint.h"
|
||||
#include "QskQuick.h"
|
||||
|
||||
QskLayoutItem::QskLayoutItem( QQuickItem* item, int row, int column, int rowSpan, int columnSpan )
|
||||
: Inherited( row, column, qMax( rowSpan, 1 ), qMax( columnSpan, 1 ), Qt::Alignment() )
|
||||
, m_item( item )
|
||||
, m_isGeometryDirty( false )
|
||||
, m_isStretchable( false )
|
||||
, m_retainSizeWhenHidden( false )
|
||||
, m_unlimitedRowSpan( rowSpan <= 0 )
|
||||
, m_unlimitedColumnSpan( columnSpan <= 0 )
|
||||
, m_updateMode( UpdateWhenVisible )
|
||||
{
|
||||
}
|
||||
|
||||
QskLayoutItem::QskLayoutItem( const QSizeF& size, int stretch, int row, int column )
|
||||
: Inherited( row, column, 1, 1, Qt::Alignment() )
|
||||
, m_item( nullptr )
|
||||
, m_spacingHint( size )
|
||||
, m_isGeometryDirty( false )
|
||||
, m_isStretchable( stretch > 0 )
|
||||
, m_retainSizeWhenHidden( false )
|
||||
, m_unlimitedRowSpan( false )
|
||||
, m_unlimitedColumnSpan( false )
|
||||
, m_updateMode( UpdateWhenVisible )
|
||||
{
|
||||
}
|
||||
|
||||
QskLayoutItem::~QskLayoutItem()
|
||||
{
|
||||
}
|
||||
|
||||
QskLayoutItem::UpdateMode QskLayoutItem::updateMode() const
|
||||
{
|
||||
return m_updateMode;
|
||||
}
|
||||
|
||||
void QskLayoutItem::setUpdateMode( UpdateMode mode )
|
||||
{
|
||||
m_updateMode = mode;
|
||||
}
|
||||
|
||||
bool QskLayoutItem::retainSizeWhenHidden() const
|
||||
{
|
||||
return m_retainSizeWhenHidden;
|
||||
}
|
||||
|
||||
void QskLayoutItem::setRetainSizeWhenHidden( bool on )
|
||||
{
|
||||
m_retainSizeWhenHidden = on;
|
||||
}
|
||||
|
||||
QSizeF QskLayoutItem::spacingHint() const
|
||||
{
|
||||
return m_spacingHint;
|
||||
}
|
||||
|
||||
void QskLayoutItem::setSpacingHint( const QSizeF& hint )
|
||||
{
|
||||
m_spacingHint = hint;
|
||||
}
|
||||
|
||||
QSizeF QskLayoutItem::sizeHint(
|
||||
Qt::SizeHint whichHint, const QSizeF& constraint ) const
|
||||
{
|
||||
if ( m_item == nullptr )
|
||||
{
|
||||
if ( whichHint < Qt::MinimumSize || whichHint > Qt::MaximumSize )
|
||||
return QSizeF( 0, 0 );
|
||||
|
||||
// a spacer item
|
||||
if ( whichHint == Qt::MaximumSize )
|
||||
{
|
||||
if ( m_isStretchable )
|
||||
return QSizeF( QskLayoutConstraint::unlimited, QskLayoutConstraint::unlimited );
|
||||
|
||||
if ( m_spacingHint.width() < 0 )
|
||||
return QSizeF( QskLayoutConstraint::unlimited, m_spacingHint.height() );
|
||||
else
|
||||
return QSizeF( m_spacingHint.width(), QskLayoutConstraint::unlimited );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_spacingHint.width() < 0 )
|
||||
return QSizeF( 0, m_spacingHint.height() );
|
||||
else
|
||||
return QSizeF( m_spacingHint.width(), 0 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return QskLayoutConstraint::sizeHint( m_item, whichHint, constraint );
|
||||
}
|
||||
}
|
||||
|
||||
QLayoutPolicy::Policy QskLayoutItem::sizePolicy( Qt::Orientation orientation ) const
|
||||
{
|
||||
auto policy = QskLayoutConstraint::sizePolicy( m_item ).policy( orientation );
|
||||
|
||||
#if 0
|
||||
if ( ( policy == QskSizePolicy::Preferred ) && m_item )
|
||||
{
|
||||
// QskSizePolicy::Preferred without having a preferred size is the default
|
||||
// setting of QskControl - taken from what QWidget does - but this combination
|
||||
// doesn't make much sense. Usually every derived control is supposed
|
||||
// to set specific values, but in case it has been forgotten we better
|
||||
// ignore the preferred size then.
|
||||
|
||||
const QSizeF hint = QskLayoutConstraint::effectiveConstraint( m_item, Qt::PreferredSize );
|
||||
|
||||
const qreal value = ( orientation == Qt::Horizontal ) ? hint.width() : hint.height();
|
||||
if ( value <= 0 )
|
||||
policy = QskSizePolicy::Ignored;
|
||||
}
|
||||
#endif
|
||||
|
||||
return static_cast< QLayoutPolicy::Policy >( policy );
|
||||
}
|
||||
|
||||
void QskLayoutItem::setGeometry( const QRectF& rect )
|
||||
{
|
||||
if ( m_item == nullptr )
|
||||
return;
|
||||
|
||||
if ( m_updateMode == UpdateNone )
|
||||
{
|
||||
if ( !m_isGeometryDirty )
|
||||
m_isGeometryDirty = ( rect != qskItemGeometry( m_item ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( m_updateMode == UpdateWhenVisible )
|
||||
{
|
||||
if ( !m_item->isVisible() )
|
||||
return;
|
||||
}
|
||||
|
||||
m_isGeometryDirty = false;
|
||||
qskSetItemGeometry( m_item, rect );
|
||||
}
|
||||
|
||||
bool QskLayoutItem::hasDynamicConstraint() const
|
||||
{
|
||||
if ( m_item )
|
||||
{
|
||||
using namespace QskLayoutConstraint;
|
||||
return constraintType( m_item ) != Unconstrained;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Qt::Orientation QskLayoutItem::dynamicConstraintOrientation() const
|
||||
{
|
||||
Qt::Orientation orientation = Qt::Vertical;
|
||||
|
||||
if ( auto control = qskControlCast( m_item ) )
|
||||
{
|
||||
const auto policy = control->sizePolicy().horizontalPolicy();
|
||||
|
||||
return ( policy == QskSizePolicy::Constrained )
|
||||
? Qt::Horizontal : Qt::Vertical;
|
||||
}
|
||||
|
||||
return orientation;
|
||||
}
|
||||
|
||||
bool QskLayoutItem::isIgnored() const
|
||||
{
|
||||
if ( m_item && !qskIsVisibleToParent( m_item ) )
|
||||
return !m_retainSizeWhenHidden;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QLayoutPolicy::ControlTypes QskLayoutItem::controlTypes( LayoutSide side ) const
|
||||
{
|
||||
return Inherited::controlTypes( side );
|
||||
}
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_LAYOUT_ITEM_H
|
||||
#define QSK_LAYOUT_ITEM_H
|
||||
|
||||
#include "QskGlobal.h"
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
/*
|
||||
QskLayoutItem.h should be hidden into some cpp file
|
||||
as it needs private headers. TODO
|
||||
*/
|
||||
|
||||
#include <private/qgridlayoutengine_p.h>
|
||||
QSK_QT_PRIVATE_END
|
||||
|
||||
class QQuickItem;
|
||||
|
||||
class QskLayoutItem : public QGridLayoutItem
|
||||
{
|
||||
using Inherited = QGridLayoutItem;
|
||||
|
||||
public:
|
||||
enum UpdateMode
|
||||
{
|
||||
UpdateNone,
|
||||
UpdateWhenVisible,
|
||||
UpdateAlways
|
||||
};
|
||||
|
||||
QskLayoutItem( QQuickItem* item, int row, int column,
|
||||
int rowSpan = 1, int columnSpan = 1 );
|
||||
|
||||
QskLayoutItem( const QSizeF& size, int stretch, int row, int column );
|
||||
|
||||
~QskLayoutItem() override;
|
||||
|
||||
QQuickItem* item();
|
||||
const QQuickItem* item() const;
|
||||
|
||||
QLayoutPolicy::Policy sizePolicy( Qt::Orientation ) const override final;
|
||||
QSizeF sizeHint( Qt::SizeHint, const QSizeF& ) const override final;
|
||||
void setGeometry( const QRectF& ) override final;
|
||||
|
||||
bool hasDynamicConstraint() const override final;
|
||||
Qt::Orientation dynamicConstraintOrientation() const override final;
|
||||
|
||||
bool isIgnored() const override final;
|
||||
QLayoutPolicy::ControlTypes controlTypes( LayoutSide side ) const override final;
|
||||
|
||||
bool retainSizeWhenHidden() const;
|
||||
void setRetainSizeWhenHidden( bool on );
|
||||
|
||||
UpdateMode updateMode() const;
|
||||
void setUpdateMode( UpdateMode );
|
||||
|
||||
QSizeF spacingHint() const;
|
||||
void setSpacingHint( const QSizeF& );
|
||||
|
||||
bool isGeometryDirty() const;
|
||||
|
||||
bool hasUnlimitedSpan() const;
|
||||
bool hasUnlimitedSpan( Qt::Orientation orientation ) const;
|
||||
|
||||
private:
|
||||
QQuickItem* m_item;
|
||||
QSizeF m_spacingHint;
|
||||
|
||||
bool m_isGeometryDirty : 1;
|
||||
bool m_isStretchable : 1;
|
||||
bool m_retainSizeWhenHidden : 1;
|
||||
bool m_unlimitedRowSpan : 1;
|
||||
bool m_unlimitedColumnSpan : 1;
|
||||
UpdateMode m_updateMode : 2;
|
||||
};
|
||||
|
||||
inline QQuickItem* QskLayoutItem::item()
|
||||
{
|
||||
return m_item;
|
||||
}
|
||||
|
||||
inline const QQuickItem* QskLayoutItem::item() const
|
||||
{
|
||||
return m_item;
|
||||
}
|
||||
|
||||
inline bool QskLayoutItem::isGeometryDirty() const
|
||||
{
|
||||
return m_isGeometryDirty;
|
||||
}
|
||||
|
||||
inline bool QskLayoutItem::hasUnlimitedSpan( Qt::Orientation orientation ) const
|
||||
{
|
||||
return ( orientation == Qt::Horizontal )
|
||||
? m_unlimitedColumnSpan : m_unlimitedRowSpan;
|
||||
}
|
||||
|
||||
inline bool QskLayoutItem::hasUnlimitedSpan() const
|
||||
{
|
||||
return m_unlimitedColumnSpan || m_unlimitedRowSpan;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -4,26 +4,57 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include "QskLinearBox.h"
|
||||
#include "QskLayoutEngine.h"
|
||||
#include "QskLayoutItem.h"
|
||||
#include "QskLinearLayoutEngine.h"
|
||||
|
||||
#include <qendian.h>
|
||||
#include "QskLayoutConstraint.h"
|
||||
#include "QskEvent.h"
|
||||
#include "QskQuick.h"
|
||||
|
||||
static void qskSetItemActive( QObject* receiver, const QQuickItem* item, bool on )
|
||||
{
|
||||
if ( ( item == nullptr ) || ( qskControlCast( item ) != nullptr ) )
|
||||
return;
|
||||
|
||||
/*
|
||||
For QQuickItems not being derived from QskControl we manually
|
||||
send QEvent::LayoutRequest events.
|
||||
*/
|
||||
|
||||
if ( on )
|
||||
{
|
||||
auto sendLayoutRequest =
|
||||
[receiver]()
|
||||
{
|
||||
QEvent event( QEvent::LayoutRequest );
|
||||
QCoreApplication::sendEvent( receiver, &event );
|
||||
};
|
||||
|
||||
QObject::connect( item, &QQuickItem::implicitWidthChanged,
|
||||
receiver, sendLayoutRequest );
|
||||
|
||||
QObject::connect( item, &QQuickItem::implicitHeightChanged,
|
||||
receiver, sendLayoutRequest );
|
||||
|
||||
QObject::connect( item, &QQuickItem::visibleChanged,
|
||||
receiver, sendLayoutRequest );
|
||||
}
|
||||
else
|
||||
{
|
||||
QObject::disconnect( item, &QQuickItem::implicitWidthChanged, receiver, nullptr );
|
||||
QObject::disconnect( item, &QQuickItem::implicitHeightChanged, receiver, nullptr );
|
||||
QObject::disconnect( item, &QQuickItem::visibleChanged, receiver, nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
class QskLinearBox::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData( Qt::Orientation orient, uint dim )
|
||||
: dimension( dim )
|
||||
, orientation( orient )
|
||||
, transposeAlignments( false )
|
||||
PrivateData( Qt::Orientation orientation, uint dimension )
|
||||
: engine( orientation, dimension )
|
||||
{
|
||||
}
|
||||
|
||||
uint dimension;
|
||||
Qt::Edges extraSpacingAt;
|
||||
|
||||
Qt::Orientation orientation : 2;
|
||||
bool transposeAlignments : 1;
|
||||
QskLinearLayoutEngine engine;
|
||||
};
|
||||
|
||||
QskLinearBox::QskLinearBox( QQuickItem* parent )
|
||||
|
|
@ -36,9 +67,8 @@ QskLinearBox::QskLinearBox( Qt::Orientation orientation, QQuickItem* parent )
|
|||
{
|
||||
}
|
||||
|
||||
QskLinearBox::QskLinearBox(
|
||||
Qt::Orientation orientation, uint dimension, QQuickItem* parent )
|
||||
: Inherited( parent )
|
||||
QskLinearBox::QskLinearBox( Qt::Orientation orientation, uint dimension, QQuickItem* parent )
|
||||
: QskIndexedLayoutBox( parent )
|
||||
, m_data( new PrivateData( orientation, dimension ) )
|
||||
{
|
||||
}
|
||||
|
|
@ -47,97 +77,308 @@ QskLinearBox::~QskLinearBox()
|
|||
{
|
||||
}
|
||||
|
||||
int QskLinearBox::entryCount() const
|
||||
{
|
||||
return m_data->engine.count();
|
||||
}
|
||||
|
||||
QQuickItem* QskLinearBox::itemAtIndex( int index ) const
|
||||
{
|
||||
return m_data->engine.itemAt( index );
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void QskLinearBox::removeAt( int index )
|
||||
{
|
||||
removeItemInternal( index, false );
|
||||
}
|
||||
|
||||
void QskLinearBox::removeItemInternal( int index, bool unparent )
|
||||
{
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( index < 0 || index >= engine.count() )
|
||||
return;
|
||||
|
||||
auto item = engine.itemAt( index );
|
||||
engine.removeAt( index );
|
||||
|
||||
if ( item )
|
||||
{
|
||||
qskSetItemActive( this, engine.itemAt( index ), false );
|
||||
|
||||
if ( !unparent )
|
||||
{
|
||||
if ( item->parentItem() == this )
|
||||
item->setParentItem( nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
}
|
||||
|
||||
void QskLinearBox::removeItem( const QQuickItem* item )
|
||||
{
|
||||
removeAt( indexOf( item ) );
|
||||
}
|
||||
|
||||
void QskLinearBox::clear( bool autoDelete )
|
||||
{
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
// do we have visible entries
|
||||
const bool hasVisibleEntries = engine.rowCount() > 0;
|
||||
|
||||
for ( int i = engine.count() - 1; i >= 0; i-- )
|
||||
{
|
||||
auto item = engine.itemAt( i );
|
||||
engine.removeAt( i );
|
||||
|
||||
if( item )
|
||||
{
|
||||
qskSetItemActive( this, item, false );
|
||||
|
||||
if( autoDelete && ( item->parent() == this ) )
|
||||
delete item;
|
||||
else
|
||||
item->setParentItem( nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
if ( hasVisibleEntries )
|
||||
resetImplicitSize();
|
||||
}
|
||||
|
||||
void QskLinearBox::autoAddItem( QQuickItem* item )
|
||||
{
|
||||
insertItem( -1, item );
|
||||
}
|
||||
|
||||
void QskLinearBox::autoRemoveItem( QQuickItem* item )
|
||||
{
|
||||
removeItemInternal( indexOf( item ), true );
|
||||
}
|
||||
|
||||
void QskLinearBox::activate()
|
||||
{
|
||||
polish();
|
||||
}
|
||||
|
||||
void QskLinearBox::invalidate()
|
||||
{
|
||||
m_data->engine.invalidate();
|
||||
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
}
|
||||
|
||||
void QskLinearBox::updateLayout()
|
||||
{
|
||||
m_data->engine.setGeometries( layoutRect() );
|
||||
}
|
||||
|
||||
QSizeF QskLinearBox::contentsSizeHint() const
|
||||
{
|
||||
return m_data->engine.sizeHint( Qt::PreferredSize, QSizeF() );
|
||||
}
|
||||
|
||||
qreal QskLinearBox::heightForWidth( qreal width ) const
|
||||
{
|
||||
auto constrainedHeight =
|
||||
[this]( QskLayoutConstraint::Type, const QskControl*, qreal width )
|
||||
{
|
||||
return m_data->engine.heightForWidth( width );
|
||||
};
|
||||
|
||||
return QskLayoutConstraint::constrainedMetric(
|
||||
QskLayoutConstraint::HeightForWidth, this, width, constrainedHeight );
|
||||
}
|
||||
|
||||
qreal QskLinearBox::widthForHeight( qreal height ) const
|
||||
{
|
||||
auto constrainedWidth =
|
||||
[this]( QskLayoutConstraint::Type, const QskControl*, qreal height )
|
||||
{
|
||||
return m_data->engine.widthForHeight( height );
|
||||
};
|
||||
|
||||
return QskLayoutConstraint::constrainedMetric(
|
||||
QskLayoutConstraint::WidthForHeight, this, height, constrainedWidth );
|
||||
}
|
||||
|
||||
void QskLinearBox::geometryChangeEvent( QskGeometryChangeEvent* event )
|
||||
{
|
||||
Inherited::geometryChangeEvent( event );
|
||||
|
||||
if ( event->isResized() )
|
||||
polish();
|
||||
}
|
||||
|
||||
|
||||
void QskLinearBox::itemChange( ItemChange change, const ItemChangeData& value )
|
||||
{
|
||||
Inherited::itemChange( change, value );
|
||||
|
||||
#if 1
|
||||
if ( change == QQuickItem::ItemVisibleHasChanged )
|
||||
{
|
||||
// when becoming visible we should run into polish anyway
|
||||
if ( value.boolValue )
|
||||
polish();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool QskLinearBox::event( QEvent* event )
|
||||
{
|
||||
switch ( event->type() )
|
||||
{
|
||||
case QEvent::LayoutRequest:
|
||||
{
|
||||
invalidate();
|
||||
break;
|
||||
}
|
||||
case QEvent::LayoutDirectionChange:
|
||||
{
|
||||
m_data->engine.setVisualDirection(
|
||||
layoutMirroring() ? Qt::RightToLeft : Qt::LeftToRight );
|
||||
|
||||
polish();
|
||||
break;
|
||||
}
|
||||
case QEvent::ContentsRectChange:
|
||||
{
|
||||
polish();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return Inherited::event( event );
|
||||
}
|
||||
|
||||
void QskLinearBox::setDimension( uint dimension )
|
||||
{
|
||||
if ( dimension < 1 )
|
||||
dimension = 1;
|
||||
|
||||
if ( dimension != m_data->dimension )
|
||||
{
|
||||
m_data->dimension = dimension;
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( dimension != engine.dimension() )
|
||||
{
|
||||
engine.setDimension( dimension );
|
||||
|
||||
rearrange();
|
||||
polish();
|
||||
resetImplicitSize();
|
||||
|
||||
Q_EMIT dimensionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
uint QskLinearBox::dimension() const
|
||||
{
|
||||
return m_data->dimension;
|
||||
return m_data->engine.dimension();
|
||||
}
|
||||
|
||||
void QskLinearBox::setOrientation( Qt::Orientation orientation )
|
||||
{
|
||||
if ( m_data->orientation != orientation )
|
||||
transpose();
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( engine.orientation() != orientation )
|
||||
{
|
||||
engine.setOrientation( orientation );
|
||||
|
||||
polish();
|
||||
resetImplicitSize();
|
||||
|
||||
Q_EMIT orientationChanged();
|
||||
}
|
||||
}
|
||||
|
||||
Qt::Orientation QskLinearBox::orientation() const
|
||||
{
|
||||
return m_data->orientation;
|
||||
return m_data->engine.orientation();
|
||||
}
|
||||
|
||||
void QskLinearBox::transpose()
|
||||
{
|
||||
const Qt::Orientation orientation =
|
||||
( m_data->orientation == Qt::Horizontal ) ? Qt::Vertical : Qt::Horizontal;
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
const int numItems = itemCount();
|
||||
#if 0
|
||||
#include <qendian.h>
|
||||
|
||||
if ( numItems > 0 )
|
||||
for ( int i = 0; i < engine.itemCount(); i++ )
|
||||
{
|
||||
for ( int i = 0; i < numItems; i++ )
|
||||
{
|
||||
QskLayoutItem* layoutItem = engine().layoutItemAt( i );
|
||||
|
||||
const int row = layoutItem->firstColumn();
|
||||
const int col = layoutItem->firstRow();
|
||||
|
||||
engine().removeItem( layoutItem );
|
||||
|
||||
layoutItem->setFirstRow( row, Qt::Vertical );
|
||||
layoutItem->setFirstRow( col, Qt::Horizontal );
|
||||
|
||||
#if 1
|
||||
if ( m_data->transposeAlignments )
|
||||
{
|
||||
// Is it worth to blow the API with this flag, or would
|
||||
// it be even better to have an indvidual flag for each
|
||||
// item - and what about the size policies: do we want to
|
||||
// transpose them too ?
|
||||
|
||||
const auto alignment = static_cast< Qt::Alignment >(
|
||||
qbswap( static_cast< quint16 >( layoutItem->alignment() ) ) );
|
||||
|
||||
layoutItem->setAlignment( alignment );
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( layoutItem->item() == nullptr )
|
||||
{
|
||||
// a spacing or stretch
|
||||
layoutItem->setSpacingHint(
|
||||
layoutItem->spacingHint().transposed() );
|
||||
}
|
||||
|
||||
engine().insertLayoutItem( layoutItem, i );
|
||||
}
|
||||
|
||||
invalidate();
|
||||
auto alignment = engine.alignmentAt( i );
|
||||
qbswap( static_cast< quint16 >( alignment ) );
|
||||
engine.setAlignmentAt( i, alignment );
|
||||
}
|
||||
|
||||
m_data->orientation = orientation;
|
||||
Q_EMIT orientationChanged();
|
||||
// extraSpacingAt ???
|
||||
#endif
|
||||
|
||||
if ( engine.orientation() == Qt::Horizontal )
|
||||
setOrientation( Qt::Vertical );
|
||||
else
|
||||
setOrientation( Qt::Horizontal );
|
||||
}
|
||||
|
||||
void QskLinearBox::setDefaultAlignment( Qt::Alignment alignment )
|
||||
{
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( alignment != engine.defaultAlignment() )
|
||||
{
|
||||
engine.setDefaultAlignment( alignment );
|
||||
Q_EMIT defaultAlignmentChanged();
|
||||
}
|
||||
}
|
||||
|
||||
Qt::Alignment QskLinearBox::defaultAlignment() const
|
||||
{
|
||||
return m_data->engine.defaultAlignment();
|
||||
}
|
||||
|
||||
void QskLinearBox::setSpacing( qreal spacing )
|
||||
{
|
||||
/*
|
||||
we should have setSpacing( qreal, Qt::Orientations ),
|
||||
but need to create an API for Qml in QskQml
|
||||
using qmlAttachedPropertiesObject then. TODO ...
|
||||
*/
|
||||
spacing = qMax( spacing, 0.0 );
|
||||
|
||||
if ( spacing != engine().spacing( Qt::Horizontal ) )
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( spacing != engine.spacing( Qt::Horizontal ) )
|
||||
{
|
||||
engine().setSpacing( spacing, Qt::Horizontal | Qt::Vertical );
|
||||
activate();
|
||||
engine.setSpacing( spacing, Qt::Horizontal | Qt::Vertical );
|
||||
polish();
|
||||
|
||||
Q_EMIT spacingChanged();
|
||||
}
|
||||
|
|
@ -145,22 +386,22 @@ void QskLinearBox::setSpacing( qreal spacing )
|
|||
|
||||
void QskLinearBox::resetSpacing()
|
||||
{
|
||||
const qreal spacing = QskLayoutEngine::defaultSpacing( Qt::Horizontal );
|
||||
const qreal spacing = m_data->engine.defaultSpacing( Qt::Horizontal );
|
||||
setSpacing( spacing );
|
||||
}
|
||||
|
||||
qreal QskLinearBox::spacing() const
|
||||
{
|
||||
// do we always want to have the same spacing for both orientations
|
||||
return engine().spacing( Qt::Horizontal );
|
||||
return m_data->engine.spacing( Qt::Horizontal );
|
||||
}
|
||||
|
||||
void QskLinearBox::setExtraSpacingAt( Qt::Edges edges )
|
||||
{
|
||||
if ( edges != m_data->extraSpacingAt )
|
||||
if ( edges != m_data->engine.extraSpacingAt() )
|
||||
{
|
||||
m_data->extraSpacingAt = edges;
|
||||
activate();
|
||||
m_data->engine.setExtraSpacingAt( edges );
|
||||
polish();
|
||||
|
||||
Q_EMIT extraSpacingAtChanged();
|
||||
}
|
||||
|
|
@ -168,7 +409,84 @@ void QskLinearBox::setExtraSpacingAt( Qt::Edges edges )
|
|||
|
||||
Qt::Edges QskLinearBox::extraSpacingAt() const
|
||||
{
|
||||
return m_data->extraSpacingAt;
|
||||
return m_data->engine.extraSpacingAt();
|
||||
}
|
||||
|
||||
void QskLinearBox::addItem( QQuickItem* item, Qt::Alignment alignment )
|
||||
{
|
||||
insertItem( -1, item, alignment );
|
||||
}
|
||||
|
||||
void QskLinearBox::insertItem(
|
||||
int index, QQuickItem* item, Qt::Alignment alignment )
|
||||
{
|
||||
if ( item == nullptr )
|
||||
return;
|
||||
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( item->parentItem() == this )
|
||||
{
|
||||
const int oldIndex = indexOf( item );
|
||||
if ( oldIndex >= 0 )
|
||||
{
|
||||
// the item has been inserted before
|
||||
|
||||
const bool doAppend = index < 0 || index >= engine.count();
|
||||
|
||||
if ( ( index == oldIndex ) ||
|
||||
( doAppend && oldIndex == engine.count() - 1 ) )
|
||||
{
|
||||
// already at its position, nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
removeAt( oldIndex );
|
||||
}
|
||||
}
|
||||
|
||||
reparentItem( item );
|
||||
|
||||
const int numItems = engine.count();
|
||||
if ( index < 0 || index > numItems )
|
||||
index = numItems;
|
||||
|
||||
engine.insertItem( item, index );
|
||||
engine.setAlignmentAt( index, alignment );
|
||||
|
||||
// Re-ordering the child items to have a a proper focus tab chain
|
||||
|
||||
bool reordered = false;
|
||||
|
||||
if ( index < engine.count() - 1 )
|
||||
{
|
||||
for ( int i = index; i < engine.count(); i++ )
|
||||
{
|
||||
if ( auto nextItem = engine.itemAt( i ) )
|
||||
{
|
||||
item->stackBefore( nextItem );
|
||||
reordered = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !reordered )
|
||||
{
|
||||
const auto children = childItems();
|
||||
if ( item != children.last() )
|
||||
item->stackAfter( children.last() );
|
||||
}
|
||||
|
||||
|
||||
qskSetItemActive( this, item, true );
|
||||
|
||||
#if 1
|
||||
// Is there a way to block consecutive calls ???
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
#endif
|
||||
}
|
||||
|
||||
void QskLinearBox::addSpacer( qreal spacing, int stretchFactor )
|
||||
|
|
@ -178,21 +496,22 @@ void QskLinearBox::addSpacer( qreal spacing, int stretchFactor )
|
|||
|
||||
void QskLinearBox::insertSpacer( int index, qreal spacing, int stretchFactor )
|
||||
{
|
||||
spacing = qMax( spacing, 0.0 );
|
||||
stretchFactor = qMax( stretchFactor, 0 );
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
QskLayoutItem* layoutItem;
|
||||
if ( m_data->orientation == Qt::Horizontal )
|
||||
layoutItem = new QskLayoutItem( QSizeF( spacing, -1.0 ), stretchFactor, 0, 0 );
|
||||
else
|
||||
layoutItem = new QskLayoutItem( QSizeF( -1.0, spacing ), stretchFactor, 0, 0 );
|
||||
const int numItems = engine.count();
|
||||
if ( index < 0 || index > numItems )
|
||||
index = numItems;
|
||||
|
||||
engine.insertSpacerAt( index, spacing );
|
||||
|
||||
stretchFactor = qMax( stretchFactor, 0 );
|
||||
engine.setStretchFactorAt( index, stretchFactor );
|
||||
|
||||
#if 1
|
||||
if ( stretchFactor >= 0 )
|
||||
layoutItem->setStretchFactor( stretchFactor, m_data->orientation ); // already above ???
|
||||
// Is there a way to block consecutive calls ???
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
#endif
|
||||
|
||||
insertLayoutItem( layoutItem, index );
|
||||
}
|
||||
|
||||
void QskLinearBox::addStretch( int stretchFactor )
|
||||
|
|
@ -205,270 +524,82 @@ void QskLinearBox::insertStretch( int index, int stretchFactor )
|
|||
insertSpacer( index, 0, stretchFactor );
|
||||
}
|
||||
|
||||
void QskLinearBox::setAlignment( int index, Qt::Alignment alignment )
|
||||
{
|
||||
if ( alignment != m_data->engine.alignmentAt( index ) )
|
||||
{
|
||||
m_data->engine.setAlignmentAt( index, alignment );
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
Qt::Alignment QskLinearBox::alignment( int index ) const
|
||||
{
|
||||
return m_data->engine.alignmentAt( index );
|
||||
}
|
||||
|
||||
void QskLinearBox::setAlignment( const QQuickItem* item, Qt::Alignment alignment )
|
||||
{
|
||||
setAlignment( indexOf( item ), alignment );
|
||||
}
|
||||
|
||||
Qt::Alignment QskLinearBox::alignment( const QQuickItem* item ) const
|
||||
{
|
||||
return alignment( indexOf( item ) );
|
||||
}
|
||||
|
||||
void QskLinearBox::setStretchFactor( int index, int stretchFactor )
|
||||
{
|
||||
if ( QskLayoutItem* layoutItem = engine().layoutItemAt( index ) )
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( engine.stretchFactorAt( index ) != stretchFactor )
|
||||
{
|
||||
if ( layoutItem->stretchFactor( m_data->orientation ) != stretchFactor )
|
||||
{
|
||||
layoutItem->setStretchFactor( stretchFactor, m_data->orientation );
|
||||
// activate();
|
||||
}
|
||||
engine.setStretchFactorAt( index, stretchFactor );
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
int QskLinearBox::stretchFactor( int index ) const
|
||||
{
|
||||
if ( QskLayoutItem* layoutItem = engine().layoutItemAt( index ) )
|
||||
return layoutItem->stretchFactor( m_data->orientation );
|
||||
|
||||
return 0;
|
||||
return m_data->engine.stretchFactorAt( index );
|
||||
}
|
||||
|
||||
void QskLinearBox::setStretchFactor( const QQuickItem* item, int stretch )
|
||||
{
|
||||
setStretchFactor( engine().indexOf( item ), stretch );
|
||||
setStretchFactor( indexOf( item ), stretch );
|
||||
}
|
||||
|
||||
int QskLinearBox::stretchFactor( const QQuickItem* item ) const
|
||||
{
|
||||
return stretchFactor( engine().indexOf( item ) );
|
||||
return stretchFactor( indexOf( item ) );
|
||||
}
|
||||
|
||||
void QskLinearBox::setRetainSizeWhenHidden( int index, bool on )
|
||||
{
|
||||
auto layoutItem = engine().layoutItemAt( index );
|
||||
if ( layoutItem && on != layoutItem->retainSizeWhenHidden() )
|
||||
auto& engine = m_data->engine;
|
||||
|
||||
if ( engine.retainSizeWhenHiddenAt( index ) != on )
|
||||
{
|
||||
layoutItem->setRetainSizeWhenHidden( on );
|
||||
invalidate();
|
||||
engine.setRetainSizeWhenHiddenAt( index, on );
|
||||
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
bool QskLinearBox::retainSizeWhenHidden( int index ) const
|
||||
{
|
||||
if ( const auto layoutItem = engine().layoutItemAt( index ) )
|
||||
return layoutItem->retainSizeWhenHidden();
|
||||
|
||||
return false;
|
||||
return m_data->engine.retainSizeWhenHiddenAt( index );
|
||||
}
|
||||
|
||||
void QskLinearBox::setRetainSizeWhenHidden( const QQuickItem* item, bool on )
|
||||
{
|
||||
setRetainSizeWhenHidden( engine().indexOf( item ), on );
|
||||
setRetainSizeWhenHidden( indexOf( item ), on );
|
||||
}
|
||||
|
||||
bool QskLinearBox::retainSizeWhenHidden( const QQuickItem* item ) const
|
||||
{
|
||||
return retainSizeWhenHidden( engine().indexOf( item ) );
|
||||
}
|
||||
|
||||
void QskLinearBox::setRowSpacing( int row, qreal spacing )
|
||||
{
|
||||
if ( row >= 0 )
|
||||
{
|
||||
engine().setRowSpacing( row, spacing, Qt::Horizontal );
|
||||
activate();
|
||||
}
|
||||
}
|
||||
|
||||
qreal QskLinearBox::rowSpacing( int row ) const
|
||||
{
|
||||
return engine().rowSpacing( row, Qt::Horizontal );
|
||||
}
|
||||
|
||||
void QskLinearBox::setColumnSpacing( int column, qreal spacing )
|
||||
{
|
||||
if ( column >= 0 )
|
||||
{
|
||||
engine().setRowSpacing( column, spacing, Qt::Vertical );
|
||||
activate();
|
||||
}
|
||||
}
|
||||
|
||||
qreal QskLinearBox::columnSpacing( int column ) const
|
||||
{
|
||||
return engine().rowSpacing( column, Qt::Vertical );
|
||||
}
|
||||
|
||||
void QskLinearBox::setRowStretchFactor( int row, int stretchFactor )
|
||||
{
|
||||
if ( row >= 0 )
|
||||
{
|
||||
engine().setRowStretchFactor( row, stretchFactor, Qt::Vertical );
|
||||
activate();
|
||||
}
|
||||
}
|
||||
|
||||
int QskLinearBox::rowStretchFactor( int row ) const
|
||||
{
|
||||
return engine().rowStretchFactor( row, Qt::Vertical );
|
||||
}
|
||||
|
||||
void QskLinearBox::setColumnStretchFactor( int column, int stretchFactor )
|
||||
{
|
||||
if ( column >= 0 )
|
||||
{
|
||||
engine().setRowStretchFactor( column, stretchFactor, Qt::Horizontal );
|
||||
activate();
|
||||
}
|
||||
}
|
||||
|
||||
int QskLinearBox::columnStretchFactor( int column ) const
|
||||
{
|
||||
return engine().rowStretchFactor( column, Qt::Horizontal );
|
||||
}
|
||||
|
||||
void QskLinearBox::setupLayoutItem( QskLayoutItem* layoutItem, int index )
|
||||
{
|
||||
int col = index % m_data->dimension;
|
||||
int row = index / m_data->dimension;
|
||||
|
||||
if ( m_data->orientation == Qt::Vertical )
|
||||
qSwap( col, row );
|
||||
|
||||
layoutItem->setFirstRow( col, Qt::Horizontal );
|
||||
layoutItem->setFirstRow( row, Qt::Vertical );
|
||||
}
|
||||
|
||||
void QskLinearBox::layoutItemInserted( QskLayoutItem*, int index )
|
||||
{
|
||||
if ( index < itemCount() - 1 )
|
||||
rearrange();
|
||||
}
|
||||
|
||||
void QskLinearBox::layoutItemRemoved( QskLayoutItem*, int index )
|
||||
{
|
||||
Q_UNUSED( index )
|
||||
rearrange();
|
||||
}
|
||||
|
||||
void QskLinearBox::rearrange()
|
||||
{
|
||||
bool doInvalidate = false;
|
||||
|
||||
const int numItems = itemCount();
|
||||
|
||||
for ( int i = 0; i < numItems; i++ )
|
||||
{
|
||||
int row = i / m_data->dimension;
|
||||
int col = i % m_data->dimension;
|
||||
|
||||
if ( m_data->orientation == Qt::Vertical )
|
||||
qSwap( col, row );
|
||||
|
||||
auto layoutItem = engine().layoutItemAt( i );
|
||||
|
||||
if ( layoutItem->firstColumn() != col || layoutItem->firstRow() != row )
|
||||
{
|
||||
engine().removeItem( layoutItem );
|
||||
|
||||
layoutItem->setFirstRow( col, Qt::Horizontal );
|
||||
layoutItem->setFirstRow( row, Qt::Vertical );
|
||||
|
||||
engine().insertLayoutItem( layoutItem, i );
|
||||
|
||||
doInvalidate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( doInvalidate )
|
||||
invalidate();
|
||||
}
|
||||
|
||||
QRectF QskLinearBox::alignedLayoutRect( const QRectF& rect ) const
|
||||
{
|
||||
if ( m_data->extraSpacingAt == 0 )
|
||||
return rect;
|
||||
|
||||
const QskLayoutEngine& engine = this->engine();
|
||||
|
||||
QRectF r = rect;
|
||||
|
||||
// not 100% sure if this works for dynamic constraints
|
||||
// and having extraSpacingAt for both directions ...
|
||||
|
||||
if ( ( m_data->extraSpacingAt & Qt::LeftEdge ) ||
|
||||
( m_data->extraSpacingAt & Qt::RightEdge ) )
|
||||
{
|
||||
bool isExpandable = false;
|
||||
|
||||
for ( int i = 0; i < engine.itemCount(); i++ )
|
||||
{
|
||||
const QskLayoutItem* item = engine.layoutItemAt( i );
|
||||
|
||||
if ( !item->isIgnored() &&
|
||||
( item->sizePolicy( Qt::Horizontal ) & QskSizePolicy::GrowFlag ) )
|
||||
{
|
||||
isExpandable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !isExpandable )
|
||||
{
|
||||
const qreal w = engine.widthForHeight( r.height() );
|
||||
|
||||
if ( m_data->extraSpacingAt & Qt::LeftEdge )
|
||||
{
|
||||
if ( m_data->extraSpacingAt & Qt::RightEdge )
|
||||
{
|
||||
r.moveLeft( r.center().x() - w / 2 );
|
||||
r.setWidth( w );
|
||||
}
|
||||
else
|
||||
{
|
||||
r.setLeft( r.right() - w );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
r.setRight( r.left() + w );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ( m_data->extraSpacingAt & Qt::TopEdge ) ||
|
||||
( m_data->extraSpacingAt & Qt::BottomEdge ) )
|
||||
{
|
||||
bool isExpandable = false;
|
||||
|
||||
for ( int i = 0; i < engine.itemCount(); i++ )
|
||||
{
|
||||
const QskLayoutItem* item = engine.layoutItemAt( i );
|
||||
|
||||
if ( !item->isIgnored() &&
|
||||
( item->sizePolicy( Qt::Vertical ) & QskSizePolicy::GrowFlag ) )
|
||||
{
|
||||
isExpandable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !isExpandable )
|
||||
{
|
||||
const qreal h = engine.heightForWidth( r.width() );
|
||||
|
||||
if ( m_data->extraSpacingAt & Qt::TopEdge )
|
||||
{
|
||||
if ( m_data->extraSpacingAt & Qt::BottomEdge )
|
||||
{
|
||||
r.moveTop( r.center().y() - h / 2 );
|
||||
r.setHeight( h );
|
||||
}
|
||||
else
|
||||
{
|
||||
r.setTop( r.bottom() - h );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
r.setBottom( r.top() + h );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
return retainSizeWhenHidden( indexOf( item ) );
|
||||
}
|
||||
|
||||
#include "moc_QskLinearBox.cpp"
|
||||
|
|
|
|||
|
|
@ -19,12 +19,17 @@ class QSK_EXPORT QskLinearBox : public QskIndexedLayoutBox
|
|||
WRITE setDimension NOTIFY dimensionChanged FINAL )
|
||||
|
||||
Q_PROPERTY( qreal spacing READ spacing
|
||||
WRITE setSpacing RESET resetSpacing
|
||||
NOTIFY spacingChanged FINAL )
|
||||
WRITE setSpacing RESET resetSpacing NOTIFY spacingChanged FINAL )
|
||||
|
||||
Q_PROPERTY( Qt::Alignment defaultAlignment READ defaultAlignment
|
||||
WRITE setDefaultAlignment NOTIFY defaultAlignmentChanged )
|
||||
|
||||
Q_PROPERTY( Qt::Edges extraSpacingAt READ extraSpacingAt
|
||||
WRITE setExtraSpacingAt NOTIFY extraSpacingAtChanged )
|
||||
|
||||
Q_PROPERTY( int entryCount READ entryCount() )
|
||||
Q_PROPERTY( bool empty READ isEmpty() )
|
||||
|
||||
using Inherited = QskIndexedLayoutBox;
|
||||
|
||||
public:
|
||||
|
|
@ -32,9 +37,26 @@ class QSK_EXPORT QskLinearBox : public QskIndexedLayoutBox
|
|||
explicit QskLinearBox( Qt::Orientation, QQuickItem* parent = nullptr );
|
||||
|
||||
QskLinearBox( Qt::Orientation, uint dimension, QQuickItem* parent = nullptr );
|
||||
|
||||
~QskLinearBox() override;
|
||||
|
||||
bool isEmpty() const;
|
||||
int entryCount() const; // items and spacers
|
||||
|
||||
#ifdef QSK_LAYOUT_COMPAT
|
||||
int itemCount() const { return entryCount(); } // items and spacers
|
||||
#endif
|
||||
|
||||
QQuickItem* itemAtIndex( int index ) const;
|
||||
int indexOf( const QQuickItem* ) const;
|
||||
|
||||
void removeItem( const QQuickItem* );
|
||||
void removeAt( int index );
|
||||
|
||||
QSizeF contentsSizeHint() const override;
|
||||
|
||||
qreal heightForWidth( qreal width ) const override;
|
||||
qreal widthForHeight( qreal height ) const override;
|
||||
|
||||
Qt::Orientation orientation() const;
|
||||
void setOrientation( Qt::Orientation );
|
||||
|
||||
|
|
@ -44,10 +66,19 @@ class QSK_EXPORT QskLinearBox : public QskIndexedLayoutBox
|
|||
void setExtraSpacingAt( Qt::Edges );
|
||||
Qt::Edges extraSpacingAt() const;
|
||||
|
||||
void setDefaultAlignment( Qt::Alignment );
|
||||
Qt::Alignment defaultAlignment() const;
|
||||
|
||||
void setSpacing( qreal spacing );
|
||||
void resetSpacing();
|
||||
qreal spacing() const;
|
||||
|
||||
Q_INVOKABLE void addItem(
|
||||
QQuickItem*, Qt::Alignment alignment = Qt::Alignment() );
|
||||
|
||||
Q_INVOKABLE void 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 );
|
||||
|
||||
|
|
@ -60,47 +91,51 @@ class QSK_EXPORT QskLinearBox : public QskIndexedLayoutBox
|
|||
void setStretchFactor( const QQuickItem*, int stretchFactor );
|
||||
int stretchFactor( const QQuickItem* ) const;
|
||||
|
||||
void setAlignment( int index, Qt::Alignment );
|
||||
Qt::Alignment alignment( int index ) const;
|
||||
|
||||
void setAlignment( const QQuickItem*, Qt::Alignment );
|
||||
Qt::Alignment alignment( const QQuickItem* ) const;
|
||||
|
||||
Q_INVOKABLE bool retainSizeWhenHidden( int index ) const;
|
||||
Q_INVOKABLE void setRetainSizeWhenHidden( int index, bool on );
|
||||
|
||||
bool retainSizeWhenHidden( const QQuickItem* ) const;
|
||||
void setRetainSizeWhenHidden( const QQuickItem*, bool on );
|
||||
|
||||
#if 1
|
||||
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;
|
||||
|
||||
Q_INVOKABLE void setRowStretchFactor( int row, int stretchFactor );
|
||||
Q_INVOKABLE int rowStretchFactor( int row ) const;
|
||||
|
||||
Q_INVOKABLE void setColumnStretchFactor( int column, int stretchFactor );
|
||||
Q_INVOKABLE int columnStretchFactor( int column ) const;
|
||||
#endif
|
||||
|
||||
public Q_SLOTS:
|
||||
void transpose();
|
||||
void activate();
|
||||
void invalidate();
|
||||
void clear( bool autoDelete = false );
|
||||
|
||||
Q_SIGNALS:
|
||||
void orientationChanged();
|
||||
void dimensionChanged();
|
||||
void defaultAlignmentChanged();
|
||||
void spacingChanged();
|
||||
void extraSpacingAtChanged();
|
||||
|
||||
protected:
|
||||
QRectF alignedLayoutRect( const QRectF& ) const override;
|
||||
bool event( QEvent* ) override;
|
||||
void geometryChangeEvent( QskGeometryChangeEvent* ) override;
|
||||
|
||||
void itemChange( ItemChange, const ItemChangeData& ) override;
|
||||
void updateLayout() override;
|
||||
|
||||
void autoAddItem( QQuickItem* ) override final;
|
||||
void autoRemoveItem( QQuickItem* ) override final;
|
||||
|
||||
private:
|
||||
void setupLayoutItem( QskLayoutItem*, int index ) override;
|
||||
void layoutItemInserted( QskLayoutItem*, int index ) override;
|
||||
void layoutItemRemoved( QskLayoutItem*, int index ) override;
|
||||
|
||||
void rearrange();
|
||||
void removeItemInternal( int index, bool autoDelete );
|
||||
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
};
|
||||
|
||||
inline bool QskLinearBox::isEmpty() const
|
||||
{
|
||||
return entryCount() <= 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,91 @@
|
|||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_LINEAR_LAYOUT_ENGINE_H
|
||||
#define QSK_LINEAR_LAYOUT_ENGINE_H
|
||||
|
||||
#include <qnamespace.h>
|
||||
#include <qrect.h>
|
||||
#include <memory>
|
||||
|
||||
class QQuickItem;
|
||||
|
||||
class QskLinearLayoutEngine
|
||||
{
|
||||
public:
|
||||
QskLinearLayoutEngine( Qt::Orientation, uint dimension );
|
||||
~QskLinearLayoutEngine();
|
||||
|
||||
Qt::Orientation orientation() const;
|
||||
void setOrientation( Qt::Orientation );
|
||||
|
||||
void setDimension( uint dimension );
|
||||
uint dimension() const;
|
||||
|
||||
void setDefaultAlignment( Qt::Alignment );
|
||||
Qt::Alignment defaultAlignment() const;
|
||||
|
||||
void setExtraSpacingAt( Qt::Edges );
|
||||
Qt::Edges extraSpacingAt() const;
|
||||
|
||||
int count() const;
|
||||
|
||||
int rowCount() const;
|
||||
int columnCount() const;
|
||||
|
||||
void setSpacing( qreal spacing, Qt::Orientations );
|
||||
qreal spacing( Qt::Orientation ) const;
|
||||
qreal defaultSpacing( Qt::Orientation ) const;
|
||||
|
||||
void insertItem( QQuickItem*, int index );
|
||||
void addItem( QQuickItem* );
|
||||
|
||||
void insertSpacerAt( int index, qreal spacing );
|
||||
void addSpacer( qreal spacing );
|
||||
|
||||
void removeAt( int index );
|
||||
|
||||
QQuickItem* itemAt( int index ) const;
|
||||
int spacerAt( int index ) const;
|
||||
|
||||
void setRetainSizeWhenHiddenAt( int index, bool on );
|
||||
bool retainSizeWhenHiddenAt( int index ) const;
|
||||
|
||||
void setAlignmentAt( int index, Qt::Alignment );
|
||||
Qt::Alignment alignmentAt( int index ) const;
|
||||
|
||||
void 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;
|
||||
|
||||
void setVisualDirection( Qt::LayoutDirection );
|
||||
Qt::LayoutDirection visualDirection() 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)
|
||||
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -4,12 +4,12 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include "QskStackBox.h"
|
||||
#include "QskLayoutConstraint.h"
|
||||
#include "QskLayoutEngine.h"
|
||||
#include "QskLayoutItem.h"
|
||||
#include "QskStackBoxAnimator.h"
|
||||
#include "QskLayoutConstraint.h"
|
||||
#include "QskEvent.h"
|
||||
#include "QskQuick.h"
|
||||
|
||||
#include <qpointer.h>
|
||||
#include <QPointer>
|
||||
|
||||
static qreal qskConstrainedValue( QskLayoutConstraint::Type type,
|
||||
const QskControl* control, qreal widthOrHeight )
|
||||
|
|
@ -35,16 +35,35 @@ static qreal qskConstrainedValue( QskLayoutConstraint::Type type,
|
|||
return constrainedValue;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class ItemInfo
|
||||
{
|
||||
public:
|
||||
inline ItemInfo()
|
||||
: item( nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
inline ItemInfo( Qt::Alignment alignment, QQuickItem* item )
|
||||
: alignment( alignment )
|
||||
, item( item )
|
||||
{
|
||||
}
|
||||
|
||||
Qt::Alignment alignment;
|
||||
QQuickItem* item;
|
||||
};
|
||||
}
|
||||
|
||||
class QskStackBox::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData()
|
||||
: currentIndex( -1 )
|
||||
{
|
||||
}
|
||||
|
||||
int currentIndex;
|
||||
QVector< ItemInfo > itemInfos;
|
||||
QPointer< QskStackBoxAnimator > animator;
|
||||
|
||||
int currentIndex = -1;
|
||||
Qt::Alignment defaultAlignment = Qt::AlignLeft | Qt::AlignVCenter;
|
||||
};
|
||||
|
||||
QskStackBox::QskStackBox( QQuickItem* parent )
|
||||
|
|
@ -53,7 +72,7 @@ QskStackBox::QskStackBox( QQuickItem* parent )
|
|||
}
|
||||
|
||||
QskStackBox::QskStackBox( bool autoAddChildren, QQuickItem* parent )
|
||||
: Inherited( parent )
|
||||
: QskIndexedLayoutBox( parent )
|
||||
, m_data( new PrivateData() )
|
||||
{
|
||||
setAutoAddChildren( autoAddChildren );
|
||||
|
|
@ -63,6 +82,22 @@ QskStackBox::~QskStackBox()
|
|||
{
|
||||
}
|
||||
|
||||
void QskStackBox::setDefaultAlignment( Qt::Alignment alignment )
|
||||
{
|
||||
if ( alignment != m_data->defaultAlignment )
|
||||
{
|
||||
m_data->defaultAlignment = alignment;
|
||||
Q_EMIT defaultAlignmentChanged( alignment );
|
||||
|
||||
polish();
|
||||
}
|
||||
}
|
||||
|
||||
Qt::Alignment QskStackBox::defaultAlignment() const
|
||||
{
|
||||
return m_data->defaultAlignment;
|
||||
}
|
||||
|
||||
void QskStackBox::setAnimator( QskStackBoxAnimator* animator )
|
||||
{
|
||||
if ( m_data->animator == animator )
|
||||
|
|
@ -103,6 +138,33 @@ QskStackBoxAnimator* QskStackBox::effectiveAnimator()
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
int QskStackBox::itemCount() const
|
||||
{
|
||||
return m_data->itemInfos.count();
|
||||
}
|
||||
|
||||
QQuickItem* QskStackBox::itemAtIndex( int index ) const
|
||||
{
|
||||
if ( index >= 0 && index < m_data->itemInfos.count() )
|
||||
return m_data->itemInfos[ index ].item;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int QskStackBox::indexOf( const QQuickItem* item ) const
|
||||
{
|
||||
if ( item && ( item->parentItem() != this ) )
|
||||
{
|
||||
for ( int i = 0; i < m_data->itemInfos.count(); i++ )
|
||||
{
|
||||
if ( item == m_data->itemInfos[i].item )
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
QQuickItem* QskStackBox::currentItem() const
|
||||
{
|
||||
return itemAtIndex( m_data->currentIndex );
|
||||
|
|
@ -113,44 +175,6 @@ int QskStackBox::currentIndex() const
|
|||
return m_data->currentIndex;
|
||||
}
|
||||
|
||||
void QskStackBox::layoutItemRemoved( QskLayoutItem*, int index )
|
||||
{
|
||||
if ( index == m_data->currentIndex )
|
||||
{
|
||||
int newIndex = m_data->currentIndex;
|
||||
if ( newIndex == itemCount() )
|
||||
newIndex--;
|
||||
|
||||
m_data->currentIndex = -1;
|
||||
|
||||
if ( newIndex >= 0 )
|
||||
setCurrentIndex( index );
|
||||
}
|
||||
else if ( index < m_data->currentIndex )
|
||||
{
|
||||
m_data->currentIndex--;
|
||||
// currentIndexChanged ???
|
||||
}
|
||||
|
||||
auto& engine = this->engine();
|
||||
if ( engine.itemCount() > 0 && engine.itemAt( 0, 0 ) == nullptr )
|
||||
{
|
||||
/*
|
||||
Using QGridLayoutEngine for a stack layout is actually
|
||||
not a good ideas. Until we have a new implementation,
|
||||
we need to work around situations, where the layout does
|
||||
not work properly with having several items in the
|
||||
same cell.
|
||||
In this particular situation we need to fix, that we lost
|
||||
the item from engine.q_grid[0].
|
||||
Calling transpose has this side effect.
|
||||
|
||||
*/
|
||||
engine.transpose();
|
||||
engine.transpose(); // reverting the call before
|
||||
}
|
||||
}
|
||||
|
||||
void QskStackBox::setCurrentIndex( int index )
|
||||
{
|
||||
if ( index < 0 || index >= itemCount() )
|
||||
|
|
@ -169,11 +193,6 @@ void QskStackBox::setCurrentIndex( int index )
|
|||
|
||||
if ( window() && isVisible() && isInitiallyPainted() && animator )
|
||||
{
|
||||
// When being hidden, the geometry is not updated.
|
||||
// So we do it now.
|
||||
|
||||
adjustItemAt( index );
|
||||
|
||||
// start the animation
|
||||
animator->setStartIndex( m_data->currentIndex );
|
||||
animator->setEndIndex( index );
|
||||
|
|
@ -201,26 +220,229 @@ void QskStackBox::setCurrentItem( const QQuickItem* item )
|
|||
setCurrentIndex( indexOf( item ) );
|
||||
}
|
||||
|
||||
QSizeF QskStackBox::layoutItemsSizeHint() const
|
||||
void QskStackBox::addItem( QQuickItem* item, Qt::Alignment alignment )
|
||||
{
|
||||
qreal width = -1;
|
||||
qreal height = -1;
|
||||
insertItem( -1, item, alignment );
|
||||
}
|
||||
|
||||
QSizeF constraint( -1, -1 );
|
||||
Qt::Orientations constraintOrientation = 0;
|
||||
void QskStackBox::insertItem(
|
||||
int index, QQuickItem* item, Qt::Alignment alignment )
|
||||
{
|
||||
if ( item == nullptr )
|
||||
return;
|
||||
|
||||
const auto& engine = this->engine();
|
||||
for ( int i = 0; i < engine.itemCount(); i++ )
|
||||
reparentItem( item );
|
||||
|
||||
if ( qskIsTransparentForPositioner( item ) )
|
||||
{
|
||||
const auto layoutItem = engine.layoutItemAt( i );
|
||||
// giving a warning, or ignoring the insert ???
|
||||
qskSetTransparentForPositioner( item, false );
|
||||
}
|
||||
|
||||
if ( layoutItem->hasDynamicConstraint() )
|
||||
const bool doAppend = ( index < 0 ) || ( index >= itemCount() );
|
||||
|
||||
if ( item->parentItem() == this )
|
||||
{
|
||||
const int oldIndex = indexOf( item );
|
||||
if ( oldIndex >= 0 )
|
||||
{
|
||||
constraintOrientation |= layoutItem->dynamicConstraintOrientation();
|
||||
// the item had been inserted before
|
||||
|
||||
if ( ( index == oldIndex ) || ( doAppend && ( oldIndex == itemCount() - 1 ) ) )
|
||||
{
|
||||
// already in place
|
||||
|
||||
auto& itemInfo = m_data->itemInfos[oldIndex];
|
||||
|
||||
if ( alignment != itemInfo.alignment )
|
||||
{
|
||||
itemInfo.alignment = alignment;
|
||||
polish();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_data->itemInfos.removeAt( oldIndex );
|
||||
}
|
||||
}
|
||||
|
||||
if ( doAppend )
|
||||
index = itemCount();
|
||||
|
||||
m_data->itemInfos.insert( index, { alignment, item } );
|
||||
|
||||
const int oldCurrentIndex = m_data->currentIndex;
|
||||
|
||||
if ( m_data->itemInfos.count() == 1 )
|
||||
{
|
||||
m_data->currentIndex = 0;
|
||||
item->setVisible( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
item->setVisible( false );
|
||||
|
||||
if ( index <= m_data->currentIndex )
|
||||
m_data->currentIndex++;
|
||||
}
|
||||
|
||||
if ( oldCurrentIndex != m_data->currentIndex )
|
||||
Q_EMIT currentIndexChanged( m_data->currentIndex );
|
||||
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
}
|
||||
|
||||
void QskStackBox::removeAt( int index )
|
||||
{
|
||||
removeItemInternal( index, false );
|
||||
}
|
||||
|
||||
void QskStackBox::removeItemInternal( int index, bool unparent )
|
||||
{
|
||||
if ( index < 0 || index >= m_data->itemInfos.count() )
|
||||
return;
|
||||
|
||||
if ( !unparent )
|
||||
{
|
||||
if ( auto item = m_data->itemInfos[ index ].item )
|
||||
{
|
||||
if ( item->parentItem() == this )
|
||||
item->setParentItem( nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
m_data->itemInfos.removeAt( index );
|
||||
|
||||
if ( index <= m_data->currentIndex )
|
||||
Q_EMIT currentIndexChanged( --m_data->currentIndex );
|
||||
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
}
|
||||
|
||||
void QskStackBox::removeItem( const QQuickItem* item )
|
||||
{
|
||||
removeAt( indexOf( item ) );
|
||||
}
|
||||
|
||||
void QskStackBox::autoAddItem( QQuickItem* item )
|
||||
{
|
||||
removeAt( indexOf( item ) );
|
||||
}
|
||||
|
||||
void QskStackBox::autoRemoveItem( QQuickItem* item )
|
||||
{
|
||||
removeItemInternal( indexOf( item ), false );
|
||||
}
|
||||
|
||||
void QskStackBox::clear( bool autoDelete )
|
||||
{
|
||||
for ( const auto& itemInfo : qskAsConst( m_data->itemInfos ) )
|
||||
{
|
||||
auto item = itemInfo.item;
|
||||
|
||||
if( autoDelete && ( item->parent() == this ) )
|
||||
{
|
||||
delete item;
|
||||
}
|
||||
else
|
||||
{
|
||||
const QSizeF hint = layoutItem->sizeHint( Qt::PreferredSize, constraint );
|
||||
item->setParentItem( nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
m_data->itemInfos.clear();
|
||||
|
||||
if ( m_data->currentIndex >= 0 )
|
||||
{
|
||||
m_data->currentIndex = -1;
|
||||
Q_EMIT currentIndexChanged( m_data->currentIndex );
|
||||
}
|
||||
}
|
||||
|
||||
void QskStackBox::setAlignment( const QQuickItem* item, Qt::Alignment alignment )
|
||||
{
|
||||
setAlignmentAt( indexOf( item ), alignment );
|
||||
}
|
||||
|
||||
Qt::Alignment QskStackBox::alignment( const QQuickItem* item ) const
|
||||
{
|
||||
return alignmentAt( indexOf( item ) );
|
||||
}
|
||||
|
||||
void QskStackBox::setAlignmentAt( int index, Qt::Alignment alignment )
|
||||
{
|
||||
if ( index < 0 || index >= m_data->itemInfos.count() )
|
||||
return;
|
||||
|
||||
m_data->itemInfos[ index ].alignment = alignment;
|
||||
|
||||
if ( index == m_data->currentIndex )
|
||||
polish();
|
||||
}
|
||||
|
||||
Qt::Alignment QskStackBox::alignmentAt( int index ) const
|
||||
{
|
||||
if ( index >= 0 && index < m_data->itemInfos.count() )
|
||||
return m_data->itemInfos[ index ].alignment;
|
||||
|
||||
return Qt::Alignment();
|
||||
}
|
||||
|
||||
QRectF QskStackBox::geometryForItemAt( int index ) const
|
||||
{
|
||||
const auto r = layoutRect();
|
||||
|
||||
if ( index >= 0 && index < m_data->itemInfos.count() )
|
||||
{
|
||||
const auto& info = m_data->itemInfos[ index ];
|
||||
|
||||
const auto align = info.alignment ? info.alignment : m_data->defaultAlignment;
|
||||
return QskLayoutConstraint::itemRect( info.item, r, align );
|
||||
}
|
||||
|
||||
return QRectF( r.x(), r.y(), 0.0, 0.0 );
|
||||
}
|
||||
|
||||
void QskStackBox::updateLayout()
|
||||
{
|
||||
const auto idx = m_data->currentIndex;
|
||||
|
||||
if ( idx >= 0 )
|
||||
{
|
||||
const auto rect = geometryForItemAt( idx );
|
||||
qskSetItemGeometry( m_data->itemInfos[ idx ].item, rect );
|
||||
}
|
||||
}
|
||||
|
||||
QSizeF QskStackBox::contentsSizeHint() const
|
||||
{
|
||||
#if 1
|
||||
if ( itemCount() == 0 )
|
||||
return QSizeF( 0, 0 );
|
||||
#endif
|
||||
|
||||
qreal width = -1;
|
||||
qreal height = -1;
|
||||
|
||||
using namespace QskLayoutConstraint;
|
||||
|
||||
int constraintTypes = Unconstrained;
|
||||
|
||||
for ( const auto& itemInfo : qskAsConst( m_data->itemInfos ) )
|
||||
{
|
||||
const auto item = itemInfo.item;
|
||||
|
||||
const auto type = constraintType( item );
|
||||
if ( type != Unconstrained )
|
||||
{
|
||||
constraintTypes |= type;
|
||||
}
|
||||
else
|
||||
{
|
||||
const QSizeF hint = effectiveConstraint( item, Qt::PreferredSize );
|
||||
|
||||
if ( hint.width() >= width )
|
||||
width = hint.width();
|
||||
|
|
@ -232,40 +454,39 @@ QSizeF QskStackBox::layoutItemsSizeHint() const
|
|||
|
||||
#if 1
|
||||
// does this work ???
|
||||
if ( constraintOrientation & Qt::Horizontal )
|
||||
|
||||
if ( constraintTypes & WidthForHeight )
|
||||
{
|
||||
constraint.setWidth( -1 );
|
||||
constraint.setHeight( height );
|
||||
const QSizeF constraint( -1, height );
|
||||
|
||||
for ( int i = 0; i < engine.itemCount(); i++ )
|
||||
for ( const auto& itemInfo : qskAsConst( m_data->itemInfos ) )
|
||||
{
|
||||
const auto layoutItem = engine.layoutItemAt( i );
|
||||
const auto item = itemInfo.item;
|
||||
|
||||
if ( layoutItem->hasDynamicConstraint() &&
|
||||
layoutItem->dynamicConstraintOrientation() == Qt::Horizontal )
|
||||
if ( constraintType( item ) == WidthForHeight )
|
||||
{
|
||||
const QSizeF hint = layoutItem->sizeHint( Qt::PreferredSize, constraint );
|
||||
if ( hint.width() > width )
|
||||
width = hint.width();
|
||||
const QSizeF hint = QskLayoutConstraint::sizeHint(
|
||||
item, Qt::PreferredSize, constraint );
|
||||
|
||||
width = qMax( width, hint.width() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( constraintOrientation & Qt::Vertical )
|
||||
if ( constraintTypes & HeightForWidth )
|
||||
{
|
||||
constraint.setWidth( width );
|
||||
constraint.setHeight( -1 );
|
||||
const QSizeF constraint( width, -1 );
|
||||
|
||||
for ( int i = 0; i < engine.itemCount(); i++ )
|
||||
for ( const auto& itemInfo : qskAsConst( m_data->itemInfos ) )
|
||||
{
|
||||
const auto layoutItem = engine.layoutItemAt( i );
|
||||
const auto item = itemInfo.item;
|
||||
|
||||
if ( layoutItem->hasDynamicConstraint() &&
|
||||
layoutItem->dynamicConstraintOrientation() == Qt::Vertical )
|
||||
if ( constraintType( item ) == HeightForWidth )
|
||||
{
|
||||
const QSizeF hint = layoutItem->sizeHint( Qt::PreferredSize, constraint );
|
||||
if ( hint.height() > height )
|
||||
height = hint.height();
|
||||
const QSizeF hint = QskLayoutConstraint::sizeHint(
|
||||
item, Qt::PreferredSize, constraint );
|
||||
|
||||
height = qMax( height, hint.height() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -286,39 +507,25 @@ qreal QskStackBox::widthForHeight( qreal height ) const
|
|||
QskLayoutConstraint::WidthForHeight, this, height, qskConstrainedValue );
|
||||
}
|
||||
|
||||
void QskStackBox::layoutItemInserted( QskLayoutItem* layoutItem, int index )
|
||||
bool QskStackBox::event( QEvent* event )
|
||||
{
|
||||
Q_UNUSED( index )
|
||||
|
||||
QQuickItem* item = layoutItem->item();
|
||||
if ( item == nullptr )
|
||||
return;
|
||||
|
||||
#if 1
|
||||
/*
|
||||
In general QGridLayoutEngine supports having multiple entries
|
||||
in one cell, but well ...
|
||||
So we have to go away from using it and doing the simple use case of
|
||||
a stack layout manually. TODO ...
|
||||
|
||||
One problem we ran into is, that a cell is considered being hidden,
|
||||
when the first entry is ignored. So for the moment we simply set the
|
||||
retainSizeWhenHidden flag, with the cost of having geometry updates
|
||||
for invisible updates.
|
||||
*/
|
||||
layoutItem->setRetainSizeWhenHidden( true );
|
||||
#endif
|
||||
if ( itemCount() == 1 )
|
||||
switch ( static_cast< int >( event->type() ) )
|
||||
{
|
||||
m_data->currentIndex = 0;
|
||||
item->setVisible( true );
|
||||
case QEvent::LayoutRequest:
|
||||
{
|
||||
resetImplicitSize();
|
||||
polish();
|
||||
break;
|
||||
}
|
||||
case QEvent::ContentsRectChange:
|
||||
case QskEvent::GeometryChange:
|
||||
{
|
||||
polish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Q_EMIT currentIndexChanged( m_data->currentIndex );
|
||||
}
|
||||
else
|
||||
{
|
||||
item->setVisible( false );
|
||||
}
|
||||
return Inherited::event( event );
|
||||
}
|
||||
|
||||
#include "moc_QskStackBox.cpp"
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class QSK_EXPORT QskStackBox : public QskIndexedLayoutBox
|
|||
Q_PROPERTY( QQuickItem* currentItem READ currentItem
|
||||
WRITE setCurrentItem NOTIFY currentItemChanged )
|
||||
|
||||
using Inherited = QskIndexedLayoutBox;
|
||||
using Inherited = QskBox;
|
||||
|
||||
public:
|
||||
explicit QskStackBox( QQuickItem* parent = nullptr );
|
||||
|
|
@ -28,36 +28,74 @@ class QSK_EXPORT QskStackBox : public QskIndexedLayoutBox
|
|||
|
||||
~QskStackBox() override;
|
||||
|
||||
bool isEmpty() const;
|
||||
|
||||
int itemCount() const;
|
||||
QQuickItem* itemAtIndex( int index ) const;
|
||||
int indexOf( const QQuickItem* ) const;
|
||||
|
||||
void addItem(
|
||||
QQuickItem*, Qt::Alignment alignment = Qt::Alignment() );
|
||||
|
||||
void insertItem(
|
||||
int index, QQuickItem*, Qt::Alignment alignment = Qt::Alignment() );
|
||||
|
||||
void removeItem( const QQuickItem* );
|
||||
void removeAt( int index );
|
||||
|
||||
QQuickItem* currentItem() const;
|
||||
int currentIndex() const;
|
||||
|
||||
qreal heightForWidth( qreal width ) const override;
|
||||
qreal widthForHeight( qreal height ) const override;
|
||||
void setDefaultAlignment( Qt::Alignment );
|
||||
Qt::Alignment defaultAlignment() const;
|
||||
|
||||
void setAlignmentAt( int index, Qt::Alignment );
|
||||
Qt::Alignment alignmentAt( int index ) const;
|
||||
|
||||
void setAlignment( const QQuickItem*, Qt::Alignment );
|
||||
Qt::Alignment alignment( const QQuickItem* ) const;
|
||||
|
||||
void setAnimator( QskStackBoxAnimator* );
|
||||
const QskStackBoxAnimator* animator() const;
|
||||
QskStackBoxAnimator* animator();
|
||||
|
||||
QSizeF contentsSizeHint() const override;
|
||||
qreal heightForWidth( qreal width ) const override;
|
||||
qreal widthForHeight( qreal height ) const override;
|
||||
|
||||
QRectF geometryForItemAt( int index ) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void defaultAlignmentChanged( Qt::Alignment );
|
||||
|
||||
public Q_SLOTS:
|
||||
void setCurrentIndex( int index );
|
||||
void setCurrentItem( const QQuickItem* );
|
||||
void clear( bool autoDelete = false );
|
||||
|
||||
Q_SIGNALS:
|
||||
void currentIndexChanged( int index );
|
||||
void currentItemChanged( QQuickItem* );
|
||||
|
||||
protected:
|
||||
bool event( QEvent* ) override;
|
||||
void updateLayout() override;
|
||||
|
||||
void autoAddItem( QQuickItem* ) override final;
|
||||
void autoRemoveItem( QQuickItem* ) override final;
|
||||
|
||||
QskStackBoxAnimator* effectiveAnimator();
|
||||
QSizeF layoutItemsSizeHint() const override;
|
||||
|
||||
private:
|
||||
friend class QskStackBoxAnimator;
|
||||
|
||||
void layoutItemInserted( QskLayoutItem*, int index ) override;
|
||||
void layoutItemRemoved( QskLayoutItem*, int index ) override;
|
||||
void removeItemInternal( int index, bool autoDelete );
|
||||
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
};
|
||||
|
||||
inline bool QskStackBox::isEmpty() const
|
||||
{
|
||||
return itemCount() <= 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include "QskStackBoxAnimator.h"
|
||||
#include "QskLayoutEngine.h"
|
||||
#include "QskLayoutItem.h"
|
||||
#include "QskStackBox.h"
|
||||
#include "QskEvent.h"
|
||||
#include "QskQuick.h"
|
||||
|
||||
static Qsk::Direction qskDirection(
|
||||
Qt::Orientation orientation, int from, int to, int itemCount )
|
||||
|
|
@ -91,17 +91,19 @@ QskStackBox* QskStackBoxAnimator::stackBox() const
|
|||
return static_cast< QskStackBox* >( parent() );
|
||||
}
|
||||
|
||||
QskLayoutItem* QskStackBoxAnimator::layoutItemAt( int index ) const
|
||||
QQuickItem* QskStackBoxAnimator::itemAt( int index ) const
|
||||
{
|
||||
return stackBox()->engine().layoutItemAt(
|
||||
return stackBox()->itemAtIndex(
|
||||
( index == 0 ) ? m_startIndex : m_endIndex );
|
||||
}
|
||||
|
||||
QskStackBoxAnimator1::QskStackBoxAnimator1( QskStackBox* parent )
|
||||
: QskStackBoxAnimator( parent )
|
||||
, m_orientation( Qt::Horizontal )
|
||||
, m_isDirty( false )
|
||||
, m_hasClip( false )
|
||||
{
|
||||
// catching geometryChanges to know about resizing
|
||||
}
|
||||
|
||||
QskStackBoxAnimator1::~QskStackBoxAnimator1()
|
||||
|
|
@ -131,97 +133,72 @@ void QskStackBoxAnimator1::setup()
|
|||
m_direction = qskDirection( m_orientation,
|
||||
startIndex(), endIndex(), stackBox->itemCount() );
|
||||
|
||||
for ( int i = 0; i < 2; i++ )
|
||||
{
|
||||
QskLayoutItem* layoutItem = layoutItemAt( i );
|
||||
if ( layoutItem )
|
||||
{
|
||||
QQuickItem* item = layoutItem->item();
|
||||
const Qt::Orientation orientation = this->orientation();
|
||||
|
||||
m_itemOffset[ i ] =
|
||||
( orientation == Qt::Horizontal ) ? item->x() : item->y();
|
||||
|
||||
if ( i == 1 )
|
||||
{
|
||||
// now move the new item outside of
|
||||
// the visible area and then "show" it
|
||||
|
||||
if ( orientation == Qt::Horizontal )
|
||||
item->setX( stackBox->width() );
|
||||
else
|
||||
item->setY( stackBox->height() );
|
||||
|
||||
item->setVisible( true );
|
||||
}
|
||||
|
||||
// we don't want the engine() to interfere, when
|
||||
// controlling the item by the animation
|
||||
|
||||
layoutItem->setUpdateMode( QskLayoutItem::UpdateNone );
|
||||
}
|
||||
}
|
||||
|
||||
m_hasClip = stackBox->clip();
|
||||
if ( !m_hasClip )
|
||||
stackBox->setClip( true );
|
||||
|
||||
stackBox->installEventFilter( this );
|
||||
m_isDirty = true;
|
||||
}
|
||||
|
||||
void QskStackBoxAnimator1::advance( qreal value )
|
||||
{
|
||||
auto stackBox = this->stackBox();
|
||||
const bool isHorizontal = m_orientation == Qt::Horizontal;
|
||||
|
||||
for ( int i = 0; i < 2; i++ )
|
||||
{
|
||||
QskLayoutItem* layoutItem = layoutItemAt( i );
|
||||
if ( layoutItem == nullptr )
|
||||
continue;
|
||||
|
||||
if ( layoutItem->isGeometryDirty() )
|
||||
if ( auto item = itemAt( i ) )
|
||||
{
|
||||
// the layout tried to replace the item, but we
|
||||
// want to have control over the position. But we
|
||||
// also lost resizing - that's why we have to do it here
|
||||
// manually
|
||||
QRectF rect = qskItemGeometry( item );
|
||||
|
||||
stackBox->adjustItemAt( ( i == 0 ) ? startIndex() : endIndex() );
|
||||
if ( m_isDirty )
|
||||
{
|
||||
const int index = ( i == 0 ) ? startIndex() : endIndex();
|
||||
rect = stackBox->geometryForItemAt( index );
|
||||
|
||||
QQuickItem* item = layoutItem->item();
|
||||
m_itemOffset[ i ] =
|
||||
( m_orientation == Qt::Horizontal ) ? item->x() : item->y();
|
||||
}
|
||||
m_itemOffset[ i ] = isHorizontal ? rect.x() : rect.y();
|
||||
}
|
||||
|
||||
QQuickItem* item = layoutItem->item();
|
||||
qreal x, y;
|
||||
|
||||
if ( m_orientation == Qt::Horizontal )
|
||||
{
|
||||
const qreal off = stackBox->width() * ( value - i );
|
||||
if ( isHorizontal )
|
||||
{
|
||||
qreal off = stackBox->width() * ( value - i );
|
||||
if ( m_direction == Qsk::LeftToRight )
|
||||
off = -off;
|
||||
|
||||
if ( m_direction == Qsk::LeftToRight )
|
||||
item->setX( m_itemOffset[ i ] - off );
|
||||
x = m_itemOffset[ i ] + off;
|
||||
y = rect.y();
|
||||
}
|
||||
else
|
||||
item->setX( m_itemOffset[ i ] + off );
|
||||
}
|
||||
else
|
||||
{
|
||||
const qreal off = stackBox->height() * ( value - i );
|
||||
{
|
||||
qreal off = stackBox->height() * ( value - i );
|
||||
if ( m_direction == Qsk::BottomToTop )
|
||||
off = -off;
|
||||
|
||||
if ( m_direction == Qsk::TopToBottom )
|
||||
item->setY( m_itemOffset[ i ] + off );
|
||||
else
|
||||
item->setY( m_itemOffset[ i ] - off );
|
||||
x = rect.x();
|
||||
y = m_itemOffset[ i ] + off;
|
||||
}
|
||||
|
||||
qskSetItemGeometry( item, x, y, rect.width(), rect.height() );
|
||||
|
||||
if ( !item->isVisible() )
|
||||
item->setVisible( true );
|
||||
}
|
||||
}
|
||||
|
||||
m_isDirty = false;
|
||||
}
|
||||
|
||||
void QskStackBoxAnimator1::done()
|
||||
{
|
||||
for ( int i = 0; i < 2; i++ )
|
||||
{
|
||||
if ( QskLayoutItem* layoutItem = layoutItemAt( i ) )
|
||||
if ( auto item = itemAt( i ) )
|
||||
{
|
||||
layoutItem->setUpdateMode( QskLayoutItem::UpdateWhenVisible );
|
||||
layoutItem->item()->setVisible( i == 1 );
|
||||
item->removeEventFilter( this );
|
||||
item->setVisible( i == 1 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -229,6 +206,25 @@ void QskStackBoxAnimator1::done()
|
|||
stackBox()->setClip( false );
|
||||
}
|
||||
|
||||
bool QskStackBoxAnimator1::eventFilter( QObject* object, QEvent* event )
|
||||
{
|
||||
if ( !m_isDirty && object == stackBox() )
|
||||
{
|
||||
switch( static_cast< int >( event->type() ) )
|
||||
{
|
||||
case QskEvent::GeometryChange:
|
||||
case QskEvent::ContentsRectChange:
|
||||
case QskEvent::LayoutRequest:
|
||||
{
|
||||
m_isDirty = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QObject::eventFilter( object, event );
|
||||
}
|
||||
|
||||
QskStackBoxAnimator3::QskStackBoxAnimator3( QskStackBox* parent )
|
||||
: QskStackBoxAnimator( parent )
|
||||
{
|
||||
|
|
@ -240,33 +236,30 @@ QskStackBoxAnimator3::~QskStackBoxAnimator3()
|
|||
|
||||
void QskStackBoxAnimator3::setup()
|
||||
{
|
||||
QskLayoutItem* layoutItem = layoutItemAt( 1 );
|
||||
if ( layoutItem )
|
||||
if ( auto item = itemAt( 1 ) )
|
||||
{
|
||||
layoutItem->item()->setOpacity( 0.0 );
|
||||
layoutItem->item()->setVisible( true );
|
||||
item->setOpacity( 0.0 );
|
||||
item->setVisible( true );
|
||||
}
|
||||
}
|
||||
|
||||
void QskStackBoxAnimator3::advance( qreal value )
|
||||
{
|
||||
QskLayoutItem* layoutItem1 = layoutItemAt( 0 );
|
||||
if ( layoutItem1 )
|
||||
layoutItem1->item()->setOpacity( 1.0 - value );
|
||||
if ( auto item1 = itemAt( 0 ) )
|
||||
item1->setOpacity( 1.0 - value );
|
||||
|
||||
QskLayoutItem* layoutItem2 = layoutItemAt( 1 );
|
||||
if ( layoutItem2 )
|
||||
layoutItem2->item()->setOpacity( value );
|
||||
if ( auto item2 = itemAt( 1 ) )
|
||||
item2->setOpacity( value );
|
||||
}
|
||||
|
||||
void QskStackBoxAnimator3::done()
|
||||
{
|
||||
for ( int i = 0; i < 2; i++ )
|
||||
{
|
||||
if ( QskLayoutItem* layoutItem = layoutItemAt( i ) )
|
||||
if ( auto item = itemAt( i ) )
|
||||
{
|
||||
layoutItem->item()->setOpacity( 1.0 );
|
||||
layoutItem->item()->setVisible( i == 1 ); // not here !!
|
||||
item->setOpacity( 1.0 );
|
||||
item->setVisible( i == 1 ); // not here !!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,14 +12,14 @@
|
|||
#include <qobject.h>
|
||||
|
||||
class QskStackBox;
|
||||
class QskLayoutItem;
|
||||
class QQuickItem;
|
||||
|
||||
class QSK_EXPORT QskStackBoxAnimator : public QObject, public QskAnimator
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QskStackBoxAnimator( QskStackBox* parent );
|
||||
QskStackBoxAnimator( QskStackBox* );
|
||||
~QskStackBoxAnimator() override;
|
||||
|
||||
void setStartIndex( int index );
|
||||
|
|
@ -30,7 +30,7 @@ class QSK_EXPORT QskStackBoxAnimator : public QObject, public QskAnimator
|
|||
|
||||
protected:
|
||||
QskStackBox* stackBox() const;
|
||||
QskLayoutItem* layoutItemAt( int index ) const;
|
||||
QQuickItem* itemAt( int index ) const;
|
||||
|
||||
private:
|
||||
int m_startIndex;
|
||||
|
|
@ -42,13 +42,15 @@ class QSK_EXPORT QskStackBoxAnimator1 : public QskStackBoxAnimator
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QskStackBoxAnimator1( QskStackBox* parent );
|
||||
QskStackBoxAnimator1( QskStackBox* );
|
||||
~QskStackBoxAnimator1() override;
|
||||
|
||||
void setOrientation( Qt::Orientation );
|
||||
Qt::Orientation orientation() const;
|
||||
|
||||
protected:
|
||||
bool eventFilter( QObject*, QEvent* ) override;
|
||||
|
||||
void setup() override;
|
||||
void advance( qreal value ) override;
|
||||
void done() override;
|
||||
|
|
@ -58,6 +60,7 @@ class QSK_EXPORT QskStackBoxAnimator1 : public QskStackBoxAnimator
|
|||
|
||||
Qt::Orientation m_orientation : 2;
|
||||
Qsk::Direction m_direction : 4;
|
||||
bool m_isDirty : 1;
|
||||
bool m_hasClip : 1;
|
||||
};
|
||||
|
||||
|
|
@ -66,7 +69,7 @@ class QSK_EXPORT QskStackBoxAnimator3 : public QskStackBoxAnimator
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QskStackBoxAnimator3( QskStackBox* parent );
|
||||
QskStackBoxAnimator3( QskStackBox* );
|
||||
~QskStackBoxAnimator3() override;
|
||||
|
||||
protected:
|
||||
|
|
|
|||
10
src/src.pro
10
src/src.pro
|
|
@ -233,25 +233,23 @@ SOURCES += \
|
|||
|
||||
HEADERS += \
|
||||
layouts/QskGridBox.h \
|
||||
layouts/QskGridLayoutEngine.h \
|
||||
layouts/QskIndexedLayoutBox.h \
|
||||
layouts/QskLayoutEngine.h \
|
||||
layouts/QskLayoutBox.h \
|
||||
layouts/QskLayoutConstraint.h \
|
||||
layouts/QskLayoutHint.h \
|
||||
layouts/QskLayoutItem.h \
|
||||
layouts/QskLinearBox.h \
|
||||
layouts/QskLinearLayoutEngine.h \
|
||||
layouts/QskStackBoxAnimator.h \
|
||||
layouts/QskStackBox.h
|
||||
|
||||
SOURCES += \
|
||||
layouts/QskGridBox.cpp \
|
||||
layouts/QskGridLayoutEngine.cpp \
|
||||
layouts/QskIndexedLayoutBox.cpp \
|
||||
layouts/QskLayoutBox.cpp \
|
||||
layouts/QskLayoutConstraint.cpp \
|
||||
layouts/QskLayoutHint.cpp \
|
||||
layouts/QskLayoutEngine.cpp \
|
||||
layouts/QskLayoutItem.cpp \
|
||||
layouts/QskLinearBox.cpp \
|
||||
layouts/QskLinearLayoutEngine.cpp \
|
||||
layouts/QskStackBoxAnimator.cpp \
|
||||
layouts/QskStackBox.cpp
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue