Utils: Avoid intermediate widgets when using LayoutBuilder

In most cases, the layout constructed in the builder was set
on a widget which in turn was put into a vbox in the actual
widget. This is not necessary, but needs some re-ordering.

Also make sure that using not-yet-parented widgets during
layout construction does not cause visible artifacts.

Change-Id: I75727a571da093d3131ea6fba467c2c646cdb6f1
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
hjk
2021-03-11 19:02:42 +01:00
parent 4151f091e3
commit 035a6ff031
25 changed files with 401 additions and 365 deletions

View File

@@ -195,6 +195,10 @@ void BaseAspect::setVisible(bool visible)
d->m_visible = visible; d->m_visible = visible;
for (QWidget *w : qAsConst(d->m_subWidgets)) { for (QWidget *w : qAsConst(d->m_subWidgets)) {
QTC_ASSERT(w, continue); QTC_ASSERT(w, continue);
// This may happen during layout building. Explicit setting visibility here
// may create a show a toplevel widget for a moment until it is parented
// to some non-shown widget.
if (visible && w->parentWidget())
w->setVisible(visible); w->setVisible(visible);
} }
} }
@@ -1000,10 +1004,10 @@ void StringAspect::addToLayout(LayoutBuilder &builder)
builder.finishRow(); builder.finishRow();
} }
const auto useMacroExpander = [this, &builder](QWidget *w) { const auto useMacroExpander = [this](QWidget *w) {
if (!d->m_expanderProvider) if (!d->m_expanderProvider)
return; return;
const auto chooser = new VariableChooser(builder.layout()->parentWidget()); const auto chooser = new VariableChooser(w);
chooser->addSupportedWidget(w); chooser->addSupportedWidget(w);
chooser->addMacroExpanderProvider(d->m_expanderProvider); chooser->addMacroExpanderProvider(d->m_expanderProvider);
}; };
@@ -1208,17 +1212,19 @@ void BoolAspect::addToLayout(LayoutBuilder &builder)
d->m_checkBox->setText(labelText()); d->m_checkBox->setText(labelText());
builder.addItem(d->m_checkBox.data()); builder.addItem(d->m_checkBox.data());
break; break;
case LabelPlacement::AtCheckBox: case LabelPlacement::AtCheckBox: {
d->m_checkBox->setText(labelText()); d->m_checkBox->setText(labelText());
LayoutBuilder::LayoutType type = builder.layoutType();
if (type == LayoutBuilder::FormLayout)
builder.addItem(createSubWidget<QLabel>()); builder.addItem(createSubWidget<QLabel>());
builder.addItem(d->m_checkBox.data()); builder.addItem(d->m_checkBox.data());
break; break;
}
case LabelPlacement::InExtraLabel: case LabelPlacement::InExtraLabel:
addLabeledItem(builder, d->m_checkBox); addLabeledItem(builder, d->m_checkBox);
break; break;
} }
d->m_checkBox->setChecked(value()); d->m_checkBox->setChecked(value());
builder.addItem(d->m_checkBox.data());
connect(d->m_checkBox.data(), &QAbstractButton::clicked, this, [this] { connect(d->m_checkBox.data(), &QAbstractButton::clicked, this, [this] {
setValue(d->m_checkBox->isChecked()); setValue(d->m_checkBox->isChecked());
}); });
@@ -1965,9 +1971,12 @@ void TextDisplay::addToLayout(LayoutBuilder &builder)
d->m_label->setTextInteractionFlags(Qt::TextSelectableByMouse); d->m_label->setTextInteractionFlags(Qt::TextSelectableByMouse);
d->m_label->setElideMode(Qt::ElideNone); d->m_label->setElideMode(Qt::ElideNone);
d->m_label->setWordWrap(true); d->m_label->setWordWrap(true);
// Do not use m_label->setVisible(isVisible()) unconditionally, it does not
// have a QWidget parent yet when used in a LayoutBuilder.
if (!isVisible())
d->m_label->setVisible(false);
} }
builder.addItem(d->m_label.data()); builder.addItem(d->m_label.data());
d->m_label->setVisible(isVisible());
} }
/*! /*!

View File

@@ -48,8 +48,6 @@ namespace Utils {
\value Grid \value Grid
\value HBox \value HBox
\value VBox \value VBox
\value HBoxWithMargins
\value VBoxWithMargins
*/ */
/*! /*!
@@ -72,19 +70,17 @@ LayoutBuilder::LayoutItem::LayoutItem()
/*! /*!
Constructs a layout item proxy for \a layout, spanning the number Constructs a layout item proxy for \a layout.
of cells specified by \a span in the target layout, with alignment \a align.
*/ */
LayoutBuilder::LayoutItem::LayoutItem(QLayout *layout, int span, Alignment align) LayoutBuilder::LayoutItem::LayoutItem(QLayout *layout)
: layout(layout), span(span), align(align) : layout(layout)
{} {}
/*! /*!
Constructs a layout item proxy for \a widget, spanning the number Constructs a layout item proxy for \a widget.
of cell specified by \a span in the target layout, with alignment \a align.
*/ */
LayoutBuilder::LayoutItem::LayoutItem(QWidget *widget, int span, Alignment align) LayoutBuilder::LayoutItem::LayoutItem(QWidget *widget)
: widget(widget), span(span), align(align) : widget(widget)
{} {}
/*! /*!
@@ -95,27 +91,165 @@ LayoutBuilder::LayoutItem::LayoutItem(QWidget *widget, int span, Alignment align
\sa BaseAspect::addToLayout() \sa BaseAspect::addToLayout()
*/ */
LayoutBuilder::LayoutItem::LayoutItem(BaseAspect &aspect, int span, Alignment align) LayoutBuilder::LayoutItem::LayoutItem(BaseAspect &aspect)
: aspect(&aspect), span(span), align(align) : aspect(&aspect)
{} {}
LayoutBuilder::LayoutItem::LayoutItem(BaseAspect *aspect, int span, Alignment align) LayoutBuilder::LayoutItem::LayoutItem(BaseAspect *aspect)
: aspect(aspect), span(span), align(align) : aspect(aspect)
{} {}
/*! /*!
Constructs a layout item containing some static \a text. Constructs a layout item containing some static \a text.
*/ */
LayoutBuilder::LayoutItem::LayoutItem(const QString &text, int span, Alignment align) LayoutBuilder::LayoutItem::LayoutItem(const QString &text)
: text(text), span(span), align(align) : text(text)
{} {}
static QLayout *createLayoutFromType(LayoutBuilder::LayoutType layoutType)
{
switch (layoutType) {
case LayoutBuilder::FormLayout: {
auto formLayout = new QFormLayout;
formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
return formLayout;
}
case LayoutBuilder::GridLayout: {
auto gridLayout = new QGridLayout;
return gridLayout;
}
case LayoutBuilder::HBoxLayout: {
auto hboxLayout = new QHBoxLayout;
return hboxLayout;
}
case LayoutBuilder::VBoxLayout: {
auto vboxLayout = new QVBoxLayout;
return vboxLayout;
}
}
QTC_CHECK(false);
return nullptr;
}
static void setMargins(bool on, QLayout *layout)
{
const int d = on ? 9 : 0;
layout->setContentsMargins(d, d, d, d);
}
static void flushPendingFormItems(QFormLayout *formLayout,
LayoutBuilder::LayoutItems &pendingFormItems)
{
QTC_ASSERT(formLayout, return);
if (pendingFormItems.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;
setMargins(false, hbox);
for (int i = 1; i < pendingFormItems.size(); ++i) {
if (QWidget *w = pendingFormItems.at(i).widget)
hbox->addWidget(w);
else if (QLayout *l = pendingFormItems.at(i).layout)
hbox->addLayout(l);
else
QTC_CHECK(false);
}
while (pendingFormItems.size() >= 2)
pendingFormItems.pop_back();
pendingFormItems.append(LayoutBuilder::LayoutItem(hbox));
}
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);
}
} else {
QTC_CHECK(false);
}
pendingFormItems.clear();
}
static void doLayoutHelper(QLayout *layout,
const LayoutBuilder::LayoutItems &items,
int currentGridRow = 0)
{
int currentGridColumn = 0;
LayoutBuilder::LayoutItems pendingFormItems;
auto formLayout = qobject_cast<QFormLayout *>(layout);
auto gridLayout = qobject_cast<QGridLayout *>(layout);
auto boxLayout = qobject_cast<QBoxLayout *>(layout);
for (const LayoutBuilder::LayoutItem &item : items) {
if (item.specialType == LayoutBuilder::SpecialType::Break) {
if (formLayout)
flushPendingFormItems(formLayout, pendingFormItems);
else if (gridLayout) {
if (currentGridColumn != 0) {
++currentGridRow;
currentGridColumn = 0;
}
}
continue;
}
QWidget *widget = item.widget;
if (gridLayout) {
Qt::Alignment align;
if (item.align == LayoutBuilder::AlignmentType::AlignAsFormLabel)
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);
currentGridColumn += item.span;
} else if (boxLayout) {
if (widget) {
boxLayout->addWidget(widget);
} else if (item.layout) {
boxLayout->addLayout(item.layout);
} else if (item.specialType == LayoutBuilder::SpecialType::Stretch) {
boxLayout->addStretch(item.specialValue.toInt());
} else if (item.specialType == LayoutBuilder::SpecialType::Space) {
boxLayout->addSpacing(item.specialValue.toInt());
}
} else {
pendingFormItems.append(item);
}
}
if (formLayout)
flushPendingFormItems(formLayout, pendingFormItems);
}
/*! /*!
Constructs a layout item from the contents of another LayoutBuilder Constructs a layout item from the contents of another LayoutBuilder
*/ */
LayoutBuilder::LayoutItem::LayoutItem(const LayoutBuilder &builder, int span, Alignment align) LayoutBuilder::LayoutItem::LayoutItem(const LayoutBuilder &builder)
: widget(builder.parentWidget()), span(span), align(align) {
{} layout = createLayoutFromType(builder.m_layoutType);
doLayoutHelper(layout, builder.m_items);
setMargins(builder.m_withMargins, layout);
}
/*! /*!
\class Utils::LayoutBuilder::Space \class Utils::LayoutBuilder::Space
@@ -145,81 +279,20 @@ LayoutBuilder::LayoutItem::LayoutItem(const LayoutBuilder &builder, int span, Al
\sa addItem(), addItems(), addRow(), finishRow() \sa addItem(), addItems(), addRow(), finishRow()
*/ */
/*!
Constructs a new layout builder with the specified \a layoutType.
The constructed layout will be attached to the provided \c QWidget \a parent.
*/
LayoutBuilder::LayoutBuilder(QWidget *parent, LayoutType layoutType)
{
init(parent, layoutType);
}
LayoutBuilder::LayoutBuilder(LayoutType layoutType, const LayoutItems &items) LayoutBuilder::LayoutBuilder(LayoutType layoutType, const LayoutItems &items)
: m_layoutType(layoutType)
{ {
init(new QWidget, layoutType); m_items.reserve(items.size() * 2);
addItems(items); for (const LayoutItem &item : items)
addItem(item);
} }
void LayoutBuilder::init(QWidget *parent, LayoutType layoutType) LayoutBuilder::LayoutBuilder() = default;
{
switch (layoutType) {
case Form:
m_formLayout = new QFormLayout(parent);
m_formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
break;
case Grid:
m_gridLayout = new QGridLayout(parent);
break;
case HBox:
case HBoxWithMargins:
m_boxLayout = new QHBoxLayout(parent);
break;
case VBox:
case VBoxWithMargins:
m_boxLayout = new QVBoxLayout(parent);
break;
}
switch (layoutType) {
case Form:
case Grid:
case HBox:
case VBox:
layout()->setContentsMargins(0, 0, 0, 0);
break;
default:
break;
}
}
/*!
Constructs a new layout builder to extend an existing \a layout.
This constructor can be used to continue the work of previous layout building.
The type of the underlying layout and previous contents will be retained,
new items will be added below existing ones.
*/
LayoutBuilder::LayoutBuilder(QLayout *layout)
{
if (auto fl = qobject_cast<QFormLayout *>(layout)) {
m_formLayout = fl;
} else if (auto grid = qobject_cast<QGridLayout *>(layout)) {
m_gridLayout = grid;
m_currentGridRow = grid->rowCount();
m_currentGridColumn = 0;
}
}
/*! /*!
Destructs a layout builder. Destructs a layout builder.
*/ */
LayoutBuilder::~LayoutBuilder() LayoutBuilder::~LayoutBuilder() = default;
{
if (m_formLayout)
flushPendingFormItems();
}
/*! /*!
Instructs a layout builder to finish the current row. Instructs a layout builder to finish the current row.
@@ -227,14 +300,7 @@ LayoutBuilder::~LayoutBuilder()
*/ */
LayoutBuilder &LayoutBuilder::finishRow() LayoutBuilder &LayoutBuilder::finishRow()
{ {
if (m_formLayout) addItem(Break());
flushPendingFormItems();
if (m_gridLayout) {
if (m_currentGridColumn != 0) {
++m_currentGridRow;
m_currentGridColumn = 0;
}
}
return *this; return *this;
} }
@@ -260,182 +326,132 @@ LayoutBuilder &LayoutBuilder::addRow(const LayoutItems &items)
return finishRow().addItems(items); return finishRow().addItems(items);
} }
/*!
\internal
*/
void LayoutBuilder::flushPendingFormItems()
{
QTC_ASSERT(m_formLayout, return);
if (m_pendingFormItems.isEmpty())
return;
// If there are more than two items, we cram the last ones in one hbox.
if (m_pendingFormItems.size() > 2) {
auto hbox = new QHBoxLayout;
hbox->setContentsMargins(0, 0, 0, 0);
for (int i = 1; i < m_pendingFormItems.size(); ++i) {
if (QWidget *w = m_pendingFormItems.at(i).widget)
hbox->addWidget(w);
else if (QLayout *l = m_pendingFormItems.at(i).layout)
hbox->addItem(l);
else
QTC_CHECK(false);
}
while (m_pendingFormItems.size() >= 2)
m_pendingFormItems.takeLast();
m_pendingFormItems.append(LayoutItem(hbox));
}
if (m_pendingFormItems.size() == 1) { // One one item given, so this spans both columns.
if (auto layout = m_pendingFormItems.at(0).layout)
m_formLayout->addRow(layout);
else if (auto widget = m_pendingFormItems.at(0).widget)
m_formLayout->addRow(widget);
} else if (m_pendingFormItems.size() == 2) { // Normal case, both columns used.
if (auto label = m_pendingFormItems.at(0).widget) {
if (auto layout = m_pendingFormItems.at(1).layout)
m_formLayout->addRow(label, layout);
else if (auto widget = m_pendingFormItems.at(1).widget)
m_formLayout->addRow(label, widget);
} else {
if (auto layout = m_pendingFormItems.at(1).layout)
m_formLayout->addRow(m_pendingFormItems.at(0).text, layout);
else if (auto widget = m_pendingFormItems.at(1).widget)
m_formLayout->addRow(m_pendingFormItems.at(0).text, widget);
}
} else {
QTC_CHECK(false);
}
m_pendingFormItems.clear();
}
/*!
Returns the layout this layout builder operates on.
*/
QLayout *LayoutBuilder::layout() const
{
if (m_formLayout)
return m_formLayout;
if (m_boxLayout)
return m_boxLayout;
return m_gridLayout;
}
QWidget *LayoutBuilder::parentWidget() const
{
QLayout *l = layout();
return l ? l->parentWidget() : nullptr;
}
/*! /*!
Adds the layout item \a item to the current row. Adds the layout item \a item to the current row.
*/ */
LayoutBuilder &LayoutBuilder::addItem(const LayoutItem &item) LayoutBuilder &LayoutBuilder::addItem(const LayoutItem &item)
{ {
if (item.widget && !item.widget->parent()) if (item.aspect)
item.widget->setParent(layout()->parentWidget());
if (item.aspect) {
item.aspect->addToLayout(*this); item.aspect->addToLayout(*this);
} else { else
if (m_gridLayout) { m_items.push_back(item);
if (auto widget = item.widget) {
Qt::Alignment align;
if (item.align == AlignAsFormLabel)
align = Qt::Alignment(widget->style()->styleHint(QStyle::SH_FormLayoutLabelAlignment));
m_gridLayout->addWidget(widget, m_currentGridRow, m_currentGridColumn, 1, item.span, align);
}
m_currentGridColumn += item.span;
if (item.specialType == SpecialType::Break)
finishRow();
} else if (m_boxLayout) {
if (auto widget = item.widget) {
m_boxLayout->addWidget(widget);
} else if (item.specialType == SpecialType::Stretch) {
m_boxLayout->addStretch(item.specialValue.toInt());
} else if (item.specialType == SpecialType::Space) {
m_boxLayout->addSpacing(item.specialValue.toInt());
}
} else {
m_pendingFormItems.append(item);
}
}
return *this; return *this;
} }
void LayoutBuilder::doLayout(QWidget *parent)
{
QLayout *layout = createLayoutFromType(m_layoutType);
parent->setLayout(layout);
doLayoutHelper(layout, m_items);
setMargins(m_withMargins, layout);
}
/*! /*!
Adds the layout item \a items to the current row. Adds the layout item \a items to the current row.
*/ */
LayoutBuilder &LayoutBuilder::addItems(const QList<LayoutBuilder::LayoutItem> &items) LayoutBuilder &LayoutBuilder::addItems(const LayoutItems &items)
{ {
for (const LayoutItem &item : items) for (const LayoutItem &item : items)
addItem(item); addItem(item);
return *this; return *this;
} }
void LayoutBuilder::attachTo(QWidget *w, bool stretchAtBottom) /*!
Attach the constructed layout to the provided \c QWidget \a parent.
This operation can only be performed once per LayoutBuilder instance.
*/
void LayoutBuilder::attachTo(QWidget *w, bool withMargins)
{ {
LayoutBuilder builder(w, VBoxWithMargins); m_withMargins = withMargins;
builder.addItem(*this); doLayout(w);
if (stretchAtBottom)
builder.addItem(Stretch());
} }
QWidget *LayoutBuilder::emerge(bool withMargins)
{
m_withMargins = withMargins;
auto w = new QWidget;
doLayout(w);
return w;
}
/*!
Constructs a layout extender to extend an existing \a layout.
This constructor can be used to continue the work of previous layout building.
The type of the underlying layout and previous contents will be retained,
new items will be added below existing ones.
*/
LayoutExtender::LayoutExtender(QLayout *layout)
: m_layout(layout)
{}
LayoutExtender::~LayoutExtender()
{
QTC_ASSERT(m_layout, return);
int currentGridRow = 0;
if (auto gridLayout = qobject_cast<QGridLayout *>(m_layout))
currentGridRow = gridLayout->rowCount();
doLayoutHelper(m_layout, m_items, currentGridRow);
}
// Special items
LayoutBuilder::Break::Break() LayoutBuilder::Break::Break()
{ {
specialType = LayoutBuilder::SpecialType::Break; specialType = SpecialType::Break;
} }
LayoutBuilder::Stretch::Stretch(int stretch) LayoutBuilder::Stretch::Stretch(int stretch)
{ {
specialType = LayoutBuilder::SpecialType::Stretch; specialType = SpecialType::Stretch;
specialValue = stretch; specialValue = stretch;
} }
LayoutBuilder::Space::Space(int space) LayoutBuilder::Space::Space(int space)
{ {
specialType = LayoutBuilder::SpecialType::Space; specialType = SpecialType::Space;
specialValue = space; specialValue = space;
} }
LayoutBuilder::Title::Title(const QString &title) LayoutBuilder::Title::Title(const QString &title)
{ {
specialType = LayoutBuilder::SpecialType::Title; specialType = SpecialType::Title;
specialValue = title; specialValue = title;
} }
// FIXME: Decide on which style to use: LayoutBuilder::Span::Span(int span_, const LayoutItem &item)
// Group { Title(...), child1, child2, ...}; or
// Group { child1, child2, ... }.withTitle(...);
Layouting::Group &Layouting::Group::withTitle(const QString &title)
{ {
if (auto box = qobject_cast<QGroupBox *>(parentWidget())) LayoutBuilder::LayoutItem::operator=(item);
box->setTitle(title); span = span_;
return *this; }
LayoutBuilder::AlignAsFormLabel::AlignAsFormLabel(const LayoutItem &item)
{
LayoutBuilder::LayoutItem::operator=(item);
align = AlignmentType::AlignAsFormLabel;
} }
namespace Layouting { namespace Layouting {
Group::Group(std::initializer_list<LayoutItem> items) Group::Group(std::initializer_list<LayoutItem> items)
: LayoutBuilder(new QGroupBox, VBoxWithMargins)
{ {
auto box = new QGroupBox;
Column builder;
bool innerMargins = true;
for (const LayoutItem &item : items) { for (const LayoutItem &item : items) {
if (item.specialType == LayoutBuilder::SpecialType::Title) { if (item.specialType == LayoutBuilder::SpecialType::Title) {
auto box = qobject_cast<QGroupBox *>(parentWidget());
QTC_ASSERT(box, continue);
box->setTitle(item.specialValue.toString()); box->setTitle(item.specialValue.toString());
box->setObjectName(item.specialValue.toString());
} else { } else {
addItem(item); builder.addItem(item);
} }
} }
builder.attachTo(box, innerMargins);
widget = box;
} }
Box::Box(LayoutType type, const LayoutItems &items)
: LayoutBuilder(type, items)
{}
} // Layouting } // Layouting
} // Utils } // Utils

