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*>::iterator it = itemList.begin();
00044 it != itemList.end(); ++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 for ( int i = 0; i < d_data->itemList.size(); i++ )
00093 delete d_data->itemList[i];
00094
00095 delete d_data;
00096 }
00097
00099 void QwtDynGridLayout::invalidate()
00100 {
00101 d_data->isDirty = true;
00102 QLayout::invalidate();
00103 }
00104
00110 void QwtDynGridLayout::setMaxColumns( uint maxColumns )
00111 {
00112 d_data->maxColumns = maxColumns;
00113 }
00114
00123 uint QwtDynGridLayout::maxColumns() const
00124 {
00125 return d_data->maxColumns;
00126 }
00127
00132 void QwtDynGridLayout::addItem( QLayoutItem *item )
00133 {
00134 d_data->itemList.append( item );
00135 invalidate();
00136 }
00137
00141 bool QwtDynGridLayout::isEmpty() const
00142 {
00143 return d_data->itemList.isEmpty();
00144 }
00145
00149 uint QwtDynGridLayout::itemCount() const
00150 {
00151 return d_data->itemList.count();
00152 }
00153
00161 QLayoutItem *QwtDynGridLayout::itemAt( int index ) const
00162 {
00163 if ( index < 0 || index >= d_data->itemList.count() )
00164 return NULL;
00165
00166 return d_data->itemList.at( index );
00167 }
00168
00176 QLayoutItem *QwtDynGridLayout::takeAt( int index )
00177 {
00178 if ( index < 0 || index >= d_data->itemList.count() )
00179 return NULL;
00180
00181 d_data->isDirty = true;
00182 return d_data->itemList.takeAt( index );
00183 }
00184
00186 int QwtDynGridLayout::count() const
00187 {
00188 return d_data->itemList.count();
00189 }
00190
00200 void QwtDynGridLayout::setExpandingDirections( Qt::Orientations expanding )
00201 {
00202 d_data->expanding = expanding;
00203 }
00204
00215 Qt::Orientations QwtDynGridLayout::expandingDirections() const
00216 {
00217 return d_data->expanding;
00218 }
00219
00226 void QwtDynGridLayout::setGeometry( const QRect &rect )
00227 {
00228 QLayout::setGeometry( rect );
00229
00230 if ( isEmpty() )
00231 return;
00232
00233 d_data->numColumns = columnsForWidth( rect.width() );
00234 d_data->numRows = itemCount() / d_data->numColumns;
00235 if ( itemCount() % d_data->numColumns )
00236 d_data->numRows++;
00237
00238 QList<QRect> itemGeometries = layoutItems( rect, d_data->numColumns );
00239
00240 int index = 0;
00241 for ( QList<QLayoutItem*>::iterator it = d_data->itemList.begin();
00242 it != d_data->itemList.end(); ++it )
00243 {
00244 ( *it )->setGeometry( itemGeometries[index] );
00245 index++;
00246 }
00247 }
00248
00260 uint QwtDynGridLayout::columnsForWidth( int width ) const
00261 {
00262 if ( isEmpty() )
00263 return 0;
00264
00265 uint maxColumns = itemCount();
00266 if ( d_data->maxColumns > 0 )
00267 maxColumns = qMin( d_data->maxColumns, maxColumns );
00268
00269 if ( maxRowWidth( maxColumns ) <= width )
00270 return maxColumns;
00271
00272 for ( uint numColumns = 2; numColumns <= maxColumns; numColumns++ )
00273 {
00274 const int rowWidth = maxRowWidth( numColumns );
00275 if ( rowWidth > width )
00276 return numColumns - 1;
00277 }
00278
00279 return 1;
00280 }
00281
00289 int QwtDynGridLayout::maxRowWidth( int numColumns ) const
00290 {
00291 int col;
00292
00293 QVector<int> colWidth( numColumns );
00294 for ( col = 0; col < numColumns; col++ )
00295 colWidth[col] = 0;
00296
00297 if ( d_data->isDirty )
00298 d_data->updateLayoutCache();
00299
00300 for ( int index = 0;
00301 index < d_data->itemSizeHints.count(); index++ )
00302 {
00303 col = index % numColumns;
00304 colWidth[col] = qMax( colWidth[col],
00305 d_data->itemSizeHints[int( index )].width() );
00306 }
00307
00308 int rowWidth = 2 * margin() + ( numColumns - 1 ) * spacing();
00309 for ( col = 0; col < numColumns; col++ )
00310 rowWidth += colWidth[col];
00311
00312 return rowWidth;
00313 }
00314
00318 int QwtDynGridLayout::maxItemWidth() const
00319 {
00320 if ( isEmpty() )
00321 return 0;
00322
00323 if ( d_data->isDirty )
00324 d_data->updateLayoutCache();
00325
00326 int w = 0;
00327 for ( int i = 0; i < d_data->itemSizeHints.count(); i++ )
00328 {
00329 const int itemW = d_data->itemSizeHints[i].width();
00330 if ( itemW > w )
00331 w = itemW;
00332 }
00333
00334 return w;
00335 }
00336
00346 QList<QRect> QwtDynGridLayout::layoutItems( const QRect &rect,
00347 uint numColumns ) const
00348 {
00349 QList<QRect> itemGeometries;
00350 if ( numColumns == 0 || isEmpty() )
00351 return itemGeometries;
00352
00353 uint numRows = itemCount() / numColumns;
00354 if ( numColumns % itemCount() )
00355 numRows++;
00356
00357 if ( numRows == 0 )
00358 return itemGeometries;
00359
00360 QVector<int> rowHeight( numRows );
00361 QVector<int> colWidth( numColumns );
00362
00363 layoutGrid( numColumns, rowHeight, colWidth );
00364
00365 bool expandH, expandV;
00366 expandH = expandingDirections() & Qt::Horizontal;
00367 expandV = expandingDirections() & Qt::Vertical;
00368
00369 if ( expandH || expandV )
00370 stretchGrid( rect, numColumns, rowHeight, colWidth );
00371
00372 const int maxColumns = d_data->maxColumns;
00373 d_data->maxColumns = numColumns;
00374 const QRect alignedRect = alignmentRect( rect );
00375 d_data->maxColumns = maxColumns;
00376
00377 const int xOffset = expandH ? 0 : alignedRect.x();
00378 const int yOffset = expandV ? 0 : alignedRect.y();
00379
00380 QVector<int> colX( numColumns );
00381 QVector<int> rowY( numRows );
00382
00383 const int xySpace = spacing();
00384
00385 rowY[0] = yOffset + margin();
00386 for ( uint r = 1; r < numRows; r++ )
00387 rowY[r] = rowY[r-1] + rowHeight[r-1] + xySpace;
00388
00389 colX[0] = xOffset + margin();
00390 for ( uint c = 1; c < numColumns; c++ )
00391 colX[c] = colX[c-1] + colWidth[c-1] + xySpace;
00392
00393 const int itemCount = d_data->itemList.size();
00394 for ( int i = 0; i < itemCount; i++ )
00395 {
00396 const int row = i / numColumns;
00397 const int col = i % numColumns;
00398
00399 QRect itemGeometry( colX[col], rowY[row],
00400 colWidth[col], rowHeight[row] );
00401 itemGeometries.append( itemGeometry );
00402 }
00403
00404 return itemGeometries;
00405 }
00406
00407
00417 void QwtDynGridLayout::layoutGrid( uint numColumns,
00418 QVector<int>& rowHeight, QVector<int>& colWidth ) const
00419 {
00420 if ( numColumns <= 0 )
00421 return;
00422
00423 if ( d_data->isDirty )
00424 d_data->updateLayoutCache();
00425
00426 for ( int index = 0; index < d_data->itemSizeHints.count(); index++ )
00427 {
00428 const int row = index / numColumns;
00429 const int col = index % numColumns;
00430
00431 const QSize &size = d_data->itemSizeHints[int( index )];
00432
00433 rowHeight[row] = ( col == 0 )
00434 ? size.height() : qMax( rowHeight[row], size.height() );
00435 colWidth[col] = ( row == 0 )
00436 ? size.width() : qMax( colWidth[col], size.width() );
00437 }
00438 }
00439
00444 bool QwtDynGridLayout::hasHeightForWidth() const
00445 {
00446 return true;
00447 }
00448
00453 int QwtDynGridLayout::heightForWidth( int width ) const
00454 {
00455 if ( isEmpty() )
00456 return 0;
00457
00458 const uint numColumns = columnsForWidth( width );
00459 uint numRows = itemCount() / numColumns;
00460 if ( itemCount() % numColumns )
00461 numRows++;
00462
00463 QVector<int> rowHeight( numRows );
00464 QVector<int> colWidth( numColumns );
00465
00466 layoutGrid( numColumns, rowHeight, colWidth );
00467
00468 int h = 2 * margin() + ( numRows - 1 ) * spacing();
00469 for ( uint row = 0; row < numRows; row++ )
00470 h += rowHeight[row];
00471
00472 return h;
00473 }
00474
00487 void QwtDynGridLayout::stretchGrid( const QRect &rect,
00488 uint numColumns, QVector<int>& rowHeight, QVector<int>& colWidth ) const
00489 {
00490 if ( numColumns == 0 || isEmpty() )
00491 return;
00492
00493 bool expandH, expandV;
00494 expandH = expandingDirections() & Qt::Horizontal;
00495 expandV = expandingDirections() & Qt::Vertical;
00496
00497 if ( expandH )
00498 {
00499 int xDelta = rect.width() - 2 * margin() - ( numColumns - 1 ) * spacing();
00500 for ( uint col = 0; col < numColumns; col++ )
00501 xDelta -= colWidth[col];
00502
00503 if ( xDelta > 0 )
00504 {
00505 for ( uint col = 0; col < numColumns; col++ )
00506 {
00507 const int space = xDelta / ( numColumns - col );
00508 colWidth[col] += space;
00509 xDelta -= space;
00510 }
00511 }
00512 }
00513
00514 if ( expandV )
00515 {
00516 uint numRows = itemCount() / numColumns;
00517 if ( itemCount() % numColumns )
00518 numRows++;
00519
00520 int yDelta = rect.height() - 2 * margin() - ( numRows - 1 ) * spacing();
00521 for ( uint row = 0; row < numRows; row++ )
00522 yDelta -= rowHeight[row];
00523
00524 if ( yDelta > 0 )
00525 {
00526 for ( uint row = 0; row < numRows; row++ )
00527 {
00528 const int space = yDelta / ( numRows - row );
00529 rowHeight[row] += space;
00530 yDelta -= space;
00531 }
00532 }
00533 }
00534 }
00535
00544 QSize QwtDynGridLayout::sizeHint() const
00545 {
00546 if ( isEmpty() )
00547 return QSize();
00548
00549 uint numColumns = itemCount();
00550 if ( d_data->maxColumns > 0 )
00551 numColumns = qMin( d_data->maxColumns, numColumns );
00552
00553 uint numRows = itemCount() / numColumns;
00554 if ( itemCount() % numColumns )
00555 numRows++;
00556
00557 QVector<int> rowHeight( numRows );
00558 QVector<int> colWidth( numColumns );
00559
00560 layoutGrid( numColumns, rowHeight, colWidth );
00561
00562 int h = 2 * margin() + ( numRows - 1 ) * spacing();
00563 for ( uint row = 0; row < numRows; row++ )
00564 h += rowHeight[row];
00565
00566 int w = 2 * margin() + ( numColumns - 1 ) * spacing();
00567 for ( uint col = 0; col < numColumns; col++ )
00568 w += colWidth[col];
00569
00570 return QSize( w, h );
00571 }
00572
00578 uint QwtDynGridLayout::numRows() const
00579 {
00580 return d_data->numRows;
00581 }
00582
00588 uint QwtDynGridLayout::numColumns() const
00589 {
00590 return d_data->numColumns;
00591 }