[desktop] Add icon-only mode to grid and improve design (#3485)

- Move Game Icon Size to the main toolbar. It's cleaner that way
- Add a "Show Game Name" toggle that does as it says. Disabling it
  basically creates an "icons-only" mode. Useful for controller-only
  nav with big icons (TODO: maybe make a 192 size?)
- Fixed a crash with controller nav. Oops
- Rounded corners of the game icon in grid mode
- Fixed the scroll bar creating extra clamping range on the grid icons
- Item can be deselected if user clicks on the blank space outside of the view

As a bonus fixed a crash on mod manager

Future TODOs for design:
- [ ] Row 1 type. Not sure what to do here tbh.
- [ ] Move around game list settings in configure_ui to make it clear
  that nothing there affects the grid view.
- [ ] 192x192 size? 256 feels too big on my 1440p screen whereas 128
  feels too small.
- Set text space as a function of fontMetrics.

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3485
Reviewed-by: DraVee <dravee@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
This commit is contained in:
crueter 2026-02-07 22:48:39 +01:00
parent e10f55d9db
commit ca9f2d43be
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
13 changed files with 273 additions and 130 deletions

View file

@ -73,6 +73,7 @@
#include <QStatusBar>
#include <QtConcurrentRun>
#include <QMimeData>
#include <QActionGroup>
// Qt Common //
#include "qt_common/config/uisettings.h"
@ -377,6 +378,22 @@ static QString PrettyProductName() {
return QSysInfo::prettyProductName();
}
namespace {
constexpr std::array<std::pair<u32, const char *>, 5> default_game_icon_sizes{
std::make_pair(0, QT_TRANSLATE_NOOP("MainWindow", "None")),
std::make_pair(32, QT_TRANSLATE_NOOP("MainWindow", "Small (32x32)")),
std::make_pair(64, QT_TRANSLATE_NOOP("MainWindow", "Standard (64x64)")),
std::make_pair(128, QT_TRANSLATE_NOOP("MainWindow", "Large (128x128)")),
std::make_pair(256, QT_TRANSLATE_NOOP("MainWindow", "Full Size (256x256)")),
};
QString GetTranslatedGameIconSize(size_t index) {
return QCoreApplication::translate("MainWindow", default_game_icon_sizes[index].second);
}
}
#ifndef _WIN32
// TODO(crueter): carboxyl does this, is it needed in qml?
inline static bool isDarkMode() {
@ -1607,6 +1624,33 @@ void MainWindow::ConnectMenuEvents() {
connect_menu(ui->action_Grid_View, &MainWindow::SetGridView);
connect_menu(ui->action_Tree_View, &MainWindow::SetTreeView);
game_size_actions = new QActionGroup(this);
game_size_actions->setExclusive(true);
for (size_t i = 0; i < default_game_icon_sizes.size(); i++) {
const auto current_size = UISettings::values.game_icon_size.GetValue();
const auto size = default_game_icon_sizes[i].first;
QAction *action = ui->menuGame_Icon_Size->addAction(GetTranslatedGameIconSize(i));
action->setCheckable(true);
if (current_size == size) action->setChecked(true);
game_size_actions->addAction(action);
connect(action, &QAction::triggered, this, [this, size](bool checked) {
if (checked) {
UISettings::values.game_icon_size.SetValue(size);
CheckIconSize();
game_list->RefreshGameDirectory();
}
});
}
CheckIconSize();
ui->action_Show_Game_Name->setChecked(UISettings::values.show_game_name.GetValue());
connect(ui->action_Show_Game_Name, &QAction::triggered, this, &MainWindow::ToggleShowGameName);
// Multiplayer
connect(ui->action_View_Lobby, &QAction::triggered, multiplayer_state,
&MultiplayerState::OnViewLobby);
@ -3385,6 +3429,9 @@ void MainWindow::SetGameListMode(Settings::GameListMode mode) {
ui->action_Tree_View->setChecked(mode == Settings::GameListMode::TreeView);
UISettings::values.game_list_mode = mode;
ui->action_Show_Game_Name->setEnabled(mode == Settings::GameListMode::GridView);
CheckIconSize();
game_list->ResetViewMode();
}
@ -3396,6 +3443,43 @@ void MainWindow::SetTreeView() {
SetGameListMode(Settings::GameListMode::TreeView);
}
void MainWindow::CheckIconSize() {
// When in grid view mode, with text off
// there is no point in having icons turned off..
auto actions = game_size_actions->actions();
if (UISettings::values.game_list_mode.GetValue() == Settings::GameListMode::GridView &&
!UISettings::values.show_game_name.GetValue()) {
u32 newSize = UISettings::values.game_icon_size.GetValue();
if (newSize == 0) {
newSize = 64;
UISettings::values.game_icon_size.SetValue(newSize);
}
// Then disable the "none" action and update that menu.
for (size_t i = 0; i < default_game_icon_sizes.size(); i++) {
const auto current_size = newSize;
const auto size = default_game_icon_sizes[i].first;
if (current_size == size) actions.at(i)->setChecked(true);
}
// Update this if you add anything before None.
actions.at(0)->setEnabled(false);
} else {
actions.at(0)->setEnabled(true);
}
}
void MainWindow::ToggleShowGameName() {
auto &setting = UISettings::values.show_game_name;
const bool newValue = !setting.GetValue();
ui->action_Show_Game_Name->setChecked(newValue);
setting.SetValue(newValue);
CheckIconSize();
game_list->RefreshGameDirectory();
}
void MainWindow::OnConfigure() {
const auto old_theme = UISettings::values.theme;
const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue();
@ -3916,7 +4000,6 @@ void MainWindow::OnDataDialog() {
// refresh stuff in case it was cleared
OnGameListRefresh();
}
void MainWindow::OnToggleFilterBar() {
@ -3939,7 +4022,6 @@ void MainWindow::OnGameListRefresh() {
SetFirmwareVersion();
}
void MainWindow::LaunchFirmwareApplet(u64 raw_program_id, std::optional<Service::NFP::CabinetMode> cabinet_mode) {
auto const program_id = Service::AM::AppletProgramId(raw_program_id);
auto result = FirmwareManager::VerifyFirmware(*QtCommon::system.get());
@ -4658,6 +4740,11 @@ void MainWindow::OnLanguageChanged(const QString& locale) {
qApp->removeTranslator(&translator);
}
QList<QAction *> actions = game_size_actions->actions();
for (size_t i = 0; i < default_game_icon_sizes.size(); i++) {
actions.at(i)->setText(GetTranslatedGameIconSize(i));
}
UISettings::values.language = locale.toStdString();
LoadTranslation();
ui->retranslateUi(this);