View File

@@ -32,9 +32,6 @@
#include <QVariant> #include <QVariant>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QBoxLayout;
class QFormLayout;
class QGridLayout;
class QLayout; class QLayout;
class QWidget; class QWidget;
QT_END_NAMESPACE QT_END_NAMESPACE
@@ -47,53 +44,49 @@ class QTCREATOR_UTILS_EXPORT LayoutBuilder
{ {
public: public:
enum LayoutType { enum LayoutType {
Form, // Plain QFormLayout, without contentMargins HBoxLayout,
Grid, // Plain QGridLayout, without contentMargins VBoxLayout,
HBox, // Plain QHBoxLayout, without contentMargins FormLayout,
VBox, // Plain QVBoxLayout, without contentMargins GridLayout,
HBoxWithMargins, // QHBoxLayout with margins };
VBoxWithMargins, // QVBoxLayout with margins
// Compat enum class AlignmentType {
FormLayout = Form, // FIXME: Remove DefaultAlignment,
GridLayout = Grid, // FIXME: Remove AlignAsFormLabel,
}; };
enum Alignment { DefaultAlignment, AlignAsFormLabel };
enum class SpecialType { enum class SpecialType {
NotSpecial, NotSpecial,
Align,
Space, Space,
Span,
Stretch, Stretch,
Break, Break,
Title Title,
}; };
class QTCREATOR_UTILS_EXPORT LayoutItem class QTCREATOR_UTILS_EXPORT LayoutItem
{ {
public: public:
LayoutItem(); LayoutItem();
LayoutItem(QLayout *layout, int span = 1, Alignment align = {}); LayoutItem(QLayout *layout);
LayoutItem(QWidget *widget, int span = 1, Alignment align = {}); LayoutItem(QWidget *widget);
LayoutItem(BaseAspect *aspect, int span = 1, Alignment align = {}); // Remove LayoutItem(BaseAspect *aspect); // Remove
LayoutItem(BaseAspect &aspect, int span = 1, Alignment align = {}); LayoutItem(BaseAspect &aspect);
LayoutItem(const QString &text, int span = 1, Alignment align = {}); LayoutItem(const QString &text);
LayoutItem(const LayoutBuilder &builder, int span = 1, Alignment align = {}); LayoutItem(const LayoutBuilder &builder);
QLayout *layout = nullptr; QLayout *layout = nullptr;
QWidget *widget = nullptr; QWidget *widget = nullptr;
BaseAspect *aspect = nullptr; BaseAspect *aspect = nullptr;
QString text; // FIXME: Use specialValue for that QString text; // FIXME: Use specialValue for that
int span = 1; int span = 1;
Alignment align; AlignmentType align = AlignmentType::DefaultAlignment;
SpecialType specialType = SpecialType::NotSpecial; SpecialType specialType = SpecialType::NotSpecial;
QVariant specialValue; QVariant specialValue;
}; };
using LayoutItems = QList<LayoutItem>; using LayoutItems = QList<LayoutItem>;
explicit LayoutBuilder(QWidget *parent, LayoutType layoutType = Form);
explicit LayoutBuilder(QLayout *layout); // Adds to existing layout.
explicit LayoutBuilder(LayoutType layoutType, const LayoutItems &items = {}); explicit LayoutBuilder(LayoutType layoutType, const LayoutItems &items = {});
LayoutBuilder(const LayoutBuilder &) = delete; LayoutBuilder(const LayoutBuilder &) = delete;
@@ -110,10 +103,10 @@ public:
LayoutBuilder &addRow(const LayoutItem &item); LayoutBuilder &addRow(const LayoutItem &item);
LayoutBuilder &addRow(const LayoutItems &items); LayoutBuilder &addRow(const LayoutItems &items);
QLayout *layout() const; LayoutType layoutType() const { return m_layoutType; }
QWidget *parentWidget() const;
void attachTo(QWidget *w, bool stretchAtBottom = true); void attachTo(QWidget *w, bool withMargins = true);
QWidget *emerge(bool withMargins = true);
class QTCREATOR_UTILS_EXPORT Space : public LayoutItem class QTCREATOR_UTILS_EXPORT Space : public LayoutItem
{ {
@@ -121,6 +114,18 @@ public:
explicit Space(int space); explicit Space(int space);
}; };
class QTCREATOR_UTILS_EXPORT Span : public LayoutItem
{
public:
Span(int span, const LayoutItem &item);
};
class QTCREATOR_UTILS_EXPORT AlignAsFormLabel : public LayoutItem
{
public:
AlignAsFormLabel(const LayoutItem &item);
};
class QTCREATOR_UTILS_EXPORT Stretch : public LayoutItem class QTCREATOR_UTILS_EXPORT Stretch : public LayoutItem
{ {
public: public:
@@ -133,75 +138,72 @@ public:
Break(); Break();
}; };
class QTCREATOR_UTILS_EXPORT Title : public LayoutBuilder::LayoutItem class QTCREATOR_UTILS_EXPORT Title : public LayoutItem
{ {
public: public:
explicit Title(const QString &title); explicit Title(const QString &title);
}; };
private: protected:
void flushPendingFormItems(); explicit LayoutBuilder(); // Adds to existing layout.
void init(QWidget *parent, LayoutType layoutType);
QFormLayout *m_formLayout = nullptr; void doLayout(QWidget *parent);
QGridLayout *m_gridLayout = nullptr;
QBoxLayout *m_boxLayout = nullptr; LayoutItems m_items;
LayoutItems m_pendingFormItems; LayoutType m_layoutType;
int m_currentGridRow = 0; bool m_withMargins = false;
int m_currentGridColumn = 0; };
class QTCREATOR_UTILS_EXPORT LayoutExtender : public LayoutBuilder
{
public:
explicit LayoutExtender(QLayout *layout);
~LayoutExtender();
private:
QLayout *m_layout = nullptr;
}; };
namespace Layouting { namespace Layouting {
class QTCREATOR_UTILS_EXPORT Group : public LayoutBuilder class QTCREATOR_UTILS_EXPORT Group : public LayoutBuilder::LayoutItem
{ {
public: public:
Group(std::initializer_list<LayoutBuilder::LayoutItem> items); Group(std::initializer_list<LayoutBuilder::LayoutItem> items);
Group &withTitle(const QString &title);
}; };
class QTCREATOR_UTILS_EXPORT Box : public LayoutBuilder class QTCREATOR_UTILS_EXPORT Column : public LayoutBuilder
{ {
public: public:
Box(LayoutType type, const LayoutItems &items); Column() : Column({}) {}
Column(std::initializer_list<LayoutItem> items) : LayoutBuilder(VBoxLayout, items) {}
}; };
class QTCREATOR_UTILS_EXPORT Column : public Box class QTCREATOR_UTILS_EXPORT Row : public LayoutBuilder
{ {
public: public:
Column(std::initializer_list<LayoutItem> items) Row() : Row({}) {}
: Box(VBox, items) Row(std::initializer_list<LayoutItem> items) : LayoutBuilder(HBoxLayout, items) {}
{}
}; };
class QTCREATOR_UTILS_EXPORT Row : public Box class QTCREATOR_UTILS_EXPORT Grid : public LayoutBuilder
{ {
public: public:
Row(std::initializer_list<LayoutItem> items) Grid() : Grid({}) {}
: Box(HBox, items) Grid(std::initializer_list<LayoutItem> items) : LayoutBuilder(GridLayout, items) {}
{}
}; };
class QTCREATOR_UTILS_EXPORT Grid : public Box class QTCREATOR_UTILS_EXPORT Form : public LayoutBuilder
{ {
public: public:
Grid(std::initializer_list<LayoutItem> items) Form() : Form({}) {}
: Box(GridLayout, items) Form(std::initializer_list<LayoutItem> items) : LayoutBuilder(FormLayout, items) {}
{}
}; };
class QTCREATOR_UTILS_EXPORT Form : public Box
{
public:
Form(std::initializer_list<LayoutItem> items)
: Box(FormLayout, items)
{}
};
using Item = LayoutBuilder::LayoutItem;
using Stretch = LayoutBuilder::Stretch; using Stretch = LayoutBuilder::Stretch;
using Space = LayoutBuilder::Space; using Space = LayoutBuilder::Space;
using Span = LayoutBuilder::Span;
using AlignAsFormLabel = LayoutBuilder::AlignAsFormLabel;
using Break = LayoutBuilder::Break; using Break = LayoutBuilder::Break;
using Title = LayoutBuilder::Title; using Title = LayoutBuilder::Title;

View File

@@ -517,10 +517,11 @@ QWidget *AndroidDeployQtStep::createConfigWidget()
AndroidManager::installQASIPackage(target(), packagePath); AndroidManager::installQASIPackage(target(), packagePath);
}); });
LayoutBuilder builder(widget); Layouting::Form builder;
builder.addRow(m_uninstallPreviousPackage); builder.addRow(m_uninstallPreviousPackage);
builder.addRow(resetDefaultDevices); builder.addRow(resetDefaultDevices);
builder.addRow(installCustomApkButton); builder.addRow(installCustomApkButton);
builder.attachTo(widget);
return widget; return widget;
} }

