forked from qt-creator/qt-creator
LayoutBuilder: Update demo
Backport the learnings and simplification from the real use to the demo case. Change-Id: I3f501b03c760484961bfd586735c0db53ba080db Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "lb.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QFormLayout>
|
||||
#include <QGridLayout>
|
||||
@@ -29,19 +28,20 @@ namespace Layouting {
|
||||
#define QTC_ASSERT(cond, action) if (Q_LIKELY(cond)) {} else { QTC_STRING(#cond); action; } do {} while (0)
|
||||
#define QTC_CHECK(cond) if (cond) {} else { QTC_STRING(#cond); } do {} while (0)
|
||||
|
||||
|
||||
template <typename XInterface>
|
||||
XInterface::Implementation *access(const XInterface *x)
|
||||
template <typename X>
|
||||
X::Implementation *access(const X *x)
|
||||
{
|
||||
return static_cast<XInterface::Implementation *>(x->ptr);
|
||||
return static_cast<X::Implementation *>(x->ptr);
|
||||
}
|
||||
|
||||
// Setter implementation
|
||||
template <typename X>
|
||||
void apply(X *x, std::initializer_list<typename X::I> ps)
|
||||
{
|
||||
for (auto && p : ps)
|
||||
p.apply(x);
|
||||
}
|
||||
|
||||
// These are free functions overloaded on the type of builder object
|
||||
// and setter id. The function implementations are independent, but
|
||||
// the base expectation is that they will forwards to the backend
|
||||
// type's setter.
|
||||
// FlowLayout
|
||||
|
||||
class FlowLayout : public QLayout
|
||||
{
|
||||
@@ -193,37 +193,49 @@ private:
|
||||
\namespace Layouting
|
||||
\inmodule QtCreator
|
||||
|
||||
\brief The Layouting namespace contains classes for use with layout builders.
|
||||
\brief The Layouting namespace contains classes and functions to conveniently
|
||||
create layouts in code.
|
||||
|
||||
Classes in the namespace help to create create QLayout or QWidget derived class,
|
||||
instances should be used locally within a function and never stored.
|
||||
|
||||
\sa Layouting::Widget, Layouting::Layout
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\class Layouting::Layout
|
||||
\inmodule QtCreator
|
||||
|
||||
The Layout class is a base class for more specific builder
|
||||
classes to create QLayout derived objects.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\class Layouting::Widget
|
||||
\inmodule QtCreator
|
||||
|
||||
The Widget class is a base class for more specific builder
|
||||
classes to create QWidget derived objects.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\class Layouting::LayoutItem
|
||||
\inmodule QtCreator
|
||||
|
||||
\brief The LayoutItem class represents widgets, layouts, and aggregate
|
||||
items for use in conjunction with layout builders.
|
||||
|
||||
Layout items are typically implicitly constructed when adding items to a
|
||||
\c LayoutBuilder instance using \c LayoutBuilder::addItem() or
|
||||
\c LayoutBuilder::addItems() and never stored in user code.
|
||||
The LayoutItem class is used for intermediate results
|
||||
while creating layouts with a concept of rows and spans, such
|
||||
as Form and Grid.
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs a layout item instance representing an empty cell.
|
||||
*/
|
||||
LayoutItem::LayoutItem() = default;
|
||||
Layout::LayoutItem::LayoutItem() = default;
|
||||
|
||||
LayoutItem::~LayoutItem() = default;
|
||||
|
||||
LayoutItem::LayoutItem(const LayoutInterface &inner)
|
||||
: LayoutItem(access(&inner))
|
||||
{}
|
||||
|
||||
LayoutItem::LayoutItem(const WidgetInterface &inner)
|
||||
: LayoutItem(access(&inner))
|
||||
{}
|
||||
Layout::LayoutItem::~LayoutItem() = default;
|
||||
|
||||
Layout::LayoutItem::LayoutItem(const LayoutModifier &inner)
|
||||
{
|
||||
ownerModifier = inner;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn template <class T> LayoutItem(const T &t)
|
||||
@@ -239,16 +251,12 @@ LayoutItem::LayoutItem(const WidgetInterface &inner)
|
||||
\endlist
|
||||
*/
|
||||
|
||||
// Helpers
|
||||
|
||||
|
||||
// Object
|
||||
|
||||
Object::Object(std::initializer_list<I> ps)
|
||||
{
|
||||
create();
|
||||
for (auto && p : ps)
|
||||
apply(p);
|
||||
ptr = new Implementation;
|
||||
apply(this, ps);
|
||||
}
|
||||
|
||||
static QWidget *widgetForItem(QLayoutItem *item)
|
||||
@@ -273,6 +281,8 @@ static QLabel *createLabel(const QString &text)
|
||||
return label;
|
||||
}
|
||||
|
||||
using LayoutItem = Layout::LayoutItem;
|
||||
|
||||
static void addItemToBoxLayout(QBoxLayout *layout, const LayoutItem &item)
|
||||
{
|
||||
if (QWidget *w = item.widget) {
|
||||
@@ -281,8 +291,6 @@ static void addItemToBoxLayout(QBoxLayout *layout, const LayoutItem &item)
|
||||
layout->addLayout(l);
|
||||
} 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 if (item.empty) {
|
||||
@@ -300,8 +308,6 @@ static void addItemToFlowLayout(FlowLayout *layout, const LayoutItem &item)
|
||||
layout->addItem(l);
|
||||
// } else if (item.stretch != -1) {
|
||||
// layout->addStretch(item.stretch);
|
||||
// } else if (item.space != -1) {
|
||||
// layout->addSpacing(item.space);
|
||||
} else if (item.empty) {
|
||||
// Nothing to do, but no reason to warn, either
|
||||
} else if (!item.text.isEmpty()) {
|
||||
@@ -311,31 +317,6 @@ static void addItemToFlowLayout(FlowLayout *layout, const LayoutItem &item)
|
||||
}
|
||||
}
|
||||
|
||||
// void doAddSpace(LayoutBuilder &builder, const Space &space)
|
||||
// {
|
||||
// ResultItem fi;
|
||||
// fi.space = space.space;
|
||||
// builder.stack.last().pendingItems.append(fi);
|
||||
// }
|
||||
|
||||
// void doAddStretch(LayoutBuilder &builder, const Stretch &stretch)
|
||||
// {
|
||||
// Item fi;
|
||||
// fi.stretch = stretch.stretch;
|
||||
// builder.stack.last().pendingItems.append(fi);
|
||||
// }
|
||||
|
||||
// void doAddLayout(LayoutBuilder &builder, QLayout *layout)
|
||||
// {
|
||||
// builder.stack.last().pendingItems.append(Item(layout));
|
||||
// }
|
||||
|
||||
// void doAddWidget(LayoutBuilder &builder, QWidget *widget)
|
||||
// {
|
||||
// builder.stack.last().pendingItems.append(Item(widget));
|
||||
// }
|
||||
|
||||
|
||||
/*!
|
||||
\class Layouting::Space
|
||||
\inmodule QtCreator
|
||||
@@ -350,26 +331,68 @@ static void addItemToFlowLayout(FlowLayout *layout, const LayoutItem &item)
|
||||
\brief The Stretch class represents some stretch in a layout.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\class Layouting::LayoutBuilder
|
||||
\internal
|
||||
\inmodule QtCreator
|
||||
|
||||
\brief The LayoutBuilder class provides a convenient way to fill \c QFormLayout
|
||||
and \c QGridLayouts with contents.
|
||||
// Layout
|
||||
|
||||
Filling a layout with items happens item-by-item, row-by-row.
|
||||
void Layout::span(int cols, int rows)
|
||||
{
|
||||
QTC_ASSERT(!pendingItems.empty(), return);
|
||||
pendingItems.back().spanCols = cols;
|
||||
pendingItems.back().spanRows = rows;
|
||||
}
|
||||
|
||||
A LayoutBuilder instance is typically used locally within a function and never stored.
|
||||
void Layout::noMargin()
|
||||
{
|
||||
customMargin({});
|
||||
}
|
||||
|
||||
\sa addItem(), addItems()
|
||||
*/
|
||||
void Layout::normalMargin()
|
||||
{
|
||||
customMargin({9, 9, 9, 9});
|
||||
}
|
||||
|
||||
void Layout::customMargin(const QMargins &margin)
|
||||
{
|
||||
access(this)->setContentsMargins(margin);
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
Destructs a layout builder.
|
||||
Attaches the constructed layout to the provided QWidget \a w.
|
||||
|
||||
This operation can only be performed once per LayoutBuilder instance.
|
||||
*/
|
||||
void Layout::attachTo(QWidget *widget)
|
||||
{
|
||||
flush();
|
||||
widget->setLayout(access(this));
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds the layout item \a item as sub items.
|
||||
*/
|
||||
void Layout::addItem(I item)
|
||||
{
|
||||
item.apply(this);
|
||||
}
|
||||
|
||||
void Layout::addItemHelper(const LayoutItem &item)
|
||||
{
|
||||
if (QBoxLayout *lt = asBox())
|
||||
addItemToBoxLayout(lt, item);
|
||||
else if (FlowLayout *lt = asFlow())
|
||||
addItemToFlowLayout(lt, item);
|
||||
else
|
||||
pendingItems.push_back(item);
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds the layout items \a items as sub items.
|
||||
*/
|
||||
void Layout::addItems(std::initializer_list<I> items)
|
||||
{
|
||||
for (const I &item : items)
|
||||
item.apply(this);
|
||||
}
|
||||
|
||||
/*!
|
||||
Starts a new row containing \a items. The row can be further extended by
|
||||
@@ -377,160 +400,141 @@ static void addItemToFlowLayout(FlowLayout *layout, const LayoutItem &item)
|
||||
|
||||
\sa addItem(), addItems()
|
||||
*/
|
||||
// void LayoutItem::addRow(const LayoutItems &items)
|
||||
// {
|
||||
// addItem(br);
|
||||
// addItems(items);
|
||||
// }
|
||||
|
||||
// /*!
|
||||
// Adds the layout item \a item as sub items.
|
||||
// */
|
||||
// void LayoutItem::addItem(const LayoutItem &item)
|
||||
// {
|
||||
// subItems.append(item);
|
||||
// }
|
||||
|
||||
// /*!
|
||||
// Adds the layout items \a items as sub items.
|
||||
// */
|
||||
// void LayoutItem::addItems(const LayoutItems &items)
|
||||
// {
|
||||
// subItems.append(items);
|
||||
// }
|
||||
|
||||
// /*!
|
||||
// Attaches the constructed layout to the provided QWidget \a w.
|
||||
|
||||
// This operation can only be performed once per LayoutBuilder instance.
|
||||
// */
|
||||
|
||||
// void LayoutItem::attachTo(QWidget *w) const
|
||||
// {
|
||||
// LayoutBuilder builder;
|
||||
|
||||
// builder.stack.append(w);
|
||||
// addItemHelper(builder, *this);
|
||||
// }
|
||||
|
||||
|
||||
// Layout
|
||||
|
||||
void LayoutInterface::span(int cols, int rows)
|
||||
void Layout::addRow(std::initializer_list<I> items)
|
||||
{
|
||||
QTC_ASSERT(!pendingItems.empty(), return);
|
||||
pendingItems.back().spanCols = cols;
|
||||
pendingItems.back().spanRows = rows;
|
||||
for (const I &item : items)
|
||||
item.apply(this);
|
||||
flush();
|
||||
}
|
||||
|
||||
void LayoutInterface::noMargin()
|
||||
void Layout::setSpacing(int spacing)
|
||||
{
|
||||
customMargin({});
|
||||
access(this)->setSpacing(spacing);
|
||||
}
|
||||
|
||||
void LayoutInterface::normalMargin()
|
||||
void Layout::setColumnStretch(int column, int stretch)
|
||||
{
|
||||
customMargin({9, 9, 9, 9});
|
||||
if (auto grid = qobject_cast<QGridLayout *>(access(this))) {
|
||||
grid->setColumnStretch(column, stretch);
|
||||
} else {
|
||||
QTC_CHECK(false);
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutInterface::customMargin(const QMargins &margin)
|
||||
void addToWidget(Widget *widget, const Layout &layout)
|
||||
{
|
||||
access(this)->setContentsMargins(margin);
|
||||
layout.flush_();
|
||||
access(widget)->setLayout(access(&layout));
|
||||
}
|
||||
|
||||
void LayoutInterface::addItem(const LayoutItem &item)
|
||||
{
|
||||
if (item.break_)
|
||||
flush();
|
||||
else
|
||||
pendingItems.push_back(item);
|
||||
}
|
||||
|
||||
void addNestedItem(WidgetInterface *widget, const LayoutInterface &layout)
|
||||
{
|
||||
widget->setLayout(layout);
|
||||
}
|
||||
|
||||
void addNestedItem(LayoutInterface *layout, const WidgetInterface &inner)
|
||||
void addToLayout(Layout *layout, const Widget &inner)
|
||||
{
|
||||
LayoutItem item;
|
||||
item.widget = access(&inner);
|
||||
layout->addItem(item);
|
||||
layout->addItemHelper(item);
|
||||
}
|
||||
|
||||
void addNestedItem(LayoutInterface *layout, const LayoutItem &inner)
|
||||
{
|
||||
layout->addItem(inner);
|
||||
}
|
||||
|
||||
void addNestedItem(LayoutInterface *layout, const LayoutInterface &inner)
|
||||
void addToLayout(Layout *layout, QWidget *inner)
|
||||
{
|
||||
LayoutItem item;
|
||||
item.layout = access(&inner);
|
||||
layout->addItem(item);
|
||||
item.widget = inner;
|
||||
layout->addItemHelper(item);
|
||||
}
|
||||
|
||||
void addNestedItem(LayoutInterface *layout, const std::function<LayoutItem()> &inner)
|
||||
void addToLayout(Layout *layout, QLayout *inner)
|
||||
{
|
||||
LayoutItem item = inner();
|
||||
layout->addItem(item);
|
||||
LayoutItem item;
|
||||
item.layout = inner;
|
||||
layout->addItemHelper(item);
|
||||
}
|
||||
|
||||
void addNestedItem(LayoutInterface *layout, const QString &inner)
|
||||
void addToLayout(Layout *layout, const Layout &inner)
|
||||
{
|
||||
inner.flush_();
|
||||
LayoutItem item;
|
||||
item.layout = access(&inner);
|
||||
layout->addItemHelper(item);
|
||||
}
|
||||
|
||||
void addToLayout(Layout *layout, const LayoutModifier &inner)
|
||||
{
|
||||
inner(layout);
|
||||
}
|
||||
|
||||
void addToLayout(Layout *layout, const QString &inner)
|
||||
{
|
||||
LayoutItem item;
|
||||
item.text = inner;
|
||||
layout->addItem(item);
|
||||
layout->addItemHelper(item);
|
||||
}
|
||||
|
||||
LayoutItem empty()
|
||||
void empty(Layout *iface)
|
||||
{
|
||||
LayoutItem item;
|
||||
item.empty = true;
|
||||
return item;
|
||||
iface->addItemHelper(item);
|
||||
}
|
||||
|
||||
LayoutItem hr()
|
||||
void hr(Layout *layout)
|
||||
{
|
||||
LayoutItem item;
|
||||
item.widget = createHr();
|
||||
return item;
|
||||
layout->addItemHelper(createHr());
|
||||
}
|
||||
|
||||
LayoutItem br()
|
||||
void br(Layout *iface)
|
||||
{
|
||||
LayoutItem item;
|
||||
item.break_ = true;
|
||||
return item;
|
||||
iface->flush();
|
||||
}
|
||||
|
||||
LayoutItem st()
|
||||
void st(Layout *iface)
|
||||
{
|
||||
LayoutItem item;
|
||||
item.stretch = 1;
|
||||
return item;
|
||||
iface->addItemHelper(item);
|
||||
}
|
||||
|
||||
QFormLayout *LayoutInterface::asForm()
|
||||
void noMargin(Layout *iface)
|
||||
{
|
||||
iface->noMargin();
|
||||
}
|
||||
|
||||
void normalMargin(Layout *iface)
|
||||
{
|
||||
iface->normalMargin();
|
||||
}
|
||||
|
||||
QFormLayout *Layout::asForm()
|
||||
{
|
||||
return qobject_cast<QFormLayout *>(access(this));
|
||||
}
|
||||
|
||||
QGridLayout *LayoutInterface::asGrid()
|
||||
QGridLayout *Layout::asGrid()
|
||||
{
|
||||
return qobject_cast<QGridLayout *>(access(this));
|
||||
}
|
||||
|
||||
QBoxLayout *LayoutInterface::asBox()
|
||||
QBoxLayout *Layout::asBox()
|
||||
{
|
||||
return qobject_cast<QBoxLayout *>(access(this));
|
||||
}
|
||||
|
||||
void LayoutInterface::flush()
|
||||
FlowLayout *Layout::asFlow()
|
||||
{
|
||||
return dynamic_cast<FlowLayout *>(access(this));
|
||||
}
|
||||
|
||||
void Layout::flush()
|
||||
{
|
||||
if (pendingItems.empty())
|
||||
return;
|
||||
|
||||
if (QGridLayout *lt = asGrid()) {
|
||||
for (const LayoutItem &item : std::as_const(pendingItems)) {
|
||||
Qt::Alignment a = currentGridColumn == 0 ? align : Qt::Alignment();
|
||||
Qt::Alignment a;
|
||||
if (currentGridColumn == 0 && useFormAlignment) {
|
||||
// if (auto widget = builder.stack.at(builder.stack.size() - 2).widget) {
|
||||
// a = widget->style()->styleHint(QStyle::SH_FormLayoutLabelAlignment);
|
||||
}
|
||||
if (item.widget)
|
||||
lt->addWidget(item.widget, currentGridRow, currentGridColumn, item.spanRows, item.spanCols, a);
|
||||
else if (item.layout)
|
||||
@@ -551,11 +555,11 @@ void LayoutInterface::flush()
|
||||
if (pendingItems.size() > 2) {
|
||||
auto hbox = new QHBoxLayout;
|
||||
hbox->setContentsMargins(0, 0, 0, 0);
|
||||
for (int i = 1; i < pendingItems.size(); ++i)
|
||||
for (size_t i = 1; i < pendingItems.size(); ++i)
|
||||
addItemToBoxLayout(hbox, pendingItems.at(i));
|
||||
while (pendingItems.size() > 1)
|
||||
pendingItems.pop_back();
|
||||
pendingItems.push_back(LayoutItem(hbox));
|
||||
pendingItems.push_back(hbox);
|
||||
}
|
||||
|
||||
if (pendingItems.size() == 1) { // Only one item given, so this spans both columns.
|
||||
@@ -601,133 +605,138 @@ void LayoutInterface::flush()
|
||||
pendingItems.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
QTC_CHECK(false); // The other layouts shouldn't use flush()
|
||||
}
|
||||
|
||||
// LayoutItem withFormAlignment()
|
||||
// {
|
||||
// LayoutItem item;
|
||||
// item.onAdd = [](LayoutBuilder &builder) {
|
||||
// if (builder.stack.size() >= 2) {
|
||||
// if (auto widget = builder.stack.at(builder.stack.size() - 2).widget) {
|
||||
// const Qt::Alignment align(widget->style()->styleHint(QStyle::SH_FormLayoutLabelAlignment));
|
||||
// builder.stack.last().align = align;
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// return item;
|
||||
// }
|
||||
void Layout::flush_() const
|
||||
{
|
||||
const_cast<Layout *>(this)->flush();
|
||||
}
|
||||
|
||||
void withFormAlignment(Layout *iface)
|
||||
{
|
||||
iface->useFormAlignment = true;
|
||||
}
|
||||
|
||||
// Flow
|
||||
|
||||
Flow::Flow(std::initializer_list<I> ps)
|
||||
{
|
||||
adopt(new FlowLayout);
|
||||
for (auto && p : ps)
|
||||
apply(p);
|
||||
// for (const LayoutItem &item : std::as_const(pendingItems))
|
||||
// addItemToFlowLayout(flowLayout, item);
|
||||
|
||||
ptr = new FlowLayout;
|
||||
apply(this, ps);
|
||||
flush();
|
||||
}
|
||||
|
||||
// Row & Column
|
||||
|
||||
Row::Row(std::initializer_list<I> ps)
|
||||
{
|
||||
adopt(new QHBoxLayout);
|
||||
for (auto && p : ps)
|
||||
apply(p);
|
||||
auto self = asBox();
|
||||
for (const LayoutItem &item : pendingItems)
|
||||
addItemToBoxLayout(self, item);
|
||||
ptr = new QHBoxLayout;
|
||||
apply(this, ps);
|
||||
flush();
|
||||
}
|
||||
|
||||
Column::Column(std::initializer_list<I> ps)
|
||||
{
|
||||
adopt(new QVBoxLayout);
|
||||
for (auto && p : ps)
|
||||
apply(p);
|
||||
auto self = asBox();
|
||||
for (const LayoutItem &item : pendingItems)
|
||||
addItemToBoxLayout(self, item);
|
||||
ptr = new QVBoxLayout;
|
||||
apply(this, ps);
|
||||
flush();
|
||||
}
|
||||
|
||||
// Grid
|
||||
|
||||
Grid::Grid()
|
||||
{
|
||||
ptr = new QGridLayout;
|
||||
}
|
||||
|
||||
Grid::Grid(std::initializer_list<I> ps)
|
||||
{
|
||||
adopt(new QGridLayout);
|
||||
for (auto && p : ps)
|
||||
apply(p);
|
||||
ptr = new QGridLayout;
|
||||
apply(this, ps);
|
||||
flush();
|
||||
}
|
||||
|
||||
// Form
|
||||
|
||||
Form::Form()
|
||||
{
|
||||
ptr = new QFormLayout;
|
||||
}
|
||||
|
||||
Form::Form(std::initializer_list<I> ps)
|
||||
{
|
||||
adopt(new QFormLayout);
|
||||
fieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
|
||||
for (auto && p : ps)
|
||||
apply(p);
|
||||
auto lt = new QFormLayout;
|
||||
ptr = lt;
|
||||
lt->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
|
||||
apply(this, ps);
|
||||
flush();
|
||||
}
|
||||
|
||||
void LayoutInterface::fieldGrowthPolicy(int policy)
|
||||
void Layout::fieldGrowthPolicy(int policy)
|
||||
{
|
||||
if (auto lt = asForm())
|
||||
lt->setFieldGrowthPolicy(QFormLayout::FieldGrowthPolicy(policy));
|
||||
}
|
||||
|
||||
QWidget *Layout::emerge() const
|
||||
{
|
||||
const_cast<Layout *>(this)->flush();
|
||||
QWidget *widget = new QWidget;
|
||||
widget->setLayout(access(this));
|
||||
return widget;
|
||||
}
|
||||
|
||||
// "Widgets"
|
||||
|
||||
Widget::Widget(std::initializer_list<I> ps)
|
||||
{
|
||||
create();
|
||||
for (auto && p : ps)
|
||||
apply(p);
|
||||
ptr = new Implementation;
|
||||
apply(this, ps);
|
||||
}
|
||||
|
||||
void WidgetInterface::resize(int w, int h)
|
||||
void Widget::resize(int w, int h)
|
||||
{
|
||||
access(this)->resize(w, h);
|
||||
}
|
||||
|
||||
void WidgetInterface::setLayout(const LayoutInterface &layout)
|
||||
void Widget::setLayout(const Layout &layout)
|
||||
{
|
||||
access(this)->setLayout(access(&layout));
|
||||
}
|
||||
|
||||
void WidgetInterface::setWindowTitle(const QString &title)
|
||||
void Widget::setWindowTitle(const QString &title)
|
||||
{
|
||||
access(this)->setWindowTitle(title);
|
||||
}
|
||||
|
||||
void WidgetInterface::setToolTip(const QString &title)
|
||||
void Widget::setToolTip(const QString &title)
|
||||
{
|
||||
access(this)->setToolTip(title);
|
||||
}
|
||||
|
||||
void WidgetInterface::show()
|
||||
void Widget::show()
|
||||
{
|
||||
access(this)->show();
|
||||
}
|
||||
|
||||
void WidgetInterface::noMargin()
|
||||
void Widget::noMargin(int)
|
||||
{
|
||||
customMargin({});
|
||||
}
|
||||
|
||||
void WidgetInterface::normalMargin()
|
||||
void Widget::normalMargin(int)
|
||||
{
|
||||
customMargin({9, 9, 9, 9});
|
||||
}
|
||||
|
||||
void WidgetInterface::customMargin(const QMargins &margin)
|
||||
void Widget::customMargin(const QMargins &margin)
|
||||
{
|
||||
access(this)->setContentsMargins(margin);
|
||||
}
|
||||
|
||||
QWidget *WidgetInterface::emerge()
|
||||
QWidget *Widget::emerge() const
|
||||
{
|
||||
return access(this);
|
||||
}
|
||||
@@ -736,18 +745,17 @@ QWidget *WidgetInterface::emerge()
|
||||
|
||||
Label::Label(std::initializer_list<I> ps)
|
||||
{
|
||||
create();
|
||||
for (auto && p : ps)
|
||||
apply(p);
|
||||
ptr = new Implementation;
|
||||
apply(this, ps);
|
||||
}
|
||||
|
||||
Label::Label(const QString &text)
|
||||
{
|
||||
create();
|
||||
ptr = new Implementation;
|
||||
setText(text);
|
||||
}
|
||||
|
||||
void LabelInterface::setText(const QString &text)
|
||||
void Label::setText(const QString &text)
|
||||
{
|
||||
access(this)->setText(text);
|
||||
}
|
||||
@@ -756,32 +764,35 @@ void LabelInterface::setText(const QString &text)
|
||||
|
||||
Group::Group(std::initializer_list<I> ps)
|
||||
{
|
||||
create();
|
||||
for (auto && p : ps)
|
||||
apply(p);
|
||||
ptr = new Implementation;
|
||||
apply(this, ps);
|
||||
}
|
||||
|
||||
void GroupInterface::setTitle(const QString &title)
|
||||
void Group::setTitle(const QString &title)
|
||||
{
|
||||
access(this)->setTitle(title);
|
||||
access(this)->setObjectName(title);
|
||||
}
|
||||
|
||||
void Group::setGroupChecker(const std::function<void (QObject *)> &checker)
|
||||
{
|
||||
checker(access(this));
|
||||
}
|
||||
|
||||
// SpinBox
|
||||
|
||||
SpinBox::SpinBox(std::initializer_list<I> ps)
|
||||
{
|
||||
create();
|
||||
for (auto && p : ps)
|
||||
apply(p);
|
||||
ptr = new Implementation;
|
||||
apply(this, ps);
|
||||
}
|
||||
|
||||
void SpinBoxInterface::setValue(int val)
|
||||
void SpinBox::setValue(int val)
|
||||
{
|
||||
access(this)->setValue(val);
|
||||
}
|
||||
|
||||
void SpinBoxInterface::onTextChanged(const std::function<void (QString)> &func)
|
||||
void SpinBox::onTextChanged(const std::function<void (QString)> &func)
|
||||
{
|
||||
QObject::connect(access(this), &QSpinBox::textChanged, func);
|
||||
}
|
||||
@@ -790,12 +801,11 @@ void SpinBoxInterface::onTextChanged(const std::function<void (QString)> &func)
|
||||
|
||||
TextEdit::TextEdit(std::initializer_list<I> ps)
|
||||
{
|
||||
create();
|
||||
for (auto && p : ps)
|
||||
apply(p);
|
||||
ptr = new Implementation;
|
||||
apply(this, ps);
|
||||
}
|
||||
|
||||
void TextEditInterface::setText(const QString &text)
|
||||
void TextEdit::setText(const QString &text)
|
||||
{
|
||||
access(this)->setText(text);
|
||||
}
|
||||
@@ -804,19 +814,18 @@ void TextEditInterface::setText(const QString &text)
|
||||
|
||||
PushButton::PushButton(std::initializer_list<I> ps)
|
||||
{
|
||||
create();
|
||||
for (auto && p : ps)
|
||||
apply(p);
|
||||
ptr = new Implementation;
|
||||
apply(this, ps);
|
||||
}
|
||||
|
||||
void PushButtonInterface::setText(const QString &text)
|
||||
void PushButton::setText(const QString &text)
|
||||
{
|
||||
access(this)->setText(text);
|
||||
}
|
||||
|
||||
void PushButtonInterface::onClicked(const std::function<void ()> &func)
|
||||
void PushButton::onClicked(const std::function<void ()> &func, QObject *guard)
|
||||
{
|
||||
QObject::connect(access(this), &QAbstractButton::clicked, func);
|
||||
QObject::connect(access(this), &QAbstractButton::clicked, guard, func);
|
||||
}
|
||||
|
||||
// Stack
|
||||
@@ -826,88 +835,92 @@ void PushButtonInterface::onClicked(const std::function<void ()> &func)
|
||||
// top-level widget. This can lead to the focus shifting away from the main application.
|
||||
Stack::Stack(std::initializer_list<I> ps)
|
||||
{
|
||||
create();
|
||||
for (auto && p : ps)
|
||||
apply(p);
|
||||
ptr = new Implementation;
|
||||
apply(this, ps);
|
||||
}
|
||||
|
||||
void addToStack(Stack *stack, const Widget &inner)
|
||||
{
|
||||
access(stack)->addWidget(inner.emerge());
|
||||
}
|
||||
|
||||
void addToStack(Stack *stack, const Layout &inner)
|
||||
{
|
||||
inner.flush_();
|
||||
access(stack)->addWidget(inner.emerge());
|
||||
}
|
||||
|
||||
void addToStack(Stack *stack, QWidget *inner)
|
||||
{
|
||||
access(stack)->addWidget(inner);
|
||||
}
|
||||
|
||||
// Splitter
|
||||
|
||||
Splitter::Splitter(std::initializer_list<I> ps)
|
||||
{
|
||||
create();
|
||||
ptr = new Implementation;
|
||||
access(this)->setOrientation(Qt::Vertical);
|
||||
for (auto && p : ps)
|
||||
apply(p);
|
||||
apply(this, ps);
|
||||
}
|
||||
|
||||
void addToSplitter(Splitter *splitter, QWidget *inner)
|
||||
{
|
||||
access(splitter)->addWidget(inner);
|
||||
}
|
||||
|
||||
void addToSplitter(Splitter *splitter, const Widget &inner)
|
||||
{
|
||||
access(splitter)->addWidget(inner.emerge());
|
||||
}
|
||||
|
||||
void addToSplitter(Splitter *splitter, const Layout &inner)
|
||||
{
|
||||
inner.flush_();
|
||||
access(splitter)->addWidget(inner.emerge());
|
||||
}
|
||||
|
||||
// ToolBar
|
||||
|
||||
ToolBar::ToolBar(std::initializer_list<I> ps)
|
||||
{
|
||||
create();
|
||||
ptr = new Implementation;
|
||||
apply(this, ps);
|
||||
access(this)->setOrientation(Qt::Horizontal);
|
||||
for (auto && p : ps)
|
||||
apply(p);
|
||||
}
|
||||
|
||||
// TabWidget
|
||||
|
||||
TabWidget::TabWidget(std::initializer_list<I> ps)
|
||||
{
|
||||
create();
|
||||
for (auto && p : ps)
|
||||
apply(p);
|
||||
ptr = new Implementation;
|
||||
apply(this, ps);
|
||||
}
|
||||
|
||||
// // Special Tab
|
||||
Tab::Tab(const QString &tabName, const Layout &inner)
|
||||
: tabName(tabName), inner(inner)
|
||||
{}
|
||||
|
||||
// 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<QTabWidget *>(builder.stack.last().widget);
|
||||
// QTC_ASSERT(tabWidget, return);
|
||||
// tabWidget->addTab(inner, tabName);
|
||||
// };
|
||||
// }
|
||||
void addToTabWidget(TabWidget *tabWidget, const Tab &tab)
|
||||
{
|
||||
access(tabWidget)->addTab(tab.inner.emerge(), tab.tabName);
|
||||
}
|
||||
|
||||
// // Special If
|
||||
// Special If
|
||||
|
||||
// If::If(bool condition, const LayoutItems &items, const LayoutItems &other)
|
||||
// {
|
||||
// subItems.append(condition ? items : other);
|
||||
// }
|
||||
If::If(bool condition,
|
||||
const std::initializer_list<Layout::I> ifcase,
|
||||
const std::initializer_list<Layout::I> thencase)
|
||||
: used(condition ? ifcase : thencase)
|
||||
{}
|
||||
|
||||
// "Properties"
|
||||
void addToLayout(Layout *layout, const If &inner)
|
||||
{
|
||||
for (const Layout::I &item : inner.used)
|
||||
item.apply(layout);
|
||||
}
|
||||
|
||||
// LayoutItem spacing(int spacing)
|
||||
// {
|
||||
// return [spacing](QObject *target) {
|
||||
// if (auto layout = qobject_cast<QLayout *>(target)) {
|
||||
// layout->setSpacing(spacing);
|
||||
// } else {
|
||||
// QTC_CHECK(false);
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
|
||||
// LayoutItem columnStretch(int column, int stretch)
|
||||
// {
|
||||
// return [column, stretch](QObject *target) {
|
||||
// if (auto grid = qobject_cast<QGridLayout *>(target)) {
|
||||
// grid->setColumnStretch(column, stretch);
|
||||
// } else {
|
||||
// QTC_CHECK(false);
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// Specials
|
||||
|
||||
QWidget *createHr(QWidget *parent)
|
||||
{
|
||||
@@ -917,10 +930,34 @@ QWidget *createHr(QWidget *parent)
|
||||
return frame;
|
||||
}
|
||||
|
||||
Span::Span(int n, const LayoutItem &item)
|
||||
: LayoutItem(item)
|
||||
Span::Span(int n, const Layout::I &item)
|
||||
: item(item), spanCols(n)
|
||||
{}
|
||||
|
||||
void addToLayout(Layout *layout, const Span &inner)
|
||||
{
|
||||
spanCols = n;
|
||||
LayoutItem item;
|
||||
layout->addItem(inner.item);
|
||||
QTC_ASSERT(!layout->pendingItems.empty(), return);
|
||||
layout->pendingItems.back().spanCols = inner.spanCols;
|
||||
layout->pendingItems.back().spanRows = inner.spanRows;
|
||||
}
|
||||
|
||||
LayoutModifier spacing(int space)
|
||||
{
|
||||
return [space](Layout *iface) { iface->setSpacing(space); };
|
||||
}
|
||||
|
||||
void addToLayout(Layout *layout, const Space &inner)
|
||||
{
|
||||
if (auto lt = layout->asBox())
|
||||
lt->addSpacing(inner.space);
|
||||
}
|
||||
|
||||
void addToLayout(Layout *layout, const Stretch &inner)
|
||||
{
|
||||
if (auto lt = layout->asBox())
|
||||
lt->addStretch(inner.stretch);
|
||||
}
|
||||
|
||||
// void createItem(LayoutItem *item, QWidget *t)
|
||||
|
@@ -4,11 +4,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QList>
|
||||
#include <QMargins>
|
||||
#include <QString>
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
|
||||
#if defined(UTILS_LIBRARY)
|
||||
@@ -24,6 +23,7 @@ class QBoxLayout;
|
||||
class QFormLayout;
|
||||
class QGridLayout;
|
||||
class QGroupBox;
|
||||
class QHBoxLayout;
|
||||
class QLabel;
|
||||
class QLayout;
|
||||
class QMargins;
|
||||
@@ -35,129 +35,67 @@ class QStackedWidget;
|
||||
class QTabWidget;
|
||||
class QTextEdit;
|
||||
class QToolBar;
|
||||
class QVBoxLayout;
|
||||
class QWidget;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Layouting {
|
||||
|
||||
struct LayoutItem;
|
||||
|
||||
// struct NestId {};
|
||||
struct NestId {};
|
||||
class NestId {};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct IdAndArg
|
||||
{
|
||||
IdAndArg(const T1 &id, const T2 &arg) : id(id), arg(arg) {}
|
||||
T1 id;
|
||||
T2 arg;
|
||||
};
|
||||
|
||||
// The main dispatchers
|
||||
|
||||
void doit(auto x, auto id, auto a);
|
||||
|
||||
// BuilderItem
|
||||
|
||||
template <typename X, typename XInterface>
|
||||
struct BuilderItem : XInterface
|
||||
class IdAndArg
|
||||
{
|
||||
public:
|
||||
struct I
|
||||
IdAndArg(const T1 &id, const T2 &arg) : id(id), arg(arg) {}
|
||||
const T1 id;
|
||||
const T2 arg; // FIXME: Could be const &, but this would currently break bindTo().
|
||||
};
|
||||
|
||||
// The main dispatcher
|
||||
|
||||
void doit(auto x, auto id, auto p);
|
||||
|
||||
template <typename X> class BuilderItem
|
||||
{
|
||||
public:
|
||||
// Nested child object
|
||||
template <typename Inner>
|
||||
BuilderItem(Inner && p)
|
||||
{
|
||||
// Nested child object
|
||||
template <typename Inner>
|
||||
I(const Inner &p)
|
||||
{
|
||||
apply = [p](XInterface *x) { doit(x, NestId{}, p); };
|
||||
}
|
||||
|
||||
// Property setter
|
||||
template <typename Id, typename Arg1>
|
||||
I(const IdAndArg<Id, Arg1> &p)
|
||||
{
|
||||
apply = [p](XInterface *x) { doit(x, p.id, p.arg); };
|
||||
}
|
||||
|
||||
std::function<void(XInterface *)> apply;
|
||||
};
|
||||
|
||||
void create()
|
||||
{
|
||||
XInterface::ptr = new XInterface::Implementation;
|
||||
apply = [&p](X *x) { doit(x, NestId{}, std::forward<Inner>(p)); };
|
||||
}
|
||||
|
||||
void adopt(XInterface::Implementation *ptr)
|
||||
// Property setter
|
||||
template <typename Id, typename Arg>
|
||||
BuilderItem(IdAndArg<Id, Arg> && idarg)
|
||||
{
|
||||
XInterface::ptr = ptr;
|
||||
apply = [&idarg](X *x) { doit(x, idarg.id, idarg.arg); };
|
||||
}
|
||||
|
||||
void apply(const I &init)
|
||||
{
|
||||
init.apply(this);
|
||||
}
|
||||
|
||||
using Id = typename XInterface::Implementation *;
|
||||
std::function<void(X *)> apply;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////
|
||||
|
||||
struct LayoutInterface;
|
||||
struct WidgetInterface;
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT LayoutItem
|
||||
{
|
||||
LayoutItem();
|
||||
LayoutItem(QLayout *l) : layout(l), empty(!l) {}
|
||||
LayoutItem(QWidget *w) : widget(w), empty(!w) {}
|
||||
LayoutItem(const QString &t) : text(t) {}
|
||||
LayoutItem(const LayoutInterface &inner);
|
||||
LayoutItem(const WidgetInterface &inner);
|
||||
~LayoutItem();
|
||||
|
||||
QString text;
|
||||
QLayout *layout = nullptr;
|
||||
QWidget *widget = nullptr;
|
||||
int space = -1;
|
||||
int stretch = -1;
|
||||
int spanCols = 1;
|
||||
int spanRows = 1;
|
||||
bool empty = false;
|
||||
bool break_ = false;
|
||||
};
|
||||
|
||||
using LayoutItems = QList<LayoutItem>;
|
||||
|
||||
|
||||
// We need two classes for each user visible Builder type.
|
||||
// The actual Builder classes derive from BuilderItem with two parameters,
|
||||
// one is the Builder class itself for CRTP and a one "Interface" type.
|
||||
// The "Interface" types act (individually, and as a hierarchy) as interface
|
||||
// members of the real QObject/QWidget/... hierarchy things. This wrapper is not
|
||||
// strictly needed, the Q* hierarchy could be used directly, at the
|
||||
// price of #include'ing the definitions of each participating class,
|
||||
// which does not scale well.
|
||||
|
||||
//
|
||||
// Basic
|
||||
//
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT ThingInterface
|
||||
class QTCREATOR_UTILS_EXPORT Thing
|
||||
{
|
||||
template <typename T>
|
||||
T *access_() const { return static_cast<T *>(ptr); }
|
||||
|
||||
public:
|
||||
void *ptr; // The product.
|
||||
};
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT ObjectInterface : ThingInterface
|
||||
class QTCREATOR_UTILS_EXPORT Object : public Thing
|
||||
{
|
||||
public:
|
||||
using Implementation = QObject;
|
||||
};
|
||||
using I = BuilderItem<Object>;
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT Object : BuilderItem<Object, ObjectInterface>
|
||||
{
|
||||
Object() = default;
|
||||
Object(std::initializer_list<I> ps);
|
||||
};
|
||||
|
||||
@@ -165,235 +103,288 @@ struct QTCREATOR_UTILS_EXPORT Object : BuilderItem<Object, ObjectInterface>
|
||||
// Layouts
|
||||
//
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT LayoutInterface : ObjectInterface
|
||||
class FlowLayout;
|
||||
class Layout;
|
||||
using LayoutModifier = std::function<void(Layout *)>;
|
||||
// using LayoutModifier = void(*)(Layout *);
|
||||
|
||||
class QTCREATOR_UTILS_EXPORT Layout : public Object
|
||||
{
|
||||
public:
|
||||
using Implementation = QLayout;
|
||||
using I = BuilderItem<Layout>;
|
||||
|
||||
Layout() = default;
|
||||
Layout(Implementation *w) { ptr = w; }
|
||||
|
||||
class LayoutItem
|
||||
{
|
||||
public:
|
||||
~LayoutItem();
|
||||
LayoutItem();
|
||||
LayoutItem(QLayout *l) : layout(l) {}
|
||||
LayoutItem(QWidget *w) : widget(w) {}
|
||||
LayoutItem(const QString &t) : text(t) {}
|
||||
LayoutItem(const LayoutModifier &inner);
|
||||
|
||||
QString text;
|
||||
QLayout *layout = nullptr;
|
||||
QWidget *widget = nullptr;
|
||||
int stretch = -1;
|
||||
int spanCols = 1;
|
||||
int spanRows = 1;
|
||||
bool empty = false;
|
||||
LayoutModifier ownerModifier;
|
||||
//Qt::Alignment align = {};
|
||||
};
|
||||
|
||||
void span(int cols, int rows);
|
||||
void noMargin();
|
||||
void normalMargin();
|
||||
void customMargin(const QMargins &margin);
|
||||
void setColumnStretch(int cols, int rows);
|
||||
void setSpacing(int space);
|
||||
|
||||
void addItem(const LayoutItem &item);
|
||||
void attachTo(QWidget *);
|
||||
void addItemHelper(const LayoutItem &item);
|
||||
void addItem(I item);
|
||||
void addItems(std::initializer_list<I> items);
|
||||
void addRow(std::initializer_list<I> items);
|
||||
|
||||
void flush();
|
||||
void flush_() const;
|
||||
void fieldGrowthPolicy(int policy);
|
||||
|
||||
QWidget *emerge() const;
|
||||
|
||||
QFormLayout *asForm();
|
||||
QGridLayout *asGrid();
|
||||
QBoxLayout *asBox();
|
||||
|
||||
std::vector<LayoutItem> pendingItems;
|
||||
FlowLayout *asFlow();
|
||||
|
||||
// Grid-only
|
||||
int currentGridColumn = 0;
|
||||
int currentGridRow = 0;
|
||||
Qt::Alignment align = {};
|
||||
//Qt::Alignment align = {};
|
||||
bool useFormAlignment = false;
|
||||
|
||||
std::vector<LayoutItem> pendingItems;
|
||||
};
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT Layout : BuilderItem<Layout, LayoutInterface>
|
||||
class QTCREATOR_UTILS_EXPORT Column : public Layout
|
||||
{
|
||||
};
|
||||
public:
|
||||
using Implementation = QVBoxLayout;
|
||||
using I = BuilderItem<Column>;
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT Column : BuilderItem<Column, LayoutInterface>
|
||||
{
|
||||
Column(std::initializer_list<I> ps);
|
||||
};
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT Row : BuilderItem<Row, LayoutInterface>
|
||||
class QTCREATOR_UTILS_EXPORT Row : public Layout
|
||||
{
|
||||
public:
|
||||
using Implementation = QHBoxLayout;
|
||||
using I = BuilderItem<Row>;
|
||||
|
||||
Row(std::initializer_list<I> ps);
|
||||
};
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT Form : BuilderItem<Form, LayoutInterface>
|
||||
class QTCREATOR_UTILS_EXPORT Form : public Layout
|
||||
{
|
||||
public:
|
||||
using Implementation = QFormLayout;
|
||||
using I = BuilderItem<Form>;
|
||||
|
||||
Form();
|
||||
Form(std::initializer_list<I> ps);
|
||||
};
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT Grid : BuilderItem<Grid, LayoutInterface>
|
||||
class QTCREATOR_UTILS_EXPORT Grid : public Layout
|
||||
{
|
||||
public:
|
||||
using Implementation = QGridLayout;
|
||||
using I = BuilderItem<Grid>;
|
||||
|
||||
Grid();
|
||||
Grid(std::initializer_list<I> ps);
|
||||
};
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT Flow : BuilderItem<Flow, LayoutInterface>
|
||||
class QTCREATOR_UTILS_EXPORT Flow : public Layout
|
||||
{
|
||||
public:
|
||||
Flow(std::initializer_list<I> ps);
|
||||
};
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT Stretch : LayoutItem
|
||||
class QTCREATOR_UTILS_EXPORT Stretch
|
||||
{
|
||||
explicit Stretch(int stretch) { this->stretch = stretch; }
|
||||
public:
|
||||
explicit Stretch(int stretch) : stretch(stretch) {}
|
||||
|
||||
int stretch;
|
||||
};
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT Space : LayoutItem
|
||||
class QTCREATOR_UTILS_EXPORT Space
|
||||
{
|
||||
explicit Space(int space) { this->space = space; }
|
||||
public:
|
||||
explicit Space(int space) : space(space) {}
|
||||
|
||||
int space;
|
||||
};
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT Span : LayoutItem
|
||||
class QTCREATOR_UTILS_EXPORT Span
|
||||
{
|
||||
Span(int n, const LayoutItem &item);
|
||||
public:
|
||||
Span(int n, const Layout::I &item);
|
||||
|
||||
Layout::I item;
|
||||
int spanCols = 1;
|
||||
int spanRows = 1;
|
||||
};
|
||||
|
||||
//
|
||||
// Widgets
|
||||
//
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT WidgetInterface : ObjectInterface
|
||||
class QTCREATOR_UTILS_EXPORT Widget : public Object
|
||||
{
|
||||
public:
|
||||
using Implementation = QWidget;
|
||||
QWidget *emerge();
|
||||
using I = BuilderItem<Widget>;
|
||||
|
||||
Widget() = default;
|
||||
Widget(std::initializer_list<I> ps);
|
||||
Widget(Implementation *w) { ptr = w; }
|
||||
|
||||
QWidget *emerge() const;
|
||||
|
||||
void show();
|
||||
void resize(int, int);
|
||||
void setLayout(const LayoutInterface &layout);
|
||||
void setLayout(const Layout &layout);
|
||||
void setWindowTitle(const QString &);
|
||||
void setToolTip(const QString &);
|
||||
void noMargin();
|
||||
void normalMargin();
|
||||
void noMargin(int = 0);
|
||||
void normalMargin(int = 0);
|
||||
void customMargin(const QMargins &margin);
|
||||
};
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT Widget : BuilderItem<Widget, WidgetInterface>
|
||||
{
|
||||
Widget(std::initializer_list<I> ps);
|
||||
};
|
||||
|
||||
// Label
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT LabelInterface : WidgetInterface
|
||||
class QTCREATOR_UTILS_EXPORT Label : public Widget
|
||||
{
|
||||
public:
|
||||
using Implementation = QLabel;
|
||||
using I = BuilderItem<Label>;
|
||||
|
||||
Label(std::initializer_list<I> ps);
|
||||
Label(const QString &text);
|
||||
|
||||
void setText(const QString &);
|
||||
};
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT Label : BuilderItem<Label, LabelInterface>
|
||||
{
|
||||
Label(std::initializer_list<I> ps);
|
||||
Label(const QString &text);
|
||||
};
|
||||
|
||||
// Group
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT GroupInterface : WidgetInterface
|
||||
class QTCREATOR_UTILS_EXPORT Group : public Widget
|
||||
{
|
||||
public:
|
||||
using Implementation = QGroupBox;
|
||||
using I = BuilderItem<Group>;
|
||||
|
||||
Group(std::initializer_list<I> ps);
|
||||
|
||||
void setTitle(const QString &);
|
||||
void setGroupChecker(const std::function<void(QObject *)> &);
|
||||
};
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT Group : BuilderItem<Group, GroupInterface>
|
||||
{
|
||||
Group(std::initializer_list<I> ps);
|
||||
};
|
||||
|
||||
// SpinBox
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT SpinBoxInterface : WidgetInterface
|
||||
class QTCREATOR_UTILS_EXPORT SpinBox : public Widget
|
||||
{
|
||||
public:
|
||||
using Implementation = QSpinBox;
|
||||
using I = BuilderItem<SpinBox>;
|
||||
|
||||
SpinBox(std::initializer_list<I> ps);
|
||||
|
||||
void setValue(int);
|
||||
void onTextChanged(const std::function<void(QString)> &);
|
||||
};
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT SpinBox : BuilderItem<SpinBox, SpinBoxInterface>
|
||||
{
|
||||
SpinBox(std::initializer_list<I> ps);
|
||||
};
|
||||
|
||||
// PushButton
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT PushButtonInterface : WidgetInterface
|
||||
class QTCREATOR_UTILS_EXPORT PushButton : public Widget
|
||||
{
|
||||
public:
|
||||
using Implementation = QPushButton;
|
||||
using I = BuilderItem<PushButton>;
|
||||
|
||||
void setText(const QString &);
|
||||
void onClicked(const std::function<void()> &);
|
||||
};
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT PushButton : BuilderItem<PushButton, PushButtonInterface>
|
||||
{
|
||||
PushButton(std::initializer_list<I> ps);
|
||||
|
||||
void setText(const QString &);
|
||||
void onClicked(const std::function<void()> &, QObject *guard);
|
||||
};
|
||||
|
||||
// TextEdit
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT TextEditInterface : WidgetInterface
|
||||
class QTCREATOR_UTILS_EXPORT TextEdit : public Widget
|
||||
{
|
||||
public:
|
||||
using Implementation = QTextEdit;
|
||||
using I = BuilderItem<TextEdit>;
|
||||
using Id = Implementation *;
|
||||
|
||||
TextEdit(std::initializer_list<I> ps);
|
||||
|
||||
void setText(const QString &);
|
||||
};
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT TextEdit : BuilderItem<TextEdit, TextEditInterface>
|
||||
{
|
||||
TextEdit(std::initializer_list<I> ps);
|
||||
};
|
||||
|
||||
// Splitter
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT SplitterInterface : WidgetInterface
|
||||
class QTCREATOR_UTILS_EXPORT Splitter : public Widget
|
||||
{
|
||||
public:
|
||||
using Implementation = QSplitter;
|
||||
};
|
||||
using I = BuilderItem<Splitter>;
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT Splitter : BuilderItem<Splitter, SplitterInterface>
|
||||
{
|
||||
Splitter(std::initializer_list<I> items);
|
||||
};
|
||||
|
||||
// Stack
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT StackInterface : WidgetInterface
|
||||
class QTCREATOR_UTILS_EXPORT Stack : public Widget
|
||||
{
|
||||
};
|
||||
public:
|
||||
using Implementation = QStackedWidget;
|
||||
using I = BuilderItem<Stack>;
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT Stack : BuilderItem<Stack, StackInterface>
|
||||
{
|
||||
Stack() : Stack({}) {}
|
||||
Stack(std::initializer_list<I> items);
|
||||
};
|
||||
|
||||
// TabWidget
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT TabInterface : WidgetInterface
|
||||
class QTCREATOR_UTILS_EXPORT Tab : public Widget
|
||||
{
|
||||
public:
|
||||
using Implementation = QWidget;
|
||||
|
||||
Tab(const QString &tabName, const Layout &inner);
|
||||
|
||||
const QString tabName;
|
||||
const Layout inner;
|
||||
};
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT TabWidgetInterface : WidgetInterface
|
||||
class QTCREATOR_UTILS_EXPORT TabWidget : public Widget
|
||||
{
|
||||
public:
|
||||
using Implementation = QTabWidget;
|
||||
};
|
||||
using I = BuilderItem<TabWidget>;
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT Tab : BuilderItem<Tab, TabInterface>
|
||||
{
|
||||
Tab(const QString &tabName, const LayoutItem &item);
|
||||
};
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT TabWidget : BuilderItem<TabWidget, TabWidgetInterface>
|
||||
{
|
||||
TabWidget(std::initializer_list<I> items);
|
||||
};
|
||||
|
||||
// ToolBar
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT ToolBarInterface : WidgetInterface
|
||||
class QTCREATOR_UTILS_EXPORT ToolBar : public Widget
|
||||
{
|
||||
public:
|
||||
using Implementation = QToolBar;
|
||||
};
|
||||
using I = Layouting::BuilderItem<ToolBar>;
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT ToolBar : BuilderItem<ToolBar, ToolBarInterface>
|
||||
{
|
||||
ToolBar(std::initializer_list<I> items);
|
||||
};
|
||||
|
||||
// Special
|
||||
|
||||
struct QTCREATOR_UTILS_EXPORT If : LayoutItem
|
||||
class QTCREATOR_UTILS_EXPORT If
|
||||
{
|
||||
If(bool condition, const LayoutItems &item, const LayoutItems &other = {});
|
||||
public:
|
||||
If(bool condition,
|
||||
const std::initializer_list<Layout::I> ifcase,
|
||||
const std::initializer_list<Layout::I> thencase = {});
|
||||
|
||||
const std::initializer_list<Layout::I> used;
|
||||
};
|
||||
|
||||
//
|
||||
@@ -413,24 +404,15 @@ struct QTCREATOR_UTILS_EXPORT If : LayoutItem
|
||||
// the base expectation is that they will forwards to the backend
|
||||
// type's setter.
|
||||
|
||||
// Special dispatchers :w
|
||||
// Special dispatchers
|
||||
|
||||
|
||||
struct BindToId {};
|
||||
class BindToId {};
|
||||
|
||||
template <typename T>
|
||||
auto bindTo(T **x)
|
||||
auto bindTo(T **p)
|
||||
{
|
||||
// FIXME: Evil hack to shut up clang-tidy which does not see that the returned tuple will
|
||||
// result in an assignment to *x and complains about every use of the bound value later.
|
||||
// main.cpp:129:5: Called C++ object pointer is null [clang-analyzer-core.CallAndMessage]
|
||||
// 1: Calling 'bindTo<QWidget>' in /data/dev/creator/tests/manual/layoutbuilder/v2/main.cpp:73
|
||||
// 2: Null pointer value stored to 'w' in /data/dev/creator/tests/manual/layoutbuilder/v2/lb.h:518
|
||||
// 3: Returning from 'bindTo<QWidget>' in /data/dev/creator/tests/manual/layoutbuilder/v2/main.cpp:73
|
||||
// 4: Called C++ object pointer is null in /data/dev/creator/tests/manual/layoutbuilder/v2/main.cpp:129
|
||||
*x = reinterpret_cast<T*>(1);
|
||||
|
||||
return IdAndArg{BindToId{}, x};
|
||||
return IdAndArg{BindToId{}, p};
|
||||
}
|
||||
|
||||
template <typename Interface>
|
||||
@@ -439,8 +421,8 @@ void doit(Interface *x, BindToId, auto p)
|
||||
*p = static_cast<Interface::Implementation *>(x->ptr);
|
||||
}
|
||||
|
||||
struct IdId {};
|
||||
auto id(auto x) { return IdAndArg{IdId{}, x}; }
|
||||
class IdId {};
|
||||
auto id(auto p) { return IdAndArg{IdId{}, p}; }
|
||||
|
||||
template <typename Interface>
|
||||
void doit(Interface *x, IdId, auto p)
|
||||
@@ -450,59 +432,119 @@ void doit(Interface *x, IdId, auto p)
|
||||
|
||||
// Setter dispatchers
|
||||
|
||||
struct SizeId {};
|
||||
class SizeId {};
|
||||
auto size(auto w, auto h) { return IdAndArg{SizeId{}, std::pair{w, h}}; }
|
||||
void doit(auto x, SizeId, auto p) { x->resize(p.first, p.second); }
|
||||
|
||||
struct TextId {};
|
||||
auto text(auto x) { return IdAndArg{TextId{}, x}; }
|
||||
void doit(auto x, TextId, auto t) { x->setText(t); }
|
||||
class TextId {};
|
||||
auto text(auto p) { return IdAndArg{TextId{}, p}; }
|
||||
void doit(auto x, TextId, auto p) { x->setText(p); }
|
||||
|
||||
struct TitleId {};
|
||||
auto title(auto x) { return IdAndArg{TitleId{}, x}; }
|
||||
void doit(auto x, TitleId, auto t) { x->setTitle(t); }
|
||||
class TitleId {};
|
||||
auto title(auto p) { return IdAndArg{TitleId{}, p}; }
|
||||
void doit(auto x, TitleId, auto p) { x->setTitle(p); }
|
||||
|
||||
struct ToolTipId {};
|
||||
auto toolTip(auto x) { return IdAndArg{ToolTipId{}, x}; }
|
||||
void doit(auto x, ToolTipId, auto t) { x->setToolTip(t); }
|
||||
class GroupCheckerId {};
|
||||
auto groupChecker(auto p) { return IdAndArg{GroupCheckerId{}, p}; }
|
||||
void doit(auto x, GroupCheckerId, auto p) { x->setGroupChecker(p); }
|
||||
|
||||
struct WindowTitleId {};
|
||||
auto windowTitle(auto x) { return IdAndArg{WindowTitleId{}, x}; }
|
||||
void doit(auto x, WindowTitleId, auto t) { x->setWindowTitle(t); }
|
||||
class ToolTipId {};
|
||||
auto toolTip(auto p) { return IdAndArg{ToolTipId{}, p}; }
|
||||
void doit(auto x, ToolTipId, auto p) { x->setToolTip(p); }
|
||||
|
||||
struct OnTextChangedId {};
|
||||
auto onTextChanged(auto x) { return IdAndArg{OnTextChangedId{}, x}; }
|
||||
void doit(auto x, OnTextChangedId, auto func) { x->onTextChanged(func); }
|
||||
class WindowTitleId {};
|
||||
auto windowTitle(auto p) { return IdAndArg{WindowTitleId{}, p}; }
|
||||
void doit(auto x, WindowTitleId, auto p) { x->setWindowTitle(p); }
|
||||
|
||||
struct OnClickedId {};
|
||||
auto onClicked(auto x) { return IdAndArg{OnClickedId{}, x}; }
|
||||
void doit(auto x, OnClickedId, auto func) { x->onClicked(func); }
|
||||
class OnTextChangedId {};
|
||||
auto onTextChanged(auto p) { return IdAndArg{OnTextChangedId{}, p}; }
|
||||
void doit(auto x, OnTextChangedId, auto p) { x->onTextChanged(p); }
|
||||
|
||||
class OnClickedId {};
|
||||
auto onClicked(auto p, auto guard) { return IdAndArg{OnClickedId{}, std::pair{p, guard}}; }
|
||||
void doit(auto x, OnClickedId, auto p) { x->onClicked(p.first, p.second); }
|
||||
|
||||
class CustomMarginId {};
|
||||
inline auto customMargin(const QMargins &p) { return IdAndArg{CustomMarginId{}, p}; }
|
||||
void doit(auto x, CustomMarginId, auto p) { x->customMargin(p); }
|
||||
|
||||
class FieldGrowthPolicyId {};
|
||||
inline auto fieldGrowthPolicy(auto p) { return IdAndArg{FieldGrowthPolicyId{}, p}; }
|
||||
void doit(auto x, FieldGrowthPolicyId, auto p) { x->fieldGrowthPolicy(p); }
|
||||
|
||||
class ColumnStretchId {};
|
||||
inline auto columnStretch(int column, int stretch) { return IdAndArg{ColumnStretchId{}, std::pair{column, stretch}}; }
|
||||
void doit(auto x, ColumnStretchId, auto p) { x->setColumnStretch(p.first, p.second); }
|
||||
|
||||
// Nesting dispatchers
|
||||
|
||||
QTCREATOR_UTILS_EXPORT void addNestedItem(WidgetInterface *widget, const LayoutInterface &layout);
|
||||
QTCREATOR_UTILS_EXPORT void addNestedItem(LayoutInterface *layout, const LayoutItem &inner);
|
||||
QTCREATOR_UTILS_EXPORT void addNestedItem(LayoutInterface *layout, const LayoutInterface &inner);
|
||||
QTCREATOR_UTILS_EXPORT void addNestedItem(LayoutInterface *layout, const WidgetInterface &inner);
|
||||
QTCREATOR_UTILS_EXPORT void addNestedItem(LayoutInterface *layout, const QString &inner);
|
||||
QTCREATOR_UTILS_EXPORT void addNestedItem(LayoutInterface *layout, const std::function<LayoutItem()> &inner);
|
||||
QTCREATOR_UTILS_EXPORT void addToLayout(Layout *layout, const Layout &inner);
|
||||
QTCREATOR_UTILS_EXPORT void addToLayout(Layout *layout, const Widget &inner);
|
||||
QTCREATOR_UTILS_EXPORT void addToLayout(Layout *layout, QWidget *inner);
|
||||
QTCREATOR_UTILS_EXPORT void addToLayout(Layout *layout, QLayout *inner);
|
||||
QTCREATOR_UTILS_EXPORT void addToLayout(Layout *layout, const LayoutModifier &inner);
|
||||
QTCREATOR_UTILS_EXPORT void addToLayout(Layout *layout, const QString &inner);
|
||||
QTCREATOR_UTILS_EXPORT void addToLayout(Layout *layout, const Space &inner);
|
||||
QTCREATOR_UTILS_EXPORT void addToLayout(Layout *layout, const Stretch &inner);
|
||||
QTCREATOR_UTILS_EXPORT void addToLayout(Layout *layout, const If &inner);
|
||||
QTCREATOR_UTILS_EXPORT void addToLayout(Layout *layout, const Span &inner);
|
||||
// ... can be added to anywhere later to support "user types"
|
||||
|
||||
void doit(auto outer, NestId, auto inner)
|
||||
QTCREATOR_UTILS_EXPORT void addToWidget(Widget *widget, const Layout &layout);
|
||||
|
||||
QTCREATOR_UTILS_EXPORT void addToTabWidget(TabWidget *tabWidget, const Tab &inner);
|
||||
|
||||
QTCREATOR_UTILS_EXPORT void addToSplitter(Splitter *splitter, QWidget *inner);
|
||||
QTCREATOR_UTILS_EXPORT void addToSplitter(Splitter *splitter, const Widget &inner);
|
||||
QTCREATOR_UTILS_EXPORT void addToSplitter(Splitter *splitter, const Layout &inner);
|
||||
|
||||
QTCREATOR_UTILS_EXPORT void addToStack(Stack *stack, QWidget *inner);
|
||||
QTCREATOR_UTILS_EXPORT void addToStack(Stack *stack, const Widget &inner);
|
||||
QTCREATOR_UTILS_EXPORT void addToStack(Stack *stack, const Layout &inner);
|
||||
|
||||
template <class Inner>
|
||||
void doit_nested(Layout *outer, Inner && inner)
|
||||
{
|
||||
addNestedItem(outer, inner);
|
||||
addToLayout(outer, std::forward<Inner>(inner));
|
||||
}
|
||||
|
||||
void doit_nested(Widget *outer, auto inner)
|
||||
{
|
||||
addToWidget(outer, inner);
|
||||
}
|
||||
|
||||
void doit_nested(TabWidget *outer, auto inner)
|
||||
{
|
||||
addToTabWidget(outer, inner);
|
||||
}
|
||||
|
||||
void doit_nested(Stack *outer, auto inner)
|
||||
{
|
||||
addToStack(outer, inner);
|
||||
}
|
||||
|
||||
void doit_nested(Splitter *outer, auto inner)
|
||||
{
|
||||
addToSplitter(outer, inner);
|
||||
}
|
||||
|
||||
template <class Inner>
|
||||
void doit(auto outer, NestId, Inner && inner)
|
||||
{
|
||||
doit_nested(outer, std::forward<Inner>(inner));
|
||||
}
|
||||
|
||||
// Special layout items
|
||||
|
||||
QTCREATOR_UTILS_EXPORT LayoutItem br();
|
||||
QTCREATOR_UTILS_EXPORT LayoutItem empty();
|
||||
QTCREATOR_UTILS_EXPORT LayoutItem hr();
|
||||
QTCREATOR_UTILS_EXPORT LayoutItem withFormAlignment();
|
||||
QTCREATOR_UTILS_EXPORT LayoutItem st();
|
||||
QTCREATOR_UTILS_EXPORT void empty(Layout *);
|
||||
QTCREATOR_UTILS_EXPORT void br(Layout *);
|
||||
QTCREATOR_UTILS_EXPORT void st(Layout *);
|
||||
QTCREATOR_UTILS_EXPORT void noMargin(Layout *);
|
||||
QTCREATOR_UTILS_EXPORT void normalMargin(Layout *);
|
||||
QTCREATOR_UTILS_EXPORT void withFormAlignment(Layout *);
|
||||
QTCREATOR_UTILS_EXPORT void hr(Layout *);
|
||||
|
||||
QTCREATOR_UTILS_EXPORT LayoutModifier spacing(int space);
|
||||
|
||||
// Convenience
|
||||
|
||||
|
@@ -68,7 +68,7 @@ int main(int argc, char *argv[])
|
||||
st,
|
||||
PushButton {
|
||||
text("Quit"),
|
||||
onClicked(QApplication::quit)
|
||||
onClicked(QApplication::quit, nullptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user