Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "qwt_dyngrid_layout.h"
00011 #include "qwt_math.h"
00012 #include <qvector.h>
00013 #include <qlist.h>
00014
00015 class QwtDynGridLayout::PrivateData
00016 {
00017 public:
00018 PrivateData():
00019 isDirty( true )
00020 {
00021 }
00022
00023 void updateLayoutCache();
00024
00025 mutable QList<QLayoutItem*> itemList;
00026
00027 uint maxColumns;
00028 uint numRows;
00029 uint numColumns;
00030
00031 Qt::Orientations expanding;
00032
00033 bool isDirty;
00034 QVector<QSize> itemSizeHints;
00035 };
00036
00037 void QwtDynGridLayout::PrivateData::updateLayoutCache()
00038 {
00039 itemSizeHints.resize( itemList.count() );
00040
00041 int index = 0;
00042
00043 for ( QList<QLayoutItem*>::const_iterator it = itemList.constBegin();
00044 it != itemList.constEnd(); ++it, index++ )
00045 {
00046 itemSizeHints[ index ] = ( *it )->sizeHint();
00047 }
00048
00049 isDirty = false;
00050 }
00051
00058 QwtDynGridLayout::QwtDynGridLayout( QWidget *parent,
00059 int margin, int spacing ):
00060 QLayout( parent )
00061 {
00062 init();
00063
00064 setSpacing( spacing );
00065 setMargin( margin );
00066 }
00067
00072 QwtDynGridLayout::QwtDynGridLayout( int spacing )
00073 {
00074 init();
00075 setSpacing( spacing );
00076 }
00077
00081 void QwtDynGridLayout::init()
00082 {
00083 d_data = new QwtDynGridLayout::PrivateData;
00084 d_data->maxColumns = d_data->numRows = d_data->numColumns = 0;
00085 d_data->expanding = 0;
00086 }
00087
00089
00090 QwtDynGridLayout::~QwtDynGridLayout()
00091 {
00092 qDeleteAll( d_data->itemList );
00093 delete d_data;
00094 }
00095
00097 void QwtDynGridLayout::invalidate()
00098 {
00099 d_data->isDirty = true;
00100 QLayout::invalidate();
00101 }
00102
00108 void QwtDynGridLayout::setMaxColumns( uint maxColumns )
00109 {
00110 d_data->maxColumns = maxColumns;
00111 }
00112
00121 uint QwtDynGridLayout::maxColumns() const
00122 {
00123 return d_data->maxColumns;
00124 }
00125
00130 void QwtDynGridLayout::addItem( QLayoutItem *item )
00131 {
00132 d_data->itemList.append( item );
00133 invalidate();
00134 }
00135
00139 bool QwtDynGridLayout::isEmpty() const
00140 {
00141 return d_data->itemList.isEmpty();
00142 }
00143
00147 uint QwtDynGridLayout::itemCount() const
00148 {
00149 return d_data->itemList.count();
00150 }
00151
00159 QLayoutItem *QwtDynGridLayout::itemAt( int index ) const
00160 {
00161 if ( index < 0 || index >= d_data->itemList.count() )
00162 return NULL;
00163
00164 return d_data->itemList.at( index );
00165 }
00166
00174 QLayoutItem *QwtDynGridLayout::takeAt( int index )
00175 {
00176 if ( index < 0 || index >= d_data->itemList.count() )
00177 return NULL;
00178
00179 d_data->isDirty = true;
00180 return d_data->itemList.takeAt( index );
00181 }
00182
00184 int QwtDynGridLayout::count() const
00185 {
00186 return d_data->itemList.count();
00187 }
00188
00198 void QwtDynGridLayout::setExpandingDirections( Qt::Orientations expanding )
00199 {
00200 d_data->expanding = expanding;
00201 }
00202
00213 Qt::Orientations QwtDynGridLayout::expandingDirections() const
00214 {
00215 return d_data->expanding;
00216 }
00217
00224 void QwtDynGridLayout::setGeometry( const QRect &rect )
00225 {
00226 QLayout::setGeometry( rect );
00227
00228 if ( isEmpty() )
00229 return;
00230
00231 d_data->numColumns = columnsForWidth( rect.width() );
00232 d_data->numRows = itemCount() / d_data->numColumns;
00233 if ( itemCount() % d_data->numColumns )
00234 d_data->numRows++;
00235
00236 const QList<QRect> itemGeometries = layoutItems( rect, d_data->numColumns );
00237
00238 int index = 0;
00239 for ( QList<QLayoutItem*>::const_iterator it = d_data->itemList.constBegin();
00240 it != d_data->itemList.constEnd(); ++it )
00241 {
00242 ( *it )->setGeometry( itemGeometries[index] );
00243 index++;
00244 }
00245 }
00246
00258 uint QwtDynGridLayout::columnsForWidth( int width ) const
00259 {
00260 if ( isEmpty() )
00261 return 0;
00262
00263 uint maxColumns = itemCount();
00264 if ( d_data->maxColumns > 0 )
00265 maxColumns = qMin( d_data->maxColumns, maxColumns );
00266
00267 if ( maxRowWidth( maxColumns ) <= width )
00268 return maxColumns;
00269
00270 for ( uint numColumns = 2; numColumns <= maxColumns; numColumns++ )
00271 {
00272 const int rowWidth = maxRowWidth( numColumns );
00273 if ( rowWidth > width )
00274 return numColumns - 1;
00275 }
00276
00277 return 1;
00278 }
00279
00287 int QwtDynGridLayout::maxRowWidth( int numColumns ) const
00288 {
00289 int col;
00290
00291 QVector<int> colWidth( numColumns );
00292 for ( col = 0; col < numColumns; col++ )
00293 colWidth[col] = 0;
00294
00295 if ( d_data->isDirty )
00296 d_data->updateLayoutCache();
00297
00298 for ( int index = 0;
00299 index < d_data->itemSizeHints.count(); index++ )
00300 {
00301 col = index % numColumns;
00302 colWidth[col] = qMax( colWidth[col],
00303 d_data->itemSizeHints[int( index )].width() );
00304 }
00305
00306 int rowWidth = 2 * margin() + ( numColumns - 1 ) * spacing();
00307 for ( col = 0; col < numColumns; col++ )
00308 rowWidth += colWidth[col];
00309
00310 return rowWidth;
00311 }
00312
00316 int QwtDynGridLayout::maxItemWidth() const
00317 {
00318 if ( isEmpty() )
00319 return 0;
00320
00321 if ( d_data->isDirty )
00322 d_data->updateLayoutCache();
00323
00324 int w = 0;
00325 for ( int i = 0; i < d_data->itemSizeHints.count(); i++ )
00326 {
00327 const int itemW = d_data->itemSizeHints[i].width();
00328 if ( itemW > w )
00329 w = itemW;
00330 }
00331
00332 return w;
00333 }
00334
00344 QList<QRect> QwtDynGridLayout::layoutItems( const QRect &rect,
00345 uint numColumns ) const
00346 {
00347 QList<QRect> itemGeometries;
00348 if ( numColumns == 0 || isEmpty() )
00349 return itemGeometries;
00350
00351 uint numRows = itemCount() / numColumns;
00352 if ( numColumns % itemCount() )
00353 numRows++;
00354
00355 if ( numRows == 0 )
00356 return itemGeometries;
00357
00358 QVector<int> rowHeight( numRows );
00359 QVector<int> colWidth( numColumns );
00360
00361 layoutGrid( numColumns, rowHeight, colWidth );
00362
00363 bool expandH, expandV;
00364 expandH = expandingDirections() & Qt::Horizontal;
00365 expandV = expandingDirections() & Qt::Vertical;
00366
00367 if ( expandH || expandV )
00368 stretchGrid( rect, numColumns, rowHeight, colWidth );
00369
00370 const int maxColumns = d_data->maxColumns;
00371 d_data->maxColumns = numColumns;
00372 const QRect alignedRect = alignmentRect( rect );
00373 d_data->maxColumns = maxColumns;
00374
00375 const int xOffset = expandH ? 0 : alignedRect.x();
00376 const int yOffset = expandV ? 0 : alignedRect.y();
00377
00378 QVector<int> colX( numColumns );
00379 QVector<int> rowY( numRows );
00380
00381 const int xySpace = spacing();
00382
00383 rowY[0] = yOffset + margin();
00384 for ( uint r = 1; r < numRows; r++ )
00385 rowY[r] = rowY[r-1] + rowHeight[r-1] + xySpace;
00386
00387 colX[0] = xOffset + margin();
00388 for ( uint c = 1; c < numColumns; c++ )
00389 colX[c] = colX[c-1] + colWidth[c-1] + xySpace;
00390
00391 const int itemCount = d_data->itemList.size();
00392 #if QT_VERSION >= 0x040700
00393 itemGeometries.reserve( itemCount );
00394 #endif
00395
00396 for ( int i = 0; i < itemCount; i++ )
00397 {
00398 const int row = i / numColumns;
00399 const int col = i % numColumns;
00400
00401 const QRect itemGeometry( colX[col], rowY[row],
00402 colWidth[col], rowHeight[row] );
00403 itemGeometries.append( itemGeometry );
00404 }
00405
00406 return itemGeometries;
00407 }
00408
00409
00419 void QwtDynGridLayout::layoutGrid( uint numColumns,
00420 QVector<int>& rowHeight, QVector<int>& colWidth ) const
00421 {
00422 if ( numColumns <= 0 )
00423 return;
00424
00425 if ( d_data->isDirty )
00426 d_data->updateLayoutCache();
00427
00428 for ( int index = 0; index < d_data->itemSizeHints.count(); index++ )
00429 {
00430 const int row = index / numColumns;
00431 const int col = index % numColumns;
00432
00433 const QSize &size = d_data->itemSizeHints[int( index )];
00434
00435 rowHeight[row] = ( col == 0 )
00436 ? size.height() : qMax( rowHeight[row], size.height() );
00437 colWidth[col] = ( row == 0 )
00438 ? size.width() : qMax( colWidth[col], size.width() );
00439 }
00440 }
00441
00446 bool QwtDynGridLayout::hasHeightForWidth() const
00447 {
00448 return true;
00449 }
00450
00455 int QwtDynGridLayout::heightForWidth( int width ) const
00456 {
00457 if ( isEmpty() )
00458 return 0;
00459
00460 const uint numColumns = columnsForWidth( width );
00461 uint numRows = itemCount() / numColumns;
00462 if ( itemCount() % numColumns )
00463 numRows++;
00464
00465 QVector<int> rowHeight( numRows );
00466 QVector<int> colWidth( numColumns );
00467
00468 layoutGrid( numColumns, rowHeight, colWidth );
00469
00470 int h = 2 * margin() + ( numRows - 1 ) * spacing();
00471 for ( uint row = 0; row < numRows; row++ )
00472 h += rowHeight[row];
00473
00474 return h;
00475 }
00476
00489 void QwtDynGridLayout::stretchGrid( const QRect &rect,
00490 uint numColumns, QVector<int>& rowHeight, QVector<int>& colWidth ) const
00491 {
00492 if ( numColumns == 0 || isEmpty() )
00493 return;
00494
00495 bool expandH, expandV;
00496 expandH = expandingDirections() & Qt::Horizontal;
00497 expandV = expandingDirections() & Qt::Vertical;
00498
00499 if ( expandH )
00500 {
00501 int xDelta = rect.width() - 2 * margin() - ( numColumns - 1 ) * spacing();
00502 for ( uint col = 0; col < numColumns; col++ )
00503 xDelta -= colWidth[col];
00504
00505 if ( xDelta > 0 )
00506 {
00507 for ( uint col = 0; col < numColumns; col++ )
00508 {
00509 const int space = xDelta / ( numColumns - col );
00510 colWidth[col] += space;
00511 xDelta -= space;
00512 }
00513 }
00514 }
00515
00516 if ( expandV )
00517 {
00518 uint numRows = itemCount() / numColumns;
00519 if ( itemCount() % numColumns )
00520 numRows++;
00521
00522 int yDelta = rect.height() - 2 * margin() - ( numRows - 1 ) * spacing();
00523 for ( uint row = 0; row < numRows; row++ )
00524 yDelta -= rowHeight[row];
00525
00526 if ( yDelta > 0 )
00527 {
00528 for ( uint row = 0; row < numRows; row++ )
00529 {
00530 const int space = yDelta / ( numRows - row );
00531 rowHeight[row] += space;
00532 yDelta -= space;
00533 }
00534 }
00535 }
00536 }
00537
00546 QSize QwtDynGridLayout::sizeHint() const
00547 {
00548 if ( isEmpty() )
00549 return QSize();
00550
00551 uint numColumns = itemCount();
00552 if ( d_data->maxColumns > 0 )
00553 numColumns = qMin( d_data->maxColumns, numColumns );
00554
00555 uint numRows = itemCount() / numColumns;
00556 if ( itemCount() % numColumns )
00557 numRows++;
00558
00559 QVector<int> rowHeight( numRows );
00560 QVector<int> colWidth( numColumns );
00561
00562 layoutGrid( numColumns, rowHeight, colWidth );
00563
00564 int h = 2 * margin() + ( numRows - 1 ) * spacing();
00565 for ( uint row = 0; row < numRows; row++ )
00566 h += rowHeight[row];
00567
00568 int w = 2 * margin() + ( numColumns - 1 ) * spacing();
00569 for ( uint col = 0; col < numColumns; col++ )
00570 w += colWidth[col];
00571
00572 return QSize( w, h );
00573 }
00574
00580 uint QwtDynGridLayout::numRows() const
00581 {
00582 return d_data->numRows;
00583 }
00584
00590 uint QwtDynGridLayout::numColumns() const
00591 {
00592 return d_data->numColumns;
00593 }