View File

@@ -185,10 +185,11 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
}); });
auto initialCMakeAspect = bc->aspect<InitialCMakeArgumentsAspect>(); auto initialCMakeAspect = bc->aspect<InitialCMakeArgumentsAspect>();
auto aspectWidget = new QWidget; auto aspectWidget = new QWidget;
LayoutBuilder aspectWidgetBuilder(aspectWidget); Layouting::Form aspectWidgetBuilder;
buildDirAspect->addToLayout(aspectWidgetBuilder); buildDirAspect->addToLayout(aspectWidgetBuilder);
aspectWidgetBuilder.finishRow(); aspectWidgetBuilder.finishRow();
initialCMakeAspect->addToLayout(aspectWidgetBuilder); initialCMakeAspect->addToLayout(aspectWidgetBuilder);
aspectWidgetBuilder.attachTo(aspectWidget, false);
mainLayout->addWidget(aspectWidget, row, 0, 1, -1); mainLayout->addWidget(aspectWidget, row, 0, 1, -1);
++row; ++row;
@@ -196,9 +197,9 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
connect(qmlDebugAspect, &QtSupport::QmlDebuggingAspect::changed, this, [this]() { connect(qmlDebugAspect, &QtSupport::QmlDebuggingAspect::changed, this, [this]() {
updateButtonState(); updateButtonState();
}); });
auto widget = new QWidget; Layouting::Form builder;
LayoutBuilder builder(widget);
qmlDebugAspect->addToLayout(builder); qmlDebugAspect->addToLayout(builder);
auto widget = builder.emerge();
mainLayout->addWidget(widget, row, 0, 1, -1); mainLayout->addWidget(widget, row, 0, 1, -1);
++row; ++row;

