source: ntrip/trunk/BNC/qwt/qwt_dyngrid_layout.cpp@ 8541

Last change on this file since 8541 was 8127, checked in by stoecker, 8 years ago

update qwt and qwtpolar, many QT5 fixes (unfinished)

File size: 14.1 KB
Line 
1/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
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#include "qwt_math.h"
12#include <qvector.h>
13#include <qlist.h>
14
15class QwtDynGridLayout::PrivateData
16{
17public:
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*>::iterator it = itemList.begin();
44 it != itemList.end(); ++it, index++ )
45 {
46 itemSizeHints[ index ] = ( *it )->sizeHint();
47 }
48
49 isDirty = false;
50}
51
52/*!
53 \param parent Parent widget
54 \param margin Margin
55 \param spacing Spacing
56*/
57
58QwtDynGridLayout::QwtDynGridLayout( QWidget *parent,
59 int margin, int spacing ):
60 QLayout( parent )
61{
62 init();
63
64 setSpacing( spacing );
65 setMargin( margin );
66}
67
68/*!
69 \param spacing Spacing
70*/
71
72QwtDynGridLayout::QwtDynGridLayout( int spacing )
73{
74 init();
75 setSpacing( spacing );
76}
77
78/*!
79 Initialize the layout with default values.
80*/
81void QwtDynGridLayout::init()
82{
83 d_data = new QwtDynGridLayout::PrivateData;
84 d_data->maxColumns = d_data->numRows = d_data->numColumns = 0;
85 d_data->expanding = 0;
86}
87
88//! Destructor
89
90QwtDynGridLayout::~QwtDynGridLayout()
91{
92 for ( int i = 0; i < d_data->itemList.size(); i++ )
93 delete d_data->itemList[i];
94
95 delete d_data;
96}
97
98//! Invalidate all internal caches
99void QwtDynGridLayout::invalidate()
100{
101 d_data->isDirty = true;
102 QLayout::invalidate();
103}
104
105/*!
106 Limit the number of columns.
107 \param maxColumns upper limit, 0 means unlimited
108 \sa maxColumns()
109*/
110void QwtDynGridLayout::setMaxColumns( uint maxColumns )
111{
112 d_data->maxColumns = maxColumns;
113}
114
115/*!
116 \brief Return the upper limit for the number of columns.
117
118 0 means unlimited, what is the default.
119
120 \return Upper limit for the number of columns
121 \sa setMaxColumns()
122*/
123uint QwtDynGridLayout::maxColumns() const
124{
125 return d_data->maxColumns;
126}
127
128/*!
129 \brief Add an item to the next free position.
130 \param item Layout item
131 */
132void QwtDynGridLayout::addItem( QLayoutItem *item )
133{
134 d_data->itemList.append( item );
135 invalidate();
136}
137
138/*!
139 \return true if this layout is empty.
140*/
141bool QwtDynGridLayout::isEmpty() const
142{
143 return d_data->itemList.isEmpty();
144}
145
146/*!
147 \return number of layout items
148*/
149uint QwtDynGridLayout::itemCount() const
150{
151 return d_data->itemList.count();
152}
153
154/*!
155 Find the item at a specific index
156
157 \param index Index
158 \return Item at a specific index
159 \sa takeAt()
160*/
161QLayoutItem *QwtDynGridLayout::itemAt( int index ) const
162{
163 if ( index < 0 || index >= d_data->itemList.count() )
164 return NULL;
165
166 return d_data->itemList.at( index );
167}
168
169/*!
170 Find the item at a specific index and remove it from the layout
171
172 \param index Index
173 \return Layout item, removed from the layout
174 \sa itemAt()
175*/
176QLayoutItem *QwtDynGridLayout::takeAt( int index )
177{
178 if ( index < 0 || index >= d_data->itemList.count() )
179 return NULL;
180
181 d_data->isDirty = true;
182 return d_data->itemList.takeAt( index );
183}
184
185//! \return Number of items in the layout
186int QwtDynGridLayout::count() const
187{
188 return d_data->itemList.count();
189}
190
191/*!
192 Set whether this layout can make use of more space than sizeHint().
193 A value of Qt::Vertical or Qt::Horizontal means that it wants to grow in only
194 one dimension, while Qt::Vertical | Qt::Horizontal means that it wants
195 to grow in both dimensions. The default value is 0.
196
197 \param expanding Or'd orientations
198 \sa expandingDirections()
199*/
200void QwtDynGridLayout::setExpandingDirections( Qt::Orientations expanding )
201{
202 d_data->expanding = expanding;
203}
204
205/*!
206 \brief Returns whether this layout can make use of more space than sizeHint().
207
208 A value of Qt::Vertical or Qt::Horizontal means that it wants to grow in only
209 one dimension, while Qt::Vertical | Qt::Horizontal means that it wants
210 to grow in both dimensions.
211
212 \return Orientations, where the layout expands
213 \sa setExpandingDirections()
214*/
215Qt::Orientations QwtDynGridLayout::expandingDirections() const
216{
217 return d_data->expanding;
218}
219
220/*!
221 Reorganizes columns and rows and resizes managed items within
222 a rectangle.
223
224 \param rect Layout geometry
225*/
226void QwtDynGridLayout::setGeometry( const QRect &rect )
227{
228 QLayout::setGeometry( rect );
229
230 if ( isEmpty() )
231 return;
232
233 d_data->numColumns = columnsForWidth( rect.width() );
234 d_data->numRows = itemCount() / d_data->numColumns;
235 if ( itemCount() % d_data->numColumns )
236 d_data->numRows++;
237
238 QList<QRect> itemGeometries = layoutItems( rect, d_data->numColumns );
239
240 int index = 0;
241 for ( QList<QLayoutItem*>::iterator it = d_data->itemList.begin();
242 it != d_data->itemList.end(); ++it )
243 {
244 ( *it )->setGeometry( itemGeometries[index] );
245 index++;
246 }
247}
248
249/*!
250 \brief Calculate the number of columns for a given width.
251
252 The calculation tries to use as many columns as possible
253 ( limited by maxColumns() )
254
255 \param width Available width for all columns
256 \return Number of columns for a given width
257
258 \sa maxColumns(), setMaxColumns()
259*/
260uint QwtDynGridLayout::columnsForWidth( int width ) const
261{
262 if ( isEmpty() )
263 return 0;
264
265 uint maxColumns = itemCount();
266 if ( d_data->maxColumns > 0 )
267 maxColumns = qMin( d_data->maxColumns, maxColumns );
268
269 if ( maxRowWidth( maxColumns ) <= width )
270 return maxColumns;
271
272 for ( uint numColumns = 2; numColumns <= maxColumns; numColumns++ )
273 {
274 const int rowWidth = maxRowWidth( numColumns );
275 if ( rowWidth > width )
276 return numColumns - 1;
277 }
278
279 return 1; // At least 1 column
280}
281
282/*!
283 Calculate the width of a layout for a given number of
284 columns.
285
286 \param numColumns Given number of columns
287 \param itemWidth Array of the width hints for all items
288*/
289int QwtDynGridLayout::maxRowWidth( int numColumns ) const
290{
291 int col;
292
293 QVector<int> colWidth( numColumns );
294 for ( col = 0; col < numColumns; col++ )
295 colWidth[col] = 0;
296
297 if ( d_data->isDirty )
298 d_data->updateLayoutCache();
299
300 for ( int index = 0;
301 index < d_data->itemSizeHints.count(); index++ )
302 {
303 col = index % numColumns;
304 colWidth[col] = qMax( colWidth[col],
305 d_data->itemSizeHints[int( index )].width() );
306 }
307
308 int rowWidth = 2 * margin() + ( numColumns - 1 ) * spacing();
309 for ( col = 0; col < numColumns; col++ )
310 rowWidth += colWidth[col];
311
312 return rowWidth;
313}
314
315/*!
316 \return the maximum width of all layout items
317*/
318int QwtDynGridLayout::maxItemWidth() const
319{
320 if ( isEmpty() )
321 return 0;
322
323 if ( d_data->isDirty )
324 d_data->updateLayoutCache();
325
326 int w = 0;
327 for ( int i = 0; i < d_data->itemSizeHints.count(); i++ )
328 {
329 const int itemW = d_data->itemSizeHints[i].width();
330 if ( itemW > w )
331 w = itemW;
332 }
333
334 return w;
335}
336
337/*!
338 Calculate the geometries of the layout items for a layout
339 with numColumns columns and a given rectangle.
340
341 \param rect Rect where to place the items
342 \param numColumns Number of columns
343 \return item geometries
344*/
345
346QList<QRect> QwtDynGridLayout::layoutItems( const QRect &rect,
347 uint numColumns ) const
348{
349 QList<QRect> itemGeometries;
350 if ( numColumns == 0 || isEmpty() )
351 return itemGeometries;
352
353 uint numRows = itemCount() / numColumns;
354 if ( numColumns % itemCount() )
355 numRows++;
356
357 if ( numRows == 0 )
358 return itemGeometries;
359
360 QVector<int> rowHeight( numRows );
361 QVector<int> colWidth( numColumns );
362
363 layoutGrid( numColumns, rowHeight, colWidth );
364
365 bool expandH, expandV;
366 expandH = expandingDirections() & Qt::Horizontal;
367 expandV = expandingDirections() & Qt::Vertical;
368
369 if ( expandH || expandV )
370 stretchGrid( rect, numColumns, rowHeight, colWidth );
371
372 const int maxColumns = d_data->maxColumns;
373 d_data->maxColumns = numColumns;
374 const QRect alignedRect = alignmentRect( rect );
375 d_data->maxColumns = maxColumns;
376
377 const int xOffset = expandH ? 0 : alignedRect.x();
378 const int yOffset = expandV ? 0 : alignedRect.y();
379
380 QVector<int> colX( numColumns );
381 QVector<int> rowY( numRows );
382
383 const int xySpace = spacing();
384
385 rowY[0] = yOffset + margin();
386 for ( uint r = 1; r < numRows; r++ )
387 rowY[r] = rowY[r-1] + rowHeight[r-1] + xySpace;
388
389 colX[0] = xOffset + margin();
390 for ( uint c = 1; c < numColumns; c++ )
391 colX[c] = colX[c-1] + colWidth[c-1] + xySpace;
392
393 const int itemCount = d_data->itemList.size();
394 for ( int i = 0; i < itemCount; i++ )
395 {
396 const int row = i / numColumns;
397 const int col = i % numColumns;
398
399 QRect itemGeometry( colX[col], rowY[row],
400 colWidth[col], rowHeight[row] );
401 itemGeometries.append( itemGeometry );
402 }
403
404 return itemGeometries;
405}
406
407
408/*!
409 Calculate the dimensions for the columns and rows for a grid
410 of numColumns columns.
411
412 \param numColumns Number of columns.
413 \param rowHeight Array where to fill in the calculated row heights.
414 \param colWidth Array where to fill in the calculated column widths.
415*/
416
417void QwtDynGridLayout::layoutGrid( uint numColumns,
418 QVector<int>& rowHeight, QVector<int>& colWidth ) const
419{
420 if ( numColumns <= 0 )
421 return;
422
423 if ( d_data->isDirty )
424 d_data->updateLayoutCache();
425
426 for ( int index = 0; index < d_data->itemSizeHints.count(); index++ )
427 {
428 const int row = index / numColumns;
429 const int col = index % numColumns;
430
431 const QSize &size = d_data->itemSizeHints[int( index )];
432
433 rowHeight[row] = ( col == 0 )
434 ? size.height() : qMax( rowHeight[row], size.height() );
435 colWidth[col] = ( row == 0 )
436 ? size.width() : qMax( colWidth[col], size.width() );
437 }
438}
439
440/*!
441 \return true: QwtDynGridLayout implements heightForWidth().
442 \sa heightForWidth()
443*/
444bool QwtDynGridLayout::hasHeightForWidth() const
445{
446 return true;
447}
448
449/*!
450 \return The preferred height for this layout, given a width.
451 \sa hasHeightForWidth()
452*/
453int QwtDynGridLayout::heightForWidth( int width ) const
454{
455 if ( isEmpty() )
456 return 0;
457
458 const uint numColumns = columnsForWidth( width );
459 uint numRows = itemCount() / numColumns;
460 if ( itemCount() % numColumns )
461 numRows++;
462
463 QVector<int> rowHeight( numRows );
464 QVector<int> colWidth( numColumns );
465
466 layoutGrid( numColumns, rowHeight, colWidth );
467
468 int h = 2 * margin() + ( numRows - 1 ) * spacing();
469 for ( uint row = 0; row < numRows; row++ )
470 h += rowHeight[row];
471
472 return h;
473}
474
475/*!
476 Stretch columns in case of expanding() & QSizePolicy::Horizontal and
477 rows in case of expanding() & QSizePolicy::Vertical to fill the entire
478 rect. Rows and columns are stretched with the same factor.
479
480 \param rect Bounding rectangle
481 \param numColumns Number of columns
482 \param rowHeight Array to be filled with the calculated row heights
483 \param colWidth Array to be filled with the calculated column widths
484
485 \sa setExpanding(), expanding()
486*/
487void QwtDynGridLayout::stretchGrid( const QRect &rect,
488 uint numColumns, QVector<int>& rowHeight, QVector<int>& colWidth ) const
489{
490 if ( numColumns == 0 || isEmpty() )
491 return;
492
493 bool expandH, expandV;
494 expandH = expandingDirections() & Qt::Horizontal;
495 expandV = expandingDirections() & Qt::Vertical;
496
497 if ( expandH )
498 {
499 int xDelta = rect.width() - 2 * margin() - ( numColumns - 1 ) * spacing();
500 for ( uint col = 0; col < numColumns; col++ )
501 xDelta -= colWidth[col];
502
503 if ( xDelta > 0 )
504 {
505 for ( uint col = 0; col < numColumns; col++ )
506 {
507 const int space = xDelta / ( numColumns - col );
508 colWidth[col] += space;
509 xDelta -= space;
510 }
511 }
512 }
513
514 if ( expandV )
515 {
516 uint numRows = itemCount() / numColumns;
517 if ( itemCount() % numColumns )
518 numRows++;
519
520 int yDelta = rect.height() - 2 * margin() - ( numRows - 1 ) * spacing();
521 for ( uint row = 0; row < numRows; row++ )
522 yDelta -= rowHeight[row];
523
524 if ( yDelta > 0 )
525 {
526 for ( uint row = 0; row < numRows; row++ )
527 {
528 const int space = yDelta / ( numRows - row );
529 rowHeight[row] += space;
530 yDelta -= space;
531 }
532 }
533 }
534}
535
536/*!
537 Return the size hint. If maxColumns() > 0 it is the size for
538 a grid with maxColumns() columns, otherwise it is the size for
539 a grid with only one row.
540
541 \return Size hint
542 \sa maxColumns(), setMaxColumns()
543*/
544QSize QwtDynGridLayout::sizeHint() const
545{
546 if ( isEmpty() )
547 return QSize();
548
549 uint numColumns = itemCount();
550 if ( d_data->maxColumns > 0 )
551 numColumns = qMin( d_data->maxColumns, numColumns );
552
553 uint numRows = itemCount() / numColumns;
554 if ( itemCount() % numColumns )
555 numRows++;
556
557 QVector<int> rowHeight( numRows );
558 QVector<int> colWidth( numColumns );
559
560 layoutGrid( numColumns, rowHeight, colWidth );
561
562 int h = 2 * margin() + ( numRows - 1 ) * spacing();
563 for ( uint row = 0; row < numRows; row++ )
564 h += rowHeight[row];
565
566 int w = 2 * margin() + ( numColumns - 1 ) * spacing();
567 for ( uint col = 0; col < numColumns; col++ )
568 w += colWidth[col];
569
570 return QSize( w, h );
571}
572
573/*!
574 \return Number of rows of the current layout.
575 \sa numColumns()
576 \warning The number of rows might change whenever the geometry changes
577*/
578uint QwtDynGridLayout::numRows() const
579{
580 return d_data->numRows;
581}
582
583/*!
584 \return Number of columns of the current layout.
585 \sa numRows()
586 \warning The number of columns might change whenever the geometry changes
587*/
588uint QwtDynGridLayout::numColumns() const
589{
590 return d_data->numColumns;
591}
Note: See TracBrowser for help on using the repository browser.