Skip to content

Commit 0c29d4e

Browse files
committed
Qt: Remove empty rows/columns in controller settings
1 parent 82947f0 commit 0c29d4e

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed

src/duckstation-qt/controllerglobalsettingswidget.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
9696
m_ui.pointerYScaleLabel->setText(QStringLiteral("%1").arg(m_ui.pointerYScale->value()));
9797

9898
updateSDLOptionsEnabled();
99+
100+
QtUtils::RemoveEmptyRowsAndColumns(m_ui.mainLayout);
99101
}
100102

101103
ControllerGlobalSettingsWidget::~ControllerGlobalSettingsWidget() = default;

src/duckstation-qt/qtutils.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <QtGui/QScreen>
2121
#include <QtWidgets/QComboBox>
2222
#include <QtWidgets/QDialog>
23+
#include <QtWidgets/QGridLayout>
2324
#include <QtWidgets/QHeaderView>
2425
#include <QtWidgets/QInputDialog>
2526
#include <QtWidgets/QLabel>
@@ -137,6 +138,104 @@ void QtUtils::SetColumnWidthsForTreeView(QTreeView* view, const std::initializer
137138
SetColumnWidthForView(view, view->header(), widths);
138139
}
139140

141+
void QtUtils::RemoveEmptyRowsAndColumns(QGridLayout* const layout)
142+
{
143+
int column = 0;
144+
while (column < layout->columnCount())
145+
{
146+
const int row_count = layout->rowCount();
147+
const int column_count = layout->columnCount();
148+
149+
// Lambda to check if a column has any items with origin in that column
150+
static constexpr auto column_has_items = [](QGridLayout* layout, int rowCount, int c) {
151+
for (int row = 0; row < rowCount; ++row)
152+
{
153+
QLayoutItem* item = layout->itemAtPosition(row, c);
154+
if (item)
155+
{
156+
const int idx = layout->indexOf(item);
157+
int itemRow, itemCol, rowSpan, colSpan;
158+
layout->getItemPosition(idx, &itemRow, &itemCol, &rowSpan, &colSpan);
159+
if (itemCol == c)
160+
return true;
161+
}
162+
}
163+
return false;
164+
};
165+
166+
if (!column_has_items(layout, row_count, column))
167+
{
168+
// Count consecutive empty columns starting from col
169+
int empty_count = 1;
170+
while ((column + empty_count) < column_count && !column_has_items(layout, row_count, column + empty_count))
171+
++empty_count;
172+
173+
// Shift all items and stretches from columns after the gap
174+
for (int c = column + empty_count; c < column_count; ++c)
175+
{
176+
const int dest_column = c - empty_count;
177+
178+
// Preserve column stretch
179+
layout->setColumnStretch(dest_column, layout->columnStretch(c));
180+
181+
// Shift items
182+
for (int row = 0; row < row_count; ++row)
183+
{
184+
QLayoutItem* const item = layout->itemAtPosition(row, c);
185+
if (!item)
186+
continue;
187+
188+
const int idx = layout->indexOf(item);
189+
int item_row, item_column, row_span, column_span;
190+
layout->getItemPosition(idx, &item_row, &item_column, &row_span, &column_span);
191+
192+
// Only process at item's origin
193+
if (item_row != row || item_column != c)
194+
continue;
195+
196+
layout->takeAt(idx);
197+
layout->addItem(item, item_row, dest_column, row_span, column_span);
198+
}
199+
}
200+
201+
// Clear stretch on the now-empty trailing columns
202+
for (int c = column_count - empty_count; c < column_count; ++c)
203+
layout->setColumnStretch(c, 0);
204+
205+
// Don't increment col - check this position again (new content shifted in)
206+
}
207+
else
208+
{
209+
// Column has items - compact rows upward within this column
210+
int target_row = 0;
211+
for (int row = 0; row < row_count; ++row)
212+
{
213+
QLayoutItem* const item = layout->itemAtPosition(row, column);
214+
if (!item)
215+
continue;
216+
217+
const int idx = layout->indexOf(item);
218+
int item_row, item_column, row_span, column_span;
219+
layout->getItemPosition(idx, &item_row, &item_column, &row_span, &column_span);
220+
221+
// Only process items whose origin is at (row, col)
222+
if (item_row != row || item_column != column)
223+
continue;
224+
225+
if (row != target_row)
226+
{
227+
layout->takeAt(idx);
228+
layout->addItem(item, target_row, column, row_span, column_span);
229+
}
230+
231+
target_row += row_span;
232+
}
233+
234+
++column;
235+
}
236+
}
237+
}
238+
140239
void QtUtils::OpenURL(QWidget* parent, const QUrl& qurl)
141240
{
142241
if (!QDesktopServices::openUrl(qurl))

src/duckstation-qt/qtutils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class Error;
2222

2323
class QComboBox;
2424
class QFrame;
25+
class QGridLayout;
2526
class QKeyEvent;
2627
class QLabel;
2728
class QMenu;
@@ -86,6 +87,10 @@ inline void SafeDeleteWidget(T*& widget)
8687
void SetColumnWidthsForTableView(QTableView* view, const std::initializer_list<int>& widths);
8788
void SetColumnWidthsForTreeView(QTreeView* view, const std::initializer_list<int>& widths);
8889

90+
/// Rearranges a grid layout to remove any empty rows or columns.
91+
/// Note that due to the way QGridLayout works, the total row/column count will not be changed.
92+
void RemoveEmptyRowsAndColumns(QGridLayout* const layout);
93+
8994
/// Returns a key id for a key event, including any modifiers that we need (e.g. Keypad).
9095
std::optional<u32> KeyEventToCode(const QKeyEvent* ev);
9196

0 commit comments

Comments
 (0)