View File

@@ -442,8 +442,6 @@ QString CMakeBuildStep::activeRunConfigTarget() const
QWidget *CMakeBuildStep::createConfigWidget() QWidget *CMakeBuildStep::createConfigWidget()
{ {
auto widget = new QWidget;
auto updateDetails = [this] { auto updateDetails = [this] {
ProcessParameters param; ProcessParameters param;
setupProcessParameters(&param); setupProcessParameters(&param);
@@ -453,10 +451,6 @@ QWidget *CMakeBuildStep::createConfigWidget()
setDisplayName(tr("Build", "ConfigWidget display name.")); setDisplayName(tr("Build", "ConfigWidget display name."));
LayoutBuilder builder(widget);
builder.addRow(m_cmakeArguments);
builder.addRow(m_toolArguments);
auto buildTargetsView = new QTreeView; auto buildTargetsView = new QTreeView;
buildTargetsView->setMinimumHeight(200); buildTargetsView->setMinimumHeight(200);
buildTargetsView->setModel(&m_buildTargetModel); buildTargetsView->setModel(&m_buildTargetModel);
@@ -466,7 +460,11 @@ QWidget *CMakeBuildStep::createConfigWidget()
auto frame = ItemViewFind::createSearchableWrapper(buildTargetsView, auto frame = ItemViewFind::createSearchableWrapper(buildTargetsView,
ItemViewFind::LightColored); ItemViewFind::LightColored);
Layouting::Form builder;
builder.addRow(m_cmakeArguments);
builder.addRow(m_toolArguments);
builder.addRow({new QLabel(tr("Targets:")), frame}); builder.addRow({new QLabel(tr("Targets:")), frame});
auto widget = builder.emerge();
updateDetails(); updateDetails();

View File

@@ -233,7 +233,9 @@ CdbOptionsPageWidget::CdbOptionsPageWidget()
Title(tr("Add Exceptions to Issues View")), Title(tr("Add Exceptions to Issues View")),
s.firstChanceExceptionTaskEntry, s.firstChanceExceptionTaskEntry,
s.secondChanceExceptionTaskEntry s.secondChanceExceptionTaskEntry
} },
Stretch()
}.attachTo(this); }.attachTo(this);
} }
@@ -287,8 +289,9 @@ CdbPathsPageWidget::CdbPathsPageWidget()
finish(); finish();
Column { Column {
Group { Title(tr("Symbol Paths")), m_symbolPaths }, Group { Title(tr("Symbol Paths")), m_symbolPaths },
Group { Title(tr("Source Paths")), m_sourcePaths } Group { Title(tr("Source Paths")), m_sourcePaths },
}.attachTo(this, false); Stretch()
}.attachTo(this);
} }
void CdbPathsPageWidget::apply() void CdbPathsPageWidget::apply()

