1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtGui module of the Qt Toolkit.
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.
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.
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.
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.
40
****************************************************************************/
42
#include "qapplication.h"
44
#include "qformlayout.h"
46
#include "qlayout_p.h"
47
#include "qlayoutengine_p.h"
55
// Fixed column matrix, stores items as [i11, i12, i21, i22...],
56
// with FORTRAN-style index operator(r, c).
57
template <class T, int NumColumns>
58
class FixedColumnMatrix {
60
typedef QVector<T> Storage;
62
FixedColumnMatrix() { }
64
void clear() { m_storage.clear(); }
66
const T &operator()(int r, int c) const { return m_storage[r * NumColumns + c]; }
67
T &operator()(int r, int c) { return m_storage[r * NumColumns + c]; }
69
int rowCount() const { return m_storage.size() / NumColumns; }
70
void addRow(const T &value);
71
void insertRow(int r, const T &value);
72
void removeRow(int r);
74
bool find(const T &value, int *rowPtr, int *colPtr) const ;
75
int count(const T &value) const { return m_storage.count(value); }
77
// Hmmpf.. Some things are faster that way.
78
const Storage &storage() const { return m_storage; }
80
static void storageIndexToPosition(int idx, int *rowPtr, int *colPtr);
86
template <class T, int NumColumns>
87
void FixedColumnMatrix<T, NumColumns>::addRow(const T &value)
89
for (int i = 0; i < NumColumns; ++i)
90
m_storage.append(value);
93
template <class T, int NumColumns>
94
void FixedColumnMatrix<T, NumColumns>::insertRow(int r, const T &value)
96
typename Storage::iterator it = m_storage.begin();
98
m_storage.insert(it, NumColumns, value);
101
template <class T, int NumColumns>
102
void FixedColumnMatrix<T, NumColumns>::removeRow(int r)
104
m_storage.remove(r * NumColumns, NumColumns);
107
template <class T, int NumColumns>
108
bool FixedColumnMatrix<T, NumColumns>::find(const T &value, int *rowPtr, int *colPtr) const
110
const int idx = m_storage.indexOf(value);
113
storageIndexToPosition(idx, rowPtr, colPtr);
117
template <class T, int NumColumns>
118
void FixedColumnMatrix<T, NumColumns>::storageIndexToPosition(int idx, int *rowPtr, int *colPtr)
120
*rowPtr = idx / NumColumns;
121
*colPtr = idx % NumColumns;
125
// special values for unset fields; must not clash with values of FieldGrowthPolicy or
127
const uint DefaultFieldGrowthPolicy = 255;
128
const uint DefaultRowWrapPolicy = 255;
130
enum { ColumnCount = 2 };
132
// -- our data structure for our items
133
// This owns the QLayoutItem
134
struct QFormLayoutItem
136
QFormLayoutItem(QLayoutItem* i) : item(i), fullRow(false), isHfw(false) { }
137
~QFormLayoutItem() { delete item; }
140
QWidget *widget() const { return item->widget(); }
141
QLayout *layout() const { return item->layout(); }
143
bool hasHeightForWidth() const { return item->hasHeightForWidth(); }
144
int heightForWidth(int width) const { return item->heightForWidth(width); }
145
int minimumHeightForWidth(int width) const { return item->minimumHeightForWidth(width); }
146
Qt::Orientations expandingDirections() const { return item->expandingDirections(); }
147
QSizePolicy::ControlTypes controlTypes() const { return item->controlTypes(); }
148
int vStretch() const { return widget() ? widget()->sizePolicy().verticalStretch() : 0; }
150
void setGeometry(const QRect& r) { item->setGeometry(r); }
151
QRect geometry() const { return item->geometry(); }
153
// For use with FixedColumnMatrix
154
bool operator==(const QFormLayoutItem& other) { return item == other.item; }
159
// set by updateSizes
165
// also set by updateSizes
166
int sbsHSpace; // only used for side by side, for the field item only (not label)
167
int vSpace; // This is the spacing to the item in the row above
169
// set by setupVerticalLayoutData
173
// set by setupHorizontalLayoutData
178
class QFormLayoutPrivate : public QLayoutPrivate
180
Q_DECLARE_PUBLIC(QFormLayout)
183
typedef FixedColumnMatrix<QFormLayoutItem *, ColumnCount> ItemMatrix;
185
QFormLayoutPrivate();
186
~QFormLayoutPrivate() { }
188
int insertRow(int row);
189
void insertRows(int row, int count);
190
void setItem(int row, QFormLayout::ItemRole role, QLayoutItem *item);
191
void setLayout(int row, QFormLayout::ItemRole role, QLayout *layout);
192
void setWidget(int row, QFormLayout::ItemRole role, QWidget *widget);
194
void arrangeWidgets(const QVector<QLayoutStruct>& layouts, QRect &rect);
198
void setupVerticalLayoutData(int width);
199
void setupHorizontalLayoutData(int width);
201
QStyle* getStyle() const;
203
inline bool haveHfwCached(int width) const
205
return (hfw_width == width) || (width == sh_width && hfw_sh_height >= 0);
208
void recalcHFW(int w);
209
void setupHfwLayoutData();
211
uint fieldGrowthPolicy : 8;
212
uint rowWrapPolicy : 8;
214
uint dirty : 2; // have we laid out yet?
215
uint sizesDirty : 2; // have we (not) gathered layout item sizes?
216
uint expandVertical : 1; // Do we expand vertically?
217
uint expandHorizontal : 1; // Do we expand horizonally?
218
Qt::Alignment labelAlignment;
219
Qt::Alignment formAlignment;
222
QList<QFormLayoutItem *> m_things;
224
int layoutWidth; // the last width that we called setupVerticalLayoutData on (for vLayouts)
226
int hfw_width; // the last width we calculated HFW for
227
int hfw_height; // what that height was
228
int hfw_minheight; // what that minheight was
230
int hfw_sh_height; // the hfw for sh_width
231
int hfw_sh_minheight; // the minhfw for sh_width
233
int min_width; // the width that gets turned into minSize (from updateSizes)
234
int sh_width; // the width that gets turned into prefSize (from updateSizes)
235
int thresh_width; // the width that we start splitting label/field pairs at (from updateSizes)
239
void calcSizeHints();
241
QVector<QLayoutStruct> vLayouts; // set by setupVerticalLayoutData;
242
int vLayoutCount; // Number of rows we calculated in setupVerticalLayoutData
243
int maxLabelWidth; // the label width we calculated in setupVerticalLayoutData
245
QVector<QLayoutStruct> hfwLayouts;
251
QFormLayoutPrivate::QFormLayoutPrivate()
252
: fieldGrowthPolicy(DefaultFieldGrowthPolicy),
253
rowWrapPolicy(DefaultRowWrapPolicy), has_hfw(false), dirty(true), sizesDirty(true),
254
expandVertical(0), expandHorizontal(0), labelAlignment(0), formAlignment(0),
255
layoutWidth(-1), hfw_width(-1), hfw_sh_height(-1), min_width(-1),
256
sh_width(-1), thresh_width(QLAYOUTSIZE_MAX), hSpacing(-1), vSpacing(-1)
260
static Qt::Alignment fixedAlignment(Qt::Alignment alignment, Qt::LayoutDirection layoutDirection)
262
if (layoutDirection == Qt::RightToLeft && alignment & Qt::AlignAbsolute) {
263
// swap left and right, and eliminate absolute flag
264
return Qt::Alignment((alignment & ~(Qt::AlignLeft | Qt::AlignRight | Qt::AlignAbsolute))
265
| ((alignment & Qt::AlignRight) ? Qt::AlignLeft : 0)
266
| ((alignment & Qt::AlignLeft) ? Qt::AlignRight : 0));
268
return alignment & ~Qt::AlignAbsolute;
272
static int storageIndexFromLayoutItem(const QFormLayoutPrivate::ItemMatrix &m,
273
QFormLayoutItem *item)
276
return m.storage().indexOf(item);
282
static void updateFormLayoutItem(QFormLayoutItem *item, int userVSpacing,
283
QFormLayout::FieldGrowthPolicy fieldGrowthPolicy,
286
item->minSize = item->item->minimumSize();
287
item->sizeHint = item->item->sizeHint();
288
item->maxSize = item->item->maximumSize();
290
if (!fullRow && (fieldGrowthPolicy == QFormLayout::FieldsStayAtSizeHint
291
|| (fieldGrowthPolicy == QFormLayout::ExpandingFieldsGrow
292
&& !(item->item->expandingDirections() & Qt::Horizontal))))
293
item->maxSize.setWidth(item->sizeHint.width());
295
item->isHfw = item->item->hasHeightForWidth();
296
item->vSpace = userVSpacing;
300
Iterate over all the controls and gather their size information
301
(min, sizeHint and max). Also work out what the spacing between
302
pairs of controls should be, and figure out the min and sizeHint
305
void QFormLayoutPrivate::updateSizes()
310
QFormLayout::RowWrapPolicy wrapPolicy = q->rowWrapPolicy();
311
bool wrapAllRows = (wrapPolicy == QFormLayout::WrapAllRows);
312
bool dontWrapRows = (wrapPolicy == QFormLayout::DontWrapRows);
313
int rr = m_matrix.rowCount();
317
// If any control can expand, so can this layout
318
// Wrapping doesn't affect expansion, though, just the minsize
319
bool expandH = false;
320
bool expandV = false;
322
QFormLayoutItem *prevLbl = 0;
323
QFormLayoutItem *prevFld = 0;
325
QWidget *parent = q->parentWidget();
326
QStyle *style = parent ? parent->style() : 0;
328
int userVSpacing = q->verticalSpacing();
329
int userHSpacing = wrapAllRows ? 0 : q->horizontalSpacing();
331
int maxMinLblWidth = 0;
332
int maxMinFldWidth = 0; // field with label
333
int maxMinIfldWidth = 0; // independent field
335
int maxShLblWidth = 0;
336
int maxShFldWidth = 0;
337
int maxShIfldWidth = 0;
339
for (int i = 0; i < rr; ++i) {
340
QFormLayoutItem *label = m_matrix(i, 0);
341
QFormLayoutItem *field = m_matrix(i, 1);
344
if (!label && !field)
348
updateFormLayoutItem(label, userVSpacing, q->fieldGrowthPolicy(), false);
351
Qt::Orientations o = label->expandingDirections();
353
if (o & Qt::Vertical)
355
if (o & Qt::Horizontal)
359
updateFormLayoutItem(field, userVSpacing, q->fieldGrowthPolicy(), !label && field->fullRow);
360
field->sbsHSpace = (!label && field->fullRow) ? 0 : userHSpacing;
364
Qt::Orientations o = field->expandingDirections();
366
if (o & Qt::Vertical)
368
if (o & Qt::Horizontal)
372
// See if we need to calculate default spacings
373
if ((userHSpacing < 0 || userVSpacing < 0) && style) {
374
QSizePolicy::ControlTypes lbltypes =
375
QSizePolicy::ControlTypes(label ? label->controlTypes() : QSizePolicy::DefaultType);
376
QSizePolicy::ControlTypes fldtypes =
377
QSizePolicy::ControlTypes(field ? field->controlTypes() : QSizePolicy::DefaultType);
380
if (userVSpacing < 0) {
382
// label spacing is to a previous item
383
QFormLayoutItem *lbltop = prevFld ? prevFld : prevLbl;
384
// field spacing is to the label (or a previous item)
385
QFormLayoutItem *fldtop = label ? label : lbltop;
386
QSizePolicy::ControlTypes lbltoptypes =
387
QSizePolicy::ControlTypes(lbltop ? lbltop->controlTypes() : QSizePolicy::DefaultType);
388
QSizePolicy::ControlTypes fldtoptypes =
389
QSizePolicy::ControlTypes(fldtop ? fldtop->controlTypes() : QSizePolicy::DefaultType);
391
label->vSpace = style->combinedLayoutSpacing(lbltoptypes, lbltypes, Qt::Vertical, 0, parent);
393
field->vSpace = style->combinedLayoutSpacing(fldtoptypes, fldtypes, Qt::Vertical, 0, parent);
395
// Side by side.. we have to also consider the spacings to empty cells, which can strangely be more than
397
QFormLayoutItem *lbltop = prevLbl ? prevLbl : prevFld;
398
QFormLayoutItem *fldtop = prevFld;
399
QSizePolicy::ControlTypes lbltoptypes =
400
QSizePolicy::ControlTypes(lbltop ? lbltop->controlTypes() : QSizePolicy::DefaultType);
401
QSizePolicy::ControlTypes fldtoptypes =
402
QSizePolicy::ControlTypes(fldtop ? fldtop->controlTypes() : QSizePolicy::DefaultType);
404
// To be compatible to QGridLayout, we have to compare solitary labels & fields with both predecessors
407
int lblspacing = style->combinedLayoutSpacing(lbltoptypes, lbltypes, Qt::Vertical, 0, parent);
408
int fldspacing = style->combinedLayoutSpacing(fldtoptypes, lbltypes, Qt::Vertical, 0, parent);
409
label->vSpace = qMax(lblspacing, fldspacing);
411
label->vSpace = style->combinedLayoutSpacing(lbltoptypes, lbltypes, Qt::Vertical, 0, parent);
415
// check spacing against both the previous label and field
417
int lblspacing = style->combinedLayoutSpacing(lbltoptypes, fldtypes, Qt::Vertical, 0, parent);
418
int fldspacing = style->combinedLayoutSpacing(fldtoptypes, fldtypes, Qt::Vertical, 0, parent);
419
field->vSpace = qMax(lblspacing, fldspacing);
421
field->vSpace = style->combinedLayoutSpacing(fldtoptypes, fldtypes, Qt::Vertical, 0, parent);
427
// hard-coded the left and right control types so that all the rows have the same
428
// inter-column spacing (otherwise the right column isn't always left aligned)
429
if (userHSpacing < 0 && !wrapAllRows && (label || !field->fullRow) && field)
430
field->sbsHSpace = style->combinedLayoutSpacing(QSizePolicy::Label, QSizePolicy::LineEdit, Qt::Horizontal, 0, parent);
433
// Now update our min/sizehint widths
434
// We choose to put the spacing in the field side in sbs, so
435
// the right edge of the labels will align, but fields may
436
// be a little ragged.. since different controls may have
437
// different appearances, a slight raggedness in the left
438
// edges of fields can be tolerated.
439
// (Note - field->sbsHSpace is 0 for WrapAllRows mode)
441
maxMinLblWidth = qMax(maxMinLblWidth, label->minSize.width());
442
maxShLblWidth = qMax(maxShLblWidth, label->sizeHint.width());
444
maxMinFldWidth = qMax(maxMinFldWidth, field->minSize.width() + field->sbsHSpace);
445
maxShFldWidth = qMax(maxShFldWidth, field->sizeHint.width() + field->sbsHSpace);
448
maxMinIfldWidth = qMax(maxMinIfldWidth, field->minSize.width());
449
maxShIfldWidth = qMax(maxShIfldWidth, field->sizeHint.width());
456
// Now, finally update the min/sizeHint widths
458
sh_width = qMax(maxShLblWidth, qMax(maxShIfldWidth, maxShFldWidth));
459
min_width = qMax(maxMinLblWidth, qMax(maxMinIfldWidth, maxMinFldWidth));
460
// in two line, we don't care as much about the threshold width
462
} else if (dontWrapRows) {
463
// This is just the max widths glommed together
464
sh_width = qMax(maxShLblWidth + maxShFldWidth, maxShIfldWidth);
465
min_width = qMax(maxMinLblWidth + maxMinFldWidth, maxMinIfldWidth);
466
thresh_width = QWIDGETSIZE_MAX;
468
// This is just the max widths glommed together
469
sh_width = qMax(maxShLblWidth + maxShFldWidth, maxShIfldWidth);
470
// min width needs to be the min when everything is wrapped,
471
// otherwise we'll never get set with a width that causes wrapping
472
min_width = qMax(maxMinLblWidth, qMax(maxMinIfldWidth, maxMinFldWidth));
473
// We split a pair at label sh + field min (### for now..)
474
thresh_width = maxShLblWidth + maxMinFldWidth;
477
// Update the expansions
478
expandVertical = expandV;
479
expandHorizontal = expandH;
484
void QFormLayoutPrivate::recalcHFW(int w)
486
setupHfwLayoutData();
491
for (int r = 0; r < vLayoutCount; ++r) {
492
int spacing = hfwLayouts.at(r).spacing;
493
h += hfwLayouts.at(r).sizeHint + spacing;
494
mh += hfwLayouts.at(r).minimumSize + spacing;
497
if (sh_width > 0 && sh_width == w) {
498
hfw_sh_height = qMin(QLAYOUTSIZE_MAX, h);
499
hfw_sh_minheight = qMin(QLAYOUTSIZE_MAX, mh);
502
hfw_height = qMin(QLAYOUTSIZE_MAX, h);
503
hfw_minheight = qMin(QLAYOUTSIZE_MAX, mh);
507
void QFormLayoutPrivate::setupHfwLayoutData()
509
// setupVerticalLayoutData must be called before this
510
// setupHorizontalLayoutData must also be called before this
511
// copies non hfw data into hfw
512
// then updates size and min
515
// Note: QGridLayout doesn't call minimumHeightForWidth,
516
// but instead uses heightForWidth for both min and sizeHint.
517
// For the common case where minimumHeightForWidth just calls
518
// heightForWidth, we do the calculation twice, which can be
519
// very expensive for word wrapped QLabels/QTextEdits, for example.
520
// So we just use heightForWidth as well.
522
int rr = m_matrix.rowCount();
525
hfwLayouts.resize(vLayoutCount);
526
for (i = 0; i < vLayoutCount; ++i)
527
hfwLayouts[i] = vLayouts.at(i);
529
for (i = 0; i < rr; ++i) {
530
QFormLayoutItem *label = m_matrix(i, 0);
531
QFormLayoutItem *field = m_matrix(i, 1);
535
// We don't check sideBySide here, since a label is only
536
// ever side by side with its field
537
int hfw = label->heightForWidth(label->layoutWidth);
538
hfwLayouts[label->vLayoutIndex].minimumSize = hfw;
539
hfwLayouts[label->vLayoutIndex].sizeHint = hfw;
541
// Reset these here, so the field can do a qMax below (the previous value may have
542
// been the fields non-hfw values, which are often larger than hfw)
543
hfwLayouts[label->vLayoutIndex].sizeHint = label->sizeHint.height();
544
hfwLayouts[label->vLayoutIndex].minimumSize = label->minSize.height();
549
int hfw = field->isHfw ? field->heightForWidth(field->layoutWidth) : 0;
550
int h = field->isHfw ? hfw : field->sizeHint.height();
551
int mh = field->isHfw ? hfw : field->minSize.height();
553
if (field->sideBySide) {
554
int oh = hfwLayouts.at(field->vLayoutIndex).sizeHint;
555
int omh = hfwLayouts.at(field->vLayoutIndex).minimumSize;
557
hfwLayouts[field->vLayoutIndex].sizeHint = qMax(h, oh);
558
hfwLayouts[field->vLayoutIndex].minimumSize = qMax(mh, omh);
560
hfwLayouts[field->vLayoutIndex].sizeHint = h;
561
hfwLayouts[field->vLayoutIndex].minimumSize = mh;
568
Given up to four items involved in a vertical spacing calculation
569
(two rows * two columns), return the max vertical spacing for the
570
row containing item1 (which may also include item2)
571
We assume parent and item1 are not null.
573
If a particular row is split, then the spacings for that row and
574
the following row are affected, and this function should be
575
called with recalculate = true for both rows (note: only rows with both
576
a label and a field can be split).
580
1) the split label's row vspace needs to be changed to qMax(label/prevLabel, label/prevField)
581
[call with item1 = label, item2 = null, prevItem1 & prevItem2 as before]
582
2) the split field's row vspace needs to be changed to the label/field spacing
583
[call with item1 = field, item2 = null, prevItem1 = label, prevItem2 = null]
585
[if the next row has one item, 'item']
586
3a) the following row's vspace needs to be changed to item/field spacing (would
587
previously been the qMax(item/label, item/field) spacings)
588
[call with item1 = item, item2 = null, prevItem1 = field, prevItem2 = null]
590
[if the next row has two items, 'label2' and 'field2']
591
3b) the following row's vspace needs to be changed to be qMax(field/label2, field/field2) spacing
592
[call with item1 = label2, item2 = field2, prevItem1 = field, prevItem2 = null]
594
In the (common) non split case, we can just use the precalculated vspace (possibly qMaxed between
597
If recalculate is true, we expect:
601
- prevItem1 can be null
602
- if item2 is not null, prevItem2 will be null (e.g. steps 1 or 3 above)
603
- if prevItem1 is null, prevItem2 will be null
605
static inline int spacingHelper(QWidget* parent, QStyle *style, int userVSpacing, bool recalculate, QFormLayoutItem* item1, QFormLayoutItem* item2, QFormLayoutItem* prevItem1, QFormLayoutItem *prevItem2)
607
int spacing = userVSpacing;
611
spacing = item1->vSpace;
613
spacing = qMax(spacing, item2->vSpace);
615
if (style && prevItem1) {
616
QSizePolicy::ControlTypes itemtypes =
617
QSizePolicy::ControlTypes(item1 ? item1->controlTypes() : QSizePolicy::DefaultType);
620
spacing = style->combinedLayoutSpacing(itemtypes, prevItem1->controlTypes(), Qt::Vertical, 0, parent);
622
// At most of one of item2 and prevItem2 will be nonnull
624
spacing2 = style->combinedLayoutSpacing(item2->controlTypes(), prevItem1->controlTypes(), Qt::Vertical, 0, parent);
626
spacing2 = style->combinedLayoutSpacing(itemtypes, prevItem2->controlTypes(), Qt::Vertical, 0, parent);
628
spacing = qMax(spacing, spacing2);
633
QWidget *wid = prevItem1->item->widget();
635
spacing = qMax(spacing, prevItem1->geometry().top() - wid->geometry().top() );
638
QWidget *wid = prevItem2->item->widget();
640
spacing = qMax(spacing, prevItem2->geometry().top() - wid->geometry().top() );
646
static inline void initLayoutStruct(QLayoutStruct& sl, QFormLayoutItem* item)
648
sl.init(item->vStretch(), item->minSize.height());
649
sl.sizeHint = item->sizeHint.height();
650
sl.maximumSize = item->maxSize.height();
651
sl.expansive = (item->expandingDirections() & Qt::Vertical);
655
void QFormLayoutPrivate::setupVerticalLayoutData(int width)
659
// Early out if we have no changes that would cause a change in vertical layout
660
if ((width == layoutWidth || (width >= thresh_width && layoutWidth >= thresh_width)) && !dirty && !sizesDirty)
665
int rr = m_matrix.rowCount();
667
QFormLayout::RowWrapPolicy rowWrapPolicy = q->rowWrapPolicy();
668
bool wrapAllRows = (rowWrapPolicy == QFormLayout::WrapAllRows);
669
bool addTopBottomStretch = true;
672
vLayouts.resize((2 * rr) + 2); // a max, some may be unused
676
int userVSpacing = q->verticalSpacing();
678
if (userVSpacing < 0) {
679
if (QWidget *widget = q->parentWidget())
680
style = widget->style();
683
// make sure our sizes are up to date
686
// Grab the widest label width here
687
// This might be different from the value computed during
688
// sizeHint/minSize, since we don't count label/field pairs that
692
for (int i = 0; i < rr; ++i) {
693
const QFormLayoutItem *label = m_matrix(i, 0);
694
const QFormLayoutItem *field = m_matrix(i, 1);
695
if (label && (label->sizeHint.width() + (field ? field->minSize.width() : 0) <= width))
696
maxLabelWidth = qMax(maxLabelWidth, label->sizeHint.width());
699
maxLabelWidth = width;
702
QFormLayoutItem *prevItem1 = 0;
703
QFormLayoutItem *prevItem2 = 0;
704
bool prevRowSplit = false;
706
for (int i = 0; i < rr; ++i) {
707
QFormLayoutItem *label = m_matrix(i, 0);
708
QFormLayoutItem *field = m_matrix(i, 1);
710
// Totally ignore empty rows...
711
if (!label && !field)
719
min1 = label->minSize;
720
sh1 = label->sizeHint;
723
min2 = field->minSize;
724
sh2 = field->sizeHint;
727
// In separate lines, we make a vLayout for everything that isn't null
728
// in side by side, we only separate label/field if we're going to wrap it
729
bool splitSideBySide = (rowWrapPolicy == QFormLayout::WrapLongRows)
730
&& ((maxLabelWidth < sh1.width()) || (width < (maxLabelWidth + min2.width())));
732
if (wrapAllRows || splitSideBySide) {
734
initLayoutStruct(vLayouts[vidx], label);
737
vLayouts[vidx - 1].spacing = spacingHelper(q->parentWidget(), style, userVSpacing, splitSideBySide || prevRowSplit, label, 0, prevItem1, prevItem2);
739
label->vLayoutIndex = vidx;
740
label->sideBySide = false;
745
if (vLayouts[vidx].stretch > 0)
746
addTopBottomStretch = false;
752
initLayoutStruct(vLayouts[vidx], field);
755
vLayouts[vidx - 1].spacing = spacingHelper(q->parentWidget(), style, userVSpacing, splitSideBySide || prevRowSplit, field, 0, prevItem1, prevItem2);
757
field->vLayoutIndex = vidx;
758
field->sideBySide = false;
763
if (vLayouts[vidx].stretch > 0)
764
addTopBottomStretch = false;
769
prevRowSplit = splitSideBySide;
771
// we're in side by side mode, and we have enough space to do that
772
QSize max1(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
773
QSize max2(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
777
bool expanding = false;
780
max1 = label->maxSize;
781
if (label->expandingDirections() & Qt::Vertical)
784
label->sideBySide = (field != 0);
785
label->vLayoutIndex = vidx;
786
stretch1 = label->vStretch();
790
max2 = field->maxSize;
791
if (field->expandingDirections() & Qt::Vertical)
794
field->sideBySide = (label || !field->fullRow);
795
field->vLayoutIndex = vidx;
796
stretch2 = field->vStretch();
799
vLayouts[vidx].init(qMax(stretch1, stretch2), qMax(min1.height(), min2.height()));
800
vLayouts[vidx].sizeHint = qMax(sh1.height(), sh2.height());
801
vLayouts[vidx].maximumSize = qMin(max1.height(), max2.height());
802
vLayouts[vidx].expansive = expanding || (vLayouts[vidx].stretch > 0);
803
vLayouts[vidx].empty = false;
805
if (vLayouts[vidx].stretch > 0)
806
addTopBottomStretch = false;
809
vLayouts[vidx - 1].spacing = spacingHelper(q->parentWidget(), style, userVSpacing, prevRowSplit, label, field, prevItem1, prevItem2);
819
prevRowSplit = false;
824
if (addTopBottomStretch) {
825
Qt::Alignment formAlignment = q->formAlignment();
827
if (!(formAlignment & Qt::AlignBottom)) {
828
// AlignTop (default if unspecified) or AlignVCenter: We add a stretch at the bottom
829
vLayouts[vidx].init(1, 0);
830
vLayouts[vidx].expansive = true;
834
if (formAlignment & (Qt::AlignVCenter | Qt::AlignBottom)) {
835
// AlignVCenter or AlignBottom: We add a stretch at the top
836
vLayouts[0].init(1, 0);
837
vLayouts[0].expansive = true;
839
vLayouts[0].init(0, 0);
842
vLayouts[0].init(0, 0);
849
void QFormLayoutPrivate::setupHorizontalLayoutData(int width)
853
// requires setupVerticalLayoutData to be called first
855
int fieldMaxWidth = 0;
857
int rr = m_matrix.rowCount();
858
bool wrapAllRows = (q->rowWrapPolicy() == QFormLayout::WrapAllRows);
860
for (int i = 0; i < rr; ++i) {
861
QFormLayoutItem *label = m_matrix(i, 0);
862
QFormLayoutItem *field = m_matrix(i, 1);
864
// Totally ignore empty rows...
865
if (!label && !field)
869
// if there is a field, and we're side by side, we use maxLabelWidth
870
// otherwise we just use the sizehint
871
label->layoutWidth = (field && label->sideBySide) ? maxLabelWidth : label->sizeHint.width();
872
label->layoutPos = 0;
876
// This is the default amount allotted to fields in sbs
877
int fldwidth = width - maxLabelWidth - field->sbsHSpace;
879
// If we've split a row, we still decide to align
880
// the field with all the other field if it will fit
881
// Fields in sbs mode get the remnants of the maxLabelWidth
882
if (!field->sideBySide) {
883
if (wrapAllRows || (!label && field->fullRow) || field->sizeHint.width() > fldwidth) {
884
field->layoutWidth = width;
885
field->layoutPos = 0;
887
field->layoutWidth = fldwidth;
888
field->layoutPos = width - fldwidth;
891
// We're sbs, so we should have a label
892
field->layoutWidth = fldwidth;
893
field->layoutPos = width - fldwidth;
896
fieldMaxWidth = qMax(fieldMaxWidth, field->maxSize.width());
900
formMaxWidth = maxLabelWidth + fieldMaxWidth;
903
void QFormLayoutPrivate::calcSizeHints()
907
int leftMargin, topMargin, rightMargin, bottomMargin;
908
q->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
911
setupVerticalLayoutData(QLAYOUTSIZE_MAX);
912
// Don't need to call setupHorizontal here
914
int h = topMargin + bottomMargin;
915
int mh = topMargin + bottomMargin;
917
// The following are set in updateSizes
918
int w = sh_width + leftMargin + rightMargin;
919
int mw = min_width + leftMargin + rightMargin;
921
for (int i = 0; i < vLayoutCount; ++i) {
922
int spacing = vLayouts.at(i).spacing;
923
h += vLayouts.at(i).sizeHint + spacing;
924
mh += vLayouts.at(i).minimumSize + spacing;
927
minSize.rwidth() = qMin(mw, QLAYOUTSIZE_MAX);
928
minSize.rheight() = qMin(mh, QLAYOUTSIZE_MAX);
929
prefSize.rwidth() = qMin(w, QLAYOUTSIZE_MAX);
930
prefSize.rheight() = qMin(h, QLAYOUTSIZE_MAX);
933
int QFormLayoutPrivate::insertRow(int row)
935
int rowCnt = m_matrix.rowCount();
936
if (uint(row) > uint(rowCnt))
943
void QFormLayoutPrivate::insertRows(int row, int count)
946
m_matrix.insertRow(row, 0);
951
void QFormLayoutPrivate::setItem(int row, QFormLayout::ItemRole role, QLayoutItem *item)
953
const bool fullRow = role == QFormLayout::SpanningRole;
954
const int column = role == QFormLayout::SpanningRole ? 1 : static_cast<int>(role);
955
if (uint(row) >= uint(m_matrix.rowCount()) || uint(column) > 1U) {
956
qWarning("QFormLayoutPrivate::setItem: Invalid cell (%d, %d)", row, column);
963
if (m_matrix(row, column)) {
964
qWarning("QFormLayoutPrivate::setItem: Cell (%d, %d) already occupied", row, column);
968
QFormLayoutItem *i = new QFormLayoutItem(item);
969
i->fullRow = fullRow;
970
m_matrix(row, column) = i;
975
void QFormLayoutPrivate::setLayout(int row, QFormLayout::ItemRole role, QLayout *layout)
979
q->addChildLayout(layout);
980
setItem(row, role, layout);
984
void QFormLayoutPrivate::setWidget(int row, QFormLayout::ItemRole role, QWidget *widget)
988
q->addChildWidget(widget);
989
setItem(row, role, QLayoutPrivate::createWidgetItem(q, widget));
993
QStyle* QFormLayoutPrivate::getStyle() const
995
Q_Q(const QFormLayout);
998
if (QWidget *parentWidget = q->parentWidget())
999
return parentWidget->style();
1001
return QApplication::style();
1007
\brief The QFormLayout class manages forms of input widgets and their associated labels.
1009
\ingroup geomanagement
1012
QFormLayout is a convenience layout class that lays out its
1013
children in a two-column form. The left column consists of labels
1014
and the right column consists of "field" widgets (line editors,
1017
Traditionally, such two-column form layouts were achieved using
1018
QGridLayout. QFormLayout is a higher-level alternative that
1019
provides the following advantages:
1022
\li \b{Adherence to the different platform's look and feel guidelines.}
1025
\l{https://developer.apple.com/library/mac/#documentation/UserExperience/Conceptual/AppleHIGuidelines/Intro/Intro.html}{Mac OS X Aqua} and KDE guidelines specify that the
1026
labels should be right-aligned, whereas Windows and GNOME
1027
applications normally use left-alignment.
1029
\li \b{Support for wrapping long rows.}
1031
For devices with small displays, QFormLayout can be set to
1032
\l{WrapLongRows}{wrap long rows}, or even to
1033
\l{WrapAllRows}{wrap all rows}.
1035
\li \b{Convenient API for creating label--field pairs.}
1037
The addRow() overload that takes a QString and a QWidget *
1038
creates a QLabel behind the scenes and automatically set up
1039
its buddy. We can then write code like this:
1041
\snippet code/src_gui_kernel_qformlayout.cpp 0
1043
Compare this with the following code, written using QGridLayout:
1045
\snippet code/src_gui_kernel_qformlayout.cpp 1
1048
The table below shows the default appearance in different styles.
1052
\li QCommonStyle derived styles (except QPlastiqueStyle)
1055
\li Qt Extended styles
1057
\li \inlineimage qformlayout-win.png
1058
\li \inlineimage qformlayout-mac.png
1059
\li \inlineimage qformlayout-kde.png
1060
\li \inlineimage qformlayout-qpe.png
1062
\li Traditional style used for Windows, GNOME, and earlier
1063
versions of KDE. Labels are left aligned, and expanding
1064
fields grow to fill the available space. (This normally
1065
corresponds to what we would get using a two-column
1067
\li Style based on the
1068
\l{https://developer.apple.com/library/mac/#documentation/UserExperience/Conceptual/AppleHIGuidelines/Intro/Intro.html}{Mac OS X Aqua} guidelines. Labels are right-aligned,
1069
the fields don't grow beyond their size hint, and the
1070
form is horizontally centered.
1071
\li Recommended style for
1072
\l{KDE applications}. Similar to MacStyle, except that the form
1073
is left-aligned and all fields grow to fill the available
1075
\li Default style for Qt Extended styles. Labels are right-aligned,
1076
expanding fields grow to fill the available space, and row
1077
wrapping is enabled for long lines.
1080
The form styles can be also be overridden individually by calling
1081
setLabelAlignment(), setFormAlignment(), setFieldGrowthPolicy(),
1082
and setRowWrapPolicy(). For example, to simulate the form layout
1083
appearance of QMacStyle on all platforms, but with left-aligned
1084
labels, you could write:
1086
\snippet code/src_gui_kernel_qformlayout.cpp 2
1088
\sa QGridLayout, QBoxLayout, QStackedLayout
1093
\enum QFormLayout::FieldGrowthPolicy
1095
This enum specifies the different policies that can be used to
1096
control the way in which the form's fields grow.
1098
\value FieldsStayAtSizeHint
1099
The fields never grow beyond their
1100
\l{QWidgetItem::sizeHint()}{effective size hint}. This is
1101
the default for QMacStyle.
1103
\value ExpandingFieldsGrow
1104
Fields with an horizontal \l{QSizePolicy}{size policy} of
1105
\l{QSizePolicy::}{Expanding} or
1106
\l{QSizePolicy::}{MinimumExpanding} will grow to fill the
1107
available space. The other fields will not grow beyond
1108
their effective size hint. This is the default policy for
1111
\value AllNonFixedFieldsGrow
1112
All fields with a size policy that allows them to grow
1113
will grow to fill the available space. This is the default
1114
policy for most styles.
1116
\sa fieldGrowthPolicy
1120
\enum QFormLayout::RowWrapPolicy
1122
This enum specifies the different policies that can be used to
1123
control the way in which the form's rows wrap.
1126
Fields are always laid out next to their label. This is
1127
the default policy for all styles except Qt Extended styles.
1130
Labels are given enough horizontal space to fit the widest label,
1131
and the rest of the space is given to the fields. If the minimum
1132
size of a field pair is wider than the available space, the field
1133
is wrapped to the next line. This is the default policy for
1137
Fields are always laid out below their label.
1143
\enum QFormLayout::ItemRole
1145
This enum specifies the types of widgets (or other layout items)
1146
that may appear in a row.
1148
\value LabelRole A label widget.
1149
\value FieldRole A field widget.
1150
\value SpanningRole A widget that spans label and field columns.
1152
\sa itemAt(), getItemPosition()
1156
Constructs a new form layout with the given \a parent widget.
1158
\sa QWidget::setLayout()
1160
QFormLayout::QFormLayout(QWidget *parent)
1161
: QLayout(*new QFormLayoutPrivate, 0, parent)
1166
Destroys the form layout.
1168
QFormLayout::~QFormLayout()
1173
The clearing and destruction order here is important. We start by clearing
1174
m_things so that QLayout and the rest of the world know that we don't babysit
1175
the layout items anymore and don't care if they are destroyed.
1177
d->m_things.clear();
1178
qDeleteAll(d->m_matrix.storage());
1179
d->m_matrix.clear();
1183
Adds a new row to the bottom of this form layout, with the given
1184
\a label and \a field.
1188
void QFormLayout::addRow(QWidget *label, QWidget *field)
1190
insertRow(-1, label, field);
1196
void QFormLayout::addRow(QWidget *label, QLayout *field)
1198
insertRow(-1, label, field);
1204
This overload automatically creates a QLabel behind the scenes
1205
with \a labelText as its text. The \a field is set as the new
1206
QLabel's \l{QLabel::setBuddy()}{buddy}.
1208
void QFormLayout::addRow(const QString &labelText, QWidget *field)
1210
insertRow(-1, labelText, field);
1216
This overload automatically creates a QLabel behind the scenes
1217
with \a labelText as its text.
1219
void QFormLayout::addRow(const QString &labelText, QLayout *field)
1221
insertRow(-1, labelText, field);
1227
Adds the specified \a widget at the end of this form layout. The
1228
\a widget spans both columns.
1230
void QFormLayout::addRow(QWidget *widget)
1232
insertRow(-1, widget);
1238
Adds the specified \a layout at the end of this form layout. The
1239
\a layout spans both columns.
1241
void QFormLayout::addRow(QLayout *layout)
1243
insertRow(-1, layout);
1247
Inserts a new row at position \a row in this form layout, with
1248
the given \a label and \a field. If \a row is out of bounds, the
1249
new row is added at the end.
1253
void QFormLayout::insertRow(int row, QWidget *label, QWidget *field)
1257
row = d->insertRow(row);
1259
d->setWidget(row, LabelRole, label);
1261
d->setWidget(row, FieldRole, field);
1268
void QFormLayout::insertRow(int row, QWidget *label, QLayout *field)
1272
row = d->insertRow(row);
1274
d->setWidget(row, LabelRole, label);
1276
d->setLayout(row, FieldRole, field);
1283
This overload automatically creates a QLabel behind the scenes
1284
with \a labelText as its text. The \a field is set as the new
1285
QLabel's \l{QLabel::setBuddy()}{buddy}.
1287
void QFormLayout::insertRow(int row, const QString &labelText, QWidget *field)
1290
if (!labelText.isEmpty()) {
1291
label = new QLabel(labelText);
1292
#ifndef QT_NO_SHORTCUT
1293
label->setBuddy(field);
1296
insertRow(row, label, field);
1302
This overload automatically creates a QLabel behind the scenes
1303
with \a labelText as its text.
1305
void QFormLayout::insertRow(int row, const QString &labelText, QLayout *field)
1307
insertRow(row, labelText.isEmpty() ? 0 : new QLabel(labelText), field);
1313
Inserts the specified \a widget at position \a row in this form
1314
layout. The \a widget spans both columns. If \a row is out of
1315
bounds, the widget is added at the end.
1317
void QFormLayout::insertRow(int row, QWidget *widget)
1322
qWarning("QFormLayout: Cannot add null field to %s", qPrintable(objectName()));
1326
row = d->insertRow(row);
1327
d->setWidget(row, SpanningRole, widget);
1334
Inserts the specified \a layout at position \a row in this form
1335
layout. The \a layout spans both columns. If \a row is out of
1336
bounds, the widget is added at the end.
1338
void QFormLayout::insertRow(int row, QLayout *layout)
1343
qWarning("QFormLayout: Cannot add null field to %s", qPrintable(objectName()));
1347
row = d->insertRow(row);
1348
d->setLayout(row, SpanningRole, layout);
1355
void QFormLayout::addItem(QLayoutItem *item)
1359
int row = d->insertRow(d->m_matrix.rowCount());
1360
d->setItem(row, FieldRole, item);
1367
int QFormLayout::count() const
1369
Q_D(const QFormLayout);
1370
return d->m_things.count();
1376
QLayoutItem *QFormLayout::itemAt(int index) const
1378
Q_D(const QFormLayout);
1379
if (QFormLayoutItem *formItem = d->m_things.value(index))
1380
return formItem->item;
1387
QLayoutItem *QFormLayout::takeAt(int index)
1391
const int storageIndex = storageIndexFromLayoutItem(d->m_matrix, d->m_things.value(index));
1392
if (storageIndex == -1) {
1393
qWarning("QFormLayout::takeAt: Invalid index %d", index);
1398
QFormLayoutPrivate::ItemMatrix::storageIndexToPosition(storageIndex, &row, &col);
1399
Q_ASSERT(d->m_matrix(row, col));
1401
QFormLayoutItem *item = d->m_matrix(row, col);
1403
d->m_things.removeAt(index);
1404
d->m_matrix(row, col) = 0;
1408
// grab ownership back from the QFormLayoutItem
1409
QLayoutItem *i = item->item;
1413
if (QLayout *l = i->layout()) {
1414
// sanity check in case the user passed something weird to QObject::setParent()
1415
if (l->parent() == this)
1425
Qt::Orientations QFormLayout::expandingDirections() const
1427
Q_D(const QFormLayout);
1428
QFormLayoutPrivate *e = const_cast<QFormLayoutPrivate *>(d);
1431
Qt::Orientations o = 0;
1432
if (e->expandHorizontal)
1434
if (e->expandVertical)
1442
bool QFormLayout::hasHeightForWidth() const
1444
Q_D(const QFormLayout);
1445
QFormLayoutPrivate *e = const_cast<QFormLayoutPrivate *>(d);
1447
return (d->has_hfw || rowWrapPolicy() == WrapLongRows);
1453
int QFormLayout::heightForWidth(int width) const
1455
Q_D(const QFormLayout);
1456
if (!hasHeightForWidth())
1459
int leftMargin, topMargin, rightMargin, bottomMargin;
1460
getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
1462
int targetWidth = width - leftMargin - rightMargin;
1464
if (!d->haveHfwCached(targetWidth)) {
1465
QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
1466
dat->setupVerticalLayoutData(targetWidth);
1467
dat->setupHorizontalLayoutData(targetWidth);
1468
dat->recalcHFW(targetWidth);
1470
if (targetWidth == d->sh_width)
1471
return d->hfw_sh_height + topMargin + bottomMargin;
1473
return d->hfw_height + topMargin + bottomMargin;
1479
void QFormLayout::setGeometry(const QRect &rect)
1482
if (d->dirty || rect != geometry()) {
1484
int leftMargin, topMargin, rightMargin, bottomMargin;
1485
getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
1486
cr.adjust(+leftMargin, +topMargin, -rightMargin, -bottomMargin);
1488
bool hfw = hasHeightForWidth();
1489
d->setupVerticalLayoutData(cr.width());
1490
d->setupHorizontalLayoutData(cr.width());
1491
if (hfw && (!d->haveHfwCached(cr.width()) || d->hfwLayouts.size() != d->vLayoutCount))
1492
d->recalcHFW(cr.width());
1494
qGeomCalc(d->hfwLayouts, 0, d->vLayoutCount, cr.y(), cr.height());
1495
d->arrangeWidgets(d->hfwLayouts, cr);
1497
qGeomCalc(d->vLayouts, 0, d->vLayoutCount, cr.y(), cr.height());
1498
d->arrangeWidgets(d->vLayouts, cr);
1500
QLayout::setGeometry(rect);
1507
QSize QFormLayout::sizeHint() const
1509
Q_D(const QFormLayout);
1510
if (!d->prefSize.isValid()) {
1511
QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
1512
dat->calcSizeHints();
1520
QSize QFormLayout::minimumSize() const
1522
// ### fix minimumSize if hfw
1523
Q_D(const QFormLayout);
1524
if (!d->minSize.isValid()) {
1525
QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
1526
dat->calcSizeHints();
1534
void QFormLayout::invalidate()
1538
d->sizesDirty = true;
1539
d->minSize = QSize();
1540
d->prefSize = QSize();
1541
d->formMaxWidth = -1;
1544
d->layoutWidth = -1;
1545
d->hfw_sh_height = -1;
1546
QLayout::invalidate();
1550
Returns the number of rows in the form.
1552
\sa QLayout::count()
1554
int QFormLayout::rowCount() const
1556
Q_D(const QFormLayout);
1557
return d->m_matrix.rowCount();
1561
Returns the layout item in the given \a row with the specified \a
1562
role (column). Returns 0 if there is no such item.
1564
\sa QLayout::itemAt(), setItem()
1566
QLayoutItem *QFormLayout::itemAt(int row, ItemRole role) const
1568
Q_D(const QFormLayout);
1569
if (uint(row) >= uint(d->m_matrix.rowCount()))
1573
if (QFormLayoutItem *item = d->m_matrix(row, 1))
1579
if (QFormLayoutItem *item = d->m_matrix(row, (role == LabelRole) ? 0 : 1))
1587
Retrieves the row and role (column) of the item at the specified
1588
\a index. If \a index is out of bounds, *\a rowPtr is set to -1;
1589
otherwise the row is stored in *\a rowPtr and the role is stored
1592
\sa itemAt(), count(), getLayoutPosition(), getWidgetPosition()
1594
void QFormLayout::getItemPosition(int index, int *rowPtr, ItemRole *rolePtr) const
1596
Q_D(const QFormLayout);
1600
const int storageIndex = storageIndexFromLayoutItem(d->m_matrix, d->m_things.value(index));
1601
if (storageIndex != -1)
1602
QFormLayoutPrivate::ItemMatrix::storageIndexToPosition(storageIndex, &row, &col);
1606
if (rolePtr && col != -1) {
1607
const bool spanning = col == 1 && d->m_matrix(row, col)->fullRow;
1609
*rolePtr = SpanningRole;
1611
*rolePtr = ItemRole(col);
1617
Retrieves the row and role (column) of the specified child \a
1618
layout. If \a layout is not in the form layout, *\a rowPtr is set
1619
to -1; otherwise the row is stored in *\a rowPtr and the role is stored
1622
void QFormLayout::getLayoutPosition(QLayout *layout, int *rowPtr, ItemRole *rolePtr) const
1627
if (itemAt(index) == layout)
1631
getItemPosition(index, rowPtr, rolePtr);
1635
Retrieves the row and role (column) of the specified \a widget in
1636
the layout. If \a widget is not in the layout, *\a rowPtr is set
1637
to -1; otherwise the row is stored in *\a rowPtr and the role is stored
1640
\sa getItemPosition(), itemAt()
1642
void QFormLayout::getWidgetPosition(QWidget *widget, int *rowPtr, ItemRole *rolePtr) const
1644
getItemPosition(indexOf(widget), rowPtr, rolePtr);
1647
// ### eliminate labelForField()
1650
Returns the label associated with the given \a field.
1654
QWidget *QFormLayout::labelForField(QWidget *field) const
1656
Q_D(const QFormLayout);
1661
getWidgetPosition(field, &row, &role);
1663
if (row != -1 && role == FieldRole) {
1664
if (QFormLayoutItem *label = d->m_matrix(row, LabelRole))
1665
return label->widget();
1673
QWidget *QFormLayout::labelForField(QLayout *field) const
1675
Q_D(const QFormLayout);
1680
getLayoutPosition(field, &row, &role);
1682
if (row != -1 && role == FieldRole) {
1683
if (QFormLayoutItem *label = d->m_matrix(row, LabelRole))
1684
return label->widget();
1690
\property QFormLayout::fieldGrowthPolicy
1691
\brief the way in which the form's fields grow
1693
The default value depends on the widget or application style. For
1694
QMacStyle, the default is FieldsStayAtSizeHint; for QCommonStyle
1695
derived styles (like Plastique and Windows), the default
1696
is ExpandingFieldsGrow; for Qt Extended styles, the default is
1697
AllNonFixedFieldsGrow.
1699
If none of the fields can grow and the form is resized, extra
1700
space is distributed according to the current
1701
\l{formAlignment}{form alignment}.
1703
\sa formAlignment, rowWrapPolicy
1706
void QFormLayout::setFieldGrowthPolicy(FieldGrowthPolicy policy)
1709
if (FieldGrowthPolicy(d->fieldGrowthPolicy) != policy) {
1710
d->fieldGrowthPolicy = policy;
1715
QFormLayout::FieldGrowthPolicy QFormLayout::fieldGrowthPolicy() const
1717
Q_D(const QFormLayout);
1718
if (d->fieldGrowthPolicy == DefaultFieldGrowthPolicy) {
1719
return QFormLayout::FieldGrowthPolicy(d->getStyle()->styleHint(QStyle::SH_FormLayoutFieldGrowthPolicy));
1721
return QFormLayout::FieldGrowthPolicy(d->fieldGrowthPolicy);
1726
\property QFormLayout::rowWrapPolicy
1727
\brief the way in which the form's rows wrap
1729
The default value depends on the widget or application style. For
1730
Qt Extended styles, the default is WrapLongRows;
1731
for the other styles, the default is DontWrapRows.
1733
If you want to display each label above its associated field
1734
(instead of next to it), set this property to WrapAllRows.
1736
\sa fieldGrowthPolicy
1739
void QFormLayout::setRowWrapPolicy(RowWrapPolicy policy)
1742
if (RowWrapPolicy(d->rowWrapPolicy) != policy) {
1743
d->rowWrapPolicy = policy;
1748
QFormLayout::RowWrapPolicy QFormLayout::rowWrapPolicy() const
1750
Q_D(const QFormLayout);
1751
if (d->rowWrapPolicy == DefaultRowWrapPolicy) {
1752
return QFormLayout::RowWrapPolicy(d->getStyle()->styleHint(QStyle::SH_FormLayoutWrapPolicy));
1754
return QFormLayout::RowWrapPolicy(d->rowWrapPolicy);
1759
\property QFormLayout::labelAlignment
1760
\brief the horizontal alignment of the labels
1762
The default value depends on the widget or application style. For
1763
QCommonStyle derived styles, except for QPlastiqueStyle, the
1764
default is Qt::AlignLeft; for the other styles, the default is
1770
void QFormLayout::setLabelAlignment(Qt::Alignment alignment)
1773
if (d->labelAlignment != alignment) {
1774
d->labelAlignment = alignment;
1779
Qt::Alignment QFormLayout::labelAlignment() const
1781
Q_D(const QFormLayout);
1782
if (!d->labelAlignment) {
1783
return Qt::Alignment(d->getStyle()->styleHint(QStyle::SH_FormLayoutLabelAlignment));
1785
return d->labelAlignment;
1790
\property QFormLayout::formAlignment
1791
\brief the alignment of the form layout's contents within the layout's geometry
1793
The default value depends on the widget or application style. For
1794
QMacStyle, the default is Qt::AlignHCenter | Qt::AlignTop; for the
1795
other styles, the default is Qt::AlignLeft | Qt::AlignTop.
1797
\sa labelAlignment, rowWrapPolicy
1800
void QFormLayout::setFormAlignment(Qt::Alignment alignment)
1803
if (d->formAlignment != alignment) {
1804
d->formAlignment = alignment;
1809
Qt::Alignment QFormLayout::formAlignment() const
1811
Q_D(const QFormLayout);
1812
if (!d->formAlignment) {
1813
return Qt::Alignment(d->getStyle()->styleHint(QStyle::SH_FormLayoutFormAlignment));
1815
return d->formAlignment;
1820
\property QFormLayout::horizontalSpacing
1821
\brief the spacing between widgets that are laid out side by side
1823
By default, if no value is explicitly set, the layout's horizontal
1824
spacing is inherited from the parent layout, or from the style settings
1825
for the parent widget.
1827
\sa verticalSpacing, QStyle::pixelMetric(), {QStyle::}{PM_LayoutHorizontalSpacing}
1829
void QFormLayout::setHorizontalSpacing(int spacing)
1832
if (spacing != d->hSpacing) {
1833
d->hSpacing = spacing;
1838
int QFormLayout::horizontalSpacing() const
1840
Q_D(const QFormLayout);
1841
if (d->hSpacing >= 0) {
1844
return qSmartSpacing(this, QStyle::PM_LayoutHorizontalSpacing);
1849
\property QFormLayout::verticalSpacing
1850
\brief the spacing between widgets that are laid out vertically
1852
By default, if no value is explicitly set, the layout's vertical spacing is
1853
inherited from the parent layout, or from the style settings for the parent
1856
\sa horizontalSpacing, QStyle::pixelMetric(), {QStyle::}{PM_LayoutHorizontalSpacing}
1858
void QFormLayout::setVerticalSpacing(int spacing)
1861
if (spacing != d->vSpacing) {
1862
d->vSpacing = spacing;
1867
int QFormLayout::verticalSpacing() const
1869
Q_D(const QFormLayout);
1870
if (d->vSpacing >= 0) {
1873
return qSmartSpacing(this, QStyle::PM_LayoutVerticalSpacing);
1878
This function sets both the vertical and horizontal spacing to
1881
\sa setVerticalSpacing(), setHorizontalSpacing()
1883
void QFormLayout::setSpacing(int spacing)
1886
d->vSpacing = d->hSpacing = spacing;
1891
If the vertical spacing is equal to the horizontal spacing,
1892
this function returns that value; otherwise it returns -1.
1894
\sa setSpacing(), verticalSpacing(), horizontalSpacing()
1896
int QFormLayout::spacing() const
1898
int hSpacing = horizontalSpacing();
1899
if (hSpacing == verticalSpacing()) {
1906
void QFormLayoutPrivate::arrangeWidgets(const QVector<QLayoutStruct>& layouts, QRect &rect)
1911
const int rr = m_matrix.rowCount();
1912
QWidget *w = q->parentWidget();
1913
Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : QApplication::layoutDirection();
1915
Qt::Alignment formAlignment = fixedAlignment(q->formAlignment(), layoutDirection);
1917
int delta = rect.width() - formMaxWidth;
1918
if (formAlignment & (Qt::AlignHCenter | Qt::AlignRight) && delta > 0) {
1920
if (formAlignment & Qt::AlignHCenter)
1924
for (i = 0; i < rr; ++i) {
1925
QFormLayoutItem *label = m_matrix(i, 0);
1926
QFormLayoutItem *field = m_matrix(i, 1);
1929
int height = layouts.at(label->vLayoutIndex).size;
1930
if ((label->expandingDirections() & Qt::Vertical) == 0) {
1932
If the field on the right-hand side is tall,
1933
we want the label to be top-aligned, but not too
1934
much. So we introduce a 7 / 4 factor so that it
1935
gets some extra pixels at the top.
1937
height = qMin(height,
1938
qMin(label->sizeHint.height() * 7 / 4,
1939
label->maxSize.height()));
1942
QSize sz(qMin(label->layoutWidth, label->sizeHint.width()), height);
1943
int x = leftOffset + rect.x() + label->layoutPos;
1944
if (fixedAlignment(q->labelAlignment(), layoutDirection) & Qt::AlignRight)
1945
x += label->layoutWidth - sz.width();
1946
QPoint p(x, layouts.at(label->vLayoutIndex).pos);
1947
// ### expansion & sizepolicy stuff
1949
label->setGeometry(QStyle::visualRect(layoutDirection, rect, QRect(p, sz)));
1953
QSize sz(field->layoutWidth, layouts.at(field->vLayoutIndex).size);
1954
QPoint p(field->layoutPos + leftOffset + rect.x(), layouts.at(field->vLayoutIndex).pos);
1956
if ((field->widget() && field->widget()->sizePolicy().horizontalPolicy() & (QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag | QSizePolicy::IgnoreFlag))
1957
|| (field->layout() && sz.width() < field->maxSize.width())) {
1958
sz.rwidth() = field->layoutWidth;
1961
if (field->maxSize.isValid())
1962
sz = sz.boundedTo(field->maxSize);
1964
field->setGeometry(QStyle::visualRect(layoutDirection, rect, QRect(p, sz)));
1970
Sets the widget in the given \a row for the given \a role to \a widget, extending the
1971
layout with empty rows if necessary.
1973
If the cell is already occupied, the \a widget is not inserted and an error message is
1974
sent to the console.
1976
\b{Note:} For most applications, addRow() or insertRow() should be used instead of setWidget().
1980
void QFormLayout::setWidget(int row, ItemRole role, QWidget *widget)
1983
int rowCnt = rowCount();
1985
d->insertRows(rowCnt, row - rowCnt + 1);
1986
d->setWidget(row, role, widget);
1990
Sets the sub-layout in the given \a row for the given \a role to \a layout, extending the
1991
form layout with empty rows if necessary.
1993
If the cell is already occupied, the \a layout is not inserted and an error message is
1994
sent to the console.
1996
\b{Note:} For most applications, addRow() or insertRow() should be used instead of setLayout().
2000
void QFormLayout::setLayout(int row, ItemRole role, QLayout *layout)
2003
int rowCnt = rowCount();
2005
d->insertRows(rowCnt, row - rowCnt + 1);
2006
d->setLayout(row, role, layout);
2010
Sets the item in the given \a row for the given \a role to \a item, extending the
2011
layout with empty rows if necessary.
2013
If the cell is already occupied, the \a item is not inserted and an error message is
2014
sent to the console.
2015
The \a item spans both columns.
2017
\warning Do not use this function to add child layouts or child
2018
widget items. Use setLayout() or setWidget() instead.
2022
void QFormLayout::setItem(int row, ItemRole role, QLayoutItem *item)
2025
int rowCnt = rowCount();
2027
d->insertRows(rowCnt, row - rowCnt + 1);
2028
d->setItem(row, role, item);
2035
void QFormLayout::resetFieldGrowthPolicy()
2038
d->fieldGrowthPolicy = DefaultFieldGrowthPolicy;
2045
void QFormLayout::resetRowWrapPolicy()
2048
d->rowWrapPolicy = DefaultRowWrapPolicy;
2055
void QFormLayout::resetFormAlignment()
2058
d->formAlignment = 0;
2065
void QFormLayout::resetLabelAlignment()
2068
d->labelAlignment = 0;
2072
void QFormLayout::dump() const
2074
Q_D(const QFormLayout);
2075
for (int i = 0; i < rowCount(); ++i) {
2076
for (int j = 0; j < 2; ++j) {
2077
qDebug("m_matrix(%d, %d) = %p", i, j, d->m_matrix(i, j));
2080
for (int i = 0; i < d->m_things.count(); ++i)
2081
qDebug("m_things[%d] = %p", i, d->m_things.at(i));