d05efaa5b03520bbce0e560d828b080175c3171b
[profile/ivi/qtbase.git] / src / widgets / kernel / qboxlayout.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qboxlayout.h"
43 #include "qapplication.h"
44 #include "qwidget.h"
45 #include "qlist.h"
46 #include "qsizepolicy.h"
47 #include "qvector.h"
48
49 #include "qlayoutengine_p.h"
50 #include "qlayout_p.h"
51
52 QT_BEGIN_NAMESPACE
53
54 /*
55     Returns true if the \a widget can be added to the \a layout;
56     otherwise returns false.
57 */
58 static bool checkWidget(QLayout *layout, QWidget *widget)
59 {
60     if (!widget) {
61         qWarning("QLayout: Cannot add null widget to %s/%s", layout->metaObject()->className(),
62                   layout->objectName().toLocal8Bit().data());
63         return false;
64     }
65     return true;
66 }
67
68 struct QBoxLayoutItem
69 {
70     QBoxLayoutItem(QLayoutItem *it, int stretch_ = 0)
71         : item(it), stretch(stretch_), magic(false) { }
72     ~QBoxLayoutItem() { delete item; }
73
74     int hfw(int w) {
75         if (item->hasHeightForWidth()) {
76             return item->heightForWidth(w);
77         } else {
78             return item->sizeHint().height();
79         }
80     }
81     int mhfw(int w) {
82         if (item->hasHeightForWidth()) {
83             return item->heightForWidth(w);
84         } else {
85             return item->minimumSize().height();
86         }
87     }
88     int hStretch() {
89         if (stretch == 0 && item->widget()) {
90             return item->widget()->sizePolicy().horizontalStretch();
91         } else {
92             return stretch;
93         }
94     }
95     int vStretch() {
96         if (stretch == 0 && item->widget()) {
97             return item->widget()->sizePolicy().verticalStretch();
98         } else {
99             return stretch;
100         }
101     }
102
103     QLayoutItem *item;
104     int stretch;
105     bool magic;
106 };
107
108 class QBoxLayoutPrivate : public QLayoutPrivate
109 {
110     Q_DECLARE_PUBLIC(QBoxLayout)
111 public:
112     QBoxLayoutPrivate() : hfwWidth(-1), dirty(true), spacing(-1) { }
113     ~QBoxLayoutPrivate();
114
115     void setDirty() {
116         geomArray.clear();
117         hfwWidth = -1;
118         hfwHeight = -1;
119         dirty = true;
120     }
121
122     QList<QBoxLayoutItem *> list;
123     QVector<QLayoutStruct> geomArray;
124     int hfwWidth;
125     int hfwHeight;
126     int hfwMinHeight;
127     QSize sizeHint;
128     QSize minSize;
129     QSize maxSize;
130     int leftMargin, topMargin, rightMargin, bottomMargin;
131     Qt::Orientations expanding;
132     uint hasHfw : 1;
133     uint dirty : 1;
134     QBoxLayout::Direction dir;
135     int spacing;
136
137     inline void deleteAll() { while (!list.isEmpty()) delete list.takeFirst(); }
138
139     void setupGeom();
140     void calcHfw(int);
141
142     void effectiveMargins(int *left, int *top, int *right, int *bottom) const;
143 };
144
145 QBoxLayoutPrivate::~QBoxLayoutPrivate()
146 {
147 }
148
149 static inline bool horz(QBoxLayout::Direction dir)
150 {
151     return dir == QBoxLayout::RightToLeft || dir == QBoxLayout::LeftToRight;
152 }
153
154 /**
155  * The purpose of this function is to make sure that widgets are not laid out outside its layout.
156  * E.g. the layoutItemRect margins are only meant to take of the surrounding margins/spacings.
157  * However, if the margin is 0, it can easily cover the area of a widget above it.
158  */
159 void QBoxLayoutPrivate::effectiveMargins(int *left, int *top, int *right, int *bottom) const
160 {
161     int l = leftMargin;
162     int t = topMargin;
163     int r = rightMargin;
164     int b = bottomMargin;
165 #ifdef Q_WS_MAC
166     Q_Q(const QBoxLayout);
167     if (horz(dir)) {
168         QBoxLayoutItem *leftBox = 0;
169         QBoxLayoutItem *rightBox = 0;
170
171         if (left || right) {
172             leftBox = list.value(0);
173             rightBox = list.value(list.count() - 1);
174             if (dir == QBoxLayout::RightToLeft)
175                 qSwap(leftBox, rightBox);
176
177             int leftDelta = 0;
178             int rightDelta = 0;
179             if (leftBox) {
180                 QLayoutItem *itm = leftBox->item;
181                 if (QWidget *w = itm->widget())
182                     leftDelta = itm->geometry().left() - w->geometry().left();
183             }
184             if (rightBox) {
185                 QLayoutItem *itm = rightBox->item;
186                 if (QWidget *w = itm->widget())
187                     rightDelta = w->geometry().right() - itm->geometry().right();
188             }
189             QWidget *w = q->parentWidget();
190             Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : QApplication::layoutDirection();
191             if (layoutDirection == Qt::RightToLeft)
192                 qSwap(leftDelta, rightDelta);
193
194             l = qMax(l, leftDelta);
195             r = qMax(r, rightDelta);
196         }
197
198         int count = top || bottom ? list.count() : 0;
199         for (int i = 0; i < count; ++i) {
200             QBoxLayoutItem *box = list.at(i);
201             QLayoutItem *itm = box->item;
202             QWidget *w = itm->widget();
203             if (w) {
204                 QRect lir = itm->geometry();
205                 QRect wr = w->geometry();
206                 if (top)
207                     t = qMax(t, lir.top() - wr.top());
208                 if (bottom)
209                     b = qMax(b, wr.bottom() - lir.bottom());
210             }
211         }
212     } else {    // vertical layout
213         QBoxLayoutItem *topBox = 0;
214         QBoxLayoutItem *bottomBox = 0;
215
216         if (top || bottom) {
217             topBox = list.value(0);
218             bottomBox = list.value(list.count() - 1);
219             if (dir == QBoxLayout::BottomToTop) {
220                 qSwap(topBox, bottomBox);
221             }
222
223             if (top && topBox) {
224                 QLayoutItem *itm = topBox->item;
225                 QWidget *w = itm->widget();
226                 if (w)
227                     t = qMax(t, itm->geometry().top() - w->geometry().top());
228             }
229
230             if (bottom && bottomBox) {
231                 QLayoutItem *itm = bottomBox->item;
232                 QWidget *w = itm->widget();
233                 if (w)
234                     b = qMax(b, w->geometry().bottom() - itm->geometry().bottom());
235             }
236         }
237
238         int count = left || right ? list.count() : 0;
239         for (int i = 0; i < count; ++i) {
240             QBoxLayoutItem *box = list.at(i);
241             QLayoutItem *itm = box->item;
242             QWidget *w = itm->widget();
243             if (w) {
244                 QRect lir = itm->geometry();
245                 QRect wr = w->geometry();
246                 if (left)
247                     l = qMax(l, lir.left() - wr.left());
248                 if (right)
249                     r = qMax(r, wr.right() - lir.right());
250             }
251         }        
252     }
253 #endif
254     if (left)
255         *left = l;
256     if (top)
257         *top = t;
258     if (right)
259         *right = r;
260     if (bottom)
261         *bottom = b;
262 }
263
264
265 /*
266     Initializes the data structure needed by qGeomCalc and
267     recalculates max/min and size hint.
268 */
269 void QBoxLayoutPrivate::setupGeom()
270 {
271     if (!dirty)
272         return;
273
274     Q_Q(QBoxLayout);
275     int maxw = horz(dir) ? 0 : QLAYOUTSIZE_MAX;
276     int maxh = horz(dir) ? QLAYOUTSIZE_MAX : 0;
277     int minw = 0;
278     int minh = 0;
279     int hintw = 0;
280     int hinth = 0;
281
282     bool horexp = false;
283     bool verexp = false;
284
285     hasHfw = false;
286
287     int n = list.count();
288     geomArray.clear();
289     QVector<QLayoutStruct> a(n);
290
291     QSizePolicy::ControlTypes controlTypes1;
292     QSizePolicy::ControlTypes controlTypes2;
293     int fixedSpacing = q->spacing();
294     int previousNonEmptyIndex = -1;
295
296     QStyle *style = 0;
297     if (fixedSpacing < 0) {
298         if (QWidget *parentWidget = q->parentWidget())
299             style = parentWidget->style();
300     }
301
302     for (int i = 0; i < n; i++) {
303         QBoxLayoutItem *box = list.at(i);
304         QSize max = box->item->maximumSize();
305         QSize min = box->item->minimumSize();
306         QSize hint = box->item->sizeHint();
307         Qt::Orientations exp = box->item->expandingDirections();
308         bool empty = box->item->isEmpty();
309         int spacing = 0;
310
311         if (!empty) {
312             if (fixedSpacing >= 0) {
313                 spacing = (previousNonEmptyIndex >= 0) ? fixedSpacing : 0;
314 #ifdef Q_WS_MAC
315                 if (!horz(dir) && previousNonEmptyIndex >= 0) {
316                     QBoxLayoutItem *sibling = (dir == QBoxLayout::TopToBottom  ? box : list.at(previousNonEmptyIndex));
317                     if (sibling) {
318                         QWidget *wid = sibling->item->widget();
319                         if (wid)
320                             spacing = qMax(spacing, sibling->item->geometry().top() - wid->geometry().top());
321                     }
322                 }
323 #endif
324             } else {
325                 controlTypes1 = controlTypes2;
326                 controlTypes2 = box->item->controlTypes();
327                 if (previousNonEmptyIndex >= 0) {
328                     QSizePolicy::ControlTypes actual1 = controlTypes1;
329                     QSizePolicy::ControlTypes actual2 = controlTypes2;
330                     if (dir == QBoxLayout::RightToLeft || dir == QBoxLayout::BottomToTop)
331                         qSwap(actual1, actual2);
332
333                     if (style) {
334                         spacing = style->combinedLayoutSpacing(actual1, actual2,
335                                              horz(dir) ? Qt::Horizontal : Qt::Vertical,
336                                              0, q->parentWidget());
337                         if (spacing < 0)
338                             spacing = 0;
339                     }
340                 }
341             }
342
343             if (previousNonEmptyIndex >= 0)
344                 a[previousNonEmptyIndex].spacing = spacing;
345             previousNonEmptyIndex = i;
346         }
347
348         bool ignore = empty && box->item->widget(); // ignore hidden widgets
349         bool dummy = true;
350         if (horz(dir)) {
351             bool expand = (exp & Qt::Horizontal || box->stretch > 0);
352             horexp = horexp || expand;
353             maxw += spacing + max.width();
354             minw += spacing + min.width();
355             hintw += spacing + hint.width();
356             if (!ignore)
357                 qMaxExpCalc(maxh, verexp, dummy,
358                             max.height(), exp & Qt::Vertical, box->item->isEmpty());
359             minh = qMax(minh, min.height());
360             hinth = qMax(hinth, hint.height());
361
362             a[i].sizeHint = hint.width();
363             a[i].maximumSize = max.width();
364             a[i].minimumSize = min.width();
365             a[i].expansive = expand;
366             a[i].stretch = box->stretch ? box->stretch : box->hStretch();
367         } else {
368             bool expand = (exp & Qt::Vertical || box->stretch > 0);
369             verexp = verexp || expand;
370             maxh += spacing + max.height();
371             minh += spacing + min.height();
372             hinth += spacing + hint.height();
373             if (!ignore)
374                 qMaxExpCalc(maxw, horexp, dummy,
375                             max.width(), exp & Qt::Horizontal, box->item->isEmpty());
376             minw = qMax(minw, min.width());
377             hintw = qMax(hintw, hint.width());
378
379             a[i].sizeHint = hint.height();
380             a[i].maximumSize = max.height();
381             a[i].minimumSize = min.height();
382             a[i].expansive = expand;
383             a[i].stretch = box->stretch ? box->stretch : box->vStretch();
384         }
385
386         a[i].empty = empty;
387         a[i].spacing = 0;   // might be initialized with a non-zero value in a later iteration
388         hasHfw = hasHfw || box->item->hasHeightForWidth();
389     }
390
391     geomArray = a;
392
393     expanding = (Qt::Orientations)
394                        ((horexp ? Qt::Horizontal : 0)
395                          | (verexp ? Qt::Vertical : 0));
396
397     minSize = QSize(minw, minh);
398     maxSize = QSize(maxw, maxh).expandedTo(minSize);
399     sizeHint = QSize(hintw, hinth).expandedTo(minSize).boundedTo(maxSize);
400
401     q->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
402     int left, top, right, bottom;
403     effectiveMargins(&left, &top, &right, &bottom);
404     QSize extra(left + right, top + bottom);
405
406     minSize += extra;
407     maxSize += extra;
408     sizeHint += extra;
409
410     dirty = false;
411 }
412
413 /*
414   Calculates and stores the preferred height given the width \a w.
415 */
416 void QBoxLayoutPrivate::calcHfw(int w)
417 {
418     QVector<QLayoutStruct> &a = geomArray;
419     int n = a.count();
420     int h = 0;
421     int mh = 0;
422
423     Q_ASSERT(n == list.size());
424
425     if (horz(dir)) {
426         qGeomCalc(a, 0, n, 0, w);
427         for (int i = 0; i < n; i++) {
428             QBoxLayoutItem *box = list.at(i);
429             h = qMax(h, box->hfw(a.at(i).size));
430             mh = qMax(mh, box->mhfw(a.at(i).size));
431         }
432     } else {
433         for (int i = 0; i < n; ++i) {
434             QBoxLayoutItem *box = list.at(i);
435             int spacing = a.at(i).spacing;
436             h += box->hfw(w);
437             mh += box->mhfw(w);
438             h += spacing;
439             mh += spacing;
440         }
441     }
442     hfwWidth = w;
443     hfwHeight = h;
444     hfwMinHeight = mh;
445 }
446
447
448 /*!
449     \class QBoxLayout
450
451     \brief The QBoxLayout class lines up child widgets horizontally or
452     vertically.
453
454     \ingroup geomanagement
455     \inmodule QtWidgets
456
457     QBoxLayout takes the space it gets (from its parent layout or from
458     the parentWidget()), divides it up into a row of boxes, and makes
459     each managed widget fill one box.
460
461     \image qhboxlayout-with-5-children.png Horizontal box layout with five child widgets
462
463     If the QBoxLayout's orientation is Qt::Horizontal the boxes are
464     placed in a row, with suitable sizes. Each widget (or other box)
465     will get at least its minimum size and at most its maximum size.
466     Any excess space is shared according to the stretch factors (more
467     about that below).
468
469     \image qvboxlayout-with-5-children.png Vertical box layout with five child widgets
470
471     If the QBoxLayout's orientation is Qt::Vertical, the boxes are
472     placed in a column, again with suitable sizes.
473
474     The easiest way to create a QBoxLayout is to use one of the
475     convenience classes, e.g. QHBoxLayout (for Qt::Horizontal boxes)
476     or QVBoxLayout (for Qt::Vertical boxes). You can also use the
477     QBoxLayout constructor directly, specifying its direction as
478     LeftToRight, RightToLeft, TopToBottom, or BottomToTop.
479
480     If the QBoxLayout is not the top-level layout (i.e. it is not
481     managing all of the widget's area and children), you must add it
482     to its parent layout before you can do anything with it. The
483     normal way to add a layout is by calling
484     parentLayout-\>addLayout().
485
486     Once you have done this, you can add boxes to the QBoxLayout using
487     one of four functions:
488
489     \list
490     \li addWidget() to add a widget to the QBoxLayout and set the
491     widget's stretch factor. (The stretch factor is along the row of
492     boxes.)
493
494     \li addSpacing() to create an empty box; this is one of the
495     functions you use to create nice and spacious dialogs. See below
496     for ways to set margins.
497
498     \li addStretch() to create an empty, stretchable box.
499
500     \li addLayout() to add a box containing another QLayout to the row
501     and set that layout's stretch factor.
502     \endlist
503
504     Use insertWidget(), insertSpacing(), insertStretch() or
505     insertLayout() to insert a box at a specified position in the
506     layout.
507
508     QBoxLayout also includes two margin widths:
509
510     \list
511     \li setContentsMargins() sets the width of the outer border on
512        each side of the widget. This is the width of the reserved space 
513        along each of the QBoxLayout's four sides.
514     \li setSpacing() sets the width between neighboring boxes. (You
515        can use addSpacing() to get more space at a particular spot.)
516     \endlist
517
518     The margin default is provided by the style. The default margin
519     most Qt styles specify is 9 for child widgets and 11 for windows.
520     The spacing defaults to the same as the margin width for a
521     top-level layout, or to the same as the parent layout.
522
523     To remove a widget from a layout, call removeWidget(). Calling
524     QWidget::hide() on a widget also effectively removes the widget
525     from the layout until QWidget::show() is called.
526
527     You will almost always want to use QVBoxLayout and QHBoxLayout
528     rather than QBoxLayout because of their convenient constructors.
529
530     \sa QGridLayout, QStackedLayout, {Layout Management}
531 */
532
533 /*!
534     \enum QBoxLayout::Direction
535
536     This type is used to determine the direction of a box layout.
537
538     \value LeftToRight  Horizontal from left to right.
539     \value RightToLeft  Horizontal from right to left.
540     \value TopToBottom  Vertical from top to bottom.
541     \value BottomToTop  Vertical from bottom to top.
542
543     \omitvalue Down
544     \omitvalue Up
545 */
546
547 /*!
548     Constructs a new QBoxLayout with direction \a dir and parent widget \a
549     parent.
550
551     \sa direction()
552 */
553 QBoxLayout::QBoxLayout(Direction dir, QWidget *parent)
554     : QLayout(*new QBoxLayoutPrivate, 0, parent)
555 {
556     Q_D(QBoxLayout);
557     d->dir = dir;
558 }
559
560
561
562 /*!
563     Destroys this box layout.
564
565     The layout's widgets aren't destroyed.
566 */
567 QBoxLayout::~QBoxLayout()
568 {
569     Q_D(QBoxLayout);
570     d->deleteAll(); // must do it before QObject deletes children, so can't be in ~QBoxLayoutPrivate
571 }
572
573 /*!
574   Reimplements QLayout::spacing(). If the spacing property is
575   valid, that value is returned. Otherwise, a value for the spacing
576   property is computed and returned. Since layout spacing in a widget
577   is style dependent, if the parent is a widget, it queries the style
578   for the (horizontal or vertical) spacing of the layout. Otherwise,
579   the parent is a layout, and it queries the parent layout for the
580   spacing().
581
582   \sa QLayout::spacing(), setSpacing()
583  */
584 int QBoxLayout::spacing() const
585 {
586     Q_D(const QBoxLayout);
587     if (d->spacing >=0) {
588         return d->spacing;
589     } else {
590         return qSmartSpacing(this, d->dir == LeftToRight || d->dir == RightToLeft
591                                            ? QStyle::PM_LayoutHorizontalSpacing
592                                            : QStyle::PM_LayoutVerticalSpacing);
593     }
594 }
595
596 /*!
597   Reimplements QLayout::setSpacing(). Sets the spacing
598   property to \a spacing. 
599
600   \sa QLayout::setSpacing(), spacing()
601  */
602 void QBoxLayout::setSpacing(int spacing)
603 {
604     Q_D(QBoxLayout);
605     d->spacing = spacing;
606     invalidate();
607 }
608
609 /*!
610     \reimp
611 */
612 QSize QBoxLayout::sizeHint() const
613 {
614     Q_D(const QBoxLayout);
615     if (d->dirty)
616         const_cast<QBoxLayout*>(this)->d_func()->setupGeom();
617     return d->sizeHint;
618 }
619
620 /*!
621     \reimp
622 */
623 QSize QBoxLayout::minimumSize() const
624 {
625     Q_D(const QBoxLayout);
626     if (d->dirty)
627         const_cast<QBoxLayout*>(this)->d_func()->setupGeom();
628     return d->minSize;
629 }
630
631 /*!
632     \reimp
633 */
634 QSize QBoxLayout::maximumSize() const
635 {
636     Q_D(const QBoxLayout);
637     if (d->dirty)
638         const_cast<QBoxLayout*>(this)->d_func()->setupGeom();
639
640     QSize s = d->maxSize.boundedTo(QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX));
641
642     if (alignment() & Qt::AlignHorizontal_Mask)
643         s.setWidth(QLAYOUTSIZE_MAX);
644     if (alignment() & Qt::AlignVertical_Mask)
645         s.setHeight(QLAYOUTSIZE_MAX);
646     return s;
647 }
648
649 /*!
650     \reimp
651 */
652 bool QBoxLayout::hasHeightForWidth() const
653 {
654     Q_D(const QBoxLayout);
655     if (d->dirty)
656         const_cast<QBoxLayout*>(this)->d_func()->setupGeom();
657     return d->hasHfw;
658 }
659
660 /*!
661     \reimp
662 */
663 int QBoxLayout::heightForWidth(int w) const
664 {
665     Q_D(const QBoxLayout);
666     if (!hasHeightForWidth())
667         return -1;
668
669     int left, top, right, bottom;
670     d->effectiveMargins(&left, &top, &right, &bottom);
671
672     w -= left + right;
673     if (w != d->hfwWidth)
674         const_cast<QBoxLayout*>(this)->d_func()->calcHfw(w);
675
676     return d->hfwHeight + top + bottom;
677 }
678
679 /*!
680     \reimp
681 */
682 int QBoxLayout::minimumHeightForWidth(int w) const
683 {
684     Q_D(const QBoxLayout);
685     (void) heightForWidth(w);
686     int top, bottom;
687     d->effectiveMargins(0, &top, 0, &bottom);
688     return d->hasHfw ? (d->hfwMinHeight + top + bottom) : -1;
689 }
690
691 /*!
692     Resets cached information.
693 */
694 void QBoxLayout::invalidate()
695 {
696     Q_D(QBoxLayout);
697     d->setDirty();
698     QLayout::invalidate();
699 }
700
701 /*!
702     \reimp
703 */
704 int QBoxLayout::count() const
705 {
706     Q_D(const QBoxLayout);
707     return d->list.count();
708 }
709
710 /*!
711     \reimp
712 */
713 QLayoutItem *QBoxLayout::itemAt(int index) const
714 {
715     Q_D(const QBoxLayout);
716     return index >= 0 && index < d->list.count() ? d->list.at(index)->item : 0;
717 }
718
719 /*!
720     \reimp
721 */
722 QLayoutItem *QBoxLayout::takeAt(int index)
723 {
724     Q_D(QBoxLayout);
725     if (index < 0 || index >= d->list.count())
726         return 0;
727     QBoxLayoutItem *b = d->list.takeAt(index);
728     QLayoutItem *item = b->item;
729     b->item = 0;
730     delete b;
731
732     invalidate();
733     return item;
734 }
735
736
737 /*!
738     \reimp
739 */
740 Qt::Orientations QBoxLayout::expandingDirections() const
741 {
742     Q_D(const QBoxLayout);
743     if (d->dirty)
744         const_cast<QBoxLayout*>(this)->d_func()->setupGeom();
745     return d->expanding;
746 }
747
748 /*!
749     \reimp
750 */
751 void QBoxLayout::setGeometry(const QRect &r)
752 {
753     Q_D(QBoxLayout);
754     if (d->dirty || r != geometry()) {
755         QRect oldRect = geometry();
756         QLayout::setGeometry(r);
757         if (d->dirty)
758             d->setupGeom();
759         QRect cr = alignment() ? alignmentRect(r) : r;
760
761         int left, top, right, bottom;
762         d->effectiveMargins(&left, &top, &right, &bottom);
763         QRect s(cr.x() + left, cr.y() + top,
764                 cr.width() - (left + right),
765                 cr.height() - (top + bottom));
766
767         QVector<QLayoutStruct> a = d->geomArray;
768         int pos = horz(d->dir) ? s.x() : s.y();
769         int space = horz(d->dir) ? s.width() : s.height();
770         int n = a.count();
771         if (d->hasHfw && !horz(d->dir)) {
772             for (int i = 0; i < n; i++) {
773                 QBoxLayoutItem *box = d->list.at(i);
774                 if (box->item->hasHeightForWidth()) {
775                     int width = qBound(box->item->minimumSize().width(), s.width(), box->item->maximumSize().width());
776                     a[i].sizeHint = a[i].minimumSize =
777                                     box->item->heightForWidth(width);
778                 }
779             }
780         }
781
782         Direction visualDir = d->dir;
783         QWidget *parent = parentWidget();
784         if (parent && parent->isRightToLeft()) {
785             if (d->dir == LeftToRight)
786                 visualDir = RightToLeft;
787             else if (d->dir == RightToLeft)
788                 visualDir = LeftToRight;
789         }
790
791         qGeomCalc(a, 0, n, pos, space);
792
793         bool reverse = (horz(visualDir)
794                         ? ((r.right() > oldRect.right()) != (visualDir == RightToLeft))
795                         : r.bottom() > oldRect.bottom());
796         for (int j = 0; j < n; j++) {
797             int i = reverse ? n-j-1 : j;
798             QBoxLayoutItem *box = d->list.at(i);
799
800             switch (visualDir) {
801             case LeftToRight:
802                 box->item->setGeometry(QRect(a.at(i).pos, s.y(), a.at(i).size, s.height()));
803                 break;
804             case RightToLeft:
805                 box->item->setGeometry(QRect(s.left() + s.right() - a.at(i).pos - a.at(i).size + 1,
806                                              s.y(), a.at(i).size, s.height()));
807                 break;
808             case TopToBottom:
809                 box->item->setGeometry(QRect(s.x(), a.at(i).pos, s.width(), a.at(i).size));
810                 break;
811             case BottomToTop:
812                 box->item->setGeometry(QRect(s.x(),
813                                              s.top() + s.bottom() - a.at(i).pos - a.at(i).size + 1,
814                                              s.width(), a.at(i).size));
815             }
816         }
817     }
818 }
819
820 /*!
821     \reimp
822 */
823 void QBoxLayout::addItem(QLayoutItem *item)
824 {
825     Q_D(QBoxLayout);
826     QBoxLayoutItem *it = new QBoxLayoutItem(item);
827     d->list.append(it);
828     invalidate();
829 }
830
831 /*!
832     Inserts \a item into this box layout at position \a index. If \a
833     index is negative, the item is added at the end.
834
835     \sa addItem(), insertWidget(), insertLayout(), insertStretch(),
836         insertSpacing()
837 */
838 void QBoxLayout::insertItem(int index, QLayoutItem *item)
839 {
840     Q_D(QBoxLayout);
841     if (index < 0)                                // append
842         index = d->list.count();
843
844     QBoxLayoutItem *it = new QBoxLayoutItem(item);
845     d->list.insert(index, it);
846     invalidate();
847 }
848
849 /*!
850     Inserts a non-stretchable space (a QSpacerItem) at position \a index, with
851     size \a size. If \a index is negative the space is added at the end.
852
853     The box layout has default margin and spacing. This function adds
854     additional space.
855
856     \sa addSpacing(), insertItem(), QSpacerItem
857 */
858 void QBoxLayout::insertSpacing(int index, int size)
859 {
860     Q_D(QBoxLayout);
861     if (index < 0)                                // append
862         index = d->list.count();
863
864     QLayoutItem *b;
865     if (horz(d->dir))
866         b = QLayoutPrivate::createSpacerItem(this, size, 0, QSizePolicy::Fixed, QSizePolicy::Minimum);
867     else
868         b = QLayoutPrivate::createSpacerItem(this, 0, size, QSizePolicy::Minimum, QSizePolicy::Fixed);
869
870     QT_TRY {
871         QBoxLayoutItem *it = new QBoxLayoutItem(b);
872         it->magic = true;
873         d->list.insert(index, it);
874
875     } QT_CATCH(...) {
876         delete b;
877         QT_RETHROW;
878     }
879     invalidate();
880 }
881
882 /*!
883     Inserts a stretchable space (a QSpacerItem) at position \a
884     index, with zero minimum size and stretch factor \a stretch. If \a
885     index is negative the space is added at the end.
886
887     \sa addStretch(), insertItem(), QSpacerItem
888 */
889 void QBoxLayout::insertStretch(int index, int stretch)
890 {
891     Q_D(QBoxLayout);
892     if (index < 0)                                // append
893         index = d->list.count();
894
895     QLayoutItem *b;
896     if (horz(d->dir))
897         b = QLayoutPrivate::createSpacerItem(this, 0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
898     else
899         b = QLayoutPrivate::createSpacerItem(this, 0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
900
901     QBoxLayoutItem *it = new QBoxLayoutItem(b, stretch);
902     it->magic = true;
903     d->list.insert(index, it);
904     invalidate();
905 }
906
907 /*!
908     \since 4.4
909
910     Inserts \a spacerItem at position \a index, with zero minimum
911     size and stretch factor. If \a index is negative the
912     space is added at the end.
913
914     \sa addSpacerItem(), insertStretch(), insertSpacing()
915 */
916 void QBoxLayout::insertSpacerItem(int index, QSpacerItem *spacerItem)
917 {
918     Q_D(QBoxLayout);
919     if (index < 0)                                // append
920         index = d->list.count();
921
922     QBoxLayoutItem *it = new QBoxLayoutItem(spacerItem);
923     it->magic = true;
924     d->list.insert(index, it);
925     invalidate();
926 }
927
928 /*!
929     Inserts \a layout at position \a index, with stretch factor \a
930     stretch. If \a index is negative, the layout is added at the end.
931
932     \a layout becomes a child of the box layout.
933
934     \sa addLayout(), insertItem()
935 */
936 void QBoxLayout::insertLayout(int index, QLayout *layout, int stretch)
937 {
938     Q_D(QBoxLayout);
939     addChildLayout(layout);
940     if (index < 0)                                // append
941         index = d->list.count();
942     QBoxLayoutItem *it = new QBoxLayoutItem(layout, stretch);
943     d->list.insert(index, it);
944     invalidate();
945 }
946
947 /*!
948     Inserts \a widget at position \a index, with stretch factor \a
949     stretch and alignment \a alignment. If \a index is negative, the
950     widget is added at the end.
951
952     The stretch factor applies only in the \l{direction()}{direction}
953     of the QBoxLayout, and is relative to the other boxes and widgets
954     in this QBoxLayout. Widgets and boxes with higher stretch factors
955     grow more.
956
957     If the stretch factor is 0 and nothing else in the QBoxLayout has
958     a stretch factor greater than zero, the space is distributed
959     according to the QWidget:sizePolicy() of each widget that's
960     involved.
961
962     The alignment is specified by \a alignment. The default alignment
963     is 0, which means that the widget fills the entire cell.
964
965     \sa addWidget(), insertItem()
966 */
967 void QBoxLayout::insertWidget(int index, QWidget *widget, int stretch,
968                               Qt::Alignment alignment)
969 {
970     Q_D(QBoxLayout);
971     if (!checkWidget(this, widget))
972          return;
973     addChildWidget(widget);
974     if (index < 0)                                // append
975         index = d->list.count();
976     QWidgetItem *b = QLayoutPrivate::createWidgetItem(this, widget);
977     b->setAlignment(alignment);
978
979     QBoxLayoutItem *it;
980     QT_TRY{
981         it = new QBoxLayoutItem(b, stretch);
982     } QT_CATCH(...) {
983         delete b;
984         QT_RETHROW;
985     }
986
987     QT_TRY{
988         d->list.insert(index, it);
989     } QT_CATCH(...) {
990         delete it;
991         QT_RETHROW;
992     }
993     invalidate();
994 }
995
996 /*!
997     Adds a non-stretchable space (a QSpacerItem) with size \a size
998     to the end of this box layout. QBoxLayout provides default margin
999     and spacing. This function adds additional space.
1000
1001     \sa insertSpacing(), addItem(), QSpacerItem
1002 */
1003 void QBoxLayout::addSpacing(int size)
1004 {
1005     insertSpacing(-1, size);
1006 }
1007
1008 /*!
1009     Adds a stretchable space (a QSpacerItem) with zero minimum
1010     size and stretch factor \a stretch to the end of this box layout.
1011
1012     \sa insertStretch(), addItem(), QSpacerItem
1013 */
1014 void QBoxLayout::addStretch(int stretch)
1015 {
1016     insertStretch(-1, stretch);
1017 }
1018
1019 /*!
1020     \since 4.4
1021
1022     Adds \a spacerItem to the end of this box layout.
1023
1024     \sa addSpacing(), addStretch()
1025 */
1026 void QBoxLayout::addSpacerItem(QSpacerItem *spacerItem)
1027 {
1028     insertSpacerItem(-1, spacerItem);
1029 }
1030
1031 /*!
1032     Adds \a widget to the end of this box layout, with a stretch
1033     factor of \a stretch and alignment \a alignment.
1034
1035     The stretch factor applies only in the \l{direction()}{direction}
1036     of the QBoxLayout, and is relative to the other boxes and widgets
1037     in this QBoxLayout. Widgets and boxes with higher stretch factors
1038     grow more.
1039
1040     If the stretch factor is 0 and nothing else in the QBoxLayout has
1041     a stretch factor greater than zero, the space is distributed
1042     according to the QWidget:sizePolicy() of each widget that's
1043     involved.
1044
1045     The alignment is specified by \a alignment. The default
1046     alignment is 0, which means that the widget fills the entire cell.
1047
1048     \sa insertWidget(), addItem(), addLayout(), addStretch(),
1049         addSpacing(), addStrut()
1050 */
1051 void QBoxLayout::addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
1052 {
1053     insertWidget(-1, widget, stretch, alignment);
1054 }
1055
1056 /*!
1057     Adds \a layout to the end of the box, with serial stretch factor
1058     \a stretch.
1059
1060     \sa insertLayout(), addItem(), addWidget()
1061 */
1062 void QBoxLayout::addLayout(QLayout *layout, int stretch)
1063 {
1064     insertLayout(-1, layout, stretch);
1065 }
1066
1067 /*!
1068     Limits the perpendicular dimension of the box (e.g. height if the
1069     box is \l LeftToRight) to a minimum of \a size. Other constraints
1070     may increase the limit.
1071
1072     \sa addItem()
1073 */
1074 void QBoxLayout::addStrut(int size)
1075 {
1076     Q_D(QBoxLayout);
1077     QLayoutItem *b;
1078     if (horz(d->dir))
1079         b = QLayoutPrivate::createSpacerItem(this, 0, size, QSizePolicy::Fixed, QSizePolicy::Minimum);
1080     else
1081         b = QLayoutPrivate::createSpacerItem(this, size, 0, QSizePolicy::Minimum, QSizePolicy::Fixed);
1082
1083     QBoxLayoutItem *it = new QBoxLayoutItem(b);
1084     it->magic = true;
1085     d->list.append(it);
1086     invalidate();
1087 }
1088
1089 /*!
1090     Sets the stretch factor for \a widget to \a stretch and returns
1091     true if \a widget is found in this layout (not including child
1092     layouts); otherwise returns false.
1093
1094     \sa setAlignment()
1095 */
1096 bool QBoxLayout::setStretchFactor(QWidget *widget, int stretch)
1097 {
1098     Q_D(QBoxLayout);
1099     if (!widget)
1100         return false;
1101     for (int i = 0; i < d->list.size(); ++i) {
1102         QBoxLayoutItem *box = d->list.at(i);
1103         if (box->item->widget() == widget) {
1104             box->stretch = stretch;
1105             invalidate();
1106             return true;
1107         }
1108     }
1109     return false;
1110 }
1111
1112 /*!
1113     \overload
1114
1115     Sets the stretch factor for the layout \a layout to \a stretch and
1116     returns true if \a layout is found in this layout (not including
1117     child layouts); otherwise returns false.
1118 */
1119 bool QBoxLayout::setStretchFactor(QLayout *layout, int stretch)
1120 {
1121     Q_D(QBoxLayout);
1122     for (int i = 0; i < d->list.size(); ++i) {
1123         QBoxLayoutItem *box = d->list.at(i);
1124         if (box->item->layout() == layout) {
1125             if (box->stretch != stretch) {
1126                 box->stretch = stretch;
1127                 invalidate();
1128             }
1129             return true;
1130         }
1131     }
1132     return false;
1133 }
1134
1135 /*!
1136     Sets the stretch factor at position \a index. to \a stretch.
1137
1138     \since 4.5
1139 */
1140
1141 void QBoxLayout::setStretch(int index, int stretch)
1142 {
1143     Q_D(QBoxLayout);
1144     if (index >= 0 && index < d->list.size()) {
1145         QBoxLayoutItem *box = d->list.at(index);
1146         if (box->stretch != stretch) {
1147             box->stretch = stretch;
1148             invalidate();
1149         }
1150     }
1151 }
1152
1153 /*!
1154     Returns the stretch factor at position \a index.
1155
1156     \since 4.5
1157 */
1158
1159 int QBoxLayout::stretch(int index) const
1160 {
1161     Q_D(const QBoxLayout);
1162     if (index >= 0 && index < d->list.size())
1163         return d->list.at(index)->stretch;
1164     return -1;
1165 }
1166
1167 /*!
1168     Sets the direction of this layout to \a direction.
1169 */
1170 void QBoxLayout::setDirection(Direction direction)
1171 {
1172     Q_D(QBoxLayout);
1173     if (d->dir == direction)
1174         return;
1175     if (horz(d->dir) != horz(direction)) {
1176         //swap around the spacers (the "magic" bits)
1177         //#### a bit yucky, knows too much.
1178         //#### probably best to add access functions to spacerItem
1179         //#### or even a QSpacerItem::flip()
1180         for (int i = 0; i < d->list.size(); ++i) {
1181             QBoxLayoutItem *box = d->list.at(i);
1182             if (box->magic) {
1183                 QSpacerItem *sp = box->item->spacerItem();
1184                 if (sp) {
1185                     if (sp->expandingDirections() == Qt::Orientations(0) /*No Direction*/) {
1186                         //spacing or strut
1187                         QSize s = sp->sizeHint();
1188                         sp->changeSize(s.height(), s.width(),
1189                             horz(direction) ? QSizePolicy::Fixed:QSizePolicy::Minimum,
1190                             horz(direction) ? QSizePolicy::Minimum:QSizePolicy::Fixed);
1191
1192                     } else {
1193                         //stretch
1194                         if (horz(direction))
1195                             sp->changeSize(0, 0, QSizePolicy::Expanding,
1196                                             QSizePolicy::Minimum);
1197                         else
1198                             sp->changeSize(0, 0, QSizePolicy::Minimum,
1199                                             QSizePolicy::Expanding);
1200                     }
1201                 }
1202             }
1203         }
1204     }
1205     d->dir = direction;
1206     invalidate();
1207 }
1208
1209 /*!
1210     \fn QBoxLayout::Direction QBoxLayout::direction() const
1211
1212     Returns the direction of the box. addWidget() and addSpacing()
1213     work in this direction; the stretch stretches in this direction.
1214
1215     \sa QBoxLayout::Direction, addWidget(), addSpacing()
1216 */
1217
1218 QBoxLayout::Direction QBoxLayout::direction() const
1219 {
1220     Q_D(const QBoxLayout);
1221     return d->dir;
1222 }
1223
1224 /*!
1225     \class QHBoxLayout
1226     \brief The QHBoxLayout class lines up widgets horizontally.
1227
1228     \ingroup geomanagement
1229     \inmodule QtWidgets
1230
1231     This class is used to construct horizontal box layout objects. See
1232     QBoxLayout for details.
1233
1234     The simplest use of the class is like this:
1235
1236     \snippet layouts/layouts.cpp 0
1237     \snippet layouts/layouts.cpp 1
1238     \snippet layouts/layouts.cpp 2
1239     \codeline
1240     \snippet layouts/layouts.cpp 3
1241     \snippet layouts/layouts.cpp 4
1242     \snippet layouts/layouts.cpp 5
1243
1244     First, we create the widgets we want in the layout. Then, we
1245     create the QHBoxLayout object and add the widgets into the
1246     layout. Finally, we call QWidget::setLayout() to install the
1247     QHBoxLayout object onto the widget. At that point, the widgets in
1248     the layout are reparented to have \c window as their parent.
1249
1250     \image qhboxlayout-with-5-children.png Horizontal box layout with five child widgets
1251
1252     \sa QVBoxLayout, QGridLayout, QStackedLayout, {Layout Management}, {Basic Layouts Example}
1253 */
1254
1255
1256 /*!
1257     Constructs a new top-level horizontal box with
1258     parent \a parent.
1259 */
1260 QHBoxLayout::QHBoxLayout(QWidget *parent)
1261     : QBoxLayout(LeftToRight, parent)
1262 {
1263 }
1264
1265 /*!
1266     Constructs a new horizontal box. You must add
1267     it to another layout.
1268 */
1269 QHBoxLayout::QHBoxLayout()
1270     : QBoxLayout(LeftToRight)
1271 {
1272 }
1273
1274
1275
1276
1277
1278 /*!
1279     Destroys this box layout.
1280
1281     The layout's widgets aren't destroyed.
1282 */
1283 QHBoxLayout::~QHBoxLayout()
1284 {
1285 }
1286
1287 /*!
1288     \class QVBoxLayout
1289     \brief The QVBoxLayout class lines up widgets vertically.
1290
1291     \ingroup geomanagement
1292     \inmodule QtWidgets
1293
1294     This class is used to construct vertical box layout objects. See
1295     QBoxLayout for details.
1296
1297     The simplest use of the class is like this:
1298
1299     \snippet layouts/layouts.cpp 6
1300     \snippet layouts/layouts.cpp 7
1301     \snippet layouts/layouts.cpp 8
1302     \codeline
1303     \snippet layouts/layouts.cpp 9
1304     \snippet layouts/layouts.cpp 10
1305     \snippet layouts/layouts.cpp 11
1306
1307     First, we create the widgets we want in the layout. Then, we
1308     create the QVBoxLayout object and add the widgets into the
1309     layout. Finally, we call QWidget::setLayout() to install the
1310     QVBoxLayout object onto the widget. At that point, the widgets in
1311     the layout are reparented to have \c window as their parent.
1312
1313     \image qvboxlayout-with-5-children.png Horizontal box layout with five child widgets
1314
1315     \sa QHBoxLayout, QGridLayout, QStackedLayout, {Layout Management}, {Basic Layouts Example}
1316 */
1317
1318 /*!
1319     Constructs a new top-level vertical box with
1320     parent \a parent.
1321 */
1322 QVBoxLayout::QVBoxLayout(QWidget *parent)
1323     : QBoxLayout(TopToBottom, parent)
1324 {
1325 }
1326
1327 /*!
1328     Constructs a new vertical box. You must add
1329     it to another layout.
1330
1331 */
1332 QVBoxLayout::QVBoxLayout()
1333     : QBoxLayout(TopToBottom)
1334 {
1335 }
1336
1337
1338 /*!
1339     Destroys this box layout.
1340
1341     The layout's widgets aren't destroyed.
1342 */
1343 QVBoxLayout::~QVBoxLayout()
1344 {
1345 }
1346
1347 QT_END_NAMESPACE