Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <qwidget.h>
00011 #include "qwt_dyngrid_layout.h"
00012 #include "qwt_math.h"
00013
00014 #if QT_VERSION < 0x040000
00015 #include <qvaluelist.h>
00016 #else
00017 #include <qlist.h>
00018 #endif
00019
00020 class QwtDynGridLayout::PrivateData
00021 {
00022 public:
00023
00024 #if QT_VERSION < 0x040000
00025 class LayoutIterator: public QGLayoutIterator
00026 {
00027 public:
00028 LayoutIterator(PrivateData *data):
00029 d_data(data)
00030 {
00031 d_iterator = d_data->itemList.begin();
00032 }
00033
00034 virtual QLayoutItem *current()
00035 {
00036 if (d_iterator == d_data->itemList.end())
00037 return NULL;
00038
00039 return *d_iterator;
00040 }
00041
00042 virtual QLayoutItem *next()
00043 {
00044 if (d_iterator == d_data->itemList.end())
00045 return NULL;
00046
00047 d_iterator++;
00048 if (d_iterator == d_data->itemList.end())
00049 return NULL;
00050
00051 return *d_iterator;
00052 }
00053
00054 virtual QLayoutItem *takeCurrent()
00055 {
00056 if ( d_iterator == d_data->itemList.end() )
00057 return NULL;
00058
00059 QLayoutItem *item = *d_iterator;
00060
00061 d_data->isDirty = true;
00062 d_iterator = d_data->itemList.remove(d_iterator);
00063 return item;
00064 }
00065
00066 private:
00067
00068 QValueListIterator<QLayoutItem*> d_iterator;
00069 QwtDynGridLayout::PrivateData *d_data;
00070 };
00071 #endif
00072
00073 PrivateData():
00074 isDirty(true)
00075 {
00076 }
00077
00078 #if QT_VERSION < 0x040000
00079 typedef QValueList<QLayoutItem*> LayoutItemList;
00080 #else
00081 typedef QList<QLayoutItem*> LayoutItemList;
00082 #endif
00083
00084 mutable LayoutItemList itemList;
00085
00086 uint maxCols;
00087 uint numRows;
00088 uint numCols;
00089
00090 #if QT_VERSION < 0x040000
00091 QSizePolicy::ExpandData expanding;
00092 #else
00093 Qt::Orientations expanding;
00094 #endif
00095
00096 bool isDirty;
00097 QwtArray<QSize> itemSizeHints;
00098 };
00099
00100
00107 QwtDynGridLayout::QwtDynGridLayout(QWidget *parent,
00108 int margin, int spacing):
00109 QLayout(parent)
00110 {
00111 init();
00112
00113 setSpacing(spacing);
00114 setMargin(margin);
00115 }
00116
00117 #if QT_VERSION < 0x040000
00118
00122 QwtDynGridLayout::QwtDynGridLayout(QLayout *parent, int spacing):
00123 QLayout(parent, spacing)
00124 {
00125 init();
00126 }
00127 #endif
00128
00133 QwtDynGridLayout::QwtDynGridLayout(int spacing)
00134 {
00135 init();
00136 setSpacing(spacing);
00137 }
00138
00142 void QwtDynGridLayout::init()
00143 {
00144 d_data = new QwtDynGridLayout::PrivateData;
00145 d_data->maxCols = d_data->numRows
00146 = d_data->numCols = 0;
00147
00148 #if QT_VERSION < 0x040000
00149 d_data->expanding = QSizePolicy::NoDirection;
00150 setSupportsMargin(true);
00151 #else
00152 d_data->expanding = 0;
00153 #endif
00154 }
00155
00157
00158 QwtDynGridLayout::~QwtDynGridLayout()
00159 {
00160 #if QT_VERSION < 0x040000
00161 deleteAllItems();
00162 #endif
00163
00164 delete d_data;
00165 }
00166
00168 void QwtDynGridLayout::invalidate()
00169 {
00170 d_data->isDirty = true;
00171 QLayout::invalidate();
00172 }
00173
00174 void QwtDynGridLayout::updateLayoutCache()
00175 {
00176 d_data->itemSizeHints.resize(itemCount());
00177
00178 int index = 0;
00179
00180 for (PrivateData::LayoutItemList::iterator it = d_data->itemList.begin();
00181 it != d_data->itemList.end(); ++it, index++)
00182 {
00183 d_data->itemSizeHints[int(index)] = (*it)->sizeHint();
00184 }
00185
00186 d_data->isDirty = false;
00187 }
00188
00195 void QwtDynGridLayout::setMaxCols(uint maxCols)
00196 {
00197 d_data->maxCols = maxCols;
00198 }
00199
00206 uint QwtDynGridLayout::maxCols() const
00207 {
00208 return d_data->maxCols;
00209 }
00210
00212
00213 void QwtDynGridLayout::addItem(QLayoutItem *item)
00214 {
00215 d_data->itemList.append(item);
00216 invalidate();
00217 }
00218
00223 bool QwtDynGridLayout::isEmpty() const
00224 {
00225 return d_data->itemList.isEmpty();
00226 }
00227
00232 uint QwtDynGridLayout::itemCount() const
00233 {
00234 return d_data->itemList.count();
00235 }
00236
00237 #if QT_VERSION < 0x040000
00238
00242 QLayoutIterator QwtDynGridLayout::iterator()
00243 {
00244 return QLayoutIterator(
00245 new QwtDynGridLayout::PrivateData::LayoutIterator(d_data) );
00246 }
00247
00248 void QwtDynGridLayout::setExpanding(QSizePolicy::ExpandData expanding)
00249 {
00250 d_data->expanding = expanding;
00251 }
00252
00253 QSizePolicy::ExpandData QwtDynGridLayout::expanding() const
00254 {
00255 return d_data->expanding;
00256 }
00257
00258 #else // QT_VERSION >= 0x040000
00259
00266 QLayoutItem *QwtDynGridLayout::itemAt( int index ) const
00267 {
00268 if ( index < 0 || index >= d_data->itemList.count() )
00269 return NULL;
00270
00271 return d_data->itemList.at(index);
00272 }
00273
00280 QLayoutItem *QwtDynGridLayout::takeAt( int index )
00281 {
00282 if ( index < 0 || index >= d_data->itemList.count() )
00283 return NULL;
00284
00285 d_data->isDirty = true;
00286 return d_data->itemList.takeAt(index);
00287 }
00288
00290 int QwtDynGridLayout::count() const
00291 {
00292 return d_data->itemList.count();
00293 }
00294
00304 void QwtDynGridLayout::setExpandingDirections(Qt::Orientations expanding)
00305 {
00306 d_data->expanding = expanding;
00307 }
00308
00316 Qt::Orientations QwtDynGridLayout::expandingDirections() const
00317 {
00318 return d_data->expanding;
00319 }
00320
00321 #endif
00322
00329 void QwtDynGridLayout::setGeometry(const QRect &rect)
00330 {
00331 QLayout::setGeometry(rect);
00332
00333 if ( isEmpty() )
00334 return;
00335
00336 d_data->numCols = columnsForWidth(rect.width());
00337 d_data->numRows = itemCount() / d_data->numCols;
00338 if ( itemCount() % d_data->numCols )
00339 d_data->numRows++;
00340
00341 #if QT_VERSION < 0x040000
00342 QValueList<QRect> itemGeometries = layoutItems(rect, d_data->numCols);
00343 #else
00344 QList<QRect> itemGeometries = layoutItems(rect, d_data->numCols);
00345 #endif
00346
00347 int index = 0;
00348 for (PrivateData::LayoutItemList::iterator it = d_data->itemList.begin();
00349 it != d_data->itemList.end(); ++it)
00350 {
00351 QWidget *w = (*it)->widget();
00352 if ( w )
00353 {
00354 w->setGeometry(itemGeometries[index]);
00355 index++;
00356 }
00357 }
00358 }
00359
00368 uint QwtDynGridLayout::columnsForWidth(int width) const
00369 {
00370 if ( isEmpty() )
00371 return 0;
00372
00373 const int maxCols = (d_data->maxCols > 0) ? d_data->maxCols : itemCount();
00374 if ( maxRowWidth(maxCols) <= width )
00375 return maxCols;
00376
00377 for (int numCols = 2; numCols <= maxCols; numCols++ )
00378 {
00379 const int rowWidth = maxRowWidth(numCols);
00380 if ( rowWidth > width )
00381 return numCols - 1;
00382 }
00383
00384 return 1;
00385 }
00386
00394 int QwtDynGridLayout::maxRowWidth(int numCols) const
00395 {
00396 int col;
00397
00398 QwtArray<int> colWidth(numCols);
00399 for ( col = 0; col < (int)numCols; col++ )
00400 colWidth[col] = 0;
00401
00402 if ( d_data->isDirty )
00403 ((QwtDynGridLayout*)this)->updateLayoutCache();
00404
00405 for ( uint index = 0;
00406 index < (uint)d_data->itemSizeHints.count(); index++ )
00407 {
00408 col = index % numCols;
00409 colWidth[col] = qwtMax(colWidth[col],
00410 d_data->itemSizeHints[int(index)].width());
00411 }
00412
00413 int rowWidth = 2 * margin() + (numCols - 1) * spacing();
00414 for ( col = 0; col < (int)numCols; col++ )
00415 rowWidth += colWidth[col];
00416
00417 return rowWidth;
00418 }
00419
00423 int QwtDynGridLayout::maxItemWidth() const
00424 {
00425 if ( isEmpty() )
00426 return 0;
00427
00428 if ( d_data->isDirty )
00429 ((QwtDynGridLayout*)this)->updateLayoutCache();
00430
00431 int w = 0;
00432 for ( uint i = 0; i < (uint)d_data->itemSizeHints.count(); i++ )
00433 {
00434 const int itemW = d_data->itemSizeHints[int(i)].width();
00435 if ( itemW > w )
00436 w = itemW;
00437 }
00438
00439 return w;
00440 }
00441
00451 #if QT_VERSION < 0x040000
00452 QValueList<QRect> QwtDynGridLayout::layoutItems(const QRect &rect,
00453 uint numCols) const
00454 #else
00455 QList<QRect> QwtDynGridLayout::layoutItems(const QRect &rect,
00456 uint numCols) const
00457 #endif
00458 {
00459 #if QT_VERSION < 0x040000
00460 QValueList<QRect> itemGeometries;
00461 #else
00462 QList<QRect> itemGeometries;
00463 #endif
00464 if ( numCols == 0 || isEmpty() )
00465 return itemGeometries;
00466
00467 uint numRows = itemCount() / numCols;
00468 if ( numRows % itemCount() )
00469 numRows++;
00470
00471 QwtArray<int> rowHeight(numRows);
00472 QwtArray<int> colWidth(numCols);
00473
00474 layoutGrid(numCols, rowHeight, colWidth);
00475
00476 bool expandH, expandV;
00477 #if QT_VERSION >= 0x040000
00478 expandH = expandingDirections() & Qt::Horizontal;
00479 expandV = expandingDirections() & Qt::Vertical;
00480 #else
00481 expandH = expanding() & QSizePolicy::Horizontally;
00482 expandV = expanding() & QSizePolicy::Vertically;
00483 #endif
00484
00485 if ( expandH || expandV )
00486 stretchGrid(rect, numCols, rowHeight, colWidth);
00487
00488 QwtDynGridLayout *that = (QwtDynGridLayout *)this;
00489 const int maxCols = d_data->maxCols;
00490 that->d_data->maxCols = numCols;
00491 const QRect alignedRect = alignmentRect(rect);
00492 that->d_data->maxCols = maxCols;
00493
00494 const int xOffset = expandH ? 0 : alignedRect.x();
00495 const int yOffset = expandV ? 0 : alignedRect.y();
00496
00497 QwtArray<int> colX(numCols);
00498 QwtArray<int> rowY(numRows);
00499
00500 const int xySpace = spacing();
00501
00502 rowY[0] = yOffset + margin();
00503 for ( int r = 1; r < (int)numRows; r++ )
00504 rowY[r] = rowY[r-1] + rowHeight[r-1] + xySpace;
00505
00506 colX[0] = xOffset + margin();
00507 for ( int c = 1; c < (int)numCols; c++ )
00508 colX[c] = colX[c-1] + colWidth[c-1] + xySpace;
00509
00510 const int itemCount = d_data->itemList.size();
00511 for ( int i = 0; i < itemCount; i++ )
00512 {
00513 const int row = i / numCols;
00514 const int col = i % numCols;
00515
00516 QRect itemGeometry(colX[col], rowY[row],
00517 colWidth[col], rowHeight[row]);
00518 itemGeometries.append(itemGeometry);
00519 }
00520
00521 return itemGeometries;
00522 }
00523
00524
00534 void QwtDynGridLayout::layoutGrid(uint numCols,
00535 QwtArray<int>& rowHeight, QwtArray<int>& colWidth) const
00536 {
00537 if ( numCols <= 0 )
00538 return;
00539
00540 if ( d_data->isDirty )
00541 ((QwtDynGridLayout*)this)->updateLayoutCache();
00542
00543 for ( uint index = 0;
00544 index < (uint)d_data->itemSizeHints.count(); index++ )
00545 {
00546 const int row = index / numCols;
00547 const int col = index % numCols;
00548
00549 const QSize &size = d_data->itemSizeHints[int(index)];
00550
00551 rowHeight[row] = (col == 0)
00552 ? size.height() : qwtMax(rowHeight[row], size.height());
00553 colWidth[col] = (row == 0)
00554 ? size.width() : qwtMax(colWidth[col], size.width());
00555 }
00556 }
00557
00562 bool QwtDynGridLayout::hasHeightForWidth() const
00563 {
00564 return true;
00565 }
00566
00571 int QwtDynGridLayout::heightForWidth(int width) const
00572 {
00573 if ( isEmpty() )
00574 return 0;
00575
00576 const uint numCols = columnsForWidth(width);
00577 uint numRows = itemCount() / numCols;
00578 if ( itemCount() % numCols )
00579 numRows++;
00580
00581 QwtArray<int> rowHeight(numRows);
00582 QwtArray<int> colWidth(numCols);
00583
00584 layoutGrid(numCols, rowHeight, colWidth);
00585
00586 int h = 2 * margin() + (numRows - 1) * spacing();
00587 for ( int row = 0; row < (int)numRows; row++ )
00588 h += rowHeight[row];
00589
00590 return h;
00591 }
00592
00600 void QwtDynGridLayout::stretchGrid(const QRect &rect,
00601 uint numCols, QwtArray<int>& rowHeight, QwtArray<int>& colWidth) const
00602 {
00603 if ( numCols == 0 || isEmpty() )
00604 return;
00605
00606 bool expandH, expandV;
00607 #if QT_VERSION >= 0x040000
00608 expandH = expandingDirections() & Qt::Horizontal;
00609 expandV = expandingDirections() & Qt::Vertical;
00610 #else
00611 expandH = expanding() & QSizePolicy::Horizontally;
00612 expandV = expanding() & QSizePolicy::Vertically;
00613 #endif
00614
00615 if ( expandH )
00616 {
00617 int xDelta = rect.width() - 2 * margin() - (numCols - 1) * spacing();
00618 for ( int col = 0; col < (int)numCols; col++ )
00619 xDelta -= colWidth[col];
00620
00621 if ( xDelta > 0 )
00622 {
00623 for ( int col = 0; col < (int)numCols; col++ )
00624 {
00625 const int space = xDelta / (numCols - col);
00626 colWidth[col] += space;
00627 xDelta -= space;
00628 }
00629 }
00630 }
00631
00632 if ( expandV )
00633 {
00634 uint numRows = itemCount() / numCols;
00635 if ( itemCount() % numCols )
00636 numRows++;
00637
00638 int yDelta = rect.height() - 2 * margin() - (numRows - 1) * spacing();
00639 for ( int row = 0; row < (int)numRows; row++ )
00640 yDelta -= rowHeight[row];
00641
00642 if ( yDelta > 0 )
00643 {
00644 for ( int row = 0; row < (int)numRows; row++ )
00645 {
00646 const int space = yDelta / (numRows - row);
00647 rowHeight[row] += space;
00648 yDelta -= space;
00649 }
00650 }
00651 }
00652 }
00653
00661 QSize QwtDynGridLayout::sizeHint() const
00662 {
00663 if ( isEmpty() )
00664 return QSize();
00665
00666 const uint numCols = (d_data->maxCols > 0 ) ? d_data->maxCols : itemCount();
00667 uint numRows = itemCount() / numCols;
00668 if ( itemCount() % numCols )
00669 numRows++;
00670
00671 QwtArray<int> rowHeight(numRows);
00672 QwtArray<int> colWidth(numCols);
00673
00674 layoutGrid(numCols, rowHeight, colWidth);
00675
00676 int h = 2 * margin() + (numRows - 1) * spacing();
00677 for ( int row = 0; row < (int)numRows; row++ )
00678 h += rowHeight[row];
00679
00680 int w = 2 * margin() + (numCols - 1) * spacing();
00681 for ( int col = 0; col < (int)numCols; col++ )
00682 w += colWidth[col];
00683
00684 return QSize(w, h);
00685 }
00686
00692 uint QwtDynGridLayout::numRows() const
00693 {
00694 return d_data->numRows;
00695 }
00696
00702 uint QwtDynGridLayout::numCols() const
00703 {
00704 return d_data->numCols;
00705 }