aboutsummaryrefslogtreecommitdiff
path: root/src/yuzu
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu')
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp2
-rw-r--r--src/yuzu/configuration/configure_general.cpp30
-rw-r--r--src/yuzu/configuration/configure_general.h7
-rw-r--r--src/yuzu/configuration/configure_general.ui41
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp3
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp19
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.h2
-rw-r--r--src/yuzu/configuration/configure_ui.cpp40
-rw-r--r--src/yuzu/debugger/controller.cpp6
-rw-r--r--src/yuzu/game_list.cpp58
-rw-r--r--src/yuzu/game_list.h2
-rw-r--r--src/yuzu/game_list_worker.cpp12
-rw-r--r--src/yuzu/main.cpp50
-rw-r--r--src/yuzu/main.h8
-rw-r--r--src/yuzu/uisettings.h1
-rw-r--r--src/yuzu/util/limitable_input_dialog.cpp38
-rw-r--r--src/yuzu/util/limitable_input_dialog.h12
17 files changed, 263 insertions, 68 deletions
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index 6028135c5..371bc01b1 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -27,6 +27,8 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry,
ui->inputTab->Initialize(input_subsystem);
+ ui->generalTab->SetResetCallback([&] { this->close(); });
+
SetConfiguration();
PopulateSelectionList();
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 55a6a37bd..38edb4d8d 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -2,11 +2,15 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <functional>
+#include <utility>
#include <QCheckBox>
+#include <QMessageBox>
#include <QSpinBox>
#include "common/settings.h"
#include "core/core.h"
#include "ui_configure_general.h"
+#include "yuzu/configuration/config.h"
#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_general.h"
#include "yuzu/uisettings.h"
@@ -23,6 +27,9 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
connect(ui->toggle_frame_limit, &QCheckBox::clicked, ui->frame_limit,
[this]() { ui->frame_limit->setEnabled(ui->toggle_frame_limit->isChecked()); });
}
+
+ connect(ui->button_reset_defaults, &QPushButton::clicked, this,
+ &ConfigureGeneral::ResetDefaults);
}
ConfigureGeneral::~ConfigureGeneral() = default;
@@ -41,6 +48,8 @@ void ConfigureGeneral::SetConfiguration() {
ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit.GetValue());
ui->frame_limit->setValue(Settings::values.frame_limit.GetValue());
+ ui->button_reset_defaults->setEnabled(runtime_lock);
+
if (Settings::IsConfiguringGlobal()) {
ui->frame_limit->setEnabled(Settings::values.use_frame_limit.GetValue());
} else {
@@ -49,6 +58,25 @@ void ConfigureGeneral::SetConfiguration() {
}
}
+// Called to set the callback when resetting settings to defaults
+void ConfigureGeneral::SetResetCallback(std::function<void()> callback) {
+ reset_callback = std::move(callback);
+}
+
+void ConfigureGeneral::ResetDefaults() {
+ QMessageBox::StandardButton answer = QMessageBox::question(
+ this, tr("yuzu"),
+ tr("This reset all settings and remove all per-game configurations. This will not delete "
+ "game directories, profiles, or input profiles. Proceed?"),
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
+ if (answer == QMessageBox::No) {
+ return;
+ }
+ UISettings::values.reset_to_defaults = true;
+ UISettings::values.is_game_list_reload_pending.exchange(true);
+ reset_callback();
+}
+
void ConfigureGeneral::ApplyConfiguration() {
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core, ui->use_multi_core,
use_multi_core);
@@ -105,6 +133,8 @@ void ConfigureGeneral::SetupPerGameUI() {
ui->toggle_background_pause->setVisible(false);
ui->toggle_hide_mouse->setVisible(false);
+ ui->button_reset_defaults->setVisible(false);
+
ConfigurationShared::SetColoredTristate(ui->toggle_frame_limit,
Settings::values.use_frame_limit, use_frame_limit);
ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core,
diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h
index 323ffbd8f..a0fd52492 100644
--- a/src/yuzu/configuration/configure_general.h
+++ b/src/yuzu/configuration/configure_general.h
@@ -4,9 +4,12 @@
#pragma once
+#include <functional>
#include <memory>
#include <QWidget>
+class ConfigureDialog;
+
namespace ConfigurationShared {
enum class CheckState;
}
@@ -24,6 +27,8 @@ public:
explicit ConfigureGeneral(QWidget* parent = nullptr);
~ConfigureGeneral() override;
+ void SetResetCallback(std::function<void()> callback);
+ void ResetDefaults();
void ApplyConfiguration();
private:
@@ -34,6 +39,8 @@ private:
void SetupPerGameUI();
+ std::function<void()> reset_callback;
+
std::unique_ptr<Ui::ConfigureGeneral> ui;
ConfigurationShared::CheckState use_frame_limit;
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index 2711116a2..bc7041090 100644
--- a/src/yuzu/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
- <width>300</width>
+ <width>329</width>
<height>407</height>
</rect>
</property>
@@ -104,6 +104,45 @@
</property>
</spacer>
</item>
+ <item>
+ <layout class="QHBoxLayout" name="layout_reset">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>5</number>
+ </property>
+ <property name="topMargin">
+ <number>5</number>
+ </property>
+ <property name="rightMargin">
+ <number>5</number>
+ </property>
+ <property name="bottomMargin">
+ <number>5</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="button_reset_defaults">
+ <property name="text">
+ <string>Reset All Settings</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="spacer_reset">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
</layout>
</item>
</layout>
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index ab3512810..d5d624b96 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -1395,7 +1395,8 @@ void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
void ConfigureInputPlayer::CreateProfile() {
const auto profile_name =
- LimitableInputDialog::GetText(this, tr("New Profile"), tr("Enter a profile name:"), 1, 20);
+ LimitableInputDialog::GetText(this, tr("New Profile"), tr("Enter a profile name:"), 1, 20,
+ LimitableInputDialog::InputLimiter::Filesystem);
if (profile_name.isEmpty()) {
return;
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index 61ba91cef..f50cda2f3 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -85,6 +85,8 @@ void PlayerControlPreview::SetConnectedStatus(bool checked) {
led_color[1] = led_pattern.position2 ? colors.led_on : colors.led_off;
led_color[2] = led_pattern.position3 ? colors.led_on : colors.led_off;
led_color[3] = led_pattern.position4 ? colors.led_on : colors.led_off;
+ is_enabled = checked;
+ ResetInputs();
}
void PlayerControlPreview::SetControllerType(const Settings::ControllerType type) {
@@ -108,6 +110,7 @@ void PlayerControlPreview::EndMapping() {
analog_mapping_index = Settings::NativeAnalog::NumAnalogs;
mapping_active = false;
blink_counter = 0;
+ ResetInputs();
}
void PlayerControlPreview::UpdateColors() {
@@ -156,7 +159,23 @@ void PlayerControlPreview::UpdateColors() {
// colors.right = QColor(Settings::values.players.GetValue()[player_index].body_color_right);
}
+void PlayerControlPreview::ResetInputs() {
+ for (std::size_t index = 0; index < button_values.size(); ++index) {
+ button_values[index] = false;
+ }
+
+ for (std::size_t index = 0; index < axis_values.size(); ++index) {
+ axis_values[index].properties = {0, 1, 0};
+ axis_values[index].value = {0, 0};
+ axis_values[index].raw_value = {0, 0};
+ }
+ update();
+}
+
void PlayerControlPreview::UpdateInput() {
+ if (!is_enabled && !mapping_active) {
+ return;
+ }
bool input_changed = false;
const auto& button_state = buttons;
for (std::size_t index = 0; index < button_values.size(); ++index) {
diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h
index 51bb84eb6..5fc16d8af 100644
--- a/src/yuzu/configuration/configure_input_player_widget.h
+++ b/src/yuzu/configuration/configure_input_player_widget.h
@@ -100,6 +100,7 @@ private:
static LedPattern GetColorPattern(std::size_t index, bool player_on);
void UpdateColors();
+ void ResetInputs();
// Draw controller functions
void DrawHandheldController(QPainter& p, QPointF center);
@@ -176,6 +177,7 @@ private:
using StickArray =
std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>;
+ bool is_enabled{};
bool mapping_active{};
int blink_counter{};
QColor button_color{};
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp
index 0a28c87c0..9674119e1 100644
--- a/src/yuzu/configuration/configure_ui.cpp
+++ b/src/yuzu/configuration/configure_ui.cpp
@@ -17,17 +17,30 @@
namespace {
constexpr std::array default_icon_sizes{
- std::make_pair(0, QT_TR_NOOP("None")),
- std::make_pair(32, QT_TR_NOOP("Small (32x32)")),
- std::make_pair(64, QT_TR_NOOP("Standard (64x64)")),
- std::make_pair(128, QT_TR_NOOP("Large (128x128)")),
- std::make_pair(256, QT_TR_NOOP("Full Size (256x256)")),
+ std::make_pair(0, QT_TRANSLATE_NOOP("ConfigureUI", "None")),
+ std::make_pair(32, QT_TRANSLATE_NOOP("ConfigureUI", "Small (32x32)")),
+ std::make_pair(64, QT_TRANSLATE_NOOP("ConfigureUI", "Standard (64x64)")),
+ std::make_pair(128, QT_TRANSLATE_NOOP("ConfigureUI", "Large (128x128)")),
+ std::make_pair(256, QT_TRANSLATE_NOOP("ConfigureUI", "Full Size (256x256)")),
};
+// clang-format off
constexpr std::array row_text_names{
- QT_TR_NOOP("Filename"), QT_TR_NOOP("Filetype"), QT_TR_NOOP("Title ID"),
- QT_TR_NOOP("Title Name"), QT_TR_NOOP("None"),
+ QT_TRANSLATE_NOOP("ConfigureUI", "Filename"),
+ QT_TRANSLATE_NOOP("ConfigureUI", "Filetype"),
+ QT_TRANSLATE_NOOP("ConfigureUI", "Title ID"),
+ QT_TRANSLATE_NOOP("ConfigureUI", "Title Name"),
+ QT_TRANSLATE_NOOP("ConfigureUI", "None"),
};
+// clang-format on
+
+QString GetTranslatedIconSize(size_t index) {
+ return QCoreApplication::translate("ConfigureUI", default_icon_sizes[index].second);
+}
+
+QString GetTranslatedRowTextName(size_t index) {
+ return QCoreApplication::translate("ConfigureUI", row_text_names[index]);
+}
} // Anonymous namespace
ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureUi) {
@@ -121,11 +134,11 @@ void ConfigureUi::RetranslateUI() {
ui->retranslateUi(this);
for (int i = 0; i < ui->icon_size_combobox->count(); i++) {
- ui->icon_size_combobox->setItemText(i, tr(default_icon_sizes[i].second));
+ ui->icon_size_combobox->setItemText(i, GetTranslatedIconSize(static_cast<size_t>(i)));
}
for (int i = 0; i < ui->row_1_text_combobox->count(); i++) {
- const QString name = tr(row_text_names[i]);
+ const QString name = GetTranslatedRowTextName(static_cast<size_t>(i));
ui->row_1_text_combobox->setItemText(i, name);
ui->row_2_text_combobox->setItemText(i, name);
@@ -152,8 +165,9 @@ void ConfigureUi::InitializeLanguageComboBox() {
}
void ConfigureUi::InitializeIconSizeComboBox() {
- for (const auto& size : default_icon_sizes) {
- ui->icon_size_combobox->addItem(QString::fromUtf8(size.second), size.first);
+ for (size_t i = 0; i < default_icon_sizes.size(); i++) {
+ const auto size = default_icon_sizes[i].first;
+ ui->icon_size_combobox->addItem(GetTranslatedIconSize(i), size);
}
}
@@ -170,7 +184,7 @@ void ConfigureUi::UpdateFirstRowComboBox(bool init) {
ui->row_1_text_combobox->clear();
for (std::size_t i = 0; i < row_text_names.size(); i++) {
- const QString row_text_name = QString::fromUtf8(row_text_names[i]);
+ const QString row_text_name = GetTranslatedRowTextName(i);
ui->row_1_text_combobox->addItem(row_text_name, QVariant::fromValue(i));
}
@@ -189,7 +203,7 @@ void ConfigureUi::UpdateSecondRowComboBox(bool init) {
ui->row_2_text_combobox->clear();
for (std::size_t i = 0; i < row_text_names.size(); ++i) {
- const QString row_text_name = QString::fromUtf8(row_text_names[i]);
+ const QString row_text_name = GetTranslatedRowTextName(i);
ui->row_2_text_combobox->addItem(row_text_name, QVariant::fromValue(i));
}
diff --git a/src/yuzu/debugger/controller.cpp b/src/yuzu/debugger/controller.cpp
index d85408ac6..c1fc69578 100644
--- a/src/yuzu/debugger/controller.cpp
+++ b/src/yuzu/debugger/controller.cpp
@@ -28,6 +28,7 @@ ControllerDialog::ControllerDialog(QWidget* parent) : QWidget(parent, Qt::Dialog
// Configure focus so that widget is focusable and the dialog automatically forwards focus to
// it.
setFocusProxy(widget);
+ widget->SetConnectedStatus(false);
widget->setFocusPolicy(Qt::StrongFocus);
widget->setFocus();
}
@@ -36,9 +37,8 @@ void ControllerDialog::refreshConfiguration() {
const auto& players = Settings::values.players.GetValue();
constexpr std::size_t player = 0;
widget->SetPlayerInputRaw(player, players[player].buttons, players[player].analogs);
- widget->SetConnectedStatus(players[player].connected);
widget->SetControllerType(players[player].controller_type);
- widget->repaint();
+ widget->SetConnectedStatus(players[player].connected);
}
QAction* ControllerDialog::toggleViewAction() {
@@ -56,6 +56,7 @@ void ControllerDialog::showEvent(QShowEvent* ev) {
if (toggle_view_action) {
toggle_view_action->setChecked(isVisible());
}
+ refreshConfiguration();
QWidget::showEvent(ev);
}
@@ -63,5 +64,6 @@ void ControllerDialog::hideEvent(QHideEvent* ev) {
if (toggle_view_action) {
toggle_view_action->setChecked(isVisible());
}
+ widget->SetConnectedStatus(false);
QWidget::hideEvent(ev);
}
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index aa3bd5e34..da956c99b 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -91,9 +91,8 @@ QString GameListSearchField::filterText() const {
QString GameList::GetLastFilterResultItem() const {
QString file_path;
- const int folder_count = item_model->rowCount();
- for (int i = 0; i < folder_count; ++i) {
+ for (int i = 1; i < item_model->rowCount() - 1; ++i) {
const QStandardItem* folder = item_model->item(i, 0);
const QModelIndex folder_index = folder->index();
const int children_count = folder->rowCount();
@@ -184,7 +183,6 @@ void GameList::OnItemExpanded(const QModelIndex& item) {
// Event in order to filter the gamelist after editing the searchfield
void GameList::OnTextChanged(const QString& new_text) {
- const int folder_count = tree_view->model()->rowCount();
QString edit_filter_text = new_text.toLower();
QStandardItem* folder;
int children_total = 0;
@@ -194,7 +192,7 @@ void GameList::OnTextChanged(const QString& new_text) {
if (edit_filter_text.isEmpty()) {
tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(),
UISettings::values.favorited_ids.size() == 0);
- for (int i = 1; i < folder_count; ++i) {
+ for (int i = 1; i < item_model->rowCount() - 1; ++i) {
folder = item_model->item(i, 0);
const QModelIndex folder_index = folder->index();
const int children_count = folder->rowCount();
@@ -207,7 +205,7 @@ void GameList::OnTextChanged(const QString& new_text) {
} else {
tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(), true);
int result_count = 0;
- for (int i = 1; i < folder_count; ++i) {
+ for (int i = 1; i < item_model->rowCount() - 1; ++i) {
folder = item_model->item(i, 0);
const QModelIndex folder_index = folder->index();
const int children_count = folder->rowCount();
@@ -328,18 +326,14 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvide
tree_view->setContextMenuPolicy(Qt::CustomContextMenu);
tree_view->setStyleSheet(QStringLiteral("QTreeView{ border: none; }"));
- item_model->insertColumns(0, UISettings::values.show_add_ons ? COLUMN_COUNT : COLUMN_COUNT - 1);
+ item_model->insertColumns(0, COLUMN_COUNT);
item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name"));
item_model->setHeaderData(COLUMN_COMPATIBILITY, Qt::Horizontal, tr("Compatibility"));
- if (UISettings::values.show_add_ons) {
- item_model->setHeaderData(COLUMN_ADD_ONS, Qt::Horizontal, tr("Add-ons"));
- item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, tr("File type"));
- item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, tr("Size"));
- } else {
- item_model->setHeaderData(COLUMN_FILE_TYPE - 1, Qt::Horizontal, tr("File type"));
- item_model->setHeaderData(COLUMN_SIZE - 1, Qt::Horizontal, tr("Size"));
- }
+ item_model->setHeaderData(COLUMN_ADD_ONS, Qt::Horizontal, tr("Add-ons"));
+ tree_view->setColumnHidden(COLUMN_ADD_ONS, !UISettings::values.show_add_ons);
+ item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, tr("File type"));
+ item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, tr("Size"));
item_model->setSortRole(GameListItemPath::SortRole);
connect(main_window, &GMainWindow::UpdateThemedIcons, this, &GameList::OnUpdateThemedIcons);
@@ -466,9 +460,8 @@ void GameList::DonePopulating(const QStringList& watch_list) {
QCoreApplication::processEvents();
}
tree_view->setEnabled(true);
- const int folder_count = tree_view->model()->rowCount();
int children_total = 0;
- for (int i = 1; i < folder_count; ++i) {
+ for (int i = 1; i < item_model->rowCount() - 1; ++i) {
children_total += item_model->item(i, 0)->rowCount();
}
search_field->setFilterResult(children_total, children_total);
@@ -512,6 +505,10 @@ void GameList::PopupContextMenu(const QPoint& menu_location) {
void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::string& path) {
QAction* favorite = context_menu.addAction(tr("Favorite"));
context_menu.addSeparator();
+ QAction* start_game = context_menu.addAction(tr("Start Game"));
+ QAction* start_game_global =
+ context_menu.addAction(tr("Start Game without Custom Configuration"));
+ context_menu.addSeparator();
QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location"));
QAction* open_mod_location = context_menu.addAction(tr("Open Mod Data Location"));
QAction* open_transferable_shader_cache =
@@ -547,6 +544,12 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
connect(open_save_location, &QAction::triggered, [this, program_id, path]() {
emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path);
});
+ connect(start_game, &QAction::triggered, [this, path]() {
+ emit BootGame(QString::fromStdString(path), 0, StartGameType::Normal);
+ });
+ connect(start_game_global, &QAction::triggered, [this, path]() {
+ emit BootGame(QString::fromStdString(path), 0, StartGameType::Global);
+ });
connect(open_mod_location, &QAction::triggered, [this, program_id, path]() {
emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path);
});
@@ -649,9 +652,9 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
}
void GameList::AddFavoritesPopup(QMenu& context_menu) {
- QAction* clear_all = context_menu.addAction(tr("Clear"));
+ QAction* clear = context_menu.addAction(tr("Clear"));
- connect(clear_all, &QAction::triggered, [this] {
+ connect(clear, &QAction::triggered, [this] {
for (const auto id : UISettings::values.favorited_ids) {
RemoveFavorite(id);
}
@@ -708,22 +711,7 @@ void GameList::PopulateAsync(QVector<UISettings::GameDir>& game_dirs) {
tree_view->setEnabled(false);
// Update the columns in case UISettings has changed
- item_model->removeColumns(0, item_model->columnCount());
- item_model->insertColumns(0, UISettings::values.show_add_ons ? COLUMN_COUNT : COLUMN_COUNT - 1);
- item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name"));
- item_model->setHeaderData(COLUMN_COMPATIBILITY, Qt::Horizontal, tr("Compatibility"));
-
- if (UISettings::values.show_add_ons) {
- item_model->setHeaderData(COLUMN_ADD_ONS, Qt::Horizontal, tr("Add-ons"));
- item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, tr("File type"));
- item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, tr("Size"));
- } else {
- item_model->setHeaderData(COLUMN_FILE_TYPE - 1, Qt::Horizontal, tr("File type"));
- item_model->setHeaderData(COLUMN_SIZE - 1, Qt::Horizontal, tr("Size"));
- item_model->removeColumns(COLUMN_COUNT - 1, 1);
- }
-
- LoadInterfaceLayout();
+ tree_view->setColumnHidden(COLUMN_ADD_ONS, !UISettings::values.show_add_ons);
// Delete any rows that might already exist if we're repopulating
item_model->removeRows(0, item_model->rowCount());
@@ -800,7 +788,7 @@ void GameList::AddFavorite(u64 program_id) {
if (folder->child(j)->data(GameListItemPath::ProgramIdRole).toULongLong() ==
program_id) {
QList<QStandardItem*> list;
- for (int k = 0; k < item_model->columnCount(); k++) {
+ for (int k = 0; k < COLUMN_COUNT; k++) {
list.append(folder->child(j, k)->clone());
}
list[0]->setData(folder->child(j)->data(GameListItem::SortRole),
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index ab6866735..b630e34ff 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -28,6 +28,7 @@ class GameListWorker;
class GameListSearchField;
class GameListDir;
class GMainWindow;
+enum class StartGameType;
namespace FileSys {
class ManualContentProvider;
@@ -82,6 +83,7 @@ public:
static const QStringList supported_file_extensions;
signals:
+ void BootGame(const QString& game_path, std::size_t program_index, StartGameType type);
void GameChosen(const QString& game_path);
void ShouldCancelWorker();
void OpenFolderRequested(u64 program_id, GameListOpenTarget target,
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 485045334..33cc90d5a 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -215,13 +215,11 @@ QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::stri
new GameListItemSize(Common::FS::GetSize(path)),
};
- if (UISettings::values.show_add_ons) {
- const auto patch_versions = GetGameListCachedObject(
- fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] {
- return FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable());
- });
- list.insert(2, new GameListItem(patch_versions));
- }
+ const auto patch_versions = GetGameListCachedObject(
+ fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] {
+ return FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable());
+ });
+ list.insert(2, new GameListItem(patch_versions));
return list;
}
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 237e26829..19339ff2d 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1094,6 +1094,7 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
}
void GMainWindow::ConnectWidgetEvents() {
+ connect(game_list, &GameList::BootGame, this, &GMainWindow::BootGame);
connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile);
connect(game_list, &GameList::OpenDirectory, this, &GMainWindow::OnGameListOpenDirectory);
connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder);
@@ -1320,7 +1321,7 @@ void GMainWindow::SelectAndSetCurrentUser() {
Settings::values.current_user = dialog.GetIndex();
}
-void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
+void GMainWindow::BootGame(const QString& filename, std::size_t program_index, StartGameType type) {
LOG_INFO(Frontend, "yuzu starting...");
StoreRecentFile(filename); // Put the filename on top of the list
@@ -1332,7 +1333,8 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData());
const auto loader = Loader::GetLoader(system, v_file, program_index);
- if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) {
+ if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success &&
+ type == StartGameType::Normal) {
// Load per game settings
const auto file_path = std::filesystem::path{filename.toStdU16String()};
const auto config_file_name = title_id == 0
@@ -2596,13 +2598,53 @@ void GMainWindow::OnConfigure() {
&GMainWindow::OnLanguageChanged);
const auto result = configure_dialog.exec();
- if (result != QDialog::Accepted && !UISettings::values.configuration_applied) {
+ if (result != QDialog::Accepted && !UISettings::values.configuration_applied &&
+ !UISettings::values.reset_to_defaults) {
+ // Runs if the user hit Cancel or closed the window, and did not ever press the Apply button
+ // or `Reset to Defaults` button
return;
} else if (result == QDialog::Accepted) {
+ // Only apply new changes if user hit Okay
+ // This is here to avoid applying changes if the user hit Apply, made some changes, then hit
+ // Cancel
configure_dialog.ApplyConfiguration();
- controller_dialog->refreshConfiguration();
+ } else if (UISettings::values.reset_to_defaults) {
+ LOG_INFO(Frontend, "Resetting all settings to defaults");
+ if (!Common::FS::RemoveFile(config->GetConfigFilePath())) {
+ LOG_WARNING(Frontend, "Failed to remove configuration file");
+ }
+ if (!Common::FS::RemoveDirContentsRecursively(
+ Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "custom")) {
+ LOG_WARNING(Frontend, "Failed to remove custom configuration files");
+ }
+ if (!Common::FS::RemoveDirRecursively(
+ Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "game_list")) {
+ LOG_WARNING(Frontend, "Failed to remove game metadata cache files");
+ }
+
+ // Explicitly save the game directories, since reinitializing config does not explicitly do
+ // so.
+ QVector<UISettings::GameDir> old_game_dirs = std::move(UISettings::values.game_dirs);
+ QVector<u64> old_favorited_ids = std::move(UISettings::values.favorited_ids);
+
+ Settings::values.disabled_addons.clear();
+
+ config = std::make_unique<Config>();
+ UISettings::values.reset_to_defaults = false;
+
+ UISettings::values.game_dirs = std::move(old_game_dirs);
+ UISettings::values.favorited_ids = std::move(old_favorited_ids);
+
+ InitializeRecentFileMenuActions();
+
+ SetDefaultUIGeometry();
+ RestoreUIState();
+
+ ShowTelemetryCallout();
}
+ controller_dialog->refreshConfiguration();
InitializeHotkeys();
+
if (UISettings::values.theme != old_theme) {
UpdateUITheme();
}
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 490b6889f..11f152cbe 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -39,6 +39,11 @@ class GameListPlaceholder;
class QtSoftwareKeyboardDialog;
+enum class StartGameType {
+ Normal, // Can use custom configuration
+ Global, // Only uses global configuration
+};
+
namespace Core::Frontend {
struct ControllerParameters;
struct InlineAppearParameters;
@@ -181,7 +186,8 @@ private:
void AllowOSSleep();
bool LoadROM(const QString& filename, std::size_t program_index);
- void BootGame(const QString& filename, std::size_t program_index = 0);
+ void BootGame(const QString& filename, std::size_t program_index = 0,
+ StartGameType with_config = StartGameType::Normal);
void ShutdownGame();
void ShowTelemetryCallout();
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index 49122ec32..cdcb83f9f 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -97,6 +97,7 @@ struct Values {
bool cache_game_list;
bool configuration_applied;
+ bool reset_to_defaults;
};
extern Values values;
diff --git a/src/yuzu/util/limitable_input_dialog.cpp b/src/yuzu/util/limitable_input_dialog.cpp
index edd78e579..6fea41f95 100644
--- a/src/yuzu/util/limitable_input_dialog.cpp
+++ b/src/yuzu/util/limitable_input_dialog.cpp
@@ -21,11 +21,13 @@ void LimitableInputDialog::CreateUI() {
text_label = new QLabel(this);
text_entry = new QLineEdit(this);
+ text_label_invalid = new QLabel(this);
buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
auto* const layout = new QVBoxLayout;
layout->addWidget(text_label);
layout->addWidget(text_entry);
+ layout->addWidget(text_label_invalid);
layout->addWidget(buttons);
setLayout(layout);
@@ -37,18 +39,36 @@ void LimitableInputDialog::ConnectEvents() {
}
QString LimitableInputDialog::GetText(QWidget* parent, const QString& title, const QString& text,
- int min_character_limit, int max_character_limit) {
+ int min_character_limit, int max_character_limit,
+ InputLimiter limit_type) {
Q_ASSERT(min_character_limit <= max_character_limit);
LimitableInputDialog dialog{parent};
dialog.setWindowTitle(title);
dialog.text_label->setText(text);
dialog.text_entry->setMaxLength(max_character_limit);
+ dialog.text_label_invalid->show();
+
+ switch (limit_type) {
+ case InputLimiter::Filesystem:
+ dialog.invalid_characters = QStringLiteral("<>:;\"/\\|,.!?*");
+ break;
+ default:
+ dialog.invalid_characters.clear();
+ dialog.text_label_invalid->hide();
+ break;
+ }
+ dialog.text_label_invalid->setText(
+ tr("The text can't contain any of the following characters:\n%1")
+ .arg(dialog.invalid_characters));
auto* const ok_button = dialog.buttons->button(QDialogButtonBox::Ok);
ok_button->setEnabled(false);
- connect(dialog.text_entry, &QLineEdit::textEdited, [&](const QString& new_text) {
- ok_button->setEnabled(new_text.length() >= min_character_limit);
+ connect(dialog.text_entry, &QLineEdit::textEdited, [&] {
+ if (!dialog.invalid_characters.isEmpty()) {
+ dialog.RemoveInvalidCharacters();
+ }
+ ok_button->setEnabled(dialog.text_entry->text().length() >= min_character_limit);
});
if (dialog.exec() != QDialog::Accepted) {
@@ -57,3 +77,15 @@ QString LimitableInputDialog::GetText(QWidget* parent, const QString& title, con
return dialog.text_entry->text();
}
+
+void LimitableInputDialog::RemoveInvalidCharacters() {
+ auto cpos = text_entry->cursorPosition();
+ for (int i = 0; i < text_entry->text().length(); i++) {
+ if (invalid_characters.contains(text_entry->text().at(i))) {
+ text_entry->setText(text_entry->text().remove(i, 1));
+ i--;
+ cpos--;
+ }
+ }
+ text_entry->setCursorPosition(cpos);
+}
diff --git a/src/yuzu/util/limitable_input_dialog.h b/src/yuzu/util/limitable_input_dialog.h
index 164ad7301..a8e31098b 100644
--- a/src/yuzu/util/limitable_input_dialog.h
+++ b/src/yuzu/util/limitable_input_dialog.h
@@ -18,14 +18,24 @@ public:
explicit LimitableInputDialog(QWidget* parent = nullptr);
~LimitableInputDialog() override;
+ enum class InputLimiter {
+ None,
+ Filesystem,
+ };
+
static QString GetText(QWidget* parent, const QString& title, const QString& text,
- int min_character_limit, int max_character_limit);
+ int min_character_limit, int max_character_limit,
+ InputLimiter limit_type = InputLimiter::None);
private:
void CreateUI();
void ConnectEvents();
+ void RemoveInvalidCharacters();
+ QString invalid_characters;
+
QLabel* text_label;
QLineEdit* text_entry;
+ QLabel* text_label_invalid;
QDialogButtonBox* buttons;
};