Qt 4.8
qformlayout.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qapplication.h"
43 #include "qdebug.h"
44 #include "qformlayout.h"
45 #include "qlabel.h"
46 #include "qlayout_p.h"
47 #include "qlayoutengine_p.h"
48 #include "qrect.h"
49 #include "qvector.h"
50 #include "qwidget.h"
51 
53 
54 namespace {
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 {
59 public:
60  typedef QVector<T> Storage;
61 
62  FixedColumnMatrix() { }
63 
64  void clear() { m_storage.clear(); }
65 
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]; }
68 
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);
73 
74  bool find(const T &value, int *rowPtr, int *colPtr) const ;
75  int count(const T &value) const { return m_storage.count(value); }
76 
77  // Hmmpf.. Some things are faster that way.
78  const Storage &storage() const { return m_storage; }
79 
80  static void storageIndexToPosition(int idx, int *rowPtr, int *colPtr);
81 
82 private:
83  Storage m_storage;
84 };
85 
86 template <class T, int NumColumns>
87 void FixedColumnMatrix<T, NumColumns>::addRow(const T &value)
88 {
89  for (int i = 0; i < NumColumns; ++i)
90  m_storage.append(value);
91 }
92 
93 template <class T, int NumColumns>
94 void FixedColumnMatrix<T, NumColumns>::insertRow(int r, const T &value)
95 {
96  Q_TYPENAME Storage::iterator it = m_storage.begin();
97  it += r * NumColumns;
98  m_storage.insert(it, NumColumns, value);
99 }
100 
101 template <class T, int NumColumns>
102 void FixedColumnMatrix<T, NumColumns>::removeRow(int r)
103 {
104  m_storage.remove(r * NumColumns, NumColumns);
105 }
106 
107 template <class T, int NumColumns>
108 bool FixedColumnMatrix<T, NumColumns>::find(const T &value, int *rowPtr, int *colPtr) const
109 {
110  const int idx = m_storage.indexOf(value);
111  if (idx == -1)
112  return false;
113  storageIndexToPosition(idx, rowPtr, colPtr);
114  return true;
115 }
116 
117 template <class T, int NumColumns>
118 void FixedColumnMatrix<T, NumColumns>::storageIndexToPosition(int idx, int *rowPtr, int *colPtr)
119 {
120  *rowPtr = idx / NumColumns;
121  *colPtr = idx % NumColumns;
122 }
123 } // namespace
124 
125 // special values for unset fields; must not clash with values of FieldGrowthPolicy or
126 // RowWrapPolicy
129 
130 enum { ColumnCount = 2 };
131 
132 // -- our data structure for our items
133 // This owns the QLayoutItem
135 {
136  QFormLayoutItem(QLayoutItem* i) : item(i), fullRow(false), isHfw(false) { }
137  ~QFormLayoutItem() { delete item; }
138 
139  // Wrappers
140  QWidget *widget() const { return item->widget(); }
141  QLayout *layout() const { return item->layout(); }
142 
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; }
149 
150  void setGeometry(const QRect& r) { item->setGeometry(r); }
151  QRect geometry() const { return item->geometry(); }
152 
153  // For use with FixedColumnMatrix
154  bool operator==(const QFormLayoutItem& other) { return item == other.item; }
155 
157  bool fullRow;
158 
159  // set by updateSizes
160  bool isHfw;
164 
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
168 
169  // set by setupVerticalLayoutData
172 
173  // set by setupHorizontalLayoutData
176 };
177 
179 {
181 
182 public:
183  typedef FixedColumnMatrix<QFormLayoutItem *, ColumnCount> ItemMatrix;
184 
187 
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);
193 
194  void arrangeWidgets(const QVector<QLayoutStruct>& layouts, QRect &rect);
195 
196  void updateSizes();
197 
198  void setupVerticalLayoutData(int width);
199  void setupHorizontalLayoutData(int width);
200 
201  QStyle* getStyle() const;
202 
203  inline bool haveHfwCached(int width) const
204  {
205  return (hfw_width == width) || (width == sh_width && hfw_sh_height >= 0);
206  }
207 
208  void recalcHFW(int w);
209  void setupHfwLayoutData();
210 
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;
220 
221  ItemMatrix m_matrix;
223 
224  int layoutWidth; // the last width that we called setupVerticalLayoutData on (for vLayouts)
225 
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
229 
230  int hfw_sh_height; // the hfw for sh_width
231  int hfw_sh_minheight; // the minhfw for sh_width
232 
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();
240 
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
244 
246 
247  int hSpacing;
248  int vSpacing;
249 };
250 
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)
257 {
258 }
259 
260 static Qt::Alignment fixedAlignment(Qt::Alignment alignment, Qt::LayoutDirection layoutDirection)
261 {
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));
267  } else {
268  return alignment & ~Qt::AlignAbsolute;
269  }
270 }
271 
273  QFormLayoutItem *item)
274 {
275  if (item) {
276  return m.storage().indexOf(item);
277  } else {
278  return -1;
279  }
280 }
281 
282 static void updateFormLayoutItem(QFormLayoutItem *item, int userVSpacing,
284  bool fullRow)
285 {
286  item->minSize = item->item->minimumSize();
287  item->sizeHint = item->item->sizeHint();
288  item->maxSize = item->item->maximumSize();
289 
290  if (!fullRow && (fieldGrowthPolicy == QFormLayout::FieldsStayAtSizeHint
291  || (fieldGrowthPolicy == QFormLayout::ExpandingFieldsGrow
292  && !(item->item->expandingDirections() & Qt::Horizontal))))
293  item->maxSize.setWidth(item->sizeHint.width());
294 
295  item->isHfw = item->item->hasHeightForWidth();
296  item->vSpace = userVSpacing;
297 }
298 
299 /*
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
303  widths.
304 */
306 {
307  Q_Q(QFormLayout);
308 
309  if (sizesDirty) {
310  QFormLayout::RowWrapPolicy wrapPolicy = q->rowWrapPolicy();
311  bool wrapAllRows = (wrapPolicy == QFormLayout::WrapAllRows);
312  bool dontWrapRows = (wrapPolicy == QFormLayout::DontWrapRows);
313  int rr = m_matrix.rowCount();
314 
315  has_hfw = false;
316 
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;
321 
322  QFormLayoutItem *prevLbl = 0;
323  QFormLayoutItem *prevFld = 0;
324 
325  QWidget *parent = q->parentWidget();
326  QStyle *style = parent ? parent->style() : 0;
327 
328  int userVSpacing = q->verticalSpacing();
329  int userHSpacing = wrapAllRows ? 0 : q->horizontalSpacing();
330 
331  int maxMinLblWidth = 0;
332  int maxMinFldWidth = 0; // field with label
333  int maxMinIfldWidth = 0; // independent field
334 
335  int maxShLblWidth = 0;
336  int maxShFldWidth = 0;
337  int maxShIfldWidth = 0;
338 
339  for (int i = 0; i < rr; ++i) {
340  QFormLayoutItem *label = m_matrix(i, 0);
341  QFormLayoutItem *field = m_matrix(i, 1);
342 
343  // Skip empty rows
344  if (!label && !field)
345  continue;
346 
347  if (label) {
348  updateFormLayoutItem(label, userVSpacing, q->fieldGrowthPolicy(), false);
349  if (label->isHfw)
350  has_hfw = true;
351  Qt::Orientations o = label->expandingDirections();
352 
353  if (o & Qt::Vertical)
354  expandV = true;
355  if (o & Qt::Horizontal)
356  expandH = true;
357  }
358  if (field) {
359  updateFormLayoutItem(field, userVSpacing, q->fieldGrowthPolicy(), !label && field->fullRow);
360  field->sbsHSpace = (!label && field->fullRow) ? 0 : userHSpacing;
361  if (field->isHfw)
362  has_hfw = true;
363 
364  Qt::Orientations o = field->expandingDirections();
365 
366  if (o & Qt::Vertical)
367  expandV = true;
368  if (o & Qt::Horizontal)
369  expandH = true;
370  }
371 
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);
378 
379  // VSpacing
380  if (userVSpacing < 0) {
381  if (wrapAllRows) {
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);
390  if (label && lbltop)
391  label->vSpace = style->combinedLayoutSpacing(lbltoptypes, lbltypes, Qt::Vertical, 0, parent);
392  if (field && fldtop)
393  field->vSpace = style->combinedLayoutSpacing(fldtoptypes, fldtypes, Qt::Vertical, 0, parent);
394  } else {
395  // Side by side.. we have to also consider the spacings to empty cells, which can strangely be more than
396  // non empty cells..
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);
403 
404  // To be compatible to QGridLayout, we have to compare solitary labels & fields with both predecessors
405  if (label) {
406  if (!field) {
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);
410  } else
411  label->vSpace = style->combinedLayoutSpacing(lbltoptypes, lbltypes, Qt::Vertical, 0, parent);
412  }
413 
414  if (field) {
415  // check spacing against both the previous label and field
416  if (!label) {
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);
420  } else
421  field->vSpace = style->combinedLayoutSpacing(fldtoptypes, fldtypes, Qt::Vertical, 0, parent);
422  }
423  }
424  }
425 
426  // HSpacing
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)
431  }
432 
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)
440  if (label) {
441  maxMinLblWidth = qMax(maxMinLblWidth, label->minSize.width());
442  maxShLblWidth = qMax(maxShLblWidth, label->sizeHint.width());
443  if (field) {
444  maxMinFldWidth = qMax(maxMinFldWidth, field->minSize.width() + field->sbsHSpace);
445  maxShFldWidth = qMax(maxShFldWidth, field->sizeHint.width() + field->sbsHSpace);
446  }
447  } else if (field) {
448  maxMinIfldWidth = qMax(maxMinIfldWidth, field->minSize.width());
449  maxShIfldWidth = qMax(maxShIfldWidth, field->sizeHint.width());
450  }
451 
452  prevLbl = label;
453  prevFld = field;
454  }
455 
456  // Now, finally update the min/sizeHint widths
457  if (wrapAllRows) {
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
461  thresh_width = 0;
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);
467  } else {
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;
475  }
476 
477  // Update the expansions
478  expandVertical = expandV;
479  expandHorizontal = expandH;
480  }
481  sizesDirty = false;
482 }
483 
485 {
487 
488  int h = 0;
489  int mh = 0;
490 
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;
495  }
496 
497  if (sh_width > 0 && sh_width == w) {
500  } else {
501  hfw_width = w;
504  }
505 }
506 
508 {
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
513 
514 
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.
521  int i;
522  int rr = m_matrix.rowCount();
523 
524  hfwLayouts.clear();
526  for (i = 0; i < vLayoutCount; ++i)
527  hfwLayouts[i] = vLayouts.at(i);
528 
529  for (i = 0; i < rr; ++i) {
530  QFormLayoutItem *label = m_matrix(i, 0);
531  QFormLayoutItem *field = m_matrix(i, 1);
532 
533  if (label) {
534  if (label->isHfw) {
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;
540  } else {
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();
545  }
546  }
547 
548  if (field) {
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();
552 
553  if (field->sideBySide) {
554  int oh = hfwLayouts.at(field->vLayoutIndex).sizeHint;
555  int omh = hfwLayouts.at(field->vLayoutIndex).minimumSize;
556 
557  hfwLayouts[field->vLayoutIndex].sizeHint = qMax(h, oh);
558  hfwLayouts[field->vLayoutIndex].minimumSize = qMax(mh, omh);
559  } else {
560  hfwLayouts[field->vLayoutIndex].sizeHint = h;
561  hfwLayouts[field->vLayoutIndex].minimumSize = mh;
562  }
563  }
564  }
565 }
566 
567 /*
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.
572 
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).
577 
578  In particular:
579 
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]
584 
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]
589 
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]
593 
594  In the (common) non split case, we can just use the precalculated vspace (possibly qMaxed between
595  label and field).
596 
597  If recalculate is true, we expect:
598  - parent != null
599  - item1 != null
600  - item2 can be null
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
604 */
605 static inline int spacingHelper(QWidget* parent, QStyle *style, int userVSpacing, bool recalculate, QFormLayoutItem* item1, QFormLayoutItem* item2, QFormLayoutItem* prevItem1, QFormLayoutItem *prevItem2)
606 {
607  int spacing = userVSpacing;
608  if (spacing < 0) {
609  if (!recalculate) {
610  if (item1)
611  spacing = item1->vSpace;
612  if (item2)
613  spacing = qMax(spacing, item2->vSpace);
614  } else {
615  if (style && prevItem1) {
616  QSizePolicy::ControlTypes itemtypes =
617  QSizePolicy::ControlTypes(item1 ? item1->controlTypes() : QSizePolicy::DefaultType);
618  int spacing2 = 0;
619 
620  spacing = style->combinedLayoutSpacing(itemtypes, prevItem1->controlTypes(), Qt::Vertical, 0, parent);
621 
622  // At most of one of item2 and prevItem2 will be nonnull
623  if (item2)
624  spacing2 = style->combinedLayoutSpacing(item2->controlTypes(), prevItem1->controlTypes(), Qt::Vertical, 0, parent);
625  else if (prevItem2)
626  spacing2 = style->combinedLayoutSpacing(itemtypes, prevItem2->controlTypes(), Qt::Vertical, 0, parent);
627 
628  spacing = qMax(spacing, spacing2);
629  }
630  }
631  } else {
632  if (prevItem1) {
633  QWidget *wid = prevItem1->item->widget();
634  if (wid)
635  spacing = qMax(spacing, prevItem1->geometry().top() - wid->geometry().top() );
636  }
637  if (prevItem2) {
638  QWidget *wid = prevItem2->item->widget();
639  if (wid)
640  spacing = qMax(spacing, prevItem2->geometry().top() - wid->geometry().top() );
641  }
642  }
643  return spacing;
644 }
645 
646 static inline void initLayoutStruct(QLayoutStruct& sl, QFormLayoutItem* item)
647 {
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);
652  sl.empty = false;
653 }
654 
656 {
657  Q_Q(QFormLayout);
658 
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)
661  return;
662 
663  layoutWidth = width;
664 
665  int rr = m_matrix.rowCount();
666  int vidx = 1;
667  QFormLayout::RowWrapPolicy rowWrapPolicy = q->rowWrapPolicy();
668  bool wrapAllRows = (rowWrapPolicy == QFormLayout::WrapAllRows);
669  bool addTopBottomStretch = true;
670 
671  vLayouts.clear();
672  vLayouts.resize((2 * rr) + 2); // a max, some may be unused
673 
674  QStyle *style = 0;
675 
676  int userVSpacing = q->verticalSpacing();
677 
678  if (userVSpacing < 0) {
679  if (QWidget *widget = q->parentWidget())
680  style = widget->style();
681  }
682 
683  // make sure our sizes are up to date
684  updateSizes();
685 
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
689  // are split.
690  maxLabelWidth = 0;
691  if (!wrapAllRows) {
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))
697  }
698  } else {
699  maxLabelWidth = width;
700  }
701 
702  QFormLayoutItem *prevItem1 = 0;
703  QFormLayoutItem *prevItem2 = 0;
704  bool prevRowSplit = false;
705 
706  for (int i = 0; i < rr; ++i) {
707  QFormLayoutItem *label = m_matrix(i, 0);
708  QFormLayoutItem *field = m_matrix(i, 1);
709 
710  // Totally ignore empty rows...
711  if (!label && !field)
712  continue;
713 
714  QSize min1;
715  QSize min2;
716  QSize sh1;
717  QSize sh2;
718  if (label) {
719  min1 = label->minSize;
720  sh1 = label->sizeHint;
721  }
722  if (field) {
723  min2 = field->minSize;
724  sh2 = field->sizeHint;
725  }
726 
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())));
731 
732  if (wrapAllRows || splitSideBySide) {
733  if (label) {
734  initLayoutStruct(vLayouts[vidx], label);
735 
736  if (vidx > 1)
737  vLayouts[vidx - 1].spacing = spacingHelper(q->parentWidget(), style, userVSpacing, splitSideBySide || prevRowSplit, label, 0, prevItem1, prevItem2);
738 
739  label->vLayoutIndex = vidx;
740  label->sideBySide = false;
741 
742  prevItem1 = label;
743  prevItem2 = 0;
744 
745  if (vLayouts[vidx].stretch > 0)
746  addTopBottomStretch = false;
747 
748  ++vidx;
749  }
750 
751  if (field) {
752  initLayoutStruct(vLayouts[vidx], field);
753 
754  if (vidx > 1)
755  vLayouts[vidx - 1].spacing = spacingHelper(q->parentWidget(), style, userVSpacing, splitSideBySide || prevRowSplit, field, 0, prevItem1, prevItem2);
756 
757  field->vLayoutIndex = vidx;
758  field->sideBySide = false;
759 
760  prevItem1 = field;
761  prevItem2 = 0;
762 
763  if (vLayouts[vidx].stretch > 0)
764  addTopBottomStretch = false;
765 
766  ++vidx;
767  }
768 
769  prevRowSplit = splitSideBySide;
770  } else {
771  // we're in side by side mode, and we have enough space to do that
774 
775  int stretch1 = 0;
776  int stretch2 = 0;
777  bool expanding = false;
778 
779  if (label) {
780  max1 = label->maxSize;
781  if (label->expandingDirections() & Qt::Vertical)
782  expanding = true;
783 
784  label->sideBySide = (field != 0);
785  label->vLayoutIndex = vidx;
786  stretch1 = label->vStretch();
787  }
788 
789  if (field) {
790  max2 = field->maxSize;
791  if (field->expandingDirections() & Qt::Vertical)
792  expanding = true;
793 
794  field->sideBySide = (label || !field->fullRow);
795  field->vLayoutIndex = vidx;
796  stretch2 = field->vStretch();
797  }
798 
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;
804 
805  if (vLayouts[vidx].stretch > 0)
806  addTopBottomStretch = false;
807 
808  if (vidx > 1)
809  vLayouts[vidx - 1].spacing = spacingHelper(q->parentWidget(), style, userVSpacing, prevRowSplit, label, field, prevItem1, prevItem2);
810 
811  if (label) {
812  prevItem1 = label;
813  prevItem2 = field;
814  } else {
815  prevItem1 = field;
816  prevItem2 = 0;
817  }
818 
819  prevRowSplit = false;
820  ++vidx;
821  }
822  }
823 
824  if (addTopBottomStretch) {
825  Qt::Alignment formAlignment = q->formAlignment();
826 
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;
831  ++vidx;
832  }
833 
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;
838  } else {
839  vLayouts[0].init(0, 0);
840  }
841  } else {
842  vLayouts[0].init(0, 0);
843  }
844 
845  vLayoutCount = vidx;
846  dirty = false;
847 }
848 
850 {
851  Q_Q(QFormLayout);
852 
853  // requires setupVerticalLayoutData to be called first
854 
855  int fieldMaxWidth = 0;
856 
857  int rr = m_matrix.rowCount();
858  bool wrapAllRows = (q->rowWrapPolicy() == QFormLayout::WrapAllRows);
859 
860  for (int i = 0; i < rr; ++i) {
861  QFormLayoutItem *label = m_matrix(i, 0);
862  QFormLayoutItem *field = m_matrix(i, 1);
863 
864  // Totally ignore empty rows...
865  if (!label && !field)
866  continue;
867 
868  if (label) {
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;
873  }
874 
875  if (field) {
876  // This is the default amount allotted to fields in sbs
877  int fldwidth = width - maxLabelWidth - field->sbsHSpace;
878 
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;
886  } else {
887  field->layoutWidth = fldwidth;
888  field->layoutPos = width - fldwidth;
889  }
890  } else {
891  // We're sbs, so we should have a label
892  field->layoutWidth = fldwidth;
893  field->layoutPos = width - fldwidth;
894  }
895 
896  fieldMaxWidth = qMax(fieldMaxWidth, field->maxSize.width());
897  }
898  }
899 
900  formMaxWidth = maxLabelWidth + fieldMaxWidth;
901 }
902 
904 {
905  Q_Q(QFormLayout);
906 
907  int leftMargin, topMargin, rightMargin, bottomMargin;
908  q->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
909 
910  updateSizes();
912  // Don't need to call setupHorizontal here
913 
914  int h = topMargin + bottomMargin;
915  int mh = topMargin + bottomMargin;
916 
917  // The following are set in updateSizes
918  int w = sh_width + leftMargin + rightMargin;
919  int mw = min_width + leftMargin + rightMargin;
920 
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;
925  }
926 
931 }
932 
934 {
935  int rowCnt = m_matrix.rowCount();
936  if (uint(row) > uint(rowCnt))
937  row = rowCnt;
938 
939  insertRows(row, 1);
940  return row;
941 }
942 
943 void QFormLayoutPrivate::insertRows(int row, int count)
944 {
945  while (count > 0) {
946  m_matrix.insertRow(row, 0);
947  --count;
948  }
949 }
950 
952 {
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);
957  return;
958  }
959 
960  if (!item)
961  return;
962 
963  if (m_matrix(row, column)) {
964  qWarning("QFormLayoutPrivate::setItem: Cell (%d, %d) already occupied", row, column);
965  return;
966  }
967 
968  QFormLayoutItem *i = new QFormLayoutItem(item);
969  i->fullRow = fullRow;
970  m_matrix(row, column) = i;
971 
972  m_things.append(i);
973 }
974 
976 {
977  if (layout) {
978  Q_Q(QFormLayout);
979  if (q->adoptLayout(layout))
980  setItem(row, role, layout);
981  }
982 }
983 
985 {
986  if (widget) {
987  Q_Q(QFormLayout);
988  q->addChildWidget(widget);
989  setItem(row, role, QLayoutPrivate::createWidgetItem(q, widget));
990  }
991 }
992 
994 {
995  Q_Q(const QFormLayout);
996 
997  // ### cache
998  if (QWidget *parentWidget = q->parentWidget())
999  return parentWidget->style();
1000  else
1001  return QApplication::style();
1002 }
1003 
1174  : QLayout(*new QFormLayoutPrivate, 0, parent)
1175 {
1176 }
1177 
1182 {
1183  Q_D(QFormLayout);
1184 
1185  /*
1186  The clearing and destruction order here is important. We start by clearing
1187  m_things so that QLayout and the rest of the world know that we don't babysit
1188  the layout items anymore and don't care if they are destroyed.
1189  */
1190  d->m_things.clear();
1191  qDeleteAll(d->m_matrix.storage());
1192  d->m_matrix.clear();
1193 }
1194 
1202 {
1203  insertRow(-1, label, field);
1204 }
1205 
1210 {
1211  insertRow(-1, label, field);
1212 }
1213 
1224 void QFormLayout::addRow(const QString &labelText, QWidget *field)
1225 {
1226  insertRow(-1, labelText, field);
1227 }
1228 
1238 void QFormLayout::addRow(const QString &labelText, QLayout *field)
1239 {
1240  insertRow(-1, labelText, field);
1241 }
1242 
1253 {
1254  insertRow(-1, widget);
1255 }
1256 
1267 {
1268  insertRow(-1, layout);
1269 }
1270 
1278 void QFormLayout::insertRow(int row, QWidget *label, QWidget *field)
1279 {
1280  Q_D(QFormLayout);
1281 
1282  row = d->insertRow(row);
1283  if (label)
1284  d->setWidget(row, LabelRole, label);
1285  if (field)
1286  d->setWidget(row, FieldRole, field);
1287  invalidate();
1288 }
1289 
1293 void QFormLayout::insertRow(int row, QWidget *label, QLayout *field)
1294 {
1295  Q_D(QFormLayout);
1296 
1297  row = d->insertRow(row);
1298  if (label)
1299  d->setWidget(row, LabelRole, label);
1300  if (field)
1301  d->setLayout(row, FieldRole, field);
1302  invalidate();
1303 }
1304 
1315 void QFormLayout::insertRow(int row, const QString &labelText, QWidget *field)
1316 {
1317  QLabel *label = 0;
1318  if (!labelText.isEmpty()) {
1319  label = new QLabel(labelText);
1320 #ifndef QT_NO_SHORTCUT
1321  label->setBuddy(field);
1322 #endif
1323  }
1324  insertRow(row, label, field);
1325 }
1326 
1336 void QFormLayout::insertRow(int row, const QString &labelText, QLayout *field)
1337 {
1338  insertRow(row, labelText.isEmpty() ? 0 : new QLabel(labelText), field);
1339 }
1340 
1352 {
1353  Q_D(QFormLayout);
1354 
1355  if (!widget) {
1356  qWarning("QFormLayout: Cannot add null field to %s", qPrintable(objectName()));
1357  return;
1358  }
1359 
1360  row = d->insertRow(row);
1361  d->setWidget(row, SpanningRole, widget);
1362  invalidate();
1363 }
1364 
1376 {
1377  Q_D(QFormLayout);
1378 
1379  if (!layout) {
1380  qWarning("QFormLayout: Cannot add null field to %s", qPrintable(objectName()));
1381  return;
1382  }
1383 
1384  row = d->insertRow(row);
1385  d->setLayout(row, SpanningRole, layout);
1386  invalidate();
1387 }
1388 
1393 {
1394  Q_D(QFormLayout);
1395 
1396  int row = d->insertRow(d->m_matrix.rowCount());
1397  d->setItem(row, FieldRole, item);
1398  invalidate();
1399 }
1400 
1405 {
1406  Q_D(const QFormLayout);
1407  return d->m_things.count();
1408 }
1409 
1414 {
1415  Q_D(const QFormLayout);
1416  if (QFormLayoutItem *formItem = d->m_things.value(index))
1417  return formItem->item;
1418  return 0;
1419 }
1420 
1425 {
1426  Q_D(QFormLayout);
1427 
1428  const int storageIndex = storageIndexFromLayoutItem(d->m_matrix, d->m_things.value(index));
1429  if (storageIndex == -1) {
1430  qWarning("QFormLayout::takeAt: Invalid index %d", index);
1431  return 0;
1432  }
1433 
1434  int row, col;
1435  QFormLayoutPrivate::ItemMatrix::storageIndexToPosition(storageIndex, &row, &col);
1436  Q_ASSERT(d->m_matrix(row, col));
1437 
1438  QFormLayoutItem *item = d->m_matrix(row, col);
1439  Q_ASSERT(item);
1440  d->m_things.removeAt(index);
1441  d->m_matrix(row, col) = 0;
1442 
1443  invalidate();
1444 
1445  // grab ownership back from the QFormLayoutItem
1446  QLayoutItem *i = item->item;
1447  item->item = 0;
1448  delete item;
1449 
1450  if (QLayout *l = i->layout()) {
1451  // sanity check in case the user passed something weird to QObject::setParent()
1452  if (l->parent() == this)
1453  l->setParent(0);
1454  }
1455 
1456  return i;
1457 }
1458 
1462 Qt::Orientations QFormLayout::expandingDirections() const
1463 {
1464  Q_D(const QFormLayout);
1465  QFormLayoutPrivate *e = const_cast<QFormLayoutPrivate *>(d);
1466  e->updateSizes();
1467 
1468  Qt::Orientations o = 0;
1469  if (e->expandHorizontal)
1470  o = Qt::Horizontal;
1471  if (e->expandVertical)
1472  o |= Qt::Vertical;
1473  return o;
1474 }
1475 
1480 {
1481  Q_D(const QFormLayout);
1482  QFormLayoutPrivate *e = const_cast<QFormLayoutPrivate *>(d);
1483  e->updateSizes();
1484  return (d->has_hfw || rowWrapPolicy() == WrapLongRows);
1485 }
1486 
1490 int QFormLayout::heightForWidth(int width) const
1491 {
1492  Q_D(const QFormLayout);
1493  if (!hasHeightForWidth())
1494  return -1;
1495 
1496  int leftMargin, topMargin, rightMargin, bottomMargin;
1497  getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
1498 
1499  int targetWidth = width - leftMargin - rightMargin;
1500 
1501  if (!d->haveHfwCached(targetWidth)) {
1502  QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
1503  dat->setupVerticalLayoutData(targetWidth);
1504  dat->setupHorizontalLayoutData(targetWidth);
1505  dat->recalcHFW(targetWidth);
1506  }
1507  if (targetWidth == d->sh_width)
1508  return d->hfw_sh_height + topMargin + bottomMargin;
1509  else
1510  return d->hfw_height + topMargin + bottomMargin;
1511 }
1512 
1517 {
1518  Q_D(QFormLayout);
1519  if (d->dirty || rect != geometry()) {
1520  QRect cr = rect;
1521  int leftMargin, topMargin, rightMargin, bottomMargin;
1522  getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
1523  cr.adjust(+leftMargin, +topMargin, -rightMargin, -bottomMargin);
1524 
1525  bool hfw = hasHeightForWidth();
1526  d->setupVerticalLayoutData(cr.width());
1527  d->setupHorizontalLayoutData(cr.width());
1528  if (hfw && (!d->haveHfwCached(cr.width()) || d->hfwLayouts.size() != d->vLayoutCount))
1529  d->recalcHFW(cr.width());
1530  if (hfw) {
1531  qGeomCalc(d->hfwLayouts, 0, d->vLayoutCount, cr.y(), cr.height());
1532  d->arrangeWidgets(d->hfwLayouts, cr);
1533  } else {
1534  qGeomCalc(d->vLayouts, 0, d->vLayoutCount, cr.y(), cr.height());
1535  d->arrangeWidgets(d->vLayouts, cr);
1536  }
1537  QLayout::setGeometry(rect);
1538  }
1539 }
1540 
1545 {
1546  Q_D(const QFormLayout);
1547  if (!d->prefSize.isValid()) {
1548  QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
1549  dat->calcSizeHints();
1550  }
1551  return d->prefSize;
1552 }
1553 
1558 {
1559  // ### fix minimumSize if hfw
1560  Q_D(const QFormLayout);
1561  if (!d->minSize.isValid()) {
1562  QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
1563  dat->calcSizeHints();
1564  }
1565  return d->minSize;
1566 }
1567 
1572 {
1573  Q_D(QFormLayout);
1574  d->dirty = true;
1575  d->sizesDirty = true;
1576  d->minSize = QSize();
1577  d->prefSize = QSize();
1578  d->formMaxWidth = -1;
1579  d->hfw_width = -1;
1580  d->sh_width = -1;
1581  d->layoutWidth = -1;
1582  d->hfw_sh_height = -1;
1584 }
1585 
1592 {
1593  Q_D(const QFormLayout);
1594  return d->m_matrix.rowCount();
1595 }
1596 
1604 {
1605  Q_D(const QFormLayout);
1606  if (uint(row) >= uint(d->m_matrix.rowCount()))
1607  return 0;
1608  switch (role) {
1609  case SpanningRole:
1610  if (QFormLayoutItem *item = d->m_matrix(row, 1))
1611  if (item->fullRow)
1612  return item->item;
1613  break;
1614  case LabelRole:
1615  case FieldRole:
1616  if (QFormLayoutItem *item = d->m_matrix(row, (role == LabelRole) ? 0 : 1))
1617  return item->item;
1618  break;
1619  }
1620  return 0;
1621 }
1622 
1631 void QFormLayout::getItemPosition(int index, int *rowPtr, ItemRole *rolePtr) const
1632 {
1633  Q_D(const QFormLayout);
1634  int col = -1;
1635  int row = -1;
1636 
1637  const int storageIndex = storageIndexFromLayoutItem(d->m_matrix, d->m_things.value(index));
1638  if (storageIndex != -1)
1639  QFormLayoutPrivate::ItemMatrix::storageIndexToPosition(storageIndex, &row, &col);
1640 
1641  if (rowPtr)
1642  *rowPtr = row;
1643  if (rolePtr && col != -1) {
1644  const bool spanning = col == 1 && d->m_matrix(row, col)->fullRow;
1645  if (spanning) {
1646  *rolePtr = SpanningRole;
1647  } else {
1648  *rolePtr = ItemRole(col);
1649  }
1650  }
1651 }
1652 
1659 void QFormLayout::getLayoutPosition(QLayout *layout, int *rowPtr, ItemRole *rolePtr) const
1660 {
1661  int n = count();
1662  int index = 0;
1663  while (index < n) {
1664  if (itemAt(index) == layout)
1665  break;
1666  ++index;
1667  }
1668  getItemPosition(index, rowPtr, rolePtr);
1669 }
1670 
1679 void QFormLayout::getWidgetPosition(QWidget *widget, int *rowPtr, ItemRole *rolePtr) const
1680 {
1681  getItemPosition(indexOf(widget), rowPtr, rolePtr);
1682 }
1683 
1684 // ### eliminate labelForField()
1685 
1692 {
1693  Q_D(const QFormLayout);
1694 
1695  int row;
1696  ItemRole role;
1697 
1698  getWidgetPosition(field, &row, &role);
1699 
1700  if (row != -1 && role == FieldRole) {
1701  if (QFormLayoutItem *label = d->m_matrix(row, LabelRole))
1702  return label->widget();
1703  }
1704  return 0;
1705 }
1706 
1711 {
1712  Q_D(const QFormLayout);
1713 
1714  int row;
1715  ItemRole role;
1716 
1717  getLayoutPosition(field, &row, &role);
1718 
1719  if (row != -1 && role == FieldRole) {
1720  if (QFormLayoutItem *label = d->m_matrix(row, LabelRole))
1721  return label->widget();
1722  }
1723  return 0;
1724 }
1725 
1747 {
1748  Q_D(QFormLayout);
1749  if (FieldGrowthPolicy(d->fieldGrowthPolicy) != policy) {
1750  d->fieldGrowthPolicy = policy;
1751  invalidate();
1752  }
1753 }
1754 
1756 {
1757  Q_D(const QFormLayout);
1758  if (d->fieldGrowthPolicy == DefaultFieldGrowthPolicy) {
1760  } else {
1761  return QFormLayout::FieldGrowthPolicy(d->fieldGrowthPolicy);
1762  }
1763 }
1764 
1783 {
1784  Q_D(QFormLayout);
1785  if (RowWrapPolicy(d->rowWrapPolicy) != policy) {
1786  d->rowWrapPolicy = policy;
1787  invalidate();
1788  }
1789 }
1790 
1792 {
1793  Q_D(const QFormLayout);
1794  if (d->rowWrapPolicy == DefaultRowWrapPolicy) {
1795  return QFormLayout::RowWrapPolicy(d->getStyle()->styleHint(QStyle::SH_FormLayoutWrapPolicy));
1796  } else {
1797  return QFormLayout::RowWrapPolicy(d->rowWrapPolicy);
1798  }
1799 }
1800 
1817 {
1818  Q_D(QFormLayout);
1819  if (d->labelAlignment != alignment) {
1820  d->labelAlignment = alignment;
1821  invalidate();
1822  }
1823 }
1824 
1825 Qt::Alignment QFormLayout::labelAlignment() const
1826 {
1827  Q_D(const QFormLayout);
1828  if (!d->labelAlignment) {
1829  return Qt::Alignment(d->getStyle()->styleHint(QStyle::SH_FormLayoutLabelAlignment));
1830  } else {
1831  return d->labelAlignment;
1832  }
1833 }
1834 
1850 {
1851  Q_D(QFormLayout);
1852  if (d->formAlignment != alignment) {
1853  d->formAlignment = alignment;
1854  invalidate();
1855  }
1856 }
1857 
1858 Qt::Alignment QFormLayout::formAlignment() const
1859 {
1860  Q_D(const QFormLayout);
1861  if (!d->formAlignment) {
1862  return Qt::Alignment(d->getStyle()->styleHint(QStyle::SH_FormLayoutFormAlignment));
1863  } else {
1864  return d->formAlignment;
1865  }
1866 }
1867 
1882 {
1883  Q_D(QFormLayout);
1884  if (spacing != d->hSpacing) {
1885  d->hSpacing = spacing;
1886  invalidate();
1887  }
1888 }
1889 
1891 {
1892  Q_D(const QFormLayout);
1893  if (d->hSpacing >= 0) {
1894  return d->hSpacing;
1895  } else {
1897  }
1898 }
1899 
1914 {
1915  Q_D(QFormLayout);
1916  if (spacing != d->vSpacing) {
1917  d->vSpacing = spacing;
1918  invalidate();
1919  }
1920 }
1921 
1922 int QFormLayout::verticalSpacing() const
1923 {
1924  Q_D(const QFormLayout);
1925  if (d->vSpacing >= 0) {
1926  return d->vSpacing;
1927  } else {
1929  }
1930 }
1931 
1939 {
1940  Q_D(QFormLayout);
1941  d->vSpacing = d->hSpacing = spacing;
1942  invalidate();
1943 }
1944 
1952 {
1953  int hSpacing = horizontalSpacing();
1954  if (hSpacing == verticalSpacing()) {
1955  return hSpacing;
1956  } else {
1957  return -1;
1958  }
1959 }
1960 
1962 {
1963  Q_Q(QFormLayout);
1964 
1965  int i;
1966  const int rr = m_matrix.rowCount();
1967  QWidget *w = q->parentWidget();
1968  Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : QApplication::layoutDirection();
1969 
1970  Qt::Alignment formAlignment = fixedAlignment(q->formAlignment(), layoutDirection);
1971  int leftOffset = 0;
1972  int delta = rect.width() - formMaxWidth;
1973  if (formAlignment & (Qt::AlignHCenter | Qt::AlignRight) && delta > 0) {
1974  leftOffset = delta;
1975  if (formAlignment & Qt::AlignHCenter)
1976  leftOffset >>= 1;
1977  }
1978 
1979  for (i = 0; i < rr; ++i) {
1980  QFormLayoutItem *label = m_matrix(i, 0);
1981  QFormLayoutItem *field = m_matrix(i, 1);
1982 
1983  if (label) {
1984  int height = layouts.at(label->vLayoutIndex).size;
1985  if ((label->expandingDirections() & Qt::Vertical) == 0) {
1986  /*
1987  If the field on the right-hand side is tall,
1988  we want the label to be top-aligned, but not too
1989  much. So we introduce a 7 / 4 factor so that it
1990  gets some extra pixels at the top.
1991  */
1992  height = qMin(height,
1993  qMin(label->sizeHint.height() * 7 / 4,
1994  label->maxSize.height()));
1995  }
1996 
1997  QSize sz(qMin(label->layoutWidth, label->sizeHint.width()), height);
1998  int x = leftOffset + rect.x() + label->layoutPos;
1999  if (fixedAlignment(q->labelAlignment(), layoutDirection) & Qt::AlignRight)
2000  x += label->layoutWidth - sz.width();
2001  QPoint p(x, layouts.at(label->vLayoutIndex).pos);
2002  // ### expansion & sizepolicy stuff
2003 
2004  label->setGeometry(QStyle::visualRect(layoutDirection, rect, QRect(p, sz)));
2005  }
2006 
2007  if (field) {
2008  QSize sz(field->layoutWidth, layouts.at(field->vLayoutIndex).size);
2009  QPoint p(field->layoutPos + leftOffset + rect.x(), layouts.at(field->vLayoutIndex).pos);
2010 /*
2011  if ((field->widget() && field->widget()->sizePolicy().horizontalPolicy() & (QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag | QSizePolicy::IgnoreFlag))
2012  || (field->layout() && sz.width() < field->maxSize.width())) {
2013  sz.rwidth() = field->layoutWidth;
2014  }
2015 */
2016  if (field->maxSize.isValid())
2017  sz = sz.boundedTo(field->maxSize);
2018 
2019  field->setGeometry(QStyle::visualRect(layoutDirection, rect, QRect(p, sz)));
2020  }
2021  }
2022 }
2023 
2036 {
2037  Q_D(QFormLayout);
2038  int rowCnt = rowCount();
2039  if (row >= rowCnt)
2040  d->insertRows(rowCnt, row - rowCnt + 1);
2041  d->setWidget(row, role, widget);
2042 }
2043 
2056 {
2057  Q_D(QFormLayout);
2058  int rowCnt = rowCount();
2059  if (row >= rowCnt)
2060  d->insertRows(rowCnt, row - rowCnt + 1);
2061  d->setLayout(row, role, layout);
2062 }
2063 
2077 void QFormLayout::setItem(int row, ItemRole role, QLayoutItem *item)
2078 {
2079  Q_D(QFormLayout);
2080  int rowCnt = rowCount();
2081  if (row >= rowCnt)
2082  d->insertRows(rowCnt, row - rowCnt + 1);
2083  d->setItem(row, role, item);
2084 }
2085 
2091 {
2092  Q_D(QFormLayout);
2093  d->fieldGrowthPolicy = DefaultFieldGrowthPolicy;
2094 }
2095 
2101 {
2102  Q_D(QFormLayout);
2103  d->rowWrapPolicy = DefaultRowWrapPolicy;
2104 }
2105 
2111 {
2112  Q_D(QFormLayout);
2113  d->formAlignment = 0;
2114 }
2115 
2121 {
2122  Q_D(QFormLayout);
2123  d->labelAlignment = 0;
2124 }
2125 
2126 #if 0
2127 void QFormLayout::dump() const
2128 {
2129  Q_D(const QFormLayout);
2130  for (int i = 0; i < rowCount(); ++i) {
2131  for (int j = 0; j < 2; ++j) {
2132  qDebug("m_matrix(%d, %d) = %p", i, j, d->m_matrix(i, j));
2133  }
2134  }
2135  for (int i = 0; i < d->m_things.count(); ++i)
2136  qDebug("m_things[%d] = %p", i, d->m_things.at(i));
2137 }
2138 #endif
2139 
bool hasHeightForWidth() const
Reimplemented Function
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...
const uint DefaultFieldGrowthPolicy
double d
Definition: qnumeric_p.h:62
static Qt::LayoutDirection layoutDirection()
void resetFormAlignment()
QWidget * parentWidget() const
Returns the parent of this widget, or 0 if it does not have any parent widget.
Definition: qwidget.h:1035
Qt::Orientations expandingDirections() const
Reimplemented Function
QStyle * getStyle() const
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 resetRowWrapPolicy()
unsigned char c[8]
Definition: qnumeric_p.h:62
QVector< QLayoutStruct > hfwLayouts
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
bool haveHfwCached(int width) const
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
int minimumHeightForWidth(int width) const
QPointer< QWidget > widget
QLayoutItem * itemAt(int row, ItemRole role) const
Returns the layout item in the given row with the specified role (column).
bool operator==(const QFormLayoutItem &other)
const uint DefaultRowWrapPolicy
void insertRows(int row, int count)
Qt::Alignment formAlignment
void invalidate()
Reimplemented Function
FieldGrowthPolicy
This enum specifies the different policies that can be used to control the way in which the form&#39;s fi...
Definition: qformlayout.h:68
#define it(className, varName)
void setLayout(int row, QFormLayout::ItemRole role, QLayout *layout)
int heightForWidth(int width) const
Reimplemented Function
void init(int stretchFactor=0, int minSize=0)
int verticalSpacing() const
QSizePolicy::ControlTypes controlTypes() const
void setVerticalSpacing(int spacing)
#define QWIDGETSIZE_MAX
Defines the maximum size for a QWidget object.
Definition: qwidget.h:1087
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:150
static void clear(QVariant::Private *d)
Definition: qvariant.cpp:197
Qt::Alignment labelAlignment() const
virtual Qt::Orientations expandingDirections() const =0
Returns whether this layout item can make use of more space than sizeHint().
int width() const
Returns the width of the rectangle.
Definition: qrect.h:303
int horizontalSpacing() const
void setRowWrapPolicy(RowWrapPolicy policy)
virtual void setGeometry(const QRect &)
Reimplemented Function
Definition: qlayout.cpp:655
ItemRole
This enum specifies the types of widgets (or other layout items) that may appear in a row...
Definition: qformlayout.h:80
static QStyle * style()
Returns the application&#39;s style object.
QSize sizeHint() const
Reimplemented Function
int rowCount() const
Returns the number of rows in the form.
void invalidate()
Reimplemented Function
Definition: qlayout.cpp:673
int height() const
Returns the height of the rectangle.
Definition: qrect.h:306
virtual QSize minimumSize() const =0
Implemented in subclasses to return the minimum size of this item.
The QString class provides a Unicode character string.
Definition: qstring.h:83
bool hasHeightForWidth() const
virtual bool hasHeightForWidth() const
Returns true if this layout&#39;s preferred height depends on its width; otherwise returns false...
void setupVerticalLayoutData(int width)
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QVector class is a template class that provides a dynamic array.
Definition: qdatastream.h:64
void resetFieldGrowthPolicy()
bool empty() const
This function is provided for STL compatibility.
Definition: qvector.h:285
#define Q_D(Class)
Definition: qglobal.h:2482
int insertRow(int row)
QRect geometry() const
static void initLayoutStruct(QLayoutStruct &sl, QFormLayoutItem *item)
void setHorizontalSpacing(int spacing)
void setWidget(int row, QFormLayout::ItemRole role, QWidget *widget)
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
void resize(int size)
Sets the size of the vector to size.
Definition: qvector.h:342
void setParent(QObject *)
Makes the object a child of parent.
Definition: qobject.cpp:1950
QStyle * style() const
Definition: qwidget.cpp:2742
#define Q_Q(Class)
Definition: qglobal.h:2483
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 setFormAlignment(Qt::Alignment alignment)
void setWidth(int w)
Sets the width to the given width.
Definition: qsize.h:132
Q_CORE_EXPORT void qDebug(const char *,...)
int width() const
Returns the width.
Definition: qsize.h:126
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
void arrangeWidgets(const QVector< QLayoutStruct > &layouts, QRect &rect)
~QFormLayout()
Destroys the form layout.
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
The QLayoutItem class provides an abstract item that a QLayout manipulates.
Definition: qlayoutitem.h:64
int spacing() const
If the vertical spacing is equal to the horizontal spacing, this function returns that value; otherwi...
QSize minimumSize() const
Reimplemented Function
void clear()
Removes all the elements from the vector and releases the memory used by the vector.
Definition: qvector.h:347
virtual int indexOf(QWidget *) const
Searches for widget widget in this layout (not including child layouts).
Definition: qlayout.cpp:1378
void resetLabelAlignment()
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
#define Q_TYPENAME
Definition: qglobal.h:1717
The QLayout class is the base class of geometry managers.
Definition: qlayout.h:90
QList< QFormLayoutItem * > m_things
const char * layout
void adjust(int x1, int y1, int x2, int y2)
Adds dx1, dy1, dx2 and dy2 respectively to the existing coordinates of the rectangle.
Definition: qrect.h:434
LayoutDirection
Definition: qnamespace.h:1580
Q_CORE_EXPORT void qWarning(const char *,...)
void setSpacing(int)
This function sets both the vertical and horizontal spacing to spacing.
void setupHorizontalLayoutData(int width)
unsigned int uint
Definition: qglobal.h:996
int verticalStretch() const
Definition: qsizepolicy.h:145
void getWidgetPosition(QWidget *widget, int *rowPtr, ItemRole *rolePtr) const
Retrieves the row and role (column) of the specified widget in the layout.
void addItem(QLayoutItem *item)
Reimplemented Function
Qt::Alignment formAlignment() const
int count() const
Reimplemented Function
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
static QWidget * parentWidget(const QWidget *w)
Qt::LayoutDirection layoutDirection
the layout direction for this widget
Definition: qwidget.h:216
void qGeomCalc(QVector< QLayoutStruct > &chain, int start, int count, int pos, int space, int spacer)
static QWidgetItem * createWidgetItem(const QLayout *layout, QWidget *widget)
Definition: qlayout.cpp:190
T * iterator
The QVector::iterator typedef provides an STL-style non-const iterator for QVector and QStack...
Definition: qvector.h:244
static int storageIndexFromLayoutItem(const QFormLayoutPrivate::ItemMatrix &m, QFormLayoutItem *item)
void setItem(int row, QFormLayout::ItemRole role, QLayoutItem *item)
int top() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:243
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:2087
Q_GUI_EXPORT int qSmartSpacing(const QLayout *layout, QStyle::PixelMetric pm)
#define Q_DECLARE_PUBLIC(Class)
Definition: qglobal.h:2477
Qt::Alignment labelAlignment
void setBuddy(QWidget *)
Sets this label&#39;s buddy to buddy.
Definition: qlabel.cpp:1297
static Qt::Alignment fixedAlignment(Qt::Alignment alignment, Qt::LayoutDirection layoutDirection)
int heightForWidth(int width) const
void setFieldGrowthPolicy(FieldGrowthPolicy policy)
int y() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:255
virtual QSize sizeHint() const =0
Implemented in subclasses to return the preferred size of this item.
QLayout * layout() const
virtual QLayout * layout()
If this item is a QLayout, it is returned as a QLayout; otherwise 0 is returned.
void getContentsMargins(int *left, int *top, int *right, int *bottom) const
Definition: qlayout.cpp:551
int vStretch() const
QWidget * widget() const
int x() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:252
QSizePolicy sizePolicy
the default layout behavior of the widget
Definition: qwidget.h:171
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
virtual QSize maximumSize() const =0
Implemented in subclasses to return the maximum size of this item.
QFormLayoutItem(QLayoutItem *i)
The QPoint class defines a point in the plane using integer precision.
Definition: qpoint.h:53
QWidget * labelForField(QWidget *field) const
Returns the label associated with the given field.
void getLayoutPosition(QLayout *layout, int *rowPtr, ItemRole *rolePtr) const
Retrieves the row and role (column) of the specified child layout.
The QStyle class is an abstract base class that encapsulates the look and feel of a GUI...
Definition: qstyle.h:68
RowWrapPolicy rowWrapPolicy() const
int & rheight()
Returns a reference to the height.
Definition: qsize.h:144
QString objectName() const
int height() const
Returns the height.
Definition: qsize.h:129
FixedColumnMatrix< QFormLayoutItem *, ColumnCount > ItemMatrix
static void updateFormLayoutItem(QFormLayoutItem *item, int userVSpacing, QFormLayout::FieldGrowthPolicy fieldGrowthPolicy, bool fullRow)
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:58
static QtFontStyle::Key getStyle(char **tokens)
bool isValid() const
Returns true if both the width and height is equal to or greater than 0; otherwise returns false...
Definition: qsize.h:123
Definition: qnamespace.h:54
QFactoryLoader * l
The QLabel widget provides a text or image display.
Definition: qlabel.h:55
Qt::Alignment alignment() const
Returns the alignment of this item.
Definition: qlayoutitem.h:85
static QString dump(const QByteArray &)
static int spacingHelper(QWidget *parent, QStyle *style, int userVSpacing, bool recalculate, QFormLayoutItem *item1, QFormLayoutItem *item2, QFormLayoutItem *prevItem1, QFormLayoutItem *prevItem2)
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...
quint16 index
void recalcHFW(int w)
QObject * parent
Definition: qobject.h:92
QLayoutItem * item
FieldGrowthPolicy fieldGrowthPolicy() const
QVector< QLayoutStruct > vLayouts
virtual QWidget * widget()
If this item is a QWidget, it is returned as a QWidget; otherwise 0 is returned.
The QFormLayout class manages forms of input widgets and their associated labels. ...
Definition: qformlayout.h:55
void setGeometry(const QRect &rect)
Reimplemented Function
QLayoutItem * takeAt(int index)
Reimplemented Function
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:53
void addRow(QWidget *label, QWidget *field)
Adds a new row to the bottom of this form layout, with the given label and field. ...
QRect geometry() const
Reimplemented Function
Definition: qlayout.cpp:664
QFormLayout(QWidget *parent=0)
Constructs a new form layout with the given parent widget.
QLayout * layout()
Reimplemented Function
void setLabelAlignment(Qt::Alignment alignment)
static const int QLAYOUTSIZE_MAX
Definition: qlayoutitem.h:56
void getItemPosition(int index, int *rowPtr, ItemRole *rolePtr) const
Retrieves the row and role (column) of the item at the specified index.
#define qPrintable(string)
Definition: qglobal.h:1750
QRect geometry
the geometry of the widget relative to its parent and excluding the window frame
Definition: qwidget.h:158
Q_OUTOFLINE_TEMPLATE void qDeleteAll(ForwardIterator begin, ForwardIterator end)
Definition: qalgorithms.h:319
Qt::Orientations expandingDirections() const
int combinedLayoutSpacing(QSizePolicy::ControlTypes controls1, QSizePolicy::ControlTypes controls2, Qt::Orientation orientation, QStyleOption *option=0, QWidget *widget=0) const
Returns the spacing that should be used between controls1 and controls2 in a layout.
Definition: qstyle.cpp:2438
void setGeometry(const QRect &r)
int & rwidth()
Returns a reference to the width.
Definition: qsize.h:141
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
static const uint layouts[2][5][14]
RowWrapPolicy
This enum specifies the different policies that can be used to control the way in which the form&#39;s ro...
Definition: qformlayout.h:74