Loading...
Searching...
No Matches
qwt_dyngrid_layout.cpp
/******************************************************************************
* Qwt Widget Library
* Copyright (C) 1997 Josef Wilgen
* Copyright (C) 2002 Uwe Rathmann
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the Qwt License, Version 1.0
*****************************************************************************/
#include "qwt_dyngrid_layout.h"
#include <qvector.h>
#include <qlist.h>
class QwtDynGridLayout::PrivateData
{
public:
PrivateData()
: isDirty( true )
{
}
void updateLayoutCache();
mutable QList< QLayoutItem* > itemList;
uint maxColumns;
uint numRows;
uint numColumns;
Qt::Orientations expanding;
bool isDirty;
QVector< QSize > itemSizeHints;
};
void QwtDynGridLayout::PrivateData::updateLayoutCache()
{
itemSizeHints.resize( itemList.count() );
int index = 0;
for ( QList< QLayoutItem* >::const_iterator it = itemList.constBegin();
it != itemList.constEnd(); ++it, index++ )
{
itemSizeHints[ index ] = ( *it )->sizeHint();
}
isDirty = false;
}
QwtDynGridLayout::QwtDynGridLayout( QWidget* parent, int margin, int spacing )
: QLayout( parent )
{
init();
setSpacing( spacing );
setContentsMargins( margin, margin, margin, margin );
}
QwtDynGridLayout::QwtDynGridLayout( int spacing )
{
init();
setSpacing( spacing );
}
void QwtDynGridLayout::init()
{
m_data = new QwtDynGridLayout::PrivateData;
m_data->maxColumns = m_data->numRows = m_data->numColumns = 0;
}
QwtDynGridLayout::~QwtDynGridLayout()
{
qDeleteAll( m_data->itemList );
delete m_data;
}
void QwtDynGridLayout::invalidate()
{
m_data->isDirty = true;
QLayout::invalidate();
}
void QwtDynGridLayout::setMaxColumns( uint maxColumns )
{
m_data->maxColumns = maxColumns;
}
uint QwtDynGridLayout::maxColumns() const
{
return m_data->maxColumns;
}
void QwtDynGridLayout::addItem( QLayoutItem* item )
{
m_data->itemList.append( item );
invalidate();
}
bool QwtDynGridLayout::isEmpty() const
{
return m_data->itemList.isEmpty();
}
uint QwtDynGridLayout::itemCount() const
{
return m_data->itemList.count();
}
QLayoutItem* QwtDynGridLayout::itemAt( int index ) const
{
if ( index < 0 || index >= m_data->itemList.count() )
return NULL;
return m_data->itemList.at( index );
}
QLayoutItem* QwtDynGridLayout::takeAt( int index )
{
if ( index < 0 || index >= m_data->itemList.count() )
return NULL;
m_data->isDirty = true;
return m_data->itemList.takeAt( index );
}
int QwtDynGridLayout::count() const
{
return m_data->itemList.count();
}
void QwtDynGridLayout::setExpandingDirections( Qt::Orientations expanding )
{
m_data->expanding = expanding;
}
Qt::Orientations QwtDynGridLayout::expandingDirections() const
{
return m_data->expanding;
}
void QwtDynGridLayout::setGeometry( const QRect& rect )
{
QLayout::setGeometry( rect );
if ( isEmpty() )
return;
m_data->numColumns = columnsForWidth( rect.width() );
m_data->numRows = itemCount() / m_data->numColumns;
if ( itemCount() % m_data->numColumns )
m_data->numRows++;
const QList< QRect > itemGeometries = layoutItems( rect, m_data->numColumns );
int index = 0;
for ( QList< QLayoutItem* >::const_iterator it = m_data->itemList.constBegin();
it != m_data->itemList.constEnd(); ++it )
{
( *it )->setGeometry( itemGeometries[index] );
index++;
}
}
uint QwtDynGridLayout::columnsForWidth( int width ) const
{
if ( isEmpty() )
return 0;
uint maxColumns = itemCount();
if ( m_data->maxColumns > 0 )
maxColumns = qMin( m_data->maxColumns, maxColumns );
if ( maxRowWidth( maxColumns ) <= width )
return maxColumns;
for ( uint numColumns = 2; numColumns <= maxColumns; numColumns++ )
{
const int rowWidth = maxRowWidth( numColumns );
if ( rowWidth > width )
return numColumns - 1;
}
return 1; // At least 1 column
}
int QwtDynGridLayout::maxRowWidth( int numColumns ) const
{
int col;
QVector< int > colWidth( numColumns );
for ( col = 0; col < numColumns; col++ )
colWidth[col] = 0;
if ( m_data->isDirty )
m_data->updateLayoutCache();
for ( int index = 0;
index < m_data->itemSizeHints.count(); index++ )
{
col = index % numColumns;
colWidth[col] = qMax( colWidth[col],
m_data->itemSizeHints[index].width() );
}
const QMargins m = contentsMargins();
int rowWidth = m.left() + m.right() + ( numColumns - 1 ) * spacing();
for ( col = 0; col < numColumns; col++ )
rowWidth += colWidth[col];
return rowWidth;
}
int QwtDynGridLayout::maxItemWidth() const
{
if ( isEmpty() )
return 0;
if ( m_data->isDirty )
m_data->updateLayoutCache();
int w = 0;
for ( int i = 0; i < m_data->itemSizeHints.count(); i++ )
{
const int itemW = m_data->itemSizeHints[i].width();
if ( itemW > w )
w = itemW;
}
return w;
}
QList< QRect > QwtDynGridLayout::layoutItems( const QRect& rect,
uint numColumns ) const
{
QList< QRect > itemGeometries;
if ( numColumns == 0 || isEmpty() )
return itemGeometries;
uint numRows = itemCount() / numColumns;
if ( numColumns % itemCount() )
numRows++;
if ( numRows == 0 )
return itemGeometries;
QVector< int > rowHeight( numRows );
QVector< int > colWidth( numColumns );
layoutGrid( numColumns, rowHeight, colWidth );
bool expandH, expandV;
expandH = expandingDirections() & Qt::Horizontal;
expandV = expandingDirections() & Qt::Vertical;
if ( expandH || expandV )
stretchGrid( rect, numColumns, rowHeight, colWidth );
const int maxColumns = m_data->maxColumns;
m_data->maxColumns = numColumns;
const QRect alignedRect = alignmentRect( rect );
m_data->maxColumns = maxColumns;
const int xOffset = expandH ? 0 : alignedRect.x();
const int yOffset = expandV ? 0 : alignedRect.y();
QVector< int > colX( numColumns );
QVector< int > rowY( numRows );
const int xySpace = spacing();
const QMargins m = contentsMargins();
rowY[0] = yOffset + m.top();
for ( uint r = 1; r < numRows; r++ )
rowY[r] = rowY[r - 1] + rowHeight[r - 1] + xySpace;
colX[0] = xOffset + m.left();
for ( uint c = 1; c < numColumns; c++ )
colX[c] = colX[c - 1] + colWidth[c - 1] + xySpace;
const int itemCount = m_data->itemList.size();
itemGeometries.reserve( itemCount );
for ( int i = 0; i < itemCount; i++ )
{
const int row = i / numColumns;
const int col = i % numColumns;
const QRect itemGeometry( colX[col], rowY[row],
colWidth[col], rowHeight[row] );
itemGeometries.append( itemGeometry );
}
return itemGeometries;
}
void QwtDynGridLayout::layoutGrid( uint numColumns,
QVector< int >& rowHeight, QVector< int >& colWidth ) const
{
if ( numColumns <= 0 )
return;
if ( m_data->isDirty )
m_data->updateLayoutCache();
for ( int index = 0; index < m_data->itemSizeHints.count(); index++ )
{
const int row = index / numColumns;
const int col = index % numColumns;
const QSize& size = m_data->itemSizeHints[index];
rowHeight[row] = ( col == 0 )
? size.height() : qMax( rowHeight[row], size.height() );
colWidth[col] = ( row == 0 )
? size.width() : qMax( colWidth[col], size.width() );
}
}
bool QwtDynGridLayout::hasHeightForWidth() const
{
return true;
}
int QwtDynGridLayout::heightForWidth( int width ) const
{
if ( isEmpty() )
return 0;
const uint numColumns = columnsForWidth( width );
uint numRows = itemCount() / numColumns;
if ( itemCount() % numColumns )
numRows++;
QVector< int > rowHeight( numRows );
QVector< int > colWidth( numColumns );
layoutGrid( numColumns, rowHeight, colWidth );
const QMargins m = contentsMargins();
int h = m.top() + m.bottom() + ( numRows - 1 ) * spacing();
for ( uint row = 0; row < numRows; row++ )
h += rowHeight[row];
return h;
}
void QwtDynGridLayout::stretchGrid( const QRect& rect,
uint numColumns, QVector< int >& rowHeight, QVector< int >& colWidth ) const
{
if ( numColumns == 0 || isEmpty() )
return;
bool expandH, expandV;
expandH = expandingDirections() & Qt::Horizontal;
expandV = expandingDirections() & Qt::Vertical;
const QMargins m = contentsMargins();
if ( expandH )
{
int xDelta = rect.width() - m.left() - m.right() - ( numColumns - 1 ) * spacing();
for ( uint col = 0; col < numColumns; col++ )
xDelta -= colWidth[col];
if ( xDelta > 0 )
{
for ( uint col = 0; col < numColumns; col++ )
{
const int space = xDelta / ( numColumns - col );
colWidth[col] += space;
xDelta -= space;
}
}
}
if ( expandV )
{
uint numRows = itemCount() / numColumns;
if ( itemCount() % numColumns )
numRows++;
int yDelta = rect.height() - m.top() - m.bottom() - ( numRows - 1 ) * spacing();
for ( uint row = 0; row < numRows; row++ )
yDelta -= rowHeight[row];
if ( yDelta > 0 )
{
for ( uint row = 0; row < numRows; row++ )
{
const int space = yDelta / ( numRows - row );
rowHeight[row] += space;
yDelta -= space;
}
}
}
}
QSize QwtDynGridLayout::sizeHint() const
{
if ( isEmpty() )
return QSize();
uint numColumns = itemCount();
if ( m_data->maxColumns > 0 )
numColumns = qMin( m_data->maxColumns, numColumns );
uint numRows = itemCount() / numColumns;
if ( itemCount() % numColumns )
numRows++;
QVector< int > rowHeight( numRows );
QVector< int > colWidth( numColumns );
layoutGrid( numColumns, rowHeight, colWidth );
const QMargins m = contentsMargins();
int h = m.top() + m.bottom() + ( numRows - 1 ) * spacing();
for ( uint row = 0; row < numRows; row++ )
h += rowHeight[row];
int w = m.left() + m.right() + ( numColumns - 1 ) * spacing();
for ( uint col = 0; col < numColumns; col++ )
w += colWidth[col];
return QSize( w, h );
}
uint QwtDynGridLayout::numRows() const
{
return m_data->numRows;
}
uint QwtDynGridLayout::numColumns() const
{
return m_data->numColumns;
}
#include "moc_qwt_dyngrid_layout.cpp"
QList
Definition qwt_abstract_legend.h:17
QVector< QSize >
QwtDynGridLayout::layoutGrid
void layoutGrid(uint numColumns, QVector< int > &rowHeight, QVector< int > &colWidth) const
Definition qwt_dyngrid_layout.cpp:419
QwtDynGridLayout::heightForWidth
virtual int heightForWidth(int) const override
Definition qwt_dyngrid_layout.cpp:455
QwtDynGridLayout::itemAt
virtual QLayoutItem * itemAt(int index) const override
Definition qwt_dyngrid_layout.cpp:157
QwtDynGridLayout::columnsForWidth
virtual uint columnsForWidth(int width) const
Calculate the number of columns for a given width.
Definition qwt_dyngrid_layout.cpp:256
QwtDynGridLayout::isEmpty
virtual bool isEmpty() const override
Definition qwt_dyngrid_layout.cpp:137
QwtDynGridLayout::takeAt
virtual QLayoutItem * takeAt(int index) override
Definition qwt_dyngrid_layout.cpp:172
QwtDynGridLayout::maxItemWidth
virtual int maxItemWidth() const
Definition qwt_dyngrid_layout.cpp:316
QwtDynGridLayout::setExpandingDirections
void setExpandingDirections(Qt::Orientations)
Definition qwt_dyngrid_layout.cpp:196
QwtDynGridLayout::sizeHint
virtual QSize sizeHint() const override
Definition qwt_dyngrid_layout.cpp:550
QwtDynGridLayout::expandingDirections
virtual Qt::Orientations expandingDirections() const override
Returns whether this layout can make use of more space than sizeHint().
Definition qwt_dyngrid_layout.cpp:211
QwtDynGridLayout::maxColumns
uint maxColumns() const
Return the upper limit for the number of columns.
Definition qwt_dyngrid_layout.cpp:119
QwtDynGridLayout::stretchGrid
void stretchGrid(const QRect &rect, uint numColumns, QVector< int > &rowHeight, QVector< int > &colWidth) const
Definition qwt_dyngrid_layout.cpp:491
QwtDynGridLayout::numColumns
uint numColumns() const
Definition qwt_dyngrid_layout.cpp:596
QwtDynGridLayout::setMaxColumns
void setMaxColumns(uint maxColumns)
Definition qwt_dyngrid_layout.cpp:106
QwtDynGridLayout::numRows
uint numRows() const
Definition qwt_dyngrid_layout.cpp:586
QwtDynGridLayout::addItem
virtual void addItem(QLayoutItem *) override
Add an item to the next free position.
Definition qwt_dyngrid_layout.cpp:128
QwtDynGridLayout::layoutItems
QList< QRect > layoutItems(const QRect &, uint numColumns) const
Definition qwt_dyngrid_layout.cpp:344
QwtDynGridLayout::setGeometry
virtual void setGeometry(const QRect &) override
Definition qwt_dyngrid_layout.cpp:222
QwtDynGridLayout::~QwtDynGridLayout
virtual ~QwtDynGridLayout()
Destructor.
Definition qwt_dyngrid_layout.cpp:88
QwtDynGridLayout::itemCount
uint itemCount() const
Definition qwt_dyngrid_layout.cpp:145
QwtDynGridLayout::QwtDynGridLayout
QwtDynGridLayout(QWidget *, int margin=0, int spacing=-1)
Definition qwt_dyngrid_layout.cpp:58
QwtDynGridLayout::hasHeightForWidth
virtual bool hasHeightForWidth() const override
Definition qwt_dyngrid_layout.cpp:446
QwtDynGridLayout::count
virtual int count() const override
Definition qwt_dyngrid_layout.cpp:182
QwtDynGridLayout::invalidate
virtual void invalidate() override
Invalidate all internal caches.
Definition qwt_dyngrid_layout.cpp:95