citra-emu
/
citra-canary
Archived
1
0
Fork 0

Merge pull request #4259 from zhaowenlan1779/game-list

citra_qt: Add Game List configuration
This commit is contained in:
Pengfei Zhu 2018-10-18 21:29:33 +08:00 committed by GitHub
commit 9458ae0977
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 427 additions and 121 deletions

View File

@ -43,6 +43,8 @@ add_executable(citra-qt
configuration/configure_motion_touch.h configuration/configure_motion_touch.h
configuration/configure_system.cpp configuration/configure_system.cpp
configuration/configure_system.h configuration/configure_system.h
configuration/configure_ui.cpp
configuration/configure_ui.h
configuration/configure_web.cpp configuration/configure_web.cpp
configuration/configure_web.h configuration/configure_web.h
debugger/console.h debugger/console.h
@ -119,6 +121,7 @@ set(UIS
configuration/configure_input.ui configuration/configure_input.ui
configuration/configure_motion_touch.ui configuration/configure_motion_touch.ui
configuration/configure_system.ui configuration/configure_system.ui
configuration/configure_ui.ui
configuration/configure_web.ui configuration/configure_web.ui
debugger/registers.ui debugger/registers.ui
multiplayer/direct_connect.ui multiplayer/direct_connect.ui

View File

@ -219,6 +219,28 @@ void Config::ReadValues() {
ReadSetting("microProfileDialogVisible", false).toBool(); ReadSetting("microProfileDialogVisible", false).toBool();
qt_config->endGroup(); qt_config->endGroup();
qt_config->beginGroup("GameList");
int icon_size = ReadSetting("iconSize", 2).toInt();
if (icon_size < 0 || icon_size > 2) {
icon_size = 2;
}
UISettings::values.game_list_icon_size = UISettings::GameListIconSize{icon_size};
int row_1 = ReadSetting("row1", 2).toInt();
if (row_1 < 0 || row_1 > 3) {
row_1 = 2;
}
UISettings::values.game_list_row_1 = UISettings::GameListText{row_1};
int row_2 = ReadSetting("row2", 0).toInt();
if (row_2 < -1 || row_2 > 3) {
row_2 = 0;
}
UISettings::values.game_list_row_2 = UISettings::GameListText{row_2};
UISettings::values.game_list_hide_no_icon = ReadSetting("hideNoIcon", false).toBool();
qt_config->endGroup();
qt_config->beginGroup("Paths"); qt_config->beginGroup("Paths");
UISettings::values.roms_path = ReadSetting("romsPath").toString(); UISettings::values.roms_path = ReadSetting("romsPath").toString();
UISettings::values.symbols_path = ReadSetting("symbolsPath").toString(); UISettings::values.symbols_path = ReadSetting("symbolsPath").toString();
@ -448,6 +470,13 @@ void Config::SaveValues() {
WriteSetting("microProfileDialogVisible", UISettings::values.microprofile_visible, false); WriteSetting("microProfileDialogVisible", UISettings::values.microprofile_visible, false);
qt_config->endGroup(); qt_config->endGroup();
qt_config->beginGroup("GameList");
WriteSetting("iconSize", static_cast<int>(UISettings::values.game_list_icon_size), 2);
WriteSetting("row1", static_cast<int>(UISettings::values.game_list_row_1), 2);
WriteSetting("row2", static_cast<int>(UISettings::values.game_list_row_2), 0);
WriteSetting("hideNoIcon", UISettings::values.game_list_hide_no_icon, false);
qt_config->endGroup();
qt_config->beginGroup("Paths"); qt_config->beginGroup("Paths");
WriteSetting("romsPath", UISettings::values.roms_path); WriteSetting("romsPath", UISettings::values.roms_path);
WriteSetting("symbolsPath", UISettings::values.symbols_path); WriteSetting("symbolsPath", UISettings::values.symbols_path);

View File

@ -63,6 +63,11 @@
<string>Web</string> <string>Web</string>
</attribute> </attribute>
</widget> </widget>
<widget class="ConfigureUi" name="uiTab">
<attribute name="title">
<string>UI</string>
</attribute>
</widget>
</widget> </widget>
</item> </item>
</layout> </layout>
@ -125,6 +130,12 @@
<header>configuration/configure_web.h</header> <header>configuration/configure_web.h</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget>
<class>ConfigureUi</class>
<extends>QWidget</extends>
<header>configuration/configure_ui.h</header>
<container>1</container>
</customwidget>
</customwidgets> </customwidgets>
<resources/> <resources/>
<connections> <connections>

View File

@ -16,8 +16,7 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry
ui->generalTab->PopulateHotkeyList(registry); ui->generalTab->PopulateHotkeyList(registry);
this->setConfiguration(); this->setConfiguration();
this->PopulateSelectionList(); this->PopulateSelectionList();
connect(ui->generalTab, &ConfigureGeneral::languageChanged, this, connect(ui->uiTab, &ConfigureUi::languageChanged, this, &ConfigureDialog::onLanguageChanged);
&ConfigureDialog::onLanguageChanged);
connect(ui->selectorList, &QListWidget::itemSelectionChanged, this, connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
&ConfigureDialog::UpdateVisibleTabs); &ConfigureDialog::UpdateVisibleTabs);
@ -39,6 +38,7 @@ void ConfigureDialog::applyConfiguration() {
ui->cameraTab->applyConfiguration(); ui->cameraTab->applyConfiguration();
ui->debugTab->applyConfiguration(); ui->debugTab->applyConfiguration();
ui->webTab->applyConfiguration(); ui->webTab->applyConfiguration();
ui->uiTab->applyConfiguration();
Settings::Apply(); Settings::Apply();
Settings::LogSettings(); Settings::LogSettings();
} }
@ -46,7 +46,7 @@ void ConfigureDialog::applyConfiguration() {
void ConfigureDialog::PopulateSelectionList() { void ConfigureDialog::PopulateSelectionList() {
const std::array<std::pair<QString, QStringList>, 4> items{ const std::array<std::pair<QString, QStringList>, 4> items{
{{tr("General"), {tr("General"), tr("Web"), tr("Debug")}}, {{tr("General"), {tr("General"), tr("Web"), tr("Debug"), tr("UI")}},
{tr("System"), {tr("System"), tr("Audio"), tr("Camera")}}, {tr("System"), {tr("System"), tr("Audio"), tr("Camera")}},
{tr("Graphics"), {tr("Graphics")}}, {tr("Graphics"), {tr("Graphics")}},
{tr("Controls"), {tr("Input")}}}}; {tr("Controls"), {tr("Input")}}}};
@ -70,6 +70,7 @@ void ConfigureDialog::onLanguageChanged(const QString& locale) {
ui->cameraTab->retranslateUi(); ui->cameraTab->retranslateUi();
ui->debugTab->retranslateUi(); ui->debugTab->retranslateUi();
ui->webTab->retranslateUi(); ui->webTab->retranslateUi();
ui->uiTab->retranslateUi();
} }
void ConfigureDialog::UpdateVisibleTabs() { void ConfigureDialog::UpdateVisibleTabs() {
@ -77,11 +78,15 @@ void ConfigureDialog::UpdateVisibleTabs() {
if (items.isEmpty()) if (items.isEmpty())
return; return;
const QHash<QString, QWidget*> widgets = { const QHash<QString, QWidget*> widgets = {{tr("General"), ui->generalTab},
{tr("General"), ui->generalTab}, {tr("System"), ui->systemTab}, {tr("System"), ui->systemTab},
{tr("Input"), ui->inputTab}, {tr("Graphics"), ui->graphicsTab}, {tr("Input"), ui->inputTab},
{tr("Audio"), ui->audioTab}, {tr("Camera"), ui->cameraTab}, {tr("Graphics"), ui->graphicsTab},
{tr("Debug"), ui->debugTab}, {tr("Web"), ui->webTab}}; {tr("Audio"), ui->audioTab},
{tr("Camera"), ui->cameraTab},
{tr("Debug"), ui->debugTab},
{tr("Web"), ui->webTab},
{tr("UI"), ui->uiTab}};
ui->tabWidget->clear(); ui->tabWidget->clear();

View File

@ -2,7 +2,6 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <QDirIterator>
#include "citra_qt/configuration/configure_general.h" #include "citra_qt/configuration/configure_general.h"
#include "citra_qt/ui_settings.h" #include "citra_qt/ui_settings.h"
#include "core/core.h" #include "core/core.h"
@ -13,28 +12,6 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
: QWidget(parent), ui(new Ui::ConfigureGeneral) { : QWidget(parent), ui(new Ui::ConfigureGeneral) {
ui->setupUi(this); ui->setupUi(this);
ui->language_combobox->addItem(tr("<System>"), QString(""));
ui->language_combobox->addItem(tr("English"), QString("en"));
QDirIterator it(":/languages", QDirIterator::NoIteratorFlags);
while (it.hasNext()) {
QString locale = it.next();
locale.truncate(locale.lastIndexOf('.'));
locale.remove(0, locale.lastIndexOf('/') + 1);
QString lang = QLocale::languageToString(QLocale(locale).language());
ui->language_combobox->addItem(lang, locale);
}
// Unlike other configuration changes, interface language changes need to be reflected on the
// interface immediately. This is done by passing a signal to the main window, and then
// retranslating when passing back.
connect(ui->language_combobox,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
&ConfigureGeneral::onLanguageChanged);
for (const auto& theme : UISettings::themes) {
ui->theme_combobox->addItem(theme.first, theme.second);
}
this->setConfiguration(); this->setConfiguration();
ui->updateBox->setVisible(UISettings::values.updater_found); ui->updateBox->setVisible(UISettings::values.updater_found);
@ -50,10 +27,6 @@ void ConfigureGeneral::setConfiguration() {
// The first item is "auto-select" with actual value -1, so plus one here will do the trick // The first item is "auto-select" with actual value -1, so plus one here will do the trick
ui->region_combobox->setCurrentIndex(Settings::values.region_value + 1); ui->region_combobox->setCurrentIndex(Settings::values.region_value + 1);
ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
ui->language_combobox->setCurrentIndex(
ui->language_combobox->findData(UISettings::values.language));
} }
void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) { void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) {
@ -62,8 +35,6 @@ void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) {
void ConfigureGeneral::applyConfiguration() { void ConfigureGeneral::applyConfiguration() {
UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
UISettings::values.theme =
ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString();
UISettings::values.check_for_update_on_start = ui->toggle_update_check->isChecked(); UISettings::values.check_for_update_on_start = ui->toggle_update_check->isChecked();
UISettings::values.update_on_close = ui->toggle_auto_update->isChecked(); UISettings::values.update_on_close = ui->toggle_auto_update->isChecked();
@ -71,13 +42,6 @@ void ConfigureGeneral::applyConfiguration() {
Settings::values.region_value = ui->region_combobox->currentIndex() - 1; Settings::values.region_value = ui->region_combobox->currentIndex() - 1;
} }
void ConfigureGeneral::onLanguageChanged(int index) {
if (index == -1)
return;
emit languageChanged(ui->language_combobox->itemData(index).toString());
}
void ConfigureGeneral::retranslateUi() { void ConfigureGeneral::retranslateUi() {
ui->retranslateUi(this); ui->retranslateUi(this);
ui->hotkeysDialog->retranslateUi(); ui->hotkeysDialog->retranslateUi();

View File

@ -24,12 +24,6 @@ public:
void applyConfiguration(); void applyConfiguration();
void retranslateUi(); void retranslateUi();
private slots:
void onLanguageChanged(int index);
signals:
void languageChanged(const QString& locale);
private: private:
void setConfiguration(); void setConfiguration();

View File

@ -31,20 +31,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="language_label">
<property name="text">
<string>Interface language</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="language_combobox"/>
</item>
</layout>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>
@ -145,33 +131,6 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QGroupBox" name="theme_group_box">
<property name="title">
<string>Theme</string>
</property>
<layout class="QHBoxLayout" name="theme_qhbox_layout">
<item>
<layout class="QVBoxLayout" name="theme_qvbox_layout">
<item>
<layout class="QHBoxLayout" name="theme_qhbox_layout_2">
<item>
<widget class="QLabel" name="theme_label">
<property name="text">
<string>Theme:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="theme_combobox"/>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="groupBox_3"> <widget class="QGroupBox" name="groupBox_3">
<property name="title"> <property name="title">

View File

@ -0,0 +1,72 @@
// Copyright 2018 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <QDirIterator>
#include "citra_qt/configuration/configure_ui.h"
#include "citra_qt/ui_settings.h"
#include "ui_configure_ui.h"
ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureUi) {
ui->setupUi(this);
ui->language_combobox->addItem(tr("<System>"), QString(""));
ui->language_combobox->addItem(tr("English"), QString("en"));
QDirIterator it(":/languages", QDirIterator::NoIteratorFlags);
while (it.hasNext()) {
QString locale = it.next();
locale.truncate(locale.lastIndexOf('.'));
locale.remove(0, locale.lastIndexOf('/') + 1);
QString lang = QLocale::languageToString(QLocale(locale).language());
ui->language_combobox->addItem(lang, locale);
}
// Unlike other configuration changes, interface language changes need to be reflected on the
// interface immediately. This is done by passing a signal to the main window, and then
// retranslating when passing back.
connect(ui->language_combobox,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
&ConfigureUi::onLanguageChanged);
for (const auto& theme : UISettings::themes) {
ui->theme_combobox->addItem(theme.first, theme.second);
}
this->setConfiguration();
}
ConfigureUi::~ConfigureUi() = default;
void ConfigureUi::setConfiguration() {
ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
ui->language_combobox->setCurrentIndex(
ui->language_combobox->findData(UISettings::values.language));
ui->icon_size_combobox->setCurrentIndex(
static_cast<int>(UISettings::values.game_list_icon_size));
ui->row_1_text_combobox->setCurrentIndex(static_cast<int>(UISettings::values.game_list_row_1));
ui->row_2_text_combobox->setCurrentIndex(static_cast<int>(UISettings::values.game_list_row_2) +
1);
ui->toggle_hide_no_icon->setChecked(UISettings::values.game_list_hide_no_icon);
}
void ConfigureUi::applyConfiguration() {
UISettings::values.theme =
ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString();
UISettings::values.game_list_icon_size =
static_cast<UISettings::GameListIconSize>(ui->icon_size_combobox->currentIndex());
UISettings::values.game_list_row_1 =
static_cast<UISettings::GameListText>(ui->row_1_text_combobox->currentIndex());
UISettings::values.game_list_row_2 =
static_cast<UISettings::GameListText>(ui->row_2_text_combobox->currentIndex() - 1);
UISettings::values.game_list_hide_no_icon = ui->toggle_hide_no_icon->isChecked();
}
void ConfigureUi::onLanguageChanged(int index) {
if (index == -1)
return;
emit languageChanged(ui->language_combobox->itemData(index).toString());
}
void ConfigureUi::retranslateUi() {
ui->retranslateUi(this);
}

View File

@ -0,0 +1,34 @@
// Copyright 2018 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <QWidget>
namespace Ui {
class ConfigureUi;
}
class ConfigureUi : public QWidget {
Q_OBJECT
public:
explicit ConfigureUi(QWidget* parent = nullptr);
~ConfigureUi();
void applyConfiguration();
void retranslateUi();
private slots:
void onLanguageChanged(int index);
signals:
void languageChanged(const QString& locale);
private:
void setConfiguration();
std::unique_ptr<Ui::ConfigureUi> ui;
};

View File

@ -0,0 +1,194 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConfigureUi</class>
<widget class="QWidget" name="ConfigureUi">
<property name="windowTitle">
<string>Form</string>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>290</width>
<height>280</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="general_groupBox">
<property name="title">
<string>General</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="language_label">
<property name="text">
<string>Interface language:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="language_combobox"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="theme_label">
<property name="text">
<string>Theme:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="theme_combobox"/>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="game_list_groupBox">
<property name="title">
<string>Game List</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="icon_size_label">
<property name="text">
<string>Icon Size:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="icon_size_combobox">
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>Small (24x24)</string>
</property>
</item>
<item>
<property name="text">
<string>Large (48x48)</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="row_1_text_label">
<property name="text">
<string>Row 1 Text:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="row_1_text_combobox">
<item>
<property name="text">
<string>File Name</string>
</property>
</item>
<item>
<property name="text">
<string>Full Path</string>
</property>
</item>
<item>
<property name="text">
<string>Title Name</string>
</property>
</item>
<item>
<property name="text">
<string>Title ID</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QLabel" name="row_2_text_label">
<property name="text">
<string>Row 2 Text:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="row_2_text_combobox">
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>File Name</string>
</property>
</item>
<item>
<property name="text">
<string>Full Path</string>
</property>
</item>
<item>
<property name="text">
<string>Title Name</string>
</property>
</item>
<item>
<property name="text">
<string>Title ID</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="toggle_hide_no_icon">
<property name="text">
<string>Hide Titles without Icon</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -723,6 +723,11 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
return update_smdh; return update_smdh;
}(); }();
if (!Loader::IsValidSMDH(smdh) && UISettings::values.game_list_hide_no_icon) {
// Skip this invalid entry
return true;
}
auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
// The game list uses this as compatibility number for untested games // The game list uses this as compatibility number for untested games

View File

@ -62,6 +62,8 @@ public:
QString FindGameByProgramID(u64 program_id); QString FindGameByProgramID(u64 program_id);
void RefreshGameDirectory();
static const QStringList supported_file_extensions; static const QStringList supported_file_extensions;
signals: signals:
@ -87,8 +89,6 @@ private:
void ValidateEntry(const QModelIndex& item); void ValidateEntry(const QModelIndex& item);
void DonePopulating(QStringList watch_list); void DonePopulating(QStringList watch_list);
void RefreshGameDirectory();
void PopupContextMenu(const QPoint& menu_location); void PopupContextMenu(const QPoint& menu_location);
void AddGamePopup(QMenu& context_menu, const QString& path, u64 program_id, u64 extdata_id); void AddGamePopup(QMenu& context_menu, const QString& path, u64 program_id, u64 extdata_id);
void AddCustomDirPopup(QMenu& context_menu, QModelIndex selected); void AddCustomDirPopup(QMenu& context_menu, QModelIndex selected);

View File

@ -124,6 +124,13 @@ public:
} }
}; };
/// Game list icon sizes (in px)
static const std::unordered_map<UISettings::GameListIconSize, int> IconSizes{
{UISettings::GameListIconSize::NoIcon, 0},
{UISettings::GameListIconSize::SmallIcon, 24},
{UISettings::GameListIconSize::LargeIcon, 48},
};
/** /**
* A specialization of GameListItem for path values. * A specialization of GameListItem for path values.
* This class ensures that for every full path value it holds, a correct string representation * This class ensures that for every full path value it holds, a correct string representation
@ -145,9 +152,18 @@ public:
setData(qulonglong(program_id), ProgramIdRole); setData(qulonglong(program_id), ProgramIdRole);
setData(qulonglong(extdata_id), ExtdataIdRole); setData(qulonglong(extdata_id), ExtdataIdRole);
if (UISettings::values.game_list_icon_size == UISettings::GameListIconSize::NoIcon) {
// Do not display icons
setData(QPixmap(), Qt::DecorationRole);
}
bool large =
UISettings::values.game_list_icon_size == UISettings::GameListIconSize::LargeIcon;
if (!Loader::IsValidSMDH(smdh_data)) { if (!Loader::IsValidSMDH(smdh_data)) {
// SMDH is not valid, set a default icon // SMDH is not valid, set a default icon
setData(GetDefaultIcon(true), Qt::DecorationRole); if (UISettings::values.game_list_icon_size != UISettings::GameListIconSize::NoIcon)
setData(GetDefaultIcon(large), Qt::DecorationRole);
return; return;
} }
@ -155,7 +171,8 @@ public:
memcpy(&smdh, smdh_data.data(), sizeof(Loader::SMDH)); memcpy(&smdh, smdh_data.data(), sizeof(Loader::SMDH));
// Get icon from SMDH // Get icon from SMDH
setData(GetQPixmapFromSMDH(smdh, true), Qt::DecorationRole); if (UISettings::values.game_list_icon_size != UISettings::GameListIconSize::NoIcon)
setData(GetQPixmapFromSMDH(smdh, large), Qt::DecorationRole);
// Get title from SMDH // Get title from SMDH
setData(GetQStringShortTitleFromSMDH(smdh, Loader::SMDH::TitleLanguage::English), setData(GetQStringShortTitleFromSMDH(smdh, Loader::SMDH::TitleLanguage::English),
@ -171,29 +188,23 @@ public:
std::string path, filename, extension; std::string path, filename, extension;
Common::SplitPath(data(FullPathRole).toString().toStdString(), &path, &filename, Common::SplitPath(data(FullPathRole).toString().toStdString(), &path, &filename,
&extension); &extension);
QString title = data(TitleRole).toString();
QString second_name = QString::fromStdString(filename + extension); const std::unordered_map<UISettings::GameListText, QString> display_texts{
static QRegExp installed_pattern( {UISettings::GameListText::FileName, QString::fromStdString(filename + extension)},
QString::fromStdString( {UISettings::GameListText::FullPath, data(FullPathRole).toString()},
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + {UISettings::GameListText::TitleName, data(TitleRole).toString()},
"Nintendo " {UISettings::GameListText::TitleID,
"3DS/00000000000000000000000000000000/00000000000000000000000000000000/" QString::fromStdString(fmt::format("{:016X}", data(ProgramIdRole).toULongLong()))},
"title/0004000(0|e)/[0-9a-f]{8}/content/") };
.replace("\\", "\\\\"));
static QRegExp system_pattern( const QString& row1 = display_texts.at(UISettings::values.game_list_row_1);
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
"00000000000000000000000000000000/" QString row2;
"title/00040010/[0-9a-f]{8}/content/") auto row_2_id = UISettings::values.game_list_row_2;
.replace("\\", "\\\\")); if (row_2_id != UISettings::GameListText::NoText) {
if (installed_pattern.exactMatch(QString::fromStdString(path)) || row2 = (row1.isEmpty() ? "" : "\n ") + display_texts.at(row_2_id);
system_pattern.exactMatch(QString::fromStdString(path))) {
// Use a different mechanism for system / installed titles showing program ID
second_name = QString("%1-%2")
.arg(data(ProgramIdRole).toULongLong(), 16, 16, QChar('0'))
.toUpper()
.arg(QString::fromStdString(filename));
} }
return title + (title.isEmpty() ? "" : "\n ") + second_name; return row1 + row2;
} else { } else {
return GameListItem::data(role); return GameListItem::data(role);
} }
@ -320,18 +331,20 @@ public:
UISettings::GameDir* game_dir = &directory; UISettings::GameDir* game_dir = &directory;
setData(QVariant::fromValue(game_dir), GameDirRole); setData(QVariant::fromValue(game_dir), GameDirRole);
int icon_size = IconSizes.at(UISettings::values.game_list_icon_size);
switch (dir_type) { switch (dir_type) {
case GameListItemType::InstalledDir: case GameListItemType::InstalledDir:
setData(QIcon::fromTheme("sd_card").pixmap(48), Qt::DecorationRole); setData(QIcon::fromTheme("sd_card").pixmap(icon_size), Qt::DecorationRole);
setData("Installed Titles", Qt::DisplayRole); setData("Installed Titles", Qt::DisplayRole);
break; break;
case GameListItemType::SystemDir: case GameListItemType::SystemDir:
setData(QIcon::fromTheme("chip").pixmap(48), Qt::DecorationRole); setData(QIcon::fromTheme("chip").pixmap(icon_size), Qt::DecorationRole);
setData("System Titles", Qt::DisplayRole); setData("System Titles", Qt::DisplayRole);
break; break;
case GameListItemType::CustomDir: case GameListItemType::CustomDir:
QString icon_name = QFileInfo::exists(game_dir->path) ? "folder" : "bad_folder"; QString icon_name = QFileInfo::exists(game_dir->path) ? "folder" : "bad_folder";
setData(QIcon::fromTheme(icon_name).pixmap(48), Qt::DecorationRole); setData(QIcon::fromTheme(icon_name).pixmap(icon_size), Qt::DecorationRole);
setData(game_dir->path, Qt::DisplayRole); setData(game_dir->path, Qt::DisplayRole);
break; break;
}; };
@ -349,7 +362,9 @@ class GameListAddDir : public GameListItem {
public: public:
explicit GameListAddDir() { explicit GameListAddDir() {
setData(type(), TypeRole); setData(type(), TypeRole);
setData(QIcon::fromTheme("plus").pixmap(48), Qt::DecorationRole);
int icon_size = IconSizes.at(UISettings::values.game_list_icon_size);
setData(QIcon::fromTheme("plus").pixmap(icon_size), Qt::DecorationRole);
setData("Add New Game Directory", Qt::DisplayRole); setData("Add New Game Directory", Qt::DisplayRole);
} }

View File

@ -1286,6 +1286,7 @@ void GMainWindow::OnConfigure() {
SetDiscordEnabled(UISettings::values.enable_discord_presence); SetDiscordEnabled(UISettings::values.enable_discord_presence);
emit UpdateThemedIcons(); emit UpdateThemedIcons();
SyncMenuUISettings(); SyncMenuUISettings();
game_list->RefreshGameDirectory();
config->Save(); config->Save();
} }
} }

View File

@ -31,6 +31,20 @@ struct GameDir {
}; };
}; };
enum class GameListIconSize {
NoIcon, ///< Do not display icons
SmallIcon, ///< Display a small (24x24) icon
LargeIcon, ///< Display a large (48x48) icon
};
enum class GameListText {
NoText = -1, ///< No text
FileName, ///< Display the file name of the entry
FullPath, ///< Display the full path of the entry
TitleName, ///< Display the name of the title
TitleID, ///< Display the title ID
};
struct Values { struct Values {
QByteArray geometry; QByteArray geometry;
QByteArray state; QByteArray state;
@ -58,6 +72,12 @@ struct Values {
// Discord RPC // Discord RPC
bool enable_discord_presence; bool enable_discord_presence;
// Game List
GameListIconSize game_list_icon_size;
GameListText game_list_row_1;
GameListText game_list_row_2;
bool game_list_hide_no_icon;
QString roms_path; QString roms_path;
QString symbols_path; QString symbols_path;
QString movie_record_path; QString movie_record_path;