Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

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             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(); // needed ???
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; // At least 1 column
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 }

Generated on Wed Aug 31 23:02:29 2005 for Qwt User's Guide by  doxygen 1.4.1