View File

@@ -170,8 +170,7 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target)
setDisplayName(tr("Debugger settings")); setDisplayName(tr("Debugger settings"));
setConfigWidgetCreator([this] { setConfigWidgetCreator([this] {
QWidget *w = new QWidget; Layouting::Form builder;
LayoutBuilder builder(w);
builder.addRow(m_cppAspect); builder.addRow(m_cppAspect);
builder.addRow(m_qmlAspect); builder.addRow(m_qmlAspect);
builder.addRow(m_overrideStartupAspect); builder.addRow(m_overrideStartupAspect);
@@ -179,8 +178,7 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target)
static const QByteArray env = qgetenv("QTC_DEBUGGER_MULTIPROCESS"); static const QByteArray env = qgetenv("QTC_DEBUGGER_MULTIPROCESS");
if (env.toInt()) if (env.toInt())
builder.addRow(m_multiProcessAspect); builder.addRow(m_multiProcessAspect);
return builder.emerge(false);
return w;
}); });
m_cppAspect = new DebuggerLanguageAspect; m_cppAspect = new DebuggerLanguageAspect;

View File

@@ -87,7 +87,8 @@ GdbOptionsPageWidget::GdbOptionsPageWidget()
Column commands { Column commands {
Group { Title { tr("Additional Startup Commands") }, s.gdbStartupCommands }, Group { Title { tr("Additional Startup Commands") }, s.gdbStartupCommands },
Group { Title { tr("Additional Attach Commands") }, s.gdbPostAttachCommands } Group { Title { tr("Additional Attach Commands") }, s.gdbPostAttachCommands },
Stretch()
}; };
Row { general, commands }.attachTo(this); Row { general, commands }.attachTo(this);
@@ -128,7 +129,7 @@ GdbOptionsPageWidget2::GdbOptionsPageWidget2()
using namespace Layouting; using namespace Layouting;
DebuggerSettings &s = *debuggerSettings(); DebuggerSettings &s = *debuggerSettings();
Group { Group extended {
Title(GdbOptionsPage::tr("Extended")), Title(GdbOptionsPage::tr("Extended")),
labelDangerous, labelDangerous,
s.targetAsync, s.targetAsync,
@@ -138,7 +139,9 @@ GdbOptionsPageWidget2::GdbOptionsPageWidget2()
s.breakOnAbort, s.breakOnAbort,
s.enableReverseDebugging, s.enableReverseDebugging,
s.multiInferior, s.multiInferior,
}.attachTo(this); };
Column { extended, Stretch() }.attachTo(this);
} }
// The "Dangerous" options. // The "Dangerous" options.

