00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "qwt_dyngrid_layout.h"
00011
00012 #if QT_VERSION >= 300
00013 #include <qptrlist.h>
00014 #else
00015 #include <qlist.h>
00016 #ifndef QPtrList
00017 #define QPtrList QList
00018 #define QPtrListIterator QListIterator
00019 #endif
00020 #endif
00021
00022 class QwtDynGridLayoutPrivate
00023 {
00024 public:
00025 QwtDynGridLayoutPrivate():
00026 isDirty(TRUE)
00027 {
00028 }
00029
00030 QPtrList<QLayoutItem> itemList;
00031
00032 bool isDirty;
00033 QwtArray<QSize> itemSizeHints;
00034 };
00035
00036 class QwtDynGridLayoutIterator: public QGLayoutIterator
00037 {
00038 public:
00039 QwtDynGridLayoutIterator(QwtDynGridLayoutPrivate *);
00040
00041 virtual QLayoutItem *current();
00042 virtual QLayoutItem *next();
00043 virtual QLayoutItem *takeCurrent();
00044
00045 private:
00046 QwtDynGridLayoutPrivate *d_data;
00047 };
00048
00049 QwtDynGridLayoutIterator::QwtDynGridLayoutIterator(
00050 QwtDynGridLayoutPrivate *data):
00051 d_data(data)
00052 {
00053 (void)d_data->itemList.first();
00054 }
00055
00056 QLayoutItem *QwtDynGridLayoutIterator::current()
00057 {
00058 return d_data->itemList.current();
00059 }
00060
00061 QLayoutItem *QwtDynGridLayoutIterator::next()
00062 {
00063 return d_data->itemList.next();
00064 }
00065
00066 QLayoutItem *QwtDynGridLayoutIterator::takeCurrent()
00067 {
00068 d_data->isDirty = TRUE;
00069 return d_data->itemList.take();
00070 }
00071
00079 QwtDynGridLayout::QwtDynGridLayout(QWidget *parent,
00080 int margin, int space, const char *name):
00081 QLayout(parent, margin, space, name)
00082 {
00083 init();
00084 }
00085
00092 QwtDynGridLayout::QwtDynGridLayout(QLayout *parent,
00093 int space, const char *name):
00094 QLayout(parent, space, name)
00095 {
00096 init();
00097 }
00098
00104 QwtDynGridLayout::QwtDynGridLayout(int space, const char *name):
00105 QLayout(space, name)
00106 {
00107 init();
00108 }
00109
00113 void QwtDynGridLayout::init()
00114 {
00115 d_layoutData = new QwtDynGridLayoutPrivate;
00116 d_maxCols = d_numRows = d_numCols = 0;
00117 d_expanding = QSizePolicy::NoDirection;
00118
00119 setSupportsMargin(TRUE);
00120 }
00121
00123
00124 QwtDynGridLayout::~QwtDynGridLayout()
00125 {
00126 deleteAllItems();
00127 delete d_layoutData;
00128 }
00129
00130 void QwtDynGridLayout::invalidate()
00131 {
00132 d_layoutData->isDirty = TRUE;
00133 QLayout::invalidate();
00134 }
00135
00136 void QwtDynGridLayout::updateLayoutCache()
00137 {
00138 d_layoutData->itemSizeHints.resize(itemCount());
00139
00140 int index = 0;
00141
00142 QPtrListIterator<QLayoutItem> it(d_layoutData->itemList);
00143 for (const QLayoutItem *item = it.toFirst(); item != 0;
00144 item = ++it, index++ )
00145 {
00146 d_layoutData->itemSizeHints[int(index)] = item->sizeHint();
00147 }
00148
00149 d_layoutData->isDirty = FALSE;
00150 }
00151
00158 void QwtDynGridLayout::setMaxCols(uint maxCols)
00159 {
00160 d_maxCols = maxCols;
00161 }
00162
00169 uint QwtDynGridLayout::maxCols() const
00170 {
00171 return d_maxCols;
00172 }
00173
00175
00176 void QwtDynGridLayout::addItem(QLayoutItem *item)
00177 {
00178 d_layoutData->itemList.append(item);
00179 invalidate();
00180 }
00181
00186 bool QwtDynGridLayout::isEmpty() const
00187 {
00188 return d_layoutData->itemList.isEmpty();
00189 }
00190
00195 uint QwtDynGridLayout::itemCount() const
00196 {
00197 return d_layoutData->itemList.count();
00198 }
00199
00204 QLayoutIterator QwtDynGridLayout::iterator()
00205 {
00206 return QLayoutIterator(
00207 new QwtDynGridLayoutIterator(d_layoutData) );
00208 }
00209
00215 void QwtDynGridLayout::setGeometry(const QRect &rect)
00216 {
00217 QLayout::setGeometry(rect);
00218
00219 if ( isEmpty() )
00220 return;
00221
00222 d_numCols = columnsForWidth(rect.width());
00223 d_numRows = itemCount() / d_numCols;
00224 if ( itemCount() % d_numCols )
00225 d_numRows++;
00226
00227 QValueList<QRect> itemGeometries = layoutItems(rect, d_numCols);
00228
00229 int index;
00230
00231 QLayoutItem *item;
00232 QPtrListIterator<QLayoutItem> it(d_layoutData->itemList);
00233 for ( index = 0, item = it.toFirst(); item != 0; item = ++it )
00234 {
00235 QWidget *w = item->widget();
00236 if ( w )
00237 {
00238 w->setGeometry(itemGeometries[index]);
00239 index++;
00240 }
00241 }
00242 }
00243
00252 uint QwtDynGridLayout::columnsForWidth(int width) const
00253 {
00254 if ( isEmpty() )
00255 return 0;
00256
00257 const int maxCols = (d_maxCols > 0) ? d_maxCols : itemCount();
00258 if ( maxRowWidth(maxCols) <= width )
00259 return maxCols;
00260
00261 for (int numCols = 2; numCols <= maxCols; numCols++ )
00262 {
00263 const int rowWidth = maxRowWidth(numCols);
00264 if ( rowWidth > width )
00265 return numCols - 1;
00266 }
00267
00268 return 1;
00269 }
00270
00278 int QwtDynGridLayout::maxRowWidth(int numCols) const
00279 {
00280 int col;
00281
00282 QwtArray<int> colWidth(numCols);
00283 for ( col = 0; col < (int)numCols; col++ )
00284 colWidth[col] = 0;
00285
00286 if ( d_layoutData->isDirty )
00287 ((QwtDynGridLayout*)this)->updateLayoutCache();
00288
00289 for ( uint index = 0;
00290 index < d_layoutData->itemSizeHints.count(); index++ )
00291 {
00292 col = index % numCols;
00293 colWidth[col] = QMAX(colWidth[col],
00294 d_layoutData->itemSizeHints[int(index)].width());
00295 }
00296
00297 int rowWidth = 2 * margin() + (numCols - 1) * spacing();
00298 for ( col = 0; col < (int)numCols; col++ )
00299 rowWidth += colWidth[col];
00300
00301 return rowWidth;
00302 }
00303
00308 int QwtDynGridLayout::maxItemWidth() const
00309 {
00310 if ( isEmpty() )
00311 return 0;
00312
00313 if ( d_layoutData->isDirty )
00314 ((QwtDynGridLayout*)this)->updateLayoutCache();
00315
00316 int w = 0;
00317 for ( uint i = 0; i < d_layoutData->itemSizeHints.count(); i++ )
00318 {
00319 const int itemW = d_layoutData->itemSizeHints[int(i)].width();
00320 if ( itemW > w )
00321 w = itemW;
00322 }
00323
00324 return w;
00325 }
00326
00335 QValueList<QRect> QwtDynGridLayout::layoutItems(const QRect &rect,
00336 uint numCols) const
00337 {
00338 QValueList<QRect> itemGeometries;
00339 if ( numCols == 0 || isEmpty() )
00340 return itemGeometries;
00341
00342 uint numRows = itemCount() / numCols;
00343 if ( numRows % itemCount() )
00344 numRows++;
00345
00346 QwtArray<int> rowHeight(numRows);
00347 QwtArray<int> colWidth(numCols);
00348
00349 layoutGrid(numCols, rowHeight, colWidth);
00350
00351 if ( expanding() != QSizePolicy::NoDirection )
00352 stretchGrid(rect, numCols, rowHeight, colWidth);
00353
00354 QwtDynGridLayout *that = (QwtDynGridLayout *)this;
00355 const int maxCols = d_maxCols;
00356 that->d_maxCols = numCols;
00357 const QRect alignedRect = alignmentRect(rect);
00358 that->d_maxCols = maxCols;
00359
00360 #if QT_VERSION < 300
00361 const int xOffset = ( expanding() & QSizePolicy::Horizontal )
00362 ? 0 : alignedRect.x();
00363 const int yOffset = ( expanding() & QSizePolicy::Vertical )
00364 ? 0 : alignedRect.y();
00365 #else
00366 const int xOffset = ( expanding() & QSizePolicy::Horizontally )
00367 ? 0 : alignedRect.x();
00368 const int yOffset = ( expanding() & QSizePolicy::Vertically )
00369 ? 0 : alignedRect.y();
00370 #endif
00371
00372 QwtArray<int> colX(numCols);
00373 QwtArray<int> rowY(numRows);
00374
00375 const int xySpace = spacing();
00376
00377 rowY[0] = yOffset + margin();
00378 for ( int r = 1; r < (int)numRows; r++ )
00379 rowY[r] = rowY[r-1] + rowHeight[r-1] + xySpace;
00380
00381 colX[0] = xOffset + margin();
00382 for ( int c = 1; c < (int)numCols; c++ )
00383 colX[c] = colX[c-1] + colWidth[c-1] + xySpace;
00384
00385 int index;
00386 QLayoutItem *item;
00387
00388 QPtrListIterator<QLayoutItem> it(d_layoutData->itemList);
00389 for ( item = it.toFirst(), index = 0; item != 0; item = ++it, index++ )
00390 {
00391 const int row = index / numCols;
00392 const int col = index % numCols;
00393
00394 QRect itemGeometry(colX[col], rowY[row],
00395 colWidth[col], rowHeight[row]);
00396 itemGeometries.append(itemGeometry);
00397 }
00398
00399 return itemGeometries;
00400 }
00401
00402
00411 void QwtDynGridLayout::layoutGrid(uint numCols,
00412 QwtArray<int>& rowHeight, QwtArray<int>& colWidth) const
00413 {
00414 if ( numCols <= 0 )
00415 return;
00416
00417 if ( d_layoutData->isDirty )
00418 ((QwtDynGridLayout*)this)->updateLayoutCache();
00419
00420 for ( uint index = 0;
00421 index < d_layoutData->itemSizeHints.count(); index++ )
00422 {
00423 const int row = index / numCols;
00424 const int col = index % numCols;
00425
00426 const QSize &size = d_layoutData->itemSizeHints[int(index)];
00427
00428 rowHeight[row] = (col == 0)
00429 ? size.height() : QMAX(rowHeight[row], size.height());
00430 colWidth[col] = (row == 0)
00431 ? size.width() : QMAX(colWidth[col], size.width());
00432 }
00433 }
00434
00443 void QwtDynGridLayout::setExpanding(QSizePolicy::ExpandData expanding)
00444 {
00445 d_expanding = expanding;
00446 }
00447
00456 QSizePolicy::ExpandData QwtDynGridLayout::expanding() const
00457 {
00458 return d_expanding;
00459 }
00460
00466 bool QwtDynGridLayout::hasHeightForWidth() const
00467 {
00468 return TRUE;
00469 }
00470
00476 int QwtDynGridLayout::heightForWidth(int width) const
00477 {
00478 if ( isEmpty() )
00479 return 0;
00480
00481 const uint numCols = columnsForWidth(width);
00482 uint numRows = itemCount() / numCols;
00483 if ( itemCount() % numCols )
00484 numRows++;
00485
00486 QwtArray<int> rowHeight(numRows);
00487 QwtArray<int> colWidth(numCols);
00488
00489 layoutGrid(numCols, rowHeight, colWidth);
00490
00491 int h = 2 * margin() + (numRows - 1) * spacing();
00492 for ( int row = 0; row < (int)numRows; row++ )
00493 h += rowHeight[row];
00494
00495 return h;
00496 }
00497
00505 void QwtDynGridLayout::stretchGrid(const QRect &rect,
00506 uint numCols, QwtArray<int>& rowHeight, QwtArray<int>& colWidth) const
00507 {
00508 if ( numCols == 0 || isEmpty() )
00509 return;
00510
00511 #if QT_VERSION < 300
00512 if ( expanding() & QSizePolicy::Horizontal )
00513 #else
00514 if ( expanding() & QSizePolicy::Horizontally )
00515 #endif
00516 {
00517 int xDelta = rect.width() - 2 * margin() - (numCols - 1) * spacing();
00518 for ( int col = 0; col < (int)numCols; col++ )
00519 xDelta -= colWidth[col];
00520
00521 if ( xDelta > 0 )
00522 {
00523 for ( int col = 0; col < (int)numCols; col++ )
00524 {
00525 const int space = xDelta / (numCols - col);
00526 colWidth[col] += space;
00527 xDelta -= space;
00528 }
00529 }
00530 }
00531
00532 #if QT_VERSION < 300
00533 if ( expanding() & QSizePolicy::Vertical )
00534 #else
00535 if ( expanding() & QSizePolicy::Vertically )
00536 #endif
00537 {
00538 uint numRows = itemCount() / numCols;
00539 if ( itemCount() % numCols )
00540 numRows++;
00541
00542 int yDelta = rect.height() - 2 * margin() - (numRows - 1) * spacing();
00543 for ( int row = 0; row < (int)numRows; row++ )
00544 yDelta -= rowHeight[row];
00545
00546 if ( yDelta > 0 )
00547 {
00548 for ( int row = 0; row < (int)numRows; row++ )
00549 {
00550 const int space = yDelta / (numRows - row);
00551 rowHeight[row] += space;
00552 yDelta -= space;
00553 }
00554 }
00555 }
00556 }
00557
00565 QSize QwtDynGridLayout::sizeHint() const
00566 {
00567 if ( isEmpty() )
00568 return QSize();
00569
00570 const uint numCols = (d_maxCols > 0 ) ? d_maxCols : itemCount();
00571 uint numRows = itemCount() / numCols;
00572 if ( itemCount() % numCols )
00573 numRows++;
00574
00575 QwtArray<int> rowHeight(numRows);
00576 QwtArray<int> colWidth(numCols);
00577
00578 layoutGrid(numCols, rowHeight, colWidth);
00579
00580 int h = 2 * margin() + (numRows - 1) * spacing();
00581 for ( int row = 0; row < (int)numRows; row++ )
00582 h += rowHeight[row];
00583
00584 int w = 2 * margin() + (numCols - 1) * spacing();
00585 for ( int col = 0; col < (int)numCols; col++ )
00586 w += colWidth[col];
00587
00588 return QSize(w, h);
00589 }
00590
00596 uint QwtDynGridLayout::numRows() const
00597 {
00598 return d_numRows;
00599 }
00600
00606 uint QwtDynGridLayout::numCols() const
00607 {
00608 return d_numCols;
00609 }
00610
00611
00612
00613
00614
00615
00616