Qwt User's Guide 6.3.0
Loading...
Searching...
No Matches
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
15class 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
37void 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
58QwtDynGridLayout::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
72{
73 init();
74 setSpacing( spacing );
75}
76
80void QwtDynGridLayout::init()
81{
82 m_data = new QwtDynGridLayout::PrivateData;
83 m_data->maxColumns = m_data->numRows = m_data->numColumns = 0;
84}
85
87
89{
90 qDeleteAll( m_data->itemList );
91 delete m_data;
92}
93
96{
97 m_data->isDirty = true;
98 QLayout::invalidate();
99}
100
106void QwtDynGridLayout::setMaxColumns( uint maxColumns )
107{
108 m_data->maxColumns = maxColumns;
109}
110
120{
121 return m_data->maxColumns;
122}
123
128void QwtDynGridLayout::addItem( QLayoutItem* item )
129{
130 m_data->itemList.append( item );
131 invalidate();
132}
133
138{
139 return m_data->itemList.isEmpty();
140}
141
146{
147 return m_data->itemList.count();
148}
149
157QLayoutItem* 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
172QLayoutItem* 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
183{
184 return m_data->itemList.count();
185}
186
196void QwtDynGridLayout::setExpandingDirections( Qt::Orientations expanding )
197{
198 m_data->expanding = expanding;
199}
200
212{
213 return m_data->expanding;
214}
215
222void 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
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
285int 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
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
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
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
419void 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
447{
448 return true;
449}
450
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
491void 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
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
587{
588 return m_data->numRows;
589}
590
597{
598 return m_data->numColumns;
599}
600
601#include "moc_qwt_dyngrid_layout.cpp"
void layoutGrid(uint numColumns, QVector< int > &rowHeight, QVector< int > &colWidth) const
virtual int heightForWidth(int) const override
virtual QLayoutItem * itemAt(int index) const override
virtual uint columnsForWidth(int width) const
Calculate the number of columns for a given width.
virtual bool isEmpty() const override
virtual QLayoutItem * takeAt(int index) override
virtual int maxItemWidth() const
void setExpandingDirections(Qt::Orientations)
virtual QSize sizeHint() const override
virtual Qt::Orientations expandingDirections() const override
Returns whether this layout can make use of more space than sizeHint().
uint maxColumns() const
Return the upper limit for the number of columns.
void stretchGrid(const QRect &rect, uint numColumns, QVector< int > &rowHeight, QVector< int > &colWidth) const
void setMaxColumns(uint maxColumns)
virtual void addItem(QLayoutItem *) override
Add an item to the next free position.
QList< QRect > layoutItems(const QRect &, uint numColumns) const
virtual void setGeometry(const QRect &) override
virtual ~QwtDynGridLayout()
Destructor.
QwtDynGridLayout(QWidget *, int margin=0, int spacing=-1)
virtual bool hasHeightForWidth() const override
virtual int count() const override
virtual void invalidate() override
Invalidate all internal caches.