View File

@@ -435,23 +435,25 @@ QWidget *FakeVimOptionPage::widget()
s.useFakeVim, s.useFakeVim,
Group { Group {
Title(tr("Vim Behavior")),
bools, bools,
ints, ints,
strings strings
}.withTitle(tr("Vim Behavior")), },
Group { Group {
Title(tr("Plugin Emulation")),
s.emulateVimCommentary, s.emulateVimCommentary,
s.emulateReplaceWithRegister, s.emulateReplaceWithRegister,
s.emulateArgTextObj, s.emulateArgTextObj,
s.emulateExchange, s.emulateExchange,
s.emulateSurround s.emulateSurround
}.withTitle(tr("Plugin Emulation")), },
Row { copyTextEditorSettings, setQtStyle, setPlainStyle, Stretch() }, Row { copyTextEditorSettings, setQtStyle, setPlainStyle, Stretch() },
Stretch() Stretch()
}.attachTo(m_widget); }.attachTo(m_widget, true);
connect(copyTextEditorSettings, &QAbstractButton::clicked, connect(copyTextEditorSettings, &QAbstractButton::clicked,
this, &FakeVimOptionPage::copyTextEditorSettings); this, &FakeVimOptionPage::copyTextEditorSettings);

View File

@@ -51,9 +51,10 @@ MesonBuildSettingsWidget::MesonBuildSettingsWidget(MesonBuildConfiguration *buil
ui->setupUi(this); ui->setupUi(this);
ui->container->setState(Utils::DetailsWidget::NoSummary); ui->container->setState(Utils::DetailsWidget::NoSummary);
ui->container->setWidget(ui->details); ui->container->setWidget(ui->details);
LayoutBuilder buildDirWBuilder{ui->buildDirWidget};
auto buildDirAspect = buildCfg->buildDirectoryAspect(); Layouting::Form buildDirWBuilder;
buildDirAspect->addToLayout(buildDirWBuilder); buildCfg->buildDirectoryAspect()->addToLayout(buildDirWBuilder);
buildDirWBuilder.attachTo(ui->buildDirWidget);
ui->parametersLineEdit->setText(buildCfg->parameters()); ui->parametersLineEdit->setText(buildCfg->parameters());
ui->optionsFilterLineEdit->setFiltering(true); ui->optionsFilterLineEdit->setFiltering(true);

View File

@@ -102,17 +102,17 @@ NimbleTaskStep::NimbleTaskStep(BuildStepList *parentList, Id id)
QWidget *NimbleTaskStep::createConfigWidget() QWidget *NimbleTaskStep::createConfigWidget()
{ {
auto widget = new QWidget; auto taskList = new QListView;
auto taskList = new QListView(widget);
taskList->setFrameShape(QFrame::StyledPanel); taskList->setFrameShape(QFrame::StyledPanel);
taskList->setSelectionMode(QAbstractItemView::NoSelection); taskList->setSelectionMode(QAbstractItemView::NoSelection);
taskList->setSelectionBehavior(QAbstractItemView::SelectRows); taskList->setSelectionBehavior(QAbstractItemView::SelectRows);
taskList->setModel(&m_tasks); taskList->setModel(&m_tasks);
LayoutBuilder builder(widget); using namespace Layouting;
builder.addRow(m_taskArgs); auto widget = Form {
builder.addRow({tr("Tasks:"), taskList}); m_taskArgs, Break(),
tr("Tasks:"), taskList
}.emerge(false);
auto buildSystem = dynamic_cast<NimbleBuildSystem *>(this->buildSystem()); auto buildSystem = dynamic_cast<NimbleBuildSystem *>(this->buildSystem());
QTC_ASSERT(buildSystem, return widget); QTC_ASSERT(buildSystem, return widget);

View File

@@ -111,7 +111,7 @@ void BuildDirectoryAspect::addToLayout(LayoutBuilder &builder)
builder.addRow({{}, d->problemLabel.data()}); builder.addRow({{}, d->problemLabel.data()});
updateProblemLabel(); updateProblemLabel();
if (!d->sourceDir.isEmpty()) { if (!d->sourceDir.isEmpty()) {
connect(this, &StringAspect::checkedChanged, builder.layout(), [this] { connect(this, &StringAspect::checkedChanged, this, [this] {
if (isChecked()) { if (isChecked()) {
setFilePath(d->savedShadowBuildDir.isEmpty() setFilePath(d->savedShadowBuildDir.isEmpty()
? d->sourceDir : d->savedShadowBuildDir); ? d->sourceDir : d->savedShadowBuildDir);

View File

@@ -326,11 +326,12 @@ NamedWidget *BuildConfiguration::createConfigWidget()
widget = named; widget = named;
} }
LayoutBuilder builder(widget); Layouting::Form builder;
for (BaseAspect *aspect : aspects()) { for (BaseAspect *aspect : aspects()) {
if (aspect->isVisible()) if (aspect->isVisible())
aspect->addToLayout(builder.finishRow()); aspect->addToLayout(builder.finishRow());
} }
builder.attachTo(widget, false);
return named; return named;
} }

View File

@@ -179,13 +179,12 @@ QWidget *BuildStep::doCreateConfigWidget()
QWidget *BuildStep::createConfigWidget() QWidget *BuildStep::createConfigWidget()
{ {
auto widget = new QWidget; Layouting::Form builder;
LayoutBuilder builder(widget);
for (BaseAspect *aspect : qAsConst(m_aspects)) { for (BaseAspect *aspect : qAsConst(m_aspects)) {
if (aspect->isVisible()) if (aspect->isVisible())
aspect->addToLayout(builder.finishRow()); aspect->addToLayout(builder.finishRow());
} }
auto widget = builder.emerge(false);
if (m_addMacroExpander) if (m_addMacroExpander)
VariableChooser::addSupportForChildWidgets(widget, macroExpander()); VariableChooser::addSupportForChildWidgets(widget, macroExpander());

View File

@@ -737,7 +737,7 @@ void KitAspectWidget::addToLayout(LayoutBuilder &builder)
m_label = new QLabel(m_kitInformation->displayName() + ':'); m_label = new QLabel(m_kitInformation->displayName() + ':');
m_label->setToolTip(m_kitInformation->description()); m_label->setToolTip(m_kitInformation->description());
builder.addRow({{m_label, 1, LayoutBuilder::AlignAsFormLabel}, mainWidget(), buttonWidget()}); builder.addRow({LayoutBuilder::AlignAsFormLabel(m_label), mainWidget(), buttonWidget()});
} }
void KitAspectWidget::setVisible(bool visible) void KitAspectWidget::setVisible(bool visible)

View File

@@ -68,10 +68,8 @@ KitManagerConfigWidget::KitManagerConfigWidget(Kit *k) :
{ {
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
LayoutBuilder builder(this, LayoutBuilder::GridLayout);
QLabel *label = new QLabel(tr("Name:")); QLabel *label = new QLabel(tr("Name:"));
label->setToolTip(tr("Kit name and icon.")); label->setToolTip(tr("Kit name and icon."));
builder.addRow({{label, 1, LayoutBuilder::AlignAsFormLabel}, m_nameEdit, m_iconButton});
QString toolTip = QString toolTip =
tr("<html><head/><body><p>The name of the kit suitable for generating " tr("<html><head/><body><p>The name of the kit suitable for generating "
@@ -85,10 +83,15 @@ KitManagerConfigWidget::KitManagerConfigWidget(Kit *k) :
label = new QLabel(tr("File system name:")); label = new QLabel(tr("File system name:"));
label->setToolTip(toolTip); label->setToolTip(toolTip);
builder.addRow({{label, 1, LayoutBuilder::AlignAsFormLabel}, m_fileSystemFriendlyNameLineEdit});
connect(m_fileSystemFriendlyNameLineEdit, &QLineEdit::textChanged, connect(m_fileSystemFriendlyNameLineEdit, &QLineEdit::textChanged,
this, &KitManagerConfigWidget::setFileSystemFriendlyName); this, &KitManagerConfigWidget::setFileSystemFriendlyName);
using namespace Layouting;
Grid {
AlignAsFormLabel(label), m_nameEdit, m_iconButton, Break(),
AlignAsFormLabel(label), m_fileSystemFriendlyNameLineEdit
}.attachTo(this);
m_iconButton->setToolTip(tr("Kit icon.")); m_iconButton->setToolTip(tr("Kit icon."));
auto setIconAction = new QAction(tr("Select Icon..."), this); auto setIconAction = new QAction(tr("Select Icon..."), this);
m_iconButton->addAction(setIconAction); m_iconButton->addAction(setIconAction);
@@ -230,7 +233,7 @@ void KitManagerConfigWidget::addAspectToWorkingCopy(KitAspect *aspect)
m_actions << action; m_actions << action;
LayoutBuilder builder(layout()); LayoutExtender builder(layout());
widget->addToLayout(builder); widget->addToLayout(builder);
m_widgets.append(widget); m_widgets.append(widget);
} }

View File

@@ -346,9 +346,7 @@ CommandLine MakeStep::effectiveMakeCommand(MakeCommandType type) const
QWidget *MakeStep::createConfigWidget() QWidget *MakeStep::createConfigWidget()
{ {
auto widget = new QWidget; Layouting::Form builder;
LayoutBuilder builder(widget);
builder.addRow(m_makeCommandAspect); builder.addRow(m_makeCommandAspect);
builder.addRow(m_userArgumentsAspect); builder.addRow(m_userArgumentsAspect);
builder.addRow({m_userJobCountAspect, m_overrideMakeflagsAspect, m_nonOverrideWarning}); builder.addRow({m_userJobCountAspect, m_overrideMakeflagsAspect, m_nonOverrideWarning});
@@ -356,6 +354,8 @@ QWidget *MakeStep::createConfigWidget()
builder.addRow(m_disabledForSubdirsAspect); builder.addRow(m_disabledForSubdirsAspect);
builder.addRow(m_buildTargetsAspect); builder.addRow(m_buildTargetsAspect);
auto widget = builder.emerge(false);
VariableChooser::addSupportForChildWidgets(widget, macroExpander()); VariableChooser::addSupportForChildWidgets(widget, macroExpander());
setSummaryUpdater([this] { setSummaryUpdater([this] {

View File

@@ -215,14 +215,13 @@ bool RunConfiguration::isEnabled() const
QWidget *RunConfiguration::createConfigurationWidget() QWidget *RunConfiguration::createConfigurationWidget()
{ {
auto widget = new QWidget; Layouting::Form builder;
{
LayoutBuilder builder(widget);
for (BaseAspect *aspect : qAsConst(m_aspects)) { for (BaseAspect *aspect : qAsConst(m_aspects)) {
if (aspect->isVisible()) if (aspect->isVisible())
aspect->addToLayout(builder.finishRow()); aspect->addToLayout(builder.finishRow());
} }
}
auto widget = builder.emerge(false);
VariableChooser::addSupportForChildWidgets(widget, &m_expander); VariableChooser::addSupportForChildWidgets(widget, &m_expander);

View File

@@ -129,8 +129,8 @@ void ArchitecturesAspect::addToLayout(LayoutBuilder &builder)
setVisibleDynamic(true); setVisibleDynamic(true);
}; };
connect(KitManager::instance(), &KitManager::kitsChanged, builder.layout(), changeHandler); connect(KitManager::instance(), &KitManager::kitsChanged, this, changeHandler);
connect(this, &ArchitecturesAspect::changed, builder.layout(), changeHandler); connect(this, &ArchitecturesAspect::changed, this, changeHandler);
changeHandler(); changeHandler();
} }
@@ -668,7 +668,7 @@ QbsBuildStepConfigWidget::QbsBuildStepConfigWidget(QbsBuildStep *step) :
installDirChooser = new PathChooser(this); installDirChooser = new PathChooser(this);
installDirChooser->setExpectedKind(PathChooser::Directory); installDirChooser->setExpectedKind(PathChooser::Directory);
LayoutBuilder builder(this); Layouting::Form builder;
builder.addRow(m_qbsStep->m_buildVariant); builder.addRow(m_qbsStep->m_buildVariant);
builder.addRow(m_qbsStep->m_selectedAbis); builder.addRow(m_qbsStep->m_selectedAbis);
builder.addRow(m_qbsStep->m_maxJobCount); builder.addRow(m_qbsStep->m_maxJobCount);
@@ -686,6 +686,7 @@ QbsBuildStepConfigWidget::QbsBuildStepConfigWidget(QbsBuildStep *step) :
builder.addRow({tr("Installation directory:"), installDirChooser}); builder.addRow({tr("Installation directory:"), installDirChooser});
builder.addRow(m_qbsStep->m_commandLine); builder.addRow(m_qbsStep->m_commandLine);
builder.attachTo(this, false);
propertyEdit->setToolTip(tr("Properties to pass to the project.")); propertyEdit->setToolTip(tr("Properties to pass to the project."));
defaultInstallDirCheckBox->setText(tr("Use default location")); defaultInstallDirCheckBox->setText(tr("Use default location"));

View File

@@ -193,7 +193,7 @@ QWidget *QbsInstallStep::createConfigWidget()
commandLineTextEdit->setTextInteractionFlags(Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse); commandLineTextEdit->setTextInteractionFlags(Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse);
commandLineTextEdit->setMinimumHeight(QFontMetrics(widget->font()).height() * 8); commandLineTextEdit->setMinimumHeight(QFontMetrics(widget->font()).height() * 8);
LayoutBuilder builder(widget); Layouting::Form builder;
builder.addRow({tr("Install root:"), installRootValueLabel}); builder.addRow({tr("Install root:"), installRootValueLabel});
builder.addRow(tr("Flags:")); builder.addRow(tr("Flags:"));
m_dryRun->addToLayout(builder); m_dryRun->addToLayout(builder);
@@ -201,6 +201,7 @@ QWidget *QbsInstallStep::createConfigWidget()
m_cleanInstallRoot->addToLayout(builder); m_cleanInstallRoot->addToLayout(builder);
builder.addRow({commandLineKeyLabel, commandLineTextEdit}); builder.addRow({commandLineKeyLabel, commandLineTextEdit});
builder.attachTo(widget);
const auto updateState = [this, commandLineTextEdit, installRootValueLabel] { const auto updateState = [this, commandLineTextEdit, installRootValueLabel] {
installRootValueLabel->setText(installRoot()); installRootValueLabel->setText(installRoot());

View File

@@ -511,18 +511,17 @@ bool QMakeStep::fromMap(const QVariantMap &map)
QWidget *QMakeStep::createConfigWidget() QWidget *QMakeStep::createConfigWidget()
{ {
auto widget = new QWidget; abisLabel = new QLabel(tr("ABIs:"));
abisLabel = new QLabel(tr("ABIs:"), widget);
abisLabel->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop); abisLabel->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop);
abisListWidget = new QListWidget(widget); abisListWidget = new QListWidget;
LayoutBuilder builder(widget); Layouting::Form builder;
builder.addRow(m_buildType); builder.addRow(m_buildType);
builder.addRow(m_userArgs); builder.addRow(m_userArgs);
builder.addRow(m_effectiveCall); builder.addRow(m_effectiveCall);
builder.addRow({abisLabel, abisListWidget}); builder.addRow({abisLabel, abisListWidget});
auto widget = builder.emerge(false);
qmakeBuildConfigChanged(); qmakeBuildConfigChanged();

View File

@@ -67,10 +67,11 @@ void QmlDebuggingAspect::addToLayout(LayoutBuilder &builder)
warningLabel->setText(warningText); warningLabel->setText(warningText);
setVisible(supported); setVisible(supported);
const bool warningLabelsVisible = supported && !warningText.isEmpty(); const bool warningLabelsVisible = supported && !warningText.isEmpty();
if (!warningLabel->parentWidget())
warningLabel->setVisible(warningLabelsVisible); warningLabel->setVisible(warningLabelsVisible);
}; };
connect(KitManager::instance(), &KitManager::kitsChanged, builder.layout(), changeHandler); connect(KitManager::instance(), &KitManager::kitsChanged, this, changeHandler);
connect(this, &QmlDebuggingAspect::changed, builder.layout(), changeHandler); connect(this, &QmlDebuggingAspect::changed, this, changeHandler);
changeHandler(); changeHandler();
} }
@@ -102,11 +103,11 @@ void QtQuickCompilerAspect::addToLayout(LayoutBuilder &builder)
const bool warningLabelsVisible = supported && !warningText.isEmpty(); const bool warningLabelsVisible = supported && !warningText.isEmpty();
warningLabel->setVisible(warningLabelsVisible); warningLabel->setVisible(warningLabelsVisible);
}; };
connect(KitManager::instance(), &KitManager::kitsChanged, builder.layout(), changeHandler); connect(KitManager::instance(), &KitManager::kitsChanged, this, changeHandler);
connect(this, &QmlDebuggingAspect::changed, builder.layout(), changeHandler); connect(this, &QmlDebuggingAspect::changed, this, changeHandler);
connect(this, &QtQuickCompilerAspect::changed, builder.layout(), changeHandler); connect(this, &QtQuickCompilerAspect::changed, this, changeHandler);
if (m_qmlDebuggingAspect) { if (m_qmlDebuggingAspect) {
connect(m_qmlDebuggingAspect, &QmlDebuggingAspect::changed, builder.layout(), connect(m_qmlDebuggingAspect, &QmlDebuggingAspect::changed, this,
changeHandler); changeHandler);
} }
changeHandler(); changeHandler();

View File

@@ -88,14 +88,14 @@ ValgrindConfigWidget::ValgrindConfigWidget(ValgrindBaseSettings *settings)
s.minimumInclusiveCostRatio, nl, s.minimumInclusiveCostRatio, nl,
s.visualizationMinimumInclusiveCostRatio, nl, s.visualizationMinimumInclusiveCostRatio, nl,
s.enableEventToolTips, nl, s.enableEventToolTips, nl,
Item { Span {
2,
Group { Group {
s.enableCacheSim, s.enableCacheSim,
s.enableBranchSim, s.enableBranchSim,
s.collectSystime, s.collectSystime,
s.collectBusEvents, s.collectBusEvents,
}, }
2 // Span.
} }
}; };

View File

@@ -214,14 +214,12 @@ void SuppressionAspect::addToLayout(LayoutBuilder &builder)
connect(d->entryList->selectionModel(), &QItemSelectionModel::selectionChanged, connect(d->entryList->selectionModel(), &QItemSelectionModel::selectionChanged,
d, &SuppressionAspectPrivate::slotSuppressionSelectionChanged); d, &SuppressionAspectPrivate::slotSuppressionSelectionChanged);
Group group { builder.addItem(tr("Suppression files:"));
Title(tr("Suppression files:")), Row group {
Row {
d->entryList.data(), d->entryList.data(),
Column { d->addEntry.data(), d->removeEntry.data(), Stretch() } Column { d->addEntry.data(), d->removeEntry.data(), Stretch() }
}
}; };
builder.addItem(Item { group, 2 }); builder.addItem(Span { 2, group });
} }
void SuppressionAspect::fromMap(const QVariantMap &map) void SuppressionAspect::fromMap(const QVariantMap &map)