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