Qt: Remove empty rows/columns in controller settings

This commit is contained in:
Stenzek
2026-01-15 20:04:04 +10:00
parent 82947f0f65
commit 0c29d4e1db
3 changed files with 106 additions and 0 deletions

View File

@@ -96,6 +96,8 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
m_ui.pointerYScaleLabel->setText(QStringLiteral("%1").arg(m_ui.pointerYScale->value()));
updateSDLOptionsEnabled();
QtUtils::RemoveEmptyRowsAndColumns(m_ui.mainLayout);
}
ControllerGlobalSettingsWidget::~ControllerGlobalSettingsWidget() = default;

View File

@@ -20,6 +20,7 @@
#include <QtGui/QScreen>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QDialog>
#include <QtWidgets/QGridLayout>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QInputDialog>
#include <QtWidgets/QLabel>
@@ -137,6 +138,104 @@ void QtUtils::SetColumnWidthsForTreeView(QTreeView* view, const std::initializer
SetColumnWidthForView(view, view->header(), widths);
}
void QtUtils::RemoveEmptyRowsAndColumns(QGridLayout* const layout)
{
int column = 0;
while (column < layout->columnCount())
{
const int row_count = layout->rowCount();
const int column_count = layout->columnCount();
// Lambda to check if a column has any items with origin in that column
static constexpr auto column_has_items = [](QGridLayout* layout, int rowCount, int c) {
for (int row = 0; row < rowCount; ++row)
{
QLayoutItem* item = layout->itemAtPosition(row, c);
if (item)
{
const int idx = layout->indexOf(item);
int itemRow, itemCol, rowSpan, colSpan;
layout->getItemPosition(idx, &itemRow, &itemCol, &rowSpan, &colSpan);
if (itemCol == c)
return true;
}
}
return false;
};
if (!column_has_items(layout, row_count, column))
{
// Count consecutive empty columns starting from col
int empty_count = 1;
while ((column + empty_count) < column_count && !column_has_items(layout, row_count, column + empty_count))
++empty_count;
// Shift all items and stretches from columns after the gap
for (int c = column + empty_count; c < column_count; ++c)
{
const int dest_column = c - empty_count;
// Preserve column stretch
layout->setColumnStretch(dest_column, layout->columnStretch(c));
// Shift items
for (int row = 0; row < row_count; ++row)
{
QLayoutItem* const item = layout->itemAtPosition(row, c);
if (!item)
continue;
const int idx = layout->indexOf(item);
int item_row, item_column, row_span, column_span;
layout->getItemPosition(idx, &item_row, &item_column, &row_span, &column_span);
// Only process at item's origin
if (item_row != row || item_column != c)
continue;
layout->takeAt(idx);
layout->addItem(item, item_row, dest_column, row_span, column_span);
}
}
// Clear stretch on the now-empty trailing columns
for (int c = column_count - empty_count; c < column_count; ++c)
layout->setColumnStretch(c, 0);
// Don't increment col - check this position again (new content shifted in)
}
else
{
// Column has items - compact rows upward within this column
int target_row = 0;
for (int row = 0; row < row_count; ++row)
{
QLayoutItem* const item = layout->itemAtPosition(row, column);
if (!item)
continue;
const int idx = layout->indexOf(item);
int item_row, item_column, row_span, column_span;
layout->getItemPosition(idx, &item_row, &item_column, &row_span, &column_span);
// Only process items whose origin is at (row, col)
if (item_row != row || item_column != column)
continue;
if (row != target_row)
{
layout->takeAt(idx);
layout->addItem(item, target_row, column, row_span, column_span);
}
target_row += row_span;
}
++column;
}
}
}
void QtUtils::OpenURL(QWidget* parent, const QUrl& qurl)
{
if (!QDesktopServices::openUrl(qurl))

View File

@@ -22,6 +22,7 @@ class Error;
class QComboBox;
class QFrame;
class QGridLayout;
class QKeyEvent;
class QLabel;
class QMenu;
@@ -86,6 +87,10 @@ inline void SafeDeleteWidget(T*& widget)
void SetColumnWidthsForTableView(QTableView* view, const std::initializer_list<int>& widths);
void SetColumnWidthsForTreeView(QTreeView* view, const std::initializer_list<int>& widths);
/// Rearranges a grid layout to remove any empty rows or columns.
/// Note that due to the way QGridLayout works, the total row/column count will not be changed.
void RemoveEmptyRowsAndColumns(QGridLayout* const layout);
/// Returns a key id for a key event, including any modifiers that we need (e.g. Keypad).
std::optional<u32> KeyEventToCode(const QKeyEvent* ev);