Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qlayout_widget.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3// Qt-Security score:significant reason:default
4
7#include "layout_p.h"
8#include "layoutinfo_p.h"
11
12#include <QtDesigner/abstractformwindow.h>
13#include <QtDesigner/qextensionmanager.h>
14#include <QtDesigner/abstractformeditor.h>
15#include <QtDesigner/propertysheet.h>
16#include <QtDesigner/abstractwidgetfactory.h>
17
18#include <QtGui/qpainter.h>
19#include <QtWidgets/qboxlayout.h>
20#include <QtWidgets/qgridlayout.h>
21#include <QtWidgets/qformlayout.h>
22#include <QtWidgets/qapplication.h>
23#include <QtGui/qevent.h>
24
25#include <QtCore/qdebug.h>
26#include <QtCore/qalgorithms.h>
27#include <QtCore/qhash.h>
28#include <QtCore/qmap.h>
29#include <QtCore/qstack.h>
30#include <QtCore/qset.h>
31
32#include <utility>
33
34#include <algorithm>
35
36enum { ShiftValue = 1 };
37enum { debugLayout = 0 };
38enum { FormLayoutColumns = 2 };
39enum { indicatorSize = 2 };
40// Grid/form Helpers: get info (overloads to make templates work)
41
42namespace { // Do not use static, will break HP-UX due to templates
43
44QT_USE_NAMESPACE
45
46// overloads to make templates over QGridLayout/QFormLayout work
47inline int gridRowCount(const QGridLayout *gridLayout)
48{
49 return gridLayout->rowCount();
50}
51
52inline int gridColumnCount(const QGridLayout *gridLayout)
53{
54 return gridLayout->columnCount();
55}
56
57// QGridLayout/QFormLayout Helpers: get item position (overloads to make templates work)
58inline void getGridItemPosition(QGridLayout *gridLayout, int index,
59 int *row, int *column, int *rowspan, int *colspan)
60{
61 gridLayout->getItemPosition(index, row, column, rowspan, colspan);
62}
63
64QRect gridItemInfo(QGridLayout *grid, int index)
65{
66 int row, column, rowSpan, columnSpan;
67 // getItemPosition is not const, grmbl..
68 grid->getItemPosition(index, &row, &column, &rowSpan, &columnSpan);
69 return QRect(column, row, columnSpan, rowSpan);
70}
71
72inline int gridRowCount(const QFormLayout *formLayout) { return formLayout->rowCount(); }
73inline int gridColumnCount(const QFormLayout *) { return FormLayoutColumns; }
74
75inline void getGridItemPosition(QFormLayout *formLayout, int index, int *row, int *column, int *rowspan, int *colspan)
76{
77 qdesigner_internal::getFormLayoutItemPosition(formLayout, index, row, column, rowspan, colspan);
78}
79} // namespace anonymous
80
81QT_BEGIN_NAMESPACE
82
83using namespace Qt::StringLiterals;
84
85static constexpr auto objectNameC = "objectName"_L1;
86#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
87static constexpr auto sizeConstraintC = "sizeConstraint"_L1;
88#else
89static constexpr auto horizSizeConstraintC = "horizontalSizeConstraint"_L1;
90static constexpr auto vertSizeConstraintC = "verticalSizeConstraint"_L1;
91#endif
92
93/* A padding spacer element that is used to represent an empty form layout cell. It should grow with its cell.
94 * Should not be used on a grid as it causes resizing inconsistencies */
95namespace qdesigner_internal {
97 public:
99
101 { return Qt::Vertical | Qt::Horizontal; }
102 };
103}
104
106{
107 return new QSpacerItem(0, 0);
108}
109
111{
113}
114
115// QGridLayout/QFormLayout Helpers: Debug items of GridLikeLayout
116template <class GridLikeLayout>
117static QDebug debugGridLikeLayout(QDebug str, const GridLikeLayout &gl)
118{
119 const int count = gl.count();
120 str << "Grid: " << gl.objectName() << gridRowCount(&gl) << " rows x " << gridColumnCount(&gl)
121 << " cols " << count << " items\n";
122 for (int i = 0; i < count; i++) {
123 QLayoutItem *item = gl.itemAt(i);
124 str << "Item " << i << item << item->widget() << gridItemInfo(const_cast<GridLikeLayout *>(&gl), i) << " empty=" << qdesigner_internal::LayoutInfo::isEmptyItem(item) << "\n";
125 }
126 return str;
127}
128
129static inline QDebug operator<<(QDebug str, const QGridLayout &gl) { return debugGridLikeLayout(str, gl); }
130
131static inline bool isEmptyFormLayoutRow(const QFormLayout *fl, int row)
132{
133 // Spanning can never be empty
134 if (fl->itemAt(row, QFormLayout::SpanningRole))
135 return false;
136 return qdesigner_internal::LayoutInfo::isEmptyItem(fl->itemAt(row, QFormLayout::LabelRole)) && qdesigner_internal::LayoutInfo::isEmptyItem(fl->itemAt(row, QFormLayout::FieldRole));
137}
138
139static inline bool canSimplifyFormLayout(const QFormLayout *formLayout, const QRect &restrictionArea)
140{
141 if (restrictionArea.x() >= FormLayoutColumns)
142 return false;
143 // Try to find empty rows
144 const int bottomCheckRow = qMin(formLayout->rowCount(), restrictionArea.top() + restrictionArea.height());
145 for (int r = restrictionArea.y(); r < bottomCheckRow; r++)
146 if (isEmptyFormLayoutRow(formLayout, r))
147 return true;
148 return false;
149}
150
151// recreate a managed layout (which does not automagically remove
152// empty rows/columns like grid or form layout) in case it needs to shrink
153
154static QLayout *recreateManagedLayout(const QDesignerFormEditorInterface *core, QWidget *w, QLayout *lt)
155{
156 const qdesigner_internal::LayoutInfo::Type t = qdesigner_internal::LayoutInfo::layoutType(core, lt);
158 const int mask = properties.fromPropertySheet(core, lt, qdesigner_internal::LayoutProperties::AllProperties);
159 qdesigner_internal::LayoutInfo::deleteLayout(core, w);
160 QLayout *rc = core->widgetFactory()->createLayout(w, nullptr, t);
161 properties.toPropertySheet(core, rc, mask, true);
162 return rc;
163}
164
165// QGridLayout/QFormLayout Helpers: find an item on a form/grid. Return index
166template <class GridLikeLayout>
167int findGridItemAt(GridLikeLayout *gridLayout, int at_row, int at_column)
168{
169 Q_ASSERT(gridLayout);
170 const int count = gridLayout->count();
171 for (int index = 0; index < count; index++) {
172 int row, column, rowspan, colspan;
173 getGridItemPosition(gridLayout, index, &row, &column, &rowspan, &colspan);
174 if (at_row >= row && at_row < (row + rowspan)
175 && at_column >= column && at_column < (column + colspan)) {
176 return index;
177 }
178 }
179 return -1;
180}
181// QGridLayout/QFormLayout Helpers: remove dummy spacers on form/grid
182template <class GridLikeLayout>
183static bool removeEmptyCellsOnGrid(GridLikeLayout *grid, const QRect &area)
184{
185 // check if there are any items in the way. Should be only spacers
186 // Unique out items that span rows/columns.
187 QList<int> indexesToBeRemoved;
188 indexesToBeRemoved.reserve(grid->count());
189 const int rightColumn = area.x() + area.width();
190 const int bottomRow = area.y() + area.height();
191 for (int c = area.x(); c < rightColumn; c++)
192 for (int r = area.y(); r < bottomRow; r++) {
193 const int index = findGridItemAt(grid, r ,c);
194 if (index != -1)
195 if (QLayoutItem *item = grid->itemAt(index)) {
196 if (qdesigner_internal::LayoutInfo::isEmptyItem(item)) {
197 if (indexesToBeRemoved.indexOf(index) == -1)
198 indexesToBeRemoved.push_back(index);
199 } else {
200 return false;
201 }
202 }
203 }
204 // remove, starting from last
205 if (!indexesToBeRemoved.isEmpty()) {
206 std::stable_sort(indexesToBeRemoved.begin(), indexesToBeRemoved.end());
207 std::reverse(indexesToBeRemoved.begin(), indexesToBeRemoved.end());
208 for (auto i : std::as_const(indexesToBeRemoved))
209 delete grid->takeAt(i);
210 }
211 return true;
212}
213
214namespace qdesigner_internal {
215// --------- LayoutProperties
216
221
245
269
270static const char *marginPropertyNamesC[] = {"leftMargin", "topMargin", "rightMargin", "bottomMargin"};
271static const char *spacingPropertyNamesC[] = {"spacing", "horizontalSpacing", "verticalSpacing" };
272static constexpr auto fieldGrowthPolicyPropertyC = "fieldGrowthPolicy"_L1;
273static constexpr auto rowWrapPolicyPropertyC = "rowWrapPolicy"_L1;
274static constexpr auto labelAlignmentPropertyC = "labelAlignment"_L1;
275static constexpr auto formAlignmentPropertyC = "formAlignment"_L1;
276static constexpr auto boxStretchPropertyC = "stretch"_L1;
277static constexpr auto gridRowStretchPropertyC = "rowStretch"_L1;
278static constexpr auto gridColumnStretchPropertyC = "columnStretch"_L1;
279static constexpr auto gridRowMinimumHeightPropertyC = "rowMinimumHeight"_L1;
280static constexpr auto gridColumnMinimumWidthPropertyC = "columnMinimumWidth"_L1;
281
282static bool intValueFromSheet(const QDesignerPropertySheetExtension *sheet, const QString &name, int *value, bool *changed)
283{
284 const int sheetIndex = sheet->indexOf(name);
285 if (sheetIndex == -1)
286 return false;
287 *value = sheet->property(sheetIndex).toInt();
288 *changed = sheet->isChanged(sheetIndex);
289 return true;
290}
291
292static void variantPropertyFromSheet(int mask, int flag, const QDesignerPropertySheetExtension *sheet, const QString &name,
293 QVariant *value, bool *changed, int *returnMask)
294{
295 if (mask & flag) {
296 const int sIndex = sheet->indexOf(name);
297 if (sIndex != -1) {
298 *value = sheet->property(sIndex);
299 *changed = sheet->isChanged(sIndex);
300 *returnMask |= flag;
301 }
302 }
303}
304
306{
307 int rc = 0;
310 // name
311 if (mask & ObjectNameProperty) {
312 const int nameIndex = sheet->indexOf(objectNameC);
313 Q_ASSERT(nameIndex != -1);
317 }
318 // -- Margins
320 for (int i = 0; i < MarginCount; i++)
321 if (mask & marginFlags[i])
323 rc |= marginFlags[i];
324
326 for (int i = 0; i < SpacingsCount; i++)
327 if (mask & spacingFlags[i])
329 rc |= spacingFlags[i];
330 // sizeConstraint, flags
331#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
334#else
339#endif
349 return rc;
350}
351
352static bool intValueToSheet(QDesignerPropertySheetExtension *sheet, const QString &name, int value, bool changed, bool applyChanged)
353
354{
355
356 const int sheetIndex = sheet->indexOf(name);
357 if (sheetIndex == -1) {
358 qWarning() << " LayoutProperties: Attempt to set property " << name << " that does not exist for the layout.";
359 return false;
360 }
361 sheet->setProperty(sheetIndex, QVariant(value));
362 if (applyChanged)
363 sheet->setChanged(sheetIndex, changed);
364 return true;
365}
366
367static void variantPropertyToSheet(int mask, int flag, bool applyChanged, QDesignerPropertySheetExtension *sheet, const QString &name,
368 const QVariant &value, bool changed, int *returnMask)
369{
370 if (mask & flag) {
371 const int sIndex = sheet->indexOf(name);
372 if (sIndex != -1) {
373 sheet->setProperty(sIndex, value);
374 if (applyChanged)
375 sheet->setChanged(sIndex, changed);
376 *returnMask |= flag;
377 }
378 }
379}
380
382{
383 int rc = 0;
386 // name
387 if (mask & ObjectNameProperty) {
388 const int nameIndex = sheet->indexOf(objectNameC);
389 Q_ASSERT(nameIndex != -1);
391 if (applyChanged)
394 }
395 // margins
397 for (int i = 0; i < MarginCount; i++)
398 if (mask & marginFlags[i])
400 rc |= marginFlags[i];
401
403 for (int i = 0; i < SpacingsCount; i++)
404 if (mask & spacingFlags[i])
406 rc |= spacingFlags[i];
407 // sizeConstraint
408#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
411#else
416#endif
426 return rc;
427}
428
429// ---------------- LayoutHelper
430LayoutHelper::LayoutHelper() = default;
431
432LayoutHelper::~LayoutHelper() = default;
433
435{
436 if (!lt)
437 return -1;
438
439 const int itemCount = lt->count();
440 for (int i = 0; i < itemCount; i++)
441 if (lt->itemAt(i)->widget() == widget)
442 return i;
443 return -1;
444}
445
447{
448 const int index = indexOf(lt, widget);
449 if (index == -1) {
450 qWarning() << "LayoutHelper::itemInfo: " << widget << " not in layout " << lt;
451 return QRect(0, 0, 1, 1);
452 }
453 return itemInfo(lt, index);
454}
455
456 // ---------------- BoxLayoutHelper
458 public:
459 BoxLayoutHelper(const Qt::Orientation orientation) : m_orientation(orientation) {}
460
461 QRect itemInfo(QLayout *lt, int index) const override;
462 void insertWidget(QLayout *lt, const QRect &info, QWidget *w) override;
463 void removeWidget(QLayout *lt, QWidget *widget) override;
464 void replaceWidget(QLayout *lt, QWidget *before, QWidget *after) override;
465
466 void pushState(const QDesignerFormEditorInterface *, const QWidget *) override;
467 void popState(const QDesignerFormEditorInterface *, QWidget *) override;
468
469 bool canSimplify(const QDesignerFormEditorInterface *, const QWidget *, const QRect &) const override { return false; }
470 void simplify(const QDesignerFormEditorInterface *, QWidget *, const QRect &) override {}
471
472 // Helper for restoring layout states
475 static QLayoutItem *findItemOfWidget(const LayoutItemVector &lv, QWidget *w);
476
477 private:
478 using BoxLayoutState = QList<QWidget *>;
479
480 static BoxLayoutState state(const QBoxLayout*lt);
481
482 QStack<BoxLayoutState> m_states;
483 const Qt::Orientation m_orientation;
484 };
485
486 QRect BoxLayoutHelper::itemInfo(QLayout * /*lt*/, int index) const
487 {
488 return m_orientation == Qt::Horizontal ? QRect(index, 0, 1, 1) : QRect(0, index, 1, 1);
489 }
490
491 void BoxLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w)
492 {
493 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
494 QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt);
495 Q_ASSERT(boxLayout);
496 boxLayout->insertWidget(m_orientation == Qt::Horizontal ? info.x() : info.y(), w);
497 }
498
499 void BoxLayoutHelper::removeWidget(QLayout *lt, QWidget *widget)
500 {
501 QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt);
502 Q_ASSERT(boxLayout);
503 boxLayout->removeWidget(widget);
504 }
505
506 void BoxLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after)
507 {
508 bool ok = false;
509 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
510 if (QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt)) {
511 const int index = boxLayout->indexOf(before);
512 if (index != -1) {
513 const bool visible = before->isVisible();
514 delete boxLayout->takeAt(index);
515 if (visible)
516 before->hide();
517 before->setParent(nullptr);
518 boxLayout->insertWidget(index, after);
519 ok = true;
520 }
521 }
522 if (!ok)
523 qWarning() << "BoxLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt;
524 }
525
526 BoxLayoutHelper::BoxLayoutState BoxLayoutHelper::state(const QBoxLayout*lt)
527 {
528 BoxLayoutState rc;
529 if (const int count = lt->count()) {
530 rc.reserve(count);
531 for (int i = 0; i < count; i++)
532 if (QWidget *w = lt->itemAt(i)->widget())
533 rc.push_back(w);
534 }
535 return rc;
536 }
537
538 void BoxLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *w)
539 {
540 const QBoxLayout *boxLayout = qobject_cast<const QBoxLayout *>(LayoutInfo::managedLayout(core, w));
541 Q_ASSERT(boxLayout);
542 m_states.push(state(boxLayout));
543 }
544
545 QLayoutItem *BoxLayoutHelper::findItemOfWidget(const LayoutItemVector &lv, QWidget *w)
546 {
547 for (auto *l : lv) {
548 if (l->widget() == w)
549 return l;
550 }
551 return nullptr;
552 }
553
554 BoxLayoutHelper::LayoutItemVector BoxLayoutHelper::disassembleLayout(QLayout *lt)
555 {
556 // Take items
557 const int count = lt->count();
558 if (count == 0)
559 return LayoutItemVector();
560 LayoutItemVector rc;
561 rc.reserve(count);
562 for (int i = count - 1; i >= 0; i--)
563 rc.push_back(lt->takeAt(i));
564 return rc;
565 }
566
567 void BoxLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *w)
568 {
569 QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(LayoutInfo::managedLayout(core, w));
570 Q_ASSERT(boxLayout);
571 const BoxLayoutState savedState = m_states.pop();
572 const BoxLayoutState currentState = state(boxLayout);
573 // Check for equality/empty. Note that this will currently
574 // always trigger as box layouts do not have a state apart from
575 // the order and there is no layout order editor yet.
576 if (savedState == state(boxLayout))
577 return;
578
579 Q_ASSERT(savedState.size() == currentState.size());
580 // Take items and reassemble in saved order
581 const LayoutItemVector items = disassembleLayout(boxLayout);
582 for (auto *w : savedState) {
583 QLayoutItem *item = findItemOfWidget(items, w);
584 Q_ASSERT(item);
585 boxLayout->addItem(item);
586 }
587 }
588
589 // Grid Layout state. Datatype storing the state of a GridLayout as a map of
590 // widgets to QRect(columns, rows) and size. Used to store the state for undo operations
591 // that do not change the widgets within the layout; also provides some manipulation
592 // functions and ability to apply the state to a layout provided its widgets haven't changed.
594 GridLayoutState() = default;
595
596 void fromLayout(QGridLayout *l);
597 void applyToLayout(const QDesignerFormEditorInterface *core, QWidget *w) const;
598
599 void insertRow(int row);
600 void insertColumn(int column);
601
602 bool simplify(const QRect &r, bool testOnly);
603 void removeFreeRow(int row);
604 void removeFreeColumn(int column);
605
606
607 // State of a cell in one dimension
610 Spanned, // Item spans it
611 Occupied // Item bordering on it
612 };
613 // Horiontal, Vertical pair of state
616
617 // Figure out states of a cell and return as a flat vector of
618 // [column1, column2,...] (address as row * columnCount + col)
619 static CellStates cellStates(const QList<QRect> &rects, int numRows, int numColumns);
620
623
624 int rowCount = 0;
625 int colCount = 0;
626 };
627
628 static inline bool needsSpacerItem(const GridLayoutState::CellState &cs) {
629 return cs.first == GridLayoutState::Free && cs.second == GridLayoutState::Free;
630 }
631
632 static inline QDebug operator<<(QDebug str, const GridLayoutState &gs)
633 {
634 str << "GridLayoutState: " << gs.rowCount << " rows x " << gs.colCount
635 << " cols " << gs.widgetItemMap.size() << " items\n";
636
637 const auto wcend = gs.widgetItemMap.constEnd();
638 for (auto it = gs.widgetItemMap.constBegin(); it != wcend; ++it)
639 str << "Item " << it.key() << it.value() << '\n';
640 return str;
641 }
642
643 GridLayoutState::CellStates GridLayoutState::cellStates(const QList<QRect> &rects, int numRows, int numColumns)
644 {
645 CellStates rc = CellStates(numRows * numColumns, CellState(Free, Free));
646 for (const auto &rect : rects) {
647 const int leftColumn = rect.x();
648 const int topRow = rect.y();
649 const int rightColumn = leftColumn + rect.width() - 1;
650 const int bottomRow = topRow + rect.height() - 1;
651 for (int r = topRow; r <= bottomRow; r++)
652 for (int c = leftColumn; c <= rightColumn; c++) {
653 const int flatIndex = r * numColumns + c;
654 // Bordering horizontally?
655 DimensionCellState &horizState = rc[flatIndex].first;
656 if (c == leftColumn || c == rightColumn) {
657 horizState = Occupied;
658 } else {
659 if (horizState < Spanned)
660 horizState = Spanned;
661 }
662 // Bordering vertically?
663 DimensionCellState &vertState = rc[flatIndex].second;
664 if (r == topRow || r == bottomRow) {
665 vertState = Occupied;
666 } else {
667 if (vertState < Spanned)
668 vertState = Spanned;
669 }
670 }
671 }
672 if (debugLayout) {
673 qDebug() << "GridLayoutState::cellStates: " << numRows << " x " << numColumns;
674 for (int r = 0; r < numRows; r++)
675 for (int c = 0; c < numColumns; c++)
676 qDebug() << " Row: " << r << " column: " << c << rc[r * numColumns + c];
677 }
678 return rc;
679 }
680
681 void GridLayoutState::fromLayout(QGridLayout *l)
682 {
683 rowCount = l->rowCount();
684 colCount = l->columnCount();
685 const int count = l->count();
686 for (int i = 0; i < count; i++) {
687 QLayoutItem *item = l->itemAt(i);
688 if (!LayoutInfo::isEmptyItem(item)) {
689 widgetItemMap.insert(item->widget(), gridItemInfo(l, i));
690 if (item->alignment())
691 widgetAlignmentMap.insert(item->widget(), item->alignment());
692 }
693 }
694 }
695
696 void GridLayoutState::applyToLayout(const QDesignerFormEditorInterface *core, QWidget *w) const
697 {
698 QGridLayout *grid = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, w));
699 Q_ASSERT(grid);
700 if (debugLayout)
701 qDebug() << ">GridLayoutState::applyToLayout" << *this << *grid;
702 const bool shrink = grid->rowCount() > rowCount || grid->columnCount() > colCount;
703 // Build a map of existing items to rectangles via widget map, delete spacers
704 QHash<QLayoutItem *, QRect> itemMap;
705 while (grid->count()) {
706 QLayoutItem *item = grid->takeAt(0);
707 if (!LayoutInfo::isEmptyItem(item)) {
708 QWidget *itemWidget = item->widget();
709 const auto it = widgetItemMap.constFind(itemWidget);
710 if (it == widgetItemMap.constEnd())
711 qFatal("GridLayoutState::applyToLayout: Attempt to apply to a layout that has a widget '%s'/'%s' added after saving the state.",
712 itemWidget->metaObject()->className(), itemWidget->objectName().toUtf8().constData());
713 itemMap.insert(item, it.value());
714 } else {
715 delete item;
716 }
717 }
718 Q_ASSERT(itemMap.size() == widgetItemMap.size());
719 // recreate if shrink
720 if (shrink)
721 grid = static_cast<QGridLayout*>(recreateManagedLayout(core, w, grid));
722
723 // Add widgets items
724 for (auto it = itemMap.cbegin(), icend = itemMap.cend(); it != icend; ++it) {
725 const QRect info = it.value();
726 const Qt::Alignment alignment = widgetAlignmentMap.value(it.key()->widget(), {});
727 grid->addItem(it.key(), info.y(), info.x(), info.height(), info.width(), alignment);
728 }
729 // create spacers
730 const CellStates cs = cellStates(itemMap.values(), rowCount, colCount);
731 for (int r = 0; r < rowCount; r++)
732 for (int c = 0; c < colCount; c++)
733 if (needsSpacerItem(cs[r * colCount + c]))
734 grid->addItem(createGridSpacer(), r, c);
735 grid->activate();
736 if (debugLayout)
737 qDebug() << "<GridLayoutState::applyToLayout" << *grid;
738 }
739
741 {
742 rowCount++;
743 for (auto it = widgetItemMap.begin(), iend = widgetItemMap.end(); it != iend; ++it) {
744 const int topRow = it.value().y();
745 if (topRow >= row) {
746 it.value().translate(0, 1);
747 } else { //Over it: Does it span it -> widen?
748 const int rowSpan = it.value().height();
749 if (rowSpan > 1 && topRow + rowSpan > row)
750 it.value().setHeight(rowSpan + 1);
751 }
752 }
753 }
754
756 {
757 colCount++;
758 for (auto it = widgetItemMap.begin(), iend = widgetItemMap.end(); it != iend; ++it) {
759 const int leftColumn = it.value().x();
760 if (leftColumn >= column) {
761 it.value().translate(1, 0);
762 } else { // Left of it: Does it span it -> widen?
763 const int colSpan = it.value().width();
764 if (colSpan > 1 && leftColumn + colSpan > column)
765 it.value().setWidth(colSpan + 1);
766 }
767 }
768 }
769
770 // Simplify: Remove empty columns/rows and such ones that are only spanned (shrink
771 // spanning items).
772 // 'AB.C.' 'ABC'
773 // 'DDDD.' ==> 'DDD'
774 // 'EF.G.' 'EFG'
775 bool GridLayoutState::simplify(const QRect &r, bool testOnly)
776 {
777 // figure out free rows/columns.
778 QList<bool> occupiedRows(rowCount, false);
779 QList<bool> occupiedColumns(colCount, false);
780 // Mark everything outside restriction rectangle as occupied
781 const int restrictionLeftColumn = r.x();
782 const int restrictionRightColumn = restrictionLeftColumn + r.width();
783 const int restrictionTopRow = r.y();
784 const int restrictionBottomRow = restrictionTopRow + r.height();
785 if (restrictionLeftColumn > 0 || restrictionRightColumn < colCount ||
786 restrictionTopRow > 0 || restrictionBottomRow < rowCount) {
787 for (int r = 0; r < rowCount; r++)
788 if (r < restrictionTopRow || r >= restrictionBottomRow)
789 occupiedRows[r] = true;
790 for (int c = 0; c < colCount; c++)
791 if (c < restrictionLeftColumn || c >= restrictionRightColumn)
792 occupiedColumns[c] = true;
793 }
794 // figure out free fields and tick off occupied rows and columns
795 const CellStates cs = cellStates(widgetItemMap.values(), rowCount, colCount);
796 for (int r = 0; r < rowCount; r++)
797 for (int c = 0; c < colCount; c++) {
798 const CellState &state = cs[r * colCount + c];
799 if (state.first == Occupied)
800 occupiedColumns[c] = true;
801 if (state.second == Occupied)
802 occupiedRows[r] = true;
803 }
804 // Any free rows/columns?
805 if (occupiedRows.indexOf(false) == -1 && occupiedColumns.indexOf(false) == -1)
806 return false;
807 if (testOnly)
808 return true;
809 // remove rows
810 for (int r = rowCount - 1; r >= 0; r--)
811 if (!occupiedRows[r])
813 // remove columns
814 for (int c = colCount - 1; c >= 0; c--)
815 if (!occupiedColumns[c])
817 return true;
818 }
819
820 void GridLayoutState::removeFreeRow(int removeRow)
821 {
822 for (auto it = widgetItemMap.begin(), iend = widgetItemMap.end(); it != iend; ++it) {
823 const int r = it.value().y();
824 Q_ASSERT(r != removeRow); // Free rows only
825 if (r < removeRow) { // Does the item span it? - shrink it
826 const int rowSpan = it.value().height();
827 if (rowSpan > 1) {
828 const int bottomRow = r + rowSpan;
829 if (bottomRow > removeRow)
830 it.value().setHeight(rowSpan - 1);
831 }
832 } else
833 if (r > removeRow) // Item below it? - move.
834 it.value().translate(0, -1);
835 }
836 rowCount--;
837 }
838
839 void GridLayoutState::removeFreeColumn(int removeColumn)
840 {
841 for (auto it = widgetItemMap.begin(), iend = widgetItemMap.end(); it != iend; ++it) {
842 const int c = it.value().x();
843 Q_ASSERT(c != removeColumn); // Free columns only
844 if (c < removeColumn) { // Does the item span it? - shrink it
845 const int colSpan = it.value().width();
846 if (colSpan > 1) {
847 const int rightColumn = c + colSpan;
848 if (rightColumn > removeColumn)
849 it.value().setWidth(colSpan - 1);
850 }
851 } else
852 if (c > removeColumn) // Item to the right of it? - move.
853 it.value().translate(-1, 0);
854 }
855 colCount--;
856 }
857
858 // ---------------- GridLayoutHelper
860 public:
861 GridLayoutHelper() = default;
862
863 QRect itemInfo(QLayout *lt, int index) const override;
864 void insertWidget(QLayout *lt, const QRect &info, QWidget *w) override;
865 void removeWidget(QLayout *lt, QWidget *widget) override;
866 void replaceWidget(QLayout *lt, QWidget *before, QWidget *after) override;
867
868 void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout) override;
869 void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout) override;
870
871 bool canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const override;
872 void simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea) override;
873
874 static void insertRow(QGridLayout *grid, int row);
875
876 private:
877 QStack<GridLayoutState> m_states;
878 };
879
880 void GridLayoutHelper::insertRow(QGridLayout *grid, int row)
881 {
882 GridLayoutState state;
883 state.fromLayout(grid);
884 state.insertRow(row);
885 QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(grid);
886 state.applyToLayout(fw->core(), grid->parentWidget());
887 }
888
889 QRect GridLayoutHelper::itemInfo(QLayout * lt, int index) const
890 {
891 QGridLayout *grid = qobject_cast<QGridLayout *>(lt);
892 Q_ASSERT(grid);
893 return gridItemInfo(grid, index);
894 }
895
896 void GridLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w)
897 {
898 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
899 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt);
900 Q_ASSERT(gridLayout);
901 // check if there are any items. Should be only spacers, else something is wrong
902 const int row = info.y();
903 int column = info.x();
904 int colSpan = info.width();
905 int rowSpan = info.height();
906 // If not empty: A multiselection was dropped on an empty item, insert row
907 // and spread items along new row
908 if (!removeEmptyCellsOnGrid(gridLayout, info)) {
909 int freeColumn = -1;
910 colSpan = rowSpan = 1;
911 // First look to the right for a free column
912 const int columnCount = gridLayout->columnCount();
913 for (int c = column; c < columnCount; c++) {
914 const int idx = findGridItemAt(gridLayout, row, c);
915 if (idx != -1 && LayoutInfo::isEmptyItem(gridLayout->itemAt(idx))) {
916 freeColumn = c;
917 break;
918 }
919 }
920 if (freeColumn != -1) {
921 removeEmptyCellsOnGrid(gridLayout, QRect(freeColumn, row, 1, 1));
922 column = freeColumn;
923 } else {
924 GridLayoutHelper::insertRow(gridLayout, row);
925 column = 0;
926 }
927 }
928 gridLayout->addWidget(w, row , column, rowSpan, colSpan);
929 }
930
931 void GridLayoutHelper::removeWidget(QLayout *lt, QWidget *widget)
932 {
933 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt);
934 Q_ASSERT(gridLayout);
935 const int index = gridLayout->indexOf(widget);
936 if (index == -1) {
937 qWarning() << "GridLayoutHelper::removeWidget : Attempt to remove " << widget << " which is not in the layout.";
938 return;
939 }
940 // delete old item and pad with by spacer items
941 int row, column, rowspan, colspan;
942 gridLayout->getItemPosition(index, &row, &column, &rowspan, &colspan);
943 delete gridLayout->takeAt(index);
944 const int rightColumn = column + colspan;
945 const int bottomRow = row + rowspan;
946 for (int c = column; c < rightColumn; c++)
947 for (int r = row; r < bottomRow; r++)
948 gridLayout->addItem(createGridSpacer(), r, c);
949 }
950
951 void GridLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after)
952 {
953 bool ok = false;
954 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
955 if (QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt)) {
956 const int index = gridLayout->indexOf(before);
957 if (index != -1) {
958 int row, column, rowSpan, columnSpan;
959 gridLayout->getItemPosition (index, &row, &column, &rowSpan, &columnSpan);
960 const bool visible = before->isVisible();
961 delete gridLayout->takeAt(index);
962 if (visible)
963 before->hide();
964 before->setParent(nullptr);
965 gridLayout->addWidget(after, row, column, rowSpan, columnSpan);
966 ok = true;
967 }
968 }
969 if (!ok)
970 qWarning() << "GridLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt;
971 }
972
973 void GridLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout)
974 {
975 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
976 Q_ASSERT(gridLayout);
978 gs.fromLayout(gridLayout);
979 m_states.push(gs);
980 }
981
982 void GridLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout)
983 {
984 Q_ASSERT(!m_states.isEmpty());
985 const GridLayoutState state = m_states.pop();
986 state.applyToLayout(core, widgetWithManagedLayout);
987 }
988
989 bool GridLayoutHelper::canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const
990 {
991 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
992 Q_ASSERT(gridLayout);
994 gs.fromLayout(gridLayout);
995 return gs.simplify(restrictionArea, true);
996 }
997
998 void GridLayoutHelper::simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea)
999 {
1000 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
1001 Q_ASSERT(gridLayout);
1002 if (debugLayout)
1003 qDebug() << ">GridLayoutHelper::simplify" << *gridLayout;
1004 GridLayoutState gs;
1005 gs.fromLayout(gridLayout);
1006 if (gs.simplify(restrictionArea, false))
1007 gs.applyToLayout(core, widgetWithManagedLayout);
1008 if (debugLayout)
1009 qDebug() << "<GridLayoutHelper::simplify" << *gridLayout;
1010 }
1011
1012 // ---------------- FormLayoutHelper
1014 public:
1016
1017 FormLayoutHelper() = default;
1018
1019 QRect itemInfo(QLayout *lt, int index) const override;
1020 void insertWidget(QLayout *lt, const QRect &info, QWidget *w) override;
1021 void removeWidget(QLayout *lt, QWidget *widget) override;
1022 void replaceWidget(QLayout *lt, QWidget *before, QWidget *after) override;
1023
1024 void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout) override;
1025 void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout) override;
1026
1027 bool canSimplify(const QDesignerFormEditorInterface *core, const QWidget *, const QRect &) const override;
1028 void simplify(const QDesignerFormEditorInterface *, QWidget *, const QRect &) override;
1029
1030 private:
1031 static FormLayoutState state(const QFormLayout *lt);
1032
1033 QStack<FormLayoutState> m_states;
1034 };
1035
1036 QRect FormLayoutHelper::itemInfo(QLayout * lt, int index) const
1037 {
1038 QFormLayout *form = qobject_cast<QFormLayout *>(lt);
1039 Q_ASSERT(form);
1040 int row, column, colspan;
1041 getFormLayoutItemPosition(form, index, &row, &column, nullptr, &colspan);
1042 return QRect(column, row, colspan, 1);
1043 }
1044
1045 void FormLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w)
1046 {
1047 if (debugLayout)
1048 qDebug() << "FormLayoutHelper::insertWidget:" << w << info;
1049 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
1050 QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt);
1051 Q_ASSERT(formLayout);
1052 // check if there are any nonspacer items? (Drop on 3rd column or drop of a multiselection
1053 // on an empty item. As the Form layout does not have insert semantics; we need to manually insert a row
1054 const bool insert = !removeEmptyCellsOnGrid(formLayout, info);
1055 formLayoutAddWidget(formLayout, w, info, insert);
1056 QLayoutSupport::createEmptyCells(formLayout);
1057 }
1058
1059 void FormLayoutHelper::removeWidget(QLayout *lt, QWidget *widget)
1060 {
1061 QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt);
1062 Q_ASSERT(formLayout);
1063 const int index = formLayout->indexOf(widget);
1064 if (index == -1) {
1065 qWarning() << "FormLayoutHelper::removeWidget : Attempt to remove " << widget << " which is not in the layout.";
1066 return;
1067 }
1068 // delete old item and pad with by spacer items
1069 int row, column, colspan;
1070 getFormLayoutItemPosition(formLayout, index, &row, &column, nullptr, &colspan);
1071 if (debugLayout)
1072 qDebug() << "FormLayoutHelper::removeWidget: #" << index << widget << " at " << row << column << colspan;
1073 delete formLayout->takeAt(index);
1074 if (colspan > 1 || column == 0)
1075 formLayout->setItem(row, QFormLayout::LabelRole, createFormSpacer());
1076 if (colspan > 1 || column == 1)
1077 formLayout->setItem(row, QFormLayout::FieldRole, createFormSpacer());
1078 }
1079
1080 void FormLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after)
1081 {
1082 bool ok = false;
1083 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
1084 if (QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt)) {
1085 const int index = formLayout->indexOf(before);
1086 if (index != -1) {
1087 int row;
1088 QFormLayout::ItemRole role;
1089 formLayout->getItemPosition (index, &row, &role);
1090 const bool visible = before->isVisible();
1091 delete formLayout->takeAt(index);
1092 if (visible)
1093 before->hide();
1094 before->setParent(nullptr);
1095 formLayout->setWidget(row, role, after);
1096 ok = true;
1097 }
1098 }
1099 if (!ok)
1100 qWarning() << "FormLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt;
1101 }
1102
1103 FormLayoutHelper::FormLayoutState FormLayoutHelper::state(const QFormLayout *lt)
1104 {
1105 const int rowCount = lt->rowCount();
1106 if (rowCount == 0)
1107 return FormLayoutState();
1108 FormLayoutState rc(rowCount, {nullptr, nullptr});
1109 const int count = lt->count();
1110 int row, column, colspan;
1111 for (int i = 0; i < count; i++) {
1112 QLayoutItem *item = lt->itemAt(i);
1113 if (!LayoutInfo::isEmptyItem(item)) {
1114 QWidget *w = item->widget();
1115 Q_ASSERT(w);
1116 getFormLayoutItemPosition(lt, i, &row, &column, nullptr, &colspan);
1117 if (colspan > 1 || column == 0)
1118 rc[row].first = w;
1119 if (colspan > 1 || column == 1)
1120 rc[row].second = w;
1121 }
1122 }
1123 if (debugLayout) {
1124 qDebug() << "FormLayoutHelper::state: " << rowCount;
1125 for (int r = 0; r < rowCount; r++)
1126 qDebug() << " Row: " << r << rc[r].first << rc[r].second;
1127 }
1128 return rc;
1129 }
1130
1131 void FormLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout)
1132 {
1133 QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
1134 Q_ASSERT(formLayout);
1135 m_states.push(state(formLayout));
1136 }
1137
1138 void FormLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout)
1139 {
1140 QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
1141 Q_ASSERT(!m_states.isEmpty() && formLayout);
1142
1143 const FormLayoutState storedState = m_states.pop();
1144 const FormLayoutState currentState = state(formLayout);
1145 if (currentState == storedState)
1146 return;
1147 const int rowCount = storedState.size();
1148 // clear out, shrink if required, but maintain items via map, pad spacers
1149 const BoxLayoutHelper::LayoutItemVector items = BoxLayoutHelper::disassembleLayout(formLayout);
1150 if (rowCount < formLayout->rowCount())
1151 formLayout = static_cast<QFormLayout*>(recreateManagedLayout(core, widgetWithManagedLayout, formLayout ));
1152 for (int r = 0; r < rowCount; r++) {
1153 QWidget *widgets[FormLayoutColumns] = { storedState[r].first, storedState[r].second };
1154 const bool spanning = widgets[0] != nullptr && widgets[0] == widgets[1];
1155 if (spanning) {
1156 formLayout->setWidget(r, QFormLayout::SpanningRole, widgets[0]);
1157 } else {
1158 for (int c = 0; c < FormLayoutColumns; c++) {
1159 const QFormLayout::ItemRole role = c == 0 ? QFormLayout::LabelRole : QFormLayout::FieldRole;
1160 if (widgets[c] && BoxLayoutHelper::findItemOfWidget(items, widgets[c])) {
1161 formLayout->setWidget(r, role, widgets[c]);
1162 } else {
1163 formLayout->setItem(r, role, createFormSpacer());
1164 }
1165 }
1166 }
1167 }
1168 }
1169
1170 bool FormLayoutHelper::canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const
1171 {
1172 const QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
1173 Q_ASSERT(formLayout);
1174 return canSimplifyFormLayout(formLayout, restrictionArea);
1175 }
1176
1177 void FormLayoutHelper::simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea)
1178 {
1179 using LayoutItemPair = std::pair<QLayoutItem*, QLayoutItem*>;
1180 using LayoutItemPairs = QList<LayoutItemPair>;
1181
1182 QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
1183 Q_ASSERT(formLayout);
1184 if (debugLayout)
1185 qDebug() << "FormLayoutHelper::simplify";
1186 // Transform into vector of item pairs
1187 const int rowCount = formLayout->rowCount();
1188 LayoutItemPairs pairs(rowCount, LayoutItemPair(0, 0));
1189 for (int i = formLayout->count() - 1; i >= 0; i--) {
1190 int row, col,colspan;
1191 getFormLayoutItemPosition(formLayout, i, &row, &col, nullptr, &colspan);
1192 if (colspan > 1) {
1193 pairs[row].first = pairs[row].second = formLayout->takeAt(i);
1194 } else {
1195 if (col == 0)
1196 pairs[row].first = formLayout->takeAt(i);
1197 else
1198 pairs[row].second = formLayout->takeAt(i);
1199 }
1200 }
1201 // Weed out empty ones
1202 const int bottomCheckRow = qMin(rowCount, restrictionArea.y() + restrictionArea.height());
1203 for (int r = bottomCheckRow - 1; r >= restrictionArea.y(); r--)
1204 if (LayoutInfo::isEmptyItem(pairs[r].first) && LayoutInfo::isEmptyItem(pairs[r].second)) {
1205 delete pairs[r].first;
1206 delete pairs[r].second;
1207 pairs.remove(r);
1208 }
1209 const int simpleRowCount = pairs.size();
1210 if (simpleRowCount < rowCount)
1211 formLayout = static_cast<QFormLayout *>(recreateManagedLayout(core, widgetWithManagedLayout, formLayout));
1212 // repopulate
1213 for (int r = 0; r < simpleRowCount; r++) {
1214 const bool spanning = pairs[r].first == pairs[r].second;
1215 if (spanning) {
1216 formLayout->setItem(r, QFormLayout::SpanningRole, pairs[r].first);
1217 } else {
1218 formLayout->setItem(r, QFormLayout::LabelRole, pairs[r].first);
1219 formLayout->setItem(r, QFormLayout::FieldRole, pairs[r].second);
1220 }
1221 }
1222 }
1223
1225{
1226 LayoutHelper *rc = nullptr;
1227 switch (type) {
1228 case LayoutInfo::HBox:
1230 break;
1231 case LayoutInfo::VBox:
1232 rc = new BoxLayoutHelper(Qt::Vertical);
1233 break;
1234 case LayoutInfo::Grid:
1235 rc = new GridLayoutHelper;
1236 break;
1237 case LayoutInfo::Form:
1238 return new FormLayoutHelper;
1239 default:
1240 break;
1241 }
1242 Q_ASSERT(rc);
1243 return rc;
1244}
1245
1246// ---- QLayoutSupport (LayoutDecorationExtension)
1256
1261
1263{
1264 if (m_indicators[i])
1265 m_indicators[i]->hide();
1266}
1267
1269{
1270 if (!m_indicators[i])
1276 indicator->show();
1277 indicator->raise();
1278}
1279
1281{
1282 delete m_helper;
1283 for (const QPointer<QWidget> &w : m_indicators) {
1284 if (!w.isNull())
1285 w->deleteLater();
1286 }
1287}
1288
1293
1298
1303
1305{
1307}
1308
1310{
1311 if (index == -1) { // first item goes anywhere
1316 return;
1317 }
1320
1322 const QRect g = extendedGeometry(index);
1323 // ### cleanup
1324 if (LayoutInfo::isEmptyItem(item)) {
1325 // Empty grid/form cell. Draw a rectangle
1328
1334 } else {
1335 // Append/Insert. Draw a bar left/right or above/below
1340
1341 const int fromRight = g.right() - pos.x();
1342 const int fromBottom = g.bottom() - pos.y();
1343
1344 const int fromLeft = pos.x() - g.x();
1345 const int fromTop = pos.y() - g.y();
1346
1347 const int fromLeftRight = qMin(fromRight, fromLeft );
1348 const int fromBottomTop = qMin(fromBottom, fromTop);
1349
1351
1353 const QRect r(layout()->geometry().topLeft(), layout()->parentWidget()->size());
1354 switch (indicatorOrientation) {
1355 case Qt::Vertical: {
1357 const bool closeToLeft = fromLeftRight == fromLeft;
1359
1360 const QWidget *parent = layout()->parentWidget();
1362 const int incr = leftToRight == closeToLeft ? 0 : +1;
1364 }
1365 break;
1366 case Qt::Horizontal: {
1368 const bool closeToTop = fromBottomTop == fromTop;
1370
1371 const int incr = closeToTop ? 0 : +1;
1373 }
1374 break;
1375 }
1376 } else {
1379 } // can handle indicatorOrientation
1380 }
1381}
1382
1384{
1385 const QLayout *lt = layout();
1386 if (!lt)
1387 return -1;
1388
1389 int index = 0;
1390
1391 while (QLayoutItem *item = lt->itemAt(index)) {
1392 if (item == i)
1393 return index;
1394
1395 ++index;
1396 }
1397
1398 return -1;
1399}
1400
1402{
1403 const QLayout *lt = layout();
1404 if (!lt)
1405 return -1;
1406
1407 int index = 0;
1408 while (QLayoutItem *item = lt->itemAt(index)) {
1409 if (item->widget() == widget)
1410 return index;
1411
1412 ++index;
1413 }
1414
1415 return -1;
1416}
1417
1419{
1420 if (!layout)
1421 return QWidgetList();
1422
1424 int index = 0;
1425 while (QLayoutItem *item = layout->itemAt(index)) {
1426 ++index;
1427
1428 QWidget *widget = item->widget();
1429 if (widget && formWindow()->isManaged(widget))
1430 lst.append(widget);
1431 }
1432
1433 return lst;
1434}
1435
1440
1441// Quick check whether simplify should be enabled for grids. May return false positives.
1442// Note: Calculating the occupied area does not work as spanning items may also be simplified.
1443
1445{
1446 if (!gl)
1447 return false;
1448 const int colCount = gl->columnCount();
1449 const int rowCount = gl->rowCount();
1450 if (colCount < 2 || rowCount < 2)
1451 return false;
1452 // try to find a spacer.
1453 const int count = gl->count();
1454 for (int index = 0; index < count; index++)
1456 return true;
1457 return false;
1458}
1459
1461{
1462 return canSimplifyFormLayout(fl, QRect(QPoint(0, 0), QSize(32767, 32767)));
1463}
1464
1465// remove dummy spacers
1470
1472{
1476
1478 for (int c = 0; c < gs.colCount; c++)
1479 for (int r = 0; r < gs.rowCount; r++)
1480 if (needsSpacerItem(cs[r * gs.colCount + c])) {
1481 const int existingItemIndex = findItemAt(gridLayout, r, c);
1482 if (existingItemIndex == -1)
1484 }
1485}
1486
1491
1493{
1494 // No spanning items here..
1495 if (const int rowCount = formLayout->rowCount())
1496 for (int c = 0; c < FormLayoutColumns; c++)
1497 for (int r = 0; r < rowCount; r++)
1498 if (findGridItemAt(formLayout, r, c) == -1)
1500}
1501
1503{
1504 if (!layout())
1505 return -1;
1506
1507 const QLayout *lt = layout();
1508 const int count = lt->count();
1509
1510 if (count == 0)
1511 return -1;
1512
1513 int best = -1;
1514 int bestIndex = -1;
1515
1516 for (int index = 0; index < count; index++) {
1518 bool visible = true;
1519 // When dragging widgets within layout, the source widget is invisible and must not be hit
1520 if (const QWidget *w = item->widget())
1521 visible = w->isVisible();
1522 if (visible) {
1523 const QRect g = item->geometry();
1524
1525 const int dist = (g.center() - pos).manhattanLength();
1526 if (best == -1 || dist < best) {
1527 best = dist;
1528 bestIndex = index;
1529 }
1530 }
1531 }
1532 return bestIndex;
1533}
1534
1535// ------------ QBoxLayoutSupport (LayoutDecorationExtension)
1536namespace {
1537class QBoxLayoutSupport: public QLayoutSupport
1538{
1539public:
1540 QBoxLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, Qt::Orientation orientation, QObject *parent = nullptr);
1541
1542 void insertWidget(QWidget *widget, const std::pair<int, int> &cell) override;
1543 void removeWidget(QWidget *widget) override;
1544 void simplify() override {}
1545 void insertRow(int /*row*/) override {}
1546 void insertColumn(int /*column*/) override {}
1547
1548 int findItemAt(int /*at_row*/, int /*at_column*/) const override { return -1; }
1549 using QLayoutSupport::findItemAt;
1550
1551private:
1552 void setCurrentCellFromIndicatorOnEmptyCell(int index) override;
1553 void setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment) override;
1554 bool supportsIndicatorOrientation(Qt::Orientation indicatorOrientation) const override;
1555 QRect extendedGeometry(int index) const override;
1556
1557 const Qt::Orientation m_orientation;
1558};
1559
1560void QBoxLayoutSupport::removeWidget(QWidget *widget)
1561{
1562 QLayout *lt = layout();
1563 const int index = lt->indexOf(widget);
1564 // Adjust the current cell in case a widget was dragged within the same layout to a position
1565 // of higher index, which happens as follows:
1566 // Drag start: The widget is hidden
1567 // Drop: Current cell is stored, widget is removed and re-added, causing an index offset that needs to be compensated
1568 std::pair<int, int> currCell = currentCell();
1569 switch (m_orientation) {
1570 case Qt::Horizontal:
1571 if (currCell.second > 0 && index < currCell.second ) {
1572 currCell.second--;
1573 setCurrentCell(currCell);
1574 }
1575 break;
1576 case Qt::Vertical:
1577 if (currCell.first > 0 && index < currCell.first) {
1578 currCell.first--;
1579 setCurrentCell(currCell);
1580 }
1581 break;
1582 }
1583 helper()->removeWidget(lt, widget);
1584}
1585
1586QBoxLayoutSupport::QBoxLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, Qt::Orientation orientation, QObject *parent) :
1587 QLayoutSupport(formWindow, widget, new BoxLayoutHelper(orientation), parent),
1588 m_orientation(orientation)
1589{
1590}
1591
1592void QBoxLayoutSupport::setCurrentCellFromIndicatorOnEmptyCell(int index)
1593{
1594 qDebug() << "QBoxLayoutSupport::setCurrentCellFromIndicatorOnEmptyCell(): Warning: found a fake spacer inside a vbox layout at " << index;
1595 setCurrentCell({0, 0});
1596}
1597
1598void QBoxLayoutSupport::insertWidget(QWidget *widget, const std::pair<int, int> &cell)
1599{
1600 switch (m_orientation) {
1601 case Qt::Horizontal:
1602 helper()->insertWidget(layout(), QRect(cell.second, 0, 1, 1), widget);
1603 break;
1604 case Qt::Vertical:
1605 helper()->insertWidget(layout(), QRect(0, cell.first, 1, 1), widget);
1606 break;
1607 }
1608}
1609
1610void QBoxLayoutSupport::setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment)
1611{
1612 if (m_orientation == Qt::Horizontal && indicatorOrientation == Qt::Vertical)
1613 setCurrentCell({0, index + increment});
1614 else if (m_orientation == Qt::Vertical && indicatorOrientation == Qt::Horizontal)
1615 setCurrentCell({index + increment, 0});
1616}
1617
1618bool QBoxLayoutSupport::supportsIndicatorOrientation(Qt::Orientation indicatorOrientation) const
1619{
1620 return m_orientation != indicatorOrientation;
1621}
1622
1623QRect QBoxLayoutSupport::extendedGeometry(int index) const
1624{
1625 QLayoutItem *item = layout()->itemAt(index);
1626 // start off with item geometry
1627 QRect g = item->geometry();
1628
1629 const QRect info = itemInfo(index);
1630
1631 // On left border: extend to widget border
1632 if (info.x() == 0) {
1633 QPoint topLeft = g.topLeft();
1634 topLeft.rx() = layout()->geometry().left();
1635 g.setTopLeft(topLeft);
1636 }
1637
1638 // On top border: extend to widget border
1639 if (info.y() == 0) {
1640 QPoint topLeft = g.topLeft();
1641 topLeft.ry() = layout()->geometry().top();
1642 g.setTopLeft(topLeft);
1643 }
1644
1645 // is this the last item?
1646 const QBoxLayout *box = static_cast<const QBoxLayout*>(layout());
1647 if (index < box->count() -1)
1648 return g; // Nope.
1649
1650 // extend to widget border
1651 QPoint bottomRight = g.bottomRight();
1652 switch (m_orientation) {
1653 case Qt::Vertical:
1654 bottomRight.ry() = layout()->geometry().bottom();
1655 break;
1656 case Qt::Horizontal:
1657 bottomRight.rx() = layout()->geometry().right();
1658 break;
1659 }
1660 g.setBottomRight(bottomRight);
1661 return g;
1662}
1663
1664// -------------- Base class for QGridLayout-like support classes (LayoutDecorationExtension)
1665template <class GridLikeLayout>
1666class GridLikeLayoutSupportBase: public QLayoutSupport
1667{
1668public:
1669
1670 GridLikeLayoutSupportBase(QDesignerFormWindowInterface *formWindow, QWidget *widget, LayoutHelper *helper, QObject *parent = nullptr) :
1671 QLayoutSupport(formWindow, widget, helper, parent) {}
1672
1673 void insertWidget(QWidget *widget, const std::pair<int, int> &cell) override;
1674 void removeWidget(QWidget *widget) override { helper()->removeWidget(layout(), widget); }
1675 int findItemAt(int row, int column) const override;
1676 using QLayoutSupport::findItemAt;
1677
1678protected:
1679 GridLikeLayout *gridLikeLayout() const {
1680 return qobject_cast<GridLikeLayout*>(LayoutInfo::managedLayout(formWindow()->core(), widget()));
1681 }
1682
1683private:
1684
1685 void setCurrentCellFromIndicatorOnEmptyCell(int index) override;
1686 void setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment) override;
1687 bool supportsIndicatorOrientation(Qt::Orientation) const override { return true; }
1688
1689 QRect extendedGeometry(int index) const override;
1690
1691 // Overwrite to check the insertion position (if there are limits)
1692 virtual void checkCellForInsertion(int * /*row*/, int * /*col*/) const {}
1693};
1694
1695template <class GridLikeLayout>
1696void GridLikeLayoutSupportBase<GridLikeLayout>::setCurrentCellFromIndicatorOnEmptyCell(int index)
1697{
1698 GridLikeLayout *grid = gridLikeLayout();
1699 Q_ASSERT(grid);
1700
1701 setInsertMode(InsertWidgetMode);
1702 int row, column, rowspan, colspan;
1703
1704 getGridItemPosition(grid, index, &row, &column, &rowspan, &colspan);
1705 setCurrentCell({row, column});
1706}
1707
1708template <class GridLikeLayout>
1709void GridLikeLayoutSupportBase<GridLikeLayout>::setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment) {
1710 const QRect info = itemInfo(index);
1711 switch (indicatorOrientation) {
1712 case Qt::Vertical: {
1713 setInsertMode(InsertColumnMode);
1714 int row = info.top();
1715 int column = increment ? info.right() + 1 : info.left();
1716 checkCellForInsertion(&row, &column);
1717 setCurrentCell({row, column});
1718 }
1719 break;
1720 case Qt::Horizontal: {
1721 setInsertMode(InsertRowMode);
1722 int row = increment ? info.bottom() + 1 : info.top();
1723 int column = info.left();
1724 checkCellForInsertion(&row, &column);
1725 setCurrentCell({row, column});
1726 }
1727 break;
1728 }
1729}
1730
1731template <class GridLikeLayout>
1732void GridLikeLayoutSupportBase<GridLikeLayout>::insertWidget(QWidget *widget, const std::pair<int, int> &cell)
1733{
1734 helper()->insertWidget(layout(), QRect(cell.second, cell.first, 1, 1), widget);
1735}
1736
1737template <class GridLikeLayout>
1738int GridLikeLayoutSupportBase<GridLikeLayout>::findItemAt(int at_row, int at_column) const
1739{
1740 GridLikeLayout *grid = gridLikeLayout();
1741 Q_ASSERT(grid);
1742 return findGridItemAt(grid, at_row, at_column);
1743}
1744
1745template <class GridLikeLayout>
1746QRect GridLikeLayoutSupportBase<GridLikeLayout>::extendedGeometry(int index) const
1747{
1748 QLayoutItem *item = layout()->itemAt(index);
1749 // start off with item geometry
1750 QRect g = item->geometry();
1751
1752 const QRect info = itemInfo(index);
1753
1754 // On left border: extend to widget border
1755 if (info.x() == 0) {
1756 QPoint topLeft = g.topLeft();
1757 topLeft.rx() = layout()->geometry().left();
1758 g.setTopLeft(topLeft);
1759 }
1760
1761 // On top border: extend to widget border
1762 if (info.y() == 0) {
1763 QPoint topLeft = g.topLeft();
1764 topLeft.ry() = layout()->geometry().top();
1765 g.setTopLeft(topLeft);
1766 }
1767 const GridLikeLayout *grid = gridLikeLayout();
1768 Q_ASSERT(grid);
1769
1770 // extend to widget border
1771 QPoint bottomRight = g.bottomRight();
1772 if (gridRowCount(grid) == info.y())
1773 bottomRight.ry() = layout()->geometry().bottom();
1774 if (gridColumnCount(grid) == info.x())
1775 bottomRight.rx() = layout()->geometry().right();
1776 g.setBottomRight(bottomRight);
1777 return g;
1778}
1779
1780// -------------- QGridLayoutSupport (LayoutDecorationExtension)
1781class QGridLayoutSupport: public GridLikeLayoutSupportBase<QGridLayout>
1782{
1783public:
1784
1785 QGridLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent = nullptr);
1786
1787 void simplify() override;
1788 void insertRow(int row) override;
1789 void insertColumn(int column) override;
1790
1791private:
1792};
1793
1794QGridLayoutSupport::QGridLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent) :
1795 GridLikeLayoutSupportBase<QGridLayout>(formWindow, widget, new GridLayoutHelper, parent)
1796{
1797}
1798
1799void QGridLayoutSupport::insertRow(int row)
1800{
1801 QGridLayout *grid = gridLayout();
1802 Q_ASSERT(grid);
1804}
1805
1806void QGridLayoutSupport::insertColumn(int column)
1807{
1808 QGridLayout *grid = gridLayout();
1809 Q_ASSERT(grid);
1810 GridLayoutState state;
1811 state.fromLayout(grid);
1812 state.insertColumn(column);
1813 state.applyToLayout(formWindow()->core(), widget());
1814}
1815
1816void QGridLayoutSupport::simplify()
1817{
1818 QGridLayout *grid = gridLayout();
1819 Q_ASSERT(grid);
1820 GridLayoutState state;
1821 state.fromLayout(grid);
1822
1823 const QRect fullArea = QRect(0, 0, state.colCount, state.rowCount);
1824 if (state.simplify(fullArea, false))
1825 state.applyToLayout(formWindow()->core(), widget());
1826}
1827
1828// -------------- QFormLayoutSupport (LayoutDecorationExtension)
1829class QFormLayoutSupport: public GridLikeLayoutSupportBase<QFormLayout>
1830{
1831public:
1832 QFormLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent = nullptr);
1833
1834 void simplify() override {}
1835 void insertRow(int /*row*/) override {}
1836 void insertColumn(int /*column*/) override {}
1837
1838private:
1839 void checkCellForInsertion(int * row, int *col) const override;
1840};
1841
1842QFormLayoutSupport::QFormLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent) :
1843 GridLikeLayoutSupportBase<QFormLayout>(formWindow, widget, new FormLayoutHelper, parent)
1844{
1845}
1846
1847void QFormLayoutSupport::checkCellForInsertion(int *row, int *col) const
1848{
1849 if (*col >= FormLayoutColumns) { // Clamp to 2 columns
1850 *col = 1;
1851 (*row)++;
1852 }
1853}
1854} // anonymous namespace
1855
1857{
1860 QLayoutSupport *rc = nullptr;
1861 switch (LayoutInfo::layoutType(formWindow->core(), layout)) {
1862 case LayoutInfo::HBox:
1864 break;
1865 case LayoutInfo::VBox:
1867 break;
1868 case LayoutInfo::Grid:
1870 break;
1871 case LayoutInfo::Form:
1873 break;
1874 default:
1875 break;
1876 }
1877 Q_ASSERT(rc);
1878 return rc;
1879}
1880} // namespace qdesigner_internal
1881
1882// -------------- QLayoutWidget
1883QLayoutWidget::QLayoutWidget(QDesignerFormWindowInterface *formWindow, QWidget *parent)
1884 : QWidget(parent), m_formWindow(formWindow),
1885 m_leftMargin(0), m_topMargin(0), m_rightMargin(0), m_bottomMargin(0)
1886{
1887}
1888
1889void QLayoutWidget::paintEvent(QPaintEvent*)
1890{
1891 if (m_formWindow->currentTool() != 0)
1892 return;
1893
1894 // only draw red borders if we're editting widgets
1895
1896 QPainter p(this);
1897
1898 QMap<int, QMap<int, bool> > excludedRowsForColumn;
1899 QMap<int, QMap<int, bool> > excludedColumnsForRow;
1900
1901 QLayout *lt = layout();
1902 QGridLayout *grid = qobject_cast<QGridLayout *>(lt);
1903 if (lt) {
1904 if (const int count = lt->count()) {
1905 p.setPen(QPen(QColor(255, 0, 0, 35), 1));
1906 for (int i = 0; i < count; i++) {
1907 QLayoutItem *item = lt->itemAt(i);
1908 if (grid) {
1909 int row, column, rowSpan, columnSpan;
1910 grid->getItemPosition(i, &row, &column, &rowSpan, &columnSpan);
1911 QMap<int, bool> rows;
1912 QMap<int, bool> columns;
1913 for (int i = rowSpan; i > 1; i--)
1914 rows[row + i - 2] = true;
1915 for (int i = columnSpan; i > 1; i--)
1916 columns[column + i - 2] = true;
1917
1918 while (rowSpan > 0) {
1919 excludedColumnsForRow[row + rowSpan - 1].insert(columns);
1920 rowSpan--;
1921 }
1922 while (columnSpan > 0) {
1923 excludedRowsForColumn[column + columnSpan - 1].insert(rows);
1924 columnSpan--;
1925 }
1926 }
1927 if (item->spacerItem()) {
1928 const QRect geometry = item->geometry();
1929 if (!geometry.isNull())
1930 p.drawRect(geometry.adjusted(1, 1, -2, -2));
1931 }
1932 }
1933 }
1934 }
1935 if (grid) {
1936 p.setPen(QPen(QColor(0, 0x80, 0, 0x80), 1));
1937 const int rowCount = grid->rowCount();
1938 const int columnCount = grid->columnCount();
1939 for (int i = 0; i < rowCount; i++) {
1940 for (int j = 0; j < columnCount; j++) {
1941 const QRect cellRect = grid->cellRect(i, j);
1942 if (j < columnCount - 1 && !excludedColumnsForRow.value(i).value(j, false)) {
1943 const double y0 = (i == 0)
1944 ? 0 : (grid->cellRect(i - 1, j).bottom() + cellRect.top()) / 2.0;
1945 const double y1 = (i == rowCount - 1)
1946 ? height() - 1 : (cellRect.bottom() + grid->cellRect(i + 1, j).top()) / 2.0;
1947 const double x = (cellRect.right() + grid->cellRect(i, j + 1).left()) / 2.0;
1948 p.drawLine(QPointF(x, y0), QPointF(x, y1));
1949 }
1950 if (i < rowCount - 1 && !excludedRowsForColumn.value(j).value(i, false)) {
1951 const double x0 = (j == 0)
1952 ? 0 : (grid->cellRect(i, j - 1).right() + cellRect.left()) / 2.0;
1953 const double x1 = (j == columnCount - 1)
1954 ? width() - 1 : (cellRect.right() + grid->cellRect(i, j + 1).left()) / 2.0;
1955 const double y = (cellRect.bottom() + grid->cellRect(i + 1, j).top()) / 2.0;
1956 p.drawLine(QPointF(x0, y), QPointF(x1, y));
1957 }
1958 }
1959 }
1960 }
1961 p.setPen(QPen(QColor(255, 0, 0, 128), 1));
1962 p.drawRect(0, 0, width() - 1, height() - 1);
1963}
1964
1965bool QLayoutWidget::event(QEvent *e)
1966{
1967 switch (e->type()) {
1968 case QEvent::LayoutRequest: {
1969 (void) QWidget::event(e);
1970 // Magic: We are layouted, but the parent is not..
1971 if (layout() && qdesigner_internal::LayoutInfo::layoutType(formWindow()->core(), parentWidget()) == qdesigner_internal::LayoutInfo::NoLayout) {
1972 resize(layout()->totalMinimumSize().expandedTo(size()));
1973 }
1974
1975 update();
1976
1977 return true;
1978 }
1979
1980 default:
1981 break;
1982 }
1983
1984 return QWidget::event(e);
1985}
1986
1987int QLayoutWidget::layoutLeftMargin() const
1988{
1989 if (m_leftMargin < 0 && layout()) {
1990 int margin;
1991 layout()->getContentsMargins(&margin, nullptr, nullptr, nullptr);
1992 return margin;
1993 }
1994 return m_leftMargin;
1995}
1996
1997void QLayoutWidget::setLayoutLeftMargin(int layoutMargin)
1998{
1999 m_leftMargin = layoutMargin;
2000 if (layout()) {
2001 int newMargin = m_leftMargin;
2002 if (newMargin >= 0 && newMargin < ShiftValue)
2003 newMargin = ShiftValue;
2004 int left, top, right, bottom;
2005 layout()->getContentsMargins(&left, &top, &right, &bottom);
2006 layout()->setContentsMargins(newMargin, top, right, bottom);
2007 }
2008}
2009
2010int QLayoutWidget::layoutTopMargin() const
2011{
2012 if (m_topMargin < 0 && layout()) {
2013 int margin;
2014 layout()->getContentsMargins(nullptr, &margin, nullptr, nullptr);
2015 return margin;
2016 }
2017 return m_topMargin;
2018}
2019
2020void QLayoutWidget::setLayoutTopMargin(int layoutMargin)
2021{
2022 m_topMargin = layoutMargin;
2023 if (layout()) {
2024 int newMargin = m_topMargin;
2025 if (newMargin >= 0 && newMargin < ShiftValue)
2026 newMargin = ShiftValue;
2027 int left, top, right, bottom;
2028 layout()->getContentsMargins(&left, &top, &right, &bottom);
2029 layout()->setContentsMargins(left, newMargin, right, bottom);
2030 }
2031}
2032
2033int QLayoutWidget::layoutRightMargin() const
2034{
2035 if (m_rightMargin < 0 && layout()) {
2036 int margin;
2037 layout()->getContentsMargins(nullptr, nullptr, &margin, nullptr);
2038 return margin;
2039 }
2040 return m_rightMargin;
2041}
2042
2043void QLayoutWidget::setLayoutRightMargin(int layoutMargin)
2044{
2045 m_rightMargin = layoutMargin;
2046 if (layout()) {
2047 int newMargin = m_rightMargin;
2048 if (newMargin >= 0 && newMargin < ShiftValue)
2049 newMargin = ShiftValue;
2050 int left, top, right, bottom;
2051 layout()->getContentsMargins(&left, &top, &right, &bottom);
2052 layout()->setContentsMargins(left, top, newMargin, bottom);
2053 }
2054}
2055
2056int QLayoutWidget::layoutBottomMargin() const
2057{
2058 if (m_bottomMargin < 0 && layout()) {
2059 int margin;
2060 layout()->getContentsMargins(nullptr, nullptr, nullptr, &margin);
2061 return margin;
2062 }
2063 return m_bottomMargin;
2064}
2065
2066void QLayoutWidget::setLayoutBottomMargin(int layoutMargin)
2067{
2068 m_bottomMargin = layoutMargin;
2069 if (layout()) {
2070 int newMargin = m_bottomMargin;
2071 if (newMargin >= 0 && newMargin < ShiftValue)
2072 newMargin = ShiftValue;
2073 int left, top, right, bottom;
2074 layout()->getContentsMargins(&left, &top, &right, &bottom);
2075 layout()->setContentsMargins(left, top, right, newMargin);
2076 }
2077}
2078
2079QT_END_NAMESPACE
friend class QWidget
Definition qpainter.h:432
BoxLayoutHelper(const Qt::Orientation orientation)
void simplify(const QDesignerFormEditorInterface *, QWidget *, const QRect &) override
void replaceWidget(QLayout *lt, QWidget *before, QWidget *after) override
void insertWidget(QLayout *lt, const QRect &info, QWidget *w) override
QRect itemInfo(QLayout *lt, int index) const override
static QLayoutItem * findItemOfWidget(const LayoutItemVector &lv, QWidget *w)
void popState(const QDesignerFormEditorInterface *, QWidget *) override
void removeWidget(QLayout *lt, QWidget *widget) override
bool canSimplify(const QDesignerFormEditorInterface *, const QWidget *, const QRect &) const override
static LayoutItemVector disassembleLayout(QLayout *lt)
void pushState(const QDesignerFormEditorInterface *, const QWidget *) override
void replaceWidget(QLayout *lt, QWidget *before, QWidget *after) override
void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout) override
void simplify(const QDesignerFormEditorInterface *, QWidget *, const QRect &) override
void insertWidget(QLayout *lt, const QRect &info, QWidget *w) override
bool canSimplify(const QDesignerFormEditorInterface *core, const QWidget *, const QRect &) const override
void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout) override
QRect itemInfo(QLayout *lt, int index) const override
void removeWidget(QLayout *lt, QWidget *widget) override
void simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea) override
QRect itemInfo(QLayout *lt, int index) const override
void replaceWidget(QLayout *lt, QWidget *before, QWidget *after) override
void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout) override
void insertWidget(QLayout *lt, const QRect &info, QWidget *w) override
bool canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const override
static void insertRow(QGridLayout *grid, int row)
void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout) override
void removeWidget(QLayout *lt, QWidget *widget) override
Qt::Orientations expandingDirections() const override
Returns whether this layout item can make use of more space than sizeHint().
Auxiliary methods to store/retrieve settings.
static const char * marginPropertyNamesC[]
static constexpr auto labelAlignmentPropertyC
static bool intValueFromSheet(const QDesignerPropertySheetExtension *sheet, const QString &name, int *value, bool *changed)
static constexpr auto boxStretchPropertyC
static constexpr auto gridColumnStretchPropertyC
static constexpr auto rowWrapPolicyPropertyC
QDESIGNER_SHARED_EXPORT void getFormLayoutItemPosition(const QFormLayout *formLayout, int index, int *rowPtr, int *columnPtr=nullptr, int *rowspanPtr=nullptr, int *colspanPtr=nullptr)
static bool intValueToSheet(QDesignerPropertySheetExtension *sheet, const QString &name, int value, bool changed, bool applyChanged)
static bool needsSpacerItem(const GridLayoutState::CellState &cs)
static void variantPropertyToSheet(int mask, int flag, bool applyChanged, QDesignerPropertySheetExtension *sheet, const QString &name, const QVariant &value, bool changed, int *returnMask)
static const char * spacingPropertyNamesC[]
static constexpr auto gridRowMinimumHeightPropertyC
static constexpr auto fieldGrowthPolicyPropertyC
static void variantPropertyFromSheet(int mask, int flag, const QDesignerPropertySheetExtension *sheet, const QString &name, QVariant *value, bool *changed, int *returnMask)
static constexpr auto gridColumnMinimumWidthPropertyC
static constexpr auto formAlignmentPropertyC
static constexpr auto gridRowStretchPropertyC
static constexpr auto objectNameC
static bool isEmptyFormLayoutRow(const QFormLayout *fl, int row)
@ indicatorSize
static bool removeEmptyCellsOnGrid(GridLikeLayout *grid, const QRect &area)
static QSpacerItem * createGridSpacer()
static bool canSimplifyFormLayout(const QFormLayout *formLayout, const QRect &restrictionArea)
static QLayout * recreateManagedLayout(const QDesignerFormEditorInterface *core, QWidget *w, QLayout *lt)
static constexpr auto vertSizeConstraintC
@ debugLayout
@ ShiftValue
int findGridItemAt(GridLikeLayout *gridLayout, int at_row, int at_column)
static QDebug debugGridLikeLayout(QDebug str, const GridLikeLayout &gl)
@ FormLayoutColumns
static QSpacerItem * createFormSpacer()
static constexpr auto horizSizeConstraintC
static CellStates cellStates(const QList< QRect > &rects, int numRows, int numColumns)
std::pair< DimensionCellState, DimensionCellState > CellState
void applyToLayout(const QDesignerFormEditorInterface *core, QWidget *w) const
bool simplify(const QRect &r, bool testOnly)
QHash< QWidget *, Qt::Alignment > widgetAlignmentMap
QHash< QWidget *, QRect > widgetItemMap