1
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
3
* Copyright (C) 1997 Josef Wilgen
4
* Copyright (C) 2002 Uwe Rathmann
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the Qwt License, Version 1.0
8
*****************************************************************************/
11
#include "qwt_dyngrid_layout.h"
14
#if QT_VERSION < 0x040000
15
#include <qvaluelist.h>
20
class QwtDynGridLayout::PrivateData
24
#if QT_VERSION < 0x040000
25
class LayoutIterator: public QGLayoutIterator
28
LayoutIterator(PrivateData *data):
31
d_iterator = d_data->itemList.begin();
34
virtual QLayoutItem *current()
36
if (d_iterator == d_data->itemList.end())
42
virtual QLayoutItem *next()
44
if (d_iterator == d_data->itemList.end())
48
if (d_iterator == d_data->itemList.end())
54
virtual QLayoutItem *takeCurrent()
56
if ( d_iterator == d_data->itemList.end() )
59
QLayoutItem *item = *d_iterator;
61
d_data->isDirty = true;
62
d_iterator = d_data->itemList.remove(d_iterator);
68
QValueListIterator<QLayoutItem*> d_iterator;
69
QwtDynGridLayout::PrivateData *d_data;
78
#if QT_VERSION < 0x040000
79
typedef QValueList<QLayoutItem*> LayoutItemList;
81
typedef QList<QLayoutItem*> LayoutItemList;
84
mutable LayoutItemList itemList;
90
#if QT_VERSION < 0x040000
91
QSizePolicy::ExpandData expanding;
93
Qt::Orientations expanding;
97
QwtArray<QSize> itemSizeHints;
102
\param parent Parent widget
104
\param spacing Spacing
107
QwtDynGridLayout::QwtDynGridLayout(QWidget *parent,
108
int margin, int spacing):
117
#if QT_VERSION < 0x040000
119
\param parent Parent widget
120
\param spacing Spacing
122
QwtDynGridLayout::QwtDynGridLayout(QLayout *parent, int spacing):
123
QLayout(parent, spacing)
130
\param spacing Spacing
133
QwtDynGridLayout::QwtDynGridLayout(int spacing)
140
Initialize the layout with default values.
142
void QwtDynGridLayout::init()
144
d_data = new QwtDynGridLayout::PrivateData;
145
d_data->maxCols = d_data->numRows
146
= d_data->numCols = 0;
148
#if QT_VERSION < 0x040000
149
d_data->expanding = QSizePolicy::NoDirection;
150
setSupportsMargin(true);
152
d_data->expanding = 0;
158
QwtDynGridLayout::~QwtDynGridLayout()
160
#if QT_VERSION < 0x040000
167
void QwtDynGridLayout::invalidate()
169
d_data->isDirty = true;
170
QLayout::invalidate();
173
void QwtDynGridLayout::updateLayoutCache()
175
d_data->itemSizeHints.resize(itemCount());
179
for (PrivateData::LayoutItemList::iterator it = d_data->itemList.begin();
180
it != d_data->itemList.end(); ++it, index++)
182
d_data->itemSizeHints[int(index)] = (*it)->sizeHint();
185
d_data->isDirty = false;
189
Limit the number of columns.
190
\param maxCols upper limit, 0 means unlimited
191
\sa QwtDynGridLayout::maxCols()
194
void QwtDynGridLayout::setMaxCols(uint maxCols)
196
d_data->maxCols = maxCols;
200
Return the upper limit for the number of columns.
201
0 means unlimited, what is the default.
202
\sa QwtDynGridLayout::setMaxCols()
205
uint QwtDynGridLayout::maxCols() const
207
return d_data->maxCols;
210
//! Adds item to the next free position.
212
void QwtDynGridLayout::addItem(QLayoutItem *item)
214
d_data->itemList.append(item);
219
\return true if this layout is empty.
222
bool QwtDynGridLayout::isEmpty() const
224
return d_data->itemList.isEmpty();
228
\return number of layout items
231
uint QwtDynGridLayout::itemCount() const
233
return d_data->itemList.count();
236
#if QT_VERSION < 0x040000
238
\return An iterator over the children of this layout.
241
QLayoutIterator QwtDynGridLayout::iterator()
243
return QLayoutIterator(
244
new QwtDynGridLayout::PrivateData::LayoutIterator(d_data) );
248
Set whether this layout can make use of more space than sizeHint().
249
A value of Vertical or Horizontal means that it wants to grow in only
250
one dimension, while BothDirections means that it wants to grow in
251
both dimensions. The default value is NoDirection.
252
\sa QwtDynGridLayout::expanding()
255
void QwtDynGridLayout::setExpanding(QSizePolicy::ExpandData expanding)
257
d_data->expanding = expanding;
261
Returns whether this layout can make use of more space than sizeHint().
262
A value of Vertical or Horizontal means that it wants to grow in only
263
one dimension, while BothDirections means that it wants to grow in
265
\sa QwtDynGridLayout::setExpanding()
268
QSizePolicy::ExpandData QwtDynGridLayout::expanding() const
270
return d_data->expanding;
273
#else // QT_VERSION >= 0x040000
275
QLayoutItem *QwtDynGridLayout::itemAt( int index ) const
277
if ( index < 0 || index >= d_data->itemList.count() )
280
return d_data->itemList.at(index);
283
QLayoutItem *QwtDynGridLayout::takeAt( int index )
285
if ( index < 0 || index >= d_data->itemList.count() )
288
d_data->isDirty = true;
289
return d_data->itemList.takeAt(index);
292
int QwtDynGridLayout::count() const
294
return d_data->itemList.count();
297
void QwtDynGridLayout::setExpandingDirections(Qt::Orientations expanding)
299
d_data->expanding = expanding;
302
Qt::Orientations QwtDynGridLayout::expandingDirections() const
304
return d_data->expanding;
310
Reorganizes columns and rows and resizes managed widgets within
314
void QwtDynGridLayout::setGeometry(const QRect &rect)
316
QLayout::setGeometry(rect);
321
d_data->numCols = columnsForWidth(rect.width());
322
d_data->numRows = itemCount() / d_data->numCols;
323
if ( itemCount() % d_data->numCols )
326
#if QT_VERSION < 0x040000
327
QValueList<QRect> itemGeometries = layoutItems(rect, d_data->numCols);
329
QList<QRect> itemGeometries = layoutItems(rect, d_data->numCols);
333
for (PrivateData::LayoutItemList::iterator it = d_data->itemList.begin();
334
it != d_data->itemList.end(); ++it)
336
QWidget *w = (*it)->widget();
339
w->setGeometry(itemGeometries[index]);
346
Calculate the number of columns for a given width. It tries to
347
use as many columns as possible (limited by maxCols())
349
\param width Available width for all columns
350
\sa QwtDynGridLayout::maxCols(), QwtDynGridLayout::setMaxCols()
353
uint QwtDynGridLayout::columnsForWidth(int width) const
358
const int maxCols = (d_data->maxCols > 0) ? d_data->maxCols : itemCount();
359
if ( maxRowWidth(maxCols) <= width )
362
for (int numCols = 2; numCols <= maxCols; numCols++ )
364
const int rowWidth = maxRowWidth(numCols);
365
if ( rowWidth > width )
369
return 1; // At least 1 column
373
Calculate the width of a layout for a given number of
376
\param numCols Given number of columns
377
\param itemWidth Array of the width hints for all items
379
int QwtDynGridLayout::maxRowWidth(int numCols) const
383
QwtArray<int> colWidth(numCols);
384
for ( col = 0; col < (int)numCols; col++ )
387
if ( d_data->isDirty )
388
((QwtDynGridLayout*)this)->updateLayoutCache();
390
for ( uint index = 0;
391
index < (uint)d_data->itemSizeHints.count(); index++ )
393
col = index % numCols;
394
colWidth[col] = qwtMax(colWidth[col],
395
d_data->itemSizeHints[int(index)].width());
398
int rowWidth = 2 * margin() + (numCols - 1) * spacing();
399
for ( col = 0; col < (int)numCols; col++ )
400
rowWidth += colWidth[col];
406
\return the maximum width of all layout items
409
int QwtDynGridLayout::maxItemWidth() const
414
if ( d_data->isDirty )
415
((QwtDynGridLayout*)this)->updateLayoutCache();
418
for ( uint i = 0; i < (uint)d_data->itemSizeHints.count(); i++ )
420
const int itemW = d_data->itemSizeHints[int(i)].width();
429
Calculate the geometries of the layout items for a layout
430
with numCols columns and a given rect.
431
\param rect Rect where to place the items
432
\param numCols Number of columns
433
\return item geometries
436
#if QT_VERSION < 0x040000
437
QValueList<QRect> QwtDynGridLayout::layoutItems(const QRect &rect,
440
QList<QRect> QwtDynGridLayout::layoutItems(const QRect &rect,
444
#if QT_VERSION < 0x040000
445
QValueList<QRect> itemGeometries;
447
QList<QRect> itemGeometries;
449
if ( numCols == 0 || isEmpty() )
450
return itemGeometries;
452
uint numRows = itemCount() / numCols;
453
if ( numRows % itemCount() )
456
QwtArray<int> rowHeight(numRows);
457
QwtArray<int> colWidth(numCols);
459
layoutGrid(numCols, rowHeight, colWidth);
461
bool expandH, expandV;
462
#if QT_VERSION >= 0x040000
463
expandH = expandingDirections() & Qt::Horizontal;
464
expandV = expandingDirections() & Qt::Vertical;
466
expandH = expanding() & QSizePolicy::Horizontally;
467
expandV = expanding() & QSizePolicy::Vertically;
470
if ( expandH || expandV )
471
stretchGrid(rect, numCols, rowHeight, colWidth);
473
QwtDynGridLayout *that = (QwtDynGridLayout *)this;
474
const int maxCols = d_data->maxCols;
475
that->d_data->maxCols = numCols;
476
const QRect alignedRect = alignmentRect(rect);
477
that->d_data->maxCols = maxCols;
479
const int xOffset = expandH ? 0 : alignedRect.x();
480
const int yOffset = expandV ? 0 : alignedRect.y();
482
QwtArray<int> colX(numCols);
483
QwtArray<int> rowY(numRows);
485
const int xySpace = spacing();
487
rowY[0] = yOffset + margin();
488
for ( int r = 1; r < (int)numRows; r++ )
489
rowY[r] = rowY[r-1] + rowHeight[r-1] + xySpace;
491
colX[0] = xOffset + margin();
492
for ( int c = 1; c < (int)numCols; c++ )
493
colX[c] = colX[c-1] + colWidth[c-1] + xySpace;
495
const int itemCount = d_data->itemList.size();
496
for ( int i = 0; i < itemCount; i++ )
498
const int row = i / numCols;
499
const int col = i % numCols;
501
QRect itemGeometry(colX[col], rowY[row],
502
colWidth[col], rowHeight[row]);
503
itemGeometries.append(itemGeometry);
506
return itemGeometries;
511
Calculate the dimensions for the columns and rows for a grid
513
\param numCols Number of columns.
514
\param rowHeight Array where to fill in the calculated row heights.
515
\param colWidth Array where to fill in the calculated column widths.
518
void QwtDynGridLayout::layoutGrid(uint numCols,
519
QwtArray<int>& rowHeight, QwtArray<int>& colWidth) const
524
if ( d_data->isDirty )
525
((QwtDynGridLayout*)this)->updateLayoutCache();
527
for ( uint index = 0;
528
index < (uint)d_data->itemSizeHints.count(); index++ )
530
const int row = index / numCols;
531
const int col = index % numCols;
533
const QSize &size = d_data->itemSizeHints[int(index)];
535
rowHeight[row] = (col == 0)
536
? size.height() : qwtMax(rowHeight[row], size.height());
537
colWidth[col] = (row == 0)
538
? size.width() : qwtMax(colWidth[col], size.width());
543
\return true: QwtDynGridLayout implements heightForWidth.
544
\sa QwtDynGridLayout::heightForWidth()
547
bool QwtDynGridLayout::hasHeightForWidth() const
553
\return The preferred height for this layout, given the width w.
554
\sa QwtDynGridLayout::hasHeightForWidth()
557
int QwtDynGridLayout::heightForWidth(int width) const
562
const uint numCols = columnsForWidth(width);
563
uint numRows = itemCount() / numCols;
564
if ( itemCount() % numCols )
567
QwtArray<int> rowHeight(numRows);
568
QwtArray<int> colWidth(numCols);
570
layoutGrid(numCols, rowHeight, colWidth);
572
int h = 2 * margin() + (numRows - 1) * spacing();
573
for ( int row = 0; row < (int)numRows; row++ )
580
Stretch columns in case of expanding() & QSizePolicy::Horizontal and
581
rows in case of expanding() & QSizePolicy::Vertical to fill the entire
582
rect. Rows and columns are stretched with the same factor.
583
\sa QwtDynGridLayout::setExpanding(), QwtDynGridLayout::expanding()
586
void QwtDynGridLayout::stretchGrid(const QRect &rect,
587
uint numCols, QwtArray<int>& rowHeight, QwtArray<int>& colWidth) const
589
if ( numCols == 0 || isEmpty() )
592
bool expandH, expandV;
593
#if QT_VERSION >= 0x040000
594
expandH = expandingDirections() & Qt::Horizontal;
595
expandV = expandingDirections() & Qt::Vertical;
597
expandH = expanding() & QSizePolicy::Horizontally;
598
expandV = expanding() & QSizePolicy::Vertically;
603
int xDelta = rect.width() - 2 * margin() - (numCols - 1) * spacing();
604
for ( int col = 0; col < (int)numCols; col++ )
605
xDelta -= colWidth[col];
609
for ( int col = 0; col < (int)numCols; col++ )
611
const int space = xDelta / (numCols - col);
612
colWidth[col] += space;
620
uint numRows = itemCount() / numCols;
621
if ( itemCount() % numCols )
624
int yDelta = rect.height() - 2 * margin() - (numRows - 1) * spacing();
625
for ( int row = 0; row < (int)numRows; row++ )
626
yDelta -= rowHeight[row];
630
for ( int row = 0; row < (int)numRows; row++ )
632
const int space = yDelta / (numRows - row);
633
rowHeight[row] += space;
641
Return the size hint. If maxCols() > 0 it is the size for
642
a grid with maxCols() columns, otherwise it is the size for
643
a grid with only one row.
644
\sa QwtDynGridLayout::maxCols(), QwtDynGridLayout::setMaxCols()
647
QSize QwtDynGridLayout::sizeHint() const
652
const uint numCols = (d_data->maxCols > 0 ) ? d_data->maxCols : itemCount();
653
uint numRows = itemCount() / numCols;
654
if ( itemCount() % numCols )
657
QwtArray<int> rowHeight(numRows);
658
QwtArray<int> colWidth(numCols);
660
layoutGrid(numCols, rowHeight, colWidth);
662
int h = 2 * margin() + (numRows - 1) * spacing();
663
for ( int row = 0; row < (int)numRows; row++ )
666
int w = 2 * margin() + (numCols - 1) * spacing();
667
for ( int col = 0; col < (int)numCols; col++ )
674
\return Number of rows of the current layout.
675
\sa QwtDynGridLayout::numCols
676
\warning The number of rows might change whenever the geometry changes
678
uint QwtDynGridLayout::numRows() const
680
return d_data->numRows;
684
\return Number of columns of the current layout.
685
\sa QwtDynGridLayout::numRows
686
\warning The number of columns might change whenever the geometry changes
688
uint QwtDynGridLayout::numCols() const
690
return d_data->numCols;