qwt_dyngrid_layout.cpp
Go to the documentation of this file.
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 #include "qwt_math.h"
00012 #include <qvector.h>
00013 #include <qlist.h>
00014 
00015 class QwtDynGridLayout::PrivateData
00016 {
00017 public:
00018     PrivateData():
00019         isDirty( true )
00020     {
00021     }
00022 
00023     void updateLayoutCache();
00024 
00025     mutable QList<QLayoutItem*> itemList;
00026 
00027     uint maxColumns;
00028     uint numRows;
00029     uint numColumns;
00030 
00031     Qt::Orientations expanding;
00032 
00033     bool isDirty;
00034     QVector<QSize> itemSizeHints;
00035 };
00036 
00037 void QwtDynGridLayout::PrivateData::updateLayoutCache()
00038 {
00039     itemSizeHints.resize( itemList.count() );
00040 
00041     int index = 0;
00042 
00043     for ( QList<QLayoutItem*>::const_iterator it = itemList.constBegin();
00044         it != itemList.constEnd(); ++it, index++ )
00045     {
00046         itemSizeHints[ index ] = ( *it )->sizeHint();
00047     }
00048 
00049     isDirty = false;
00050 }
00051 
00058 QwtDynGridLayout::QwtDynGridLayout( QWidget *parent,
00059         int margin, int spacing ):
00060     QLayout( parent )
00061 {
00062     init();
00063 
00064     setSpacing( spacing );
00065     setMargin( margin );
00066 }
00067 
00072 QwtDynGridLayout::QwtDynGridLayout( int spacing )
00073 {
00074     init();
00075     setSpacing( spacing );
00076 }
00077 
00081 void QwtDynGridLayout::init()
00082 {
00083     d_data = new QwtDynGridLayout::PrivateData;
00084     d_data->maxColumns = d_data->numRows = d_data->numColumns = 0;
00085     d_data->expanding = 0;
00086 }
00087 
00089 
00090 QwtDynGridLayout::~QwtDynGridLayout()
00091 {
00092     qDeleteAll( d_data->itemList );
00093     delete d_data;
00094 }
00095 
00097 void QwtDynGridLayout::invalidate()
00098 {
00099     d_data->isDirty = true;
00100     QLayout::invalidate();
00101 }
00102 
00108 void QwtDynGridLayout::setMaxColumns( uint maxColumns )
00109 {
00110     d_data->maxColumns = maxColumns;
00111 }
00112 
00121 uint QwtDynGridLayout::maxColumns() const
00122 {
00123     return d_data->maxColumns;
00124 }
00125 
00130 void QwtDynGridLayout::addItem( QLayoutItem *item )
00131 {
00132     d_data->itemList.append( item );
00133     invalidate();
00134 }
00135 
00139 bool QwtDynGridLayout::isEmpty() const
00140 {
00141     return d_data->itemList.isEmpty();
00142 }
00143 
00147 uint QwtDynGridLayout::itemCount() const
00148 {
00149     return d_data->itemList.count();
00150 }
00151 
00159 QLayoutItem *QwtDynGridLayout::itemAt( int index ) const
00160 {
00161     if ( index < 0 || index >= d_data->itemList.count() )
00162         return NULL;
00163 
00164     return d_data->itemList.at( index );
00165 }
00166 
00174 QLayoutItem *QwtDynGridLayout::takeAt( int index )
00175 {
00176     if ( index < 0 || index >= d_data->itemList.count() )
00177         return NULL;
00178 
00179     d_data->isDirty = true;
00180     return d_data->itemList.takeAt( index );
00181 }
00182 
00184 int QwtDynGridLayout::count() const
00185 {
00186     return d_data->itemList.count();
00187 }
00188 
00198 void QwtDynGridLayout::setExpandingDirections( Qt::Orientations expanding )
00199 {
00200     d_data->expanding = expanding;
00201 }
00202 
00213 Qt::Orientations QwtDynGridLayout::expandingDirections() const
00214 {
00215     return d_data->expanding;
00216 }
00217 
00224 void QwtDynGridLayout::setGeometry( const QRect &rect )
00225 {
00226     QLayout::setGeometry( rect );
00227 
00228     if ( isEmpty() )
00229         return;
00230 
00231     d_data->numColumns = columnsForWidth( rect.width() );
00232     d_data->numRows = itemCount() / d_data->numColumns;
00233     if ( itemCount() % d_data->numColumns )
00234         d_data->numRows++;
00235 
00236     const QList<QRect> itemGeometries = layoutItems( rect, d_data->numColumns );
00237 
00238     int index = 0;
00239     for ( QList<QLayoutItem*>::const_iterator it = d_data->itemList.constBegin();
00240         it != d_data->itemList.constEnd(); ++it )
00241     {
00242         ( *it )->setGeometry( itemGeometries[index] );
00243         index++;
00244     }
00245 }
00246 
00258 uint QwtDynGridLayout::columnsForWidth( int width ) const
00259 {
00260     if ( isEmpty() )
00261         return 0;
00262 
00263     uint maxColumns = itemCount();
00264     if ( d_data->maxColumns > 0 ) 
00265         maxColumns = qMin( d_data->maxColumns, maxColumns );
00266 
00267     if ( maxRowWidth( maxColumns ) <= width )
00268         return maxColumns;
00269 
00270     for ( uint numColumns = 2; numColumns <= maxColumns; numColumns++ )
00271     {
00272         const int rowWidth = maxRowWidth( numColumns );
00273         if ( rowWidth > width )
00274             return numColumns - 1;
00275     }
00276 
00277     return 1; // At least 1 column
00278 }
00279 
00287 int QwtDynGridLayout::maxRowWidth( int numColumns ) const
00288 {
00289     int col;
00290 
00291     QVector<int> colWidth( numColumns );
00292     for ( col = 0; col < numColumns; col++ )
00293         colWidth[col] = 0;
00294 
00295     if ( d_data->isDirty )
00296         d_data->updateLayoutCache();
00297 
00298     for ( int index = 0;
00299         index < d_data->itemSizeHints.count(); index++ )
00300     {
00301         col = index % numColumns;
00302         colWidth[col] = qMax( colWidth[col],
00303             d_data->itemSizeHints[int( index )].width() );
00304     }
00305 
00306     int rowWidth = 2 * margin() + ( numColumns - 1 ) * spacing();
00307     for ( col = 0; col < numColumns; col++ )
00308         rowWidth += colWidth[col];
00309 
00310     return rowWidth;
00311 }
00312 
00316 int QwtDynGridLayout::maxItemWidth() const
00317 {
00318     if ( isEmpty() )
00319         return 0;
00320 
00321     if ( d_data->isDirty )
00322         d_data->updateLayoutCache();
00323 
00324     int w = 0;
00325     for ( int i = 0; i < d_data->itemSizeHints.count(); i++ )
00326     {
00327         const int itemW = d_data->itemSizeHints[i].width();
00328         if ( itemW > w )
00329             w = itemW;
00330     }
00331 
00332     return w;
00333 }
00334 
00344 QList<QRect> QwtDynGridLayout::layoutItems( const QRect &rect,
00345     uint numColumns ) const
00346 {
00347     QList<QRect> itemGeometries;
00348     if ( numColumns == 0 || isEmpty() )
00349         return itemGeometries;
00350 
00351     uint numRows = itemCount() / numColumns;
00352     if ( numColumns % itemCount() )
00353         numRows++;
00354 
00355     if ( numRows == 0 )
00356         return itemGeometries;
00357 
00358     QVector<int> rowHeight( numRows );
00359     QVector<int> colWidth( numColumns );
00360 
00361     layoutGrid( numColumns, rowHeight, colWidth );
00362 
00363     bool expandH, expandV;
00364     expandH = expandingDirections() & Qt::Horizontal;
00365     expandV = expandingDirections() & Qt::Vertical;
00366 
00367     if ( expandH || expandV )
00368         stretchGrid( rect, numColumns, rowHeight, colWidth );
00369 
00370     const int maxColumns = d_data->maxColumns;
00371     d_data->maxColumns = numColumns;
00372     const QRect alignedRect = alignmentRect( rect );
00373     d_data->maxColumns = maxColumns;
00374 
00375     const int xOffset = expandH ? 0 : alignedRect.x();
00376     const int yOffset = expandV ? 0 : alignedRect.y();
00377 
00378     QVector<int> colX( numColumns );
00379     QVector<int> rowY( numRows );
00380 
00381     const int xySpace = spacing();
00382 
00383     rowY[0] = yOffset + margin();
00384     for ( uint r = 1; r < numRows; r++ )
00385         rowY[r] = rowY[r-1] + rowHeight[r-1] + xySpace;
00386 
00387     colX[0] = xOffset + margin();
00388     for ( uint c = 1; c < numColumns; c++ )
00389         colX[c] = colX[c-1] + colWidth[c-1] + xySpace;
00390 
00391     const int itemCount = d_data->itemList.size();
00392 #if QT_VERSION >= 0x040700
00393     itemGeometries.reserve( itemCount );
00394 #endif
00395 
00396     for ( int i = 0; i < itemCount; i++ )
00397     {
00398         const int row = i / numColumns;
00399         const int col = i % numColumns;
00400 
00401         const QRect itemGeometry( colX[col], rowY[row],
00402             colWidth[col], rowHeight[row] );
00403         itemGeometries.append( itemGeometry );
00404     }
00405 
00406     return itemGeometries;
00407 }
00408 
00409 
00419 void QwtDynGridLayout::layoutGrid( uint numColumns,
00420     QVector<int>& rowHeight, QVector<int>& colWidth ) const
00421 {
00422     if ( numColumns <= 0 )
00423         return;
00424 
00425     if ( d_data->isDirty )
00426         d_data->updateLayoutCache();
00427 
00428     for ( int index = 0; index < d_data->itemSizeHints.count(); index++ )
00429     {
00430         const int row = index / numColumns;
00431         const int col = index % numColumns;
00432 
00433         const QSize &size = d_data->itemSizeHints[int( index )];
00434 
00435         rowHeight[row] = ( col == 0 )
00436             ? size.height() : qMax( rowHeight[row], size.height() );
00437         colWidth[col] = ( row == 0 )
00438             ? size.width() : qMax( colWidth[col], size.width() );
00439     }
00440 }
00441 
00446 bool QwtDynGridLayout::hasHeightForWidth() const
00447 {
00448     return true;
00449 }
00450 
00455 int QwtDynGridLayout::heightForWidth( int width ) const
00456 {
00457     if ( isEmpty() )
00458         return 0;
00459 
00460     const uint numColumns = columnsForWidth( width );
00461     uint numRows = itemCount() / numColumns;
00462     if ( itemCount() % numColumns )
00463         numRows++;
00464 
00465     QVector<int> rowHeight( numRows );
00466     QVector<int> colWidth( numColumns );
00467 
00468     layoutGrid( numColumns, rowHeight, colWidth );
00469 
00470     int h = 2 * margin() + ( numRows - 1 ) * spacing();
00471     for ( uint row = 0; row < numRows; row++ )
00472         h += rowHeight[row];
00473 
00474     return h;
00475 }
00476 
00489 void QwtDynGridLayout::stretchGrid( const QRect &rect,
00490     uint numColumns, QVector<int>& rowHeight, QVector<int>& colWidth ) const
00491 {
00492     if ( numColumns == 0 || isEmpty() )
00493         return;
00494 
00495     bool expandH, expandV;
00496     expandH = expandingDirections() & Qt::Horizontal;
00497     expandV = expandingDirections() & Qt::Vertical;
00498 
00499     if ( expandH )
00500     {
00501         int xDelta = rect.width() - 2 * margin() - ( numColumns - 1 ) * spacing();
00502         for ( uint col = 0; col < numColumns; col++ )
00503             xDelta -= colWidth[col];
00504 
00505         if ( xDelta > 0 )
00506         {
00507             for ( uint col = 0; col < numColumns; col++ )
00508             {
00509                 const int space = xDelta / ( numColumns - col );
00510                 colWidth[col] += space;
00511                 xDelta -= space;
00512             }
00513         }
00514     }
00515 
00516     if ( expandV )
00517     {
00518         uint numRows = itemCount() / numColumns;
00519         if ( itemCount() % numColumns )
00520             numRows++;
00521 
00522         int yDelta = rect.height() - 2 * margin() - ( numRows - 1 ) * spacing();
00523         for ( uint row = 0; row < numRows; row++ )
00524             yDelta -= rowHeight[row];
00525 
00526         if ( yDelta > 0 )
00527         {
00528             for ( uint row = 0; row < numRows; row++ )
00529             {
00530                 const int space = yDelta / ( numRows - row );
00531                 rowHeight[row] += space;
00532                 yDelta -= space;
00533             }
00534         }
00535     }
00536 }
00537 
00546 QSize QwtDynGridLayout::sizeHint() const
00547 {
00548     if ( isEmpty() )
00549         return QSize();
00550 
00551     uint numColumns = itemCount();
00552     if ( d_data->maxColumns > 0 )
00553         numColumns = qMin( d_data->maxColumns, numColumns );
00554 
00555     uint numRows = itemCount() / numColumns;
00556     if ( itemCount() % numColumns )
00557         numRows++;
00558 
00559     QVector<int> rowHeight( numRows );
00560     QVector<int> colWidth( numColumns );
00561 
00562     layoutGrid( numColumns, rowHeight, colWidth );
00563 
00564     int h = 2 * margin() + ( numRows - 1 ) * spacing();
00565     for ( uint row = 0; row < numRows; row++ )
00566         h += rowHeight[row];
00567 
00568     int w = 2 * margin() + ( numColumns - 1 ) * spacing();
00569     for ( uint col = 0; col < numColumns; col++ )
00570         w += colWidth[col];
00571 
00572     return QSize( w, h );
00573 }
00574 
00580 uint QwtDynGridLayout::numRows() const
00581 {
00582     return d_data->numRows;
00583 }
00584 
00590 uint QwtDynGridLayout::numColumns() const
00591 {
00592     return d_data->numColumns;
00593 }


plotjuggler
Author(s): Davide Faconti
autogenerated on Wed Jul 3 2019 19:28:04