mirror of
https://github.com/PabloMK7/citra.git
synced 2025-09-11 05:10:05 +00:00
Merge branch 'PabloMK7:master' into wayland
This commit is contained in:
commit
9d64ddb121
171 changed files with 9190 additions and 1771 deletions
|
@ -81,6 +81,9 @@ add_executable(citra-qt
|
|||
configuration/configure_ui.cpp
|
||||
configuration/configure_ui.h
|
||||
configuration/configure_ui.ui
|
||||
configuration/configure_web.cpp
|
||||
configuration/configure_web.h
|
||||
configuration/configure_web.ui
|
||||
configuration/configure_cheats.cpp
|
||||
configuration/configure_cheats.h
|
||||
configuration/configure_cheats.ui
|
||||
|
|
|
@ -327,6 +327,8 @@ void Config::ReadCameraValues() {
|
|||
void Config::ReadControlValues() {
|
||||
qt_config->beginGroup(QStringLiteral("Controls"));
|
||||
|
||||
ReadBasicSetting(Settings::values.use_artic_base_controller);
|
||||
|
||||
int num_touch_from_button_maps =
|
||||
qt_config->beginReadArray(QStringLiteral("touch_from_button_maps"));
|
||||
|
||||
|
@ -636,6 +638,8 @@ void Config::ReadPathValues() {
|
|||
UISettings::values.game_dirs.append(game_dir);
|
||||
}
|
||||
}
|
||||
UISettings::values.last_artic_base_addr =
|
||||
ReadSetting(QStringLiteral("last_artic_base_addr"), QString{}).toString();
|
||||
UISettings::values.recent_files = ReadSetting(QStringLiteral("recentFiles")).toStringList();
|
||||
UISettings::values.language = ReadSetting(QStringLiteral("language"), QString{}).toString();
|
||||
}
|
||||
|
@ -665,6 +669,8 @@ void Config::ReadRendererValues() {
|
|||
ReadGlobalSetting(Settings::values.texture_filter);
|
||||
ReadGlobalSetting(Settings::values.texture_sampling);
|
||||
|
||||
ReadGlobalSetting(Settings::values.delay_game_render_thread_us);
|
||||
|
||||
if (global) {
|
||||
ReadBasicSetting(Settings::values.use_shader_jit);
|
||||
}
|
||||
|
@ -920,6 +926,8 @@ void Config::SaveCameraValues() {
|
|||
void Config::SaveControlValues() {
|
||||
qt_config->beginGroup(QStringLiteral("Controls"));
|
||||
|
||||
WriteBasicSetting(Settings::values.use_artic_base_controller);
|
||||
|
||||
WriteSetting(QStringLiteral("profile"), Settings::values.current_input_profile_index, 0);
|
||||
qt_config->beginWriteArray(QStringLiteral("profiles"));
|
||||
for (std::size_t p = 0; p < Settings::values.input_profiles.size(); ++p) {
|
||||
|
@ -1135,6 +1143,8 @@ void Config::SavePathValues() {
|
|||
WriteSetting(QStringLiteral("expanded"), game_dir.expanded, true);
|
||||
}
|
||||
qt_config->endArray();
|
||||
WriteSetting(QStringLiteral("last_artic_base_addr"),
|
||||
UISettings::values.last_artic_base_addr, QString{});
|
||||
WriteSetting(QStringLiteral("recentFiles"), UISettings::values.recent_files);
|
||||
WriteSetting(QStringLiteral("language"), UISettings::values.language, QString{});
|
||||
}
|
||||
|
@ -1164,6 +1174,8 @@ void Config::SaveRendererValues() {
|
|||
WriteGlobalSetting(Settings::values.texture_filter);
|
||||
WriteGlobalSetting(Settings::values.texture_sampling);
|
||||
|
||||
WriteGlobalSetting(Settings::values.delay_game_render_thread_us);
|
||||
|
||||
if (global) {
|
||||
WriteSetting(QStringLiteral("use_shader_jit"), Settings::values.use_shader_jit.GetValue(),
|
||||
true);
|
||||
|
|
|
@ -97,6 +97,12 @@
|
|||
<header>configuration/configure_enhancements.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ConfigureWeb</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>configuration/configure_web.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ConfigureUi</class>
|
||||
<extends>QWidget</extends>
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout1">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
|
@ -100,7 +100,7 @@
|
|||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="toggle_console">
|
||||
<property name="text">
|
||||
|
@ -125,7 +125,7 @@
|
|||
<property name="title">
|
||||
<string>CPU</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<layout class="QGridLayout" name="clock_speed_GLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QWidget" name="clock_speed_widget" native="true">
|
||||
<layout class="QHBoxLayout" name="clock_speed_layout">
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "citra_qt/configuration/configure_storage.h"
|
||||
#include "citra_qt/configuration/configure_system.h"
|
||||
#include "citra_qt/configuration/configure_ui.h"
|
||||
#include "citra_qt/configuration/configure_web.h"
|
||||
#include "citra_qt/hotkeys.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
|
@ -28,7 +29,7 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, Cor
|
|||
system{system_}, is_powered_on{system.IsPoweredOn()},
|
||||
general_tab{std::make_unique<ConfigureGeneral>(this)},
|
||||
system_tab{std::make_unique<ConfigureSystem>(system, this)},
|
||||
input_tab{std::make_unique<ConfigureInput>(this)},
|
||||
input_tab{std::make_unique<ConfigureInput>(system, this)},
|
||||
hotkeys_tab{std::make_unique<ConfigureHotkeys>(this)},
|
||||
graphics_tab{
|
||||
std::make_unique<ConfigureGraphics>(gl_renderer, physical_devices, is_powered_on, this)},
|
||||
|
@ -37,7 +38,7 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, Cor
|
|||
camera_tab{std::make_unique<ConfigureCamera>(this)},
|
||||
debug_tab{std::make_unique<ConfigureDebug>(is_powered_on, this)},
|
||||
storage_tab{std::make_unique<ConfigureStorage>(is_powered_on, this)},
|
||||
ui_tab{std::make_unique<ConfigureUi>(this)} {
|
||||
web_tab{std::make_unique<ConfigureWeb>(this)}, ui_tab{std::make_unique<ConfigureUi>(this)} {
|
||||
Settings::SetConfiguringGlobal(true);
|
||||
|
||||
ui->setupUi(this);
|
||||
|
@ -52,6 +53,7 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, Cor
|
|||
ui->tabWidget->addTab(camera_tab.get(), tr("Camera"));
|
||||
ui->tabWidget->addTab(debug_tab.get(), tr("Debug"));
|
||||
ui->tabWidget->addTab(storage_tab.get(), tr("Storage"));
|
||||
ui->tabWidget->addTab(web_tab.get(), tr("Web"));
|
||||
ui->tabWidget->addTab(ui_tab.get(), tr("UI"));
|
||||
|
||||
hotkeys_tab->Populate(registry);
|
||||
|
@ -87,6 +89,7 @@ void ConfigureDialog::SetConfiguration() {
|
|||
audio_tab->SetConfiguration();
|
||||
camera_tab->SetConfiguration();
|
||||
debug_tab->SetConfiguration();
|
||||
web_tab->SetConfiguration();
|
||||
ui_tab->SetConfiguration();
|
||||
storage_tab->SetConfiguration();
|
||||
}
|
||||
|
@ -102,6 +105,7 @@ void ConfigureDialog::ApplyConfiguration() {
|
|||
audio_tab->ApplyConfiguration();
|
||||
camera_tab->ApplyConfiguration();
|
||||
debug_tab->ApplyConfiguration();
|
||||
web_tab->ApplyConfiguration();
|
||||
ui_tab->ApplyConfiguration();
|
||||
storage_tab->ApplyConfiguration();
|
||||
system.ApplySettings();
|
||||
|
@ -114,7 +118,7 @@ void ConfigureDialog::PopulateSelectionList() {
|
|||
ui->selectorList->clear();
|
||||
|
||||
const std::array<std::pair<QString, QList<QWidget*>>, 5> items{
|
||||
{{tr("General"), {general_tab.get(), debug_tab.get(), ui_tab.get()}},
|
||||
{{tr("General"), {general_tab.get(), web_tab.get(), debug_tab.get(), ui_tab.get()}},
|
||||
{tr("System"), {system_tab.get(), camera_tab.get(), storage_tab.get()}},
|
||||
{tr("Graphics"), {enhancements_tab.get(), graphics_tab.get()}},
|
||||
{tr("Audio"), {audio_tab.get()}},
|
||||
|
@ -154,6 +158,7 @@ void ConfigureDialog::RetranslateUI() {
|
|||
audio_tab->RetranslateUI();
|
||||
camera_tab->RetranslateUI();
|
||||
debug_tab->RetranslateUI();
|
||||
web_tab->RetranslateUI();
|
||||
ui_tab->RetranslateUI();
|
||||
storage_tab->RetranslateUI();
|
||||
}
|
||||
|
@ -173,6 +178,7 @@ void ConfigureDialog::UpdateVisibleTabs() {
|
|||
{camera_tab.get(), tr("Camera")},
|
||||
{debug_tab.get(), tr("Debug")},
|
||||
{storage_tab.get(), tr("Storage")},
|
||||
{web_tab.get(), tr("Web")},
|
||||
{ui_tab.get(), tr("UI")}};
|
||||
|
||||
ui->tabWidget->clear();
|
||||
|
|
|
@ -29,6 +29,7 @@ class ConfigureAudio;
|
|||
class ConfigureCamera;
|
||||
class ConfigureDebug;
|
||||
class ConfigureStorage;
|
||||
class ConfigureWeb;
|
||||
class ConfigureUi;
|
||||
|
||||
class ConfigureDialog : public QDialog {
|
||||
|
@ -69,5 +70,6 @@ private:
|
|||
std::unique_ptr<ConfigureCamera> camera_tab;
|
||||
std::unique_ptr<ConfigureDebug> debug_tab;
|
||||
std::unique_ptr<ConfigureStorage> storage_tab;
|
||||
std::unique_ptr<ConfigureWeb> web_tab;
|
||||
std::unique_ptr<ConfigureUi> ui_tab;
|
||||
};
|
||||
|
|
|
@ -26,6 +26,10 @@ ConfigureGraphics::ConfigureGraphics(QString gl_renderer, std::span<const QStrin
|
|||
// Set the index to -1 to ensure the below lambda is called with setCurrentIndex
|
||||
ui->graphics_api_combo->setCurrentIndex(-1);
|
||||
|
||||
const auto width = static_cast<int>(QString::fromStdString("000000000").size() * 6);
|
||||
ui->delay_render_display_label->setMinimumWidth(width);
|
||||
ui->delay_render_combo->setVisible(!Settings::IsConfiguringGlobal());
|
||||
|
||||
auto graphics_api_combo_model =
|
||||
qobject_cast<QStandardItemModel*>(ui->graphics_api_combo->model());
|
||||
#ifndef ENABLE_SOFTWARE_RENDERER
|
||||
|
@ -82,12 +86,25 @@ ConfigureGraphics::ConfigureGraphics(QString gl_renderer, std::span<const QStrin
|
|||
connect(ui->graphics_api_combo, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||
&ConfigureGraphics::SetPhysicalDeviceComboVisibility);
|
||||
|
||||
connect(ui->delay_render_slider, &QSlider::valueChanged, this, [&](int value) {
|
||||
ui->delay_render_display_label->setText(
|
||||
QStringLiteral("%1 ms")
|
||||
.arg(((double)value) / 1000.f, 0, 'f', 3)
|
||||
.rightJustified(QString::fromStdString("000000000").size()));
|
||||
});
|
||||
|
||||
SetConfiguration();
|
||||
}
|
||||
|
||||
ConfigureGraphics::~ConfigureGraphics() = default;
|
||||
|
||||
void ConfigureGraphics::SetConfiguration() {
|
||||
ui->delay_render_slider->setValue(Settings::values.delay_game_render_thread_us.GetValue());
|
||||
ui->delay_render_display_label->setText(
|
||||
QStringLiteral("%1 ms")
|
||||
.arg(((double)ui->delay_render_slider->value()) / 1000, 0, 'f', 3)
|
||||
.rightJustified(QString::fromStdString("000000000").size()));
|
||||
|
||||
if (!Settings::IsConfiguringGlobal()) {
|
||||
ConfigurationShared::SetHighlight(ui->graphics_api_group,
|
||||
!Settings::values.graphics_api.UsingGlobal());
|
||||
|
@ -101,6 +118,16 @@ void ConfigureGraphics::SetConfiguration() {
|
|||
&Settings::values.texture_sampling);
|
||||
ConfigurationShared::SetHighlight(ui->widget_texture_sampling,
|
||||
!Settings::values.texture_sampling.UsingGlobal());
|
||||
ConfigurationShared::SetHighlight(
|
||||
ui->delay_render_layout, !Settings::values.delay_game_render_thread_us.UsingGlobal());
|
||||
|
||||
if (Settings::values.delay_game_render_thread_us.UsingGlobal()) {
|
||||
ui->delay_render_combo->setCurrentIndex(0);
|
||||
ui->delay_render_slider->setEnabled(false);
|
||||
} else {
|
||||
ui->delay_render_combo->setCurrentIndex(1);
|
||||
ui->delay_render_slider->setEnabled(true);
|
||||
}
|
||||
} else {
|
||||
ui->graphics_api_combo->setCurrentIndex(
|
||||
static_cast<int>(Settings::values.graphics_api.GetValue()));
|
||||
|
@ -144,6 +171,9 @@ void ConfigureGraphics::ApplyConfiguration() {
|
|||
ui->toggle_disk_shader_cache, use_disk_shader_cache);
|
||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync_new, ui->toggle_vsync_new,
|
||||
use_vsync_new);
|
||||
ConfigurationShared::ApplyPerGameSetting(
|
||||
&Settings::values.delay_game_render_thread_us, ui->delay_render_combo,
|
||||
[this](s32) { return ui->delay_render_slider->value(); });
|
||||
|
||||
if (Settings::IsConfiguringGlobal()) {
|
||||
Settings::values.use_shader_jit = ui->toggle_shader_jit->isChecked();
|
||||
|
@ -170,9 +200,16 @@ void ConfigureGraphics::SetupPerGameUI() {
|
|||
ui->toggle_async_present->setEnabled(Settings::values.async_presentation.UsingGlobal());
|
||||
ui->graphics_api_combo->setEnabled(Settings::values.graphics_api.UsingGlobal());
|
||||
ui->physical_device_combo->setEnabled(Settings::values.physical_device.UsingGlobal());
|
||||
ui->delay_render_combo->setEnabled(
|
||||
Settings::values.delay_game_render_thread_us.UsingGlobal());
|
||||
return;
|
||||
}
|
||||
|
||||
connect(ui->delay_render_combo, qOverload<int>(&QComboBox::activated), this, [this](int index) {
|
||||
ui->delay_render_slider->setEnabled(index == 1);
|
||||
ConfigurationShared::SetHighlight(ui->delay_render_layout, index == 1);
|
||||
});
|
||||
|
||||
ui->toggle_shader_jit->setVisible(false);
|
||||
|
||||
ConfigurationShared::SetColoredComboBox(
|
||||
|
|
|
@ -307,6 +307,83 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="delay_render_layout" native="true">
|
||||
<layout class="QHBoxLayout" name="delay_render_layout_inner">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QComboBox" name="delay_render_combo">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Use global</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Use per-game</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_delay_render">
|
||||
<property name="text">
|
||||
<string>Delay game render thread:</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Delays the emulated game render thread the specified amount of milliseconds every time it submits render commands to the GPU.</p><p>Adjust this feature in the (very few) dynamic-fps games to fix performance issues.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="delay_render_slider">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>16000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>250</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksBelow</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="delay_render_display_label">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "citra_qt/configuration/configure_input.h"
|
||||
#include "citra_qt/configuration/configure_motion_touch.h"
|
||||
#include "common/param_package.h"
|
||||
#include "core/core.h"
|
||||
#include "ui_configure_input.h"
|
||||
|
||||
const std::array<std::string, ConfigureInput::ANALOG_SUB_BUTTONS_NUM>
|
||||
|
@ -145,8 +146,8 @@ static QString AnalogToText(const Common::ParamPackage& param, const std::string
|
|||
return QObject::tr("[unknown]");
|
||||
}
|
||||
|
||||
ConfigureInput::ConfigureInput(QWidget* parent)
|
||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()),
|
||||
ConfigureInput::ConfigureInput(Core::System& _system, QWidget* parent)
|
||||
: QWidget(parent), system(_system), ui(std::make_unique<Ui::ConfigureInput>()),
|
||||
timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) {
|
||||
ui->setupUi(this);
|
||||
setFocusPolicy(Qt::ClickFocus);
|
||||
|
@ -400,6 +401,9 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
|||
ConfigureInput::~ConfigureInput() = default;
|
||||
|
||||
void ConfigureInput::ApplyConfiguration() {
|
||||
|
||||
Settings::values.use_artic_base_controller = ui->use_artic_controller->isChecked();
|
||||
|
||||
std::transform(buttons_param.begin(), buttons_param.end(),
|
||||
Settings::values.current_input_profile.buttons.begin(),
|
||||
[](const Common::ParamPackage& param) { return param.Serialize(); });
|
||||
|
@ -444,6 +448,10 @@ QList<QKeySequence> ConfigureInput::GetUsedKeyboardKeys() {
|
|||
}
|
||||
|
||||
void ConfigureInput::LoadConfiguration() {
|
||||
|
||||
ui->use_artic_controller->setChecked(Settings::values.use_artic_base_controller.GetValue());
|
||||
ui->use_artic_controller->setEnabled(!system.IsPoweredOn());
|
||||
|
||||
std::transform(Settings::values.current_input_profile.buttons.begin(),
|
||||
Settings::values.current_input_profile.buttons.end(), buttons_param.begin(),
|
||||
[](const std::string& str) { return Common::ParamPackage(str); });
|
||||
|
|
|
@ -30,7 +30,7 @@ class ConfigureInput : public QWidget {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConfigureInput(QWidget* parent = nullptr);
|
||||
explicit ConfigureInput(Core::System& system, QWidget* parent = nullptr);
|
||||
~ConfigureInput() override;
|
||||
|
||||
/// Save all button configurations to settings file
|
||||
|
@ -50,6 +50,7 @@ signals:
|
|||
void InputKeysChanged(QList<QKeySequence> new_key_list);
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
std::unique_ptr<Ui::ConfigureInput> ui;
|
||||
|
||||
std::unique_ptr<QTimer> timeout_timer;
|
||||
|
|
|
@ -841,6 +841,13 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="use_artic_controller">
|
||||
<property name="text">
|
||||
<string>Use Artic Controller when connected to Artic Base Server</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
@ -151,7 +151,14 @@ void ConfigurePerGame::LoadConfiguration() {
|
|||
ui->display_title_id->setText(
|
||||
QStringLiteral("%1").arg(title_id, 16, 16, QLatin1Char{'0'}).toUpper());
|
||||
|
||||
const auto loader = Loader::GetLoader(filename);
|
||||
std::unique_ptr<Loader::AppLoader> loader_ptr;
|
||||
Loader::AppLoader* loader;
|
||||
if (system.IsPoweredOn()) {
|
||||
loader = &system.GetAppLoader();
|
||||
} else {
|
||||
loader_ptr = Loader::GetLoader(filename);
|
||||
loader = loader_ptr.get();
|
||||
}
|
||||
|
||||
std::string title;
|
||||
if (loader->ReadTitle(title) == Loader::ResultStatus::Success)
|
||||
|
|
File diff suppressed because it is too large
Load diff
36
src/citra_qt/configuration/configure_web.cpp
Normal file
36
src/citra_qt/configuration/configure_web.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2017 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QIcon>
|
||||
#include <QMessageBox>
|
||||
#include <QtConcurrent/QtConcurrentRun>
|
||||
#include "citra_qt/configuration/configure_web.h"
|
||||
#include "citra_qt/uisettings.h"
|
||||
#include "network/network_settings.h"
|
||||
#include "ui_configure_web.h"
|
||||
|
||||
ConfigureWeb::ConfigureWeb(QWidget* parent)
|
||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureWeb>()) {
|
||||
ui->setupUi(this);
|
||||
|
||||
#ifndef USE_DISCORD_PRESENCE
|
||||
ui->discord_group->setVisible(false);
|
||||
#endif
|
||||
SetConfiguration();
|
||||
}
|
||||
|
||||
ConfigureWeb::~ConfigureWeb() = default;
|
||||
|
||||
void ConfigureWeb::SetConfiguration() {
|
||||
|
||||
ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence.GetValue());
|
||||
}
|
||||
|
||||
void ConfigureWeb::ApplyConfiguration() {
|
||||
UISettings::values.enable_discord_presence = ui->toggle_discordrpc->isChecked();
|
||||
}
|
||||
|
||||
void ConfigureWeb::RetranslateUI() {
|
||||
ui->retranslateUi(this);
|
||||
}
|
28
src/citra_qt/configuration/configure_web.h
Normal file
28
src/citra_qt/configuration/configure_web.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2017 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <QFutureWatcher>
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class ConfigureWeb;
|
||||
}
|
||||
|
||||
class ConfigureWeb : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConfigureWeb(QWidget* parent = nullptr);
|
||||
~ConfigureWeb() override;
|
||||
|
||||
void ApplyConfiguration();
|
||||
void RetranslateUI();
|
||||
void SetConfiguration();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::ConfigureWeb> ui;
|
||||
};
|
53
src/citra_qt/configuration/configure_web.ui
Normal file
53
src/citra_qt/configuration/configure_web.ui
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ConfigureWeb</class>
|
||||
<widget class="QWidget" name="ConfigureWeb">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>996</width>
|
||||
<height>561</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="discord_group">
|
||||
<property name="title">
|
||||
<string>Discord Presence</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_21">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="toggle_discordrpc">
|
||||
<property name="text">
|
||||
<string>Show Current Game in your Discord Status</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>toggle_discordrpc</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -381,6 +381,10 @@ void GMainWindow::InitializeWidgets() {
|
|||
progress_bar->hide();
|
||||
statusBar()->addPermanentWidget(progress_bar);
|
||||
|
||||
artic_traffic_label = new QLabel();
|
||||
artic_traffic_label->setToolTip(
|
||||
tr("Current Artic Base traffic speed. Higher values indicate bigger transfer loads."));
|
||||
|
||||
emu_speed_label = new QLabel();
|
||||
emu_speed_label->setToolTip(tr("Current emulation speed. Values higher or lower than 100% "
|
||||
"indicate emulation is running faster or slower than a 3DS."));
|
||||
|
@ -392,7 +396,8 @@ void GMainWindow::InitializeWidgets() {
|
|||
tr("Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For "
|
||||
"full-speed emulation this should be at most 16.67 ms."));
|
||||
|
||||
for (auto& label : {emu_speed_label, game_fps_label, emu_frametime_label}) {
|
||||
for (auto& label :
|
||||
{artic_traffic_label, emu_speed_label, game_fps_label, emu_frametime_label}) {
|
||||
label->setVisible(false);
|
||||
label->setFrameStyle(QFrame::NoFrame);
|
||||
label->setContentsMargins(4, 0, 4, 0);
|
||||
|
@ -866,6 +871,7 @@ void GMainWindow::ConnectMenuEvents() {
|
|||
// File
|
||||
connect_menu(ui->action_Load_File, &GMainWindow::OnMenuLoadFile);
|
||||
connect_menu(ui->action_Install_CIA, &GMainWindow::OnMenuInstallCIA);
|
||||
connect_menu(ui->action_Connect_Artic, &GMainWindow::OnMenuConnectArticBase);
|
||||
for (u32 region = 0; region < Core::NUM_SYSTEM_TITLE_REGIONS; region++) {
|
||||
connect_menu(ui->menu_Boot_Home_Menu->actions().at(region),
|
||||
[this, region] { OnMenuBootHomeMenu(region); });
|
||||
|
@ -935,6 +941,10 @@ void GMainWindow::ConnectMenuEvents() {
|
|||
|
||||
// Help
|
||||
connect_menu(ui->action_Open_Citra_Folder, &GMainWindow::OnOpenCitraFolder);
|
||||
connect_menu(ui->action_Open_Log_Folder, []() {
|
||||
QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LogDir));
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
||||
});
|
||||
connect_menu(ui->action_FAQ, []() {
|
||||
QDesktopServices::openUrl(QUrl(QStringLiteral("https://citra-emu.org/wiki/faq/")));
|
||||
});
|
||||
|
@ -964,7 +974,7 @@ void GMainWindow::UpdateMenuState() {
|
|||
action->setEnabled(emulation_running);
|
||||
}
|
||||
|
||||
ui->action_Capture_Screenshot->setEnabled(emulation_running && !is_paused);
|
||||
ui->action_Capture_Screenshot->setEnabled(emulation_running);
|
||||
|
||||
if (emulation_running && is_paused) {
|
||||
ui->action_Pause->setText(tr("&Continue"));
|
||||
|
@ -1203,6 +1213,14 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
|||
tr("GBA Virtual Console ROMs are not supported by Citra."));
|
||||
break;
|
||||
|
||||
case Core::System::ResultStatus::ErrorArticDisconnected:
|
||||
QMessageBox::critical(
|
||||
this, tr("Artic Base Server"),
|
||||
tr(fmt::format(
|
||||
"An error has occurred whilst communicating with the Artic Base Server.\n{}",
|
||||
system.GetStatusDetails())
|
||||
.c_str()));
|
||||
break;
|
||||
default:
|
||||
QMessageBox::critical(
|
||||
this, tr("Error while loading ROM!"),
|
||||
|
@ -1223,7 +1241,13 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
|||
}
|
||||
|
||||
void GMainWindow::BootGame(const QString& filename) {
|
||||
if (filename.endsWith(QStringLiteral(".cia"))) {
|
||||
if (emu_thread) {
|
||||
ShutdownGame();
|
||||
}
|
||||
|
||||
const bool is_artic = filename.startsWith(QString::fromStdString("articbase://"));
|
||||
|
||||
if (!is_artic && filename.endsWith(QStringLiteral(".cia"))) {
|
||||
const auto answer = QMessageBox::question(
|
||||
this, tr("CIA must be installed before usage"),
|
||||
tr("Before using this CIA, you must install it. Do you want to install it now?"),
|
||||
|
@ -1235,8 +1259,12 @@ void GMainWindow::BootGame(const QString& filename) {
|
|||
return;
|
||||
}
|
||||
|
||||
show_artic_label = is_artic;
|
||||
|
||||
LOG_INFO(Frontend, "Citra starting...");
|
||||
StoreRecentFile(filename); // Put the filename on top of the list
|
||||
if (!is_artic) {
|
||||
StoreRecentFile(filename); // Put the filename on top of the list
|
||||
}
|
||||
|
||||
if (movie_record_on_start) {
|
||||
movie.PrepareForRecording();
|
||||
|
@ -1246,16 +1274,26 @@ void GMainWindow::BootGame(const QString& filename) {
|
|||
}
|
||||
|
||||
const std::string path = filename.toStdString();
|
||||
const auto loader = Loader::GetLoader(path);
|
||||
auto loader = Loader::GetLoader(path);
|
||||
|
||||
u64 title_id{0};
|
||||
loader->ReadProgramId(title_id);
|
||||
Loader::ResultStatus res = loader->ReadProgramId(title_id);
|
||||
|
||||
if (Loader::ResultStatus::Success == res) {
|
||||
// Load per game settings
|
||||
const std::string name{is_artic ? "" : FileUtil::GetFilename(filename.toStdString())};
|
||||
const std::string config_file_name =
|
||||
title_id == 0 ? name : fmt::format("{:016X}", title_id);
|
||||
LOG_INFO(Frontend, "Loading per game config file for title {}", config_file_name);
|
||||
Config per_game_config(config_file_name, Config::ConfigType::PerGameConfig);
|
||||
}
|
||||
|
||||
// Artic Base Server cannot accept a client multiple times, so multiple loaders are not
|
||||
// possible. Instead register the app loader early and do not create it again on system load.
|
||||
if (!loader->SupportsMultipleInstancesForSameFile()) {
|
||||
system.RegisterAppLoaderEarly(loader);
|
||||
}
|
||||
|
||||
// Load per game settings
|
||||
const std::string name{FileUtil::GetFilename(filename.toStdString())};
|
||||
const std::string config_file_name = title_id == 0 ? name : fmt::format("{:016X}", title_id);
|
||||
LOG_INFO(Frontend, "Loading per game config file for title {}", config_file_name);
|
||||
Config per_game_config(config_file_name, Config::ConfigType::PerGameConfig);
|
||||
system.ApplySettings();
|
||||
|
||||
Settings::LogSettings();
|
||||
|
@ -1265,8 +1303,11 @@ void GMainWindow::BootGame(const QString& filename) {
|
|||
game_list->SaveInterfaceLayout();
|
||||
config->Save();
|
||||
|
||||
if (!LoadROM(filename))
|
||||
if (!LoadROM(filename)) {
|
||||
render_window->ReleaseRenderTarget();
|
||||
secondary_window->ReleaseRenderTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
// Set everything up
|
||||
if (movie_record_on_start) {
|
||||
|
@ -1420,6 +1461,8 @@ void GMainWindow::ShutdownGame() {
|
|||
// Disable status bar updates
|
||||
status_bar_update_timer.stop();
|
||||
message_label_used_for_movie = false;
|
||||
show_artic_label = false;
|
||||
artic_traffic_label->setVisible(false);
|
||||
emu_speed_label->setVisible(false);
|
||||
game_fps_label->setVisible(false);
|
||||
emu_frametime_label->setVisible(false);
|
||||
|
@ -1759,6 +1802,17 @@ void GMainWindow::OnMenuInstallCIA() {
|
|||
InstallCIA(filepaths);
|
||||
}
|
||||
|
||||
void GMainWindow::OnMenuConnectArticBase() {
|
||||
bool ok = false;
|
||||
auto res = QInputDialog::getText(this, tr("Connect to Artic Base"),
|
||||
tr("Enter Artic Base server address:"), QLineEdit::Normal,
|
||||
UISettings::values.last_artic_base_addr, &ok);
|
||||
if (ok) {
|
||||
UISettings::values.last_artic_base_addr = res;
|
||||
BootGame(QString::fromStdString("articbase://").append(res));
|
||||
}
|
||||
}
|
||||
|
||||
void GMainWindow::OnMenuBootHomeMenu(u32 region) {
|
||||
BootGame(QString::fromStdString(Core::GetHomeMenuNcchPath(region)));
|
||||
}
|
||||
|
@ -2365,33 +2419,47 @@ void GMainWindow::OnSaveMovie() {
|
|||
}
|
||||
|
||||
void GMainWindow::OnCaptureScreenshot() {
|
||||
if (!emu_thread || !emu_thread->IsRunning()) [[unlikely]] {
|
||||
if (!emu_thread) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
|
||||
OnPauseGame();
|
||||
std::string path = UISettings::values.screenshot_path.GetValue();
|
||||
if (!FileUtil::IsDirectory(path)) {
|
||||
if (!FileUtil::CreateFullPath(path)) {
|
||||
QMessageBox::information(this, tr("Invalid Screenshot Directory"),
|
||||
tr("Cannot create specified screenshot directory. Screenshot "
|
||||
"path is set back to its default value."));
|
||||
path = FileUtil::GetUserPath(FileUtil::UserPath::UserDir);
|
||||
path.append("screenshots/");
|
||||
UISettings::values.screenshot_path = path;
|
||||
};
|
||||
const bool was_running = emu_thread->IsRunning();
|
||||
|
||||
if (was_running ||
|
||||
(QMessageBox::question(
|
||||
this, tr("Game will unpause"),
|
||||
tr("The game will be unpaused, and the next frame will be captured. Is this okay?"),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes)) {
|
||||
if (was_running) {
|
||||
OnPauseGame();
|
||||
}
|
||||
std::string path = UISettings::values.screenshot_path.GetValue();
|
||||
if (!FileUtil::IsDirectory(path)) {
|
||||
if (!FileUtil::CreateFullPath(path)) {
|
||||
QMessageBox::information(
|
||||
this, tr("Invalid Screenshot Directory"),
|
||||
tr("Cannot create specified screenshot directory. Screenshot "
|
||||
"path is set back to its default value."));
|
||||
path = FileUtil::GetUserPath(FileUtil::UserPath::UserDir);
|
||||
path.append("screenshots/");
|
||||
UISettings::values.screenshot_path = path;
|
||||
};
|
||||
}
|
||||
|
||||
static QRegularExpression expr(QStringLiteral("[\\/:?\"<>|]"));
|
||||
const std::string filename = game_title.remove(expr).toStdString();
|
||||
const std::string timestamp = QDateTime::currentDateTime()
|
||||
.toString(QStringLiteral("dd.MM.yy_hh.mm.ss.z"))
|
||||
.toStdString();
|
||||
path.append(fmt::format("/{}_{}.png", filename, timestamp));
|
||||
|
||||
auto* const screenshot_window =
|
||||
secondary_window->HasFocus() ? secondary_window : render_window;
|
||||
screenshot_window->CaptureScreenshot(
|
||||
UISettings::values.screenshot_resolution_factor.GetValue(),
|
||||
QString::fromStdString(path));
|
||||
OnStartGame();
|
||||
}
|
||||
|
||||
static QRegularExpression expr(QStringLiteral("[\\/:?\"<>|]"));
|
||||
const std::string filename = game_title.remove(expr).toStdString();
|
||||
const std::string timestamp =
|
||||
QDateTime::currentDateTime().toString(QStringLiteral("dd.MM.yy_hh.mm.ss.z")).toStdString();
|
||||
path.append(fmt::format("/{}_{}.png", filename, timestamp));
|
||||
|
||||
auto* const screenshot_window = secondary_window->HasFocus() ? secondary_window : render_window;
|
||||
screenshot_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor.GetValue(),
|
||||
QString::fromStdString(path));
|
||||
OnStartGame();
|
||||
}
|
||||
|
||||
void GMainWindow::OnDumpVideo() {
|
||||
|
@ -2575,6 +2643,53 @@ void GMainWindow::UpdateStatusBar() {
|
|||
|
||||
auto results = system.GetAndResetPerfStats();
|
||||
|
||||
if (show_artic_label) {
|
||||
const bool do_mb = results.artic_transmitted >= (1000.0 * 1000.0);
|
||||
const double value = do_mb ? (results.artic_transmitted / (1000.0 * 1000.0))
|
||||
: (results.artic_transmitted / 1000.0);
|
||||
static const std::array<std::pair<Core::PerfStats::PerfArticEventBits, QString>, 5>
|
||||
perf_events = {
|
||||
std::make_pair(Core::PerfStats::PerfArticEventBits::ARTIC_SHARED_EXT_DATA,
|
||||
tr("(Accessing SharedExtData)")),
|
||||
std::make_pair(Core::PerfStats::PerfArticEventBits::ARTIC_SYSTEM_SAVE_DATA,
|
||||
tr("(Accessing SystemSaveData)")),
|
||||
std::make_pair(Core::PerfStats::PerfArticEventBits::ARTIC_BOSS_EXT_DATA,
|
||||
tr("(Accessing BossExtData)")),
|
||||
std::make_pair(Core::PerfStats::PerfArticEventBits::ARTIC_EXT_DATA,
|
||||
tr("(Accessing ExtData)")),
|
||||
std::make_pair(Core::PerfStats::PerfArticEventBits::ARTIC_SAVE_DATA,
|
||||
tr("(Accessing SaveData)")),
|
||||
};
|
||||
|
||||
const QString unit = do_mb ? tr("MB/s") : tr("KB/s");
|
||||
QString event{};
|
||||
for (auto p : perf_events) {
|
||||
if (results.artic_events.Get(p.first)) {
|
||||
event = QString::fromStdString(" ") + p.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const std::array label_color = {QStringLiteral("#ffffff"), QStringLiteral("#eed202"),
|
||||
QStringLiteral("#ff3333")};
|
||||
|
||||
int style_index;
|
||||
|
||||
if (value > 200.0) {
|
||||
style_index = 2;
|
||||
} else if (value > 125.0) {
|
||||
style_index = 1;
|
||||
} else {
|
||||
style_index = 0;
|
||||
}
|
||||
const QString style_sheet =
|
||||
QStringLiteral("QLabel { color: %0; }").arg(label_color[style_index]);
|
||||
|
||||
artic_traffic_label->setText(
|
||||
tr("Artic Base Traffic: %1 %2%3").arg(value, 0, 'f', 0).arg(unit).arg(event));
|
||||
artic_traffic_label->setStyleSheet(style_sheet);
|
||||
}
|
||||
|
||||
if (Settings::values.frame_limit.GetValue() == 0) {
|
||||
emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
|
||||
} else {
|
||||
|
@ -2585,6 +2700,9 @@ void GMainWindow::UpdateStatusBar() {
|
|||
game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 0));
|
||||
emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
|
||||
|
||||
if (show_artic_label) {
|
||||
artic_traffic_label->setVisible(true);
|
||||
}
|
||||
emu_speed_label->setVisible(true);
|
||||
game_fps_label->setVisible(true);
|
||||
emu_frametime_label->setVisible(true);
|
||||
|
@ -2736,6 +2854,7 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
|
|||
|
||||
QString title, message;
|
||||
QMessageBox::Icon error_severity_icon;
|
||||
bool can_continue = true;
|
||||
if (result == Core::System::ResultStatus::ErrorSystemFiles) {
|
||||
const QString common_message =
|
||||
tr("%1 is missing. Please <a "
|
||||
|
@ -2756,6 +2875,13 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
|
|||
title = tr("Save/load Error");
|
||||
message = QString::fromStdString(details);
|
||||
error_severity_icon = QMessageBox::Icon::Warning;
|
||||
} else if (result == Core::System::ResultStatus::ErrorArticDisconnected) {
|
||||
title = tr("Artic Base Server");
|
||||
message =
|
||||
tr(fmt::format("A communication error has occurred. The game will quit.\n{}", details)
|
||||
.c_str());
|
||||
error_severity_icon = QMessageBox::Icon::Critical;
|
||||
can_continue = false;
|
||||
} else {
|
||||
title = tr("Fatal Error");
|
||||
message =
|
||||
|
@ -2772,12 +2898,14 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
|
|||
message_box.setText(message);
|
||||
message_box.setIcon(error_severity_icon);
|
||||
if (error_severity_icon == QMessageBox::Icon::Critical) {
|
||||
message_box.addButton(tr("Continue"), QMessageBox::RejectRole);
|
||||
if (can_continue) {
|
||||
message_box.addButton(tr("Continue"), QMessageBox::RejectRole);
|
||||
}
|
||||
QPushButton* abort_button = message_box.addButton(tr("Quit Game"), QMessageBox::AcceptRole);
|
||||
if (result != Core::System::ResultStatus::ShutdownRequested)
|
||||
message_box.exec();
|
||||
|
||||
if (result == Core::System::ResultStatus::ShutdownRequested ||
|
||||
if (!can_continue || result == Core::System::ResultStatus::ShutdownRequested ||
|
||||
message_box.clickedButton() == abort_button) {
|
||||
if (emu_thread) {
|
||||
ShutdownGame();
|
||||
|
|
|
@ -216,6 +216,7 @@ private slots:
|
|||
void OnConfigurePerGame();
|
||||
void OnMenuLoadFile();
|
||||
void OnMenuInstallCIA();
|
||||
void OnMenuConnectArticBase();
|
||||
void OnMenuBootHomeMenu(u32 region);
|
||||
void OnUpdateProgress(std::size_t written, std::size_t total);
|
||||
void OnCIAInstallReport(Service::AM::InstallStatus status, QString filepath);
|
||||
|
@ -302,6 +303,8 @@ private:
|
|||
// Status bar elements
|
||||
QProgressBar* progress_bar = nullptr;
|
||||
QLabel* message_label = nullptr;
|
||||
bool show_artic_label = false;
|
||||
QLabel* artic_traffic_label = nullptr;
|
||||
QLabel* emu_speed_label = nullptr;
|
||||
QLabel* game_fps_label = nullptr;
|
||||
QLabel* emu_frametime_label = nullptr;
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
</widget>
|
||||
<addaction name="action_Load_File"/>
|
||||
<addaction name="action_Install_CIA"/>
|
||||
<addaction name="action_Connect_Artic"/>
|
||||
<addaction name="menu_Boot_Home_Menu"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="menu_recent_files"/>
|
||||
|
@ -202,6 +203,7 @@
|
|||
<addaction name="separator"/>
|
||||
<addaction name="action_Report_Compatibility"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_Open_Log_Folder"/>
|
||||
<addaction name="action_FAQ"/>
|
||||
<addaction name="action_About"/>
|
||||
</widget>
|
||||
|
@ -222,6 +224,11 @@
|
|||
<string>Install CIA...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Connect_Artic">
|
||||
<property name="text">
|
||||
<string>Connect to Artic Base...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Boot_Home_Menu_JPN">
|
||||
<property name="text">
|
||||
<string>JPN</string>
|
||||
|
@ -473,6 +480,14 @@
|
|||
<string>Fullscreen</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Open_Log_Folder">
|
||||
<property name="text">
|
||||
<string>Open Log Folder</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Opens the Citra Log folder</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Open_Maintenance_Tool">
|
||||
<property name="text">
|
||||
<string>Modify Citra Install</string>
|
||||
|
|
|
@ -116,6 +116,7 @@ struct Values {
|
|||
bool game_dir_deprecated_deepscan;
|
||||
QVector<UISettings::GameDir> game_dirs;
|
||||
QStringList recent_files;
|
||||
QString last_artic_base_addr;
|
||||
QString language;
|
||||
|
||||
QString theme;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue