Utils: Add "layouting" widgets to layoutbuilder

This allows us to handle widgets that have an "addWidget" function.

Change-Id: Id1b63bae7032403fdd3c5e6ba60283cf56cc1cfe
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Marcus Tillmanns
2023-10-12 10:39:25 +02:00
parent db8d82e51e
commit 413fda678f
2 changed files with 39 additions and 44 deletions

View File

@@ -238,7 +238,7 @@ struct Slice
{ {
Slice() = default; Slice() = default;
Slice(QLayout *l) : layout(l) {} Slice(QLayout *l) : layout(l) {}
Slice(QWidget *w) : widget(w) {} Slice(QWidget *w, bool isLayouting=false) : widget(w), isLayouting(isLayouting) {}
QLayout *layout = nullptr; QLayout *layout = nullptr;
QWidget *widget = nullptr; QWidget *widget = nullptr;
@@ -249,6 +249,7 @@ struct Slice
int currentGridColumn = 0; int currentGridColumn = 0;
int currentGridRow = 0; int currentGridRow = 0;
bool isFormAlignment = false; bool isFormAlignment = false;
bool isLayouting = false;
Qt::Alignment align = {}; // Can be changed to Qt::Alignment align = {}; // Can be changed to
// Grid or Form // Grid or Form
@@ -397,18 +398,6 @@ void Slice::flush()
for (const ResultItem &item : std::as_const(pendingItems)) for (const ResultItem &item : std::as_const(pendingItems))
addItemToFlowLayout(flowLayout, item); addItemToFlowLayout(flowLayout, item);
} else if (auto stackWidget = qobject_cast<QStackedWidget *>(widget)) {
for (const ResultItem &item : std::as_const(pendingItems)) {
if (item.widget)
stackWidget->addWidget(item.widget);
else if (item.layout) {
auto w = new QWidget();
w->setLayout(item.layout);
stackWidget->addWidget(w);
} else {
QTC_CHECK(false);
}
}
} else { } else {
QTC_CHECK(false); QTC_CHECK(false);
} }
@@ -606,10 +595,30 @@ static void layoutExit(LayoutBuilder &builder)
QLayout *layout = builder.stack.last().layout; QLayout *layout = builder.stack.last().layout;
builder.stack.pop_back(); builder.stack.pop_back();
if (QWidget *widget = builder.stack.last().widget) if (builder.stack.last().isLayouting) {
widget->setLayout(layout);
else
builder.stack.last().pendingItems.append(ResultItem(layout)); builder.stack.last().pendingItems.append(ResultItem(layout));
} else if (QWidget *widget = builder.stack.last().widget) {
widget->setLayout(layout);
} else
builder.stack.last().pendingItems.append(ResultItem(layout));
}
template<class T>
static void layoutingWidgetExit(LayoutBuilder &builder)
{
const Slice slice = builder.stack.last();
T *w = qobject_cast<T *>(slice.widget);
for (const ResultItem &ri : slice.pendingItems) {
if (ri.widget) {
w->addWidget(ri.widget);
} else if (ri.layout) {
auto child = new QWidget;
child->setLayout(ri.layout);
w->addWidget(child);
}
}
builder.stack.pop_back();
builder.stack.last().pendingItems.append(ResultItem(w));
} }
static void widgetExit(LayoutBuilder &builder) static void widgetExit(LayoutBuilder &builder)
@@ -758,13 +767,10 @@ Stack::Stack(std::initializer_list<LayoutItem> items)
// "setVisible()" when a child is added, which can lead to the widget being spawned as a // "setVisible()" when a child is added, which can lead to the widget being spawned as a
// top-level widget. This can lead to the focus shifting away from the main application. // top-level widget. This can lead to the focus shifting away from the main application.
subItems = items; subItems = items;
onAdd = [](LayoutBuilder &builder) { builder.stack.append(new QStackedWidget); }; onAdd = [](LayoutBuilder &builder) {
onExit = [](LayoutBuilder &builder) { builder.stack.append(Slice(new QStackedWidget, true));
QWidget *widget = builder.stack.last().widget;
builder.stack.last().flush();
builder.stack.pop_back();
builder.stack.last().pendingItems.append(ResultItem(widget));
}; };
onExit = layoutingWidgetExit<QStackedWidget>;
} }
PushButton::PushButton(std::initializer_list<LayoutItem> items) PushButton::PushButton(std::initializer_list<LayoutItem> items)
@@ -791,18 +797,9 @@ Splitter::Splitter(std::initializer_list<LayoutItem> items)
onAdd = [](LayoutBuilder &builder) { onAdd = [](LayoutBuilder &builder) {
auto splitter = new QSplitter; auto splitter = new QSplitter;
splitter->setOrientation(Qt::Vertical); splitter->setOrientation(Qt::Vertical);
builder.stack.append(splitter); builder.stack.append(Slice(splitter, true));
};
onExit = [](LayoutBuilder &builder) {
const Slice slice = builder.stack.last();
QSplitter *splitter = qobject_cast<QSplitter *>(slice.widget);
for (const ResultItem &ri : slice.pendingItems) {
if (ri.widget)
splitter->addWidget(ri.widget);
}
builder.stack.pop_back();
builder.stack.last().pendingItems.append(ResultItem(splitter));
}; };
onExit = layoutingWidgetExit<QSplitter>;
} }
ToolBar::ToolBar(std::initializer_list<LayoutItem> items) ToolBar::ToolBar(std::initializer_list<LayoutItem> items)
@@ -811,18 +808,9 @@ ToolBar::ToolBar(std::initializer_list<LayoutItem> items)
onAdd = [](LayoutBuilder &builder) { onAdd = [](LayoutBuilder &builder) {
auto toolbar = new QToolBar; auto toolbar = new QToolBar;
toolbar->setOrientation(Qt::Horizontal); toolbar->setOrientation(Qt::Horizontal);
builder.stack.append(toolbar); builder.stack.append(Slice(toolbar, true));
};
onExit = [](LayoutBuilder &builder) {
const Slice slice = builder.stack.last();
QToolBar *toolBar = qobject_cast<QToolBar *>(slice.widget);
for (const ResultItem &ri : slice.pendingItems) {
if (ri.widget)
toolBar->addWidget(ri.widget);
}
builder.stack.pop_back();
builder.stack.last().pendingItems.append(ResultItem(toolBar));
}; };
onExit = layoutingWidgetExit<QToolBar>;
} }
TabWidget::TabWidget(std::initializer_list<LayoutItem> items) TabWidget::TabWidget(std::initializer_list<LayoutItem> items)

View File

@@ -49,5 +49,12 @@ int main(int argc, char *argv[])
} }
}.emerge()->show(); }.emerge()->show();
Splitter {
windowTitle("Splitter with sub layouts"),
Column {"First Widget"},
Row {"Second Widget"},
}.emerge()->show();
return app.exec(); return app.exec();
} }