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