Make VDE tools flow

Took 1 hour 23 minutes

Took 5 seconds
This commit is contained in:
Lukas Brübach 2026-05-14 14:48:32 +02:00
parent b785574d2f
commit e174dc397f
4 changed files with 64 additions and 23 deletions

View file

@ -151,7 +151,7 @@ int FlowLayout::layoutAllRows(const int originX, const int originY, const int av
if (!rowItems.isEmpty() && rowUsedWidth + spaceX + itemSize.width() > availableWidth) { if (!rowItems.isEmpty() && rowUsedWidth + spaceX + itemSize.width() > availableWidth) {
// Current item does not fit — flush the current row, begin a new one. // Current item does not fit — flush the current row, begin a new one.
layoutSingleRow(rowItems, originX, currentY); layoutSingleRow(rowItems, originX, currentY, availableWidth);
rowItems.clear(); rowItems.clear();
currentY += rowHeight + verticalSpacing(); currentY += rowHeight + verticalSpacing();
rowUsedWidth = 0; rowUsedWidth = 0;
@ -166,33 +166,67 @@ int FlowLayout::layoutAllRows(const int originX, const int originY, const int av
rowHeight = qMax(rowHeight, itemSize.height()); rowHeight = qMax(rowHeight, itemSize.height());
} }
layoutSingleRow(rowItems, originX, currentY); // Flush the final row. layoutSingleRow(rowItems, originX, currentY, availableWidth); // Flush the final row.
return currentY + rowHeight; return currentY + rowHeight;
} }
/** /**
* @brief Sets the geometry for every item in @p rowItems, starting at (@p x, @p y). * @brief Sets the geometry for every item in @p rowItems, starting at (@p x, @p y).
* *
* Each item is placed at its sizeHint, clamped to its maximumSize. * Items whose horizontal size policy includes the Expand or MinimumExpanding flag
* share the leftover row width proportionally (like QHBoxLayout stretch), so that
* e.g. a QLineEdit can fill remaining space while fixed-size buttons stay compact.
*
* Items without an expanding policy are placed at their sizeHint, clamped to maximumSize.
*/ */
void FlowLayout::layoutSingleRow(const QVector<QLayoutItem *> &rowItems, int x, const int y) void FlowLayout::layoutSingleRow(const QVector<QLayoutItem *> &rowItems, int x, const int y, const int availableWidth)
{ {
if (rowItems.isEmpty())
return;
// ── Pass 1: measure fixed width and count expanding items ────────────────
int fixedWidth = 0;
int expandingCount = 0;
int spacingTotal = (rowItems.size() - 1) * horizontalSpacing();
for (QLayoutItem *item : rowItems) { for (QLayoutItem *item : rowItems) {
if (!item || item->isEmpty()) { if (!item || item->isEmpty()) {
continue; continue;
} }
QWidget *widget = item->widget(); QWidget *widget = item->widget();
if (!widget) { const QSizePolicy::Policy hPolicy = widget ? widget->sizePolicy().horizontalPolicy() : QSizePolicy::Fixed;
continue;
if (hPolicy & QSizePolicy::ExpandFlag) {
++expandingCount;
} else {
const int maxW = widget ? widget->maximumWidth() : QWIDGETSIZE_MAX;
fixedWidth += qMin(item->sizeHint().width(), maxW);
}
} }
// Extra pixels to share among expanding items (never negative).
const int extra = qMax(0, availableWidth - spacingTotal - fixedWidth);
const int expandingShare = (expandingCount > 0) ? extra / expandingCount : 0;
// ── Pass 2: place items ──────────────────────────────────────────────────
for (QLayoutItem *item : rowItems) {
if (!item || item->isEmpty())
continue;
QWidget *widget = item->widget();
if (!widget)
continue;
const QSizePolicy::Policy hPolicy = widget->sizePolicy().horizontalPolicy();
const QSize maxSize = widget->maximumSize(); const QSize maxSize = widget->maximumSize();
const int itemWidth = qMin(item->sizeHint().width(), maxSize.width()); const bool expands = hPolicy & QSizePolicy::ExpandFlag;
const int itemWidth =
expands ? qMin(expandingShare, maxSize.width()) : qMin(item->sizeHint().width(), maxSize.width());
const int itemHeight = qMin(item->sizeHint().height(), maxSize.height()); const int itemHeight = qMin(item->sizeHint().height(), maxSize.height());
item->setGeometry(QRect(QPoint(x, y), QSize(itemWidth, itemHeight))); item->setGeometry(QRect(QPoint(x, y), QSize(itemWidth, itemHeight)));
// Move the x-position to the right, leaving space for horizontal spacing
x += itemWidth + horizontalSpacing(); x += itemWidth + horizontalSpacing();
} }
} }

View file

