Qwt User's Guide: qwt_dyngrid_layout.cpp Source File

Qwt User's Guide 6.2.0

qwt_dyngrid_layout.cpp
1 /******************************************************************************
2 * Qwt Widget Library
3 * Copyright (C) 1997 Josef Wilgen
4 * Copyright (C) 2002 Uwe Rathmann
5 *
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 *****************************************************************************/
9
10 #include "qwt_dyngrid_layout.h"
11
12 #include <qvector.h>
13 #include <qlist.h>
14
15 class QwtDynGridLayout::PrivateData
16 {
17 public:
18 PrivateData()
19 : isDirty( true )
20 {
21 }
22
23 void updateLayoutCache();
24
25 mutable QList< QLayoutItem* > itemList;
26
27 uint maxColumns;
28 uint numRows;
29 uint numColumns;
30
31 Qt::Orientations expanding;
32
33 bool isDirty;
34 QVector< QSize > itemSizeHints;
35 };
36
37 void QwtDynGridLayout::PrivateData::updateLayoutCache()
38 {
39 itemSizeHints.resize( itemList.count() );
40
41 int index = 0;
42
43 for ( QList< QLayoutItem* >::const_iterator it = itemList.constBegin();
44 it != itemList.constEnd(); ++it, index++ )
45 {
46 itemSizeHints[ index ] = ( *it )->sizeHint();
47 }
48
49 isDirty = false;
50 }
51
58 QwtDynGridLayout::QwtDynGridLayout( QWidget* parent, int margin, int spacing )
59 : QLayout( parent )
60 {
61 init();
62
63 setSpacing( spacing );
64 setContentsMargins( margin, margin, margin, margin );
65 }
66
71 QwtDynGridLayout::QwtDynGridLayout( int spacing )
72 {
73 init();
74 setSpacing( spacing );
75 }
76
80 void QwtDynGridLayout::init()
81 {
82 m_data = new QwtDynGridLayout::PrivateData;
83 m_data->maxColumns = m_data->numRows = m_data->numColumns = 0;
84 }
85
87
88 QwtDynGridLayout::~QwtDynGridLayout()
89 {
90 qDeleteAll( m_data->itemList );
91 delete m_data;
92 }
93
95 void QwtDynGridLayout::invalidate()
96 {
97 m_data->isDirty = true;
98 QLayout::invalidate();
99 }
100
106 void QwtDynGridLayout::setMaxColumns( uint maxColumns )
107 {
108 m_data->maxColumns = maxColumns;
109 }
110
119 uint QwtDynGridLayout::maxColumns() const
120 {
121 return m_data->maxColumns;
122 }
123
128 void QwtDynGridLayout::addItem( QLayoutItem* item )
129 {
130 m_data->itemList.append( item );
131 invalidate();
132 }
133
137 bool QwtDynGridLayout::isEmpty() const
138 {
139 return m_data->itemList.isEmpty();
140 }
141
145 uint QwtDynGridLayout::itemCount() const
146 {
147 return m_data->itemList.count();
148 }
149
157 QLayoutItem* QwtDynGridLayout::itemAt( int index ) const
158 {
159 if ( index < 0 || index >= m_data->itemList.count() )
160 return NULL;
161
162 return m_data->itemList.at( index );
163 }
164
172 QLayoutItem* QwtDynGridLayout::takeAt( int index )
173 {
174 if ( index < 0 || index >= m_data->itemList.count() )
175 return NULL;
176
177 m_data->isDirty = true;
178 return m_data->itemList.takeAt( index );
179 }
180
182 int QwtDynGridLayout::count() const
183 {
184 return m_data->itemList.count();
185 }
186
196 void QwtDynGridLayout::setExpandingDirections( Qt::Orientations expanding )
197 {
198 m_data->expanding = expanding;
199 }
200
211 Qt::Orientations QwtDynGridLayout::expandingDirections() const
212 {
213 return m_data->expanding;
214 }
215
222 void QwtDynGridLayout::setGeometry( const QRect& rect )
223 {
224 QLayout::setGeometry( rect );
225
226 if ( isEmpty() )
227 return;
228
229 m_data->numColumns = columnsForWidth( rect.width() );
230 m_data->numRows = itemCount() / m_data->numColumns;
231 if ( itemCount() % m_data->numColumns )
232 m_data->numRows++;
233
234 const QList< QRect > itemGeometries = layoutItems( rect, m_data->numColumns );
235
236 int index = 0;
237 for ( QList< QLayoutItem* >::const_iterator it = m_data->itemList.constBegin();
238 it != m_data->itemList.constEnd(); ++it )
239 {
240 ( *it )->setGeometry( itemGeometries[index] );
241 index++;
242 }
243 }
244
256 uint QwtDynGridLayout::columnsForWidth( int width ) const
257 {
258 if ( isEmpty() )
259 return 0;
260
261 uint maxColumns = itemCount();
262 if ( m_data->maxColumns > 0 )
263 maxColumns = qMin( m_data->maxColumns, maxColumns );
264
265 if ( maxRowWidth( maxColumns ) <= width )
266 return maxColumns;
267
268 for ( uint numColumns = 2; numColumns <= maxColumns; numColumns++ )
269 {
270 const int rowWidth = maxRowWidth( numColumns );
271 if ( rowWidth > width )
272 return numColumns - 1;
273 }
274
275 return 1; // At least 1 column
276 }
277
285 int QwtDynGridLayout::maxRowWidth( int numColumns ) const
286 {
287 int col;
288
289 QVector< int > colWidth( numColumns );
290 for ( col = 0; col < numColumns; col++ )
291 colWidth[col] = 0;
292
293 if ( m_data->isDirty )
294 m_data->updateLayoutCache();
295
296 for ( int index = 0;
297 index < m_data->itemSizeHints.count(); index++ )
298 {
299 col = index % numColumns;
300 colWidth[col] = qMax( colWidth[col],
301 m_data->itemSizeHints[index].width() );
302 }
303
304 const QMargins m = contentsMargins();
305
306 int rowWidth = m.left() + m.right() + ( numColumns - 1 ) * spacing();
307 for ( col = 0; col < numColumns; col++ )
308 rowWidth += colWidth[col];
309
310 return rowWidth;
311 }
312
316 int QwtDynGridLayout::maxItemWidth() const
317 {
318 if ( isEmpty() )
319 return 0;
320
321 if ( m_data->isDirty )
322 m_data->updateLayoutCache();
323
324 int w = 0;
325 for ( int i = 0; i < m_data->itemSizeHints.count(); i++ )
326 {
327 const int itemW = m_data->itemSizeHints[i].width();
328 if ( itemW > w )
329 w = itemW;
330 }
331
332 return w;
333 }
334
344 QList< QRect > QwtDynGridLayout::layoutItems( const QRect& rect,
345 uint numColumns ) const
346 {
347 QList< QRect > itemGeometries;
348 if ( numColumns == 0 || isEmpty() )
349 return itemGeometries;
350
351 uint numRows = itemCount() / numColumns;
352 if ( numColumns % itemCount() )
353 numRows++;
354
355 if ( numRows == 0 )
356 return itemGeometries;
357
358 QVector< int > rowHeight( numRows );
359 QVector< int > colWidth( numColumns );
360
361 layoutGrid( numColumns, rowHeight, colWidth );
362
363 bool expandH, expandV;
364 expandH = expandingDirections() & Qt::Horizontal;
365 expandV = expandingDirections() & Qt::Vertical;
366
367 if ( expandH || expandV )
368 stretchGrid( rect, numColumns, rowHeight, colWidth );
369
370 const int maxColumns = m_data->maxColumns;
371 m_data->maxColumns = numColumns;
372 const QRect alignedRect = alignmentRect( rect );
373 m_data->maxColumns = maxColumns;
374
375 const int xOffset = expandH ? 0 : alignedRect.x();
376 const int yOffset = expandV ? 0 : alignedRect.y();
377
378 QVector< int > colX( numColumns );
379 QVector< int > rowY( numRows );
380
381 const int xySpace = spacing();
382
383 const QMargins m = contentsMargins();
384
385 rowY[0] = yOffset + m.top();
386 for ( uint r = 1; r < numRows; r++ )
387 rowY[r] = rowY[r - 1] + rowHeight[r - 1] + xySpace;
388
389 colX[0] = xOffset + m.left();
390 for ( uint c = 1; c < numColumns; c++ )
391 colX[c] = colX[c - 1] + colWidth[c - 1] + xySpace;
392
393 const int itemCount = m_data->itemList.size();
394 itemGeometries.reserve( itemCount );
395
396 for ( int i = 0; i < itemCount; i++ )
397 {
398 const int row = i / numColumns;
399 const int col = i % numColumns;
400
401 const QRect itemGeometry( colX[col], rowY[row],
402 colWidth[col], rowHeight[row] );
403 itemGeometries.append( itemGeometry );
404 }
405
406 return itemGeometries;
407 }
408
409
419 void QwtDynGridLayout::layoutGrid( uint numColumns,
420 QVector< int >& rowHeight, QVector< int >& colWidth ) const
421 {
422 if ( numColumns <= 0 )
423 return;
424
425 if ( m_data->isDirty )
426 m_data->updateLayoutCache();
427
428 for ( int index = 0; index < m_data->itemSizeHints.count(); index++ )
429 {
430 const int row = index / numColumns;
431 const int col = index % numColumns;
432
433 const QSize& size = m_data->itemSizeHints[index];
434
435 rowHeight[row] = ( col == 0 )
436 ? size.height() : qMax( rowHeight[row], size.height() );
437 colWidth[col] = ( row == 0 )
438 ? size.width() : qMax( colWidth[col], size.width() );
439 }
440 }
441
446 bool QwtDynGridLayout::hasHeightForWidth() const
447 {
448 return true;
449 }
450
455 int QwtDynGridLayout::heightForWidth( int width ) const
456 {
457 if ( isEmpty() )
458 return 0;
459
460 const uint numColumns = columnsForWidth( width );
461 uint numRows = itemCount() / numColumns;
462 if ( itemCount() % numColumns )
463 numRows++;
464
465 QVector< int > rowHeight( numRows );
466 QVector< int > colWidth( numColumns );
467
468 layoutGrid( numColumns, rowHeight, colWidth );
469
470 const QMargins m = contentsMargins();
471
472 int h = m.top() + m.bottom() + ( numRows - 1 ) * spacing();
473 for ( uint row = 0; row < numRows; row++ )
474 h += rowHeight[row];
475
476 return h;
477 }
478
491 void QwtDynGridLayout::stretchGrid( const QRect& rect,
492 uint numColumns, QVector< int >& rowHeight, QVector< int >& colWidth ) const
493 {
494 if ( numColumns == 0 || isEmpty() )
495 return;
496
497 bool expandH, expandV;
498 expandH = expandingDirections() & Qt::Horizontal;
499 expandV = expandingDirections() & Qt::Vertical;
500
501 const QMargins m = contentsMargins();
502
503 if ( expandH )
504 {
505 int xDelta = rect.width() - m.left() - m.right() - ( numColumns - 1 ) * spacing();
506 for ( uint col = 0; col < numColumns; col++ )
507 xDelta -= colWidth[col];
508
509 if ( xDelta > 0 )
510 {
511 for ( uint col = 0; col < numColumns; col++ )
512 {
513 const int space = xDelta / ( numColumns - col );
514 colWidth[col] += space;
515 xDelta -= space;
516 }
517 }
518 }
519
520 if ( expandV )
521 {
522 uint numRows = itemCount() / numColumns;
523 if ( itemCount() % numColumns )
524 numRows++;
525
526 int yDelta = rect.height() - m.top() - m.bottom() - ( numRows - 1 ) * spacing();
527 for ( uint row = 0; row < numRows; row++ )
528 yDelta -= rowHeight[row];
529
530 if ( yDelta > 0 )
531 {
532 for ( uint row = 0; row < numRows; row++ )
533 {
534 const int space = yDelta / ( numRows - row );
535 rowHeight[row] += space;
536 yDelta -= space;
537 }
538 }
539 }
540 }
541
550 QSize QwtDynGridLayout::sizeHint() const
551 {
552 if ( isEmpty() )
553 return QSize();
554
555 uint numColumns = itemCount();
556 if ( m_data->maxColumns > 0 )
557 numColumns = qMin( m_data->maxColumns, numColumns );
558
559 uint numRows = itemCount() / numColumns;
560 if ( itemCount() % numColumns )
561 numRows++;
562
563 QVector< int > rowHeight( numRows );
564 QVector< int > colWidth( numColumns );
565
566 layoutGrid( numColumns, rowHeight, colWidth );
567
568 const QMargins m = contentsMargins();
569
570 int h = m.top() + m.bottom() + ( numRows - 1 ) * spacing();
571 for ( uint row = 0; row < numRows; row++ )
572 h += rowHeight[row];
573
574 int w = m.left() + m.right() + ( numColumns - 1 ) * spacing();
575 for ( uint col = 0; col < numColumns; col++ )
576 w += colWidth[col];
577
578 return QSize( w, h );
579 }
580
586 uint QwtDynGridLayout::numRows() const
587 {
588 return m_data->numRows;
589 }
590
596 uint QwtDynGridLayout::numColumns() const
597 {
598 return m_data->numColumns;
599 }
600
601 #if QWT_MOC_INCLUDE
602 #include "moc_qwt_dyngrid_layout.cpp"
603 #endif
QList< QLayoutItem * >
QVector< QSize >
QwtDynGridLayout::layoutGrid
void layoutGrid(uint numColumns, QVector< int > &rowHeight, QVector< int > &colWidth) const
Definition: qwt_dyngrid_layout.cpp:419
QwtDynGridLayout::heightForWidth
virtual int heightForWidth(int) const override
Definition: qwt_dyngrid_layout.cpp:455
QwtDynGridLayout::itemAt
virtual QLayoutItem * itemAt(int index) const override
Definition: qwt_dyngrid_layout.cpp:157
QwtDynGridLayout::columnsForWidth
virtual uint columnsForWidth(int width) const
Calculate the number of columns for a given width.
Definition: qwt_dyngrid_layout.cpp:256
QwtDynGridLayout::isEmpty
virtual bool isEmpty() const override
Definition: qwt_dyngrid_layout.cpp:137
QwtDynGridLayout::takeAt
virtual QLayoutItem * takeAt(int index) override
Definition: qwt_dyngrid_layout.cpp:172
QwtDynGridLayout::maxItemWidth
virtual int maxItemWidth() const
Definition: qwt_dyngrid_layout.cpp:316
QwtDynGridLayout::setExpandingDirections
void setExpandingDirections(Qt::Orientations)
Definition: qwt_dyngrid_layout.cpp:196
QwtDynGridLayout::sizeHint
virtual QSize sizeHint() const override
Definition: qwt_dyngrid_layout.cpp:550
QwtDynGridLayout::expandingDirections
virtual Qt::Orientations expandingDirections() const override
Returns whether this layout can make use of more space than sizeHint().
Definition: qwt_dyngrid_layout.cpp:211
QwtDynGridLayout::maxColumns
uint maxColumns() const
Return the upper limit for the number of columns.
Definition: qwt_dyngrid_layout.cpp:119
QwtDynGridLayout::stretchGrid
void stretchGrid(const QRect &rect, uint numColumns, QVector< int > &rowHeight, QVector< int > &colWidth) const
Definition: qwt_dyngrid_layout.cpp:491
QwtDynGridLayout::numColumns
uint numColumns() const
Definition: qwt_dyngrid_layout.cpp:596
QwtDynGridLayout::setMaxColumns
void setMaxColumns(uint maxColumns)
Definition: qwt_dyngrid_layout.cpp:106
QwtDynGridLayout::numRows
uint numRows() const
Definition: qwt_dyngrid_layout.cpp:586
QwtDynGridLayout::addItem
virtual void addItem(QLayoutItem *) override
Add an item to the next free position.
Definition: qwt_dyngrid_layout.cpp:128
QwtDynGridLayout::layoutItems
QList< QRect > layoutItems(const QRect &, uint numColumns) const
Definition: qwt_dyngrid_layout.cpp:344
QwtDynGridLayout::setGeometry
virtual void setGeometry(const QRect &) override
Definition: qwt_dyngrid_layout.cpp:222
QwtDynGridLayout::~QwtDynGridLayout
virtual ~QwtDynGridLayout()
Destructor.
Definition: qwt_dyngrid_layout.cpp:88
QwtDynGridLayout::itemCount
uint itemCount() const
Definition: qwt_dyngrid_layout.cpp:145
QwtDynGridLayout::QwtDynGridLayout
QwtDynGridLayout(QWidget *, int margin=0, int spacing=-1)
Definition: qwt_dyngrid_layout.cpp:58
QwtDynGridLayout::hasHeightForWidth
virtual bool hasHeightForWidth() const override
Definition: qwt_dyngrid_layout.cpp:446
QwtDynGridLayout::count
virtual int count() const override
Definition: qwt_dyngrid_layout.cpp:182
QwtDynGridLayout::invalidate
virtual void invalidate() override
Invalidate all internal caches.
Definition: qwt_dyngrid_layout.cpp:95