summaryrefslogtreecommitdiff
path: root/src/libs/utils/layoutbuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/utils/layoutbuilder.cpp')
-rw-r--r--src/libs/utils/layoutbuilder.cpp711
1 files changed, 436 insertions, 275 deletions
diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp
index e86e69a830..c7ead009c7 100644
--- a/src/libs/utils/layoutbuilder.cpp
+++ b/src/libs/utils/layoutbuilder.cpp
@@ -10,10 +10,12 @@
#include <QLabel>
#include <QPushButton>
#include <QStackedLayout>
+#include <QSpacerItem>
#include <QSplitter>
#include <QStyle>
#include <QTabWidget>
#include <QTextEdit>
+#include <QApplication>
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
*/
+struct ResultItem
+{
+ ResultItem() = default;
+ explicit ResultItem(QLayout *l) : layout(l) {}
+ explicit ResultItem(QWidget *w) : widget(w) {}
-/*!
- Constructs a layout item representing something that knows how to add it
- to a layout by itself.
- */
-QLayout *LayoutBuilder::createLayout() const
+ QString text;
+ QLayout *layout = nullptr;
+ 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;
- 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;
+
+ void flush();
+
+ int currentGridColumn = 0;
+ int currentGridRow = 0;
+
+ AttachType attachType = WithMargins;
+ QList<ResultItem> 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<QFormLayout *>(layout)) {
+
+ // 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 (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 (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<QLabel *>(l->widget())) {
+ if (QWidget *widget = widgetForItem(f))
+ label->setBuddy(widget);
+ }
+ }
+
+ } else if (auto gridLayout = qobject_cast<QGridLayout *>(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<QBoxLayout *>(layout)) {
+
+ for (const ResultItem &item : std::as_const(pendingItems))
+ addItemToBoxLayout(boxLayout, item);
+
+ } else if (auto stackLayout = qobject_cast<QStackedLayout *>(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<QLabel *>(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;
-
- auto formLayout = qobject_cast<QFormLayout *>(layout);
- auto gridLayout = qobject_cast<QGridLayout *>(layout);
- auto boxLayout = qobject_cast<QBoxLayout *>(layout);
- auto stackLayout = qobject_cast<QStackedLayout *>(layout);
-
- 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;
- }
+ ResultItem fi;
+ fi.text = text;
+ builder.stack.last().pendingItems.append(fi);
+}
- QWidget *widget = item.widget;
-
- 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);
- }
- }
+void doAddSpace(LayoutBuilder &builder, const Space &space)
+{
+ ResultItem fi;
+ fi.space = space.space;
+ builder.stack.last().pendingItems.append(fi);
+}
- if (formLayout)
- flushPendingFormItems(formLayout, pendingFormItems);
+void doAddStretch(LayoutBuilder &builder, const Stretch &stretch)
+{
+ ResultItem fi;
+ fi.stretch = stretch.stretch;
+ builder.stack.last().pendingItems.append(fi);
}
+void doAddLayout(LayoutBuilder &builder, QLayout *layout)
+{
+ builder.stack.last().pendingItems.append(ResultItem(layout));
+}
-/*!
- Constructs a layout item from the contents of another LayoutBuilder
- */
-void LayoutItem::setBuilder(const LayoutBuilder &builder)
+void doAddWidget(LayoutBuilder &builder, QWidget *widget)
{
- layout = builder.createLayout();
- doLayoutHelper(layout, builder.m_items, Layouting::WithoutMargins);
+ builder.stack.last().pendingItems.append(ResultItem(widget));
}
+
/*!
- \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<QFormLayout *>(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<LayoutItem> items)
+{
+ subItems = items;
+ onAdd = [](LayoutBuilder &builder) { builder.stack.append(new QVBoxLayout); };
+ onExit = layoutExit;
+}
+
+Row::Row(std::initializer_list<LayoutItem> items)
+{
+ subItems = items;
+ onAdd = [](LayoutBuilder &builder) { builder.stack.append(new QHBoxLayout); };
+ onExit = layoutExit;
+}
+
+Grid::Grid(std::initializer_list<LayoutItem> 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<LayoutItem> items)
+{
+ subItems = items;
+ onAdd = [](LayoutBuilder &builder) { builder.stack.append(newFormLayout()); };
+ onExit = layoutExit;
+}
+
+Stack::Stack(std::initializer_list<LayoutItem> 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<QGridLayout *>(m_layout))
- currentGridRow = gridLayout->rowCount();
- doLayoutHelper(m_layout, m_items, m_attachType, currentGridRow);
+ Slice slice;
+ slice.layout = layout;
+ if (auto gridLayout = qobject_cast<QGridLayout *>(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<LayoutItem> &items)
+template <class T>
+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<QTabWidget *>(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<LayoutItem> items)
{
- applyItems(this, new QGroupBox, items);
+ this->subItems = items;
+ setupWidget<QGroupBox>(this);
}
PushButton::PushButton(std::initializer_list<LayoutItem> items)
{
- applyItems(this, new QPushButton, items);
+ this->subItems = items;
+ setupWidget<QPushButton>(this);
}
TextEdit::TextEdit(std::initializer_list<LayoutItem> items)
{
- applyItems(this, new QTextEdit, items);
+ this->subItems = items;
+ setupWidget<QTextEdit>(this);
}
Splitter::Splitter(std::initializer_list<LayoutItem> items)
{
- applyItems(this, new QSplitter(Qt::Vertical), items);
- }
-
+ this->subItems = items;
+ setupWidget<QSplitter>(this); // FIXME: Default was Qt::Vertical)
+}
TabWidget::TabWidget(std::initializer_list<LayoutItem> items)
- {
- applyItems(this, new QTabWidget, items);
+{
+ this->subItems = items;
+ setupWidget<QTabWidget>(this);
}
-// "Properties"
+// Special Tab
-static LayoutItem setter(const LayoutItem::Setter &setter)
+Tab::Tab(const QString &tabName, const LayoutItem &item)
{
- LayoutItem item;
- item.setter = setter;
- return 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<QTabWidget *>(builder.stack.last().widget);
+ QTC_ASSERT(tabWidget, return);
+ tabWidget->addTab(inner, tabName);
+ };
+}
+
+// Special Application
+
+Application::Application(std::initializer_list<LayoutItem> items)
+{
+ subItems = items;
+ setupWidget<QWidget>(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"
+
LayoutItem title(const QString &title)
{
- return setter([title](QObject *target) {
+ return [title](QObject *target) {
if (auto groupBox = qobject_cast<QGroupBox *>(target)) {
groupBox->setTitle(title);
groupBox->setObjectName(title);
+ } else if (auto widget = qobject_cast<QWidget *>(target)) {
+ widget->setWindowTitle(title);
} else {
QTC_CHECK(false);
}
- });
+ };
}
LayoutItem onClicked(const std::function<void ()> &func, QObject *guard)
{
- return setter([func, guard](QObject *target) {
+ return [func, guard](QObject *target) {
if (auto button = qobject_cast<QAbstractButton *>(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<QAbstractButton *>(target)) {
button->setText(text);
} else if (auto textEdit = qobject_cast<QTextEdit *>(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<QWidget *>(target)) {
widget->setToolTip(toolTip);
} else {
QTC_CHECK(false);
}
- });
+ };
}
-LayoutItem bindTo(QSplitter **out)
+LayoutItem spacing(int spacing)
{
- return setter([out](QObject *target) {
- *out = qobject_cast<QSplitter *>(target);
- });
+ return [spacing](QObject *target) {
+ if (auto layout = qobject_cast<QLayout *>(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<QTabWidget *>(target);
- });
+ return [w, h](QObject *target) {
+ if (auto widget = qobject_cast<QWidget *>(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<void(QObject *target)> &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