Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qformlayout.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qapplication.h"
5#include "qdebug.h"
6#include "qformlayout.h"
7#include "qlabel.h"
8#include "qlayout_p.h"
9#include "qlayoutengine_p.h"
10#include "qlist.h"
11#include "qrect.h"
12#include "qwidget.h"
13
15
16namespace QtPrivate {
17// Fixed column matrix, stores items as [i11, i12, i21, i22...],
18// with FORTRAN-style index operator(r, c).
19template <class T, int NumColumns>
21public:
22 typedef QList<T> Storage;
23
25
26 void clear() { m_storage.clear(); }
27
28 const T &operator()(int r, int c) const { return m_storage[r * NumColumns + c]; }
29 T &operator()(int r, int c) { return m_storage[r * NumColumns + c]; }
30
31 int rowCount() const { return m_storage.size() / NumColumns; }
32 void insertRow(int r, const T &value);
33 void removeRow(int r);
34
35 // Hmmpf.. Some things are faster that way.
36 const Storage &storage() const { return m_storage; }
37
38 static void storageIndexToPosition(int idx, int *rowPtr, int *colPtr);
39
40private:
41 Storage m_storage;
42};
43
44template <class T, int NumColumns>
46{
47 typename Storage::iterator it = m_storage.begin();
48 it += r * NumColumns;
49 m_storage.insert(it, NumColumns, value);
50}
51
52template <class T, int NumColumns>
54{
55 m_storage.remove(r * NumColumns, NumColumns);
56}
57
58template <class T, int NumColumns>
59void FixedColumnMatrix<T, NumColumns>::storageIndexToPosition(int idx, int *rowPtr, int *colPtr)
60{
61 *rowPtr = idx / NumColumns;
62 *colPtr = idx % NumColumns;
63}
64} // namespace
65
66// special values for unset fields; must not clash with values of FieldGrowthPolicy or
67// RowWrapPolicy
70
71// -- our data structure for our items
72// This owns the QLayoutItem
74{
76 ~QFormLayoutItem() { delete item; }
77
78 // Wrappers
79 QWidget *widget() const { return item->widget(); }
80 QLayout *layout() const { return item->layout(); }
81
82 bool hasHeightForWidth() const { return item->hasHeightForWidth(); }
83 int heightForWidth(int width) const { return item->heightForWidth(width); }
85 Qt::Orientations expandingDirections() const { return item->expandingDirections(); }
86 QSizePolicy::ControlTypes controlTypes() const { return item->controlTypes(); }
87 int vStretch() const { return widget() ? widget()->sizePolicy().verticalStretch() : 0; }
88
89 void setGeometry(const QRect& r) { item->setGeometry(r); }
90 QRect geometry() const { return item->geometry(); }
91
92 void setVisible(bool on);
93 bool isHidden() const { return !isVisible || (widget() && widget()->isHidden()); }
94
95 // For use with FixedColumnMatrix
96 bool operator==(const QFormLayoutItem& other) { return item == other.item; }
97
98 QLayoutItem *item = nullptr;
99 bool fullRow = false;
100 bool isVisible = true;
101
102 // set by updateSizes
103 bool isHfw = false;
107
108 // also set by updateSizes
109 int sbsHSpace = -1; // only used for side by side, for the field item only (not label)
110 int vSpace = -1; // This is the spacing to the item in the row above
111
112 // set by setupVerticalLayoutData
113 bool sideBySide = false;
114 int vLayoutIndex = -1;
115
116 // set by setupHorizontalLayoutData
117 int layoutPos = -1;
118 int layoutWidth = -1;
119};
120
122{
123 for (int i = 0; i < layout->count(); ++i) {
125 if (QWidget *widget = item->widget())
126 widget->setVisible(on);
127 else if (item->layout())
128 hideOrShowWidgetsInLayout(item->layout(), on);
129 }
130}
131
133{
134 isVisible = on;
135 // Explicitly hide the widget so that it loses focus and
136 // doesn't automatically get shown again when this layout
137 // hides and shows.
138 if (widget()) {
139 widget()->setVisible(on);
140 return;
141 }
142 // Layouts can't be hidden, so we have to traverse the widgets
143 // inside and hide all of them so that they also lose focus.
144 if (layout())
146}
147
149{
150 Q_DECLARE_PUBLIC(QFormLayout)
151
152public:
154
157
158 int insertRow(int row);
159 void insertRows(int row, int count);
160 void removeRow(int row);
164
165 void arrangeWidgets(const QList<QLayoutStruct> &layouts, QRect &rect);
166
167 void updateSizes();
168
171
172 QStyle* getStyle() const;
173
174 inline bool haveHfwCached(int width) const
175 {
176 return (hfw_width == width) || (width == sh_width && hfw_sh_height >= 0);
177 }
178
179 void recalcHFW(int w);
180 void setupHfwLayoutData();
181
185 uint dirty : 2; // have we laid out yet?
186 uint sizesDirty : 2; // have we (not) gathered layout item sizes?
187 uint expandVertical : 1; // Do we expand vertically?
188 uint expandHorizontal : 1; // Do we expand horizonally?
189 Qt::Alignment labelAlignment;
190 Qt::Alignment formAlignment;
191
193 QList<QFormLayoutItem *> m_things;
194
195 int layoutWidth = -1; // the last width that we called setupVerticalLayoutData on (for vLayouts)
196
197 int hfw_width = -1; // the last width we calculated HFW for
198 int hfw_height = -1; // what that height was
199
200 int hfw_sh_height = -1; // the hfw for sh_width
201 int hfw_sh_minheight = -1; // the minhfw for sh_width
202
203 int min_width = -1; // the width that gets turned into minSize (from updateSizes)
204 int sh_width = -1; // the width that gets turned into prefSize (from updateSizes)
205 int thresh_width = QLAYOUTSIZE_MAX; // the width that we start splitting label/field pairs at (from updateSizes)
209 void calcSizeHints();
210
211 QList<QLayoutStruct> vLayouts; // set by setupVerticalLayoutData;
212 int vLayoutCount; // Number of rows we calculated in setupVerticalLayoutData
213 int maxLabelWidth; // the label width we calculated in setupVerticalLayoutData
214
215 QList<QLayoutStruct> hfwLayouts;
216
217 int hSpacing = -1;
218 int vSpacing = -1;
219 QLayoutItem* replaceAt(int index, QLayoutItem*) override;
220};
221
223 : fieldGrowthPolicy(DefaultFieldGrowthPolicy),
224 rowWrapPolicy(DefaultRowWrapPolicy), has_hfw(false), dirty(true), sizesDirty(true),
225 expandVertical(0), expandHorizontal(0)
226{
227}
228
229static Qt::Alignment fixedAlignment(Qt::Alignment alignment, Qt::LayoutDirection layoutDirection)
230{
231 if (layoutDirection == Qt::RightToLeft && alignment & Qt::AlignAbsolute) {
232 // swap left and right, and eliminate absolute flag
233 return Qt::Alignment((alignment & ~(Qt::AlignLeft | Qt::AlignRight | Qt::AlignAbsolute))
236 } else {
237 return alignment & ~Qt::AlignAbsolute;
238 }
239}
240
243{
244 if (item) {
245 return m.storage().indexOf(item);
246 } else {
247 return -1;
248 }
249}
250
251static void updateFormLayoutItem(QFormLayoutItem *item, int userVSpacing,
252 QFormLayout::FieldGrowthPolicy fieldGrowthPolicy,
253 bool fullRow)
254{
255 item->minSize = item->item->minimumSize();
256 item->sizeHint = item->item->sizeHint();
257 item->maxSize = item->item->maximumSize();
258
259 if (!fullRow && (fieldGrowthPolicy == QFormLayout::FieldsStayAtSizeHint
260 || (fieldGrowthPolicy == QFormLayout::ExpandingFieldsGrow
261 && !(item->item->expandingDirections() & Qt::Horizontal))))
262 item->maxSize.setWidth(item->sizeHint.width());
263
264 item->isHfw = item->item->hasHeightForWidth();
265 item->vSpace = userVSpacing;
266}
267
268/*
269 Iterate over all the controls and gather their size information
270 (min, sizeHint and max). Also work out what the spacing between
271 pairs of controls should be, and figure out the min and sizeHint
272 widths.
273*/
275{
276 Q_Q(QFormLayout);
277
278 if (sizesDirty) {
279 QFormLayout::RowWrapPolicy wrapPolicy = q->rowWrapPolicy();
280 bool wrapAllRows = (wrapPolicy == QFormLayout::WrapAllRows);
281 bool dontWrapRows = (wrapPolicy == QFormLayout::DontWrapRows);
282 int rr = m_matrix.rowCount();
283
284 has_hfw = false;
285
286 // If any control can expand, so can this layout
287 // Wrapping doesn't affect expansion, though, just the minsize
288 bool expandH = false;
289 bool expandV = false;
290
291 QFormLayoutItem *prevLbl = nullptr;
292 QFormLayoutItem *prevFld = nullptr;
293
294 QWidget *parent = q->parentWidget();
295 QStyle *style = parent ? parent->style() : nullptr;
296
297 int userVSpacing = q->verticalSpacing();
298 int userHSpacing = wrapAllRows ? 0 : q->horizontalSpacing();
299
300 int maxMinLblWidth = 0;
301 int maxMinFldWidth = 0; // field with label
302 int maxMinIfldWidth = 0; // independent field
303
304 int maxShLblWidth = 0;
305 int maxShFldWidth = 0;
306 int maxShIfldWidth = 0;
307
308 for (int i = 0; i < rr; ++i) {
310 QFormLayoutItem *field = m_matrix(i, 1);
311
312 // Skip empty rows
313 if (!label && !field)
314 continue;
315
316 if (label) {
317 updateFormLayoutItem(label, userVSpacing, q->fieldGrowthPolicy(), false);
318 if (label->isHfw)
319 has_hfw = true;
320 Qt::Orientations o = label->expandingDirections();
321
322 if (o & Qt::Vertical)
323 expandV = true;
324 if (o & Qt::Horizontal)
325 expandH = true;
326 }
327 if (field) {
328 updateFormLayoutItem(field, userVSpacing, q->fieldGrowthPolicy(), !label && field->fullRow);
329 field->sbsHSpace = (!label && field->fullRow) ? 0 : userHSpacing;
330 if (field->isHfw)
331 has_hfw = true;
332
333 Qt::Orientations o = field->expandingDirections();
334
335 if (o & Qt::Vertical)
336 expandV = true;
337 if (o & Qt::Horizontal)
338 expandH = true;
339 }
340
341 // See if we need to calculate default spacings
342 if ((userHSpacing < 0 || userVSpacing < 0) && style) {
343 QSizePolicy::ControlTypes lbltypes =
344 QSizePolicy::ControlTypes(label ? label->controlTypes() : QSizePolicy::DefaultType);
345 QSizePolicy::ControlTypes fldtypes =
346 QSizePolicy::ControlTypes(field ? field->controlTypes() : QSizePolicy::DefaultType);
347
348 // VSpacing
349 if (userVSpacing < 0) {
350 if (wrapAllRows) {
351 // label spacing is to a previous item
352 QFormLayoutItem *lbltop = prevFld ? prevFld : prevLbl;
353 // field spacing is to the label (or a previous item)
354 QFormLayoutItem *fldtop = label ? label : lbltop;
355 QSizePolicy::ControlTypes lbltoptypes =
356 QSizePolicy::ControlTypes(lbltop ? lbltop->controlTypes() : QSizePolicy::DefaultType);
357 QSizePolicy::ControlTypes fldtoptypes =
358 QSizePolicy::ControlTypes(fldtop ? fldtop->controlTypes() : QSizePolicy::DefaultType);
359 if (label && lbltop)
360 label->vSpace = style->combinedLayoutSpacing(lbltoptypes, lbltypes, Qt::Vertical, nullptr, parent);
361 if (field && fldtop)
362 field->vSpace = style->combinedLayoutSpacing(fldtoptypes, fldtypes, Qt::Vertical, nullptr, parent);
363 } else {
364 // Side by side.. we have to also consider the spacings to empty cells, which can strangely be more than
365 // non empty cells..
366 QFormLayoutItem *lbltop = prevLbl ? prevLbl : prevFld;
367 QFormLayoutItem *fldtop = prevFld;
368 QSizePolicy::ControlTypes lbltoptypes =
369 QSizePolicy::ControlTypes(lbltop ? lbltop->controlTypes() : QSizePolicy::DefaultType);
370 QSizePolicy::ControlTypes fldtoptypes =
371 QSizePolicy::ControlTypes(fldtop ? fldtop->controlTypes() : QSizePolicy::DefaultType);
372
373 // To be compatible to QGridLayout, we have to compare solitary labels & fields with both predecessors
374 if (label && !label->isHidden()) {
375 if (!field) {
376 int lblspacing = style->combinedLayoutSpacing(lbltoptypes, lbltypes, Qt::Vertical, nullptr, parent);
377 int fldspacing = style->combinedLayoutSpacing(fldtoptypes, lbltypes, Qt::Vertical, nullptr, parent);
378 label->vSpace = qMax(lblspacing, fldspacing);
379 } else {
380 label->vSpace = style->combinedLayoutSpacing(lbltoptypes, lbltypes, Qt::Vertical, nullptr, parent);
381 }
382 }
383
384 if (field && !field->isHidden()) {
385 // check spacing against both the previous label and field
386 if (!label) {
387 int lblspacing = style->combinedLayoutSpacing(lbltoptypes, fldtypes, Qt::Vertical, nullptr, parent);
388 int fldspacing = style->combinedLayoutSpacing(fldtoptypes, fldtypes, Qt::Vertical, nullptr, parent);
389 field->vSpace = qMax(lblspacing, fldspacing);
390 } else {
391 field->vSpace = style->combinedLayoutSpacing(fldtoptypes, fldtypes, Qt::Vertical, nullptr, parent);
392 }
393 }
394 }
395 }
396
397 // HSpacing
398 // hard-coded the left and right control types so that all the rows have the same
399 // inter-column spacing (otherwise the right column isn't always left aligned)
400 if (userHSpacing < 0 && !wrapAllRows && (label || !field->fullRow) && field)
402 }
403
404 // Now update our min/sizehint widths
405 // We choose to put the spacing in the field side in sbs, so
406 // the right edge of the labels will align, but fields may
407 // be a little ragged.. since different controls may have
408 // different appearances, a slight raggedness in the left
409 // edges of fields can be tolerated.
410 // (Note - field->sbsHSpace is 0 for WrapAllRows mode)
411 if (label) {
412 maxMinLblWidth = qMax(maxMinLblWidth, label->minSize.width());
413 maxShLblWidth = qMax(maxShLblWidth, label->sizeHint.width());
414 }
415 if (field) {
416 if (field->fullRow) {
417 maxMinIfldWidth = qMax(maxMinIfldWidth, field->minSize.width());
418 maxShIfldWidth = qMax(maxShIfldWidth, field->sizeHint.width());
419 } else {
420 maxMinFldWidth = qMax(maxMinFldWidth, field->minSize.width() + field->sbsHSpace);
421 maxShFldWidth = qMax(maxShFldWidth, field->sizeHint.width() + field->sbsHSpace);
422 }
423 }
424
425 prevLbl = label;
426 prevFld = field;
427 }
428
429 // Now, finally update the min/sizeHint widths
430 if (wrapAllRows) {
431 sh_width = qMax(maxShLblWidth, qMax(maxShIfldWidth, maxShFldWidth));
432 min_width = qMax(maxMinLblWidth, qMax(maxMinIfldWidth, maxMinFldWidth));
433 // in two line, we don't care as much about the threshold width
434 thresh_width = 0;
435 } else if (dontWrapRows) {
436 // This is just the max widths glommed together
437 sh_width = qMax(maxShLblWidth + maxShFldWidth, maxShIfldWidth);
438 min_width = qMax(maxMinLblWidth + maxMinFldWidth, maxMinIfldWidth);
440 } else {
441 // This is just the max widths glommed together
442 sh_width = qMax(maxShLblWidth + maxShFldWidth, maxShIfldWidth);
443 // min width needs to be the min when everything is wrapped,
444 // otherwise we'll never get set with a width that causes wrapping
445 min_width = qMax(maxMinLblWidth, qMax(maxMinIfldWidth, maxMinFldWidth));
446 // We split a pair at label sh + field min (### for now..)
447 thresh_width = maxShLblWidth + maxMinFldWidth;
448 }
449
450 // Update the expansions
451 expandVertical = expandV;
452 expandHorizontal = expandH;
453 }
454 sizesDirty = false;
455}
456
458{
460
461 int h = 0;
462 int mh = 0;
463
464 for (int r = 0; r < vLayoutCount; ++r) {
468 }
469
470 if (sh_width > 0 && sh_width == w) {
473 } else {
474 hfw_width = w;
476 }
477}
478
480{
481 Q_Q(QFormLayout);
482 // setupVerticalLayoutData must be called before this
483 // setupHorizontalLayoutData must also be called before this
484 // copies non hfw data into hfw
485 // then updates size and min
486
487
488 // Note: QGridLayout doesn't call minimumHeightForWidth,
489 // but instead uses heightForWidth for both min and sizeHint.
490 // For the common case where minimumHeightForWidth just calls
491 // heightForWidth, we do the calculation twice, which can be
492 // very expensive for word wrapped QLabels/QTextEdits, for example.
493 // So we just use heightForWidth as well.
494 int i;
495 int rr = m_matrix.rowCount();
496
499 for (i = 0; i < vLayoutCount; ++i)
501
502 for (i = 0; i < rr; ++i) {
504 QFormLayoutItem *field = m_matrix(i, 1);
505
506 // ignore rows with only hidden items
507 if (!q->isRowVisible(i))
508 continue;
509
510 if (label && label->vLayoutIndex > -1) {
511 if (label->isHfw) {
512 // We don't check sideBySide here, since a label is only
513 // ever side by side with its field
514 int hfw = label->heightForWidth(label->layoutWidth);
515 hfwLayouts[label->vLayoutIndex].minimumSize = hfw;
516 hfwLayouts[label->vLayoutIndex].sizeHint = hfw;
517 } else {
518 // Reset these here, so the field can do a qMax below (the previous value may have
519 // been the fields non-hfw values, which are often larger than hfw)
520 hfwLayouts[label->vLayoutIndex].sizeHint = label->sizeHint.height();
521 hfwLayouts[label->vLayoutIndex].minimumSize = label->minSize.height();
522 }
523 }
524
525 if (field && field->vLayoutIndex > -1) {
526 int hfw = field->isHfw ? field->heightForWidth(field->layoutWidth) : 0;
527 int h = field->isHfw ? hfw : field->sizeHint.height();
528 int mh = field->isHfw ? hfw : field->minSize.height();
529
530 if (field->sideBySide) {
531 int oh = hfwLayouts.at(field->vLayoutIndex).sizeHint;
532 int omh = hfwLayouts.at(field->vLayoutIndex).minimumSize;
533
534 hfwLayouts[field->vLayoutIndex].sizeHint = qMax(h, oh);
535 hfwLayouts[field->vLayoutIndex].minimumSize = qMax(mh, omh);
536 } else {
537 hfwLayouts[field->vLayoutIndex].sizeHint = h;
538 hfwLayouts[field->vLayoutIndex].minimumSize = mh;
539 }
540 }
541 }
542}
543
544/*
545 Given up to four items involved in a vertical spacing calculation
546 (two rows * two columns), return the max vertical spacing for the
547 row containing item1 (which may also include item2)
548 We assume parent and item1 are not null.
549
550 If a particular row is split, then the spacings for that row and
551 the following row are affected, and this function should be
552 called with recalculate = true for both rows (note: only rows with both
553 a label and a field can be split).
554
555 In particular:
556
557 1) the split label's row vspace needs to be changed to qMax(label/prevLabel, label/prevField)
558 [call with item1 = label, item2 = null, prevItem1 & prevItem2 as before]
559 2) the split field's row vspace needs to be changed to the label/field spacing
560 [call with item1 = field, item2 = null, prevItem1 = label, prevItem2 = null]
561
562 [if the next row has one item, 'item']
563 3a) the following row's vspace needs to be changed to item/field spacing (would
564 previously been the qMax(item/label, item/field) spacings)
565 [call with item1 = item, item2 = null, prevItem1 = field, prevItem2 = null]
566
567 [if the next row has two items, 'label2' and 'field2']
568 3b) the following row's vspace needs to be changed to be qMax(field/label2, field/field2) spacing
569 [call with item1 = label2, item2 = field2, prevItem1 = field, prevItem2 = null]
570
571 In the (common) non split case, we can just use the precalculated vspace (possibly qMaxed between
572 label and field).
573
574 If recalculate is true, we expect:
575 - parent != null
576 - item1 != null
577 - item2 can be null
578 - prevItem1 can be null
579 - if item2 is not null, prevItem2 will be null (e.g. steps 1 or 3 above)
580 - if prevItem1 is null, prevItem2 will be null
581*/
582static inline int spacingHelper(QWidget* parent, QStyle *style, int userVSpacing, bool recalculate, QFormLayoutItem* item1, QFormLayoutItem* item2, QFormLayoutItem* prevItem1, QFormLayoutItem *prevItem2)
583{
584 int spacing = userVSpacing;
585 if (spacing < 0) {
586 if (!recalculate) {
587 if (item1)
588 spacing = item1->vSpace;
589 if (item2)
590 spacing = qMax(spacing, item2->vSpace);
591 } else {
592 if (style && prevItem1) {
593 QSizePolicy::ControlTypes itemtypes =
594 QSizePolicy::ControlTypes(item1 ? item1->controlTypes() : QSizePolicy::DefaultType);
595 int spacing2 = 0;
596
597 spacing = style->combinedLayoutSpacing(itemtypes, prevItem1->controlTypes(), Qt::Vertical, nullptr, parent);
598
599 // At most of one of item2 and prevItem2 will be nonnull
600 if (item2)
601 spacing2 = style->combinedLayoutSpacing(item2->controlTypes(), prevItem1->controlTypes(), Qt::Vertical, nullptr, parent);
602 else if (prevItem2)
603 spacing2 = style->combinedLayoutSpacing(itemtypes, prevItem2->controlTypes(), Qt::Vertical, nullptr, parent);
604
605 spacing = qMax(spacing, spacing2);
606 }
607 }
608 } else {
609 if (prevItem1) {
610 QWidget *wid = prevItem1->item->widget();
611 if (wid)
612 spacing = qMax(spacing, prevItem1->geometry().top() - wid->geometry().top() );
613 }
614 if (prevItem2) {
615 QWidget *wid = prevItem2->item->widget();
616 if (wid)
617 spacing = qMax(spacing, prevItem2->geometry().top() - wid->geometry().top() );
618 }
619 }
620 return qMax(spacing, 0);
621}
622
624{
625 sl.init(item->vStretch(), item->minSize.height());
626 sl.sizeHint = item->sizeHint.height();
627 sl.maximumSize = item->maxSize.height();
628 sl.expansive = (item->expandingDirections() & Qt::Vertical);
629 sl.empty = false;
630}
631
633{
634 Q_Q(QFormLayout);
635
636 // Early out if we have no changes that would cause a change in vertical layout
638 return;
639
641
642 int rr = m_matrix.rowCount();
643 int vidx = 1;
644 QFormLayout::RowWrapPolicy rowWrapPolicy = q->rowWrapPolicy();
645 bool wrapAllRows = (rowWrapPolicy == QFormLayout::WrapAllRows);
646 bool addTopBottomStretch = true;
647
648 vLayouts.clear();
649 vLayouts.resize((2 * rr) + 2); // a max, some may be unused
650
651 QStyle *style = nullptr;
652
653 int userVSpacing = q->verticalSpacing();
654
655 if (userVSpacing < 0) {
656 if (QWidget *widget = q->parentWidget())
657 style = widget->style();
658 }
659
660 // make sure our sizes are up to date
661 updateSizes();
662
663 // Grab the widest label width here
664 // This might be different from the value computed during
665 // sizeHint/minSize, since we don't count label/field pairs that
666 // are split.
667 maxLabelWidth = 0;
668 if (!wrapAllRows) {
669 for (int i = 0; i < rr; ++i) {
670 const QFormLayoutItem *label = m_matrix(i, 0);
671 const QFormLayoutItem *field = m_matrix(i, 1);
672 if (label && (label->sizeHint.width() + (field ? field->minSize.width() : 0) <= width))
673 maxLabelWidth = qMax(maxLabelWidth, label->sizeHint.width());
674 }
675 } else {
677 }
678
679 QFormLayoutItem *prevItem1 = nullptr;
680 QFormLayoutItem *prevItem2 = nullptr;
681 bool prevRowSplit = false;
682
683 for (int i = 0; i < rr; ++i) {
685 QFormLayoutItem *field = m_matrix(i, 1);
686
687 // Ignore empty rows or rows with only hidden items,
688 // and invalidate their position in the layout.
689 if (!q->isRowVisible(i)) {
690 if (label)
691 label->vLayoutIndex = -1;
692 if (field)
693 field->vLayoutIndex = -1;
694 continue;
695 }
696
697 QSize min1;
698 QSize min2;
699 QSize sh1;
700 QSize sh2;
701 if (label) {
702 min1 = label->minSize;
703 sh1 = label->sizeHint;
704 }
705 if (field) {
706 min2 = field->minSize;
707 sh2 = field->sizeHint;
708 }
709
710 // In separate lines, we make a vLayout for everything that isn't null
711 // in side by side, we only separate label/field if we're going to wrap it
712 bool splitSideBySide = (rowWrapPolicy == QFormLayout::WrapLongRows)
713 && ((maxLabelWidth < sh1.width()) || (width < (maxLabelWidth + min2.width())));
714
715 if (wrapAllRows || splitSideBySide) {
716 if (label) {
718
719 if (vidx > 1)
720 vLayouts[vidx - 1].spacing = spacingHelper(q->parentWidget(), style, userVSpacing, splitSideBySide || prevRowSplit, label, nullptr, prevItem1, prevItem2);
721
722 label->vLayoutIndex = vidx;
723 label->sideBySide = false;
724
725 prevItem1 = label;
726 prevItem2 = nullptr;
727
728 if (vLayouts[vidx].stretch > 0)
729 addTopBottomStretch = false;
730
731 ++vidx;
732 }
733
734 if (field) {
735 initLayoutStruct(vLayouts[vidx], field);
736
737 if (vidx > 1)
738 vLayouts[vidx - 1].spacing = spacingHelper(q->parentWidget(), style, userVSpacing, splitSideBySide || prevRowSplit, field, nullptr, prevItem1, prevItem2);
739
740 field->vLayoutIndex = vidx;
741 field->sideBySide = false;
742
743 prevItem1 = field;
744 prevItem2 = nullptr;
745
746 if (vLayouts[vidx].stretch > 0)
747 addTopBottomStretch = false;
748
749 ++vidx;
750 }
751
752 prevRowSplit = splitSideBySide;
753 } else {
754 // we're in side by side mode, and we have enough space to do that
757
758 int stretch1 = 0;
759 int stretch2 = 0;
760 bool expanding = false;
761
762 if (label) {
763 max1 = label->maxSize;
764 if (label->expandingDirections() & Qt::Vertical)
765 expanding = true;
766
767 label->sideBySide = (field != nullptr);
768 label->vLayoutIndex = vidx;
769 stretch1 = label->vStretch();
770 }
771
772 if (field) {
773 max2 = field->maxSize;
774 if (field->expandingDirections() & Qt::Vertical)
775 expanding = true;
776
777 field->sideBySide = (label || !field->fullRow);
778 field->vLayoutIndex = vidx;
779 stretch2 = field->vStretch();
780 }
781
782 vLayouts[vidx].init(qMax(stretch1, stretch2), qMax(min1.height(), min2.height()));
783 vLayouts[vidx].sizeHint = qMax(sh1.height(), sh2.height());
784 vLayouts[vidx].maximumSize = qMin(max1.height(), max2.height());
785 vLayouts[vidx].expansive = expanding || (vLayouts[vidx].stretch > 0);
786 vLayouts[vidx].empty = false;
787
788 if (vLayouts[vidx].expansive)
789 addTopBottomStretch = false;
790
791 if (vidx > 1)
792 vLayouts[vidx - 1].spacing = spacingHelper(q->parentWidget(), style, userVSpacing, prevRowSplit, label, field, prevItem1, prevItem2);
793
794 if (label) {
795 prevItem1 = label;
796 prevItem2 = field;
797 } else {
798 prevItem1 = field;
799 prevItem2 = nullptr;
800 }
801
802 prevRowSplit = false;
803 ++vidx;
804 }
805 }
806
807 if (addTopBottomStretch) {
808 Qt::Alignment formAlignment = q->formAlignment();
809
811 // AlignTop (default if unspecified) or AlignVCenter: We add a stretch at the bottom
812 vLayouts[vidx].init(1, 0);
813 vLayouts[vidx].expansive = true;
814 ++vidx;
815 }
816
818 // AlignVCenter or AlignBottom: We add a stretch at the top
819 vLayouts[0].init(1, 0);
820 vLayouts[0].expansive = true;
821 } else {
822 vLayouts[0].init(0, 0);
823 }
824 } else {
825 vLayouts[0].init(0, 0);
826 }
827
828 vLayoutCount = vidx;
829 dirty = false;
830}
831
833{
834 Q_Q(QFormLayout);
835
836 // requires setupVerticalLayoutData to be called first
837
838 int fieldMaxWidth = 0;
839
840 int rr = m_matrix.rowCount();
841 bool wrapAllRows = (q->rowWrapPolicy() == QFormLayout::WrapAllRows);
842
843 for (int i = 0; i < rr; ++i) {
845 QFormLayoutItem *field = m_matrix(i, 1);
846
847 // Totally ignore empty rows...
848 if (!label && !field)
849 continue;
850
851 if (label) {
852 // if there is a field, and we're side by side, we use maxLabelWidth
853 // otherwise we just use the sizehint
854 label->layoutWidth = (field && label->sideBySide) ? maxLabelWidth : label->sizeHint.width();
855 label->layoutPos = 0;
856 }
857
858 if (field) {
859 // This is the default amount allotted to fields in sbs
860 int fldwidth = width - maxLabelWidth - field->sbsHSpace;
861
862 // If we've split a row, we still decide to align
863 // the field with all the other field if it will fit
864 // Fields in sbs mode get the remnants of the maxLabelWidth
865 if (!field->sideBySide) {
866 if (wrapAllRows || (!label && field->fullRow) || field->sizeHint.width() > fldwidth) {
867 field->layoutWidth = width;
868 field->layoutPos = 0;
869 } else {
870 field->layoutWidth = fldwidth;
871 field->layoutPos = width - fldwidth;
872 }
873 } else {
874 // We're sbs, so we should have a label
875 field->layoutWidth = fldwidth;
876 field->layoutPos = width - fldwidth;
877 }
878
879 fieldMaxWidth = qMax(fieldMaxWidth, field->maxSize.width());
880 }
881 }
882
883 formMaxWidth = maxLabelWidth + fieldMaxWidth;
884}
885
887{
888 Q_Q(QFormLayout);
889
890 int leftMargin, topMargin, rightMargin, bottomMargin;
891 q->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
892
893 updateSizes();
895 // Don't need to call setupHorizontal here
896
897 int h = topMargin + bottomMargin;
898 int mh = topMargin + bottomMargin;
899
900 // The following are set in updateSizes
901 int w = sh_width + leftMargin + rightMargin;
902 int mw = min_width + leftMargin + rightMargin;
903
904 for (int i = 0; i < vLayoutCount; ++i) {
905 int spacing = vLayouts.at(i).spacing;
908 }
909
914}
915
917{
918 int rowCnt = m_matrix.rowCount();
919 if (uint(row) > uint(rowCnt))
920 row = rowCnt;
921
922 insertRows(row, 1);
923 return row;
924}
925
927{
928 while (count > 0) {
930 --count;
931 }
932}
933
939
941{
942 const bool fullRow = role == QFormLayout::SpanningRole;
943 const int column = role == QFormLayout::SpanningRole ? 1 : static_cast<int>(role);
944 if (Q_UNLIKELY(uint(row) >= uint(m_matrix.rowCount()) || uint(column) > 1U)) {
945 qWarning("QFormLayoutPrivate::setItem: Invalid cell (%d, %d)", row, column);
946 return false;
947 }
948
949 if (!item)
950 return false;
951
952 if (Q_UNLIKELY(m_matrix(row, column))) {
953 qWarning("QFormLayoutPrivate::setItem: Cell (%d, %d) already occupied", row, column);
954 return false;
955 }
956
958 i->fullRow = fullRow;
959 m_matrix(row, column) = i;
960
962 return true;
963}
964
966{
967 if (layout) {
968 Q_Q(QFormLayout);
969 if (q->adoptLayout(layout))
970 setItem(row, role, layout);
971 }
972}
973
975{
976 if (widget) {
977 Q_Q(QFormLayout);
978 q->addChildWidget(widget);
980 if (!setItem(row, role, item))
981 delete item;
982 }
983}
984
986{
987 Q_Q(const QFormLayout);
988
989 // ### cache
990 if (QWidget *parentWidget = q->parentWidget())
991 return parentWidget->style();
992 else
993 return QApplication::style();
994}
995
997{
998 Q_Q(QFormLayout);
999 if (!newitem)
1000 return nullptr;
1001 const int storageIndex = storageIndexFromLayoutItem(m_matrix, m_things.value(index));
1002 if (Q_UNLIKELY(storageIndex == -1)) {
1003 // ### Qt6 - fix warning too when this class becomes public
1004 qWarning("QFormLayoutPrivate::replaceAt: Invalid index %d", index);
1005 return nullptr;
1006 }
1007
1008 int row, col;
1010 Q_ASSERT(m_matrix(row, col));
1011
1013 Q_ASSERT(item);
1014
1015 QLayoutItem *olditem = item->item;
1016 item->item = newitem;
1017
1018 q->invalidate();
1019 return olditem;
1020}
1021
1205 : QLayout(*new QFormLayoutPrivate, nullptr, parent)
1206{
1207}
1208
1213{
1214 Q_D(QFormLayout);
1215
1216 /*
1217 The clearing and destruction order here is important. We start by clearing
1218 m_things so that QLayout and the rest of the world know that we don't babysit
1219 the layout items anymore and don't care if they are destroyed.
1220 */
1221 d->m_things.clear();
1222 qDeleteAll(d->m_matrix.storage());
1223 d->m_matrix.clear();
1224}
1225
1233{
1234 insertRow(-1, label, field);
1235}
1236
1241{
1242 insertRow(-1, label, field);
1243}
1244
1252void QFormLayout::addRow(const QString &labelText, QWidget *field)
1253{
1254 insertRow(-1, labelText, field);
1255}
1256
1263void QFormLayout::addRow(const QString &labelText, QLayout *field)
1264{
1265 insertRow(-1, labelText, field);
1266}
1267
1275{
1276 insertRow(-1, widget);
1277}
1278
1286{
1287 insertRow(-1, layout);
1288}
1289
1298{
1299 Q_D(QFormLayout);
1300 if ((label && !d->checkWidget(label)) || (field && !d->checkWidget(field)))
1301 return;
1302
1303 row = d->insertRow(row);
1304 if (label)
1305 d->setWidget(row, LabelRole, label);
1306 if (field)
1307 d->setWidget(row, FieldRole, field);
1308 invalidate();
1309}
1310
1315{
1316 Q_D(QFormLayout);
1317 if ((label && !d->checkWidget(label)) || (field && !d->checkLayout(field)))
1318 return;
1319
1320 row = d->insertRow(row);
1321 if (label)
1322 d->setWidget(row, LabelRole, label);
1323 if (field)
1324 d->setLayout(row, FieldRole, field);
1325 invalidate();
1326}
1327
1335void QFormLayout::insertRow(int row, const QString &labelText, QWidget *field)
1336{
1337 Q_D(QFormLayout);
1338 if (field && !d->checkWidget(field))
1339 return;
1340
1341 QLabel *label = nullptr;
1342 if (!labelText.isEmpty()) {
1343 label = new QLabel(labelText);
1344#ifndef QT_NO_SHORTCUT
1345 label->setBuddy(field);
1346#endif
1347 }
1348 insertRow(row, label, field);
1349}
1350
1357void QFormLayout::insertRow(int row, const QString &labelText, QLayout *field)
1358{
1359 Q_D(QFormLayout);
1360 if (field && !d->checkLayout(field))
1361 return;
1362
1363 insertRow(row, labelText.isEmpty() ? nullptr : new QLabel(labelText), field);
1364}
1365
1374{
1375 Q_D(QFormLayout);
1376 if (!d->checkWidget(widget))
1377 return;
1378
1379 row = d->insertRow(row);
1380 d->setWidget(row, SpanningRole, widget);
1381 invalidate();
1382}
1383
1392{
1393 Q_D(QFormLayout);
1394 if (!d->checkLayout(layout))
1395 return;
1396
1397 row = d->insertRow(row);
1398 d->setLayout(row, SpanningRole, layout);
1399 invalidate();
1400}
1401
1403{
1404 if (!item)
1405 return nullptr;
1406
1407 // grab ownership back from the QFormLayoutItem
1408 QLayoutItem *i = item->item;
1409 item->item = nullptr;
1410 delete item;
1411
1412 if (QLayout *l = i->layout()) {
1413 // sanity check in case the user passed something weird to QObject::setParent()
1414 if (l->parent() == layout)
1415 l->setParent(nullptr);
1416 }
1417
1418 return i;
1419}
1420
1422{
1423 if (Q_LIKELY(item)) {
1424 delete item->widget();
1425 if (QLayout *layout = item->layout()) {
1426 while (QLayoutItem *child = layout->takeAt(0))
1428 }
1429 delete item;
1430 }
1431}
1432
1458
1484
1511
1535{
1536 Q_D(QFormLayout);
1537
1538 if (Q_UNLIKELY(!(uint(row) < uint(d->m_matrix.rowCount())))) {
1539 qWarning("QFormLayout::takeRow: Invalid row %d", row);
1540 return TakeRowResult();
1541 }
1542
1543 QFormLayoutItem *label = d->m_matrix(row, 0);
1544 QFormLayoutItem *field = d->m_matrix(row, 1);
1545
1546 d->m_things.removeOne(label);
1547 d->m_things.removeOne(field);
1548 d->m_matrix.removeRow(row);
1549
1550 invalidate();
1551
1554 result.fieldItem = ownershipCleanedItem(field, this);
1555 return result;
1556}
1557
1580{
1581 Q_D(QFormLayout);
1582 if (Q_UNLIKELY(!d->checkWidget(widget)))
1583 return TakeRowResult();
1584
1585 int row;
1586 ItemRole role;
1587 getWidgetPosition(widget, &row, &role);
1588
1589 if (Q_UNLIKELY(row < 0)) {
1590 qWarning("QFormLayout::takeRow: Invalid widget");
1591 return TakeRowResult();
1592 }
1593
1594 return takeRow(row);
1595}
1596
1620{
1621 Q_D(QFormLayout);
1622 if (Q_UNLIKELY(!d->checkLayout(layout)))
1623 return TakeRowResult();
1624
1625 int row;
1626 ItemRole role;
1627 getLayoutPosition(layout, &row, &role);
1628
1629 if (Q_UNLIKELY(row < 0)) {
1630 qWarning("QFormLayout::takeRow: Invalid layout");
1631 return TakeRowResult();
1632 }
1633
1634 return takeRow(row);
1635}
1636
1641{
1642 Q_D(QFormLayout);
1643
1644 int row = d->insertRow(d->m_matrix.rowCount());
1645 d->setItem(row, FieldRole, item);
1646 invalidate();
1647}
1648
1653{
1654 Q_D(const QFormLayout);
1655 return d->m_things.size();
1656}
1657
1662{
1663 Q_D(const QFormLayout);
1664 if (QFormLayoutItem *formItem = d->m_things.value(index))
1665 return formItem->item;
1666 return nullptr;
1667}
1668
1673{
1674 Q_D(QFormLayout);
1675
1676 const int storageIndex = storageIndexFromLayoutItem(d->m_matrix, d->m_things.value(index));
1677 if (Q_UNLIKELY(storageIndex == -1)) {
1678 qWarning("QFormLayout::takeAt: Invalid index %d", index);
1679 return nullptr;
1680 }
1681
1682 int row, col;
1684 Q_ASSERT(d->m_matrix(row, col));
1685
1686 QFormLayoutItem *item = d->m_matrix(row, col);
1687 Q_ASSERT(item);
1688 d->m_things.removeAt(index);
1689 d->m_matrix(row, col) = 0;
1690
1691 invalidate();
1692
1693 return ownershipCleanedItem(item, this);
1694}
1695
1699Qt::Orientations QFormLayout::expandingDirections() const
1700{
1701 Q_D(const QFormLayout);
1702 QFormLayoutPrivate *e = const_cast<QFormLayoutPrivate *>(d);
1703 e->updateSizes();
1704
1705 Qt::Orientations o;
1706 if (e->expandHorizontal)
1707 o = Qt::Horizontal;
1708 if (e->expandVertical)
1709 o |= Qt::Vertical;
1710 return o;
1711}
1712
1717{
1718 Q_D(const QFormLayout);
1719 QFormLayoutPrivate *e = const_cast<QFormLayoutPrivate *>(d);
1720 e->updateSizes();
1721 return (d->has_hfw || rowWrapPolicy() == WrapLongRows);
1722}
1723
1728{
1729 Q_D(const QFormLayout);
1730 if (!hasHeightForWidth())
1731 return -1;
1732
1733 int leftMargin, topMargin, rightMargin, bottomMargin;
1734 getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
1735
1736 int targetWidth = width - leftMargin - rightMargin;
1737
1738 if (!d->haveHfwCached(targetWidth)) {
1739 QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
1740 dat->setupVerticalLayoutData(targetWidth);
1741 dat->setupHorizontalLayoutData(targetWidth);
1742 dat->recalcHFW(targetWidth);
1743 }
1744 if (targetWidth == d->sh_width)
1745 return d->hfw_sh_height + topMargin + bottomMargin;
1746 else
1747 return d->hfw_height + topMargin + bottomMargin;
1748}
1749
1754{
1755 Q_D(QFormLayout);
1756 if (d->dirty || rect != geometry()) {
1757 QRect cr = rect;
1758 int leftMargin, topMargin, rightMargin, bottomMargin;
1759 getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
1760 cr.adjust(+leftMargin, +topMargin, -rightMargin, -bottomMargin);
1761
1762 bool hfw = hasHeightForWidth();
1763 d->setupVerticalLayoutData(cr.width());
1764 d->setupHorizontalLayoutData(cr.width());
1765 if (hfw && (!d->haveHfwCached(cr.width()) || d->hfwLayouts.size() != d->vLayoutCount))
1766 d->recalcHFW(cr.width());
1767 if (hfw) {
1768 qGeomCalc(d->hfwLayouts, 0, d->vLayoutCount, cr.y(), cr.height());
1769 d->arrangeWidgets(d->hfwLayouts, cr);
1770 } else {
1771 qGeomCalc(d->vLayouts, 0, d->vLayoutCount, cr.y(), cr.height());
1772 d->arrangeWidgets(d->vLayouts, cr);
1773 }
1775 }
1776}
1777
1782{
1783 Q_D(const QFormLayout);
1784 if (!d->prefSize.isValid()) {
1785 QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
1786 dat->calcSizeHints();
1787 }
1788 return d->prefSize;
1789}
1790
1795{
1796 // ### fix minimumSize if hfw
1797 Q_D(const QFormLayout);
1798 if (!d->minSize.isValid()) {
1799 QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
1800 dat->calcSizeHints();
1801 }
1802 return d->minSize;
1803}
1804
1809{
1810 Q_D(QFormLayout);
1811 d->dirty = true;
1812 d->sizesDirty = true;
1813 d->minSize = QSize();
1814 d->prefSize = QSize();
1815 d->formMaxWidth = -1;
1816 d->hfw_width = -1;
1817 d->sh_width = -1;
1818 d->layoutWidth = -1;
1819 d->hfw_sh_height = -1;
1821}
1822
1829{
1830 Q_D(const QFormLayout);
1831 return d->m_matrix.rowCount();
1832}
1833
1841{
1842 Q_D(const QFormLayout);
1843 if (uint(row) >= uint(d->m_matrix.rowCount()))
1844 return nullptr;
1845 switch (role) {
1846 case SpanningRole:
1847 if (QFormLayoutItem *item = d->m_matrix(row, 1))
1848 if (item->fullRow)
1849 return item->item;
1850 break;
1851 case LabelRole:
1852 case FieldRole:
1853 if (QFormLayoutItem *item = d->m_matrix(row, (role == LabelRole) ? 0 : 1))
1854 return item->item;
1855 break;
1856 }
1857 return nullptr;
1858}
1859
1868void QFormLayout::getItemPosition(int index, int *rowPtr, ItemRole *rolePtr) const
1869{
1870 Q_D(const QFormLayout);
1871 int col = -1;
1872 int row = -1;
1873
1874 const int storageIndex = storageIndexFromLayoutItem(d->m_matrix, d->m_things.value(index));
1875 if (storageIndex != -1)
1877
1878 if (rowPtr)
1879 *rowPtr = row;
1880 if (rolePtr && row != -1) {
1881 const bool spanning = col == 1 && d->m_matrix(row, col)->fullRow;
1882 if (spanning) {
1883 *rolePtr = SpanningRole;
1884 } else {
1885 *rolePtr = ItemRole(col);
1886 }
1887 }
1888}
1889
1896void QFormLayout::getLayoutPosition(QLayout *layout, int *rowPtr, ItemRole *rolePtr) const
1897{
1898 int n = count();
1899 int index = 0;
1900 while (index < n) {
1901 if (itemAt(index) == layout)
1902 break;
1903 ++index;
1904 }
1905 getItemPosition(index, rowPtr, rolePtr);
1906}
1907
1916void QFormLayout::getWidgetPosition(QWidget *widget, int *rowPtr, ItemRole *rolePtr) const
1917{
1918 getItemPosition(indexOf(widget), rowPtr, rolePtr);
1919}
1920
1921// ### eliminate labelForField()
1922
1929{
1930 Q_D(const QFormLayout);
1931
1932 int row;
1933 ItemRole role = LabelRole;
1934
1935 getWidgetPosition(field, &row, &role);
1936
1937 if (row != -1 && role == FieldRole) {
1938 if (QFormLayoutItem *label = d->m_matrix(row, LabelRole))
1939 return label->widget();
1940 }
1941 return nullptr;
1942}
1943
1948{
1949 Q_D(const QFormLayout);
1950
1951 int row;
1952 ItemRole role;
1953
1954 getLayoutPosition(field, &row, &role);
1955
1956 if (row != -1 && role == FieldRole) {
1957 if (QFormLayoutItem *label = d->m_matrix(row, LabelRole))
1958 return label->widget();
1959 }
1960 return nullptr;
1961}
1962
1981{
1982 Q_D(QFormLayout);
1983 if (FieldGrowthPolicy(d->fieldGrowthPolicy) != policy) {
1984 d->fieldGrowthPolicy = policy;
1985 invalidate();
1986 }
1987}
1988
1990{
1991 Q_D(const QFormLayout);
1992 if (d->fieldGrowthPolicy == DefaultFieldGrowthPolicy) {
1994 } else {
1995 return QFormLayout::FieldGrowthPolicy(d->fieldGrowthPolicy);
1996 }
1997}
1998
2014{
2015 Q_D(QFormLayout);
2016 if (RowWrapPolicy(d->rowWrapPolicy) != policy) {
2017 d->rowWrapPolicy = policy;
2018 invalidate();
2019 }
2020}
2021
2023{
2024 Q_D(const QFormLayout);
2025 if (d->rowWrapPolicy == DefaultRowWrapPolicy) {
2026 return QFormLayout::RowWrapPolicy(d->getStyle()->styleHint(QStyle::SH_FormLayoutWrapPolicy));
2027 } else {
2028 return QFormLayout::RowWrapPolicy(d->rowWrapPolicy);
2029 }
2030}
2031
2045{
2046 Q_D(QFormLayout);
2047 if (d->labelAlignment != alignment) {
2048 d->labelAlignment = alignment;
2049 invalidate();
2050 }
2051}
2052
2053Qt::Alignment QFormLayout::labelAlignment() const
2054{
2055 Q_D(const QFormLayout);
2056 if (!d->labelAlignment) {
2057 return Qt::Alignment(d->getStyle()->styleHint(QStyle::SH_FormLayoutLabelAlignment));
2058 } else {
2059 return d->labelAlignment;
2060 }
2061}
2062
2075{
2076 Q_D(QFormLayout);
2077 if (d->formAlignment != alignment) {
2078 d->formAlignment = alignment;
2079 invalidate();
2080 }
2081}
2082
2083Qt::Alignment QFormLayout::formAlignment() const
2084{
2085 Q_D(const QFormLayout);
2086 if (!d->formAlignment) {
2087 return Qt::Alignment(d->getStyle()->styleHint(QStyle::SH_FormLayoutFormAlignment));
2088 } else {
2089 return d->formAlignment;
2090 }
2091}
2092
2104{
2105 Q_D(QFormLayout);
2106 if (spacing != d->hSpacing) {
2107 d->hSpacing = spacing;
2108 invalidate();
2109 }
2110}
2111
2113{
2114 Q_D(const QFormLayout);
2115 if (d->hSpacing >= 0) {
2116 return d->hSpacing;
2117 } else {
2119 }
2120}
2121
2133{
2134 Q_D(QFormLayout);
2135 if (spacing != d->vSpacing) {
2136 d->vSpacing = spacing;
2137 invalidate();
2138 }
2139}
2140
2142{
2143 Q_D(const QFormLayout);
2144 if (d->vSpacing >= 0) {
2145 return d->vSpacing;
2146 } else {
2148 }
2149}
2150
2158{
2159 Q_D(QFormLayout);
2160 d->vSpacing = d->hSpacing = spacing;
2161 invalidate();
2162}
2163
2171{
2172 int hSpacing = horizontalSpacing();
2173 if (hSpacing == verticalSpacing()) {
2174 return hSpacing;
2175 } else {
2176 return -1;
2177 }
2178}
2179
2180void QFormLayoutPrivate::arrangeWidgets(const QList<QLayoutStruct> &layouts, QRect &rect)
2181{
2182 Q_Q(QFormLayout);
2183
2184 int i;
2185 const int rr = m_matrix.rowCount();
2186 QWidget *w = q->parentWidget();
2188
2189 Qt::Alignment formAlignment = fixedAlignment(q->formAlignment(), layoutDirection);
2190 int leftOffset = 0;
2191 int delta = rect.width() - formMaxWidth;
2192 if (formAlignment & (Qt::AlignHCenter | Qt::AlignRight) && delta > 0) {
2193 leftOffset = delta;
2195 leftOffset >>= 1;
2196 }
2197
2198 for (i = 0; i < rr; ++i) {
2200 QFormLayoutItem *field = m_matrix(i, 1);
2201
2202 if (!q->isRowVisible(i))
2203 continue;
2204
2205 if (label && label->vLayoutIndex > -1) {
2206 int height = layouts.at(label->vLayoutIndex).size;
2207 if ((label->expandingDirections() & Qt::Vertical) == 0) {
2208 /*
2209 If the field on the right-hand side is tall,
2210 we want the label to be top-aligned, but not too
2211 much. So we introduce a 7 / 4 factor so that it
2212 gets some extra pixels at the top.
2213 */
2214 height = qMin(height,
2215 qMin(label->sizeHint.height() * 7 / 4,
2216 label->maxSize.height()));
2217 }
2218
2219 QSize sz(qMin(label->layoutWidth, label->sizeHint.width()), height);
2220 int x = leftOffset + rect.x() + label->layoutPos;
2221 const auto fAlign = fixedAlignment(q->labelAlignment(), layoutDirection);
2222 if (fAlign & Qt::AlignRight)
2223 x += label->layoutWidth - sz.width();
2224 else if (fAlign & Qt::AlignHCenter)
2225 x += label->layoutWidth / 2 - sz.width() / 2;
2226 QPoint p(x, layouts.at(label->vLayoutIndex).pos);
2227 // ### expansion & sizepolicy stuff
2228
2229 label->setGeometry(QStyle::visualRect(layoutDirection, rect, QRect(p, sz)));
2230 }
2231
2232 if (field && field->vLayoutIndex > -1) {
2233 QSize sz(field->layoutWidth, layouts.at(field->vLayoutIndex).size);
2234 QPoint p(field->layoutPos + leftOffset + rect.x(), layouts.at(field->vLayoutIndex).pos);
2235/*
2236 if ((field->widget() && field->widget()->sizePolicy().horizontalPolicy() & (QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag | QSizePolicy::IgnoreFlag))
2237 || (field->layout() && sz.width() < field->maxSize.width())) {
2238 sz.rwidth() = field->layoutWidth;
2239 }
2240*/
2241 if (field->maxSize.isValid())
2242 sz = sz.boundedTo(field->maxSize);
2243
2244 field->setGeometry(QStyle::visualRect(layoutDirection, rect, QRect(p, sz)));
2245 }
2246 }
2247}
2248
2261{
2262 Q_D(QFormLayout);
2263 int rowCnt = rowCount();
2264 if (row >= rowCnt)
2265 d->insertRows(rowCnt, row - rowCnt + 1);
2266 d->setWidget(row, role, widget);
2267}
2268
2281{
2282 Q_D(QFormLayout);
2283 int rowCnt = rowCount();
2284 if (row >= rowCnt)
2285 d->insertRows(rowCnt, row - rowCnt + 1);
2286 d->setLayout(row, role, layout);
2287}
2288
2303{
2304 Q_D(QFormLayout);
2305 int rowCnt = rowCount();
2306 if (row >= rowCnt)
2307 d->insertRows(rowCnt, row - rowCnt + 1);
2308 d->setItem(row, role, item);
2309}
2310
2321{
2322 Q_D(QFormLayout);
2323 QFormLayoutItem *label = d->m_matrix(row, 0);
2324 QFormLayoutItem *field = d->m_matrix(row, 1);
2325 bool change = false;
2326 if (label) {
2327 change = label->isVisible != on;
2328 label->setVisible(on);
2329 }
2330 if (field) {
2331 change |= field->isVisible != on;
2332 field->setVisible(on);
2333 }
2334 if (change)
2335 invalidate();
2336}
2337
2349{
2350 Q_D(QFormLayout);
2351 if (Q_UNLIKELY(!d->checkWidget(widget)))
2352 return;
2353
2354 int row;
2355 ItemRole role;
2356 getWidgetPosition(widget, &row, &role);
2357
2358 if (Q_UNLIKELY(row < 0)) {
2359 qWarning("QFormLayout::setRowVisible: Invalid widget");
2360 return;
2361 }
2362
2363 setRowVisible(row, on);
2364}
2365
2377{
2378 Q_D(QFormLayout);
2379 if (Q_UNLIKELY(!d->checkLayout(layout)))
2380 return;
2381
2382 int row;
2383 ItemRole role;
2384 getLayoutPosition(layout, &row, &role);
2385
2386 if (Q_UNLIKELY(row < 0)) {
2387 qWarning("QFormLayout::setRowVisible: Invalid layout");
2388 return;
2389 }
2390
2391 setRowVisible(row, on);
2392}
2393
2401{
2402 Q_D(const QFormLayout);
2403 QFormLayoutItem *label = d->m_matrix(row, 0);
2404 QFormLayoutItem *field = d->m_matrix(row, 1);
2405
2406 int visibleItemCount = 2;
2407 if (!label || label->isHidden() || (label->widget() && label->widget()->isHidden()))
2408 --visibleItemCount;
2409 if (!field || field->isHidden() || (field->widget() && field->widget()->isHidden()))
2410 --visibleItemCount;
2411
2412 return visibleItemCount > 0;
2413}
2414
2423{
2424 Q_D(const QFormLayout);
2425 if (Q_UNLIKELY(!d->checkWidget(widget)))
2426 return false;
2427 int row;
2428 ItemRole role;
2429 getWidgetPosition(widget, &row, &role);
2430
2431 if (Q_UNLIKELY(row < 0)) {
2432 qWarning("QFormLayout::takeRow: Invalid widget");
2433 return false;
2434 }
2435
2436 return isRowVisible(row);
2437}
2438
2447{
2448 Q_D(const QFormLayout);
2449 if (Q_UNLIKELY(!d->checkLayout(layout)))
2450 return false;
2451 int row;
2452 ItemRole role;
2453 getLayoutPosition(layout, &row, &role);
2454
2455 if (Q_UNLIKELY(row < 0)) {
2456 qWarning("QFormLayout::takeRow: Invalid layout");
2457 return false;
2458 }
2459
2460 return isRowVisible(row);
2461}
2462
2467void QFormLayout::resetFieldGrowthPolicy()
2468{
2469 Q_D(QFormLayout);
2470 d->fieldGrowthPolicy = DefaultFieldGrowthPolicy;
2471}
2472
2477void QFormLayout::resetRowWrapPolicy()
2478{
2479 Q_D(QFormLayout);
2480 d->rowWrapPolicy = DefaultRowWrapPolicy;
2481}
2482
2487void QFormLayout::resetFormAlignment()
2488{
2489 Q_D(QFormLayout);
2490 d->formAlignment = { };
2491}
2492
2497void QFormLayout::resetLabelAlignment()
2498{
2499 Q_D(QFormLayout);
2500 d->labelAlignment = { };
2501}
2502
2503#if 0
2504void QFormLayout::dump() const
2505{
2506 Q_D(const QFormLayout);
2507 for (int i = 0; i < rowCount(); ++i) {
2508 for (int j = 0; j < 2; ++j) {
2509 qDebug("m_matrix(%d, %d) = %p", i, j, d->m_matrix(i, j));
2510 }
2511 }
2512 for (int i = 0; i < d->m_things.count(); ++i)
2513 qDebug("m_things[%d] = %p", i, d->m_things.at(i));
2514}
2515#endif
2516
2518
2519#include "moc_qformlayout.cpp"
static QStyle * style()
Returns the application's style object.
int count() const override
\reimp
QLayoutItem * takeAt(int) override
\reimp
QLayoutItem * itemAt(int) const override
\reimp
void insertRows(int row, int count)
QList< QLayoutStruct > vLayouts
void arrangeWidgets(const QList< QLayoutStruct > &layouts, QRect &rect)
void setupVerticalLayoutData(int width)
QStyle * getStyle() const
QLayoutItem * replaceAt(int index, QLayoutItem *) override
Qt::Alignment labelAlignment
Qt::Alignment formAlignment
void setLayout(int row, QFormLayout::ItemRole role, QLayout *layout)
int insertRow(int row)
void removeRow(int row)
void recalcHFW(int w)
void setWidget(int row, QFormLayout::ItemRole role, QWidget *widget)
bool setItem(int row, QFormLayout::ItemRole role, QLayoutItem *item)
QList< QFormLayoutItem * > m_things
void setupHorizontalLayoutData(int width)
bool haveHfwCached(int width) const
QList< QLayoutStruct > hfwLayouts
The QFormLayout class manages forms of input widgets and their associated labels.
Definition qformlayout.h:18
TakeRowResult takeRow(int row)
int heightForWidth(int width) const override
\reimp
void setWidget(int row, ItemRole role, QWidget *widget)
Sets the widget in the given row for the given role to widget, extending the layout with empty rows i...
void getItemPosition(int index, int *rowPtr, ItemRole *rolePtr) const
Retrieves the row and role (column) of the item at the specified index.
void setLayout(int row, ItemRole role, QLayout *layout)
Sets the sub-layout in the given row for the given role to layout, extending the form layout with emp...
RowWrapPolicy rowWrapPolicy
the way in which the form's rows wrap
Definition qformlayout.h:24
void setRowWrapPolicy(RowWrapPolicy policy)
RowWrapPolicy
This enum specifies the different policies that can be used to control the way in which the form's ro...
Definition qformlayout.h:40
void setItem(int row, ItemRole role, QLayoutItem *item)
Sets the item in the given row for the given role to item, extending the layout with empty rows if ne...
QLayoutItem * itemAt(int row, ItemRole role) const
Returns the layout item in the given row with the specified role (column).
void setRowVisible(int row, bool on)
void setFieldGrowthPolicy(FieldGrowthPolicy policy)
int verticalSpacing
the spacing between widgets that are laid out vertically
Definition qformlayout.h:30
void setFormAlignment(Qt::Alignment alignment)
bool isRowVisible(int row) const
~QFormLayout()
Destroys the form layout.
Qt::Alignment formAlignment
the alignment of the form layout's contents within the layout's geometry
Definition qformlayout.h:28
void setGeometry(const QRect &rect) override
\reimp
void setHorizontalSpacing(int spacing)
Qt::Orientations expandingDirections() const override
\reimp
void getWidgetPosition(QWidget *widget, int *rowPtr, ItemRole *rolePtr) const
Retrieves the row and role (column) of the specified widget in the layout.
int count() const override
\reimp
int rowCount() const
Returns the number of rows in the form.
QWidget * labelForField(QWidget *field) const
Returns the label associated with the given field.
QSize minimumSize() const override
\reimp
void setVerticalSpacing(int spacing)
QSize sizeHint() const override
\reimp
void setSpacing(int) override
This function sets both the vertical and horizontal spacing to spacing.
void addItem(QLayoutItem *item) override
\reimp
int horizontalSpacing
the spacing between widgets that are laid out side by side
Definition qformlayout.h:29
QLayoutItem * takeAt(int index) override
\reimp
int spacing() const override
If the vertical spacing is equal to the horizontal spacing, this function returns that value; otherwi...
void getLayoutPosition(QLayout *layout, int *rowPtr, ItemRole *rolePtr) const
Retrieves the row and role (column) of the specified child layout.
FieldGrowthPolicy fieldGrowthPolicy
the way in which the form's fields grow
Definition qformlayout.h:22
void invalidate() override
\reimp
QFormLayout(QWidget *parent=nullptr)
\variable QFormLayout::TakeRowResult::labelItem
bool hasHeightForWidth() const override
\reimp
void insertRow(int row, QWidget *label, QWidget *field)
Inserts a new row at position row in this form layout, with the given label and field.
void addRow(QWidget *label, QWidget *field)
Adds a new row to the bottom of this form layout, with the given label and field.
void setLabelAlignment(Qt::Alignment alignment)
void removeRow(int row)
ItemRole
This enum specifies the types of widgets (or other layout items) that may appear in a row.
Definition qformlayout.h:47
FieldGrowthPolicy
This enum specifies the different policies that can be used to control the way in which the form's fi...
Definition qformlayout.h:33
@ FieldsStayAtSizeHint
Definition qformlayout.h:34
@ ExpandingFieldsGrow
Definition qformlayout.h:35
Qt::Alignment labelAlignment
the horizontal alignment of the labels
Definition qformlayout.h:26
Qt::LayoutDirection layoutDirection
the default layout direction for this application
The QLabel widget provides a text or image display.
Definition qlabel.h:20
The QLayoutItem class provides an abstract item that a QLayout manipulates.
Definition qlayoutitem.h:25
virtual Qt::Orientations expandingDirections() const =0
Returns whether this layout item can make use of more space than sizeHint().
virtual QRect geometry() const =0
Returns the rectangle covered by this layout item.
virtual QSizePolicy::ControlTypes controlTypes() const
Returns the control type(s) for the layout item.
virtual bool hasHeightForWidth() const
Returns true if this layout's preferred height depends on its width; otherwise returns false.
virtual int heightForWidth(int) const
Returns the preferred height for this layout item, given the width, which is not used in this default...
virtual QLayout * layout()
If this item is a QLayout, it is returned as a QLayout; otherwise \nullptr is returned.
Qt::Alignment alignment() const
Returns the alignment of this item.
Definition qlayoutitem.h:45
virtual void setGeometry(const QRect &)=0
Implemented in subclasses to set this item's geometry to r.
virtual int minimumHeightForWidth(int) const
Returns the minimum height this widget needs for the given width, w.
virtual QWidget * widget() const
If this item manages a QWidget, returns that widget.
static QWidgetItem * createWidgetItem(const QLayout *layout, QWidget *widget)
Definition qlayout.cpp:148
The QLayout class is the base class of geometry managers.
Definition qlayout.h:26
QRect geometry() const override
\reimp
Definition qlayout.cpp:460
void getContentsMargins(int *left, int *top, int *right, int *bottom) const
Definition qlayout.cpp:347
void invalidate() override
\reimp
Definition qlayout.cpp:469
virtual void setGeometry(const QRect &) override
\reimp
Definition qlayout.cpp:451
QLayout * layout() override
\reimp
virtual int indexOf(const QWidget *) const
Searches for widget widget in this layout (not including child layouts).
Definition qlayout.cpp:1177
Definition qlist.h:75
qsizetype size() const noexcept
Definition qlist.h:397
bool empty() const noexcept
Definition qlist.h:685
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
T value(qsizetype i) const
Definition qlist.h:664
void resize(qsizetype size)
Definition qlist.h:403
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
QObject * parent
Definition qobject.h:73
\inmodule QtCore\reentrant
Definition qpoint.h:25
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr void adjust(int x1, int y1, int x2, int y2) noexcept
Adds dx1, dy1, dx2 and dy2 respectively to the existing coordinates of the rectangle.
Definition qrect.h:373
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:239
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:176
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:185
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:188
constexpr int verticalStretch() const noexcept
Returns the vertical stretch factor of the size policy.
Definition qsizepolicy.h:93
\inmodule QtCore
Definition qsize.h:25
constexpr QSize boundedTo(const QSize &) const noexcept
Returns a size holding the minimum width and height of this size and the given otherSize.
Definition qsize.h:197
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
constexpr int & rheight() noexcept
Returns a reference to the height.
Definition qsize.h:157
constexpr int & rwidth() noexcept
Returns a reference to the width.
Definition qsize.h:154
constexpr bool isValid() const noexcept
Returns true if both the width and height is equal to or greater than 0; otherwise returns false.
Definition qsize.h:127
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
The QStyle class is an abstract base class that encapsulates the look and feel of a GUI.
Definition qstyle.h:29
@ SH_FormLayoutWrapPolicy
Definition qstyle.h:670
@ SH_FormLayoutFieldGrowthPolicy
Definition qstyle.h:673
@ SH_FormLayoutFormAlignment
Definition qstyle.h:674
@ SH_FormLayoutLabelAlignment
Definition qstyle.h:675
static QRect visualRect(Qt::LayoutDirection direction, const QRect &boundingRect, const QRect &logicalRect)
Returns the given logicalRectangle converted to screen coordinates based on the specified direction.
Definition qstyle.cpp:2143
int combinedLayoutSpacing(QSizePolicy::ControlTypes controls1, QSizePolicy::ControlTypes controls2, Qt::Orientation orientation, QStyleOption *option=nullptr, QWidget *widget=nullptr) const
Definition qstyle.cpp:2371
@ PM_LayoutVerticalSpacing
Definition qstyle.h:517
@ PM_LayoutHorizontalSpacing
Definition qstyle.h:516
The QWidgetItem class is a layout item that represents a widget.
Definition qlayoutitem.h:86
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
Qt::LayoutDirection layoutDirection
the layout direction for this widget.
Definition qwidget.h:170
bool isHidden() const
Returns true if the widget is hidden, otherwise returns false.
Definition qwidget.h:877
QRect geometry
the geometry of the widget relative to its parent and excluding the window frame
Definition qwidget.h:106
QSizePolicy sizePolicy
the default layout behavior of the widget
Definition qwidget.h:119
virtual void setVisible(bool visible)
Definition qwidget.cpp:8255
QStyle * style() const
Definition qwidget.cpp:2600
QWidget * parentWidget() const
Returns the parent of this widget, or \nullptr if it does not have any parent widget.
Definition qwidget.h:904
const T & operator()(int r, int c) const
static void storageIndexToPosition(int idx, int *rowPtr, int *colPtr)
const Storage & storage() const
T & operator()(int r, int c)
void insertRow(int r, const T &value)
QOpenGLWidget * widget
[1]
qreal spacing
qDeleteAll(list.begin(), list.end())
QSet< QString >::iterator it
rect
[4]
uint alignment
Combined button and popup list for selecting options.
\macro QT_NO_KEYWORDS >
Definition qcompare.h:63
@ AlignRight
Definition qnamespace.h:146
@ AlignBottom
Definition qnamespace.h:154
@ AlignVCenter
Definition qnamespace.h:155
@ AlignHCenter
Definition qnamespace.h:148
@ AlignAbsolute
Definition qnamespace.h:150
@ AlignLeft
Definition qnamespace.h:144
LayoutDirection
@ RightToLeft
@ Horizontal
Definition qnamespace.h:99
@ Vertical
Definition qnamespace.h:100
#define Q_UNLIKELY(x)
#define Q_LIKELY(x)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static int storageIndexFromLayoutItem(const QFormLayoutPrivate::ItemMatrix &m, QFormLayoutItem *item)
static int spacingHelper(QWidget *parent, QStyle *style, int userVSpacing, bool recalculate, QFormLayoutItem *item1, QFormLayoutItem *item2, QFormLayoutItem *prevItem1, QFormLayoutItem *prevItem2)
static Qt::Alignment fixedAlignment(Qt::Alignment alignment, Qt::LayoutDirection layoutDirection)
const uint DefaultFieldGrowthPolicy
static void updateFormLayoutItem(QFormLayoutItem *item, int userVSpacing, QFormLayout::FieldGrowthPolicy fieldGrowthPolicy, bool fullRow)
static void hideOrShowWidgetsInLayout(QLayout *layout, bool on)
static QLayoutItem * ownershipCleanedItem(QFormLayoutItem *item, QFormLayout *layout)
static void clearAndDestroyQLayoutItem(QLayoutItem *item)
static void initLayoutStruct(QLayoutStruct &sl, QFormLayoutItem *item)
const uint DefaultRowWrapPolicy
static QGtk3Storage * m_storage
Q_WIDGETS_EXPORT int qSmartSpacing(const QLayout *layout, QStyle::PixelMetric pm)
void qGeomCalc(QList< QLayoutStruct > &chain, int start, int count, int pos, int space, int spacer)
QT_BEGIN_NAMESPACE constexpr int QLAYOUTSIZE_MAX
Definition qlayoutitem.h:16
static const double leftOffset
#define qDebug
[1]
Definition qlogging.h:164
#define qWarning
Definition qlogging.h:166
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLint GLint GLint GLint GLint x
[0]
const GLfloat * m
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLuint index
[2]
GLboolean r
[2]
GLenum GLenum GLsizei count
GLint GLsizei width
GLuint GLsizei const GLchar * label
[43]
GLfloat n
GLfloat GLfloat GLfloat GLfloat h
GLenum GLenum GLsizei void GLsizei void * column
const GLubyte * c
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLenum GLenum GLsizei void * row
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
unsigned int uint
Definition qtypes.h:34
#define QWIDGETSIZE_MAX
Definition qwidget.h:917
QObject::connect nullptr
QVBoxLayout * layout
QSharedPointer< T > other(t)
[5]
QGraphicsItem * item
QLayoutItem * child
[0]
QSizePolicy policy
Qt::Orientations expandingDirections() const
int heightForWidth(int width) const
QLayout * layout() const
bool hasHeightForWidth() const
QWidget * widget() const
void setGeometry(const QRect &r)
void setVisible(bool on)
QRect geometry() const
bool operator==(const QFormLayoutItem &other)
int vStretch() const
bool isHidden() const
QLayoutItem * item
int minimumHeightForWidth(int width) const
QFormLayoutItem(QLayoutItem *i)
QSizePolicy::ControlTypes controlTypes() const
Contains the result of a QFormLayout::takeRow() call.
Definition qformlayout.h:54