@ -54,7 +54,7 @@ public:
// Layout passes (virtual so subclasses can override placement logic) // Layout passes (virtual so subclasses can override placement logic)
virtual int layoutAllRows(int originX, int originY, int availableWidth); virtual int layoutAllRows(int originX, int originY, int availableWidth);
virtual void layoutSingleRow(const QVector<QLayoutItem *> &rowItems, int x, int y); virtual void layoutSingleRow(const QVector<QLayoutItem *> &rowItems, int x, int y, int availableWidth);
int layoutAllColumns(int originX, int originY, int availableHeight); int layoutAllColumns(int originX, int originY, int availableHeight);
void layoutSingleColumn(const QVector<QLayoutItem *> &colItems, int x, int y); void layoutSingleColumn(const QVector<QLayoutItem *> &colItems, int x, int y);

View file

@ -69,7 +69,13 @@ VisualDeckEditorWidget::VisualDeckEditorWidget(QWidget *parent,
void VisualDeckEditorWidget::initializeSearchBarAndCompleter() void VisualDeckEditorWidget::initializeSearchBarAndCompleter()
{ {
searchBar = new QLineEdit(this); searchContainer = new QWidget(this);
searchContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
searchLayout = new QHBoxLayout(searchContainer);
searchContainer->setLayout(searchLayout);
searchBar = new QLineEdit(searchContainer);
searchContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
connect(searchBar, &QLineEdit::returnPressed, this, [=, this]() { connect(searchBar, &QLineEdit::returnPressed, this, [=, this]() {
if (!searchBar->hasFocus()) if (!searchBar->hasFocus())
return; return;
@ -80,6 +86,8 @@ void VisualDeckEditorWidget::initializeSearchBarAndCompleter()
} }
}); });
searchLayout->addWidget(searchBar);
setFocusProxy(searchBar); setFocusProxy(searchBar);
setFocusPolicy(Qt::ClickFocus); setFocusPolicy(Qt::ClickFocus);
@ -133,13 +141,15 @@ void VisualDeckEditorWidget::initializeSearchBarAndCompleter()
}); });
// Search button functionality // Search button functionality
searchPushButton = new QPushButton(this); searchPushButton = new QPushButton(searchContainer);
connect(searchPushButton, &QPushButton::clicked, this, [=, this]() { connect(searchPushButton, &QPushButton::clicked, this, [=, this]() {
ExactCard card = CardDatabaseManager::query()->getCard({searchBar->text()}); ExactCard card = CardDatabaseManager::query()->getCard({searchBar->text()});
if (card) { if (card) {
emit cardAdditionRequested(card); emit cardAdditionRequested(card);
} }
}); });
searchLayout->addWidget(searchPushButton);
} }
void VisualDeckEditorWidget::initializeDisplayOptionsWidget() void VisualDeckEditorWidget::initializeDisplayOptionsWidget()
@ -156,18 +166,14 @@ void VisualDeckEditorWidget::initializeDisplayOptionsWidget()
void VisualDeckEditorWidget::initializeDisplayOptionsAndSearchWidget() void VisualDeckEditorWidget::initializeDisplayOptionsAndSearchWidget()
{ {
initializeSearchBarAndCompleter(); initializeSearchBarAndCompleter();
initializeDisplayOptionsWidget(); initializeDisplayOptionsWidget();
displayOptionsAndSearch = new QWidget(this); displayOptionsAndSearch = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);
displayOptionsAndSearchLayout = new QHBoxLayout(displayOptionsAndSearch);
displayOptionsAndSearchLayout->setContentsMargins(0, 0, 0, 0);
displayOptionsAndSearchLayout->setAlignment(Qt::AlignLeft);
displayOptionsAndSearch->setLayout(displayOptionsAndSearchLayout);
displayOptionsAndSearchLayout->addWidget(displayOptionsWidget); // We split into two sub-widgets here so that the searchBar and button wrap together. At this point, we've done
displayOptionsAndSearchLayout->addWidget(searchBar); // pretty much all we can and have reached our minimum size.
displayOptionsAndSearchLayout->addWidget(searchPushButton); displayOptionsAndSearch->addWidget(displayOptionsWidget);
displayOptionsAndSearch->addWidget(searchContainer); // Expanding — fills remainder of its row
} }
void VisualDeckEditorWidget::initializeScrollAreaAndZoneContainer() void VisualDeckEditorWidget::initializeScrollAreaAndZoneContainer()

View file

@ -90,9 +90,10 @@ private:
CardDatabaseModel *cardDatabaseModel; CardDatabaseModel *cardDatabaseModel;
CardDatabaseDisplayModel *cardDatabaseDisplayModel; CardDatabaseDisplayModel *cardDatabaseDisplayModel;
CardCompleterProxyModel *proxyModel; CardCompleterProxyModel *proxyModel;
QWidget *searchContainer;
QHBoxLayout *searchLayout;
QCompleter *completer; QCompleter *completer;
QWidget *displayOptionsAndSearch; FlowWidget *displayOptionsAndSearch;
QHBoxLayout *displayOptionsAndSearchLayout;
VisualDeckDisplayOptionsWidget *displayOptionsWidget; VisualDeckDisplayOptionsWidget *displayOptionsWidget;
QPushButton *searchPushButton; QPushButton *searchPushButton;
QScrollArea *scrollArea; QScrollArea *scrollArea;