2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2020 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2020-09-18 12:11:40 +02:00
|
|
|
|
|
|
|
|
#include "layoutbuilder.h"
|
|
|
|
|
|
2022-05-25 06:30:04 +02:00
|
|
|
#include "qtcassert.h"
|
2020-09-18 12:11:40 +02:00
|
|
|
|
|
|
|
|
#include <QFormLayout>
|
|
|
|
|
#include <QGridLayout>
|
2021-02-18 14:18:34 +01:00
|
|
|
#include <QGroupBox>
|
2023-04-24 16:40:01 +02:00
|
|
|
#include <QLabel>
|
2022-08-01 18:18:02 +02:00
|
|
|
#include <QPushButton>
|
2022-09-01 11:20:58 +02:00
|
|
|
#include <QStackedLayout>
|
2023-01-11 14:43:41 +01:00
|
|
|
#include <QSplitter>
|
2020-10-08 07:24:19 +02:00
|
|
|
#include <QStyle>
|
2022-11-18 10:44:10 +01:00
|
|
|
#include <QTabWidget>
|
2023-04-25 16:58:21 +02:00
|
|
|
#include <QTextEdit>
|
2020-09-18 12:11:40 +02:00
|
|
|
|
2023-04-25 10:15:07 +02:00
|
|
|
namespace Layouting {
|
2020-09-18 12:11:40 +02:00
|
|
|
|
2020-09-21 09:39:54 +02:00
|
|
|
/*!
|
|
|
|
|
\enum Utils::LayoutBuilder::LayoutType
|
|
|
|
|
\inmodule QtCreator
|
|
|
|
|
|
|
|
|
|
The LayoutType enum describes the type of \c QLayout a layout builder
|
|
|
|
|
operates on.
|
|
|
|
|
|
2021-02-18 14:18:34 +01:00
|
|
|
\value Form
|
|
|
|
|
\value Grid
|
|
|
|
|
\value HBox
|
|
|
|
|
\value VBox
|
2020-09-21 09:39:54 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\class Utils::LayoutBuilder::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.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Constructs a layout item instance representing an empty cell.
|
|
|
|
|
*/
|
2023-01-19 13:51:52 +01:00
|
|
|
LayoutItem::LayoutItem()
|
2020-09-21 09:39:54 +02:00
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
2023-04-24 16:40:01 +02:00
|
|
|
\fn template <class T> LayoutItem(const T &t)
|
2020-09-21 09:39:54 +02:00
|
|
|
|
2023-04-24 16:40:01 +02:00
|
|
|
Constructs a layout item proxy for \a t.
|
2020-09-21 09:39:54 +02:00
|
|
|
|
2023-04-24 16:40:01 +02:00
|
|
|
T could be
|
|
|
|
|
\list
|
|
|
|
|
\li \c {QString}
|
|
|
|
|
\li \c {QWidget *}
|
|
|
|
|
\li \c {QLayout *}
|
|
|
|
|
\endlist
|
2020-09-21 09:39:54 +02:00
|
|
|
*/
|
2021-02-18 14:18:34 +01:00
|
|
|
|
2020-09-21 09:39:54 +02:00
|
|
|
|
|
|
|
|
/*!
|
2023-04-24 16:40:01 +02:00
|
|
|
Constructs a layout item representing something that knows how to add it
|
|
|
|
|
to a layout by itself.
|
2020-09-21 09:39:54 +02:00
|
|
|
*/
|
2022-02-15 10:41:13 +01:00
|
|
|
QLayout *LayoutBuilder::createLayout() const
|
2021-03-11 19:02:42 +01:00
|
|
|
{
|
2022-02-15 10:41:13 +01:00
|
|
|
QLayout *layout = nullptr;
|
|
|
|
|
switch (m_layoutType) {
|
2021-03-11 19:02:42 +01:00
|
|
|
case LayoutBuilder::FormLayout: {
|
|
|
|
|
auto formLayout = new QFormLayout;
|
2021-12-01 17:18:03 +03:00
|
|
|
formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
|
2022-02-15 10:41:13 +01:00
|
|
|
layout = formLayout;
|
|
|
|
|
break;
|
2021-03-11 19:02:42 +01:00
|
|
|
}
|
|
|
|
|
case LayoutBuilder::GridLayout: {
|
|
|
|
|
auto gridLayout = new QGridLayout;
|
2022-02-15 10:41:13 +01:00
|
|
|
layout = gridLayout;
|
|
|
|
|
break;
|
2021-03-11 19:02:42 +01:00
|
|
|
}
|
|
|
|
|
case LayoutBuilder::HBoxLayout: {
|
|
|
|
|
auto hboxLayout = new QHBoxLayout;
|
2022-02-15 10:41:13 +01:00
|
|
|
layout = hboxLayout;
|
|
|
|
|
break;
|
2021-03-11 19:02:42 +01:00
|
|
|
}
|
|
|
|
|
case LayoutBuilder::VBoxLayout: {
|
|
|
|
|
auto vboxLayout = new QVBoxLayout;
|
2022-02-15 10:41:13 +01:00
|
|
|
layout = vboxLayout;
|
|
|
|
|
break;
|
2021-03-11 19:02:42 +01:00
|
|
|
}
|
2022-09-01 11:20:58 +02:00
|
|
|
case LayoutBuilder::StackLayout: {
|
|
|
|
|
auto stackLayout = new QStackedLayout;
|
|
|
|
|
layout = stackLayout;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-03-11 19:02:42 +01:00
|
|
|
}
|
2022-02-15 10:41:13 +01:00
|
|
|
QTC_ASSERT(layout, return nullptr);
|
|
|
|
|
if (m_spacing)
|
|
|
|
|
layout->setSpacing(*m_spacing);
|
|
|
|
|
return layout;
|
2021-03-11 19:02:42 +01:00
|
|
|
}
|
|
|
|
|
|
2022-07-14 18:16:31 +02:00
|
|
|
static QWidget *widgetForItem(QLayoutItem *item)
|
|
|
|
|
{
|
|
|
|
|
if (QWidget *w = item->widget())
|
|
|
|
|
return w;
|
|
|
|
|
if (item->spacerItem())
|
|
|
|
|
return nullptr;
|
|
|
|
|
QLayout *l = item->layout();
|
|
|
|
|
if (!l)
|
|
|
|
|
return nullptr;
|
|
|
|
|
for (int i = 0, n = l->count(); i < n; ++i) {
|
|
|
|
|
if (QWidget *w = widgetForItem(l->itemAt(i)))
|
|
|
|
|
return w;
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-19 12:49:50 +01:00
|
|
|
static QLabel *createLabel(const QString &text)
|
|
|
|
|
{
|
|
|
|
|
auto label = new QLabel(text);
|
|
|
|
|
label->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
|
|
|
|
return label;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-19 13:51:52 +01:00
|
|
|
static void addItemToBoxLayout(QBoxLayout *layout, const LayoutItem &item)
|
2022-07-15 09:24:41 +02:00
|
|
|
{
|
|
|
|
|
if (QWidget *w = item.widget) {
|
|
|
|
|
layout->addWidget(w);
|
|
|
|
|
} else if (QLayout *l = item.layout) {
|
|
|
|
|
layout->addLayout(l);
|
2023-01-19 13:51:52 +01:00
|
|
|
} else if (item.specialType == LayoutItem::SpecialType::Stretch) {
|
2022-07-15 09:24:41 +02:00
|
|
|
layout->addStretch(item.specialValue.toInt());
|
2023-01-19 13:51:52 +01:00
|
|
|
} else if (item.specialType == LayoutItem::SpecialType::Space) {
|
2022-07-15 09:24:41 +02:00
|
|
|
layout->addSpacing(item.specialValue.toInt());
|
2023-01-19 13:51:52 +01:00
|
|
|
} else if (item.specialType == LayoutItem::SpecialType::HorizontalRule) {
|
2022-08-29 17:38:41 +02:00
|
|
|
layout->addWidget(Layouting::createHr());
|
2022-07-15 09:24:41 +02:00
|
|
|
} else if (!item.text.isEmpty()) {
|
2023-01-19 12:49:50 +01:00
|
|
|
layout->addWidget(createLabel(item.text));
|
2022-07-15 09:24:41 +02:00
|
|
|
} else {
|
|
|
|
|
QTC_CHECK(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-11 19:02:42 +01:00
|
|
|
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;
|
2022-07-15 15:59:04 +02:00
|
|
|
hbox->setContentsMargins(0, 0, 0, 0);
|
2022-07-15 09:24:41 +02:00
|
|
|
for (int i = 1; i < pendingFormItems.size(); ++i)
|
|
|
|
|
addItemToBoxLayout(hbox, pendingFormItems.at(i));
|
2021-03-11 19:02:42 +01:00
|
|
|
while (pendingFormItems.size() >= 2)
|
|
|
|
|
pendingFormItems.pop_back();
|
2023-01-19 13:51:52 +01:00
|
|
|
pendingFormItems.append(LayoutItem(hbox));
|
2021-03-11 19:02:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-14 18:16:31 +02:00
|
|
|
// 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-11 19:02:42 +01:00
|
|
|
pendingFormItems.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void doLayoutHelper(QLayout *layout,
|
|
|
|
|
const LayoutBuilder::LayoutItems &items,
|
2022-07-28 11:01:05 +02:00
|
|
|
const Layouting::AttachType attachType,
|
2021-03-11 19:02:42 +01:00
|
|
|
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);
|
2022-09-01 11:20:58 +02:00
|
|
|
auto stackLayout = qobject_cast<QStackedLayout *>(layout);
|
2021-03-11 19:02:42 +01:00
|
|
|
|
2023-01-19 13:51:52 +01:00
|
|
|
for (const LayoutItem &item : items) {
|
|
|
|
|
if (item.specialType == LayoutItem::SpecialType::Break) {
|
2021-03-11 19:02:42 +01:00
|
|
|
if (formLayout)
|
|
|
|
|
flushPendingFormItems(formLayout, pendingFormItems);
|
|
|
|
|
else if (gridLayout) {
|
|
|
|
|
if (currentGridColumn != 0) {
|
|
|
|
|
++currentGridRow;
|
|
|
|
|
currentGridColumn = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QWidget *widget = item.widget;
|
|
|
|
|
|
|
|
|
|
if (gridLayout) {
|
2022-07-28 11:01:05 +02:00
|
|
|
Qt::Alignment align = {};
|
|
|
|
|
if (attachType == Layouting::WithFormAlignment && currentGridColumn == 0)
|
2021-03-11 19:02:42 +01:00
|
|
|
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);
|
2022-07-20 10:42:06 +02:00
|
|
|
else if (!item.text.isEmpty())
|
2023-01-19 12:49:50 +01:00
|
|
|
gridLayout->addWidget(createLabel(item.text), currentGridRow, currentGridColumn, 1, 1, align);
|
2021-03-11 19:02:42 +01:00
|
|
|
currentGridColumn += item.span;
|
|
|
|
|
} else if (boxLayout) {
|
2022-07-15 09:24:41 +02:00
|
|
|
addItemToBoxLayout(boxLayout, item);
|
2022-09-01 11:20:58 +02:00
|
|
|
} else if (stackLayout) {
|
|
|
|
|
stackLayout->addWidget(item.widget);
|
2021-03-11 19:02:42 +01:00
|
|
|
} else {
|
|
|
|
|
pendingFormItems.append(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (formLayout)
|
|
|
|
|
flushPendingFormItems(formLayout, pendingFormItems);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-02-18 14:18:34 +01:00
|
|
|
/*!
|
|
|
|
|
Constructs a layout item from the contents of another LayoutBuilder
|
|
|
|
|
*/
|
2023-04-24 16:40:01 +02:00
|
|
|
void LayoutItem::setBuilder(const LayoutBuilder &builder)
|
2021-03-11 19:02:42 +01:00
|
|
|
{
|
2022-02-15 10:41:13 +01:00
|
|
|
layout = builder.createLayout();
|
2022-07-28 11:01:05 +02:00
|
|
|
doLayoutHelper(layout, builder.m_items, Layouting::WithoutMargins);
|
2021-03-11 19:02:42 +01:00
|
|
|
}
|
2021-02-18 14:18:34 +01:00
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\class Utils::LayoutBuilder::Space
|
|
|
|
|
\inmodule QtCreator
|
|
|
|
|
|
|
|
|
|
\brief The LayoutBuilder::Space class represents some empty space in a layout.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\class Utils::LayoutBuilder::Stretch
|
|
|
|
|
\inmodule QtCreator
|
|
|
|
|
|
|
|
|
|
\brief The LayoutBuilder::Stretch class represents some stretch in a layout.
|
|
|
|
|
*/
|
2020-09-21 09:39:54 +02:00
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\class Utils::LayoutBuilder
|
|
|
|
|
\inmodule QtCreator
|
|
|
|
|
|
|
|
|
|
\brief The LayoutBuilder class provides a convenient way to fill \c QFormLayout
|
|
|
|
|
and \c QGridLayouts with contents.
|
|
|
|
|
|
|
|
|
|
Filling a layout with items happens item-by-item, row-by-row.
|
|
|
|
|
|
|
|
|
|
A LayoutBuilder instance is typically used locally within a function and never stored.
|
|
|
|
|
|
|
|
|
|
\sa addItem(), addItems(), addRow(), finishRow()
|
|
|
|
|
*/
|
|
|
|
|
|
2021-02-18 14:18:34 +01:00
|
|
|
LayoutBuilder::LayoutBuilder(LayoutType layoutType, const LayoutItems &items)
|
2021-03-11 19:02:42 +01:00
|
|
|
: m_layoutType(layoutType)
|
2021-02-18 14:18:34 +01:00
|
|
|
{
|
2021-03-11 19:02:42 +01:00
|
|
|
m_items.reserve(items.size() * 2);
|
|
|
|
|
for (const LayoutItem &item : items)
|
|
|
|
|
addItem(item);
|
2020-09-18 12:11:40 +02:00
|
|
|
}
|
|
|
|
|
|
2022-02-15 10:41:13 +01:00
|
|
|
LayoutBuilder &LayoutBuilder::setSpacing(int spacing)
|
|
|
|
|
{
|
|
|
|
|
m_spacing = spacing;
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-11 19:02:42 +01:00
|
|
|
LayoutBuilder::LayoutBuilder() = default;
|
2020-09-18 12:11:40 +02:00
|
|
|
|
2020-09-21 09:39:54 +02:00
|
|
|
/*!
|
|
|
|
|
Destructs a layout builder.
|
|
|
|
|
*/
|
2021-03-11 19:02:42 +01:00
|
|
|
LayoutBuilder::~LayoutBuilder() = default;
|
2020-09-18 12:11:40 +02:00
|
|
|
|
2020-09-21 09:39:54 +02:00
|
|
|
/*!
|
|
|
|
|
Instructs a layout builder to finish the current row.
|
|
|
|
|
This is implicitly called by LayoutBuilder's destructor.
|
|
|
|
|
*/
|
2020-09-18 04:54:41 +02:00
|
|
|
LayoutBuilder &LayoutBuilder::finishRow()
|
2020-09-18 12:11:40 +02:00
|
|
|
{
|
2021-03-11 19:02:42 +01:00
|
|
|
addItem(Break());
|
2020-09-18 12:11:40 +02:00
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-21 09:39:54 +02:00
|
|
|
/*!
|
|
|
|
|
This starts a new row containing \a items. The row can be further extended by
|
|
|
|
|
other items using \c addItem() or \c addItems().
|
|
|
|
|
|
|
|
|
|
\sa finishRow(), addItem(), addItems()
|
|
|
|
|
*/
|
2021-02-18 14:18:34 +01:00
|
|
|
LayoutBuilder &LayoutBuilder::addRow(const LayoutItems &items)
|
2020-09-18 04:54:41 +02:00
|
|
|
{
|
|
|
|
|
return finishRow().addItems(items);
|
2020-09-18 12:11:40 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-21 09:39:54 +02:00
|
|
|
/*!
|
2021-03-11 19:02:42 +01:00
|
|
|
Adds the layout item \a item to the current row.
|
2020-09-21 09:39:54 +02:00
|
|
|
*/
|
2021-03-11 19:02:42 +01:00
|
|
|
LayoutBuilder &LayoutBuilder::addItem(const LayoutItem &item)
|
2020-09-18 12:11:40 +02:00
|
|
|
{
|
2023-04-24 16:40:01 +02:00
|
|
|
if (item.onAdd) {
|
|
|
|
|
item.onAdd(*this);
|
2021-03-23 10:38:16 +01:00
|
|
|
} else {
|
2021-03-11 19:02:42 +01:00
|
|
|
m_items.push_back(item);
|
2021-03-23 10:38:16 +01:00
|
|
|
}
|
2021-03-11 19:02:42 +01:00
|
|
|
return *this;
|
|
|
|
|
}
|
2020-09-18 12:11:40 +02:00
|
|
|
|
2022-07-26 11:35:19 +02:00
|
|
|
void LayoutBuilder::doLayout(QWidget *parent, Layouting::AttachType attachType) const
|
2021-03-11 19:02:42 +01:00
|
|
|
{
|
2022-02-15 10:41:13 +01:00
|
|
|
QLayout *layout = createLayout();
|
2021-03-11 19:02:42 +01:00
|
|
|
parent->setLayout(layout);
|
2020-09-18 12:11:40 +02:00
|
|
|
|
2022-07-28 11:01:05 +02:00
|
|
|
doLayoutHelper(layout, m_items, attachType);
|
2022-07-26 11:35:19 +02:00
|
|
|
if (attachType == Layouting::WithoutMargins)
|
|
|
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
2020-09-18 12:11:40 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-21 09:39:54 +02:00
|
|
|
/*!
|
2021-03-11 19:02:42 +01:00
|
|
|
Adds the layout item \a items to the current row.
|
2020-09-21 09:39:54 +02:00
|
|
|
*/
|
2021-03-11 19:02:42 +01:00
|
|
|
LayoutBuilder &LayoutBuilder::addItems(const LayoutItems &items)
|
2021-02-18 14:18:34 +01:00
|
|
|
{
|
2021-03-11 19:02:42 +01:00
|
|
|
for (const LayoutItem &item : items)
|
|
|
|
|
addItem(item);
|
|
|
|
|
return *this;
|
2021-02-18 14:18:34 +01:00
|
|
|
}
|
|
|
|
|
|
2020-09-21 09:39:54 +02:00
|
|
|
/*!
|
2021-03-11 19:02:42 +01:00
|
|
|
Attach the constructed layout to the provided \c QWidget \a parent.
|
|
|
|
|
|
|
|
|
|
This operation can only be performed once per LayoutBuilder instance.
|
2020-09-21 09:39:54 +02:00
|
|
|
*/
|
2022-07-26 11:35:19 +02:00
|
|
|
void LayoutBuilder::attachTo(QWidget *w, Layouting::AttachType attachType) const
|
2020-09-18 12:11:40 +02:00
|
|
|
{
|
2022-07-26 11:35:19 +02:00
|
|
|
doLayout(w, attachType);
|
2021-03-11 19:02:42 +01:00
|
|
|
}
|
2020-09-18 12:11:40 +02:00
|
|
|
|
2022-07-26 11:35:19 +02:00
|
|
|
QWidget *LayoutBuilder::emerge(Layouting::AttachType attachType)
|
2021-03-11 19:02:42 +01:00
|
|
|
{
|
|
|
|
|
auto w = new QWidget;
|
2022-07-26 11:35:19 +02:00
|
|
|
doLayout(w, attachType);
|
2021-03-11 19:02:42 +01:00
|
|
|
return w;
|
2020-09-18 12:11:40 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-21 09:39:54 +02:00
|
|
|
/*!
|
2021-03-11 19:02:42 +01:00
|
|
|
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.
|
2020-09-21 09:39:54 +02:00
|
|
|
*/
|
2020-09-18 04:54:41 +02:00
|
|
|
|
2022-07-28 11:01:05 +02:00
|
|
|
LayoutExtender::LayoutExtender(QLayout *layout, Layouting::AttachType attachType)
|
|
|
|
|
: m_layout(layout), m_attachType(attachType)
|
2021-03-11 19:02:42 +01:00
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
LayoutExtender::~LayoutExtender()
|
2021-02-18 14:18:34 +01:00
|
|
|
{
|
2021-03-11 19:02:42 +01:00
|
|
|
QTC_ASSERT(m_layout, return);
|
|
|
|
|
int currentGridRow = 0;
|
|
|
|
|
if (auto gridLayout = qobject_cast<QGridLayout *>(m_layout))
|
|
|
|
|
currentGridRow = gridLayout->rowCount();
|
2022-07-28 11:01:05 +02:00
|
|
|
doLayoutHelper(m_layout, m_items, m_attachType, currentGridRow);
|
2021-02-18 14:18:34 +01:00
|
|
|
}
|
|
|
|
|
|
2021-03-11 19:02:42 +01:00
|
|
|
// Special items
|
|
|
|
|
|
2023-01-19 13:51:52 +01:00
|
|
|
Tab::Tab(const QString &tabName, const LayoutBuilder &item)
|
2022-11-18 10:44:10 +01:00
|
|
|
{
|
|
|
|
|
text = tabName;
|
|
|
|
|
widget = new QWidget;
|
|
|
|
|
item.attachTo(widget);
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-01 18:18:02 +02:00
|
|
|
// "Widgets"
|
|
|
|
|
|
2023-01-19 13:51:52 +01:00
|
|
|
static void applyItems(QWidget *widget, const QList<LayoutItem> &items)
|
2022-08-10 17:13:21 +02:00
|
|
|
{
|
|
|
|
|
bool hadLayout = false;
|
2023-01-19 13:51:52 +01:00
|
|
|
for (const LayoutItem &item : items) {
|
2022-08-10 17:13:21 +02:00
|
|
|
if (item.setter) {
|
|
|
|
|
item.setter(widget);
|
|
|
|
|
} else if (item.layout && !hadLayout) {
|
|
|
|
|
hadLayout = true;
|
|
|
|
|
widget->setLayout(item.layout);
|
|
|
|
|
} else {
|
|
|
|
|
QTC_CHECK(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-21 11:10:34 +02:00
|
|
|
|
2022-11-18 10:44:10 +01:00
|
|
|
Group::Group(std::initializer_list<LayoutItem> items)
|
2021-03-02 12:48:46 +01:00
|
|
|
{
|
2022-07-26 08:46:28 +02:00
|
|
|
widget = new QGroupBox;
|
2022-08-10 17:13:21 +02:00
|
|
|
applyItems(widget, items);
|
2021-03-02 12:48:46 +01:00
|
|
|
}
|
|
|
|
|
|
2022-11-18 10:44:10 +01:00
|
|
|
PushButton::PushButton(std::initializer_list<LayoutItem> items)
|
2022-08-01 18:18:02 +02:00
|
|
|
{
|
|
|
|
|
widget = new QPushButton;
|
2022-08-10 17:13:21 +02:00
|
|
|
applyItems(widget, items);
|
2022-08-01 18:18:02 +02:00
|
|
|
}
|
|
|
|
|
|
2023-04-25 16:58:21 +02:00
|
|
|
TextEdit::TextEdit(std::initializer_list<LayoutItem> items)
|
|
|
|
|
{
|
|
|
|
|
widget = new QTextEdit;
|
|
|
|
|
applyItems(widget, items);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-11 14:43:41 +01:00
|
|
|
Splitter::Splitter(std::initializer_list<LayoutItem> items)
|
|
|
|
|
: Splitter(new QSplitter(Qt::Vertical), items) {}
|
|
|
|
|
|
|
|
|
|
Splitter::Splitter(QSplitter *splitter, std::initializer_list<LayoutItem> items)
|
|
|
|
|
{
|
|
|
|
|
widget = splitter;
|
|
|
|
|
for (const LayoutItem &item : items)
|
|
|
|
|
splitter->addWidget(item.widget);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-18 10:44:10 +01:00
|
|
|
TabWidget::TabWidget(std::initializer_list<Tab> tabs)
|
|
|
|
|
: TabWidget(new QTabWidget, tabs) {}
|
|
|
|
|
|
|
|
|
|
TabWidget::TabWidget(QTabWidget *tabWidget, std::initializer_list<Tab> tabs)
|
|
|
|
|
{
|
|
|
|
|
widget = tabWidget;
|
|
|
|
|
for (const Tab &tab : tabs)
|
|
|
|
|
tabWidget->addTab(tab.widget, tab.text);
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-01 18:18:02 +02:00
|
|
|
// "Properties"
|
|
|
|
|
|
2023-04-25 10:51:14 +02:00
|
|
|
LayoutItem::Setter title(const QString &title)
|
2022-07-21 12:10:56 +02:00
|
|
|
{
|
2023-04-25 10:51:14 +02:00
|
|
|
return [title](QObject *target) {
|
2022-07-21 12:10:56 +02:00
|
|
|
if (auto groupBox = qobject_cast<QGroupBox *>(target)) {
|
|
|
|
|
groupBox->setTitle(title);
|
|
|
|
|
groupBox->setObjectName(title);
|
|
|
|
|
} else {
|
|
|
|
|
QTC_CHECK(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-19 13:51:52 +01:00
|
|
|
LayoutItem::Setter onClicked(const std::function<void ()> &func, QObject *guard)
|
2022-08-01 18:18:02 +02:00
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-19 13:51:52 +01:00
|
|
|
LayoutItem::Setter text(const QString &text)
|
2022-08-01 18:18:02 +02:00
|
|
|
{
|
|
|
|
|
return [text](QObject *target) {
|
|
|
|
|
if (auto button = qobject_cast<QAbstractButton *>(target)) {
|
|
|
|
|
button->setText(text);
|
2023-04-25 16:58:21 +02:00
|
|
|
} else if (auto textEdit = qobject_cast<QTextEdit *>(target)) {
|
|
|
|
|
textEdit->setText(text);
|
2022-08-01 18:18:02 +02:00
|
|
|
} else {
|
|
|
|
|
QTC_CHECK(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-19 13:51:52 +01:00
|
|
|
LayoutItem::Setter tooltip(const QString &toolTip)
|
2022-08-01 18:18:02 +02:00
|
|
|
{
|
|
|
|
|
return [toolTip](QObject *target) {
|
|
|
|
|
if (auto widget = qobject_cast<QWidget *>(target)) {
|
|
|
|
|
widget->setToolTip(toolTip);
|
|
|
|
|
} else {
|
|
|
|
|
QTC_CHECK(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-26 23:18:00 +02:00
|
|
|
QWidget *createHr(QWidget *parent)
|
|
|
|
|
{
|
|
|
|
|
auto frame = new QFrame(parent);
|
|
|
|
|
frame->setFrameShape(QFrame::HLine);
|
|
|
|
|
frame->setFrameShadow(QFrame::Sunken);
|
|
|
|
|
return frame;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-19 13:51:52 +01:00
|
|
|
// Singletons.
|
|
|
|
|
Break br;
|
|
|
|
|
Stretch st;
|
|
|
|
|
Space empty(0);
|
|
|
|
|
HorizontalRule hr;
|
2022-07-22 18:54:04 +02:00
|
|
|
|
2023-04-25 10:15:07 +02:00
|
|
|
} // Layouting
|