diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index baf80e3fe7f..fd953d24934 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -216,9 +216,7 @@ void BaseAspect::addLabeledItem(Layouting::LayoutBuilder &builder, QWidget *widg if (QLabel *l = label()) { l->setBuddy(widget); builder.addItem(l); - LayoutItem item(widget); - item.span = std::max(d->m_spanX - 1, 1); - builder.addItem(item); + builder.addItem(Span(std::max(d->m_spanX - 1, 1), LayoutItem(widget))); } else { builder.addItem(LayoutItem(widget)); } @@ -425,13 +423,23 @@ void BaseAspect::addToLayout(LayoutBuilder &) { } -void doLayout(const BaseAspect &aspect, LayoutBuilder &builder) +void createItem(Layouting::LayoutItem *item, const BaseAspect &aspect) { - const_cast(aspect).addToLayout(builder); - if (builder.layoutType() == LayoutBuilder::FormLayout || builder.layoutType() == LayoutBuilder::VBoxLayout) - builder.finishRow(); + item->onAdd = [&aspect](LayoutBuilder &builder) { + const_cast(aspect).addToLayout(builder); + builder.addItem(br); + }; } +void createItem(Layouting::LayoutItem *item, const BaseAspect *aspect) +{ + item->onAdd = [aspect](LayoutBuilder &builder) { + const_cast(aspect)->addToLayout(builder); + builder.addItem(br); + }; +} + + /*! Updates this aspect's value from user-initiated changes in the widget. @@ -1063,7 +1071,7 @@ void StringAspect::addToLayout(Layouting::LayoutBuilder &builder) { if (d->m_checker && d->m_checkBoxPlacement == CheckBoxPlacement::Top) { d->m_checker->addToLayout(builder); - builder.finishRow(); + builder.addItem(br); } const auto useMacroExpander = [this](QWidget *w) { @@ -1404,8 +1412,7 @@ void BoolAspect::addToLayout(Layouting::LayoutBuilder &builder) break; case LabelPlacement::AtCheckBox: { d->m_checkBox->setText(labelText()); - Layouting::LayoutBuilder::LayoutType type = builder.layoutType(); - if (type == LayoutBuilder::FormLayout) + if (builder.isForm()) builder.addItem(createSubWidget()); builder.addItem(d->m_checkBox.data()); break; @@ -1566,7 +1573,8 @@ void SelectionAspect::addToLayout(Layouting::LayoutBuilder &builder) button->setChecked(i == value()); button->setEnabled(option.enabled); button->setToolTip(option.tooltip); - builder.addItems({Layouting::empty, button}); + builder.addItem(Layouting::empty); + builder.addItem(button); d->m_buttons.append(button); d->m_buttonGroup->addButton(button, i); if (isAutoApply()) { @@ -2284,7 +2292,7 @@ TextDisplay::~TextDisplay() = default; /*! \reimp */ -void TextDisplay::addToLayout(LayoutBuilder &builder) +void TextDisplay::addToLayout(Layouting::LayoutBuilder &builder) { if (!d->m_label) { d->m_label = createSubWidget(d->m_message, d->m_type); diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 9950fbef61a..3eae9ffaea1 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -18,7 +18,10 @@ class QAction; class QSettings; QT_END_NAMESPACE -namespace Layouting { class LayoutBuilder; } +namespace Layouting { +class LayoutItem; +class LayoutBuilder; +} namespace Utils { @@ -204,7 +207,8 @@ private: std::unique_ptr d; }; -QTCREATOR_UTILS_EXPORT void doLayout(const BaseAspect &aspect, Layouting::LayoutBuilder &builder); +QTCREATOR_UTILS_EXPORT void createItem(Layouting::LayoutItem *item, const BaseAspect &aspect); +QTCREATOR_UTILS_EXPORT void createItem(Layouting::LayoutItem *item, const BaseAspect *aspect); class QTCREATOR_UTILS_EXPORT BoolAspect : public BaseAspect { diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index e86e69a8302..c7ead009c74 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -10,10 +10,12 @@ #include #include #include +#include #include #include #include #include +#include namespace Layouting { @@ -26,20 +28,7 @@ namespace Layouting { /*! - \enum Utils::LayoutBuilder::LayoutType - \inmodule QtCreator - - The LayoutType enum describes the type of \c QLayout a layout builder - operates on. - - \value Form - \value Grid - \value HBox - \value VBox -*/ - -/*! - \class Utils::LayoutBuilder::LayoutItem + \class Layouting::LayoutItem \inmodule QtCreator \brief The LayoutItem class represents widgets, layouts, and aggregate @@ -53,8 +42,9 @@ namespace Layouting { /*! Constructs a layout item instance representing an empty cell. */ -LayoutItem::LayoutItem() -{} +LayoutItem::LayoutItem() = default; + +LayoutItem::~LayoutItem() = default; /*! @@ -70,47 +60,38 @@ LayoutItem::LayoutItem() \endlist */ - -/*! - Constructs a layout item representing something that knows how to add it - to a layout by itself. - */ -QLayout *LayoutBuilder::createLayout() const +struct ResultItem { + ResultItem() = default; + explicit ResultItem(QLayout *l) : layout(l) {} + explicit ResultItem(QWidget *w) : widget(w) {} + + QString text; QLayout *layout = nullptr; - switch (m_layoutType) { - case LayoutBuilder::FormLayout: { - auto formLayout = new QFormLayout; - formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); - layout = formLayout; - break; - } - case LayoutBuilder::GridLayout: { - auto gridLayout = new QGridLayout; - layout = gridLayout; - break; - } - case LayoutBuilder::HBoxLayout: { - auto hboxLayout = new QHBoxLayout; - layout = hboxLayout; - break; - } - case LayoutBuilder::VBoxLayout: { - auto vboxLayout = new QVBoxLayout; - layout = vboxLayout; - break; - } - case LayoutBuilder::StackLayout: { - auto stackLayout = new QStackedLayout; - layout = stackLayout; - break; - } - } - QTC_ASSERT(layout, return nullptr); - if (m_spacing) - layout->setSpacing(*m_spacing); - return layout; -} + QWidget *widget = nullptr; + int space = -1; + int stretch = -1; + int span = 1; +}; + +struct LayoutBuilder::Slice +{ + Slice() = default; + Slice(QLayout *l) : layout(l) {} + Slice(QWidget *w) : widget(w) {} + Slice(QWidget *w, AttachType a) : widget(w), attachType(a) {} + + QLayout *layout = nullptr; + QWidget *widget = nullptr; + + void flush(); + + int currentGridColumn = 0; + int currentGridRow = 0; + + AttachType attachType = WithMargins; + QList pendingItems; +}; static QWidget *widgetForItem(QLayoutItem *item) { @@ -135,18 +116,16 @@ static QLabel *createLabel(const QString &text) return label; } -static void addItemToBoxLayout(QBoxLayout *layout, const LayoutItem &item) +static void addItemToBoxLayout(QBoxLayout *layout, const ResultItem &item) { if (QWidget *w = item.widget) { layout->addWidget(w); } else if (QLayout *l = item.layout) { layout->addLayout(l); - } else if (item.specialType == LayoutItem::SpecialType::Stretch) { - layout->addStretch(item.specialValue.toInt()); - } else if (item.specialType == LayoutItem::SpecialType::Space) { - layout->addSpacing(item.specialValue.toInt()); - } else if (item.specialType == LayoutItem::SpecialType::HorizontalRule) { - layout->addWidget(Layouting::createHr()); + } else if (item.stretch != -1) { + layout->addStretch(item.stretch); + } else if (item.space != -1) { + layout->addSpacing(item.space); } else if (!item.text.isEmpty()) { layout->addWidget(createLabel(item.text)); } else { @@ -154,138 +133,168 @@ static void addItemToBoxLayout(QBoxLayout *layout, const LayoutItem &item) } } -static void flushPendingFormItems(QFormLayout *formLayout, - LayoutBuilder::LayoutItems &pendingFormItems) +void LayoutBuilder::Slice::flush() { - QTC_ASSERT(formLayout, return); - - if (pendingFormItems.empty()) + if (pendingItems.empty()) return; - // If there are more than two items, we cram the last ones in one hbox. - if (pendingFormItems.size() > 2) { - auto hbox = new QHBoxLayout; - hbox->setContentsMargins(0, 0, 0, 0); - for (int i = 1; i < pendingFormItems.size(); ++i) - addItemToBoxLayout(hbox, pendingFormItems.at(i)); - while (pendingFormItems.size() >= 2) - pendingFormItems.pop_back(); - pendingFormItems.append(LayoutItem(hbox)); - } + if (auto formLayout = qobject_cast(layout)) { - if (pendingFormItems.size() == 1) { // One one item given, so this spans both columns. - if (auto layout = pendingFormItems.at(0).layout) - formLayout->addRow(layout); - else if (auto widget = pendingFormItems.at(0).widget) - formLayout->addRow(widget); - } else if (pendingFormItems.size() == 2) { // Normal case, both columns used. - if (auto label = pendingFormItems.at(0).widget) { - if (auto layout = pendingFormItems.at(1).layout) - formLayout->addRow(label, layout); - else if (auto widget = pendingFormItems.at(1).widget) - formLayout->addRow(label, widget); - } else { - if (auto layout = pendingFormItems.at(1).layout) - formLayout->addRow(pendingFormItems.at(0).text, layout); - else if (auto widget = pendingFormItems.at(1).widget) - formLayout->addRow(pendingFormItems.at(0).text, widget); + // If there are more than two items, we cram the last ones in one hbox. + if (pendingItems.size() > 2) { + auto hbox = new QHBoxLayout; + hbox->setContentsMargins(0, 0, 0, 0); + for (int i = 1; i < pendingItems.size(); ++i) + addItemToBoxLayout(hbox, pendingItems.at(i)); + while (pendingItems.size() > 1) + pendingItems.pop_back(); + pendingItems.append(ResultItem(hbox)); } + + if (pendingItems.size() == 1) { // One one item given, so this spans both columns. + const ResultItem &f0 = pendingItems.at(0); + if (auto layout = f0.layout) + formLayout->addRow(layout); + else if (auto widget = f0.widget) + formLayout->addRow(widget); + } else if (pendingItems.size() == 2) { // Normal case, both columns used. + ResultItem &f1 = pendingItems[1]; + const ResultItem &f0 = pendingItems.at(0); + if (!f1.widget && !f1.layout && !f1.text.isEmpty()) + f1.widget = createLabel(f1.text); + + if (f0.widget) { + if (f1.layout) + formLayout->addRow(f0.widget, f1.layout); + else if (f1.widget) + formLayout->addRow(f0.widget, f1.widget); + } else { + if (f1.layout) + formLayout->addRow(f0.text, f1.layout); + else if (f1.widget) + formLayout->addRow(f0.text, f1.widget); + } + } else { + QTC_CHECK(false); + } + + // Set up label as buddy if possible. + const int lastRow = formLayout->rowCount() - 1; + QLayoutItem *l = formLayout->itemAt(lastRow, QFormLayout::LabelRole); + QLayoutItem *f = formLayout->itemAt(lastRow, QFormLayout::FieldRole); + if (l && f) { + if (QLabel *label = qobject_cast(l->widget())) { + if (QWidget *widget = widgetForItem(f)) + label->setBuddy(widget); + } + } + + } else if (auto gridLayout = qobject_cast(layout)) { + + for (const ResultItem &item : std::as_const(pendingItems)) { + Qt::Alignment align = {}; + // if (attachType == Layouting::WithFormAlignment && currentGridColumn == 0) + // align = Qt::Alignment(m_widget->style()->styleHint(QStyle::SH_FormLayoutLabelAlignment)); + if (item.widget) + gridLayout->addWidget(item.widget, currentGridRow, currentGridColumn, 1, item.span, align); + else if (item.layout) + gridLayout->addLayout(item.layout, currentGridRow, currentGridColumn, 1, item.span, align); + else if (!item.text.isEmpty()) + gridLayout->addWidget(createLabel(item.text), currentGridRow, currentGridColumn, 1, 1, align); + currentGridColumn += item.span; + } + ++currentGridRow; + currentGridColumn = 0; + + } else if (auto boxLayout = qobject_cast(layout)) { + + for (const ResultItem &item : std::as_const(pendingItems)) + addItemToBoxLayout(boxLayout, item); + + } else if (auto stackLayout = qobject_cast(layout)) { + for (const ResultItem &item : std::as_const(pendingItems)) { + if (item.widget) + stackLayout->addWidget(item.widget); + else + QTC_CHECK(false); + } + } else { QTC_CHECK(false); } - // Set up label as buddy if possible. - const int lastRow = formLayout->rowCount() - 1; - QLayoutItem *l = formLayout->itemAt(lastRow, QFormLayout::LabelRole); - QLayoutItem *f = formLayout->itemAt(lastRow, QFormLayout::FieldRole); - if (l && f) { - if (QLabel *label = qobject_cast(l->widget())) { - if (QWidget *widget = widgetForItem(f)) - label->setBuddy(widget); - } + pendingItems.clear(); +} + +static void addItemHelper(LayoutBuilder &builder, const LayoutItem &item) +{ + if (item.onAdd) + item.onAdd(builder); + + if (item.setter) { + if (QWidget *widget = builder.stack.last().widget) + item.setter(widget); + else if (QLayout *layout = builder.stack.last().layout) + item.setter(layout); + else + QTC_CHECK(false); } - pendingFormItems.clear(); + for (const LayoutItem &subItem : item.subItems) + addItemHelper(builder, subItem); + + if (item.onExit) + item.onExit(builder); } -static void doLayoutHelper(QLayout *layout, - const LayoutBuilder::LayoutItems &items, - const Layouting::AttachType attachType, - int currentGridRow = 0) +void doAddText(LayoutBuilder &builder, const QString &text) { - int currentGridColumn = 0; - LayoutBuilder::LayoutItems pendingFormItems; + ResultItem fi; + fi.text = text; + builder.stack.last().pendingItems.append(fi); +} - auto formLayout = qobject_cast(layout); - auto gridLayout = qobject_cast(layout); - auto boxLayout = qobject_cast(layout); - auto stackLayout = qobject_cast(layout); +void doAddSpace(LayoutBuilder &builder, const Space &space) +{ + ResultItem fi; + fi.space = space.space; + builder.stack.last().pendingItems.append(fi); +} - for (const LayoutItem &item : items) { - if (item.specialType == LayoutItem::SpecialType::Break) { - if (formLayout) - flushPendingFormItems(formLayout, pendingFormItems); - else if (gridLayout) { - if (currentGridColumn != 0) { - ++currentGridRow; - currentGridColumn = 0; - } - } - continue; - } +void doAddStretch(LayoutBuilder &builder, const Stretch &stretch) +{ + ResultItem fi; + fi.stretch = stretch.stretch; + builder.stack.last().pendingItems.append(fi); +} - QWidget *widget = item.widget; +void doAddLayout(LayoutBuilder &builder, QLayout *layout) +{ + builder.stack.last().pendingItems.append(ResultItem(layout)); +} - if (gridLayout) { - Qt::Alignment align = {}; - if (attachType == Layouting::WithFormAlignment && currentGridColumn == 0) - align = Qt::Alignment(widget->style()->styleHint(QStyle::SH_FormLayoutLabelAlignment)); - if (widget) - gridLayout->addWidget(widget, currentGridRow, currentGridColumn, 1, item.span, align); - else if (item.layout) - gridLayout->addLayout(item.layout, currentGridRow, currentGridColumn, 1, item.span, align); - else if (!item.text.isEmpty()) - gridLayout->addWidget(createLabel(item.text), currentGridRow, currentGridColumn, 1, 1, align); - currentGridColumn += item.span; - } else if (boxLayout) { - addItemToBoxLayout(boxLayout, item); - } else if (stackLayout) { - stackLayout->addWidget(item.widget); - } else { - pendingFormItems.append(item); - } - } - - if (formLayout) - flushPendingFormItems(formLayout, pendingFormItems); +void doAddWidget(LayoutBuilder &builder, QWidget *widget) +{ + builder.stack.last().pendingItems.append(ResultItem(widget)); } /*! - Constructs a layout item from the contents of another LayoutBuilder - */ -void LayoutItem::setBuilder(const LayoutBuilder &builder) -{ - layout = builder.createLayout(); - doLayoutHelper(layout, builder.m_items, Layouting::WithoutMargins); -} - -/*! - \class Utils::LayoutBuilder::Space + \class Layouting::Space \inmodule QtCreator - \brief The LayoutBuilder::Space class represents some empty space in a layout. + \brief The Layouting::Space class represents some empty space in a layout. */ /*! - \class Utils::LayoutBuilder::Stretch + \class Layouting::Stretch \inmodule QtCreator - \brief The LayoutBuilder::Stretch class represents some stretch in a layout. + \brief The Layouting::Stretch class represents some stretch in a layout. */ /*! - \class Utils::LayoutBuilder + \class LayoutBuilder \inmodule QtCreator \brief The LayoutBuilder class provides a convenient way to fill \c QFormLayout @@ -298,20 +307,6 @@ void LayoutItem::setBuilder(const LayoutBuilder &builder) \sa addItem(), addItems(), addRow(), finishRow() */ -LayoutBuilder::LayoutBuilder(LayoutType layoutType, const LayoutItems &items) - : m_layoutType(layoutType) -{ - m_items.reserve(items.size() * 2); - for (const LayoutItem &item : items) - addItem(item); -} - -LayoutBuilder &LayoutBuilder::setSpacing(int spacing) -{ - m_spacing = spacing; - return *this; -} - LayoutBuilder::LayoutBuilder() = default; /*! @@ -319,14 +314,30 @@ LayoutBuilder::LayoutBuilder() = default; */ LayoutBuilder::~LayoutBuilder() = default; +void LayoutBuilder::addItem(const LayoutItem &item) +{ + addItemHelper(*this, item); +} + +void LayoutBuilder::addItems(const LayoutItems &items) +{ + for (const LayoutItem &item : items) + addItemHelper(*this, item); +} + +void LayoutBuilder::addRow(const LayoutItems &items) +{ + addItem(br); + addItems(items); +} + /*! Instructs a layout builder to finish the current row. This is implicitly called by LayoutBuilder's destructor. */ -LayoutBuilder &LayoutBuilder::finishRow() +void LayoutItem::finishRow() { - addItem(Break()); - return *this; + addItem(br); } /*! @@ -335,42 +346,26 @@ LayoutBuilder &LayoutBuilder::finishRow() \sa finishRow(), addItem(), addItems() */ -LayoutBuilder &LayoutBuilder::addRow(const LayoutItems &items) +void LayoutItem::addRow(const LayoutItems &items) { - return finishRow().addItems(items); + finishRow(); + addItems(items); } /*! - Adds the layout item \a item to the current row. + Adds the layout item \a item as sub items. */ -LayoutBuilder &LayoutBuilder::addItem(const LayoutItem &item) +void LayoutItem::addItem(const LayoutItem &item) { - if (item.onAdd) { - item.onAdd(*this); - } else { - m_items.push_back(item); - } - return *this; -} - -void LayoutBuilder::doLayout(QWidget *parent, Layouting::AttachType attachType) const -{ - QLayout *layout = createLayout(); - parent->setLayout(layout); - - doLayoutHelper(layout, m_items, attachType); - if (attachType == Layouting::WithoutMargins) - layout->setContentsMargins(0, 0, 0, 0); + subItems.append(item); } /*! - Adds the layout item \a items to the current row. + Adds the layout items \a items as sub items. */ -LayoutBuilder &LayoutBuilder::addItems(const LayoutItems &items) +void LayoutItem::addItems(const LayoutItems &items) { - for (const LayoutItem &item : items) - addItem(item); - return *this; + subItems.append(items); } /*! @@ -378,18 +373,106 @@ LayoutBuilder &LayoutBuilder::addItems(const LayoutItems &items) This operation can only be performed once per LayoutBuilder instance. */ -void LayoutBuilder::attachTo(QWidget *w, Layouting::AttachType attachType) const + +void LayoutItem::attachTo(QWidget *w, AttachType attachType) const { - doLayout(w, attachType); + LayoutBuilder builder; + + builder.stack.append({w, attachType}); + addItemHelper(builder, *this); } -QWidget *LayoutBuilder::emerge(Layouting::AttachType attachType) +QWidget *LayoutItem::emerge(Layouting::AttachType attachType) { auto w = new QWidget; - doLayout(w, attachType); + attachTo(w, attachType); return w; } +bool LayoutBuilder::isForm() const +{ + return qobject_cast(stack.last().layout); +} + +static void layoutExit(LayoutBuilder &builder) +{ + builder.stack.last().flush(); + QLayout *layout = builder.stack.last().layout; + if (builder.stack.back().attachType == WithoutMargins) + layout->setContentsMargins(0, 0, 0, 0); + builder.stack.pop_back(); + + if (QWidget *widget = builder.stack.last().widget) + widget->setLayout(layout); + else + builder.stack.last().pendingItems.append(ResultItem(layout)); +} + +static void widgetExit(LayoutBuilder &builder) +{ + QWidget *widget = builder.stack.last().widget; + if (builder.stack.back().attachType == WithoutMargins) + widget->setContentsMargins(0, 0, 0, 0); + builder.stack.pop_back(); + builder.stack.last().pendingItems.append(ResultItem(widget)); +} + +Column::Column(std::initializer_list items) +{ + subItems = items; + onAdd = [](LayoutBuilder &builder) { builder.stack.append(new QVBoxLayout); }; + onExit = layoutExit; +} + +Row::Row(std::initializer_list items) +{ + subItems = items; + onAdd = [](LayoutBuilder &builder) { builder.stack.append(new QHBoxLayout); }; + onExit = layoutExit; +} + +Grid::Grid(std::initializer_list items) +{ + subItems = items; + onAdd = [](LayoutBuilder &builder) { builder.stack.append(new QGridLayout); }; + onExit = layoutExit; +} + +static QFormLayout *newFormLayout() +{ + auto formLayout = new QFormLayout; + formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + return formLayout; +} + +Form::Form(std::initializer_list items) +{ + subItems = items; + onAdd = [](LayoutBuilder &builder) { builder.stack.append(newFormLayout()); }; + onExit = layoutExit; +} + +Stack::Stack(std::initializer_list items) +{ + subItems = items; + onAdd = [](LayoutBuilder &builder) { builder.stack.append(new QStackedLayout); }; + onExit = layoutExit; +} + +LayoutItem br() +{ + LayoutItem item; + item.onAdd = [](LayoutBuilder &builder) { + builder.stack.last().flush(); + }; + return item; +} + +LayoutItem empty() +{ + return {}; +} + /*! Constructs a layout extender to extend an existing \a layout. @@ -399,111 +482,123 @@ QWidget *LayoutBuilder::emerge(Layouting::AttachType attachType) */ LayoutExtender::LayoutExtender(QLayout *layout, Layouting::AttachType attachType) - : m_layout(layout), m_attachType(attachType) -{} - -LayoutExtender::~LayoutExtender() { - QTC_ASSERT(m_layout, return); - int currentGridRow = 0; - if (auto gridLayout = qobject_cast(m_layout)) - currentGridRow = gridLayout->rowCount(); - doLayoutHelper(m_layout, m_items, m_attachType, currentGridRow); + Slice slice; + slice.layout = layout; + if (auto gridLayout = qobject_cast(layout)) + slice.currentGridRow = gridLayout->rowCount(); + slice.attachType = attachType; + stack.append(slice); } -// Special items - -Tab::Tab(const QString &tabName, const LayoutBuilder &item) -{ - text = tabName; - widget = new QWidget; - item.attachTo(widget); - specialType = LayoutItem::SpecialType::Tab; -} +LayoutExtender::~LayoutExtender() = default; // "Widgets" -static void applyItems(LayoutItem *owner, QWidget *widget, const QList &items) +template +void setupWidget(LayoutItem *item) { - owner->widget = widget; - bool hadLayout = false; - for (const LayoutItem &item : items) { - if (item.setter) { - item.setter(widget); - } else if (item.specialType == LayoutItem::SpecialType::Tab) { - auto tabWidget = qobject_cast(widget); - QTC_ASSERT(tabWidget, continue); - tabWidget->addTab(item.widget, item.text); - } else if (item.layout && !hadLayout) { - hadLayout = true; - widget->setLayout(item.layout); - } else { - QTC_CHECK(false); - } - } -} + item->onAdd = [](LayoutBuilder &builder) { builder.stack.append(new T); }; + item->onExit = widgetExit; +}; Group::Group(std::initializer_list items) { - applyItems(this, new QGroupBox, items); + this->subItems = items; + setupWidget(this); } PushButton::PushButton(std::initializer_list items) { - applyItems(this, new QPushButton, items); + this->subItems = items; + setupWidget(this); } TextEdit::TextEdit(std::initializer_list items) { - applyItems(this, new QTextEdit, items); + this->subItems = items; + setupWidget(this); } Splitter::Splitter(std::initializer_list items) { - applyItems(this, new QSplitter(Qt::Vertical), items); - } - + this->subItems = items; + setupWidget(this); // FIXME: Default was Qt::Vertical) +} TabWidget::TabWidget(std::initializer_list items) - { - applyItems(this, new QTabWidget, items); +{ + this->subItems = items; + setupWidget(this); +} + +// Special Tab + +Tab::Tab(const QString &tabName, const LayoutItem &item) +{ + onAdd = [item](LayoutBuilder &builder) { + auto tab = new QWidget; + builder.stack.append(tab); + item.attachTo(tab); + }; + onExit = [tabName](LayoutBuilder &builder) { + QWidget *inner = builder.stack.last().widget; + builder.stack.pop_back(); + auto tabWidget = qobject_cast(builder.stack.last().widget); + QTC_ASSERT(tabWidget, return); + tabWidget->addTab(inner, tabName); + }; +} + +// Special Application + +Application::Application(std::initializer_list items) +{ + subItems = items; + setupWidget(this); + onExit = {}; // Hack: Don't dropp the last slice, we need the resulting widget. +} + +int Application::exec(int &argc, char *argv[]) +{ + auto app = new QApplication(argc, argv); + LayoutBuilder builder; + addItemHelper(builder, *this); + if (QWidget *widget = builder.stack.last().widget) + widget->show(); + return app->exec(); } // "Properties" -static LayoutItem setter(const LayoutItem::Setter &setter) -{ - LayoutItem item; - item.setter = setter; - return item; -} - LayoutItem title(const QString &title) { - return setter([title](QObject *target) { + return [title](QObject *target) { if (auto groupBox = qobject_cast(target)) { groupBox->setTitle(title); groupBox->setObjectName(title); + } else if (auto widget = qobject_cast(target)) { + widget->setWindowTitle(title); } else { QTC_CHECK(false); } - }); + }; } LayoutItem onClicked(const std::function &func, QObject *guard) { - return setter([func, guard](QObject *target) { + return [func, guard](QObject *target) { if (auto button = qobject_cast(target)) { QObject::connect(button, &QAbstractButton::clicked, guard ? guard : target, func); } else { QTC_CHECK(false); } - }); + }; } LayoutItem text(const QString &text) { - return setter([text](QObject *target) { + return [text](QObject *target) { if (auto button = qobject_cast(target)) { button->setText(text); } else if (auto textEdit = qobject_cast(target)) { @@ -511,32 +606,40 @@ LayoutItem text(const QString &text) } else { QTC_CHECK(false); } - }); + }; } LayoutItem tooltip(const QString &toolTip) { - return setter([toolTip](QObject *target) { + return [toolTip](QObject *target) { if (auto widget = qobject_cast(target)) { widget->setToolTip(toolTip); } else { QTC_CHECK(false); } - }); + }; } -LayoutItem bindTo(QSplitter **out) +LayoutItem spacing(int spacing) { - return setter([out](QObject *target) { - *out = qobject_cast(target); - }); + return [spacing](QObject *target) { + if (auto layout = qobject_cast(target)) { + layout->setSpacing(spacing); + } else { + QTC_CHECK(false); + } + }; } -LayoutItem bindTo(QTabWidget **out) +LayoutItem resize(int w, int h) { - return setter([out](QObject *target) { - *out = qobject_cast(target); - }); + return [w, h](QObject *target) { + if (auto widget = qobject_cast(target)) { + widget->resize(w, h); + } else { + QTC_CHECK(false); + } + }; } QWidget *createHr(QWidget *parent) @@ -548,9 +651,67 @@ QWidget *createHr(QWidget *parent) } // Singletons. -Break br; -Stretch st; -Space empty(0); -HorizontalRule hr; + +LayoutItem::LayoutItem(const LayoutItem &t) +{ + operator=(t); +} + +void createItem(LayoutItem *item, LayoutItem(*t)()) +{ + *item = t(); +} + +void createItem(LayoutItem *item, const std::function &t) +{ + item->setter = t; +} + +void createItem(LayoutItem *item, QWidget *t) +{ + item->onAdd = [t](LayoutBuilder &builder) { doAddWidget(builder, t); }; +} + +void createItem(LayoutItem *item, QLayout *t) +{ + item->onAdd = [t](LayoutBuilder &builder) { doAddLayout(builder, t); }; +} + +void createItem(LayoutItem *item, const QString &t) +{ + item->onAdd = [t](LayoutBuilder &builder) { doAddText(builder, t); }; +} + +void createItem(LayoutItem *item, const Space &t) +{ + item->onAdd = [t](LayoutBuilder &builder) { doAddSpace(builder, t); }; +} + +void createItem(LayoutItem *item, const Stretch &t) +{ + item->onAdd = [t](LayoutBuilder &builder) { doAddStretch(builder, t); }; +} + +void createItem(LayoutItem *item, const Span &t) +{ + item->onAdd = [t](LayoutBuilder &builder) { + addItemHelper(builder, t.item); + builder.stack.last().pendingItems.last().span = t.span; + }; +} + +LayoutItem hr() +{ + LayoutItem item; + item.onAdd = [](LayoutBuilder &builder) { doAddWidget(builder, createHr()); }; + return item; +} + +LayoutItem st() +{ + LayoutItem item; + item.onAdd = [](LayoutBuilder &builder) { doAddStretch(builder, Stretch(1)); }; + return item; +} } // Layouting diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index aea4db876c1..1e9e6b9ad3e 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -5,7 +5,6 @@ #include #include -#include #include #include @@ -18,10 +17,9 @@ QT_BEGIN_NAMESPACE class QLayout; -class QSplitter; -class QTabWidget; -class QTextEdit; +class QObject; class QWidget; +template T qobject_cast(QObject *object); QT_END_NAMESPACE namespace Layouting { @@ -34,6 +32,7 @@ enum AttachType { class LayoutBuilder; class LayoutItem; +class Span; // Special items @@ -51,28 +50,20 @@ public: const int stretch; }; -class QTCREATOR_UTILS_EXPORT Break -{ -public: - Break() {} -}; - -class QTCREATOR_UTILS_EXPORT Span -{ -public: - Span(int span, const LayoutItem &item) : span(span), item(item) {} - const int span; - const LayoutItem &item; -}; - -class QTCREATOR_UTILS_EXPORT HorizontalRule -{ -public: - HorizontalRule() {} -}; // LayoutItem +using LayoutItems = QList; + +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const std::function &t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, QWidget *t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, QLayout *t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, LayoutItem(*t)()); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const QString &t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const Span &t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const Space &t); +void QTCREATOR_UTILS_EXPORT createItem(LayoutItem *item, const Stretch &t); + class QTCREATOR_UTILS_EXPORT LayoutItem { public: @@ -81,72 +72,81 @@ public: AlignAsFormLabel, }; - enum class SpecialType { - NotSpecial, - Space, - Stretch, - Break, - HorizontalRule, - Tab, - }; - using Setter = std::function; - using OnAdder = std::function; LayoutItem(); + ~LayoutItem(); + + LayoutItem(const LayoutItem &t); + LayoutItem &operator=(const LayoutItem &t) = default; template LayoutItem(const T &t) { - if constexpr (std::is_same_v) { - text = t; - } else if constexpr (std::is_same_v) { - specialType = LayoutItem::SpecialType::Space; - specialValue = t.space; - } else if constexpr (std::is_same_v) { - specialType = LayoutItem::SpecialType::Stretch; - specialValue = t.stretch; - } else if constexpr (std::is_same_v) { - specialType = LayoutItem::SpecialType::Break; - } else if constexpr (std::is_same_v) { - LayoutItem::operator=(t.item); - span = t.span; - } else if constexpr (std::is_same_v) { - specialType = SpecialType::HorizontalRule; - } else if constexpr (std::is_base_of_v) { - setBuilder(t); - } else if constexpr (std::is_base_of_v) { + if constexpr (std::is_base_of_v) LayoutItem::operator=(t); - } else if constexpr (std::is_base_of_v) { - setter = t; - } else if constexpr (std::is_base_of_v>) { - layout = t; - } else if constexpr (std::is_base_of_v>) { - widget = t; - } else if constexpr (std::is_pointer_v) { - onAdd = [t](LayoutBuilder &builder) { doLayout(*t, builder); }; - } else { - onAdd = [&t](LayoutBuilder &builder) { doLayout(t, builder); }; - } + else + createItem(this, t); } - void setBuilder(const LayoutBuilder &builder); + void attachTo(QWidget *w, AttachType attachType = WithMargins) const; + QWidget *emerge(AttachType attachType = WithMargins); - QLayout *layout = nullptr; - QWidget *widget = nullptr; - OnAdder onAdd; + void addItem(const LayoutItem &item); + void addItems(const LayoutItems &items); + void addRow(const LayoutItems &items); + void finishRow(); - QString text; // FIXME: Use specialValue for that - int span = 1; - AlignmentType align = AlignmentType::DefaultAlignment; - Setter setter; - SpecialType specialType = SpecialType::NotSpecial; - QVariant specialValue; + std::function onAdd; + std::function onExit; + std::function setter; + LayoutItems subItems; +}; + +class QTCREATOR_UTILS_EXPORT Span +{ +public: + Span(int span, const LayoutItem &item) : span(span), item(item) {} + const int span; + LayoutItem item; +}; + +class QTCREATOR_UTILS_EXPORT Column : public LayoutItem +{ +public: + Column(std::initializer_list items); +}; + +class QTCREATOR_UTILS_EXPORT Row : public LayoutItem +{ +public: + Row(std::initializer_list items); +}; + +class QTCREATOR_UTILS_EXPORT Grid : public LayoutItem +{ +public: + Grid() : Grid({}) {} + Grid(std::initializer_list items); +}; + +class QTCREATOR_UTILS_EXPORT Form : public LayoutItem +{ +public: + Form() : Form({}) {} + Form(std::initializer_list items); +}; + +class QTCREATOR_UTILS_EXPORT Stack : public LayoutItem +{ +public: + Stack() : Stack({}) {} + Stack(std::initializer_list items); }; class QTCREATOR_UTILS_EXPORT Tab : public LayoutItem { public: - Tab(const QString &tabName, const LayoutBuilder &item); + Tab(const QString &tabName, const LayoutItem &item); }; class QTCREATOR_UTILS_EXPORT Group : public LayoutItem @@ -179,124 +179,67 @@ public: TabWidget(std::initializer_list items); }; -// Singleton items. +class QTCREATOR_UTILS_EXPORT Application : public LayoutItem +{ +public: + Application(std::initializer_list items); -QTCREATOR_UTILS_EXPORT extern Break br; -QTCREATOR_UTILS_EXPORT extern Stretch st; -QTCREATOR_UTILS_EXPORT extern Space empty; -QTCREATOR_UTILS_EXPORT extern HorizontalRule hr; + int exec(int &argc, char *argv[]); +}; + +// "Singletons" + +QTCREATOR_UTILS_EXPORT LayoutItem br(); +QTCREATOR_UTILS_EXPORT LayoutItem st(); +QTCREATOR_UTILS_EXPORT LayoutItem empty(); +QTCREATOR_UTILS_EXPORT LayoutItem hr(); // "Properties" -QTCREATOR_UTILS_EXPORT LayoutItem bindTo(QTabWidget **); -QTCREATOR_UTILS_EXPORT LayoutItem bindTo(QSplitter **); - QTCREATOR_UTILS_EXPORT LayoutItem title(const QString &title); QTCREATOR_UTILS_EXPORT LayoutItem text(const QString &text); QTCREATOR_UTILS_EXPORT LayoutItem tooltip(const QString &toolTip); -QTCREATOR_UTILS_EXPORT LayoutItem onClicked(const std::function &func, - QObject *guard = nullptr); - +QTCREATOR_UTILS_EXPORT LayoutItem resize(int, int); +QTCREATOR_UTILS_EXPORT LayoutItem spacing(int); +QTCREATOR_UTILS_EXPORT LayoutItem windowTitle(const QString &windowTitle); +QTCREATOR_UTILS_EXPORT LayoutItem onClicked(const std::function &, + QObject *guard = nullptr); // Convenience QTCREATOR_UTILS_EXPORT QWidget *createHr(QWidget *parent = nullptr); +template +LayoutItem bindTo(T **out) +{ + return [out](QObject *target) { *out = qobject_cast(target); }; +} // LayoutBuilder class QTCREATOR_UTILS_EXPORT LayoutBuilder { - Q_DISABLE_COPY(LayoutBuilder) + Q_DISABLE_COPY_MOVE(LayoutBuilder) public: - enum LayoutType { - HBoxLayout, - VBoxLayout, - FormLayout, - GridLayout, - StackLayout, - }; - - using LayoutItems = QList; - - explicit LayoutBuilder(LayoutType layoutType, const LayoutItems &items = {}); - - LayoutBuilder(LayoutBuilder &&) = default; - LayoutBuilder &operator=(LayoutBuilder &&) = default; - + LayoutBuilder(); ~LayoutBuilder(); - LayoutBuilder &setSpacing(int spacing); + void addItem(const LayoutItem &item); + void addItems(const LayoutItems &items); + void addRow(const LayoutItems &items); - LayoutBuilder &addItem(const LayoutItem &item); - LayoutBuilder &addItems(const LayoutItems &items); + bool isForm() const; - LayoutBuilder &finishRow(); - LayoutBuilder &addRow(const LayoutItems &items); - - LayoutType layoutType() const { return m_layoutType; } - - void attachTo(QWidget *w, Layouting::AttachType attachType = Layouting::WithMargins) const; - QWidget *emerge(Layouting::AttachType attachType = Layouting::WithMargins); - -protected: - friend class LayoutItem; - - explicit LayoutBuilder(); // Adds to existing layout. - - QLayout *createLayout() const; - void doLayout(QWidget *parent, Layouting::AttachType attachType) const; - - LayoutItems m_items; - LayoutType m_layoutType; - std::optional m_spacing; + struct Slice; + QList stack; }; class QTCREATOR_UTILS_EXPORT LayoutExtender : public LayoutBuilder { public: - explicit LayoutExtender(QLayout *layout, Layouting::AttachType attachType); + explicit LayoutExtender(QLayout *layout, AttachType attachType); ~LayoutExtender(); - -private: - QLayout *m_layout = nullptr; - Layouting::AttachType m_attachType = {}; -}; - -class QTCREATOR_UTILS_EXPORT Column : public LayoutBuilder -{ -public: - Column() : LayoutBuilder(VBoxLayout) {} - Column(std::initializer_list items) : LayoutBuilder(VBoxLayout, items) {} -}; - -class QTCREATOR_UTILS_EXPORT Row : public LayoutBuilder -{ -public: - Row() : LayoutBuilder(HBoxLayout) {} - Row(std::initializer_list items) : LayoutBuilder(HBoxLayout, items) {} -}; - -class QTCREATOR_UTILS_EXPORT Grid : public LayoutBuilder -{ -public: - Grid() : LayoutBuilder(GridLayout) {} - Grid(std::initializer_list items) : LayoutBuilder(GridLayout, items) {} -}; - -class QTCREATOR_UTILS_EXPORT Form : public LayoutBuilder -{ -public: - Form() : LayoutBuilder(FormLayout) {} - Form(std::initializer_list items) : LayoutBuilder(FormLayout, items) {} -}; - -class QTCREATOR_UTILS_EXPORT Stack : public LayoutBuilder -{ -public: - Stack() : LayoutBuilder(StackLayout) {} - Stack(std::initializer_list items) : LayoutBuilder(StackLayout, items) {} }; } // Layouting diff --git a/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp b/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp index 9d2741209ed..a968c2eb962 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp +++ b/src/plugins/beautifier/artisticstyle/artisticstyleoptionspage.cpp @@ -91,7 +91,7 @@ ArtisticStyleOptionsPageWidget::ArtisticStyleOptionsPageWidget(ArtisticStyleSett Row { m_useSpecificConfigFile, m_specificConfigFile }, m_useHomeFile, Row { m_useCustomStyle, m_configurations } - }.attachTo(options); + }.attachTo(options, WithoutMargins); Column { Group { diff --git a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp index c70b5251a2c..44d32cc3a91 100644 --- a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp @@ -44,7 +44,10 @@ ClangFormatGlobalConfigWidget::ClangFormatGlobalConfigWidget( using namespace Layouting; + QWidget *globalSettingsGroupBoxWidget = nullptr; + Group globalSettingsGroupBox { + bindTo(&globalSettingsGroupBoxWidget), title(Tr::tr("ClangFormat settings:")), Column { m_useGlobalSettings, @@ -73,7 +76,8 @@ ClangFormatGlobalConfigWidget::ClangFormatGlobalConfigWidget( m_useGlobalSettings->show(); return; } - globalSettingsGroupBox.widget->show(); + + globalSettingsGroupBoxWidget->show(); } ClangFormatGlobalConfigWidget::~ClangFormatGlobalConfigWidget() = default; diff --git a/src/plugins/coreplugin/find/findtoolbar.cpp b/src/plugins/coreplugin/find/findtoolbar.cpp index 11c51fe26ea..4690502f50a 100644 --- a/src/plugins/coreplugin/find/findtoolbar.cpp +++ b/src/plugins/coreplugin/find/findtoolbar.cpp @@ -147,8 +147,8 @@ FindToolBar::FindToolBar(CurrentDocumentFind *currentDocumentFind) m_findEdit, findButtonsWidget, br, - Column { m_replaceLabel, st }.setSpacing(0), - Column { m_replaceEdit, st }.setSpacing(0), + Column { spacing(0), m_replaceLabel, st }, + Column { spacing(0), m_replaceEdit, st }, gridLayout, }.attachTo(this); diff --git a/src/plugins/cpaster/pasteview.cpp b/src/plugins/cpaster/pasteview.cpp index c575fa582b7..b1f4864b6e0 100644 --- a/src/plugins/cpaster/pasteview.cpp +++ b/src/plugins/cpaster/pasteview.cpp @@ -108,6 +108,7 @@ PasteView::PasteView(const QList &protocols, }.attachTo(groupBox); Column { + spacing(2), Form { Tr::tr("Protocol:"), m_protocolBox, br, Tr::tr("&Expires after:"), m_expirySpinBox, br, @@ -117,7 +118,7 @@ PasteView::PasteView(const QList &protocols, m_uiComment, m_stackedWidget, buttonBox - }.setSpacing(2).attachTo(this); + }.attachTo(this); connect(m_uiPatchList, &QListWidget::itemChanged, this, &PasteView::contentChanged); diff --git a/src/plugins/cppeditor/cppcodestylesettingspage.cpp b/src/plugins/cppeditor/cppcodestylesettingspage.cpp index 72308ed4caa..b9cdbc47f39 100644 --- a/src/plugins/cppeditor/cppcodestylesettingspage.cpp +++ b/src/plugins/cppeditor/cppcodestylesettingspage.cpp @@ -175,8 +175,15 @@ public: using namespace Layouting; + QWidget *contentGroupWidget = nullptr; + QWidget *bracesGroupWidget = nullptr; + QWidget *switchGroupWidget = nullptr; + QWidget *alignmentGroupWidget = nullptr; + QWidget *typesGroupWidget = nullptr; + const Group contentGroup { title(Tr::tr("Indent")), + bindTo(&contentGroupWidget), Column { m_indentAccessSpecifiers, m_indentDeclarationsRelativeToAccessSpecifiers, @@ -189,6 +196,7 @@ public: const Group bracesGroup { title(Tr::tr("Indent Braces")), + bindTo(&bracesGroupWidget), Column { m_indentClassBraces, m_indentNamespaceBraces, @@ -201,6 +209,7 @@ public: const Group switchGroup { title(Tr::tr("Indent within \"switch\"")), + bindTo(&switchGroupWidget), Column { m_indentSwitchLabels, m_indentCaseStatements, @@ -212,6 +221,7 @@ public: const Group alignmentGroup { title(Tr::tr("Align")), + bindTo(&alignmentGroupWidget), Column { m_alignAssignments, m_extraPaddingConditions, @@ -221,6 +231,7 @@ public: const Group typesGroup { title(Tr::tr("Bind '*' and '&&' in types/declarations to")), + bindTo(&typesGroupWidget), Column { m_bindStarToIdentifier, m_bindStarToTypeName, @@ -247,11 +258,11 @@ public: m_categoryTab->setProperty("_q_custom_style_disabled", true); m_controllers.append(m_tabSettingsWidget); - m_controllers.append(contentGroup.widget); - m_controllers.append(bracesGroup.widget); - m_controllers.append(switchGroup.widget); - m_controllers.append(alignmentGroup.widget); - m_controllers.append(typesGroup.widget); + m_controllers.append(contentGroupWidget); + m_controllers.append(bracesGroupWidget); + m_controllers.append(switchGroupWidget); + m_controllers.append(alignmentGroupWidget); + m_controllers.append(typesGroupWidget); } QCheckBox *createCheckBox(const QString &text, const QString &toolTip = {}) diff --git a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp index 8aa30b3c630..d7abf7b12b5 100644 --- a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp +++ b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp @@ -496,7 +496,7 @@ void SourcePathMapAspect::addToLayout(Layouting::LayoutBuilder &builder) QTC_CHECK(!d->m_widget); d->m_widget = createSubWidget(); d->m_widget->setSourcePathMap(value()); - builder.addRow({d->m_widget.data()}); + builder.addItem(d->m_widget.data()); } QVariant SourcePathMapAspect::volatileValue() const diff --git a/src/plugins/mesonprojectmanager/mesonbuildsettingswidget.cpp b/src/plugins/mesonprojectmanager/mesonbuildsettingswidget.cpp index cedd9c5f3ef..8becece66b1 100644 --- a/src/plugins/mesonprojectmanager/mesonbuildsettingswidget.cpp +++ b/src/plugins/mesonprojectmanager/mesonbuildsettingswidget.cpp @@ -74,9 +74,9 @@ MesonBuildSettingsWidget::MesonBuildSettingsWidget(MesonBuildConfiguration *buil Row { configureButton, wipeButton, } }.attachTo(this, WithoutMargins); - Form buildDirWBuilder; - buildCfg->buildDirectoryAspect()->addToLayout(buildDirWBuilder); - buildDirWBuilder.attachTo(buildDirWidget, WithoutMargins); + Form { + buildCfg->buildDirectoryAspect(), + }.attachTo(buildDirWidget, WithoutMargins); parametersLineEdit->setText(buildCfg->parameters()); optionsFilterLineEdit->setFiltering(true); diff --git a/src/plugins/projectexplorer/buildaspects.cpp b/src/plugins/projectexplorer/buildaspects.cpp index adf37a33620..133cfb15b38 100644 --- a/src/plugins/projectexplorer/buildaspects.cpp +++ b/src/plugins/projectexplorer/buildaspects.cpp @@ -112,7 +112,7 @@ void BuildDirectoryAspect::addToLayout(Layouting::LayoutBuilder &builder) StringAspect::addToLayout(builder); d->problemLabel = new InfoLabel({}, InfoLabel::Warning); d->problemLabel->setElideMode(Qt::ElideNone); - builder.addRow({{}, d->problemLabel.data()}); + builder.addItems({{}, d->problemLabel.data()}); updateProblemLabel(); if (!d->sourceDir.isEmpty()) { connect(this, &StringAspect::checkedChanged, this, [this] { diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp index 124941b11a1..904530e9c77 100644 --- a/src/plugins/projectexplorer/buildconfiguration.cpp +++ b/src/plugins/projectexplorer/buildconfiguration.cpp @@ -322,12 +322,12 @@ NamedWidget *BuildConfiguration::createConfigWidget() widget = named; } - Layouting::Form builder; + Layouting::Form form; for (BaseAspect *aspect : aspects()) { if (aspect->isVisible()) - aspect->addToLayout(builder.finishRow()); + form.addItem(aspect); } - builder.attachTo(widget, Layouting::WithoutMargins); + form.attachTo(widget, Layouting::WithoutMargins); return named; } diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp index 69f05e41c4e..a7f74c3f03d 100644 --- a/src/plugins/projectexplorer/buildstep.cpp +++ b/src/plugins/projectexplorer/buildstep.cpp @@ -160,12 +160,12 @@ QWidget *BuildStep::doCreateConfigWidget() QWidget *BuildStep::createConfigWidget() { - Layouting::Form builder; + Layouting::Form form; for (BaseAspect *aspect : std::as_const(m_aspects)) { if (aspect->isVisible()) - aspect->addToLayout(builder.finishRow()); + form.addItem(aspect); } - auto widget = builder.emerge(Layouting::WithoutMargins); + auto widget = form.emerge(Layouting::WithoutMargins); if (m_addMacroExpander) VariableChooser::addSupportForChildWidgets(widget, macroExpander()); diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp index cb67e11fac0..65c8475adba 100644 --- a/src/plugins/projectexplorer/kitmanager.cpp +++ b/src/plugins/projectexplorer/kitmanager.cpp @@ -757,8 +757,7 @@ void KitAspectWidget::addToLayoutWithLabel(QWidget *parent) }); Layouting::LayoutExtender builder(parent->layout(), Layouting::WithFormAlignment); - builder.finishRow(); - builder.addItem(label); + builder.addItems({label, Layouting::br}); addToLayout(builder); } diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp index 558e4fa7122..5ab5f109ff2 100644 --- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp +++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp @@ -551,6 +551,11 @@ int SelectorView::padding() ///////// // KitAreaWidget ///////// +void doLayout(KitAspectWidget *widget, Layouting::LayoutBuilder &builder) +{ + widget->addToLayout(builder); +} + class KitAreaWidget : public QWidget { Q_OBJECT @@ -573,18 +578,15 @@ public: delete layout(); - Layouting::LayoutBuilder builder(Layouting::LayoutBuilder::GridLayout); + Layouting::Grid grid; for (KitAspect *aspect : KitManager::kitAspects()) { if (k && k->isMutable(aspect->id())) { KitAspectWidget *widget = aspect->createConfigWidget(k); m_widgets << widget; - QLabel *label = new QLabel(aspect->displayName()); - builder.addItem(label); - widget->addToLayout(builder); - builder.finishRow(); + grid.addItems({aspect->displayName(), widget, Layouting::br}); } } - builder.attachTo(this); + grid.attachTo(this); layout()->setContentsMargins(3, 3, 3, 3); m_kit = k; diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index 32740d6c33c..c6e47f7f838 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -216,13 +216,13 @@ bool RunConfiguration::isEnabled() const QWidget *RunConfiguration::createConfigurationWidget() { - Layouting::Form builder; + Layouting::Form form; for (BaseAspect *aspect : std::as_const(m_aspects)) { if (aspect->isVisible()) - aspect->addToLayout(builder.finishRow()); + form.addItem(aspect); } - auto widget = builder.emerge(Layouting::WithoutMargins); + auto widget = form.emerge(Layouting::WithoutMargins); VariableChooser::addSupportForChildWidgets(widget, &m_expander); diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp index c1fceb613c1..face7d2ce4f 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.cpp +++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp @@ -634,9 +634,9 @@ FilePath ExecutableAspect::executable() const */ void ExecutableAspect::addToLayout(LayoutBuilder &builder) { - m_executable.addToLayout(builder); + builder.addItem(m_executable); if (m_alternativeExecutable) - m_alternativeExecutable->addToLayout(builder.finishRow()); + builder.addItems({br, m_alternativeExecutable}); } /*! diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp index acea24b0763..1f7fca3b856 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp @@ -658,25 +658,26 @@ QbsBuildStepConfigWidget::QbsBuildStepConfigWidget(QbsBuildStep *step) installDirChooser = new PathChooser(this); installDirChooser->setExpectedKind(PathChooser::Directory); - Layouting::Form builder; - builder.addRow({m_qbsStep->m_buildVariant}); - builder.addRow({m_qbsStep->m_selectedAbis}); - builder.addRow({m_qbsStep->m_maxJobCount}); - builder.addRow({QbsProjectManager::Tr::tr("Properties:"), propertyEdit}); + using namespace Layouting; + Form { + m_qbsStep->m_buildVariant, br, + m_qbsStep->m_selectedAbis, br, + m_qbsStep->m_maxJobCount, br, + QbsProjectManager::Tr::tr("Properties:"), propertyEdit, br, - builder.addRow({QbsProjectManager::Tr::tr("Flags:")}); - m_qbsStep->m_keepGoing->addToLayout(builder); - m_qbsStep->m_showCommandLines->addToLayout(builder); - m_qbsStep->m_forceProbes->addToLayout(builder); + QbsProjectManager::Tr::tr("Flags:"), + m_qbsStep->m_keepGoing, + m_qbsStep->m_showCommandLines, + m_qbsStep->m_forceProbes, br, - builder.addRow({QbsProjectManager::Tr::tr("Installation flags:")}); - m_qbsStep->m_install->addToLayout(builder); - m_qbsStep->m_cleanInstallDir->addToLayout(builder); - builder.addItem(defaultInstallDirCheckBox); + QbsProjectManager::Tr::tr("Installation flags:"), + m_qbsStep->m_install, + m_qbsStep->m_cleanInstallDir, + defaultInstallDirCheckBox, br, - builder.addRow({QbsProjectManager::Tr::tr("Installation directory:"), installDirChooser}); - builder.addRow({m_qbsStep->m_commandLine}); - builder.attachTo(this, Layouting::WithoutMargins); + QbsProjectManager::Tr::tr("Installation directory:"), installDirChooser, br, + m_qbsStep->m_commandLine, br, + }.attachTo(this, Layouting::WithoutMargins); propertyEdit->setToolTip(QbsProjectManager::Tr::tr("Properties to pass to the project.")); defaultInstallDirCheckBox->setText(QbsProjectManager::Tr::tr("Use default location")); diff --git a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp index 179928c1795..939a03d9d9c 100644 --- a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp @@ -172,15 +172,12 @@ QWidget *QbsInstallStep::createConfigWidget() commandLineTextEdit->setTextInteractionFlags(Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse); commandLineTextEdit->setMinimumHeight(QFontMetrics(widget->font()).height() * 8); - Layouting::Form builder; - builder.addRow({Tr::tr("Install root:"), installRootValueLabel}); - builder.addRow({Tr::tr("Flags:")}); - m_dryRun->addToLayout(builder); - m_keepGoing->addToLayout(builder); - m_cleanInstallRoot->addToLayout(builder); - - builder.addRow({commandLineKeyLabel, commandLineTextEdit}); - builder.attachTo(widget); + using namespace Layouting; + Form { + Tr::tr("Install root:"), installRootValueLabel, br, + Tr::tr("Flags:"), m_dryRun, m_keepGoing, m_cleanInstallRoot, br, + commandLineKeyLabel, commandLineTextEdit + }.attachTo(widget); const auto updateState = [this, commandLineTextEdit, installRootValueLabel] { installRootValueLabel->setText(installRoot().toUserOutput()); diff --git a/src/plugins/qmljseditor/qmljseditingsettingspage.cpp b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp index 8d168d440a4..7b6474449c4 100644 --- a/src/plugins/qmljseditor/qmljseditingsettingspage.cpp +++ b/src/plugins/qmljseditor/qmljseditingsettingspage.cpp @@ -246,10 +246,13 @@ public: QObject::connect(useQmlls, &QCheckBox::stateChanged, this, [this](int checked) { useLatestQmlls->setEnabled(checked != Qt::Unchecked); }); + using namespace Layouting; // clang-format off - const auto formattingGroup = + QWidget *formattingGroup = nullptr; + Column { Group { + bindTo(&formattingGroup), title(Tr::tr("Automatic Formatting on File Save")), Column { autoFormatOnSave, @@ -260,10 +263,7 @@ public: formatCommandOptionsLabel, formatCommandOptions } }, - }; - - Column { - formattingGroup, + }, Group { title(Tr::tr("Qt Quick Toolbars")), Column { pinContextPane, enableContextPane }, @@ -283,7 +283,7 @@ public: }.attachTo(this); // clang-format on - Utils::VariableChooser::addSupportForChildWidgets(formattingGroup.widget, + Utils::VariableChooser::addSupportForChildWidgets(formattingGroup, Utils::globalMacroExpander()); const auto updateFormatCommandState = [&, formatCommandLabel, formatCommandOptionsLabel] { diff --git a/src/plugins/scxmleditor/common/navigatorslider.cpp b/src/plugins/scxmleditor/common/navigatorslider.cpp index 68d74dd1bed..dd45a1c8af4 100644 --- a/src/plugins/scxmleditor/common/navigatorslider.cpp +++ b/src/plugins/scxmleditor/common/navigatorslider.cpp @@ -31,11 +31,12 @@ NavigatorSlider::NavigatorSlider(QWidget *parent) using namespace Layouting; Row { + spacing(0), zoomOut, m_slider, zoomIn, Space(20), - }.setSpacing(0).attachTo(this, WithoutMargins); + }.attachTo(this, WithoutMargins); connect(zoomOut, &QToolButton::clicked, this, &NavigatorSlider::zoomOut); connect(zoomIn, &QToolButton::clicked, this, &NavigatorSlider::zoomIn); diff --git a/src/plugins/scxmleditor/common/search.cpp b/src/plugins/scxmleditor/common/search.cpp index 34f26017333..b7b56295fd5 100644 --- a/src/plugins/scxmleditor/common/search.cpp +++ b/src/plugins/scxmleditor/common/search.cpp @@ -47,9 +47,10 @@ Search::Search(QWidget *parent) using namespace Layouting; Column { + spacing(0), m_searchEdit, m_searchView, - }.setSpacing(0).attachTo(this, WithoutMargins); + }.attachTo(this, WithoutMargins); connect(m_searchEdit, &Utils::FancyLineEdit::textChanged, this, &Search::setSearchText); connect(m_searchView, &TableView::pressed, this, &Search::rowActivated); diff --git a/src/plugins/scxmleditor/common/shapestoolbox.cpp b/src/plugins/scxmleditor/common/shapestoolbox.cpp index 1343859cc62..a0354d0bce4 100644 --- a/src/plugins/scxmleditor/common/shapestoolbox.cpp +++ b/src/plugins/scxmleditor/common/shapestoolbox.cpp @@ -31,8 +31,9 @@ ShapesToolbox::ShapesToolbox(QWidget *parent) using namespace Layouting; Column { + spacing(0), scrollArea, - }.setSpacing(0).attachTo(this, WithoutMargins); + }.attachTo(this, WithoutMargins); } void ShapesToolbox::setUIFactory(ScxmlEditor::PluginInterface::ScxmlUiFactory *factory) diff --git a/src/plugins/scxmleditor/common/stateview.cpp b/src/plugins/scxmleditor/common/stateview.cpp index 57759263fd4..e4c23046c7f 100644 --- a/src/plugins/scxmleditor/common/stateview.cpp +++ b/src/plugins/scxmleditor/common/stateview.cpp @@ -38,8 +38,10 @@ StateView::StateView(StateItem *state, QWidget *parent) }.attachTo(titleBar, WithoutMargins); Column { - titleBar, m_graphicsView - }.setSpacing(0).attachTo(this, WithoutMargins); + spacing(0), + titleBar, + m_graphicsView + }.attachTo(this, WithoutMargins); initScene(); } diff --git a/tests/manual/layoutbuilder/comparison/layoutbuilder/main.cpp b/tests/manual/layoutbuilder/comparison/layoutbuilder/main.cpp index 96911edee8c..6620ba52e21 100644 --- a/tests/manual/layoutbuilder/comparison/layoutbuilder/main.cpp +++ b/tests/manual/layoutbuilder/comparison/layoutbuilder/main.cpp @@ -1,11 +1,6 @@ #include "mainwindow.h" -#include - int main(int argc, char *argv[]) { - QApplication a(argc, argv); - ApplicationWindow w; - w.show(); - return a.exec(); + return app.exec(argc, argv); } diff --git a/tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.h b/tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.h index 8ff57827f9d..5ccb647f846 100644 --- a/tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.h +++ b/tests/manual/layoutbuilder/comparison/layoutbuilder/mainwindow.h @@ -2,28 +2,23 @@ #include "layoutbuilder.h" -#include -#include +#include using namespace Layouting; -class ApplicationWindow : public QWidget +Application app { -public: - ApplicationWindow() - { - resize(600, 400); - setWindowTitle("Hello World"); + resize(600, 400), + title("Hello World"), - Column { - TextEdit { - text("Hallo") - }, + Column { + TextEdit { + text("Hallo") + }, - PushButton { - text("Quit"), - onClicked([] { QCoreApplication::quit(); }) - } - }.attachTo(this); + PushButton { + text("Quit"), + onClicked([] { QApplication::quit(); }) + } } }; diff --git a/tests/manual/layoutbuilder/comparison/quick/Main.qml b/tests/manual/layoutbuilder/comparison/quick/Main.qml index 2200399429d..617b573caaa 100644 --- a/tests/manual/layoutbuilder/comparison/quick/Main.qml +++ b/tests/manual/layoutbuilder/comparison/quick/Main.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -ApplicationWindow { - +ApplicationWindow +{ width: 640 height: 480 visible: true diff --git a/tests/manual/layoutbuilder/comparison/widgets/main.cpp b/tests/manual/layoutbuilder/comparison/widgets/main.cpp index 5d394e06c38..c610fc6a497 100644 --- a/tests/manual/layoutbuilder/comparison/widgets/main.cpp +++ b/tests/manual/layoutbuilder/comparison/widgets/main.cpp @@ -1,8 +1,5 @@ - #include "mainwindow.h" -#include - int main(int argc, char *argv[]) { QApplication a(argc, argv); diff --git a/tests/manual/layoutbuilder/comparison/widgets/mainwindow.h b/tests/manual/layoutbuilder/comparison/widgets/mainwindow.h index 9acf84d4b55..1dc8ad6f838 100644 --- a/tests/manual/layoutbuilder/comparison/widgets/mainwindow.h +++ b/tests/manual/layoutbuilder/comparison/widgets/mainwindow.h @@ -23,6 +23,6 @@ public: l->addWidget(pushButton); connect(pushButton, &QPushButton::clicked, - qApp, &QCoreApplication::quit); + qApp, &QApplication::quit); } }; diff --git a/tests/manual/tasktree/taskwidget.cpp b/tests/manual/tasktree/taskwidget.cpp index d5420defe59..e2770d916e3 100644 --- a/tests/manual/tasktree/taskwidget.cpp +++ b/tests/manual/tasktree/taskwidget.cpp @@ -184,11 +184,8 @@ Tasking::WorkflowPolicy GroupWidget::workflowPolicy() const return m_workflowPolicy; } - -void doLayout(const TaskGroup &taskGroup, LayoutBuilder &builder) +void createItem(Layouting::LayoutItem *item, const TaskGroup &taskGroup) { - builder.addItem(taskGroup.group); - builder.addItem(Group { taskGroup.items }); - builder.finishRow(); + item->addItems({taskGroup.group, Group { taskGroup.items }, br}); } diff --git a/tests/manual/tasktree/taskwidget.h b/tests/manual/tasktree/taskwidget.h index 8caebf658b2..0e7828ac84b 100644 --- a/tests/manual/tasktree/taskwidget.h +++ b/tests/manual/tasktree/taskwidget.h @@ -83,4 +83,4 @@ public: Layouting::Column items; }; -void doLayout(const TaskGroup &taskGroup, Layouting::LayoutBuilder &builder); +void createItem(Layouting::LayoutItem *item, const TaskGroup &taskGroup);