qwt_dyngrid_layout.cpp

00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
00002  * Qwt Widget Library
00003  * Copyright (C) 1997   Josef Wilgen
00004  * Copyright (C) 2002   Uwe Rathmann
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the Qwt License, Version 1.0
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; // At least 1 column
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 }

Generated on Mon Feb 26 21:22:36 2007 for Qwt User's Guide by  doxygen 1.4.6