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 return *d_iterator;
00037 }
00038
00039 virtual QLayoutItem *next()
00040 {
00041 d_iterator++;
00042 return *d_iterator;
00043 }
00044
00045 virtual QLayoutItem *takeCurrent()
00046 {
00047 if ( d_iterator == d_data->itemList.end() )
00048 return NULL;
00049
00050 QLayoutItem *item = *d_iterator;
00051
00052 d_data->isDirty = true;
00053 d_iterator = d_data->itemList.remove(d_iterator);
00054 return item;
00055 }
00056
00057 private:
00058
00059 QValueListIterator<QLayoutItem*> d_iterator;
00060 QwtDynGridLayout::PrivateData *d_data;
00061 };
00062 #endif
00063
00064 PrivateData():
00065 isDirty(true)
00066 {
00067 }
00068
00069 #if QT_VERSION < 0x040000
00070 typedef QValueList<QLayoutItem*> LayoutItemList;
00071 #else
00072 typedef QList<QLayoutItem*> LayoutItemList;
00073 #endif
00074
00075 mutable LayoutItemList itemList;
00076
00077 uint maxCols;
00078 uint numRows;
00079 uint numCols;
00080
00081 #if QT_VERSION < 0x040000
00082 QSizePolicy::ExpandData expanding;
00083 #else
00084 Qt::Orientations expanding;
00085 #endif
00086
00087 bool isDirty;
00088 QwtArray<QSize> itemSizeHints;
00089 };
00090
00091
00099 QwtDynGridLayout::QwtDynGridLayout(QWidget *parent,
00100 int margin, int space):
00101 QLayout(parent)
00102 {
00103 init();
00104
00105 setSpacing(space);
00106 setMargin(margin);
00107 }
00108
00109 #if QT_VERSION < 0x040000
00110
00115 QwtDynGridLayout::QwtDynGridLayout(QLayout *parent, int space):
00116 QLayout(parent, space)
00117 {
00118 init();
00119 }
00120 #endif
00121
00127 QwtDynGridLayout::QwtDynGridLayout(int space)
00128 {
00129 init();
00130 setSpacing(space);
00131 }
00132
00136 void QwtDynGridLayout::init()
00137 {
00138 d_data = new QwtDynGridLayout::PrivateData;
00139 d_data->maxCols = d_data->numRows
00140 = d_data->numCols = 0;
00141
00142 #if QT_VERSION < 0x040000
00143 d_data->expanding = QSizePolicy::NoDirection;
00144 setSupportsMargin(true);
00145 #else
00146 d_data->expanding = 0;
00147 #endif
00148 }
00149
00151
00152 QwtDynGridLayout::~QwtDynGridLayout()
00153 {
00154 #if QT_VERSION < 0x040000
00155 deleteAllItems();
00156 #else
00157 #ifdef __GNUC__
00158 #warning what about deleteAllItems
00159 #endif
00160 #endif
00161
00162 delete d_data;
00163 }
00164
00165 void QwtDynGridLayout::invalidate()
00166 {
00167 d_data->isDirty = true;
00168 QLayout::invalidate();
00169 }
00170
00171 void QwtDynGridLayout::updateLayoutCache()
00172 {
00173 d_data->itemSizeHints.resize(itemCount());
00174
00175 int index = 0;
00176
00177 for (PrivateData::LayoutItemList::iterator it = d_data->itemList.begin();
00178 it != d_data->itemList.end(); ++it, index++)
00179 {
00180 d_data->itemSizeHints[int(index)] = (*it)->sizeHint();
00181 }
00182
00183 d_data->isDirty = false;
00184 }
00185
00192 void QwtDynGridLayout::setMaxCols(uint maxCols)
00193 {
00194 d_data->maxCols = maxCols;
00195 }
00196
00203 uint QwtDynGridLayout::maxCols() const
00204 {
00205 return d_data->maxCols;
00206 }
00207
00209
00210 void QwtDynGridLayout::addItem(QLayoutItem *item)
00211 {
00212 d_data->itemList.append(item);
00213 invalidate();
00214 }
00215
00220 bool QwtDynGridLayout::isEmpty() const
00221 {
00222 return d_data->itemList.isEmpty();
00223 }
00224
00229 uint QwtDynGridLayout::itemCount() const
00230 {
00231 return d_data->itemList.count();
00232 }
00233
00234 #if QT_VERSION < 0x040000
00235
00239 QLayoutIterator QwtDynGridLayout::iterator()
00240 {
00241 return QLayoutIterator(
00242 new QwtDynGridLayout::PrivateData::LayoutIterator(d_data) );
00243 }
00244
00253 void QwtDynGridLayout::setExpanding(QSizePolicy::ExpandData expanding)
00254 {
00255 d_data->expanding = expanding;
00256 }
00257
00266 QSizePolicy::ExpandData QwtDynGridLayout::expanding() const
00267 {
00268 return d_data->expanding;
00269 }
00270
00271 #else // QT_VERSION >= 0x040000
00272
00273 QLayoutItem *QwtDynGridLayout::itemAt( int index ) const
00274 {
00275 if ( index < 0 || index >= d_data->itemList.count() )
00276 return NULL;
00277
00278 return d_data->itemList.at(index);
00279 }
00280
00281 QLayoutItem *QwtDynGridLayout::takeAt( int index )
00282 {
00283 if ( index < 0 || index >= d_data->itemList.count() )
00284 return NULL;
00285
00286 d_data->isDirty = true;
00287 return d_data->itemList.takeAt(index);
00288 }
00289
00290 int QwtDynGridLayout::count() const
00291 {
00292 return d_data->itemList.count();
00293 }
00294
00295 void QwtDynGridLayout::setExpandingDirections(Qt::Orientations expanding)
00296 {
00297 d_data->expanding = expanding;
00298 }
00299
00300 Qt::Orientations QwtDynGridLayout::expandingDirections() const
00301 {
00302 return d_data->expanding;
00303 }
00304
00305 #endif
00306
00312 void QwtDynGridLayout::setGeometry(const QRect &rect)
00313 {
00314 QLayout::setGeometry(rect);
00315
00316 if ( isEmpty() )
00317 return;
00318
00319 d_data->numCols = columnsForWidth(rect.width());
00320 d_data->numRows = itemCount() / d_data->numCols;
00321 if ( itemCount() % d_data->numCols )
00322 d_data->numRows++;
00323
00324 #if QT_VERSION < 0x040000
00325 QValueList<QRect> itemGeometries = layoutItems(rect, d_data->numCols);
00326 #else
00327 QList<QRect> itemGeometries = layoutItems(rect, d_data->numCols);
00328 #endif
00329
00330 int index = 0;
00331 for (PrivateData::LayoutItemList::iterator it = d_data->itemList.begin();
00332 it != d_data->itemList.end(); ++it)
00333 {
00334 QWidget *w = (*it)->widget();
00335 if ( w )
00336 {
00337 w->setGeometry(itemGeometries[index]);
00338 index++;
00339 }
00340 }
00341 }
00342
00351 uint QwtDynGridLayout::columnsForWidth(int width) const
00352 {
00353 if ( isEmpty() )
00354 return 0;
00355
00356 const int maxCols = (d_data->maxCols > 0) ? d_data->maxCols : itemCount();
00357 if ( maxRowWidth(maxCols) <= width )
00358 return maxCols;
00359
00360 for (int numCols = 2; numCols <= maxCols; numCols++ )
00361 {
00362 const int rowWidth = maxRowWidth(numCols);
00363 if ( rowWidth > width )
00364 return numCols - 1;
00365 }
00366
00367 return 1;
00368 }
00369
00377 int QwtDynGridLayout::maxRowWidth(int numCols) const
00378 {
00379 int col;
00380
00381 QwtArray<int> colWidth(numCols);
00382 for ( col = 0; col < (int)numCols; col++ )
00383 colWidth[col] = 0;
00384
00385 if ( d_data->isDirty )
00386 ((QwtDynGridLayout*)this)->updateLayoutCache();
00387
00388 for ( uint index = 0;
00389 index < (uint)d_data->itemSizeHints.count(); index++ )
00390 {
00391 col = index % numCols;
00392 colWidth[col] = qwtMax(colWidth[col],
00393 d_data->itemSizeHints[int(index)].width());
00394 }
00395
00396 int rowWidth = 2 * margin() + (numCols - 1) * spacing();
00397 for ( col = 0; col < (int)numCols; col++ )
00398 rowWidth += colWidth[col];
00399
00400 return rowWidth;
00401 }
00402
00407 int QwtDynGridLayout::maxItemWidth() const
00408 {
00409 if ( isEmpty() )
00410 return 0;
00411
00412 if ( d_data->isDirty )
00413 ((QwtDynGridLayout*)this)->updateLayoutCache();
00414
00415 int w = 0;
00416 for ( uint i = 0; i < (uint)d_data->itemSizeHints.count(); i++ )
00417 {
00418 const int itemW = d_data->itemSizeHints[int(i)].width();
00419 if ( itemW > w )
00420 w = itemW;
00421 }
00422
00423 return w;
00424 }
00425
00434 #if QT_VERSION < 0x040000
00435 QValueList<QRect> QwtDynGridLayout::layoutItems(const QRect &rect,
00436 uint numCols) const
00437 #else
00438 QList<QRect> QwtDynGridLayout::layoutItems(const QRect &rect,
00439 uint numCols) const
00440 #endif
00441 {
00442 #if QT_VERSION < 0x040000
00443 QValueList<QRect> itemGeometries;
00444 #else
00445 QList<QRect> itemGeometries;
00446 #endif
00447 if ( numCols == 0 || isEmpty() )
00448 return itemGeometries;
00449
00450 uint numRows = itemCount() / numCols;
00451 if ( numRows % itemCount() )
00452 numRows++;
00453
00454 QwtArray<int> rowHeight(numRows);
00455 QwtArray<int> colWidth(numCols);
00456
00457 layoutGrid(numCols, rowHeight, colWidth);
00458
00459 bool expandH, expandV;
00460 #if QT_VERSION >= 0x040000
00461 expandH = expandingDirections() & Qt::Horizontal;
00462 expandV = expandingDirections() & Qt::Vertical;
00463 #else
00464 expandH = expanding() & QSizePolicy::Horizontally;
00465 expandV = expanding() & QSizePolicy::Vertically;
00466 #endif
00467
00468 if ( expandH || expandV )
00469 stretchGrid(rect, numCols, rowHeight, colWidth);
00470
00471 QwtDynGridLayout *that = (QwtDynGridLayout *)this;
00472 const int maxCols = d_data->maxCols;
00473 that->d_data->maxCols = numCols;
00474 const QRect alignedRect = alignmentRect(rect);
00475 that->d_data->maxCols = maxCols;
00476
00477 const int xOffset = expandH ? 0 : alignedRect.x();
00478 const int yOffset = expandV ? 0 : alignedRect.y();
00479
00480 QwtArray<int> colX(numCols);
00481 QwtArray<int> rowY(numRows);
00482
00483 const int xySpace = spacing();
00484
00485 rowY[0] = yOffset + margin();
00486 for ( int r = 1; r < (int)numRows; r++ )
00487 rowY[r] = rowY[r-1] + rowHeight[r-1] + xySpace;
00488
00489 colX[0] = xOffset + margin();
00490 for ( int c = 1; c < (int)numCols; c++ )
00491 colX[c] = colX[c-1] + colWidth[c-1] + xySpace;
00492
00493 const int itemCount = d_data->itemList.size();
00494 for ( int i = 0; i < itemCount; i++ )
00495 {
00496 const int row = i / numCols;
00497 const int col = i % numCols;
00498
00499 QRect itemGeometry(colX[col], rowY[row],
00500 colWidth[col], rowHeight[row]);
00501 itemGeometries.append(itemGeometry);
00502 }
00503
00504 return itemGeometries;
00505 }
00506
00507
00516 void QwtDynGridLayout::layoutGrid(uint numCols,
00517 QwtArray<int>& rowHeight, QwtArray<int>& colWidth) const
00518 {
00519 if ( numCols <= 0 )
00520 return;
00521
00522 if ( d_data->isDirty )
00523 ((QwtDynGridLayout*)this)->updateLayoutCache();
00524
00525 for ( uint index = 0;
00526 index < (uint)d_data->itemSizeHints.count(); index++ )
00527 {
00528 const int row = index / numCols;
00529 const int col = index % numCols;
00530
00531 const QSize &size = d_data->itemSizeHints[int(index)];
00532
00533 rowHeight[row] = (col == 0)
00534 ? size.height() : qwtMax(rowHeight[row], size.height());
00535 colWidth[col] = (row == 0)
00536 ? size.width() : qwtMax(colWidth[col], size.width());
00537 }
00538 }
00539
00545 bool QwtDynGridLayout::hasHeightForWidth() const
00546 {
00547 return true;
00548 }
00549
00555 int QwtDynGridLayout::heightForWidth(int width) const
00556 {
00557 if ( isEmpty() )
00558 return 0;
00559
00560 const uint numCols = columnsForWidth(width);
00561 uint numRows = itemCount() / numCols;
00562 if ( itemCount() % numCols )
00563 numRows++;
00564
00565 QwtArray<int> rowHeight(numRows);
00566 QwtArray<int> colWidth(numCols);
00567
00568 layoutGrid(numCols, rowHeight, colWidth);
00569
00570 int h = 2 * margin() + (numRows - 1) * spacing();
00571 for ( int row = 0; row < (int)numRows; row++ )
00572 h += rowHeight[row];
00573
00574 return h;
00575 }
00576
00584 void QwtDynGridLayout::stretchGrid(const QRect &rect,
00585 uint numCols, QwtArray<int>& rowHeight, QwtArray<int>& colWidth) const
00586 {
00587 if ( numCols == 0 || isEmpty() )
00588 return;
00589
00590 bool expandH, expandV;
00591 #if QT_VERSION >= 0x040000
00592 expandH = expandingDirections() & Qt::Horizontal;
00593 expandV = expandingDirections() & Qt::Vertical;
00594 #else
00595 expandH = expanding() & QSizePolicy::Horizontally;
00596 expandV = expanding() & QSizePolicy::Vertically;
00597 #endif
00598
00599 if ( expandH )
00600 {
00601 int xDelta = rect.width() - 2 * margin() - (numCols - 1) * spacing();
00602 for ( int col = 0; col < (int)numCols; col++ )
00603 xDelta -= colWidth[col];
00604
00605 if ( xDelta > 0 )
00606 {
00607 for ( int col = 0; col < (int)numCols; col++ )
00608 {
00609 const int space = xDelta / (numCols - col);
00610 colWidth[col] += space;
00611 xDelta -= space;
00612 }
00613 }
00614 }
00615
00616 if ( expandV )
00617 {
00618 uint numRows = itemCount() / numCols;
00619 if ( itemCount() % numCols )
00620 numRows++;
00621
00622 int yDelta = rect.height() - 2 * margin() - (numRows - 1) * spacing();
00623 for ( int row = 0; row < (int)numRows; row++ )
00624 yDelta -= rowHeight[row];
00625
00626 if ( yDelta > 0 )
00627 {
00628 for ( int row = 0; row < (int)numRows; row++ )
00629 {
00630 const int space = yDelta / (numRows - row);
00631 rowHeight[row] += space;
00632 yDelta -= space;
00633 }
00634 }
00635 }
00636 }
00637
00645 QSize QwtDynGridLayout::sizeHint() const
00646 {
00647 if ( isEmpty() )
00648 return QSize();
00649
00650 const uint numCols = (d_data->maxCols > 0 ) ? d_data->maxCols : itemCount();
00651 uint numRows = itemCount() / numCols;
00652 if ( itemCount() % numCols )
00653 numRows++;
00654
00655 QwtArray<int> rowHeight(numRows);
00656 QwtArray<int> colWidth(numCols);
00657
00658 layoutGrid(numCols, rowHeight, colWidth);
00659
00660 int h = 2 * margin() + (numRows - 1) * spacing();
00661 for ( int row = 0; row < (int)numRows; row++ )
00662 h += rowHeight[row];
00663
00664 int w = 2 * margin() + (numCols - 1) * spacing();
00665 for ( int col = 0; col < (int)numCols; col++ )
00666 w += colWidth[col];
00667
00668 return QSize(w, h);
00669 }
00670
00676 uint QwtDynGridLayout::numRows() const
00677 {
00678 return d_data->numRows;
00679 }
00680
00686 uint QwtDynGridLayout::numCols() const
00687 {
00688 return d_data->numCols;
00689 }