11#include <QtDesigner/abstractformwindow.h>
12#include <QtDesigner/qextensionmanager.h>
13#include <QtDesigner/abstractformeditor.h>
14#include <QtDesigner/propertysheet.h>
15#include <QtDesigner/abstractwidgetfactory.h>
17#include <QtGui/qpainter.h>
18#include <QtWidgets/qboxlayout.h>
19#include <QtWidgets/qgridlayout.h>
20#include <QtWidgets/qformlayout.h>
21#include <QtWidgets/qapplication.h>
22#include <QtGui/qevent.h>
24#include <QtCore/qdebug.h>
25#include <QtCore/qalgorithms.h>
26#include <QtCore/qhash.h>
27#include <QtCore/qmap.h>
28#include <QtCore/qstack.h>
29#include <QtCore/qpair.h>
30#include <QtCore/qset.h>
45inline int gridRowCount(
const QGridLayout *gridLayout)
47 return gridLayout->rowCount();
50inline int gridColumnCount(
const QGridLayout *gridLayout)
52 return gridLayout->columnCount();
56inline void getGridItemPosition(QGridLayout *gridLayout,
int index,
57 int *row,
int *column,
int *rowspan,
int *colspan)
59 gridLayout->getItemPosition(index, row, column, rowspan, colspan);
62QRect gridItemInfo(QGridLayout *grid,
int index)
64 int row, column, rowSpan, columnSpan;
66 grid->getItemPosition(index, &row, &column, &rowSpan, &columnSpan);
67 return QRect(column, row, columnSpan, rowSpan);
70inline int gridRowCount(
const QFormLayout *formLayout) {
return formLayout->rowCount(); }
73inline void getGridItemPosition(QFormLayout *formLayout,
int index,
int *row,
int *column,
int *rowspan,
int *colspan)
81using namespace Qt::StringLiterals;
84#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
85static constexpr auto sizeConstraintC =
"sizeConstraint"_L1;
92
99 {
return Qt::Vertical | Qt::Horizontal; }
105 return new QSpacerItem(0, 0);
114template <
class GridLikeLayout>
117 const int count = gl.count();
118 str <<
"Grid: " << gl.objectName() << gridRowCount(&gl) <<
" rows x " << gridColumnCount(&gl)
119 <<
" cols " << count <<
" items\n";
120 for (
int i = 0; i < count; i++) {
121 QLayoutItem *item = gl.itemAt(i);
122 str <<
"Item " << i << item << item->widget() << gridItemInfo(
const_cast<GridLikeLayout *>(&gl), i) <<
" empty=" << qdesigner_internal::LayoutInfo::isEmptyItem(item) <<
"\n";
127static inline QDebug operator<<(QDebug str,
const QGridLayout &gl) {
return debugGridLikeLayout(str, gl); }
132 if (fl->itemAt(row, QFormLayout::SpanningRole))
134 return qdesigner_internal::LayoutInfo::isEmptyItem(fl->itemAt(row, QFormLayout::LabelRole)) && qdesigner_internal::LayoutInfo::isEmptyItem(fl->itemAt(row, QFormLayout::FieldRole));
142 const int bottomCheckRow = qMin(formLayout->rowCount(), restrictionArea.top() + restrictionArea.height());
143 for (
int r = restrictionArea.y(); r < bottomCheckRow; r++)
154 const qdesigner_internal::LayoutInfo::Type t = qdesigner_internal::LayoutInfo::layoutType(core, lt);
156 const int mask = properties.fromPropertySheet(core, lt, qdesigner_internal::LayoutProperties::AllProperties);
157 qdesigner_internal::LayoutInfo::deleteLayout(core, w);
158 QLayout *rc = core->widgetFactory()->createLayout(w,
nullptr, t);
159 properties.toPropertySheet(core, rc, mask,
true);
164template <
class GridLikeLayout>
167 Q_ASSERT(gridLayout);
168 const int count = gridLayout->count();
169 for (
int index = 0; index < count; index++) {
170 int row, column, rowspan, colspan;
171 getGridItemPosition(gridLayout, index, &row, &column, &rowspan, &colspan);
172 if (at_row >= row && at_row < (row + rowspan)
173 && at_column >= column && at_column < (column + colspan)) {
180template <
class GridLikeLayout>
185 QList<
int> indexesToBeRemoved;
186 indexesToBeRemoved.reserve(grid->count());
187 const int rightColumn = area.x() + area.width();
188 const int bottomRow = area.y() + area.height();
189 for (
int c = area.x(); c < rightColumn; c++)
190 for (
int r = area.y(); r < bottomRow; r++) {
191 const int index = findGridItemAt(grid, r ,c);
193 if (QLayoutItem *item = grid->itemAt(index)) {
194 if (qdesigner_internal::LayoutInfo::isEmptyItem(item)) {
195 if (indexesToBeRemoved.indexOf(index) == -1)
196 indexesToBeRemoved.push_back(index);
203 if (!indexesToBeRemoved.isEmpty()) {
204 std::stable_sort(indexesToBeRemoved.begin(), indexesToBeRemoved.end());
205 std::reverse(indexesToBeRemoved.begin(), indexesToBeRemoved.end());
206 for (
auto i : std::as_const(indexesToBeRemoved))
207 delete grid->takeAt(i);
229#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
250#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
280static bool intValueFromSheet(
const QDesignerPropertySheetExtension *sheet,
const QString &name,
int *value,
bool *changed)
282 const int sheetIndex = sheet->indexOf(name);
283 if (sheetIndex == -1)
285 *value = sheet->property(sheetIndex).toInt();
286 *changed = sheet->isChanged(sheetIndex);
291 QVariant *value,
bool *changed,
int *returnMask)
294 const int sIndex = sheet->indexOf(name);
296 *value = sheet->property(sIndex);
297 *changed = sheet->isChanged(sIndex);
329#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
350static bool intValueToSheet(QDesignerPropertySheetExtension *sheet,
const QString &name,
int value,
bool changed,
bool applyChanged)
354 const int sheetIndex = sheet->indexOf(name);
355 if (sheetIndex == -1) {
356 qWarning() <<
" LayoutProperties: Attempt to set property " << name <<
" that does not exist for the layout.";
359 sheet->setProperty(sheetIndex, QVariant(value));
361 sheet->setChanged(sheetIndex, changed);
365static void variantPropertyToSheet(
int mask,
int flag,
bool applyChanged, QDesignerPropertySheetExtension *sheet,
const QString &name,
366 const QVariant &value,
bool changed,
int *returnMask)
369 const int sIndex = sheet->indexOf(name);
371 sheet->setProperty(sIndex, value);
373 sheet->setChanged(sIndex, changed);
406#if QT_VERSION < QT_VERSION_CHECK(7
, 0
, 0
)
437 const int itemCount =
lt->
count();
448 qWarning() <<
"LayoutHelper::itemInfo: " <<
widget <<
" not in layout " <<
lt;
449 return QRect(0, 0, 1, 1);
467 bool canSimplify(
const QDesignerFormEditorInterface *,
const QWidget *,
const QRect &)
const override {
return false; }
468 void simplify(
const QDesignerFormEditorInterface *,
QWidget *,
const QRect &)
override {}
478 static BoxLayoutState state(
const QBoxLayout*lt);
480 QStack<BoxLayoutState> m_states;
481 const Qt::Orientation m_orientation;
486 return m_orientation == Qt::Horizontal ? QRect(index, 0, 1, 1) : QRect(0, index, 1, 1);
492 QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt);
494 boxLayout->insertWidget(m_orientation == Qt::Horizontal ? info.x() : info.y(), w);
499 QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt);
501 boxLayout->removeWidget(widget);
508 if (QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt)) {
509 const int index = boxLayout->indexOf(before);
511 const bool visible = before->isVisible();
512 delete boxLayout->takeAt(index);
515 before->setParent(
nullptr);
516 boxLayout->insertWidget(index, after);
521 qWarning() <<
"BoxLayoutHelper::replaceWidget : Unable to replace " << before <<
" by " << after <<
" in " << lt;
524 BoxLayoutHelper::BoxLayoutState
BoxLayoutHelper::state(
const QBoxLayout*lt)
527 if (
const int count = lt->count()) {
529 for (
int i = 0; i < count; i++)
530 if (
QWidget *w = lt->itemAt(i)->widget())
538 const QBoxLayout *boxLayout = qobject_cast<
const QBoxLayout *>(LayoutInfo::managedLayout(core, w));
540 m_states.push(state(boxLayout));
546 if (l->widget() == w)
555 const int count = lt->count();
557 return LayoutItemVector();
560 for (
int i = count - 1; i >= 0; i--)
561 rc.push_back(lt->takeAt(i));
567 QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(LayoutInfo::managedLayout(core, w));
569 const BoxLayoutState savedState = m_states.pop();
570 const BoxLayoutState currentState = state(boxLayout);
574 if (savedState == state(boxLayout))
577 Q_ASSERT(savedState.size() == currentState.size());
579 const LayoutItemVector items = disassembleLayout(boxLayout);
580 for (
auto *w : savedState) {
581 QLayoutItem *item = findItemOfWidget(items, w);
583 boxLayout->addItem(item);
633 <<
" cols " << gs.widgetItemMap.size() <<
" items\n";
635 const auto wcend = gs.widgetItemMap.constEnd();
636 for (
auto it = gs.widgetItemMap.constBegin(); it != wcend; ++it)
637 str <<
"Item " << it.key() << it.value() <<
'\n';
641 GridLayoutState::CellStates
GridLayoutState::cellStates(
const QList<QRect> &rects,
int numRows,
int numColumns)
643 CellStates rc = CellStates(numRows * numColumns, CellState(
Free,
Free));
644 for (
const auto &rect : rects) {
645 const int leftColumn = rect.x();
646 const int topRow = rect.y();
647 const int rightColumn = leftColumn + rect.width() - 1;
648 const int bottomRow = topRow + rect.height() - 1;
649 for (
int r = topRow; r <= bottomRow; r++)
650 for (
int c = leftColumn; c <= rightColumn; c++) {
651 const int flatIndex = r * numColumns + c;
653 DimensionCellState &horizState = rc[flatIndex].first;
654 if (c == leftColumn || c == rightColumn) {
655 horizState = Occupied;
657 if (horizState < Spanned)
658 horizState = Spanned;
661 DimensionCellState &vertState = rc[flatIndex].second;
662 if (r == topRow || r == bottomRow) {
663 vertState = Occupied;
665 if (vertState < Spanned)
671 qDebug() <<
"GridLayoutState::cellStates: " << numRows <<
" x " << numColumns;
672 for (
int r = 0; r < numRows; r++)
673 for (
int c = 0; c < numColumns; c++)
674 qDebug() <<
" Row: " << r <<
" column: " << c << rc[r * numColumns + c];
683 const int count = l->count();
684 for (
int i = 0; i < count; i++) {
685 QLayoutItem *item = l->itemAt(i);
686 if (!LayoutInfo::isEmptyItem(item)) {
687 widgetItemMap.insert(item->widget(), gridItemInfo(l, i));
688 if (item->alignment())
689 widgetAlignmentMap.insert(item->widget(), item->alignment());
696 QGridLayout *grid = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, w));
699 qDebug() <<
">GridLayoutState::applyToLayout" << *
this << *grid;
700 const bool shrink = grid->rowCount() >
rowCount || grid->columnCount() >
colCount;
702 QHash<QLayoutItem *, QRect> itemMap;
703 while (grid->count()) {
704 QLayoutItem *item = grid->takeAt(0);
705 if (!LayoutInfo::isEmptyItem(item)) {
706 QWidget *itemWidget = item->widget();
707 const auto it = widgetItemMap.constFind(itemWidget);
708 if (it == widgetItemMap.constEnd())
709 qFatal(
"GridLayoutState::applyToLayout: Attempt to apply to a layout that has a widget '%s'/'%s' added after saving the state.",
710 itemWidget->metaObject()->className(), itemWidget->objectName().toUtf8().constData());
711 itemMap.insert(item, it.value());
716 Q_ASSERT(itemMap.size() == widgetItemMap.size());
719 grid =
static_cast<QGridLayout*>(recreateManagedLayout(core, w, grid));
722 for (
auto it = itemMap.cbegin(), icend = itemMap.cend(); it != icend; ++it) {
723 const QRect info = it.value();
724 const Qt::Alignment alignment = widgetAlignmentMap.value(it.key()->widget(), {});
725 grid->addItem(it.key(), info.y(), info.x(), info.height(), info.width(), alignment);
728 const CellStates cs = cellStates(itemMap.values(), rowCount, colCount);
729 for (
int r = 0; r < rowCount; r++)
730 for (
int c = 0; c < colCount; c++)
731 if (needsSpacerItem(cs[r * colCount + c]))
732 grid->addItem(createGridSpacer(), r, c);
735 qDebug() <<
"<GridLayoutState::applyToLayout" << *grid;
741 for (
auto it = widgetItemMap.begin(), iend = widgetItemMap.end(); it != iend; ++it) {
742 const int topRow = it.value().y();
744 it.value().translate(0, 1);
746 const int rowSpan = it.value().height();
747 if (rowSpan > 1 && topRow + rowSpan > row)
748 it.value().setHeight(rowSpan + 1);
756 for (
auto it = widgetItemMap.begin(), iend = widgetItemMap.end(); it != iend; ++it) {
757 const int leftColumn = it.value().x();
758 if (leftColumn >= column) {
759 it.value().translate(1, 0);
761 const int colSpan = it.value().width();
762 if (colSpan > 1 && leftColumn + colSpan > column)
763 it.value().setWidth(colSpan + 1);
776 QList<
bool> occupiedRows(rowCount,
false);
777 QList<
bool> occupiedColumns(colCount,
false);
779 const int restrictionLeftColumn = r.x();
780 const int restrictionRightColumn = restrictionLeftColumn + r.width();
781 const int restrictionTopRow = r.y();
782 const int restrictionBottomRow = restrictionTopRow + r.height();
783 if (restrictionLeftColumn > 0 || restrictionRightColumn <
colCount ||
784 restrictionTopRow > 0 || restrictionBottomRow <
rowCount) {
785 for (
int r = 0; r < rowCount; r++)
786 if (r < restrictionTopRow || r >= restrictionBottomRow)
787 occupiedRows[r] =
true;
788 for (
int c = 0; c < colCount; c++)
789 if (c < restrictionLeftColumn || c >= restrictionRightColumn)
790 occupiedColumns[c] =
true;
793 const CellStates cs = cellStates(widgetItemMap.values(), rowCount, colCount);
795 for (
int c = 0; c <
colCount; c++) {
797 if (state.first == Occupied)
798 occupiedColumns[c] =
true;
799 if (state.second == Occupied)
800 occupiedRows[r] =
true;
803 if (occupiedRows.indexOf(
false) == -1 && occupiedColumns.indexOf(
false) == -1)
808 for (
int r =
rowCount - 1; r >= 0; r--)
809 if (!occupiedRows[r])
812 for (
int c =
colCount - 1; c >= 0; c--)
813 if (!occupiedColumns[c])
820 for (
auto it = widgetItemMap.begin(), iend = widgetItemMap.end(); it != iend; ++it) {
821 const int r = it.value().y();
822 Q_ASSERT(r != removeRow);
824 const int rowSpan = it.value().height();
826 const int bottomRow = r + rowSpan;
827 if (bottomRow > removeRow)
828 it.value().setHeight(rowSpan - 1);
832 it.value().translate(0, -1);
839 for (
auto it = widgetItemMap.begin(), iend = widgetItemMap.end(); it != iend; ++it) {
840 const int c = it.value().x();
841 Q_ASSERT(c != removeColumn);
842 if (c < removeColumn) {
843 const int colSpan = it.value().width();
845 const int rightColumn = c + colSpan;
846 if (rightColumn > removeColumn)
847 it.value().setWidth(colSpan - 1);
850 if (c > removeColumn)
851 it.value().translate(-1, 0);
866 void pushState(
const QDesignerFormEditorInterface *core,
const QWidget *widgetWithManagedLayout)
override;
867 void popState(
const QDesignerFormEditorInterface *core,
QWidget *widgetWithManagedLayout)
override;
869 bool canSimplify(
const QDesignerFormEditorInterface *core,
const QWidget *widgetWithManagedLayout,
const QRect &restrictionArea)
const override;
870 void simplify(
const QDesignerFormEditorInterface *core,
QWidget *widgetWithManagedLayout,
const QRect &restrictionArea)
override;
875 QStack<GridLayoutState> m_states;
883 QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(grid);
889 QGridLayout *grid = qobject_cast<QGridLayout *>(lt);
891 return gridItemInfo(grid, index);
897 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt);
898 Q_ASSERT(gridLayout);
900 const int row = info.y();
901 int column = info.x();
902 int colSpan = info.width();
903 int rowSpan = info.height();
906 if (!removeEmptyCellsOnGrid(gridLayout, info)) {
908 colSpan = rowSpan = 1;
910 const int columnCount = gridLayout->columnCount();
911 for (
int c = column; c < columnCount; c++) {
912 const int idx = findGridItemAt(gridLayout, row, c);
913 if (idx != -1 && LayoutInfo::isEmptyItem(gridLayout->itemAt(idx))) {
918 if (freeColumn != -1) {
919 removeEmptyCellsOnGrid(gridLayout, QRect(freeColumn, row, 1, 1));
926 gridLayout->addWidget(w, row , column, rowSpan, colSpan);
931 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt);
932 Q_ASSERT(gridLayout);
933 const int index = gridLayout->indexOf(widget);
935 qWarning() <<
"GridLayoutHelper::removeWidget : Attempt to remove " << widget <<
" which is not in the layout.";
939 int row, column, rowspan, colspan;
940 gridLayout->getItemPosition(index, &row, &column, &rowspan, &colspan);
941 delete gridLayout->takeAt(index);
942 const int rightColumn = column + colspan;
943 const int bottomRow = row + rowspan;
944 for (
int c = column; c < rightColumn; c++)
945 for (
int r = row; r < bottomRow; r++)
946 gridLayout->addItem(createGridSpacer(), r, c);
953 if (QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt)) {
954 const int index = gridLayout->indexOf(before);
956 int row, column, rowSpan, columnSpan;
957 gridLayout->getItemPosition (index, &row, &column, &rowSpan, &columnSpan);
958 const bool visible = before->isVisible();
959 delete gridLayout->takeAt(index);
962 before->setParent(
nullptr);
963 gridLayout->addWidget(after, row, column, rowSpan, columnSpan);
968 qWarning() <<
"GridLayoutHelper::replaceWidget : Unable to replace " << before <<
" by " << after <<
" in " << lt;
973 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
974 Q_ASSERT(gridLayout);
982 Q_ASSERT(!m_states.isEmpty());
989 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
990 Q_ASSERT(gridLayout);
998 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
999 Q_ASSERT(gridLayout);
1001 qDebug() <<
">GridLayoutHelper::simplify" << *gridLayout;
1007 qDebug() <<
"<GridLayoutHelper::simplify" << *gridLayout;
1022 void pushState(
const QDesignerFormEditorInterface *core,
const QWidget *widgetWithManagedLayout)
override;
1023 void popState(
const QDesignerFormEditorInterface *core,
QWidget *widgetWithManagedLayout)
override;
1025 bool canSimplify(
const QDesignerFormEditorInterface *core,
const QWidget *,
const QRect &)
const override;
1029 static FormLayoutState state(
const QFormLayout *lt);
1031 QStack<FormLayoutState> m_states;
1036 QFormLayout *form = qobject_cast<QFormLayout *>(lt);
1038 int row, column, colspan;
1039 getFormLayoutItemPosition(form, index, &row, &column,
nullptr, &colspan);
1040 return QRect(column, row, colspan, 1);
1046 qDebug() <<
"FormLayoutHelper::insertWidget:" << w << info;
1048 QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt);
1049 Q_ASSERT(formLayout);
1052 const bool insert = !removeEmptyCellsOnGrid(formLayout, info);
1053 formLayoutAddWidget(formLayout, w, info, insert);
1054 QLayoutSupport::createEmptyCells(formLayout);
1059 QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt);
1060 Q_ASSERT(formLayout);
1061 const int index = formLayout->indexOf(widget);
1063 qWarning() <<
"FormLayoutHelper::removeWidget : Attempt to remove " << widget <<
" which is not in the layout.";
1067 int row, column, colspan;
1068 getFormLayoutItemPosition(formLayout, index, &row, &column,
nullptr, &colspan);
1070 qDebug() <<
"FormLayoutHelper::removeWidget: #" << index << widget <<
" at " << row << column << colspan;
1071 delete formLayout->takeAt(index);
1072 if (colspan > 1 || column == 0)
1073 formLayout->setItem(row, QFormLayout::LabelRole, createFormSpacer());
1074 if (colspan > 1 || column == 1)
1075 formLayout->setItem(row, QFormLayout::FieldRole, createFormSpacer());
1082 if (QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt)) {
1083 const int index = formLayout->indexOf(before);
1086 QFormLayout::ItemRole role;
1087 formLayout->getItemPosition (index, &row, &role);
1088 const bool visible = before->isVisible();
1089 delete formLayout->takeAt(index);
1092 before->setParent(
nullptr);
1093 formLayout->setWidget(row, role, after);
1098 qWarning() <<
"FormLayoutHelper::replaceWidget : Unable to replace " << before <<
" by " << after <<
" in " << lt;
1101 FormLayoutHelper::FormLayoutState
FormLayoutHelper::state(
const QFormLayout *lt)
1103 const int rowCount = lt->rowCount();
1105 return FormLayoutState();
1106 FormLayoutState rc(rowCount, {
nullptr,
nullptr});
1107 const int count = lt->count();
1108 int row, column, colspan;
1109 for (
int i = 0; i < count; i++) {
1110 QLayoutItem *item = lt->itemAt(i);
1111 if (!LayoutInfo::isEmptyItem(item)) {
1114 getFormLayoutItemPosition(lt, i, &row, &column,
nullptr, &colspan);
1115 if (colspan > 1 || column == 0)
1117 if (colspan > 1 || column == 1)
1122 qDebug() <<
"FormLayoutHelper::state: " << rowCount;
1123 for (
int r = 0; r < rowCount; r++)
1124 qDebug() <<
" Row: " << r << rc[r].first << rc[r].second;
1131 QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
1132 Q_ASSERT(formLayout);
1133 m_states.push(state(formLayout));
1138 QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
1139 Q_ASSERT(!m_states.isEmpty() && formLayout);
1141 const FormLayoutState storedState = m_states.pop();
1142 const FormLayoutState currentState = state(formLayout);
1143 if (currentState == storedState)
1145 const int rowCount = storedState.size();
1147 const BoxLayoutHelper::LayoutItemVector items = BoxLayoutHelper::disassembleLayout(formLayout);
1148 if (rowCount < formLayout->rowCount())
1149 formLayout =
static_cast<QFormLayout*>(recreateManagedLayout(core, widgetWithManagedLayout, formLayout ));
1150 for (
int r = 0; r < rowCount; r++) {
1152 const bool spanning = widgets[0] !=
nullptr && widgets[0] == widgets[1];
1154 formLayout->setWidget(r, QFormLayout::SpanningRole, widgets[0]);
1157 const QFormLayout::ItemRole role = c == 0 ? QFormLayout::LabelRole : QFormLayout::FieldRole;
1158 if (widgets[c] && BoxLayoutHelper::findItemOfWidget(items, widgets[c])) {
1159 formLayout->setWidget(r, role, widgets[c]);
1161 formLayout->setItem(r, role, createFormSpacer());
1170 const QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
1171 Q_ASSERT(formLayout);
1177 using LayoutItemPair =
std::pair<QLayoutItem*, QLayoutItem*>;
1178 using LayoutItemPairs = QList<LayoutItemPair>;
1180 QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
1181 Q_ASSERT(formLayout);
1183 qDebug() <<
"FormLayoutHelper::simplify";
1185 const int rowCount = formLayout->rowCount();
1186 LayoutItemPairs pairs(rowCount, LayoutItemPair(0, 0));
1187 for (
int i = formLayout->count() - 1; i >= 0; i--) {
1188 int row, col,colspan;
1189 getFormLayoutItemPosition(formLayout, i, &row, &col,
nullptr, &colspan);
1191 pairs[row].first = pairs[row].second = formLayout->takeAt(i);
1194 pairs[row].first = formLayout->takeAt(i);
1196 pairs[row].second = formLayout->takeAt(i);
1200 const int bottomCheckRow = qMin(rowCount, restrictionArea.y() + restrictionArea.height());
1201 for (
int r = bottomCheckRow - 1; r >= restrictionArea.y(); r--)
1202 if (LayoutInfo::isEmptyItem(pairs[r].first) && LayoutInfo::isEmptyItem(pairs[r].second)) {
1203 delete pairs[r].first;
1204 delete pairs[r].second;
1207 const int simpleRowCount = pairs.size();
1208 if (simpleRowCount < rowCount)
1209 formLayout =
static_cast<QFormLayout *>(recreateManagedLayout(core, widgetWithManagedLayout, formLayout));
1211 for (
int r = 0; r < simpleRowCount; r++) {
1212 const bool spanning = pairs[r].first == pairs[r].second;
1214 formLayout->setItem(r, QFormLayout::SpanningRole, pairs[r].first);
1216 formLayout->setItem(r, QFormLayout::LabelRole, pairs[r].first);
1217 formLayout->setItem(r, QFormLayout::FieldRole, pairs[r].second);
1535class QBoxLayoutSupport:
public QLayoutSupport
1538 QBoxLayoutSupport(QDesignerFormWindowInterface *formWindow,
QWidget *widget, Qt::Orientation orientation, QObject *parent =
nullptr);
1540 void insertWidget(
QWidget *widget,
const std::pair<
int,
int> &cell) override;
1541 void removeWidget(
QWidget *widget) override;
1542 void simplify() override {}
1543 void insertRow(
int ) override {}
1544 void insertColumn(
int ) override {}
1546 int findItemAt(
int ,
int )
const override {
return -1; }
1547 using QLayoutSupport::findItemAt;
1550 void setCurrentCellFromIndicatorOnEmptyCell(
int index) override;
1551 void setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation,
int index,
int increment)
override;
1552 bool supportsIndicatorOrientation(Qt::Orientation indicatorOrientation)
const override;
1553 QRect extendedGeometry(
int index)
const override;
1555 const Qt::Orientation m_orientation;
1558void QBoxLayoutSupport::removeWidget(
QWidget *widget)
1560 QLayout *lt = layout();
1561 const int index = lt->indexOf(widget);
1566 std::pair<
int,
int> currCell = currentCell();
1567 switch (m_orientation) {
1568 case Qt::Horizontal:
1569 if (currCell.second > 0 && index < currCell.second ) {
1571 setCurrentCell(currCell);
1575 if (currCell.first > 0 && index < currCell.first) {
1577 setCurrentCell(currCell);
1581 helper()->removeWidget(lt, widget);
1584QBoxLayoutSupport::QBoxLayoutSupport(QDesignerFormWindowInterface *formWindow,
QWidget *widget, Qt::Orientation orientation, QObject *parent) :
1585 QLayoutSupport(formWindow, widget,
new BoxLayoutHelper(orientation), parent),
1586 m_orientation(orientation)
1590void QBoxLayoutSupport::setCurrentCellFromIndicatorOnEmptyCell(
int index)
1592 qDebug() <<
"QBoxLayoutSupport::setCurrentCellFromIndicatorOnEmptyCell(): Warning: found a fake spacer inside a vbox layout at " << index;
1593 setCurrentCell({0, 0});
1596void QBoxLayoutSupport::insertWidget(
QWidget *widget,
const std::pair<
int,
int> &cell)
1598 switch (m_orientation) {
1599 case Qt::Horizontal:
1600 helper()->insertWidget(layout(), QRect(cell.second, 0, 1, 1), widget);
1603 helper()->insertWidget(layout(), QRect(0, cell.first, 1, 1), widget);
1608void QBoxLayoutSupport::setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation,
int index,
int increment)
1610 if (m_orientation == Qt::Horizontal && indicatorOrientation == Qt::Vertical)
1611 setCurrentCell({0, index + increment});
1612 else if (m_orientation == Qt::Vertical && indicatorOrientation == Qt::Horizontal)
1613 setCurrentCell({index + increment, 0});
1616bool QBoxLayoutSupport::supportsIndicatorOrientation(Qt::Orientation indicatorOrientation)
const
1618 return m_orientation != indicatorOrientation;
1621QRect QBoxLayoutSupport::extendedGeometry(
int index)
const
1623 QLayoutItem *item = layout()->itemAt(index);
1625 QRect g = item->geometry();
1627 const QRect info = itemInfo(index);
1630 if (info.x() == 0) {
1631 QPoint topLeft = g.topLeft();
1632 topLeft.rx() = layout()->geometry().left();
1633 g.setTopLeft(topLeft);
1637 if (info.y() == 0) {
1638 QPoint topLeft = g.topLeft();
1639 topLeft.ry() = layout()->geometry().top();
1640 g.setTopLeft(topLeft);
1644 const QBoxLayout *box =
static_cast<
const QBoxLayout*>(layout());
1645 if (index < box->count() -1)
1649 QPoint bottomRight = g.bottomRight();
1650 switch (m_orientation) {
1652 bottomRight.ry() = layout()->geometry().bottom();
1654 case Qt::Horizontal:
1655 bottomRight.rx() = layout()->geometry().right();
1658 g.setBottomRight(bottomRight);
1663template <
class GridLikeLayout>
1664class GridLikeLayoutSupportBase:
public QLayoutSupport
1668 GridLikeLayoutSupportBase(QDesignerFormWindowInterface *formWindow,
QWidget *widget,
LayoutHelper *helper, QObject *parent =
nullptr) :
1669 QLayoutSupport(formWindow, widget, helper, parent) {}
1671 void insertWidget(
QWidget *widget,
const std::pair<
int,
int> &cell) override;
1672 void removeWidget(
QWidget *widget) override { helper()->removeWidget(layout(), widget); }
1673 int findItemAt(
int row,
int column)
const override;
1674 using QLayoutSupport::findItemAt;
1677 GridLikeLayout *gridLikeLayout()
const {
1678 return qobject_cast<GridLikeLayout*>(LayoutInfo::managedLayout(formWindow()->core(), widget()));
1683 void setCurrentCellFromIndicatorOnEmptyCell(
int index) override;
1684 void setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation,
int index,
int increment)
override;
1685 bool supportsIndicatorOrientation(Qt::Orientation)
const override {
return true; }
1687 QRect extendedGeometry(
int index)
const override;
1690 virtual void checkCellForInsertion(
int * ,
int * )
const {}
1693template <
class GridLikeLayout>
1694void GridLikeLayoutSupportBase<GridLikeLayout>::setCurrentCellFromIndicatorOnEmptyCell(
int index)
1696 GridLikeLayout *grid = gridLikeLayout();
1699 setInsertMode(InsertWidgetMode);
1700 int row, column, rowspan, colspan;
1702 getGridItemPosition(grid, index, &row, &column, &rowspan, &colspan);
1703 setCurrentCell({row, column});
1706template <
class GridLikeLayout>
1707void GridLikeLayoutSupportBase<GridLikeLayout>::setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation,
int index,
int increment) {
1708 const QRect info = itemInfo(index);
1709 switch (indicatorOrientation) {
1710 case Qt::Vertical: {
1711 setInsertMode(InsertColumnMode);
1712 int row = info.top();
1713 int column = increment ? info.right() + 1 : info.left();
1714 checkCellForInsertion(&row, &column);
1715 setCurrentCell({row, column});
1718 case Qt::Horizontal: {
1719 setInsertMode(InsertRowMode);
1720 int row = increment ? info.bottom() + 1 : info.top();
1721 int column = info.left();
1722 checkCellForInsertion(&row, &column);
1723 setCurrentCell({row, column});
1729template <
class GridLikeLayout>
1730void GridLikeLayoutSupportBase<GridLikeLayout>::insertWidget(
QWidget *widget,
const std::pair<
int,
int> &cell)
1732 helper()->insertWidget(layout(), QRect(cell.second, cell.first, 1, 1), widget);
1735template <
class GridLikeLayout>
1736int GridLikeLayoutSupportBase<GridLikeLayout>::findItemAt(
int at_row,
int at_column)
const
1738 GridLikeLayout *grid = gridLikeLayout();
1740 return findGridItemAt(grid, at_row, at_column);
1743template <
class GridLikeLayout>
1744QRect GridLikeLayoutSupportBase<GridLikeLayout>::extendedGeometry(
int index)
const
1746 QLayoutItem *item = layout()->itemAt(index);
1748 QRect g = item->geometry();
1750 const QRect info = itemInfo(index);
1753 if (info.x() == 0) {
1754 QPoint topLeft = g.topLeft();
1755 topLeft.rx() = layout()->geometry().left();
1756 g.setTopLeft(topLeft);
1760 if (info.y() == 0) {
1761 QPoint topLeft = g.topLeft();
1762 topLeft.ry() = layout()->geometry().top();
1763 g.setTopLeft(topLeft);
1765 const GridLikeLayout *grid = gridLikeLayout();
1769 QPoint bottomRight = g.bottomRight();
1770 if (gridRowCount(grid) == info.y())
1771 bottomRight.ry() = layout()->geometry().bottom();
1772 if (gridColumnCount(grid) == info.x())
1773 bottomRight.rx() = layout()->geometry().right();
1774 g.setBottomRight(bottomRight);
1779class QGridLayoutSupport:
public GridLikeLayoutSupportBase<QGridLayout>
1783 QGridLayoutSupport(QDesignerFormWindowInterface *formWindow,
QWidget *widget, QObject *parent =
nullptr);
1785 void simplify() override;
1786 void insertRow(
int row) override;
1787 void insertColumn(
int column) override;
1792QGridLayoutSupport::QGridLayoutSupport(QDesignerFormWindowInterface *formWindow,
QWidget *widget, QObject *parent) :
1793 GridLikeLayoutSupportBase<QGridLayout>(formWindow, widget,
new GridLayoutHelper, parent)
1797void QGridLayoutSupport::insertRow(
int row)
1799 QGridLayout *grid = gridLayout();
1804void QGridLayoutSupport::insertColumn(
int column)
1806 QGridLayout *grid = gridLayout();
1814void QGridLayoutSupport::simplify()
1816 QGridLayout *grid = gridLayout();
1821 const QRect fullArea = QRect(0, 0, state.colCount, state.rowCount);
1827class QFormLayoutSupport:
public GridLikeLayoutSupportBase<QFormLayout>
1830 QFormLayoutSupport(QDesignerFormWindowInterface *formWindow,
QWidget *widget, QObject *parent =
nullptr);
1832 void simplify() override {}
1833 void insertRow(
int ) override {}
1834 void insertColumn(
int ) override {}
1837 void checkCellForInsertion(
int * row,
int *col)
const override;
1840QFormLayoutSupport::QFormLayoutSupport(QDesignerFormWindowInterface *formWindow,
QWidget *widget, QObject *parent) :
1841 GridLikeLayoutSupportBase<QFormLayout>(formWindow, widget,
new FormLayoutHelper, parent)
1845void QFormLayoutSupport::checkCellForInsertion(
int *row,
int *col)
const
1881QLayoutWidget::QLayoutWidget(QDesignerFormWindowInterface *formWindow, QWidget *parent)
1882 : QWidget(parent), m_formWindow(formWindow),
1883 m_leftMargin(0), m_topMargin(0), m_rightMargin(0), m_bottomMargin(0)
1887void QLayoutWidget::paintEvent(QPaintEvent*)
1889 if (m_formWindow->currentTool() != 0)
1896 QMap<
int, QMap<
int,
bool> > excludedRowsForColumn;
1897 QMap<
int, QMap<
int,
bool> > excludedColumnsForRow;
1899 QLayout *lt = layout();
1900 QGridLayout *grid = qobject_cast<QGridLayout *>(lt);
1902 if (
const int count = lt->count()) {
1903 p.setPen(QPen(QColor(255, 0, 0, 35), 1));
1904 for (
int i = 0; i < count; i++) {
1905 QLayoutItem *item = lt->itemAt(i);
1907 int row, column, rowSpan, columnSpan;
1908 grid->getItemPosition(i, &row, &column, &rowSpan, &columnSpan);
1909 QMap<
int,
bool> rows;
1910 QMap<
int,
bool> columns;
1911 for (
int i = rowSpan; i > 1; i--)
1912 rows[row + i - 2] =
true;
1913 for (
int i = columnSpan; i > 1; i--)
1914 columns[column + i - 2] =
true;
1916 while (rowSpan > 0) {
1917 excludedColumnsForRow[row + rowSpan - 1].insert(columns);
1920 while (columnSpan > 0) {
1921 excludedRowsForColumn[column + columnSpan - 1].insert(rows);
1925 if (item->spacerItem()) {
1926 const QRect geometry = item->geometry();
1927 if (!geometry.isNull())
1928 p.drawRect(geometry.adjusted(1, 1, -2, -2));
1934 p.setPen(QPen(QColor(0, 0x80, 0, 0x80), 1));
1935 const int rowCount = grid->rowCount();
1936 const int columnCount = grid->columnCount();
1937 for (
int i = 0; i < rowCount; i++) {
1938 for (
int j = 0; j < columnCount; j++) {
1939 const QRect cellRect = grid->cellRect(i, j);
1940 if (j < columnCount - 1 && !excludedColumnsForRow.value(i).value(j,
false)) {
1941 const double y0 = (i == 0)
1942 ? 0 : (grid->cellRect(i - 1, j).bottom() + cellRect.top()) / 2.0;
1943 const double y1 = (i == rowCount - 1)
1944 ? height() - 1 : (cellRect.bottom() + grid->cellRect(i + 1, j).top()) / 2.0;
1945 const double x = (cellRect.right() + grid->cellRect(i, j + 1).left()) / 2.0;
1946 p.drawLine(QPointF(x, y0), QPointF(x, y1));
1948 if (i < rowCount - 1 && !excludedRowsForColumn.value(j).value(i,
false)) {
1949 const double x0 = (j == 0)
1950 ? 0 : (grid->cellRect(i, j - 1).right() + cellRect.left()) / 2.0;
1951 const double x1 = (j == columnCount - 1)
1952 ? width() - 1 : (cellRect.right() + grid->cellRect(i, j + 1).left()) / 2.0;
1953 const double y = (cellRect.bottom() + grid->cellRect(i + 1, j).top()) / 2.0;
1954 p.drawLine(QPointF(x0, y), QPointF(x1, y));
1959 p.setPen(QPen(QColor(255, 0, 0, 128), 1));
1960 p.drawRect(0, 0, width() - 1, height() - 1);
1963bool QLayoutWidget::event(QEvent *e)
1965 switch (e->type()) {
1966 case QEvent::LayoutRequest: {
1967 (
void) QWidget::event(e);
1969 if (layout() && qdesigner_internal::LayoutInfo::layoutType(formWindow()->core(), parentWidget()) == qdesigner_internal::LayoutInfo::NoLayout) {
1970 resize(layout()->totalMinimumSize().expandedTo(size()));
1982 return QWidget::event(e);
1985int QLayoutWidget::layoutLeftMargin()
const
1987 if (m_leftMargin < 0 && layout()) {
1989 layout()->getContentsMargins(&margin,
nullptr,
nullptr,
nullptr);
1992 return m_leftMargin;
1995void QLayoutWidget::setLayoutLeftMargin(
int layoutMargin)
1997 m_leftMargin = layoutMargin;
1999 int newMargin = m_leftMargin;
2000 if (newMargin >= 0 && newMargin < ShiftValue)
2001 newMargin = ShiftValue;
2002 int left, top, right, bottom;
2003 layout()->getContentsMargins(&left, &top, &right, &bottom);
2004 layout()->setContentsMargins(newMargin, top, right, bottom);
2008int QLayoutWidget::layoutTopMargin()
const
2010 if (m_topMargin < 0 && layout()) {
2012 layout()->getContentsMargins(
nullptr, &margin,
nullptr,
nullptr);
2018void QLayoutWidget::setLayoutTopMargin(
int layoutMargin)
2020 m_topMargin = layoutMargin;
2022 int newMargin = m_topMargin;
2023 if (newMargin >= 0 && newMargin < ShiftValue)
2024 newMargin = ShiftValue;
2025 int left, top, right, bottom;
2026 layout()->getContentsMargins(&left, &top, &right, &bottom);
2027 layout()->setContentsMargins(left, newMargin, right, bottom);
2031int QLayoutWidget::layoutRightMargin()
const
2033 if (m_rightMargin < 0 && layout()) {
2035 layout()->getContentsMargins(
nullptr,
nullptr, &margin,
nullptr);
2038 return m_rightMargin;
2041void QLayoutWidget::setLayoutRightMargin(
int layoutMargin)
2043 m_rightMargin = layoutMargin;
2045 int newMargin = m_rightMargin;
2046 if (newMargin >= 0 && newMargin < ShiftValue)
2047 newMargin = ShiftValue;
2048 int left, top, right, bottom;
2049 layout()->getContentsMargins(&left, &top, &right, &bottom);
2050 layout()->setContentsMargins(left, top, newMargin, bottom);
2054int QLayoutWidget::layoutBottomMargin()
const
2056 if (m_bottomMargin < 0 && layout()) {
2058 layout()->getContentsMargins(
nullptr,
nullptr,
nullptr, &margin);
2061 return m_bottomMargin;
2064void QLayoutWidget::setLayoutBottomMargin(
int layoutMargin)
2066 m_bottomMargin = layoutMargin;
2068 int newMargin = m_bottomMargin;
2069 if (newMargin >= 0 && newMargin < ShiftValue)
2070 newMargin = ShiftValue;
2071 int left, top, right, bottom;
2072 layout()->getContentsMargins(&left, &top, &right, &bottom);
2073 layout()->setContentsMargins(left, top, right, newMargin);
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 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
GridLayoutHelper()=default
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 CellStates cellStates(const QList< QRect > &rects, int numRows, int numColumns)
void removeFreeColumn(int column)
void insertColumn(int column)
std::pair< DimensionCellState, DimensionCellState > CellState
void applyToLayout(const QDesignerFormEditorInterface *core, QWidget *w) const
bool simplify(const QRect &r, bool testOnly)
void removeFreeRow(int row)
GridLayoutState()=default
QHash< QWidget *, Qt::Alignment > widgetAlignmentMap
void fromLayout(QGridLayout *l)
QHash< QWidget *, QRect > widgetItemMap