source: vendor/trolltech/current/src/kernel/qlayout.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 72.4 KB
Line 
1/****************************************************************************
2** $Id: qlayout.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of layout classes
5**
6** Created : 960416
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qlayout.h"
39
40#ifndef QT_NO_LAYOUT
41
42#include "qapplication.h"
43#include "qwidget.h"
44#include "qptrlist.h"
45#include "qsizepolicy.h"
46
47#include "qlayoutengine_p.h"
48
49/*
50 Three internal classes related to QGridLayout: (1) QGridBox is a
51 QLayoutItem with (row, column) information; (2) QGridMultiBox is a
52 QGridBox with (torow, tocolumn) information; (3) QGridLayoutData is
53 the internal representation of a QGridLayout.
54*/
55
56class QGridBox
57{
58public:
59 QGridBox( QLayoutItem *lit ) { item_ = lit; }
60
61 QGridBox( QWidget *wid ) { item_ = new QWidgetItem( wid ); }
62 QGridBox( int w, int h, QSizePolicy::SizeType hData = QSizePolicy::Minimum,
63 QSizePolicy::SizeType vData = QSizePolicy::Minimum )
64 { item_ = new QSpacerItem( w, h, hData, vData ); }
65 ~QGridBox() { delete item_; }
66
67 QSize sizeHint() const { return item_->sizeHint(); }
68 QSize minimumSize() const { return item_->minimumSize(); }
69 QSize maximumSize() const { return item_->maximumSize(); }
70 QSizePolicy::ExpandData expanding() const { return item_->expanding(); }
71 bool isEmpty() const { return item_->isEmpty(); }
72
73 bool hasHeightForWidth() const { return item_->hasHeightForWidth(); }
74 int heightForWidth( int w ) const { return item_->heightForWidth(w); }
75
76 void setAlignment( int a ) { item_->setAlignment( a ); }
77 void setGeometry( const QRect &r ) { item_->setGeometry( r ); }
78 int alignment() const { return item_->alignment(); }
79 QLayoutItem *item() { return item_; }
80 QLayoutItem *takeItem() { QLayoutItem *i = item_; item_ = 0; return i; }
81
82 int hStretch() { return item_->widget() ?
83 item_->widget()->sizePolicy().horStretch() : 0; }
84 int vStretch() { return item_->widget() ?
85 item_->widget()->sizePolicy().verStretch() : 0; }
86
87private:
88 friend class QGridLayoutData;
89 friend class QGridLayoutDataIterator;
90
91 QLayoutItem *item_;
92 int row, col;
93};
94
95class QGridMultiBox
96{
97public:
98 QGridMultiBox( QGridBox *box, int toRow, int toCol )
99 : box_( box ), torow( toRow ), tocol( toCol ) { }
100 ~QGridMultiBox() { delete box_; }
101 QGridBox *box() { return box_; }
102 QLayoutItem *takeItem() { return box_->takeItem(); }
103
104private:
105 friend class QGridLayoutData;
106 friend class QGridLayoutDataIterator;
107
108 QGridBox *box_;
109 int torow, tocol;
110};
111
112class QGridLayoutData
113{
114public:
115 QGridLayoutData();
116 QGridLayoutData( int nRows, int nCols );
117 ~QGridLayoutData();
118
119 void add( QGridBox*, int row, int col );
120 void add( QGridBox*, int row1, int row2, int col1, int col2 );
121 QSize sizeHint( int ) const;
122 QSize minimumSize( int ) const;
123 QSize maximumSize( int ) const;
124
125 QSizePolicy::ExpandData expanding( int spacing );
126
127 void distribute( QRect, int );
128 inline int numRows() const { return rr; }
129 inline int numCols() const { return cc; }
130 inline void expand( int rows, int cols )
131 { setSize( QMAX(rows, rr), QMAX(cols, cc) ); }
132 inline void setRowStretch( int r, int s )
133 { expand( r + 1, 0 ); rStretch[r] = s; setDirty(); }
134 inline void setColStretch( int c, int s )
135 { expand( 0, c + 1 ); cStretch[c] = s; setDirty(); }
136 inline int rowStretch( int r ) const { return rStretch[r]; }
137 inline int colStretch( int c ) const { return cStretch[c]; }
138 inline void setRowSpacing( int r, int s )
139 { expand( r + 1, 0 ); rSpacing[r] = s; setDirty(); }
140 inline void setColSpacing( int c, int s )
141 { expand( 0, c + 1 ); cSpacing[c] = s; setDirty(); }
142 inline int rowSpacing( int r ) const { return rSpacing[r]; }
143 inline int colSpacing( int c ) const { return cSpacing[c]; }
144
145 inline void setReversed( bool r, bool c ) { hReversed = c; vReversed = r; }
146 inline bool horReversed() const { return hReversed; }
147 inline bool verReversed() const { return vReversed; }
148 inline void setDirty() { needRecalc = TRUE; hfw_width = -1; }
149 inline bool isDirty() const { return needRecalc; }
150 bool hasHeightForWidth( int space );
151 int heightForWidth( int, int, int );
152 int minimumHeightForWidth( int, int, int );
153
154 bool findWidget( QWidget* w, int *row, int *col );
155
156 inline void getNextPos( int &row, int &col ) { row = nextR; col = nextC; }
157 inline uint count() const
158 { return things.count() + ( multi ? multi->count() : 0 ); }
159 QRect cellGeometry( int row, int col ) const;
160
161private:
162 void setNextPosAfter( int r, int c );
163 void recalcHFW( int w, int s );
164 void addHfwData ( QGridBox *box, int width );
165 void init();
166 QSize findSize( QCOORD QLayoutStruct::*, int ) const;
167 void addData( QGridBox *b, bool r = TRUE, bool c = TRUE );
168 void setSize( int rows, int cols );
169 void setupLayoutData( int space );
170 void setupHfwLayoutData( int space );
171
172 int rr;
173 int cc;
174 QMemArray<QLayoutStruct> rowData;
175 QMemArray<QLayoutStruct> colData;
176 QMemArray<QLayoutStruct> *hfwData;
177 QMemArray<int> rStretch;
178 QMemArray<int> cStretch;
179 QMemArray<int> rSpacing;
180 QMemArray<int> cSpacing;
181 QPtrList<QGridBox> things;
182 QPtrList<QGridMultiBox> *multi;
183
184 int hfw_width;
185 int hfw_height;
186 int hfw_minheight;
187 int nextR;
188 int nextC;
189
190 uint hReversed : 1;
191 uint vReversed : 1;
192 uint needRecalc : 1;
193 uint has_hfw : 1;
194 uint addVertical : 1;
195
196 friend class QGridLayoutDataIterator;
197};
198
199QGridLayoutData::QGridLayoutData()
200{
201 init();
202}
203
204QGridLayoutData::QGridLayoutData( int nRows, int nCols )
205 : rowData( 0 ), colData( 0 )
206{
207 init();
208 if ( nRows < 0 ) {
209 nRows = 1;
210 addVertical = FALSE;
211 }
212 if ( nCols < 0 ) {
213 nCols = 1;
214 addVertical = TRUE;
215 }
216 setSize( nRows, nCols );
217}
218
219QGridLayoutData::~QGridLayoutData()
220{
221 // must be cleared while the data is still in a stable state
222 things.clear();
223
224 delete multi;
225 delete hfwData;
226}
227
228void QGridLayoutData::init()
229{
230 addVertical = FALSE;
231 setDirty();
232 multi = 0;
233 rr = cc = 0;
234 nextR = nextC = 0;
235 hfwData = 0;
236 things.setAutoDelete( TRUE );
237 hReversed = FALSE;
238 vReversed = FALSE;
239}
240
241bool QGridLayoutData::hasHeightForWidth( int spacing )
242{
243 setupLayoutData( spacing );
244 return has_hfw;
245}
246
247/*
248 Assumes that setupLayoutData() has been called, and that
249 qGeomCalc() has filled in colData with appropriate values.
250*/
251void QGridLayoutData::recalcHFW( int w, int spacing )
252{
253 /*
254 Go through all children, using colData and heightForWidth()
255 and put the results in hfw_rowData.
256 */
257 if ( !hfwData )
258 hfwData = new QMemArray<QLayoutStruct>( rr );
259 setupHfwLayoutData( spacing );
260 QMemArray<QLayoutStruct> &rData = *hfwData;
261
262 int h = 0;
263 int mh = 0;
264 int n = 0;
265 for ( int r = 0; r < rr; r++ ) {
266 h += rData[r].sizeHint;
267 mh += rData[r].minimumSize;
268 if ( !rData[r].empty )
269 n++;
270 }
271 if ( n ) {
272 h += ( n - 1 ) * spacing;
273 mh += ( n - 1 ) * spacing;
274 }
275
276 hfw_width = w;
277 hfw_height = QMIN( QLAYOUTSIZE_MAX, h );
278 hfw_minheight = QMIN( QLAYOUTSIZE_MAX, h );
279}
280
281int QGridLayoutData::heightForWidth( int w, int margin, int spacing )
282{
283 setupLayoutData( spacing );
284 if ( !has_hfw )
285 return -1;
286 if ( w + 2*margin != hfw_width ) {
287 qGeomCalc( colData, 0, cc, 0, w+2*margin, spacing );
288 recalcHFW( w+2*margin, spacing );
289 }
290 return hfw_height + 2*margin;
291}
292
293int QGridLayoutData::minimumHeightForWidth( int w, int margin, int spacing )
294{
295 (void) heightForWidth( w, margin, spacing );
296 return has_hfw ? (hfw_minheight + 2*margin) : -1;
297}
298
299bool QGridLayoutData::findWidget( QWidget* w, int *row, int *col )
300{
301 QPtrListIterator<QGridBox> it( things );
302 QGridBox * box;
303 while ( (box = it.current()) != 0 ) {
304 ++it;
305 if ( box->item()->widget() == w ) {
306 if ( row )
307 *row = box->row;
308 if ( col )
309 *col = box->col;
310 return TRUE;
311 }
312 }
313 if ( multi ) {
314 QPtrListIterator<QGridMultiBox> it( *multi );
315 QGridMultiBox * mbox;
316 while ( (mbox = it.current()) != 0 ) {
317 ++it;
318 box = mbox->box();
319 if ( box->item()->widget() == w ) {
320 if ( row )
321 *row = box->row;
322 if ( col )
323 *col = box->col;
324 return TRUE;
325 }
326
327 }
328 }
329 return FALSE;
330}
331
332QSize QGridLayoutData::findSize( QCOORD QLayoutStruct::*size, int spacer ) const
333{
334 QGridLayoutData *that = (QGridLayoutData *)this;
335 that->setupLayoutData( spacer );
336
337 int w = 0;
338 int h = 0;
339 int n = 0;
340 for ( int r = 0; r < rr; r++ ) {
341 h = h + rowData[r].*size;
342 if ( !rowData[r].empty )
343 n++;
344 }
345 if ( n )
346 h += ( n - 1 ) * spacer;
347 n = 0;
348 for ( int c = 0; c < cc; c++ ) {
349 w = w + colData[c].*size;
350 if ( !colData[c].empty )
351 n++;
352 }
353 if ( n )
354 w += ( n - 1 ) * spacer;
355 w = QMIN( QLAYOUTSIZE_MAX, w );
356 h = QMIN( QLAYOUTSIZE_MAX, h );
357
358 return QSize( w, h );
359}
360
361QSizePolicy::ExpandData QGridLayoutData::expanding( int spacing )
362{
363 setupLayoutData( spacing );
364 int ret = 0;
365
366 for ( int r = 0; r < rr; r++ ) {
367 if ( rowData[r].expansive ) {
368 ret |= (int) QSizePolicy::Vertically;
369 break;
370 }
371 }
372 for ( int c = 0; c < cc; c++ ) {
373 if ( colData[c].expansive ) {
374 ret |= (int) QSizePolicy::Horizontally;
375 break;
376 }
377 }
378 return (QSizePolicy::ExpandData) ret;
379}
380
381QSize QGridLayoutData::sizeHint( int spacer ) const
382{
383 return findSize( &QLayoutStruct::sizeHint, spacer );
384}
385
386QSize QGridLayoutData::maximumSize( int spacer ) const
387{
388 return findSize( &QLayoutStruct::maximumSize, spacer );
389}
390
391QSize QGridLayoutData::minimumSize( int spacer ) const
392{
393 return findSize( &QLayoutStruct::minimumSize, spacer );
394}
395
396void QGridLayoutData::setSize( int r, int c )
397{
398 if ( (int)rowData.size() < r ) {
399 int newR = QMAX( r, rr * 2 );
400 rowData.resize( newR );
401 rStretch.resize( newR );
402 rSpacing.resize( newR );
403 for ( int i = rr; i < newR; i++ ) {
404 rowData[i].init();
405 rStretch[i] = 0;
406 rSpacing[i] = 0;
407 }
408 }
409 if ( (int)colData.size() < c ) {
410 int newC = QMAX( c, cc * 2 );
411 colData.resize( newC );
412 cStretch.resize( newC );
413 cSpacing.resize( newC );
414 for ( int i = cc; i < newC; i++ ) {
415 colData[i].init();
416 cStretch[i] = 0;
417 cSpacing[i] = 0;
418 }
419 }
420
421 if ( hfwData && (int)hfwData->size() < r ) {
422 delete hfwData;
423 hfwData = 0;
424 hfw_width = -1;
425 }
426 rr = r;
427 cc = c;
428}
429
430void QGridLayoutData::setNextPosAfter( int row, int col )
431{
432 if ( addVertical ) {
433 if ( col > nextC || col == nextC && row >= nextR ) {
434 nextR = row + 1;
435 nextC = col;
436 if ( nextR >= rr ) {
437 nextR = 0;
438 nextC++;
439 }
440 }
441 } else {
442 if ( row > nextR || row == nextR && col >= nextC ) {
443 nextR = row;
444 nextC = col + 1;
445 if ( nextC >= cc ) {
446 nextC = 0;
447 nextR++;
448 }
449 }
450 }
451}
452
453void QGridLayoutData::add( QGridBox *box, int row, int col )
454{
455 expand( row+1, col+1 );
456 box->row = row;
457 box->col = col;
458 things.append( box );
459 setDirty();
460 setNextPosAfter( row, col );
461}
462
463void QGridLayoutData::add( QGridBox *box, int row1, int row2, int col1,
464 int col2 )
465{
466#ifdef QT_CHECK_RANGE
467 if ( row2 >= 0 && row2 < row1 )
468 qWarning( "QGridLayout: Multi-cell fromRow greater than toRow" );
469 if ( col2 >= 0 && col2 < col1 )
470 qWarning( "QGridLayout: Multi-cell fromCol greater than toCol" );
471#endif
472 if ( row1 == row2 && col1 == col2 ) {
473 add( box, row1, col1 );
474 return;
475 }
476 expand( row2+1, col2+1 );
477 box->row = row1;
478 box->col = col1;
479 QGridMultiBox *mbox = new QGridMultiBox( box, row2, col2 );
480 if ( !multi ) {
481 multi = new QPtrList<QGridMultiBox>;
482 multi->setAutoDelete( TRUE );
483 }
484 multi->append( mbox );
485 setDirty();
486 if ( col2 < 0 )
487 col2 = cc - 1;
488
489 setNextPosAfter( row2, col2 );
490}
491
492void QGridLayoutData::addData( QGridBox *box, bool r, bool c )
493{
494 QSize hint = box->sizeHint();
495 QSize minS = box->minimumSize();
496 QSize maxS = box->maximumSize();
497
498 if ( c ) {
499 if ( !cStretch[box->col] )
500 colData[box->col].stretch = QMAX( colData[box->col].stretch,
501 box->hStretch() );
502 colData[box->col].sizeHint = QMAX( hint.width(),
503 colData[box->col].sizeHint );
504 colData[box->col].minimumSize = QMAX( minS.width(),
505 colData[box->col].minimumSize );
506
507 qMaxExpCalc( colData[box->col].maximumSize, colData[box->col].expansive,
508 maxS.width(),
509 box->expanding() & QSizePolicy::Horizontally );
510 }
511 if ( r ) {
512 if ( !rStretch[box->row] )
513 rowData[box->row].stretch = QMAX( rowData[box->row].stretch,
514 box->vStretch() );
515 rowData[box->row].sizeHint = QMAX( hint.height(),
516 rowData[box->row].sizeHint );
517 rowData[box->row].minimumSize = QMAX( minS.height(),
518 rowData[box->row].minimumSize );
519
520 qMaxExpCalc( rowData[box->row].maximumSize, rowData[box->row].expansive,
521 maxS.height(),
522 box->expanding() & QSizePolicy::Vertically );
523 }
524 if ( box->isEmpty() ) {
525 if ( box->item()->widget() != 0 ) {
526 /*
527 Hidden widgets should behave exactly the same as if
528 there were no widgets at all in the cell. We could have
529 QWidgetItem::maximumSize() to return
530 QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX). However, that
531 value is not suitable for QBoxLayouts. So let's fix it
532 here.
533 */
534 if ( c )
535 colData[box->col].maximumSize = QLAYOUTSIZE_MAX;
536 if ( r )
537 rowData[box->row].maximumSize = QLAYOUTSIZE_MAX;
538 }
539 } else {
540 // Empty boxes (i.e. spacers) do not get borders. This is
541 // hacky, but compatible.
542 if ( c )
543 colData[box->col].empty = FALSE;
544 if ( r )
545 rowData[box->row].empty = FALSE;
546 }
547}
548
549static void distributeMultiBox( QMemArray<QLayoutStruct> &chain, int spacing,
550 int start, int end,
551 int minSize, int sizeHint,
552 QMemArray<int> &stretchArray, int stretch )
553{
554 int i;
555 int w = 0;
556 int wh = 0;
557 int max = 0;
558 for ( i = start; i <= end; i++ ) {
559 w += chain[i].minimumSize;
560 wh += chain[i].sizeHint;
561 max += chain[i].maximumSize;
562 chain[i].empty = FALSE;
563 if ( stretchArray[i] == 0 )
564 chain[i].stretch = QMAX(chain[i].stretch,stretch);
565 }
566 w += spacing * ( end - start );
567 wh += spacing * ( end - start );
568 max += spacing * ( end - start );
569
570 if ( max < minSize ) { // implies w < minSize
571 /*
572 We must increase the maximum size of at least one of the
573 items. qGeomCalc() will put the extra space in between the
574 items. We must recover that extra space and put it
575 somewhere. It does not really matter where, since the user
576 can always specify stretch factors and avoid this code.
577 */
578 qGeomCalc( chain, start, end - start + 1, 0, minSize, spacing );
579 int pos = 0;
580 for ( i = start; i <= end; i++ ) {
581 int nextPos = ( i == end ) ? minSize - 1 : chain[i + 1].pos;
582 int realSize = nextPos - pos;
583 if ( i != end )
584 realSize -= spacing;
585 if ( chain[i].minimumSize < realSize )
586 chain[i].minimumSize = realSize;
587 if ( chain[i].maximumSize < chain[i].minimumSize )
588 chain[i].maximumSize = chain[i].minimumSize;
589 pos = nextPos;
590 }
591 } else if ( w < minSize ) {
592 qGeomCalc( chain, start, end - start + 1, 0, minSize, spacing );
593 for ( i = start; i <= end; i++ ) {
594 if ( chain[i].minimumSize < chain[i].size )
595 chain[i].minimumSize = chain[i].size;
596 }
597 }
598
599 if ( wh < sizeHint ) {
600 qGeomCalc( chain, start, end - start + 1, 0, sizeHint, spacing );
601 for ( i = start; i <= end; i++ ) {
602 if ( chain[i].sizeHint < chain[i].size )
603 chain[i].sizeHint = chain[i].size;
604 }
605 }
606}
607
608//#define QT_LAYOUT_DISABLE_CACHING
609
610void QGridLayoutData::setupLayoutData( int spacing )
611{
612#ifndef QT_LAYOUT_DISABLE_CACHING
613 if ( !needRecalc )
614 return;
615#endif
616 has_hfw = FALSE;
617 int i;
618
619 for ( i = 0; i < rr; i++ )
620 rowData[i].init( rStretch[i], rSpacing[i] );
621 for ( i = 0; i < cc; i++ )
622 colData[i].init( cStretch[i], cSpacing[i] );
623
624 QPtrListIterator<QGridBox> it( things );
625 QGridBox * box;
626 while ( (box = it.current()) != 0 ) {
627 ++it;
628 addData( box );
629 has_hfw = has_hfw || box->item()->hasHeightForWidth();
630 }
631
632 if ( multi ) {
633 QPtrListIterator<QGridMultiBox> it( *multi );
634 QGridMultiBox * mbox;
635 while ( (mbox = it.current()) != 0 ) {
636 ++it;
637 QGridBox *box = mbox->box();
638 int r1 = box->row;
639 int c1 = box->col;
640 int r2 = mbox->torow;
641 int c2 = mbox->tocol;
642 if ( r2 < 0 )
643 r2 = rr - 1;
644 if ( c2 < 0 )
645 c2 = cc - 1;
646
647 QSize hint = box->sizeHint();
648 QSize min = box->minimumSize();
649 if ( box->hasHeightForWidth() )
650 has_hfw = TRUE;
651
652 if ( r1 == r2 ) {
653 addData( box, TRUE, FALSE );
654 } else {
655 distributeMultiBox( rowData, spacing, r1, r2,
656 min.height(), hint.height(),
657 rStretch, box->vStretch() );
658 }
659 if ( c1 == c2 ) {
660 addData( box, FALSE, TRUE );
661 } else {
662 distributeMultiBox( colData, spacing, c1, c2,
663 min.width(), hint.width(),
664 cStretch, box->hStretch() );
665 }
666 }
667 }
668 for ( i = 0; i < rr; i++ )
669 rowData[i].expansive = rowData[i].expansive || rowData[i].stretch > 0;
670 for ( i = 0; i < cc; i++ )
671 colData[i].expansive = colData[i].expansive || colData[i].stretch > 0;
672
673 needRecalc = FALSE;
674}
675
676void QGridLayoutData::addHfwData( QGridBox *box, int width )
677{
678 QMemArray<QLayoutStruct> &rData = *hfwData;
679 if ( box->hasHeightForWidth() ) {
680 int hint = box->heightForWidth( width );
681 rData[box->row].sizeHint = QMAX( hint, rData[box->row].sizeHint );
682 rData[box->row].minimumSize = QMAX( hint, rData[box->row].minimumSize );
683 } else {
684 QSize hint = box->sizeHint();
685 QSize minS = box->minimumSize();
686 rData[box->row].sizeHint = QMAX( hint.height(),
687 rData[box->row].sizeHint );
688 rData[box->row].minimumSize = QMAX( minS.height(),
689 rData[box->row].minimumSize );
690 }
691}
692
693/*
694 Similar to setupLayoutData(), but uses heightForWidth(colData)
695 instead of sizeHint(). Assumes that setupLayoutData() and
696 qGeomCalc(colData) has been called.
697*/
698void QGridLayoutData::setupHfwLayoutData( int spacing )
699{
700 QMemArray<QLayoutStruct> &rData = *hfwData;
701 int i;
702 for ( i = 0; i < rr; i++ ) {
703 rData[i] = rowData[i];
704 rData[i].minimumSize = rData[i].sizeHint = 0;
705 }
706 QPtrListIterator<QGridBox> it( things );
707 QGridBox * box;
708 while ( (box=it.current()) != 0 ) {
709 ++it;
710 addHfwData( box, colData[box->col].size );
711 }
712 if ( multi ) {
713 QPtrListIterator<QGridMultiBox> it( *multi );
714 QGridMultiBox * mbox;
715 while ( (mbox=it.current()) != 0 ) {
716 ++it;
717 QGridBox *box = mbox->box();
718 int r1 = box->row;
719 int c1 = box->col;
720 int r2 = mbox->torow;
721 int c2 = mbox->tocol;
722 if ( r2 < 0 )
723 r2 = rr-1;
724 if ( c2 < 0 )
725 c2 = cc-1;
726 int w = colData[c2].pos + colData[c2].size - colData[c1].pos;
727 if ( r1 == r2 ) {
728 addHfwData( box, w );
729 } else {
730 QSize hint = box->sizeHint();
731 QSize min = box->minimumSize();
732 if ( box->hasHeightForWidth() ) {
733 int hfwh = box->heightForWidth( w );
734 if ( hfwh > hint.height() )
735 hint.setHeight( hfwh );
736 if ( hfwh > min.height() )
737 min.setHeight( hfwh );
738 }
739 distributeMultiBox( rData, spacing, r1, r2,
740 min.height(), hint.height(),
741 rStretch, box->vStretch() );
742 }
743 }
744 }
745 for ( i = 0; i < rr; i++ )
746 rData[i].expansive = rData[i].expansive || rData[i].stretch > 0;
747}
748
749void QGridLayoutData::distribute( QRect r, int spacing )
750{
751 bool visualHReversed = hReversed;
752 if ( QApplication::reverseLayout() )
753 visualHReversed = !visualHReversed;
754
755 setupLayoutData( spacing );
756
757 qGeomCalc( colData, 0, cc, r.x(), r.width(), spacing );
758 QMemArray<QLayoutStruct> *rDataPtr;
759 if ( has_hfw ) {
760 recalcHFW( r.width(), spacing );
761 qGeomCalc( *hfwData, 0, rr, r.y(), r.height(), spacing );
762 rDataPtr = hfwData;
763 } else {
764 qGeomCalc( rowData, 0, rr, r.y(), r.height(), spacing );
765 rDataPtr = &rowData;
766 }
767 QMemArray<QLayoutStruct> &rData = *rDataPtr;
768
769 QPtrListIterator<QGridBox> it( things );
770 QGridBox * box;
771 while ( (box=it.current()) != 0 ) {
772 ++it;
773 int x = colData[box->col].pos;
774 int y = rData[box->row].pos;
775 int w = colData[box->col].size;
776 int h = rData[box->row].size;
777 if ( visualHReversed )
778 x = r.left() + r.right() - x - w + 1;
779 if ( vReversed )
780 y = r.top() + r.bottom() - y - h + 1;
781 box->setGeometry( QRect( x, y, w, h ) );
782 }
783 if ( multi ) {
784 QPtrListIterator<QGridMultiBox> it( *multi );
785 QGridMultiBox * mbox;
786 while ( (mbox=it.current()) != 0 ) {
787 ++it;
788 QGridBox *box = mbox->box();
789 int r2 = mbox->torow;
790 int c2 = mbox->tocol;
791 if ( r2 < 0 )
792 r2 = rr-1;
793 if ( c2 < 0 )
794 c2 = cc-1;
795
796 int x = colData[box->col].pos;
797 int y = rData[box->row].pos;
798 int x2p = colData[c2].pos + colData[c2].size; // x2+1
799 int y2p = rData[r2].pos + rData[r2].size; // y2+1
800 int w = x2p - x;
801 int h = y2p - y;
802 // this code is copied from above:
803 if ( visualHReversed )
804 x = r.left() + r.right() - x - w + 1;
805 if ( vReversed )
806 y = r.top() + r.bottom() - y - h + 1;
807 box->setGeometry( QRect( x, y, w, h ) );
808 }
809 }
810}
811
812QRect QGridLayoutData::cellGeometry( int row, int col ) const
813{
814 if ( row < 0 || row >= rr || col < 0 || col >= cc )
815 return QRect();
816
817 const QMemArray<QLayoutStruct> *rDataPtr;
818 if ( has_hfw )
819 rDataPtr = hfwData;
820 else
821 rDataPtr = &rowData;
822 return QRect( colData[col].pos, (*rDataPtr)[row].pos,
823 colData[col].size, (*rDataPtr)[row].size );
824}
825
826class QGridLayoutDataIterator : public QGLayoutIterator
827{
828public:
829 QGridLayoutDataIterator( QGridLayoutData *d );
830 uint count() const { return data->count(); }
831 QLayoutItem *current() {
832 if ( multi ) {
833 if ( !data->multi || idx >= (int)data->multi->count() )
834 return 0;
835 return data->multi->at( idx )->box()->item();
836 } else {
837 if ( idx >= (int)data->things.count() )
838 return 0;
839 return data->things.at( idx )->item();
840 }
841 }
842 void toFirst() {
843 multi = data->things.isEmpty();
844 idx = 0;
845 }
846 QLayoutItem *next() {
847 idx++;
848 if ( !multi && idx >= (int)data->things.count() ) {
849 multi = TRUE;
850 idx = 0;
851 }
852 return current();
853 }
854 QLayoutItem *takeCurrent() {
855 QLayoutItem *item = 0;
856 if ( multi ) {
857 if ( !data->multi || idx >= (int)data->multi->count() )
858 return 0;
859 QGridMultiBox *b = data->multi->take( idx );
860 item = b->takeItem();
861 delete b;
862 } else {
863 if ( idx >= (int)data->things.count() )
864 return 0;
865 QGridBox *b = data->things.take( idx );
866 item = b->takeItem();
867 delete b;
868 }
869 return item;
870 }
871
872private:
873 QGridLayoutData *data;
874 bool multi;
875 int idx;
876};
877
878inline QGridLayoutDataIterator::QGridLayoutDataIterator( QGridLayoutData *d )
879 : data( d )
880{
881 toFirst();
882}
883
884/*!
885 \class QGridLayout
886
887 \brief The QGridLayout class lays out widgets in a grid.
888
889 \ingroup geomanagement
890 \ingroup appearance
891 \mainclass
892
893 QGridLayout takes the space made available to it (by its parent
894 layout or by the mainWidget()), divides it up into rows and
895 columns, and puts each widget it manages into the correct cell.
896
897 Columns and rows behave identically; we will discuss columns, but
898 there are equivalent functions for rows.
899
900 Each column has a minimum width and a stretch factor. The minimum
901 width is the greatest of that set using addColSpacing() and the
902 minimum width of each widget in that column. The stretch factor is
903 set using setColStretch() and determines how much of the available
904 space the column will get over and above its necessary minimum.
905
906 Normally, each managed widget or layout is put into a cell of its
907 own using addWidget(), addLayout() or by the \link
908 QLayout::setAutoAdd() auto-add facility\endlink. It is also
909 possible for a widget to occupy multiple cells using
910 addMultiCellWidget(). If you do this, QGridLayout will guess how
911 to distribute the size over the columns/rows (based on the stretch
912 factors).
913
914 To remove a widget from a layout, call remove(). Calling
915 QWidget::hide() on a widget also effectively removes the widget
916 from the layout until QWidget::show() is called.
917
918 This illustration shows a fragment of a dialog with a five-column,
919 three-row grid (the grid is shown overlaid in magenta):
920
921 \img gridlayout.png
922
923 Columns 0, 2 and 4 in this dialog fragment are made up of a
924 QLabel, a QLineEdit, and a QListBox. Columns 1 and 3 are
925 placeholders made with addColSpacing(). Row 0 consists of three
926 QLabel objects, row 1 of three QLineEdit objects and row 2 of
927 three QListBox objects. We used placeholder columns (1 and 3) to
928 get the right amount of space between the columns.
929
930 Note that the columns and rows are not equally wide or tall. If
931 you want two columns to have the same width, you must set their
932 minimum widths and stretch factors to be the same yourself. You do
933 this using addColSpacing() and setColStretch().
934
935 If the QGridLayout is not the top-level layout (i.e. does not
936 manage all of the widget's area and children), you must add it to
937 its parent layout when you create it, but before you do anything
938 with it. The normal way to add a layout is by calling
939 parentLayout-\>addLayout().
940
941 Once you have added your layout you can start putting widgets and
942 other layouts into the cells of your grid layout using
943 addWidget(), addLayout() and addMultiCellWidget().
944
945 QGridLayout also includes two margin widths: the border and the
946 spacing. The border is the width of the reserved space along each
947 of the QGridLayout's four sides. The spacing is the width of the
948 automatically allocated spacing between neighboring boxes.
949
950 Both the border and the spacing are parameters of the constructor
951 and default to 0.
952
953 \sa QGrid, \link layout.html Layout Overview \endlink
954*/
955
956/*!
957 \enum QGridLayout::Corner
958
959 This enum identifies which corner is the origin (0, 0) of the
960 layout.
961
962 \value TopLeft the top-left corner
963 \value TopRight the top-right corner
964 \value BottomLeft the bottom-left corner
965 \value BottomRight the bottom-right corner
966*/
967
968/*!
969 Constructs a new QGridLayout with \a nRows rows, \a nCols columns
970 and parent widget, \a parent. \a parent may not be 0. The grid
971 layout is called \a name.
972
973 \a margin is the number of pixels between the edge of the widget
974 and its managed children. \a space is the default number of pixels
975 between cells. If \a space is -1, the value of \a margin is used.
976*/
977QGridLayout::QGridLayout( QWidget *parent, int nRows, int nCols, int margin,
978 int space, const char *name )
979 : QLayout( parent, margin, space, name )
980{
981 init( nRows, nCols );
982}
983
984/*!
985 Constructs a new grid that is placed inside \a parentLayout with
986 \a nRows rows and \a nCols columns. If \a spacing is -1, this
987 QGridLayout inherits its parent's spacing(); otherwise \a spacing
988 is used. The grid layout is called \a name.
989
990 This grid is placed according to \a parentLayout's default
991 placement rules.
992*/
993QGridLayout::QGridLayout( QLayout *parentLayout, int nRows, int nCols,
994 int spacing, const char *name )
995 : QLayout( parentLayout, spacing, name )
996{
997 init( nRows, nCols );
998}
999
1000/*!
1001 Constructs a new grid with \a nRows rows and \a nCols columns. If
1002 \a spacing is -1, this QGridLayout inherits its parent's
1003 spacing(); otherwise \a spacing is used. The grid layout is called
1004 \a name.
1005
1006 You must insert this grid into another layout. You can insert
1007 widgets and layouts into this layout at any time, but laying out
1008 will not be performed before this is inserted into another layout.
1009*/
1010QGridLayout::QGridLayout( int nRows, int nCols,
1011 int spacing, const char *name )
1012 : QLayout( spacing, name )
1013{
1014 init( nRows, nCols );
1015}
1016
1017/*!
1018 Destroys the grid layout. Geometry management is terminated if
1019 this is a top-level grid.
1020
1021 The layout's widgets aren't destroyed.
1022*/
1023QGridLayout::~QGridLayout()
1024{
1025 delete data;
1026}
1027
1028/*!
1029 Returns the number of rows in this grid.
1030*/
1031int QGridLayout::numRows() const
1032{
1033 return data->numRows();
1034}
1035
1036/*!
1037 Returns the number of columns in this grid.
1038*/
1039int QGridLayout::numCols() const
1040{
1041 return data->numCols();
1042}
1043
1044/*!
1045 Returns the preferred size of this grid.
1046*/
1047QSize QGridLayout::sizeHint() const
1048{
1049 return data->sizeHint( spacing() ) + QSize( 2 * margin(), 2 * margin() );
1050}
1051
1052/*!
1053 Returns the minimum size needed by this grid.
1054*/
1055QSize QGridLayout::minimumSize() const
1056{
1057 return data->minimumSize( spacing() ) + QSize( 2 * margin(), 2 * margin() );
1058}
1059
1060/*!
1061 Returns the maximum size needed by this grid.
1062*/
1063QSize QGridLayout::maximumSize() const
1064{
1065 QSize s = data->maximumSize( spacing() ) +
1066 QSize( 2 * margin(), 2 * margin() );
1067 s = s.boundedTo( QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX) );
1068 if ( alignment() & Qt::AlignHorizontal_Mask )
1069 s.setWidth( QLAYOUTSIZE_MAX );
1070 if ( alignment() & Qt::AlignVertical_Mask )
1071 s.setHeight( QLAYOUTSIZE_MAX );
1072 return s;
1073}
1074
1075/*!
1076 Returns TRUE if this layout's preferred height depends on its
1077 width; otherwise returns FALSE.
1078*/
1079bool QGridLayout::hasHeightForWidth() const
1080{
1081 return ((QGridLayout*)this)->data->hasHeightForWidth( spacing() );
1082}
1083
1084/*!
1085 Returns the layout's preferred height when it is \a w pixels wide.
1086*/
1087int QGridLayout::heightForWidth( int w ) const
1088{
1089 QGridLayout *that = (QGridLayout*)this;
1090 return that->data->heightForWidth( w, margin(), spacing() );
1091}
1092
1093/*! \internal */
1094int QGridLayout::minimumHeightForWidth( int w ) const
1095{
1096 QGridLayout *that = (QGridLayout*)this;
1097 return that->data->minimumHeightForWidth( w, margin(), spacing() );
1098}
1099
1100/*!
1101 Searches for widget \a w in this layout (not including child
1102 layouts). If \a w is found, it sets \c *\a row and \c *\a col to
1103 the row and column and returns TRUE; otherwise returns FALSE.
1104
1105 Note: if a widget spans multiple rows/columns, the top-left cell
1106 is returned.
1107*/
1108bool QGridLayout::findWidget( QWidget* w, int *row, int *col )
1109{
1110 return data->findWidget( w, row, col );
1111}
1112
1113/*!
1114 Resizes managed widgets within the rectangle \a r.
1115*/
1116void QGridLayout::setGeometry( const QRect &r )
1117{
1118 if ( data->isDirty() || r != geometry() ) {
1119 QLayout::setGeometry( r );
1120 QRect cr = alignment() ? alignmentRect( r ) : r;
1121 QRect s( cr.x() + margin(), cr.y() + margin(),
1122 cr.width() - 2 * margin(), cr.height() - 2 * margin() );
1123 data->distribute( s, spacing() );
1124 }
1125}
1126
1127/*!
1128 Returns the geometry of the cell with row \a row and column \a col
1129 in the grid. Returns an invalid rectangle if \a row or \a col is
1130 outside the grid.
1131
1132 \warning in the current version of Qt this function does not
1133 return valid results until setGeometry() has been called, i.e.
1134 after the mainWidget() is visible.
1135*/
1136QRect QGridLayout::cellGeometry( int row, int col ) const
1137{
1138 return data->cellGeometry( row, col );
1139}
1140
1141/*!
1142 Expands this grid so that it will have \a nRows rows and \a nCols
1143 columns. Will not shrink the grid. You should not need to call
1144 this function because QGridLayout expands automatically as new
1145 items are inserted.
1146*/
1147void QGridLayout::expand( int nRows, int nCols )
1148{
1149 data->expand( nRows, nCols );
1150}
1151
1152/*!
1153 Sets up the grid.
1154*/
1155void QGridLayout::init( int nRows, int nCols )
1156{
1157 setSupportsMargin( TRUE );
1158 data = new QGridLayoutData( nRows, nCols );
1159}
1160
1161/*!
1162 \overload
1163
1164 Adds \a item to the next free position of this layout.
1165*/
1166void QGridLayout::addItem( QLayoutItem *item )
1167{
1168 int r, c;
1169 data->getNextPos( r, c );
1170 add( item, r, c );
1171}
1172
1173/*!
1174 Adds \a item at position \a row, \a col. The layout takes
1175 ownership of the \a item.
1176*/
1177void QGridLayout::addItem( QLayoutItem *item, int row, int col )
1178{
1179 add( item, row, col );
1180}
1181
1182/*!
1183 Adds \a item at position \a row, \a col. The layout takes
1184 ownership of the \a item.
1185*/
1186void QGridLayout::add( QLayoutItem *item, int row, int col )
1187{
1188 QGridBox *box = new QGridBox( item );
1189 data->add( box, row, col );
1190}
1191
1192/*!
1193 Adds the \a item to the cell grid, spanning multiple rows/columns.
1194
1195 The cell will span from \a fromRow, \a fromCol to \a toRow, \a
1196 toCol. Alignment is specified by \a alignment, which is a bitwise
1197 OR of \l Qt::AlignmentFlags values. The default alignment is 0,
1198 which means that the widget fills the entire cell.
1199*/
1200void QGridLayout::addMultiCell( QLayoutItem *item, int fromRow, int toRow,
1201 int fromCol, int toCol, int alignment )
1202{
1203 QGridBox *b = new QGridBox( item );
1204 b->setAlignment( alignment );
1205 data->add( b, fromRow, toRow, fromCol, toCol );
1206}
1207
1208/*
1209 Returns TRUE if the widget \a w can be added to the layout \a l;
1210 otherwise returns FALSE.
1211*/
1212static bool checkWidget( QLayout *l, QWidget *w )
1213{
1214 if ( !w ) {
1215#if defined(QT_CHECK_STATE)
1216 qWarning( "QLayout: Cannot add null widget to %s/%s", l->className(),
1217 l->name() );
1218#endif
1219 return FALSE;
1220 }
1221 if ( w->parentWidget() != l->mainWidget() && l->mainWidget() ) {
1222#if defined(QT_CHECK_STATE)
1223 if ( w->parentWidget() )
1224 qWarning( "QLayout: Adding %s/%s (child of %s/%s) to layout for "
1225 "%s/%s", w->className(), w->name(),
1226 w->parentWidget()->className(), w->parentWidget()->name(),
1227 l->mainWidget()->className(), l->mainWidget()->name() );
1228 else
1229 qWarning( "QLayout: Adding %s/%s (top-level widget) to layout for"
1230 " %s/%s", w->className(), w->name(),
1231 l->mainWidget()->className(), l->mainWidget()->name() );
1232#endif
1233 return FALSE;
1234 }
1235 return TRUE;
1236}
1237
1238/*!
1239 Adds the widget \a w to the cell grid at \a row, \a col. The
1240 top-left position is (0, 0) by default.
1241
1242 Alignment is specified by \a alignment, which is a bitwise OR of
1243 \l Qt::AlignmentFlags values. The default alignment is 0, which
1244 means that the widget fills the entire cell.
1245
1246 \list
1247 \i You should not call this if you have enabled the
1248 \link QLayout::setAutoAdd() auto-add facility of the layout\endlink.
1249
1250 \i From Qt 3.0, the \a alignment parameter is interpreted more
1251 aggressively than in previous versions of Qt. A non-default
1252 alignment now indicates that the widget should not grow to fill
1253 the available space, but should be sized according to sizeHint().
1254 \endlist
1255
1256 \sa addMultiCellWidget()
1257*/
1258void QGridLayout::addWidget( QWidget *w, int row, int col, int alignment )
1259{
1260 if ( !checkWidget( this, w ) )
1261 return;
1262 if ( row < 0 || col < 0 ) {
1263#if defined(QT_CHECK_STATE)
1264 qWarning( "QGridLayout: Cannot add %s/%s to %s/%s at row %d col %d",
1265 w->className(), w->name(), className(), name(), row, col );
1266#endif
1267 return;
1268 }
1269 QWidgetItem *b = new QWidgetItem( w );
1270 b->setAlignment( alignment );
1271 add( b, row, col );
1272}
1273
1274/*!
1275 Adds the widget \a w to the cell grid, spanning multiple
1276 rows/columns. The cell will span from \a fromRow, \a fromCol to \a
1277 toRow, \a toCol.
1278
1279 Alignment is specified by \a alignment, which is a bitwise OR of
1280 \l Qt::AlignmentFlags values. The default alignment is 0, which
1281 means that the widget fills the entire cell.
1282
1283 A non-zero alignment indicates that the widget should not grow to
1284 fill the available space but should be sized according to
1285 sizeHint().
1286
1287 \sa addWidget()
1288*/
1289void QGridLayout::addMultiCellWidget( QWidget *w, int fromRow, int toRow,
1290 int fromCol, int toCol, int alignment )
1291{
1292 QGridBox *b = new QGridBox( w );
1293 b->setAlignment( alignment );
1294 data->add( b, fromRow, toRow, fromCol, toCol );
1295}
1296
1297/*!
1298 Places the \a layout at position (\a row, \a col) in the grid. The
1299 top-left position is (0, 0).
1300
1301 \a layout becomes a child of the grid layout.
1302
1303 \sa addMultiCellLayout()
1304*/
1305void QGridLayout::addLayout( QLayout *layout, int row, int col )
1306{
1307 addChildLayout( layout );
1308 add( layout, row, col );
1309}
1310
1311/*!
1312 Adds the layout \a layout to the cell grid, spanning multiple
1313 rows/columns. The cell will span from \a fromRow, \a fromCol to \a
1314 toRow, \a toCol.
1315
1316 Alignment is specified by \a alignment, which is a bitwise OR of
1317 \l Qt::AlignmentFlags values. The default alignment is 0, which
1318 means that the widget fills the entire cell.
1319
1320 A non-zero alignment indicates that the layout should not grow to
1321 fill the available space but should be sized according to
1322 sizeHint().
1323
1324 \a layout becomes a child of the grid layout.
1325
1326 \sa addLayout()
1327*/
1328void QGridLayout::addMultiCellLayout( QLayout *layout, int fromRow, int toRow,
1329 int fromCol, int toCol, int alignment )
1330{
1331 addChildLayout( layout );
1332 QGridBox *b = new QGridBox( layout );
1333 b->setAlignment( alignment );
1334 data->add( b, fromRow, toRow, fromCol, toCol );
1335}
1336
1337/*!
1338 Sets the stretch factor of row \a row to \a stretch. The first row
1339 is number 0.
1340
1341 The stretch factor is relative to the other rows in this grid.
1342 Rows with a higher stretch factor take more of the available
1343 space.
1344
1345 The default stretch factor is 0. If the stretch factor is 0 and no
1346 other row in this table can grow at all, the row may still grow.
1347
1348 \sa rowStretch(), setRowSpacing(), setColStretch()
1349*/
1350void QGridLayout::setRowStretch( int row, int stretch )
1351{
1352 data->setRowStretch( row, stretch );
1353}
1354
1355/*!
1356 Returns the stretch factor for row \a row.
1357
1358 \sa setRowStretch()
1359*/
1360int QGridLayout::rowStretch( int row ) const
1361{
1362 return data->rowStretch( row );
1363}
1364
1365/*!
1366 Returns the stretch factor for column \a col.
1367
1368 \sa setColStretch()
1369*/
1370int QGridLayout::colStretch( int col ) const
1371{
1372 return data->colStretch( col );
1373}
1374
1375/*!
1376 Sets the stretch factor of column \a col to \a stretch. The first
1377 column is number 0.
1378
1379 The stretch factor is relative to the other columns in this grid.
1380 Columns with a higher stretch factor take more of the available
1381 space.
1382
1383 The default stretch factor is 0. If the stretch factor is 0 and no
1384 other column in this table can grow at all, the column may still
1385 grow.
1386
1387 \sa colStretch(), addColSpacing(), setRowStretch()
1388*/
1389void QGridLayout::setColStretch( int col, int stretch )
1390{
1391 data->setColStretch( col, stretch );
1392}
1393
1394#if QT_VERSION >= 0x040000
1395#error "Make add{Row,Col}Spacing() inline QT_NO_COMPAT functions defined in terms of set{Row,Col}Spacing()"
1396#endif
1397
1398/*!
1399 \obsolete
1400
1401 Sets the minimum height of row \a row to \a minsize pixels.
1402
1403 Use setRowSpacing() instead.
1404*/
1405void QGridLayout::addRowSpacing( int row, int minsize )
1406{
1407 QLayoutItem *b = new QSpacerItem( 0, minsize );
1408 add( b, row, 0 );
1409}
1410
1411/*!
1412 \obsolete
1413
1414 Sets the minimum width of column \a col to \a minsize pixels.
1415
1416 Use setColSpacing() instead.
1417*/
1418void QGridLayout::addColSpacing( int col, int minsize )
1419{
1420 QLayoutItem *b = new QSpacerItem( minsize, 0 );
1421 add( b, 0, col );
1422}
1423
1424/*!
1425 Sets the minimum height of row \a row to \a minSize pixels.
1426
1427 \sa rowSpacing(), setColSpacing()
1428*/
1429void QGridLayout::setRowSpacing( int row, int minSize )
1430{
1431 data->setRowSpacing( row, minSize );
1432}
1433
1434/*!
1435 Returns the row spacing for row \a row.
1436
1437 \sa setRowSpacing()
1438*/
1439int QGridLayout::rowSpacing( int row ) const
1440{
1441 return data->rowSpacing( row );
1442}
1443
1444/*!
1445 Sets the minimum width of column \a col to \a minSize pixels.
1446
1447 \sa colSpacing(), setRowSpacing()
1448*/
1449void QGridLayout::setColSpacing( int col, int minSize )
1450{
1451 data->setColSpacing( col, minSize );
1452}
1453
1454/*!
1455 Returns the column spacing for column \a col.
1456
1457 \sa setColSpacing()
1458*/
1459int QGridLayout::colSpacing( int col ) const
1460{
1461 return data->colSpacing( col );
1462}
1463
1464/*!
1465 Returns whether this layout can make use of more space than
1466 sizeHint(). A value of \c Vertical or \c Horizontal means that it wants
1467 to grow in only one dimension, whereas \c BothDirections means that
1468 it wants to grow in both dimensions.
1469*/
1470QSizePolicy::ExpandData QGridLayout::expanding() const
1471{
1472 return data->expanding( spacing() );
1473}
1474
1475/*!
1476 Sets the grid's origin corner, i.e. position (0, 0), to \a c.
1477*/
1478void QGridLayout::setOrigin( Corner c )
1479{
1480 data->setReversed( c == BottomLeft || c == BottomRight,
1481 c == TopRight || c == BottomRight );
1482}
1483
1484/*!
1485 Returns the corner that's used for the grid's origin, i.e. for
1486 position (0, 0).
1487*/
1488QGridLayout::Corner QGridLayout::origin() const
1489{
1490 if ( data->horReversed() ) {
1491 return data->verReversed() ? BottomRight : TopRight;
1492 } else {
1493 return data->verReversed() ? BottomLeft : TopLeft;
1494 }
1495}
1496
1497/*!
1498 Resets cached information.
1499*/
1500void QGridLayout::invalidate()
1501{
1502 QLayout::invalidate();
1503 QLayout::setGeometry( QRect() ); // for binary compatibility (?)
1504 data->setDirty();
1505}
1506
1507/*! \reimp */
1508QLayoutIterator QGridLayout::iterator()
1509{
1510 return QLayoutIterator( new QGridLayoutDataIterator(data) );
1511}
1512
1513struct QBoxLayoutItem
1514{
1515 QBoxLayoutItem( QLayoutItem *it, int stretch_ = 0 )
1516 : item( it ), stretch( stretch_ ), magic( FALSE ) { }
1517 ~QBoxLayoutItem() { delete item; }
1518
1519 int hfw( int w ) {
1520 if ( item->hasHeightForWidth() ) {
1521 return item->heightForWidth( w );
1522 } else {
1523 return item->sizeHint().height();
1524 }
1525 }
1526 int mhfw( int w ) {
1527 if ( item->hasHeightForWidth() ) {
1528 return item->heightForWidth( w );
1529 } else {
1530 return item->minimumSize().height();
1531 }
1532 }
1533 int hStretch() {
1534 if ( stretch == 0 && item->widget() ) {
1535 return item->widget()->sizePolicy().horStretch();
1536 } else {
1537 return stretch;
1538 }
1539 }
1540 int vStretch() {
1541 if ( stretch == 0 && item->widget() ) {
1542 return item->widget()->sizePolicy().verStretch();
1543 } else {
1544 return stretch;
1545 }
1546 }
1547
1548 QLayoutItem *item;
1549 int stretch;
1550 bool magic;
1551};
1552
1553class QBoxLayoutData
1554{
1555public:
1556 QBoxLayoutData() : geomArray( 0 ), hfwWidth( -1 ), dirty( TRUE )
1557 { list.setAutoDelete( TRUE ); }
1558
1559 ~QBoxLayoutData() { delete geomArray; }
1560 void setDirty() {
1561 delete geomArray;
1562 geomArray = 0;
1563 hfwWidth = -1;
1564 hfwHeight = -1;
1565 dirty = TRUE;
1566 }
1567
1568 QPtrList<QBoxLayoutItem> list;
1569 QMemArray<QLayoutStruct> *geomArray;
1570 int hfwWidth;
1571 int hfwHeight;
1572 int hfwMinHeight;
1573 QSize sizeHint;
1574 QSize minSize;
1575 QSize maxSize;
1576 QSizePolicy::ExpandData expanding;
1577 uint hasHfw : 1;
1578 uint dirty : 1;
1579};
1580
1581class QBoxLayoutIterator : public QGLayoutIterator
1582{
1583public:
1584 QBoxLayoutIterator( QBoxLayoutData *d ) : data( d ), idx( 0 ) {}
1585 QLayoutItem *current() {
1586 if ( idx >= int(data->list.count()) )
1587 return 0;
1588 return data->list.at(idx)->item;
1589 }
1590 QLayoutItem *next() {
1591 idx++;
1592 return current();
1593 }
1594 QLayoutItem *takeCurrent() {
1595 QLayoutItem *item = 0;
1596
1597 QBoxLayoutItem *b = data->list.take( idx );
1598 if ( b ) {
1599 item = b->item;
1600 b->item = 0;
1601 delete b;
1602 }
1603 data->setDirty();
1604 return item;
1605 }
1606
1607private:
1608 QBoxLayoutData *data;
1609 int idx;
1610};
1611
1612/*!
1613 \class QBoxLayout
1614
1615 \brief The QBoxLayout class lines up child widgets horizontally or
1616 vertically.
1617
1618 \ingroup geomanagement
1619 \ingroup appearance
1620
1621 QBoxLayout takes the space it gets (from its parent layout or from
1622 the mainWidget()), divides it up into a row of boxes, and makes
1623 each managed widget fill one box.
1624
1625 \img qhbox-m.png Horizontal box with five child widgets
1626
1627 If the QBoxLayout's orientation is \c Horizontal the boxes are
1628 placed in a row, with suitable sizes. Each widget (or other box)
1629 will get at least its minimum size and at most its maximum size.
1630 Any excess space is shared according to the stretch factors (more
1631 about that below).
1632
1633 \img qvbox-m.png Vertical box with five child widgets
1634
1635 If the QBoxLayout's orientation is \c Vertical, the boxes are
1636 placed in a column, again with suitable sizes.
1637
1638 The easiest way to create a QBoxLayout is to use one of the
1639 convenience classes, e.g. QHBoxLayout (for \c Horizontal boxes) or
1640 QVBoxLayout (for \c Vertical boxes). You can also use the
1641 QBoxLayout constructor directly, specifying its direction as \c
1642 LeftToRight, \c Down, \c RightToLeft or \c Up.
1643
1644 If the QBoxLayout is not the top-level layout (i.e. it is not
1645 managing all of the widget's area and children), you must add it
1646 to its parent layout before you can do anything with it. The
1647 normal way to add a layout is by calling
1648 parentLayout-\>addLayout().
1649
1650 Once you have done this, you can add boxes to the QBoxLayout using
1651 one of four functions:
1652
1653 \list
1654 \i addWidget() to add a widget to the QBoxLayout and set the
1655 widget's stretch factor. (The stretch factor is along the row of
1656 boxes.)
1657
1658 \i addSpacing() to create an empty box; this is one of the
1659 functions you use to create nice and spacious dialogs. See below
1660 for ways to set margins.
1661
1662 \i addStretch() to create an empty, stretchable box.
1663
1664 \i addLayout() to add a box containing another QLayout to the row
1665 and set that layout's stretch factor.
1666 \endlist
1667
1668 Use insertWidget(), insertSpacing(), insertStretch() or
1669 insertLayout() to insert a box at a specified position in the
1670 layout.
1671
1672 QBoxLayout also includes two margin widths:
1673
1674 \list
1675 \i setMargin() sets the width of the outer border. This is the width
1676 of the reserved space along each of the QBoxLayout's four sides.
1677 \i setSpacing() sets the width between neighboring boxes. (You
1678 can use addSpacing() to get more space at a particular spot.)
1679 \endlist
1680
1681 The margin defaults to 0. The spacing defaults to the same as the
1682 margin width for a top-level layout, or to the same as the parent
1683 layout. Both are parameters to the constructor.
1684
1685 To remove a widget from a layout, call remove(). Calling
1686 QWidget::hide() on a widget also effectively removes the widget
1687 from the layout until QWidget::show() is called.
1688
1689 You will almost always want to use QVBoxLayout and QHBoxLayout
1690 rather than QBoxLayout because of their convenient constructors.
1691
1692 \sa QGrid \link layout.html Layout Overview \endlink
1693*/
1694
1695/*!
1696 \enum QBoxLayout::Direction
1697
1698 This type is used to determine the direction of a box layout.
1699
1700 \value LeftToRight Horizontal, from left to right
1701 \value RightToLeft Horizontal, from right to left
1702 \value TopToBottom Vertical, from top to bottom
1703 \value Down The same as \c TopToBottom
1704 \value BottomToTop Vertical, from bottom to top
1705 \value Up The same as \c BottomToTop
1706*/
1707
1708static inline bool horz( QBoxLayout::Direction dir )
1709{
1710 return dir == QBoxLayout::RightToLeft || dir == QBoxLayout::LeftToRight;
1711}
1712
1713/*!
1714 Constructs a new QBoxLayout with direction \a d and main widget \a
1715 parent. \a parent may not be 0.
1716
1717 The \a margin is the number of pixels between the edge of the
1718 widget and its managed children. The \a spacing is the default
1719 number of pixels between neighboring children. If \a spacing is -1
1720 the value of \a margin is used for \a spacing.
1721
1722 \a name is the internal object name.
1723
1724 \sa direction()
1725*/
1726QBoxLayout::QBoxLayout( QWidget *parent, Direction d,
1727 int margin, int spacing, const char *name )
1728 : QLayout( parent, margin, spacing, name )
1729{
1730 data = new QBoxLayoutData;
1731 dir = d;
1732 setSupportsMargin( TRUE );
1733}
1734
1735/*!
1736 Constructs a new QBoxLayout called \a name, with direction \a d,
1737 and inserts it into \a parentLayout.
1738
1739 The \a spacing is the default number of pixels between neighboring
1740 children. If \a spacing is -1, the layout will inherit its
1741 parent's spacing().
1742*/
1743QBoxLayout::QBoxLayout( QLayout *parentLayout, Direction d, int spacing,
1744 const char *name )
1745 : QLayout( parentLayout, spacing, name )
1746{
1747 data = new QBoxLayoutData;
1748 dir = d;
1749 setSupportsMargin( TRUE );
1750}
1751
1752/*!
1753 Constructs a new QBoxLayout called \a name, with direction \a d.
1754
1755 If \a spacing is -1, the layout will inherit its parent's
1756 spacing(); otherwise \a spacing is used.
1757
1758 You must insert this box into another layout.
1759*/
1760QBoxLayout::QBoxLayout( Direction d, int spacing, const char *name )
1761 : QLayout( spacing, name )
1762{
1763 data = new QBoxLayoutData;
1764 dir = d;
1765 setSupportsMargin( TRUE );
1766}
1767
1768/*!
1769 Destroys this box layout.
1770
1771 The layout's widgets aren't destroyed.
1772*/
1773QBoxLayout::~QBoxLayout()
1774{
1775 delete data;
1776}
1777
1778/*!
1779 Returns the preferred size of this box layout.
1780*/
1781QSize QBoxLayout::sizeHint() const
1782{
1783 if ( data->dirty ) {
1784 QBoxLayout *that = (QBoxLayout*)this;
1785 that->setupGeom();
1786 }
1787 return data->sizeHint + QSize( 2 * margin(), 2 * margin() );
1788}
1789
1790/*!
1791 Returns the minimum size needed by this box layout.
1792*/
1793QSize QBoxLayout::minimumSize() const
1794{
1795 if ( data->dirty ) {
1796 QBoxLayout *that = (QBoxLayout*)this;
1797 that->setupGeom();
1798 }
1799 return data->minSize + QSize( 2 * margin(), 2 * margin() );
1800}
1801
1802/*!
1803 Returns the maximum size needed by this box layout.
1804*/
1805QSize QBoxLayout::maximumSize() const
1806{
1807 if ( data->dirty ) {
1808 QBoxLayout *that = (QBoxLayout*)this;
1809 that->setupGeom();
1810 }
1811 QSize s = ( data->maxSize + QSize(2 * margin(), 2 * margin()) )
1812 .boundedTo(QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX));
1813 if ( alignment() & Qt::AlignHorizontal_Mask )
1814 s.setWidth( QLAYOUTSIZE_MAX );
1815 if ( alignment() & Qt::AlignVertical_Mask )
1816 s.setHeight( QLAYOUTSIZE_MAX );
1817 return s;
1818}
1819
1820/*!
1821 Returns TRUE if this layout's preferred height depends on its width;
1822 otherwise returns FALSE.
1823*/
1824bool QBoxLayout::hasHeightForWidth() const
1825{
1826 if ( data->dirty ) {
1827 QBoxLayout *that = (QBoxLayout*)this;
1828 that->setupGeom();
1829 }
1830 return data->hasHfw;
1831}
1832
1833/*!
1834 Returns the layout's preferred height when it is \a w pixels wide.
1835*/
1836int QBoxLayout::heightForWidth( int w ) const
1837{
1838 if ( !hasHeightForWidth() )
1839 return -1;
1840 w -= 2 * margin();
1841 if ( w != data->hfwWidth ) {
1842 QBoxLayout *that = (QBoxLayout*)this;
1843 that->calcHfw( w );
1844 }
1845 return data->hfwHeight + 2 * margin();
1846}
1847
1848/*! \internal */
1849int QBoxLayout::minimumHeightForWidth( int w ) const
1850{
1851 (void) heightForWidth( w );
1852 return data->hasHfw ? (data->hfwMinHeight + 2 * margin() ) : -1;
1853}
1854
1855/*!
1856 Resets cached information.
1857*/
1858void QBoxLayout::invalidate()
1859{
1860 QLayout::invalidate();
1861 data->setDirty();
1862}
1863
1864/*!
1865 \reimp
1866*/
1867QLayoutIterator QBoxLayout::iterator()
1868{
1869 return QLayoutIterator( new QBoxLayoutIterator(data) );
1870}
1871
1872/*!
1873 Returns whether this layout can make use of more space than
1874 sizeHint(). A value of \c Vertical or \c Horizontal means that it wants
1875 to grow in only one dimension, whereas \c BothDirections means that
1876 it wants to grow in both dimensions.
1877*/
1878QSizePolicy::ExpandData QBoxLayout::expanding() const
1879{
1880 if ( data->dirty ) {
1881 QBoxLayout *that = (QBoxLayout*)this;
1882 that->setupGeom();
1883 }
1884 return data->expanding;
1885}
1886
1887/*!
1888 Resizes managed widgets within the rectangle \a r.
1889*/
1890void QBoxLayout::setGeometry( const QRect &r )
1891{
1892 if ( !data->geomArray || r != geometry() ) {
1893 QLayout::setGeometry( r );
1894 if ( !data->geomArray )
1895 setupGeom();
1896 QRect cr = alignment() ? alignmentRect( r ) : r;
1897 QRect s( cr.x() + margin(), cr.y() + margin(),
1898 cr.width() - 2 * margin(), cr.height() - 2 * margin() );
1899
1900 QMemArray<QLayoutStruct> a = *data->geomArray;
1901 int pos = horz( dir ) ? s.x() : s.y();
1902 int space = horz( dir ) ? s.width() : s.height();
1903 int n = a.count();
1904 if ( data->hasHfw && !horz(dir) ) {
1905 for ( int i = 0; i < n; i++ ) {
1906 QBoxLayoutItem *box = data->list.at( i );
1907 if ( box->item->hasHeightForWidth() )
1908 a[i].sizeHint = a[i].minimumSize =
1909 box->item->heightForWidth( s.width() );
1910 }
1911 }
1912
1913 Direction visualDir = dir;
1914 if ( QApplication::reverseLayout() ) {
1915 if ( dir == LeftToRight )
1916 visualDir = RightToLeft;
1917 else if ( dir == RightToLeft )
1918 visualDir = LeftToRight;
1919 }
1920
1921 qGeomCalc( a, 0, n, pos, space, spacing() );
1922 for ( int i = 0; i < n; i++ ) {
1923 QBoxLayoutItem *box = data->list.at( i );
1924
1925 switch ( visualDir ) {
1926 case LeftToRight:
1927 box->item->setGeometry( QRect(a[i].pos, s.y(),
1928 a[i].size, s.height()) );
1929 break;
1930 case RightToLeft:
1931 box->item->setGeometry( QRect(s.left() + s.right()
1932 - a[i].pos - a[i].size + 1, s.y(),
1933 a[i].size, s.height()) );
1934 break;
1935 case TopToBottom:
1936 box->item->setGeometry( QRect(s.x(), a[i].pos,
1937 s.width(), a[i].size) );
1938 break;
1939 case BottomToTop:
1940 box->item->setGeometry( QRect(s.x(), s.top() + s.bottom()
1941 - a[i].pos - a[i].size + 1,
1942 s.width(), a[i].size) );
1943 }
1944 }
1945 }
1946}
1947
1948/*!
1949 Adds \a item to the end of this box layout.
1950*/
1951void QBoxLayout::addItem( QLayoutItem *item )
1952{
1953 QBoxLayoutItem *it = new QBoxLayoutItem( item );
1954 data->list.append( it );
1955 invalidate();
1956}
1957
1958/*!
1959 Inserts \a item into this box layout at position \a index. If \a
1960 index is negative, the item is added at the end.
1961
1962 \warning Does not call QLayout::insertChildLayout() if \a item is
1963 a QLayout.
1964
1965 \sa addItem(), findWidget()
1966*/
1967void QBoxLayout::insertItem( int index, QLayoutItem *item )
1968{
1969 if ( index < 0 ) // append
1970 index = data->list.count();
1971
1972 QBoxLayoutItem *it = new QBoxLayoutItem( item );
1973 data->list.insert( index, it );
1974 invalidate();
1975}
1976
1977/*!
1978 Inserts a non-stretchable space at position \a index, with size \a
1979 size. If \a index is negative the space is added at the end.
1980
1981 The box layout has default margin and spacing. This function adds
1982 additional space.
1983
1984 \sa insertStretch()
1985*/
1986void QBoxLayout::insertSpacing( int index, int size )
1987{
1988 if ( index < 0 ) // append
1989 index = data->list.count();
1990
1991 // hack in QGridLayoutData: spacers do not get insideSpacing
1992 QLayoutItem *b;
1993 if ( horz( dir ) )
1994 b = new QSpacerItem( size, 0, QSizePolicy::Fixed,
1995 QSizePolicy::Minimum );
1996 else
1997 b = new QSpacerItem( 0, size, QSizePolicy::Minimum,
1998 QSizePolicy::Fixed );
1999
2000 QBoxLayoutItem *it = new QBoxLayoutItem( b );
2001 it->magic = TRUE;
2002 data->list.insert( index, it );
2003 invalidate();
2004}
2005
2006/*!
2007 Inserts a stretchable space at position \a index, with zero
2008 minimum size and stretch factor \a stretch. If \a index is
2009 negative the space is added at the end.
2010
2011 \sa insertSpacing()
2012*/
2013void QBoxLayout::insertStretch( int index, int stretch )
2014{
2015 if ( index < 0 ) // append
2016 index = data->list.count();
2017
2018 // hack in QGridLayoutData: spacers do not get insideSpacing
2019 QLayoutItem *b;
2020 if ( horz( dir ) )
2021 b = new QSpacerItem( 0, 0, QSizePolicy::Expanding,
2022 QSizePolicy::Minimum );
2023 else
2024 b = new QSpacerItem( 0, 0, QSizePolicy::Minimum,
2025 QSizePolicy::Expanding );
2026
2027 QBoxLayoutItem *it = new QBoxLayoutItem( b, stretch );
2028 it->magic = TRUE;
2029 data->list.insert( index, it );
2030 invalidate();
2031}
2032
2033/*!
2034 Inserts \a layout at position \a index, with stretch factor \a
2035 stretch. If \a index is negative, the layout is added at the end.
2036
2037 \a layout becomes a child of the box layout.
2038
2039 \sa setAutoAdd(), insertWidget(), insertSpacing()
2040*/
2041void QBoxLayout::insertLayout( int index, QLayout *layout, int stretch )
2042{
2043 if ( index < 0 ) // append
2044 index = data->list.count();
2045
2046 addChildLayout( layout );
2047 QBoxLayoutItem *it = new QBoxLayoutItem( layout, stretch );
2048 data->list.insert( index, it );
2049 invalidate();
2050}
2051
2052/*!
2053 Inserts \a widget at position \a index, with stretch factor \a
2054 stretch and alignment \a alignment. If \a index is negative, the
2055 widget is added at the end.
2056
2057 The stretch factor applies only in the \link direction() direction
2058 \endlink of the QBoxLayout, and is relative to the other boxes and
2059 widgets in this QBoxLayout. Widgets and boxes with higher stretch
2060 factors grow more.
2061
2062 If the stretch factor is 0 and nothing else in the QBoxLayout has
2063 a stretch factor greater than zero, the space is distributed
2064 according to the QWidget:sizePolicy() of each widget that's
2065 involved.
2066
2067 Alignment is specified by \a alignment, which is a bitwise OR of
2068 \l Qt::AlignmentFlags values. The default alignment is 0, which
2069 means that the widget fills the entire cell.
2070
2071 From Qt 3.0, the \a alignment parameter is interpreted more
2072 aggressively than in previous versions of Qt. A non-default
2073 alignment now indicates that the widget should not grow to fill
2074 the available space, but should be sized according to sizeHint().
2075
2076 \sa setAutoAdd(), insertLayout(), insertSpacing()
2077*/
2078void QBoxLayout::insertWidget( int index, QWidget *widget, int stretch,
2079 int alignment )
2080{
2081 if ( !checkWidget(this, widget) )
2082 return;
2083
2084 if ( index < 0 ) // append
2085 index = data->list.count();
2086
2087 QWidgetItem *b = new QWidgetItem( widget );
2088 b->setAlignment( alignment );
2089 QBoxLayoutItem *it = new QBoxLayoutItem( b, stretch );
2090 data->list.insert( index, it );
2091 invalidate();
2092}
2093
2094/*!
2095 Adds a non-stretchable space with size \a size to the end of this
2096 box layout. QBoxLayout provides default margin and spacing. This
2097 function adds additional space.
2098
2099 \sa insertSpacing(), addStretch()
2100*/
2101void QBoxLayout::addSpacing( int size )
2102{
2103 insertSpacing( -1, size );
2104}
2105
2106/*!
2107 Adds a stretchable space with zero minimum size and stretch factor
2108 \a stretch to the end of this box layout.
2109
2110 \sa addSpacing()
2111*/
2112void QBoxLayout::addStretch( int stretch )
2113{
2114 insertStretch( -1, stretch );
2115}
2116
2117/*!
2118 Adds \a widget to the end of this box layout, with a stretch
2119 factor of \a stretch and alignment \a alignment.
2120
2121 The stretch factor applies only in the \link direction() direction
2122 \endlink of the QBoxLayout, and is relative to the other boxes and
2123 widgets in this QBoxLayout. Widgets and boxes with higher stretch
2124 factors grow more.
2125
2126 If the stretch factor is 0 and nothing else in the QBoxLayout has
2127 a stretch factor greater than zero, the space is distributed
2128 according to the QWidget:sizePolicy() of each widget that's
2129 involved.
2130
2131 Alignment is specified by \a alignment which is a bitwise OR of \l
2132 Qt::AlignmentFlags values. The default alignment is 0, which means
2133 that the widget fills the entire cell.
2134
2135 From Qt 3.0, the \a alignment parameter is interpreted more
2136 aggressively than in previous versions of Qt. A non-default
2137 alignment now indicates that the widget should not grow to fill
2138 the available space, but should be sized according to sizeHint().
2139
2140 \sa insertWidget(), setAutoAdd(), addLayout(), addSpacing()
2141*/
2142void QBoxLayout::addWidget( QWidget *widget, int stretch,
2143 int alignment )
2144{
2145 insertWidget( -1, widget, stretch, alignment );
2146}
2147
2148/*!
2149 Adds \a layout to the end of the box, with serial stretch factor
2150 \a stretch.
2151
2152 \sa insertLayout(), setAutoAdd(), addWidget(), addSpacing()
2153*/
2154void QBoxLayout::addLayout( QLayout *layout, int stretch )
2155{
2156 insertLayout( -1, layout, stretch );
2157}
2158
2159/*!
2160 Limits the perpendicular dimension of the box (e.g. height if the
2161 box is LeftToRight) to a minimum of \a size. Other constraints may
2162 increase the limit.
2163*/
2164void QBoxLayout::addStrut( int size )
2165{
2166 QLayoutItem *b;
2167 if ( horz( dir ) )
2168 b = new QSpacerItem( 0, size, QSizePolicy::Fixed,
2169 QSizePolicy::Minimum );
2170 else
2171 b = new QSpacerItem( size, 0, QSizePolicy::Minimum,
2172 QSizePolicy::Fixed );
2173
2174 QBoxLayoutItem *it = new QBoxLayoutItem( b );
2175 it->magic = TRUE;
2176 data->list.append( it );
2177 invalidate();
2178}
2179
2180/*!
2181 Searches for widget \a w in this layout (not including child
2182 layouts).
2183
2184 Returns the index of \a w, or -1 if \a w is not found.
2185*/
2186int QBoxLayout::findWidget( QWidget* w )
2187{
2188 const int n = data->list.count();
2189 for ( int i = 0; i < n; i++ ) {
2190 if ( data->list.at(i)->item->widget() == w )
2191 return i;
2192 }
2193 return -1;
2194}
2195
2196/*!
2197 Sets the stretch factor for widget \a w to \a stretch and returns
2198 TRUE if \a w is found in this layout (not including child
2199 layouts); otherwise returns FALSE.
2200*/
2201bool QBoxLayout::setStretchFactor( QWidget *w, int stretch )
2202{
2203 QPtrListIterator<QBoxLayoutItem> it( data->list );
2204 QBoxLayoutItem *box;
2205 while ( (box=it.current()) != 0 ) {
2206 ++it;
2207 if ( box->item->widget() == w ) {
2208 box->stretch = stretch;
2209 invalidate();
2210 return TRUE;
2211 }
2212 }
2213 return FALSE;
2214}
2215
2216/*!
2217 \overload
2218
2219 Sets the stretch factor for the layout \a l to \a stretch and
2220 returns TRUE if \a l is found in this layout (not including child
2221 layouts); otherwise returns FALSE.
2222*/
2223bool QBoxLayout::setStretchFactor( QLayout *l, int stretch )
2224{
2225 QPtrListIterator<QBoxLayoutItem> it( data->list );
2226 QBoxLayoutItem *box;
2227 while ( (box=it.current()) != 0 ) {
2228 ++it;
2229 if ( box->item->layout() == l ) {
2230 box->stretch = stretch;
2231 invalidate();
2232 return TRUE;
2233 }
2234 }
2235 return FALSE;
2236}
2237
2238/*!
2239 Sets the direction of this layout to \a direction.
2240*/
2241void QBoxLayout::setDirection( Direction direction )
2242{
2243 if ( dir == direction )
2244 return;
2245 if ( horz(dir) != horz(direction) ) {
2246 //swap around the spacers (the "magic" bits)
2247 //#### a bit yucky, knows too much.
2248 //#### probably best to add access functions to spacerItem
2249 //#### or even a QSpacerItem::flip()
2250 QPtrListIterator<QBoxLayoutItem> it( data->list );
2251 QBoxLayoutItem *box;
2252 while ( (box=it.current()) != 0 ) {
2253 ++it;
2254 if ( box->magic ) {
2255 QSpacerItem *sp = box->item->spacerItem();
2256 if ( sp ) {
2257 if ( sp->expanding() == QSizePolicy::NoDirection ) {
2258 //spacing or strut
2259 QSize s = sp->sizeHint();
2260 sp->changeSize( s.height(), s.width(),
2261 horz(direction) ? QSizePolicy::Fixed:QSizePolicy::Minimum,
2262 horz(direction) ? QSizePolicy::Minimum:QSizePolicy::Fixed );
2263
2264 } else {
2265 //stretch
2266 if ( horz(direction) )
2267 sp->changeSize( 0, 0, QSizePolicy::Expanding,
2268 QSizePolicy::Minimum );
2269 else
2270 sp->changeSize( 0, 0, QSizePolicy::Minimum,
2271 QSizePolicy::Expanding );
2272 }
2273 }
2274 }
2275 }
2276 }
2277 dir = direction;
2278 invalidate();
2279 if ( mainWidget() ) {
2280 QEvent *lh = new QEvent( QEvent::LayoutHint );
2281 QApplication::postEvent( mainWidget(), lh );
2282 }
2283
2284}
2285
2286/*
2287 Initializes the data structure needed by qGeomCalc and
2288 recalculates max/min and size hint.
2289*/
2290void QBoxLayout::setupGeom()
2291{
2292 if ( !data->dirty )
2293 return;
2294
2295 int maxw = horz( dir ) ? 0 : QLAYOUTSIZE_MAX;
2296 int maxh = horz( dir ) ? QLAYOUTSIZE_MAX : 0;
2297 int minw = 0;
2298 int minh = 0;
2299 int hintw = 0;
2300 int hinth = 0;
2301
2302 bool horexp = FALSE;
2303 bool verexp = FALSE;
2304
2305 data->hasHfw = FALSE;
2306
2307 delete data->geomArray;
2308 int n = data->list.count();
2309 data->geomArray = new QMemArray<QLayoutStruct>( n );
2310 QMemArray<QLayoutStruct>& a = *data->geomArray;
2311
2312 bool first = TRUE;
2313 for ( int i = 0; i < n; i++ ) {
2314 QBoxLayoutItem *box = data->list.at( i );
2315 QSize max = box->item->maximumSize();
2316 QSize min = box->item->minimumSize();
2317 QSize hint = box->item->sizeHint();
2318 QSizePolicy::ExpandData exp = box->item->expanding();
2319 bool empty = box->item->isEmpty();
2320 // space before non-empties, except the first:
2321 int space = ( empty || first ) ? 0 : spacing();
2322 bool ignore = empty && box->item->widget(); // ignore hidden widgets
2323
2324 if ( horz(dir) ) {
2325 bool expand = exp & QSizePolicy::Horizontally || box->stretch > 0;
2326 horexp = horexp || expand;
2327 maxw += max.width() + space;
2328 minw += min.width() + space;
2329 hintw += hint.width() + space;
2330 if ( !ignore )
2331 qMaxExpCalc( maxh, verexp,
2332 max.height(), exp & QSizePolicy::Vertically );
2333 minh = QMAX( minh, min.height() );
2334 hinth = QMAX( hinth, hint.height() );
2335
2336 a[i].sizeHint = hint.width();
2337 a[i].maximumSize = max.width();
2338 a[i].minimumSize = min.width();
2339 a[i].expansive = expand;
2340 a[i].stretch = box->stretch ? box->stretch : box->hStretch();
2341 } else {
2342 bool expand = ( exp & QSizePolicy::Vertically || box->stretch > 0 );
2343 verexp = verexp || expand;
2344 maxh += max.height() + space;
2345 minh += min.height() + space;
2346 hinth += hint.height() + space;
2347 if ( !ignore )
2348 qMaxExpCalc( maxw, horexp,
2349 max.width(), exp & QSizePolicy::Horizontally );
2350 minw = QMAX( minw, min.width() );
2351 hintw = QMAX( hintw, hint.width() );
2352
2353 a[i].sizeHint = hint.height();
2354 a[i].maximumSize = max.height();
2355 a[i].minimumSize = min.height();
2356 a[i].expansive = expand;
2357 a[i].stretch = box->stretch ? box->stretch : box->vStretch();
2358 }
2359
2360 a[i].empty = empty;
2361 data->hasHfw = data->hasHfw || box->item->hasHeightForWidth();
2362 first = first && empty;
2363 }
2364
2365 data->expanding = (QSizePolicy::ExpandData)
2366 ( (horexp ? QSizePolicy::Horizontally : 0)
2367 | (verexp ? QSizePolicy::Vertically : 0) );
2368
2369 data->minSize = QSize( minw, minh );
2370 data->maxSize = QSize( maxw, maxh ).expandedTo( data->minSize );
2371 data->sizeHint = QSize( hintw, hinth )
2372 .expandedTo( data->minSize )
2373 .boundedTo( data->maxSize );
2374
2375 data->dirty = FALSE;
2376}
2377
2378/*
2379 Calculates and stores the preferred height given the width \a w.
2380*/
2381void QBoxLayout::calcHfw( int w )
2382{
2383 int h = 0;
2384 int mh = 0;
2385
2386 if ( horz(dir) ) {
2387 QMemArray<QLayoutStruct> &a = *data->geomArray;
2388 int n = a.count();
2389 qGeomCalc( a, 0, n, 0, w, spacing() );
2390 for ( int i = 0; i < n; i++ ) {
2391 QBoxLayoutItem *box = data->list.at(i);
2392 h = QMAX( h, box->hfw(a[i].size) );
2393 mh = QMAX( mh, box->mhfw(a[i].size) );
2394 }
2395 } else {
2396 QPtrListIterator<QBoxLayoutItem> it( data->list );
2397 QBoxLayoutItem *box;
2398 bool first = TRUE;
2399 while ( (box = it.current()) != 0 ) {
2400 ++it;
2401 bool empty = box->item->isEmpty();
2402 h += box->hfw( w );
2403 mh += box->mhfw( w );
2404 if ( !first && !empty ) {
2405 h += spacing();
2406 mh += spacing();
2407 }
2408 first = first && empty;
2409 }
2410 }
2411 data->hfwWidth = w;
2412 data->hfwHeight = h;
2413 data->hfwMinHeight = mh;
2414}
2415
2416/*!
2417 \fn QBoxLayout::Direction QBoxLayout::direction() const
2418
2419 Returns the direction of the box. addWidget() and addSpacing()
2420 work in this direction; the stretch stretches in this direction.
2421
2422 \sa QBoxLayout::Direction addWidget() addSpacing()
2423*/
2424
2425/*!
2426 \class QHBoxLayout
2427 \brief The QHBoxLayout class lines up widgets horizontally.
2428
2429 \ingroup geomanagement
2430 \ingroup appearance
2431 \mainclass
2432
2433 This class is used to construct horizontal box layout objects. See
2434 \l QBoxLayout for more details.
2435
2436 The simplest use of the class is like this:
2437 \code
2438 QBoxLayout * l = new QHBoxLayout( widget );
2439 l->setAutoAdd( TRUE );
2440 new QSomeWidget( widget );
2441 new QSomeOtherWidget( widget );
2442 new QAnotherWidget( widget );
2443 \endcode
2444
2445 or like this:
2446 \code
2447 QBoxLayout * l = new QHBoxLayout( widget );
2448 l->addWidget( existingChildOfWidget );
2449 l->addWidget( anotherChildOfWidget );
2450 \endcode
2451
2452 \img qhboxlayout.png QHBox
2453
2454 \sa QVBoxLayout QGridLayout
2455 \link layout.html the Layout overview \endlink
2456*/
2457
2458/*!
2459 Constructs a new top-level horizontal box called \a name, with
2460 parent \a parent.
2461
2462 The \a margin is the number of pixels between the edge of the
2463 widget and its managed children. The \a spacing is the default
2464 number of pixels between neighboring children. If \a spacing is -1
2465 the value of \a margin is used for \a spacing.
2466*/
2467QHBoxLayout::QHBoxLayout( QWidget *parent, int margin,
2468 int spacing, const char *name )
2469 : QBoxLayout( parent, LeftToRight, margin, spacing, name )
2470{
2471}
2472
2473/*!
2474 Constructs a new horizontal box called name \a name and adds it to
2475 \a parentLayout.
2476
2477 The \a spacing is the default number of pixels between neighboring
2478 children. If \a spacing is -1, this QHBoxLayout will inherit its
2479 parent's spacing().
2480*/
2481QHBoxLayout::QHBoxLayout( QLayout *parentLayout, int spacing,
2482 const char *name )
2483 : QBoxLayout( parentLayout, LeftToRight, spacing, name )
2484{
2485}
2486
2487/*!
2488 Constructs a new horizontal box called name \a name. You must add
2489 it to another layout.
2490
2491 The \a spacing is the default number of pixels between neighboring
2492 children. If \a spacing is -1, this QHBoxLayout will inherit its
2493 parent's spacing().
2494*/
2495QHBoxLayout::QHBoxLayout( int spacing, const char *name )
2496 : QBoxLayout( LeftToRight, spacing, name )
2497{
2498}
2499
2500/*!
2501 Destroys this box layout.
2502
2503 The layout's widgets aren't destroyed.
2504*/
2505QHBoxLayout::~QHBoxLayout()
2506{
2507}
2508
2509/*!
2510 \class QVBoxLayout
2511
2512 \brief The QVBoxLayout class lines up widgets vertically.
2513
2514 \ingroup geomanagement
2515 \ingroup appearance
2516 \mainclass
2517
2518 This class is used to construct vertical box layout objects. See
2519 QBoxLayout for more details.
2520
2521 The simplest use of the class is like this:
2522 \code
2523 QBoxLayout * l = new QVBoxLayout( widget );
2524 l->addWidget( aWidget );
2525 l->addWidget( anotherWidget );
2526 \endcode
2527
2528 \img qvboxlayout.png QVBox
2529
2530 \sa QHBoxLayout QGridLayout \link layout.html the Layout overview \endlink
2531*/
2532
2533/*!
2534 Constructs a new top-level vertical box called \a name, with
2535 parent \a parent.
2536
2537 The \a margin is the number of pixels between the edge of the
2538 widget and its managed children. The \a spacing is the default
2539 number of pixels between neighboring children. If \a spacing is -1
2540 the value of \a margin is used for \a spacing.
2541*/
2542QVBoxLayout::QVBoxLayout( QWidget *parent, int margin, int spacing,
2543 const char *name )
2544 : QBoxLayout( parent, TopToBottom, margin, spacing, name )
2545{
2546
2547}
2548
2549/*!
2550 Constructs a new vertical box called name \a name and adds it to
2551 \a parentLayout.
2552
2553 The \a spacing is the default number of pixels between neighboring
2554 children. If \a spacing is -1, this QVBoxLayout will inherit its
2555 parent's spacing().
2556*/
2557QVBoxLayout::QVBoxLayout( QLayout *parentLayout, int spacing,
2558 const char *name )
2559 : QBoxLayout( parentLayout, TopToBottom, spacing, name )
2560{
2561}
2562
2563/*!
2564 Constructs a new vertical box called name \a name. You must add
2565 it to another layout.
2566
2567 The \a spacing is the default number of pixels between neighboring
2568 children. If \a spacing is -1, this QVBoxLayout will inherit its
2569 parent's spacing().
2570*/
2571QVBoxLayout::QVBoxLayout( int spacing, const char *name )
2572 : QBoxLayout( TopToBottom, spacing, name )
2573{
2574}
2575
2576/*!
2577 Destroys this box layout.
2578
2579 The layout's widgets aren't destroyed.
2580*/
2581QVBoxLayout::~QVBoxLayout()
2582{
2583}
2584
2585QBoxLayout *QBoxLayout::createTmpCopy()
2586{
2587 QBoxLayout *bl = new QBoxLayout( direction() );
2588 delete bl->data;
2589 bl->data = data;
2590 return bl;
2591}
2592
2593#endif // QT_NO_LAYOUT
Note: See TracBrowser for help on using the repository browser.