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
00167 void QwtDynGridLayout::invalidate()
00168 {
00169 d_data->isDirty = true;
00170 QLayout::invalidate();
00171 }
00172
00173 void QwtDynGridLayout::updateLayoutCache()
00174 {
00175 d_data->itemSizeHints.resize(itemCount());
00176
00177 int index = 0;
00178
00179 for (PrivateData::LayoutItemList::iterator it = d_data->itemList.begin();
00180 it != d_data->itemList.end(); ++it, index++)
00181 {
00182 d_data->itemSizeHints[int(index)] = (*it)->sizeHint();
00183 }
00184
00185 d_data->isDirty = false;
00186 }
00187
00194 void QwtDynGridLayout::setMaxCols(uint maxCols)
00195 {
00196 d_data->maxCols = maxCols;
00197 }
00198
00205 uint QwtDynGridLayout::maxCols() const
00206 {
00207 return d_data->maxCols;
00208 }
00209
00211
00212 void QwtDynGridLayout::addItem(QLayoutItem *item)
00213 {
00214 d_data->itemList.append(item);
00215 invalidate();
00216 }
00217
00222 bool QwtDynGridLayout::isEmpty() const
00223 {
00224 return d_data->itemList.isEmpty();
00225 }
00226
00231 uint QwtDynGridLayout::itemCount() const
00232 {
00233 return d_data->itemList.count();
00234 }
00235
00236 #if QT_VERSION < 0x040000
00237
00241 QLayoutIterator QwtDynGridLayout::iterator()
00242 {
00243 return QLayoutIterator(
00244 new QwtDynGridLayout::PrivateData::LayoutIterator(d_data) );
00245 }
00246
00255 void QwtDynGridLayout::setExpanding(QSizePolicy::ExpandData expanding)
00256 {
00257 d_data->expanding = expanding;
00258 }
00259
00268 QSizePolicy::ExpandData QwtDynGridLayout::expanding() const
00269 {
00270 return d_data->expanding;
00271 }
00272
00273 #else // QT_VERSION >= 0x040000
00274
00275 QLayoutItem *QwtDynGridLayout::itemAt( int index ) const
00276 {
00277 if ( index < 0 || index >= d_data->itemList.count() )
00278 return NULL;
00279
00280 return d_data->itemList.at(index);
00281 }
00282
00283 QLayoutItem *QwtDynGridLayout::takeAt( int index )
00284 {
00285 if ( index < 0 || index >= d_data->itemList.count() )
00286 return NULL;
00287
00288 d_data->isDirty = true;
00289 return d_data->itemList.takeAt(index);
00290 }
00291
00292 int QwtDynGridLayout::count() const
00293 {
00294 return d_data->itemList.count();
00295 }
00296
00297 void QwtDynGridLayout::setExpandingDirections(Qt::Orientations expanding)
00298 {
00299 d_data->expanding = expanding;
00300 }
00301
00302 Qt::Orientations QwtDynGridLayout::expandingDirections() const
00303 {
00304 return d_data->expanding;
00305 }
00306
00307 #endif
00308
00314 void QwtDynGridLayout::setGeometry(const QRect &rect)
00315 {
00316 QLayout::setGeometry(rect);
00317
00318 if ( isEmpty() )
00319 return;
00320
00321 d_data->numCols = columnsForWidth(rect.width());
00322 d_data->numRows = itemCount() / d_data->numCols;
00323 if ( itemCount() % d_data->numCols )
00324 d_data->numRows++;
00325
00326 #if QT_VERSION < 0x040000
00327 QValueList<QRect> itemGeometries = layoutItems(rect, d_data->numCols);
00328 #else
00329 QList<QRect> itemGeometries = layoutItems(rect, d_data->numCols);
00330 #endif
00331
00332 int index = 0;
00333 for (PrivateData::LayoutItemList::iterator it = d_data->itemList.begin();
00334 it != d_data->itemList.end(); ++it)
00335 {
00336 QWidget *w = (*it)->widget();
00337 if ( w )
00338 {
00339 w->setGeometry(itemGeometries[index]);
00340 index++;
00341 }
00342 }
00343 }
00344
00353 uint QwtDynGridLayout::columnsForWidth(int width) const
00354 {
00355 if ( isEmpty() )
00356 return 0;
00357
00358 const int maxCols = (d_data->maxCols > 0) ? d_data->maxCols : itemCount();
00359 if ( maxRowWidth(maxCols) <= width )
00360 return maxCols;
00361
00362 for (int numCols = 2; numCols <= maxCols; numCols++ )
00363 {
00364 const int rowWidth = maxRowWidth(numCols);
00365 if ( rowWidth > width )
00366 return numCols - 1;
00367 }
00368
00369 return 1;
00370 }
00371
00379 int QwtDynGridLayout::maxRowWidth(int numCols) const
00380 {
00381 int col;
00382
00383 QwtArray<int> colWidth(numCols);
00384 for ( col = 0; col < (int)numCols; col++ )
00385 colWidth[col] = 0;
00386
00387 if ( d_data->isDirty )
00388 ((QwtDynGridLayout*)this)->updateLayoutCache();
00389
00390 for ( uint index = 0;
00391 index < (uint)d_data->itemSizeHints.count(); index++ )
00392 {
00393 col = index % numCols;
00394 colWidth[col] = qwtMax(colWidth[col],
00395 d_data->itemSizeHints[int(index)].width());
00396 }
00397
00398 int rowWidth = 2 * margin() + (numCols - 1) * spacing();
00399 for ( col = 0; col < (int)numCols; col++ )
00400 rowWidth += colWidth[col];
00401
00402 return rowWidth;
00403 }
00404
00409 int QwtDynGridLayout::maxItemWidth() const
00410 {
00411 if ( isEmpty() )
00412 return 0;
00413
00414 if ( d_data->isDirty )
00415 ((QwtDynGridLayout*)this)->updateLayoutCache();
00416
00417 int w = 0;
00418 for ( uint i = 0; i < (uint)d_data->itemSizeHints.count(); i++ )
00419 {
00420 const int itemW = d_data->itemSizeHints[int(i)].width();
00421 if ( itemW > w )
00422 w = itemW;
00423 }
00424
00425 return w;
00426 }
00427
00436 #if QT_VERSION < 0x040000
00437 QValueList<QRect> QwtDynGridLayout::layoutItems(const QRect &rect,
00438 uint numCols) const
00439 #else
00440 QList<QRect> QwtDynGridLayout::layoutItems(const QRect &rect,
00441 uint numCols) const
00442 #endif
00443 {
00444 #if QT_VERSION < 0x040000
00445 QValueList<QRect> itemGeometries;
00446 #else
00447 QList<QRect> itemGeometries;
00448 #endif
00449 if ( numCols == 0 || isEmpty() )
00450 return itemGeometries;
00451
00452 uint numRows = itemCount() / numCols;
00453 if ( numRows % itemCount() )
00454 numRows++;
00455
00456 QwtArray<int> rowHeight(numRows);
00457 QwtArray<int> colWidth(numCols);
00458
00459 layoutGrid(numCols, rowHeight, colWidth);
00460
00461 bool expandH, expandV;
00462 #if QT_VERSION >= 0x040000
00463 expandH = expandingDirections() & Qt::Horizontal;
00464 expandV = expandingDirections() & Qt::Vertical;
00465 #else
00466 expandH = expanding() & QSizePolicy::Horizontally;
00467 expandV = expanding() & QSizePolicy::Vertically;
00468 #endif
00469
00470 if ( expandH || expandV )
00471 stretchGrid(rect, numCols, rowHeight, colWidth);
00472
00473 QwtDynGridLayout *that = (QwtDynGridLayout *)this;
00474 const int maxCols = d_data->maxCols;
00475 that->d_data->maxCols = numCols;
00476 const QRect alignedRect = alignmentRect(rect);
00477 that->d_data->maxCols = maxCols;
00478
00479 const int xOffset = expandH ? 0 : alignedRect.x();
00480 const int yOffset = expandV ? 0 : alignedRect.y();
00481
00482 QwtArray<int> colX(numCols);
00483 QwtArray<int> rowY(numRows);
00484
00485 const int xySpace = spacing();
00486
00487 rowY[0] = yOffset + margin();
00488 for ( int r = 1; r < (int)numRows; r++ )
00489 rowY[r] = rowY[r-1] + rowHeight[r-1] + xySpace;
00490
00491 colX[0] = xOffset + margin();
00492 for ( int c = 1; c < (int)numCols; c++ )
00493 colX[c] = colX[c-1] + colWidth[c-1] + xySpace;
00494
00495 const int itemCount = d_data->itemList.size();
00496 for ( int i = 0; i < itemCount; i++ )
00497 {
00498 const int row = i / numCols;
00499 const int col = i % numCols;
00500
00501 QRect itemGeometry(colX[col], rowY[row],
00502 colWidth[col], rowHeight[row]);
00503 itemGeometries.append(itemGeometry);
00504 }
00505
00506 return itemGeometries;
00507 }
00508
00509
00518 void QwtDynGridLayout::layoutGrid(uint numCols,
00519 QwtArray<int>& rowHeight, QwtArray<int>& colWidth) const
00520 {
00521 if ( numCols <= 0 )
00522 return;
00523
00524 if ( d_data->isDirty )
00525 ((QwtDynGridLayout*)this)->updateLayoutCache();
00526
00527 for ( uint index = 0;
00528 index < (uint)d_data->itemSizeHints.count(); index++ )
00529 {
00530 const int row = index / numCols;
00531 const int col = index % numCols;
00532
00533 const QSize &size = d_data->itemSizeHints[int(index)];
00534
00535 rowHeight[row] = (col == 0)
00536 ? size.height() : qwtMax(rowHeight[row], size.height());
00537 colWidth[col] = (row == 0)
00538 ? size.width() : qwtMax(colWidth[col], size.width());
00539 }
00540 }
00541
00547 bool QwtDynGridLayout::hasHeightForWidth() const
00548 {
00549 return true;
00550 }
00551
00557 int QwtDynGridLayout::heightForWidth(int width) const
00558 {
00559 if ( isEmpty() )
00560 return 0;
00561
00562 const uint numCols = columnsForWidth(width);
00563 uint numRows = itemCount() / numCols;
00564 if ( itemCount() % numCols )
00565 numRows++;
00566
00567 QwtArray<int> rowHeight(numRows);
00568 QwtArray<int> colWidth(numCols);
00569
00570 layoutGrid(numCols, rowHeight, colWidth);
00571
00572 int h = 2 * margin() + (numRows - 1) * spacing();
00573 for ( int row = 0; row < (int)numRows; row++ )
00574 h += rowHeight[row];
00575
00576 return h;
00577 }
00578
00586 void QwtDynGridLayout::stretchGrid(const QRect &rect,
00587 uint numCols, QwtArray<int>& rowHeight, QwtArray<int>& colWidth) const
00588 {
00589 if ( numCols == 0 || isEmpty() )
00590 return;
00591
00592 bool expandH, expandV;
00593 #if QT_VERSION >= 0x040000
00594 expandH = expandingDirections() & Qt::Horizontal;
00595 expandV = expandingDirections() & Qt::Vertical;
00596 #else
00597 expandH = expanding() & QSizePolicy::Horizontally;
00598 expandV = expanding() & QSizePolicy::Vertically;
00599 #endif
00600
00601 if ( expandH )
00602 {
00603 int xDelta = rect.width() - 2 * margin() - (numCols - 1) * spacing();
00604 for ( int col = 0; col < (int)numCols; col++ )
00605 xDelta -= colWidth[col];
00606
00607 if ( xDelta > 0 )
00608 {
00609 for ( int col = 0; col < (int)numCols; col++ )
00610 {
00611 const int space = xDelta / (numCols - col);
00612 colWidth[col] += space;
00613 xDelta -= space;
00614 }
00615 }
00616 }
00617
00618 if ( expandV )
00619 {
00620 uint numRows = itemCount() / numCols;
00621 if ( itemCount() % numCols )
00622 numRows++;
00623
00624 int yDelta = rect.height() - 2 * margin() - (numRows - 1) * spacing();
00625 for ( int row = 0; row < (int)numRows; row++ )
00626 yDelta -= rowHeight[row];
00627
00628 if ( yDelta > 0 )
00629 {
00630 for ( int row = 0; row < (int)numRows; row++ )
00631 {
00632 const int space = yDelta / (numRows - row);
00633 rowHeight[row] += space;
00634 yDelta -= space;
00635 }
00636 }
00637 }
00638 }
00639
00647 QSize QwtDynGridLayout::sizeHint() const
00648 {
00649 if ( isEmpty() )
00650 return QSize();
00651
00652 const uint numCols = (d_data->maxCols > 0 ) ? d_data->maxCols : itemCount();
00653 uint numRows = itemCount() / numCols;
00654 if ( itemCount() % numCols )
00655 numRows++;
00656
00657 QwtArray<int> rowHeight(numRows);
00658 QwtArray<int> colWidth(numCols);
00659
00660 layoutGrid(numCols, rowHeight, colWidth);
00661
00662 int h = 2 * margin() + (numRows - 1) * spacing();
00663 for ( int row = 0; row < (int)numRows; row++ )
00664 h += rowHeight[row];
00665
00666 int w = 2 * margin() + (numCols - 1) * spacing();
00667 for ( int col = 0; col < (int)numCols; col++ )
00668 w += colWidth[col];
00669
00670 return QSize(w, h);
00671 }
00672
00678 uint QwtDynGridLayout::numRows() const
00679 {
00680 return d_data->numRows;
00681 }
00682
00688 uint QwtDynGridLayout::numCols() const
00689 {
00690 return d_data->numCols;
00691 }