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;
84#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
85static constexpr auto sizeConstraintC = "sizeConstraint"_L1;
86#else
87static constexpr auto horizSizeConstraintC = "horizontalSizeConstraint"_L1;
88static constexpr auto vertSizeConstraintC = "verticalSizeConstraint"_L1;
89#endif
90
91/* A padding spacer element that is used to represent an empty form layout cell. It should grow with its cell.
92 * Should not be used on a grid as it causes resizing inconsistencies */
93namespace qdesigner_internal {
95 public:
97
99 { return Qt::Vertical | Qt::Horizontal; }
100 };
101}
102
104{
105 return new QSpacerItem(0, 0);
106}
107
109{
111}
112
113// QGridLayout/QFormLayout Helpers: Debug items of GridLikeLayout
114template <class GridLikeLayout>
115static QDebug debugGridLikeLayout(QDebug str, const GridLikeLayout &gl)
116{
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";
123 }
124 return str;
125}
126
127static inline QDebug operator<<(QDebug str, const QGridLayout &gl) { return debugGridLikeLayout(str, gl); }
128
129static inline bool isEmptyFormLayoutRow(const QFormLayout *fl, int row)
130{
131 // Spanning can never be empty
132 if (fl->itemAt(row, QFormLayout::SpanningRole))
133 return false;
134 return qdesigner_internal::LayoutInfo::isEmptyItem(fl->itemAt(row, QFormLayout::LabelRole)) && qdesigner_internal::LayoutInfo::isEmptyItem(fl->itemAt(row, QFormLayout::FieldRole));
135}
136
137static inline bool canSimplifyFormLayout(const QFormLayout *formLayout, const QRect &restrictionArea)
138{
139 if (restrictionArea.x() >= FormLayoutColumns)
140 return false;
141 // Try to find empty rows
142 const int bottomCheckRow = qMin(formLayout->rowCount(), restrictionArea.top() + restrictionArea.height());
143 for (int r = restrictionArea.y(); r < bottomCheckRow; r++)
144 if (isEmptyFormLayoutRow(formLayout, r))
145 return true;
146 return false;
147}
148
149// recreate a managed layout (which does not automagically remove
150// empty rows/columns like grid or form layout) in case it needs to shrink
151
152static QLayout *recreateManagedLayout(const QDesignerFormEditorInterface *core, QWidget *w, QLayout *lt)
153{
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);
160 return rc;
161}
162
163// QGridLayout/QFormLayout Helpers: find an item on a form/grid. Return index
164template <class GridLikeLayout>
165int findGridItemAt(GridLikeLayout *gridLayout, int at_row, int at_column)
166{
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)) {
174 return index;
175 }
176 }
177 return -1;
178}
179// QGridLayout/QFormLayout Helpers: remove dummy spacers on form/grid
180template <class GridLikeLayout>
181static bool removeEmptyCellsOnGrid(GridLikeLayout *grid, const QRect &area)
182{
183 // check if there are any items in the way. Should be only spacers
184 // Unique out items that span rows/columns.
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);
192 if (index != -1)
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);
197 } else {
198 return false;
199 }
200 }
201 }
202 // remove, starting from last
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);
208 }
209 return true;
210}
211
212namespace qdesigner_internal {
213// --------- LayoutProperties
214
219
243
267
268static const char *marginPropertyNamesC[] = {"leftMargin", "topMargin", "rightMargin", "bottomMargin"};
269static const char *spacingPropertyNamesC[] = {"spacing", "horizontalSpacing", "verticalSpacing" };
270static constexpr auto fieldGrowthPolicyPropertyC = "fieldGrowthPolicy"_L1;
271static constexpr auto rowWrapPolicyPropertyC = "rowWrapPolicy"_L1;
272static constexpr auto labelAlignmentPropertyC = "labelAlignment"_L1;
273static constexpr auto formAlignmentPropertyC = "formAlignment"_L1;
274static constexpr auto boxStretchPropertyC = "stretch"_L1;
275static constexpr auto gridRowStretchPropertyC = "rowStretch"_L1;
276static constexpr auto gridColumnStretchPropertyC = "columnStretch"_L1;
277static constexpr auto gridRowMinimumHeightPropertyC = "rowMinimumHeight"_L1;
278static constexpr auto gridColumnMinimumWidthPropertyC = "columnMinimumWidth"_L1;
279
280static bool intValueFromSheet(const QDesignerPropertySheetExtension *sheet, const QString &name, int *value, bool *changed)
281{
282 const int sheetIndex = sheet->indexOf(name);
283 if (sheetIndex == -1)
284 return false;
285 *value = sheet->property(sheetIndex).toInt();
286 *changed = sheet->isChanged(sheetIndex);
287 return true;
288}
289
290static void variantPropertyFromSheet(int mask, int flag, const QDesignerPropertySheetExtension *sheet, const QString &name,
291 QVariant *value, bool *changed, int *returnMask)
292{
293 if (mask & flag) {
294 const int sIndex = sheet->indexOf(name);
295 if (sIndex != -1) {
296 *value = sheet->property(sIndex);
297 *changed = sheet->isChanged(sIndex);
298 *returnMask |= flag;
299 }
300 }
301}
302
304{
305 int rc = 0;
308 // name
309 if (mask & ObjectNameProperty) {
310 const int nameIndex = sheet->indexOf(objectNameC);
311 Q_ASSERT(nameIndex != -1);
315 }
316 // -- Margins
318 for (int i = 0; i < MarginCount; i++)
319 if (mask & marginFlags[i])
321 rc |= marginFlags[i];
322
324 for (int i = 0; i < SpacingsCount; i++)
325 if (mask & spacingFlags[i])
327 rc |= spacingFlags[i];
328 // sizeConstraint, flags
329#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
332#else
337#endif
347 return rc;
348}
349
350static bool intValueToSheet(QDesignerPropertySheetExtension *sheet, const QString &name, int value, bool changed, bool applyChanged)
351
352{
353
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.";
357 return false;
358 }
359 sheet->setProperty(sheetIndex, QVariant(value));
360 if (applyChanged)
361 sheet->setChanged(sheetIndex, changed);
362 return true;
363}
364
365static void variantPropertyToSheet(int mask, int flag, bool applyChanged, QDesignerPropertySheetExtension *sheet, const QString &name,
366 const QVariant &value, bool changed, int *returnMask)
367{
368 if (mask & flag) {
369 const int sIndex = sheet->indexOf(name);
370 if (sIndex != -1) {
371 sheet->setProperty(sIndex, value);
372 if (applyChanged)
373 sheet->setChanged(sIndex, changed);
374 *returnMask |= flag;
375 }
376 }
377}
378
380{
381 int rc = 0;
384 // name
385 if (mask & ObjectNameProperty) {
386 const int nameIndex = sheet->indexOf(objectNameC);
387 Q_ASSERT(nameIndex != -1);
389 if (applyChanged)
392 }
393 // margins
395 for (int i = 0; i < MarginCount; i++)
396 if (mask & marginFlags[i])
398 rc |= marginFlags[i];
399
401 for (int i = 0; i < SpacingsCount; i++)
402 if (mask & spacingFlags[i])
404 rc |= spacingFlags[i];
405 // sizeConstraint
406#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
409#else
414#endif
424 return rc;
425}
426
427// ---------------- LayoutHelper
428LayoutHelper::LayoutHelper() = default;
429
430LayoutHelper::~LayoutHelper() = default;
431
433{
434 if (!lt)
435 return -1;
436
437 const int itemCount = lt->count();
438 for (int i = 0; i < itemCount; i++)
439 if (lt->itemAt(i)->widget() == widget)
440 return i;
441 return -1;
442}
443
445{
446 const int index = indexOf(lt, widget);
447 if (index == -1) {
448 qWarning() << "LayoutHelper::itemInfo: " << widget << " not in layout " << lt;
449 return QRect(0, 0, 1, 1);
450 }
451 return itemInfo(lt, index);
452}
453
454 // ---------------- BoxLayoutHelper
456 public:
457 BoxLayoutHelper(const Qt::Orientation orientation) : m_orientation(orientation) {}
458
459 QRect itemInfo(QLayout *lt, int index) const override;
460 void insertWidget(QLayout *lt, const QRect &info, QWidget *w) override;
461 void removeWidget(QLayout *lt, QWidget *widget) override;
462 void replaceWidget(QLayout *lt, QWidget *before, QWidget *after) override;
463
464 void pushState(const QDesignerFormEditorInterface *, const QWidget *) override;
465 void popState(const QDesignerFormEditorInterface *, QWidget *) override;
466
467 bool canSimplify(const QDesignerFormEditorInterface *, const QWidget *, const QRect &) const override { return false; }
468 void simplify(const QDesignerFormEditorInterface *, QWidget *, const QRect &) override {}
469
470 // Helper for restoring layout states
473 static QLayoutItem *findItemOfWidget(const LayoutItemVector &lv, QWidget *w);
474
475 private:
476 using BoxLayoutState = QList<QWidget *>;
477
478 static BoxLayoutState state(const QBoxLayout*lt);
479
480 QStack<BoxLayoutState> m_states;
481 const Qt::Orientation m_orientation;
482 };
483
484 QRect BoxLayoutHelper::itemInfo(QLayout * /*lt*/, int index) const
485 {
486 return m_orientation == Qt::Horizontal ? QRect(index, 0, 1, 1) : QRect(0, index, 1, 1);
487 }
488
489 void BoxLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w)
490 {
491 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
492 QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt);
493 Q_ASSERT(boxLayout);
494 boxLayout->insertWidget(m_orientation == Qt::Horizontal ? info.x() : info.y(), w);
495 }
496
497 void BoxLayoutHelper::removeWidget(QLayout *lt, QWidget *widget)
498 {
499 QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt);
500 Q_ASSERT(boxLayout);
501 boxLayout->removeWidget(widget);
502 }
503
504 void BoxLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after)
505 {
506 bool ok = false;
507 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
508 if (QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt)) {
509 const int index = boxLayout->indexOf(before);
510 if (index != -1) {
511 const bool visible = before->isVisible();
512 delete boxLayout->takeAt(index);
513 if (visible)
514 before->hide();
515 before->setParent(nullptr);
516 boxLayout->insertWidget(index, after);
517 ok = true;
518 }
519 }
520 if (!ok)
521 qWarning() << "BoxLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt;
522 }
523
524 BoxLayoutHelper::BoxLayoutState BoxLayoutHelper::state(const QBoxLayout*lt)
525 {
526 BoxLayoutState rc;
527 if (const int count = lt->count()) {
528 rc.reserve(count);
529 for (int i = 0; i < count; i++)
530 if (QWidget *w = lt->itemAt(i)->widget())
531 rc.push_back(w);
532 }
533 return rc;
534 }
535
536 void BoxLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *w)
537 {
538 const QBoxLayout *boxLayout = qobject_cast<const QBoxLayout *>(LayoutInfo::managedLayout(core, w));
539 Q_ASSERT(boxLayout);
540 m_states.push(state(boxLayout));
541 }
542
543 QLayoutItem *BoxLayoutHelper::findItemOfWidget(const LayoutItemVector &lv, QWidget *w)
544 {
545 for (auto *l : lv) {
546 if (l->widget() == w)
547 return l;
548 }
549 return nullptr;
550 }
551
552 BoxLayoutHelper::LayoutItemVector BoxLayoutHelper::disassembleLayout(QLayout *lt)
553 {
554 // Take items
555 const int count = lt->count();
556 if (count == 0)
557 return LayoutItemVector();
558 LayoutItemVector rc;
559 rc.reserve(count);
560 for (int i = count - 1; i >= 0; i--)
561 rc.push_back(lt->takeAt(i));
562 return rc;
563 }
564
565 void BoxLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *w)
566 {
567 QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(LayoutInfo::managedLayout(core, w));
568 Q_ASSERT(boxLayout);
569 const BoxLayoutState savedState = m_states.pop();
570 const BoxLayoutState currentState = state(boxLayout);
571 // Check for equality/empty. Note that this will currently
572 // always trigger as box layouts do not have a state apart from
573 // the order and there is no layout order editor yet.
574 if (savedState == state(boxLayout))
575 return;
576
577 Q_ASSERT(savedState.size() == currentState.size());
578 // Take items and reassemble in saved order
579 const LayoutItemVector items = disassembleLayout(boxLayout);
580 for (auto *w : savedState) {
581 QLayoutItem *item = findItemOfWidget(items, w);
582 Q_ASSERT(item);
583 boxLayout->addItem(item);
584 }
585 }
586
587 // Grid Layout state. Datatype storing the state of a GridLayout as a map of
588 // widgets to QRect(columns, rows) and size. Used to store the state for undo operations
589 // that do not change the widgets within the layout; also provides some manipulation
590 // functions and ability to apply the state to a layout provided its widgets haven't changed.
592 GridLayoutState() = default;
593
594 void fromLayout(QGridLayout *l);
595 void applyToLayout(const QDesignerFormEditorInterface *core, QWidget *w) const;
596
597 void insertRow(int row);
598 void insertColumn(int column);
599
600 bool simplify(const QRect &r, bool testOnly);
601 void removeFreeRow(int row);
602 void removeFreeColumn(int column);
603
604
605 // State of a cell in one dimension
608 Spanned, // Item spans it
609 Occupied // Item bordering on it
610 };
611 // Horiontal, Vertical pair of state
614
615 // Figure out states of a cell and return as a flat vector of
616 // [column1, column2,...] (address as row * columnCount + col)
617 static CellStates cellStates(const QList<QRect> &rects, int numRows, int numColumns);
618
621
622 int rowCount = 0;
623 int colCount = 0;
624 };
625
626 static inline bool needsSpacerItem(const GridLayoutState::CellState &cs) {
627 return cs.first == GridLayoutState::Free && cs.second == GridLayoutState::Free;
628 }
629
630 static inline QDebug operator<<(QDebug str, const GridLayoutState &gs)
631 {
632 str << "GridLayoutState: " << gs.rowCount << " rows x " << gs.colCount
633 << " cols " << gs.widgetItemMap.size() << " items\n";
634
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';
638 return str;
639 }
640
641 GridLayoutState::CellStates GridLayoutState::cellStates(const QList<QRect> &rects, int numRows, int numColumns)
642 {
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;
652 // Bordering horizontally?
653 DimensionCellState &horizState = rc[flatIndex].first;
654 if (c == leftColumn || c == rightColumn) {
655 horizState = Occupied;
656 } else {
657 if (horizState < Spanned)
658 horizState = Spanned;
659 }
660 // Bordering vertically?
661 DimensionCellState &vertState = rc[flatIndex].second;
662 if (r == topRow || r == bottomRow) {
663 vertState = Occupied;
664 } else {
665 if (vertState < Spanned)
666 vertState = Spanned;
667 }
668 }
669 }
670 if (debugLayout) {
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];
675 }
676 return rc;
677 }
678
679 void GridLayoutState::fromLayout(QGridLayout *l)
680 {
681 rowCount = l->rowCount();
682 colCount = l->columnCount();
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());
690 }
691 }
692 }
693
694 void GridLayoutState::applyToLayout(const QDesignerFormEditorInterface *core, QWidget *w) const
695 {
696 QGridLayout *grid = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, w));
697 Q_ASSERT(grid);
698 if (debugLayout)
699 qDebug() << ">GridLayoutState::applyToLayout" << *this << *grid;
700 const bool shrink = grid->rowCount() > rowCount || grid->columnCount() > colCount;
701 // Build a map of existing items to rectangles via widget map, delete spacers
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());
712 } else {
713 delete item;
714 }
715 }
716 Q_ASSERT(itemMap.size() == widgetItemMap.size());
717 // recreate if shrink
718 if (shrink)
719 grid = static_cast<QGridLayout*>(recreateManagedLayout(core, w, grid));
720
721 // Add widgets items
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);
726 }
727 // create spacers
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);
733 grid->activate();
734 if (debugLayout)
735 qDebug() << "<GridLayoutState::applyToLayout" << *grid;
736 }
737
739 {
740 rowCount++;
741 for (auto it = widgetItemMap.begin(), iend = widgetItemMap.end(); it != iend; ++it) {
742 const int topRow = it.value().y();
743 if (topRow >= row) {
744 it.value().translate(0, 1);
745 } else { //Over it: Does it span it -> widen?
746 const int rowSpan = it.value().height();
747 if (rowSpan > 1 && topRow + rowSpan > row)
748 it.value().setHeight(rowSpan + 1);
749 }
750 }
751 }
752
754 {
755 colCount++;
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);
760 } else { // Left of it: Does it span it -> widen?
761 const int colSpan = it.value().width();
762 if (colSpan > 1 && leftColumn + colSpan > column)
763 it.value().setWidth(colSpan + 1);
764 }
765 }
766 }
767
768 // Simplify: Remove empty columns/rows and such ones that are only spanned (shrink
769 // spanning items).
770 // 'AB.C.' 'ABC'
771 // 'DDDD.' ==> 'DDD'
772 // 'EF.G.' 'EFG'
773 bool GridLayoutState::simplify(const QRect &r, bool testOnly)
774 {
775 // figure out free rows/columns.
776 QList<bool> occupiedRows(rowCount, false);
777 QList<bool> occupiedColumns(colCount, false);
778 // Mark everything outside restriction rectangle as occupied
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;
791 }
792 // figure out free fields and tick off occupied rows and columns
793 const CellStates cs = cellStates(widgetItemMap.values(), rowCount, colCount);
794 for (int r = 0; r < rowCount; r++)
795 for (int c = 0; c < colCount; c++) {
796 const CellState &state = cs[r * colCount + c];
797 if (state.first == Occupied)
798 occupiedColumns[c] = true;
799 if (state.second == Occupied)
800 occupiedRows[r] = true;
801 }
802 // Any free rows/columns?
803 if (occupiedRows.indexOf(false) == -1 && occupiedColumns.indexOf(false) == -1)
804 return false;
805 if (testOnly)
806 return true;
807 // remove rows
808 for (int r = rowCount - 1; r >= 0; r--)
809 if (!occupiedRows[r])
811 // remove columns
812 for (int c = colCount - 1; c >= 0; c--)
813 if (!occupiedColumns[c])
815 return true;
816 }
817
818 void GridLayoutState::removeFreeRow(int removeRow)
819 {
820 for (auto it = widgetItemMap.begin(), iend = widgetItemMap.end(); it != iend; ++it) {
821 const int r = it.value().y();
822 Q_ASSERT(r != removeRow); // Free rows only
823 if (r < removeRow) { // Does the item span it? - shrink it
824 const int rowSpan = it.value().height();
825 if (rowSpan > 1) {
826 const int bottomRow = r + rowSpan;
827 if (bottomRow > removeRow)
828 it.value().setHeight(rowSpan - 1);
829 }
830 } else
831 if (r > removeRow) // Item below it? - move.
832 it.value().translate(0, -1);
833 }
834 rowCount--;
835 }
836
837 void GridLayoutState::removeFreeColumn(int removeColumn)
838 {
839 for (auto it = widgetItemMap.begin(), iend = widgetItemMap.end(); it != iend; ++it) {
840 const int c = it.value().x();
841 Q_ASSERT(c != removeColumn); // Free columns only
842 if (c < removeColumn) { // Does the item span it? - shrink it
843 const int colSpan = it.value().width();
844 if (colSpan > 1) {
845 const int rightColumn = c + colSpan;
846 if (rightColumn > removeColumn)
847 it.value().setWidth(colSpan - 1);
848 }
849 } else
850 if (c > removeColumn) // Item to the right of it? - move.
851 it.value().translate(-1, 0);
852 }
853 colCount--;
854 }
855
856 // ---------------- GridLayoutHelper
858 public:
859 GridLayoutHelper() = default;
860
861 QRect itemInfo(QLayout *lt, int index) const override;
862 void insertWidget(QLayout *lt, const QRect &info, QWidget *w) override;
863 void removeWidget(QLayout *lt, QWidget *widget) override;
864 void replaceWidget(QLayout *lt, QWidget *before, QWidget *after) override;
865
866 void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout) override;
867 void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout) override;
868
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;
871
872 static void insertRow(QGridLayout *grid, int row);
873
874 private:
875 QStack<GridLayoutState> m_states;
876 };
877
878 void GridLayoutHelper::insertRow(QGridLayout *grid, int row)
879 {
880 GridLayoutState state;
881 state.fromLayout(grid);
882 state.insertRow(row);
883 QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(grid);
884 state.applyToLayout(fw->core(), grid->parentWidget());
885 }
886
887 QRect GridLayoutHelper::itemInfo(QLayout * lt, int index) const
888 {
889 QGridLayout *grid = qobject_cast<QGridLayout *>(lt);
890 Q_ASSERT(grid);
891 return gridItemInfo(grid, index);
892 }
893
894 void GridLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w)
895 {
896 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
897 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt);
898 Q_ASSERT(gridLayout);
899 // check if there are any items. Should be only spacers, else something is wrong
900 const int row = info.y();
901 int column = info.x();
902 int colSpan = info.width();
903 int rowSpan = info.height();
904 // If not empty: A multiselection was dropped on an empty item, insert row
905 // and spread items along new row
906 if (!removeEmptyCellsOnGrid(gridLayout, info)) {
907 int freeColumn = -1;
908 colSpan = rowSpan = 1;
909 // First look to the right for a free column
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))) {
914 freeColumn = c;
915 break;
916 }
917 }
918 if (freeColumn != -1) {
919 removeEmptyCellsOnGrid(gridLayout, QRect(freeColumn, row, 1, 1));
920 column = freeColumn;
921 } else {
922 GridLayoutHelper::insertRow(gridLayout, row);
923 column = 0;
924 }
925 }
926 gridLayout->addWidget(w, row , column, rowSpan, colSpan);
927 }
928
929 void GridLayoutHelper::removeWidget(QLayout *lt, QWidget *widget)
930 {
931 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt);
932 Q_ASSERT(gridLayout);
933 const int index = gridLayout->indexOf(widget);
934 if (index == -1) {
935 qWarning() << "GridLayoutHelper::removeWidget : Attempt to remove " << widget << " which is not in the layout.";
936 return;
937 }
938 // delete old item and pad with by spacer items
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);
947 }
948
949 void GridLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after)
950 {
951 bool ok = false;
952 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
953 if (QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt)) {
954 const int index = gridLayout->indexOf(before);
955 if (index != -1) {
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);
960 if (visible)
961 before->hide();
962 before->setParent(nullptr);
963 gridLayout->addWidget(after, row, column, rowSpan, columnSpan);
964 ok = true;
965 }
966 }
967 if (!ok)
968 qWarning() << "GridLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt;
969 }
970
971 void GridLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout)
972 {
973 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
974 Q_ASSERT(gridLayout);
976 gs.fromLayout(gridLayout);
977 m_states.push(gs);
978 }
979
980 void GridLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout)
981 {
982 Q_ASSERT(!m_states.isEmpty());
983 const GridLayoutState state = m_states.pop();
984 state.applyToLayout(core, widgetWithManagedLayout);
985 }
986
987 bool GridLayoutHelper::canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const
988 {
989 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
990 Q_ASSERT(gridLayout);
992 gs.fromLayout(gridLayout);
993 return gs.simplify(restrictionArea, true);
994 }
995
996 void GridLayoutHelper::simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea)
997 {
998 QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
999 Q_ASSERT(gridLayout);
1000 if (debugLayout)
1001 qDebug() << ">GridLayoutHelper::simplify" << *gridLayout;
1002 GridLayoutState gs;
1003 gs.fromLayout(gridLayout);
1004 if (gs.simplify(restrictionArea, false))
1005 gs.applyToLayout(core, widgetWithManagedLayout);
1006 if (debugLayout)
1007 qDebug() << "<GridLayoutHelper::simplify" << *gridLayout;
1008 }
1009
1010 // ---------------- FormLayoutHelper
1012 public:
1014
1015 FormLayoutHelper() = default;
1016
1017 QRect itemInfo(QLayout *lt, int index) const override;
1018 void insertWidget(QLayout *lt, const QRect &info, QWidget *w) override;
1019 void removeWidget(QLayout *lt, QWidget *widget) override;
1020 void replaceWidget(QLayout *lt, QWidget *before, QWidget *after) override;
1021
1022 void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout) override;
1023 void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout) override;
1024
1025 bool canSimplify(const QDesignerFormEditorInterface *core, const QWidget *, const QRect &) const override;
1026 void simplify(const QDesignerFormEditorInterface *, QWidget *, const QRect &) override;
1027
1028 private:
1029 static FormLayoutState state(const QFormLayout *lt);
1030
1031 QStack<FormLayoutState> m_states;
1032 };
1033
1034 QRect FormLayoutHelper::itemInfo(QLayout * lt, int index) const
1035 {
1036 QFormLayout *form = qobject_cast<QFormLayout *>(lt);
1037 Q_ASSERT(form);
1038 int row, column, colspan;
1039 getFormLayoutItemPosition(form, index, &row, &column, nullptr, &colspan);
1040 return QRect(column, row, colspan, 1);
1041 }
1042
1043 void FormLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w)
1044 {
1045 if (debugLayout)
1046 qDebug() << "FormLayoutHelper::insertWidget:" << w << info;
1047 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
1048 QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt);
1049 Q_ASSERT(formLayout);
1050 // check if there are any nonspacer items? (Drop on 3rd column or drop of a multiselection
1051 // on an empty item. As the Form layout does not have insert semantics; we need to manually insert a row
1052 const bool insert = !removeEmptyCellsOnGrid(formLayout, info);
1053 formLayoutAddWidget(formLayout, w, info, insert);
1054 QLayoutSupport::createEmptyCells(formLayout);
1055 }
1056
1057 void FormLayoutHelper::removeWidget(QLayout *lt, QWidget *widget)
1058 {
1059 QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt);
1060 Q_ASSERT(formLayout);
1061 const int index = formLayout->indexOf(widget);
1062 if (index == -1) {
1063 qWarning() << "FormLayoutHelper::removeWidget : Attempt to remove " << widget << " which is not in the layout.";
1064 return;
1065 }
1066 // delete old item and pad with by spacer items
1067 int row, column, colspan;
1068 getFormLayoutItemPosition(formLayout, index, &row, &column, nullptr, &colspan);
1069 if (debugLayout)
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());
1076 }
1077
1078 void FormLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after)
1079 {
1080 bool ok = false;
1081 QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
1082 if (QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt)) {
1083 const int index = formLayout->indexOf(before);
1084 if (index != -1) {
1085 int row;
1086 QFormLayout::ItemRole role;
1087 formLayout->getItemPosition (index, &row, &role);
1088 const bool visible = before->isVisible();
1089 delete formLayout->takeAt(index);
1090 if (visible)
1091 before->hide();
1092 before->setParent(nullptr);
1093 formLayout->setWidget(row, role, after);
1094 ok = true;
1095 }
1096 }
1097 if (!ok)
1098 qWarning() << "FormLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt;
1099 }
1100
1101 FormLayoutHelper::FormLayoutState FormLayoutHelper::state(const QFormLayout *lt)
1102 {
1103 const int rowCount = lt->rowCount();
1104 if (rowCount == 0)
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)) {
1112 QWidget *w = item->widget();
1113 Q_ASSERT(w);
1114 getFormLayoutItemPosition(lt, i, &row, &column, nullptr, &colspan);
1115 if (colspan > 1 || column == 0)
1116 rc[row].first = w;
1117 if (colspan > 1 || column == 1)
1118 rc[row].second = w;
1119 }
1120 }
1121 if (debugLayout) {
1122 qDebug() << "FormLayoutHelper::state: " << rowCount;
1123 for (int r = 0; r < rowCount; r++)
1124 qDebug() << " Row: " << r << rc[r].first << rc[r].second;
1125 }
1126 return rc;
1127 }
1128
1129 void FormLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout)
1130 {
1131 QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
1132 Q_ASSERT(formLayout);
1133 m_states.push(state(formLayout));
1134 }
1135
1136 void FormLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout)
1137 {
1138 QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
1139 Q_ASSERT(!m_states.isEmpty() && formLayout);
1140
1141 const FormLayoutState storedState = m_states.pop();
1142 const FormLayoutState currentState = state(formLayout);
1143 if (currentState == storedState)
1144 return;
1145 const int rowCount = storedState.size();
1146 // clear out, shrink if required, but maintain items via map, pad spacers
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++) {
1151 QWidget *widgets[FormLayoutColumns] = { storedState[r].first, storedState[r].second };
1152 const bool spanning = widgets[0] != nullptr && widgets[0] == widgets[1];
1153 if (spanning) {
1154 formLayout->setWidget(r, QFormLayout::SpanningRole, widgets[0]);
1155 } else {
1156 for (int c = 0; c < FormLayoutColumns; c++) {
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]);
1160 } else {
1161 formLayout->setItem(r, role, createFormSpacer());
1162 }
1163 }
1164 }
1165 }
1166 }
1167
1168 bool FormLayoutHelper::canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const
1169 {
1170 const QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
1171 Q_ASSERT(formLayout);
1172 return canSimplifyFormLayout(formLayout, restrictionArea);
1173 }
1174
1175 void FormLayoutHelper::simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea)
1176 {
1177 using LayoutItemPair = std::pair<QLayoutItem*, QLayoutItem*>;
1178 using LayoutItemPairs = QList<LayoutItemPair>;
1179
1180 QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
1181 Q_ASSERT(formLayout);
1182 if (debugLayout)
1183 qDebug() << "FormLayoutHelper::simplify";
1184 // Transform into vector of item pairs
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);
1190 if (colspan > 1) {
1191 pairs[row].first = pairs[row].second = formLayout->takeAt(i);
1192 } else {
1193 if (col == 0)
1194 pairs[row].first = formLayout->takeAt(i);
1195 else
1196 pairs[row].second = formLayout->takeAt(i);
1197 }
1198 }
1199 // Weed out empty ones
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;
1205 pairs.remove(r);
1206 }
1207 const int simpleRowCount = pairs.size();
1208 if (simpleRowCount < rowCount)
1209 formLayout = static_cast<QFormLayout *>(recreateManagedLayout(core, widgetWithManagedLayout, formLayout));
1210 // repopulate
1211 for (int r = 0; r < simpleRowCount; r++) {
1212 const bool spanning = pairs[r].first == pairs[r].second;
1213 if (spanning) {
1214 formLayout->setItem(r, QFormLayout::SpanningRole, pairs[r].first);
1215 } else {
1216 formLayout->setItem(r, QFormLayout::LabelRole, pairs[r].first);
1217 formLayout->setItem(r, QFormLayout::FieldRole, pairs[r].second);
1218 }
1219 }
1220 }
1221
1223{
1224 LayoutHelper *rc = nullptr;
1225 switch (type) {
1226 case LayoutInfo::HBox:
1228 break;
1229 case LayoutInfo::VBox:
1230 rc = new BoxLayoutHelper(Qt::Vertical);
1231 break;
1232 case LayoutInfo::Grid:
1233 rc = new GridLayoutHelper;
1234 break;
1235 case LayoutInfo::Form:
1236 return new FormLayoutHelper;
1237 default:
1238 break;
1239 }
1240 Q_ASSERT(rc);
1241 return rc;
1242}
1243
1244// ---- QLayoutSupport (LayoutDecorationExtension)
1254
1259
1261{
1262 if (m_indicators[i])
1263 m_indicators[i]->hide();
1264}
1265
1267{
1268 if (!m_indicators[i])
1274 indicator->show();
1275 indicator->raise();
1276}
1277
1279{
1280 delete m_helper;
1281 for (const QPointer<QWidget> &w : m_indicators) {
1282 if (!w.isNull())
1283 w->deleteLater();
1284 }
1285}
1286
1291
1296
1301
1303{
1305}
1306
1308{
1309 if (index == -1) { // first item goes anywhere
1314 return;
1315 }
1318
1320 const QRect g = extendedGeometry(index);
1321 // ### cleanup
1322 if (LayoutInfo::isEmptyItem(item)) {
1323 // Empty grid/form cell. Draw a rectangle
1326
1332 } else {
1333 // Append/Insert. Draw a bar left/right or above/below
1338
1339 const int fromRight = g.right() - pos.x();
1340 const int fromBottom = g.bottom() - pos.y();
1341
1342 const int fromLeft = pos.x() - g.x();
1343 const int fromTop = pos.y() - g.y();
1344
1345 const int fromLeftRight = qMin(fromRight, fromLeft );
1346 const int fromBottomTop = qMin(fromBottom, fromTop);
1347
1349
1351 const QRect r(layout()->geometry().topLeft(), layout()->parentWidget()->size());
1352 switch (indicatorOrientation) {
1353 case Qt::Vertical: {
1355 const bool closeToLeft = fromLeftRight == fromLeft;
1357
1358 const QWidget *parent = layout()->parentWidget();
1360 const int incr = leftToRight == closeToLeft ? 0 : +1;
1362 }
1363 break;
1364 case Qt::Horizontal: {
1366 const bool closeToTop = fromBottomTop == fromTop;
1368
1369 const int incr = closeToTop ? 0 : +1;
1371 }
1372 break;
1373 }
1374 } else {
1377 } // can handle indicatorOrientation
1378 }
1379}
1380
1382{
1383 const QLayout *lt = layout();
1384 if (!lt)
1385 return -1;
1386
1387 int index = 0;
1388
1389 while (QLayoutItem *item = lt->itemAt(index)) {
1390 if (item == i)
1391 return index;
1392
1393 ++index;
1394 }
1395
1396 return -1;
1397}
1398
1400{
1401 const QLayout *lt = layout();
1402 if (!lt)
1403 return -1;
1404
1405 int index = 0;
1406 while (QLayoutItem *item = lt->itemAt(index)) {
1407 if (item->widget() == widget)
1408 return index;
1409
1410 ++index;
1411 }
1412
1413 return -1;
1414}
1415
1417{
1418 if (!layout)
1419 return QWidgetList();
1420
1422 int index = 0;
1423 while (QLayoutItem *item = layout->itemAt(index)) {
1424 ++index;
1425
1426 QWidget *widget = item->widget();
1427 if (widget && formWindow()->isManaged(widget))
1428 lst.append(widget);
1429 }
1430
1431 return lst;
1432}
1433
1438
1439// Quick check whether simplify should be enabled for grids. May return false positives.
1440// Note: Calculating the occupied area does not work as spanning items may also be simplified.
1441
1443{
1444 if (!gl)
1445 return false;
1446 const int colCount = gl->columnCount();
1447 const int rowCount = gl->rowCount();
1448 if (colCount < 2 || rowCount < 2)
1449 return false;
1450 // try to find a spacer.
1451 const int count = gl->count();
1452 for (int index = 0; index < count; index++)
1454 return true;
1455 return false;
1456}
1457
1459{
1460 return canSimplifyFormLayout(fl, QRect(QPoint(0, 0), QSize(32767, 32767)));
1461}
1462
1463// remove dummy spacers
1468
1470{
1474
1476 for (int c = 0; c < gs.colCount; c++)
1477 for (int r = 0; r < gs.rowCount; r++)
1478 if (needsSpacerItem(cs[r * gs.colCount + c])) {
1479 const int existingItemIndex = findItemAt(gridLayout, r, c);
1480 if (existingItemIndex == -1)
1482 }
1483}
1484
1489
1491{
1492 // No spanning items here..
1493 if (const int rowCount = formLayout->rowCount())
1494 for (int c = 0; c < FormLayoutColumns; c++)
1495 for (int r = 0; r < rowCount; r++)
1496 if (findGridItemAt(formLayout, r, c) == -1)
1498}
1499
1501{
1502 if (!layout())
1503 return -1;
1504
1505 const QLayout *lt = layout();
1506 const int count = lt->count();
1507
1508 if (count == 0)
1509 return -1;
1510
1511 int best = -1;
1512 int bestIndex = -1;
1513
1514 for (int index = 0; index < count; index++) {
1516 bool visible = true;
1517 // When dragging widgets within layout, the source widget is invisible and must not be hit
1518 if (const QWidget *w = item->widget())
1519 visible = w->isVisible();
1520 if (visible) {
1521 const QRect g = item->geometry();
1522
1523 const int dist = (g.center() - pos).manhattanLength();
1524 if (best == -1 || dist < best) {
1525 best = dist;
1526 bestIndex = index;
1527 }
1528 }
1529 }
1530 return bestIndex;
1531}
1532
1533// ------------ QBoxLayoutSupport (LayoutDecorationExtension)
1534namespace {
1535class QBoxLayoutSupport: public QLayoutSupport
1536{
1537public:
1538 QBoxLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, Qt::Orientation orientation, QObject *parent = nullptr);
1539
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 /*row*/) override {}
1544 void insertColumn(int /*column*/) override {}
1545
1546 int findItemAt(int /*at_row*/, int /*at_column*/) const override { return -1; }
1547 using QLayoutSupport::findItemAt;
1548
1549private:
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;
1554
1555 const Qt::Orientation m_orientation;
1556};
1557
1558void QBoxLayoutSupport::removeWidget(QWidget *widget)
1559{
1560 QLayout *lt = layout();
1561 const int index = lt->indexOf(widget);
1562 // Adjust the current cell in case a widget was dragged within the same layout to a position
1563 // of higher index, which happens as follows:
1564 // Drag start: The widget is hidden
1565 // Drop: Current cell is stored, widget is removed and re-added, causing an index offset that needs to be compensated
1566 std::pair<int, int> currCell = currentCell();
1567 switch (m_orientation) {
1568 case Qt::Horizontal:
1569 if (currCell.second > 0 && index < currCell.second ) {
1570 currCell.second--;
1571 setCurrentCell(currCell);
1572 }
1573 break;
1574 case Qt::Vertical:
1575 if (currCell.first > 0 && index < currCell.first) {
1576 currCell.first--;
1577 setCurrentCell(currCell);
1578 }
1579 break;
1580 }
1581 helper()->removeWidget(lt, widget);
1582}
1583
1584QBoxLayoutSupport::QBoxLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, Qt::Orientation orientation, QObject *parent) :
1585 QLayoutSupport(formWindow, widget, new BoxLayoutHelper(orientation), parent),
1586 m_orientation(orientation)
1587{
1588}
1589
1590void QBoxLayoutSupport::setCurrentCellFromIndicatorOnEmptyCell(int index)
1591{
1592 qDebug() << "QBoxLayoutSupport::setCurrentCellFromIndicatorOnEmptyCell(): Warning: found a fake spacer inside a vbox layout at " << index;
1593 setCurrentCell({0, 0});
1594}
1595
1596void QBoxLayoutSupport::insertWidget(QWidget *widget, const std::pair<int, int> &cell)
1597{
1598 switch (m_orientation) {
1599 case Qt::Horizontal:
1600 helper()->insertWidget(layout(), QRect(cell.second, 0, 1, 1), widget);
1601 break;
1602 case Qt::Vertical:
1603 helper()->insertWidget(layout(), QRect(0, cell.first, 1, 1), widget);
1604 break;
1605 }
1606}
1607
1608void QBoxLayoutSupport::setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment)
1609{
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});
1614}
1615
1616bool QBoxLayoutSupport::supportsIndicatorOrientation(Qt::Orientation indicatorOrientation) const
1617{
1618 return m_orientation != indicatorOrientation;
1619}
1620
1621QRect QBoxLayoutSupport::extendedGeometry(int index) const
1622{
1623 QLayoutItem *item = layout()->itemAt(index);
1624 // start off with item geometry
1625 QRect g = item->geometry();
1626
1627 const QRect info = itemInfo(index);
1628
1629 // On left border: extend to widget border
1630 if (info.x() == 0) {
1631 QPoint topLeft = g.topLeft();
1632 topLeft.rx() = layout()->geometry().left();
1633 g.setTopLeft(topLeft);
1634 }
1635
1636 // On top border: extend to widget border
1637 if (info.y() == 0) {
1638 QPoint topLeft = g.topLeft();
1639 topLeft.ry() = layout()->geometry().top();
1640 g.setTopLeft(topLeft);
1641 }
1642
1643 // is this the last item?
1644 const QBoxLayout *box = static_cast<const QBoxLayout*>(layout());
1645 if (index < box->count() -1)
1646 return g; // Nope.
1647
1648 // extend to widget border
1649 QPoint bottomRight = g.bottomRight();
1650 switch (m_orientation) {
1651 case Qt::Vertical:
1652 bottomRight.ry() = layout()->geometry().bottom();
1653 break;
1654 case Qt::Horizontal:
1655 bottomRight.rx() = layout()->geometry().right();
1656 break;
1657 }
1658 g.setBottomRight(bottomRight);
1659 return g;
1660}
1661
1662// -------------- Base class for QGridLayout-like support classes (LayoutDecorationExtension)
1663template <class GridLikeLayout>
1664class GridLikeLayoutSupportBase: public QLayoutSupport
1665{
1666public:
1667
1668 GridLikeLayoutSupportBase(QDesignerFormWindowInterface *formWindow, QWidget *widget, LayoutHelper *helper, QObject *parent = nullptr) :
1669 QLayoutSupport(formWindow, widget, helper, parent) {}
1670
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;
1675
1676protected:
1677 GridLikeLayout *gridLikeLayout() const {
1678 return qobject_cast<GridLikeLayout*>(LayoutInfo::managedLayout(formWindow()->core(), widget()));
1679 }
1680
1681private:
1682
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; }
1686
1687 QRect extendedGeometry(int index) const override;
1688
1689 // Overwrite to check the insertion position (if there are limits)
1690 virtual void checkCellForInsertion(int * /*row*/, int * /*col*/) const {}
1691};
1692
1693template <class GridLikeLayout>
1694void GridLikeLayoutSupportBase<GridLikeLayout>::setCurrentCellFromIndicatorOnEmptyCell(int index)
1695{
1696 GridLikeLayout *grid = gridLikeLayout();
1697 Q_ASSERT(grid);
1698
1699 setInsertMode(InsertWidgetMode);
1700 int row, column, rowspan, colspan;
1701
1702 getGridItemPosition(grid, index, &row, &column, &rowspan, &colspan);
1703 setCurrentCell({row, column});
1704}
1705
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});
1716 }
1717 break;
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});
1724 }
1725 break;
1726 }
1727}
1728
1729template <class GridLikeLayout>
1730void GridLikeLayoutSupportBase<GridLikeLayout>::insertWidget(QWidget *widget, const std::pair<int, int> &cell)
1731{
1732 helper()->insertWidget(layout(), QRect(cell.second, cell.first, 1, 1), widget);
1733}
1734
1735template <class GridLikeLayout>
1736int GridLikeLayoutSupportBase<GridLikeLayout>::findItemAt(int at_row, int at_column) const
1737{
1738 GridLikeLayout *grid = gridLikeLayout();
1739 Q_ASSERT(grid);
1740 return findGridItemAt(grid, at_row, at_column);
1741}
1742
1743template <class GridLikeLayout>
1744QRect GridLikeLayoutSupportBase<GridLikeLayout>::extendedGeometry(int index) const
1745{
1746 QLayoutItem *item = layout()->itemAt(index);
1747 // start off with item geometry
1748 QRect g = item->geometry();
1749
1750 const QRect info = itemInfo(index);
1751
1752 // On left border: extend to widget border
1753 if (info.x() == 0) {
1754 QPoint topLeft = g.topLeft();
1755 topLeft.rx() = layout()->geometry().left();
1756 g.setTopLeft(topLeft);
1757 }
1758
1759 // On top border: extend to widget border
1760 if (info.y() == 0) {
1761 QPoint topLeft = g.topLeft();
1762 topLeft.ry() = layout()->geometry().top();
1763 g.setTopLeft(topLeft);
1764 }
1765 const GridLikeLayout *grid = gridLikeLayout();
1766 Q_ASSERT(grid);
1767
1768 // extend to widget border
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);
1775 return g;
1776}
1777
1778// -------------- QGridLayoutSupport (LayoutDecorationExtension)
1779class QGridLayoutSupport: public GridLikeLayoutSupportBase<QGridLayout>
1780{
1781public:
1782
1783 QGridLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent = nullptr);
1784
1785 void simplify() override;
1786 void insertRow(int row) override;
1787 void insertColumn(int column) override;
1788
1789private:
1790};
1791
1792QGridLayoutSupport::QGridLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent) :
1793 GridLikeLayoutSupportBase<QGridLayout>(formWindow, widget, new GridLayoutHelper, parent)
1794{
1795}
1796
1797void QGridLayoutSupport::insertRow(int row)
1798{
1799 QGridLayout *grid = gridLayout();
1800 Q_ASSERT(grid);
1802}
1803
1804void QGridLayoutSupport::insertColumn(int column)
1805{
1806 QGridLayout *grid = gridLayout();
1807 Q_ASSERT(grid);
1808 GridLayoutState state;
1809 state.fromLayout(grid);
1810 state.insertColumn(column);
1811 state.applyToLayout(formWindow()->core(), widget());
1812}
1813
1814void QGridLayoutSupport::simplify()
1815{
1816 QGridLayout *grid = gridLayout();
1817 Q_ASSERT(grid);
1818 GridLayoutState state;
1819 state.fromLayout(grid);
1820
1821 const QRect fullArea = QRect(0, 0, state.colCount, state.rowCount);
1822 if (state.simplify(fullArea, false))
1823 state.applyToLayout(formWindow()->core(), widget());
1824}
1825
1826// -------------- QFormLayoutSupport (LayoutDecorationExtension)
1827class QFormLayoutSupport: public GridLikeLayoutSupportBase<QFormLayout>
1828{
1829public:
1830 QFormLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent = nullptr);
1831
1832 void simplify() override {}
1833 void insertRow(int /*row*/) override {}
1834 void insertColumn(int /*column*/) override {}
1835
1836private:
1837 void checkCellForInsertion(int * row, int *col) const override;
1838};
1839
1840QFormLayoutSupport::QFormLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent) :
1841 GridLikeLayoutSupportBase<QFormLayout>(formWindow, widget, new FormLayoutHelper, parent)
1842{
1843}
1844
1845void QFormLayoutSupport::checkCellForInsertion(int *row, int *col) const
1846{
1847 if (*col >= FormLayoutColumns) { // Clamp to 2 columns
1848 *col = 1;
1849 (*row)++;
1850 }
1851}
1852} // anonymous namespace
1853
1855{
1858 QLayoutSupport *rc = nullptr;
1859 switch (LayoutInfo::layoutType(formWindow->core(), layout)) {
1860 case LayoutInfo::HBox:
1862 break;
1863 case LayoutInfo::VBox:
1865 break;
1866 case LayoutInfo::Grid:
1868 break;
1869 case LayoutInfo::Form:
1871 break;
1872 default:
1873 break;
1874 }
1875 Q_ASSERT(rc);
1876 return rc;
1877}
1878} // namespace qdesigner_internal
1879
1880// -------------- QLayoutWidget
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)
1884{
1885}
1886
1887void QLayoutWidget::paintEvent(QPaintEvent*)
1888{
1889 if (m_formWindow->currentTool() != 0)
1890 return;
1891
1892 // only draw red borders if we're editting widgets
1893
1894 QPainter p(this);
1895
1896 QMap<int, QMap<int, bool> > excludedRowsForColumn;
1897 QMap<int, QMap<int, bool> > excludedColumnsForRow;
1898
1899 QLayout *lt = layout();
1900 QGridLayout *grid = qobject_cast<QGridLayout *>(lt);
1901 if (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);
1906 if (grid) {
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;
1915
1916 while (rowSpan > 0) {
1917 excludedColumnsForRow[row + rowSpan - 1].insert(columns);
1918 rowSpan--;
1919 }
1920 while (columnSpan > 0) {
1921 excludedRowsForColumn[column + columnSpan - 1].insert(rows);
1922 columnSpan--;
1923 }
1924 }
1925 if (item->spacerItem()) {
1926 const QRect geometry = item->geometry();
1927 if (!geometry.isNull())
1928 p.drawRect(geometry.adjusted(1, 1, -2, -2));
1929 }
1930 }
1931 }
1932 }
1933 if (grid) {
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));
1947 }
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));
1955 }
1956 }
1957 }
1958 }
1959 p.setPen(QPen(QColor(255, 0, 0, 128), 1));
1960 p.drawRect(0, 0, width() - 1, height() - 1);
1961}
1962
1963bool QLayoutWidget::event(QEvent *e)
1964{
1965 switch (e->type()) {
1966 case QEvent::LayoutRequest: {
1967 (void) QWidget::event(e);
1968 // Magic: We are layouted, but the parent is not..
1969 if (layout() && qdesigner_internal::LayoutInfo::layoutType(formWindow()->core(), parentWidget()) == qdesigner_internal::LayoutInfo::NoLayout) {
1970 resize(layout()->totalMinimumSize().expandedTo(size()));
1971 }
1972
1973 update();
1974
1975 return true;
1976 }
1977
1978 default:
1979 break;
1980 }
1981
1982 return QWidget::event(e);
1983}
1984
1985int QLayoutWidget::layoutLeftMargin() const
1986{
1987 if (m_leftMargin < 0 && layout()) {
1988 int margin;
1989 layout()->getContentsMargins(&margin, nullptr, nullptr, nullptr);
1990 return margin;
1991 }
1992 return m_leftMargin;
1993}
1994
1995void QLayoutWidget::setLayoutLeftMargin(int layoutMargin)
1996{
1997 m_leftMargin = layoutMargin;
1998 if (layout()) {
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);
2005 }
2006}
2007
2008int QLayoutWidget::layoutTopMargin() const
2009{
2010 if (m_topMargin < 0 && layout()) {
2011 int margin;
2012 layout()->getContentsMargins(nullptr, &margin, nullptr, nullptr);
2013 return margin;
2014 }
2015 return m_topMargin;
2016}
2017
2018void QLayoutWidget::setLayoutTopMargin(int layoutMargin)
2019{
2020 m_topMargin = layoutMargin;
2021 if (layout()) {
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);
2028 }
2029}
2030
2031int QLayoutWidget::layoutRightMargin() const
2032{
2033 if (m_rightMargin < 0 && layout()) {
2034 int margin;
2035 layout()->getContentsMargins(nullptr, nullptr, &margin, nullptr);
2036 return margin;
2037 }
2038 return m_rightMargin;
2039}
2040
2041void QLayoutWidget::setLayoutRightMargin(int layoutMargin)
2042{
2043 m_rightMargin = layoutMargin;
2044 if (layout()) {
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);
2051 }
2052}
2053
2054int QLayoutWidget::layoutBottomMargin() const
2055{
2056 if (m_bottomMargin < 0 && layout()) {
2057 int margin;
2058 layout()->getContentsMargins(nullptr, nullptr, nullptr, &margin);
2059 return margin;
2060 }
2061 return m_bottomMargin;
2062}
2063
2064void QLayoutWidget::setLayoutBottomMargin(int layoutMargin)
2065{
2066 m_bottomMargin = layoutMargin;
2067 if (layout()) {
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);
2074 }
2075}
2076
2077QT_END_NAMESPACE
friend class QWidget
Definition qpainter.h:431
BoxLayoutHelper(const Qt::Orientation orientation)
void simplify(const QDesignerFormEditorInterface *, QWidget *, const QRect &) override
void replaceWidget(QLayout *lt, QWidget *before, QWidget *after) override
void insertWidget(QLayout *lt, const QRect &info, QWidget *w) override
QRect itemInfo(QLayout *lt, int index) const override
static QLayoutItem * findItemOfWidget(const LayoutItemVector &lv, QWidget *w)
void popState(const QDesignerFormEditorInterface *, QWidget *) override
void removeWidget(QLayout *lt, QWidget *widget) override
bool canSimplify(const QDesignerFormEditorInterface *, const QWidget *, const QRect &) const override
static LayoutItemVector disassembleLayout(QLayout *lt)
void pushState(const QDesignerFormEditorInterface *, const QWidget *) override
void replaceWidget(QLayout *lt, QWidget *before, QWidget *after) override
void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout) override
void simplify(const QDesignerFormEditorInterface *, QWidget *, const QRect &) override
void insertWidget(QLayout *lt, const QRect &info, QWidget *w) override
bool canSimplify(const QDesignerFormEditorInterface *core, const QWidget *, const QRect &) const override
void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout) override
QRect itemInfo(QLayout *lt, int index) const override
void removeWidget(QLayout *lt, QWidget *widget) override
void simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea) override
QRect itemInfo(QLayout *lt, int index) const override
void replaceWidget(QLayout *lt, QWidget *before, QWidget *after) override
void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout) override
void insertWidget(QLayout *lt, const QRect &info, QWidget *w) override
bool canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const override
static void insertRow(QGridLayout *grid, int row)
void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout) override
void removeWidget(QLayout *lt, QWidget *widget) override
Qt::Orientations expandingDirections() const override
Returns whether this layout item can make use of more space than sizeHint().
Auxiliary methods to store/retrieve settings.
static const char * marginPropertyNamesC[]
static constexpr auto labelAlignmentPropertyC
static bool intValueFromSheet(const QDesignerPropertySheetExtension *sheet, const QString &name, int *value, bool *changed)
static constexpr auto boxStretchPropertyC
static constexpr auto gridColumnStretchPropertyC
static constexpr auto rowWrapPolicyPropertyC
QDESIGNER_SHARED_EXPORT void getFormLayoutItemPosition(const QFormLayout *formLayout, int index, int *rowPtr, int *columnPtr=nullptr, int *rowspanPtr=nullptr, int *colspanPtr=nullptr)
static bool intValueToSheet(QDesignerPropertySheetExtension *sheet, const QString &name, int value, bool changed, bool applyChanged)
static bool needsSpacerItem(const GridLayoutState::CellState &cs)
static void variantPropertyToSheet(int mask, int flag, bool applyChanged, QDesignerPropertySheetExtension *sheet, const QString &name, const QVariant &value, bool changed, int *returnMask)
static const char * spacingPropertyNamesC[]
static constexpr auto gridRowMinimumHeightPropertyC
static constexpr auto fieldGrowthPolicyPropertyC
static void variantPropertyFromSheet(int mask, int flag, const QDesignerPropertySheetExtension *sheet, const QString &name, QVariant *value, bool *changed, int *returnMask)
static constexpr auto gridColumnMinimumWidthPropertyC
static constexpr auto formAlignmentPropertyC
static constexpr auto gridRowStretchPropertyC
static constexpr auto objectNameC
static bool isEmptyFormLayoutRow(const QFormLayout *fl, int row)
@ indicatorSize
static bool removeEmptyCellsOnGrid(GridLikeLayout *grid, const QRect &area)
static QSpacerItem * createGridSpacer()
static bool canSimplifyFormLayout(const QFormLayout *formLayout, const QRect &restrictionArea)
static QLayout * recreateManagedLayout(const QDesignerFormEditorInterface *core, QWidget *w, QLayout *lt)
static constexpr auto vertSizeConstraintC
@ debugLayout
@ ShiftValue
int findGridItemAt(GridLikeLayout *gridLayout, int at_row, int at_column)
static QDebug debugGridLikeLayout(QDebug str, const GridLikeLayout &gl)
@ FormLayoutColumns
static QSpacerItem * createFormSpacer()
static constexpr auto horizSizeConstraintC
static CellStates cellStates(const QList< QRect > &rects, int numRows, int numColumns)
std::pair< DimensionCellState, DimensionCellState > CellState
void applyToLayout(const QDesignerFormEditorInterface *core, QWidget *w) const
bool simplify(const QRect &r, bool testOnly)
QHash< QWidget *, Qt::Alignment > widgetAlignmentMap
QHash< QWidget *, QRect > widgetItemMap