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

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