00001
00002
00003
00004
00005
00006
00007
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;
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
00612
00613
00614
00615
00616