Main Page | Class Hierarchy | Alphabetical List | Class List | 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 "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; // At least 1 column
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 // Local Variables:
00612 // mode: C++
00613 // c-file-style: "stroustrup"
00614 // indent-tabs-mode: nil
00615 // End:
00616 

Generated on Sun Nov 21 11:12:43 2004 for Qwt User's Guide by doxygen 1.3.5