[Config/UI] Add simple emulator settings dialog

Also rework a bunch of cvar handling
This commit is contained in:
Herman S.
2025-11-04 20:15:12 +09:00
parent 6b4aaabf04
commit dc2985f819
8 changed files with 836 additions and 51 deletions
+8 -5
View File
@@ -40,6 +40,7 @@
#include "xenia/ui/postprocessing_dialog_qt.h"
#include "xenia/ui/profile_dialog_qt.h"
#include "xenia/ui/qt_util.h"
#include "xenia/ui/simple_config_dialog_qt.h"
#include "xenia/ui/xmp_dialog_qt.h"
#if XE_PLATFORM_WIN32
@@ -1526,13 +1527,15 @@ void EmulatorWindow::ToggleProfilesConfigDialog() {
}
void EmulatorWindow::ToggleConfigDialog() {
if (!config_dialog_qt_) {
config_dialog_qt_ = new ConfigDialogQt(nullptr, this);
if (!simple_config_dialog_qt_) {
simple_config_dialog_qt_ = new SimpleConfigDialogQt(nullptr, this);
} else {
simple_config_dialog_qt_->ReloadConfigValues();
}
config_dialog_qt_->show();
config_dialog_qt_->raise();
config_dialog_qt_->activateWindow();
simple_config_dialog_qt_->show();
simple_config_dialog_qt_->raise();
simple_config_dialog_qt_->activateWindow();
}
void EmulatorWindow::OpenConfigDialog(const std::string& category) {
+1
View File
@@ -277,6 +277,7 @@ class EmulatorWindow {
QPointer<class PostProcessingDialogQt> postprocessing_dialog_qt_;
QPointer<class GameListDialogQt> game_list_dialog_qt_;
QPointer<class ProfileDialogQt> profile_dialog_qt_;
QPointer<class SimpleConfigDialogQt> simple_config_dialog_qt_;
QPointer<class ConfigDialogQt> config_dialog_qt_;
QPointer<class ContextMenuWidgetQt> context_menu_widget_qt_;
QPointer<class XmpDialogQt> xmp_dialog_qt_;
+19 -36
View File
@@ -64,23 +64,28 @@
#endif // XE_PLATFORM_WIN32
#if XE_PLATFORM_WIN32
#define APU_OPTIONS "[any, nop, sdl, xaudio2]"
#define GPU_OPTIONS "[any, d3d12, vulkan, null]"
#define HID_OPTIONS "[any, nop, sdl, winkey, xinput]"
#define APU_OPTIONS "[xaudio2, sdl, nop]"
#define GPU_OPTIONS "[d3d12, vulkan, null]"
#define HID_OPTIONS "[sdl, winkey, xinput, nop]"
DEFINE_string(apu, "xaudio2", "Audio system. Use: " APU_OPTIONS, "APU");
DEFINE_string(gpu, "d3d12", "Graphics system. Use: " GPU_OPTIONS, "GPU");
DEFINE_string(hid, "sdl", "Input system. Use: " HID_OPTIONS, "HID");
#elif XE_PLATFORM_LINUX
#define APU_OPTIONS "[any, alsa, nop, sdl]"
#define GPU_OPTIONS "[any, vulkan, null]"
#define HID_OPTIONS "[any, nop, sdl]"
#define APU_OPTIONS "[alsa, sdl, nop]"
#define GPU_OPTIONS "[vulkan, null]"
#define HID_OPTIONS "[sdl, nop]"
DEFINE_string(apu, "alsa", "Audio system. Use: " APU_OPTIONS, "APU");
DEFINE_string(gpu, "vulkan", "Graphics system. Use: " GPU_OPTIONS, "GPU");
DEFINE_string(hid, "sdl", "Input system. Use: " HID_OPTIONS, "HID");
#else
#define APU_OPTIONS "[any, nop, sdl]"
#define GPU_OPTIONS "[any, vulkan, null]"
#define HID_OPTIONS "[any, nop, sdl]"
#define APU_OPTIONS "[sdl, nop]"
#define GPU_OPTIONS "[vulkan, null]"
#define HID_OPTIONS "[sdl, nop]"
DEFINE_string(apu, "sdl", "Audio system. Use: " APU_OPTIONS, "APU");
DEFINE_string(gpu, "vulkan", "Graphics system. Use: " GPU_OPTIONS, "GPU");
DEFINE_string(hid, "sdl", "Input system. Use: " HID_OPTIONS, "HID");
#endif
DEFINE_string(apu, "any", "Audio system. Use: " APU_OPTIONS, "APU");
DEFINE_string(gpu, "any", "Graphics system. Use: " GPU_OPTIONS, "GPU");
DEFINE_string(hid, "any", "Input system. Use: " HID_OPTIONS, "HID");
DEFINE_path(
storage_root, "",
"Root path for persistent internal data storage (config, etc.), or empty "
@@ -247,7 +252,7 @@ class EmulatorApp final : public xe::ui::WindowedApp {
}
std::unique_ptr<T> Create(const std::string_view name, Args... args) {
if (!name.empty() && name != "any") {
if (!name.empty()) {
auto it = std::find_if(
creators_.cbegin(), creators_.cend(),
[&name](const auto& f) { return name.compare(f.name) == 0; });
@@ -270,27 +275,6 @@ class EmulatorApp final : public xe::ui::WindowedApp {
Args... args) {
std::vector<std::unique_ptr<T>> instances;
// "Any" path
if (name.empty() || name == "any") {
for (const auto& creator : creators_) {
if (!creator.is_available()) {
continue;
}
// Skip xinput for "any" and use SDL
if (creator.name.compare("xinput") == 0) {
continue;
}
auto instance = creator.instantiate(std::forward<Args>(args)...);
if (instance) {
instances.emplace_back(std::move(instance));
}
}
return instances;
}
// "Specified" path. Winkey is always added on windows.
if (name != "winkey") {
auto it = std::find_if(
creators_.cbegin(), creators_.cend(),
@@ -304,7 +288,6 @@ class EmulatorApp final : public xe::ui::WindowedApp {
}
}
// Always add winkey for passthrough.
auto it = std::find_if(
creators_.cbegin(), creators_.cend(),
[&name](const auto& f) { return f.name.compare("winkey") == 0; });
+3 -1
View File
@@ -525,7 +525,9 @@ void ConfigDialogQt::ResetToDefaults() {
XELOGI("Resetting config to defaults (UI only)");
for (auto& var_info : config_vars_) {
// Get the default value
if (var_info.name.find("logged_profile_slot_") != std::string::npos) {
continue;
}
var_info.var->ResetConfigValueToDefault();
std::string default_value;
+22 -9
View File
@@ -36,6 +36,19 @@ inline const std::vector<CvarAlias>& GetCvarAliases() {
{"render_target_path_d3d12", "rov", "render_target_path", "accuracy"},
{"render_target_path_vulkan", "fbo", "render_target_path", "performance"},
{"render_target_path_vulkan", "fsi", "render_target_path", "accuracy"},
#if XE_PLATFORM_WIN32
{"gpu", "any", "gpu", "d3d12"},
{"apu", "any", "apu", "xaudio2"},
{"hid", "any", "hid", "sdl"},
#elif XE_PLATFORM_LINUX
{"gpu", "any", "gpu", "vulkan"},
{"apu", "any", "apu", "alsa"},
{"hid", "any", "hid", "sdl"},
#else
{"gpu", "any", "gpu", "vulkan"},
{"apu", "any", "apu", "sdl"},
{"hid", "any", "hid", "sdl"},
#endif
};
return aliases;
}
@@ -45,17 +58,17 @@ inline const std::map<std::string, std::vector<std::string>>&
GetKnownEnumOptions() {
static const std::map<std::string, std::vector<std::string>> options = {
#if XE_PLATFORM_WIN32
{"gpu", {"any", "d3d12", "vulkan", "null"}},
{"apu", {"any", "nop", "sdl", "xaudio2"}},
{"hid", {"any", "nop", "sdl", "winkey", "xinput"}},
{"gpu", {"d3d12", "vulkan", "null"}},
{"apu", {"xaudio2", "sdl", "nop"}},
{"hid", {"sdl", "winkey", "xinput", "nop"}},
#elif XE_PLATFORM_LINUX
{"gpu", {"any", "vulkan", "null"}},
{"apu", {"any", "alsa", "nop", "sdl"}},
{"hid", {"any", "nop", "sdl"}},
{"gpu", {"vulkan", "null"}},
{"apu", {"alsa", "sdl", "nop"}},
{"hid", {"sdl", "nop"}},
#else
{"gpu", {"any", "vulkan", "null"}},
{"apu", {"any", "nop", "sdl"}},
{"hid", {"any", "nop", "sdl"}},
{"gpu", {"vulkan", "null"}},
{"apu", {"nop", "sdl"}},
{"hid", {"sdl", "nop"}},
#endif
{"d3d12_readback_resolve",
{"kCopy", "kComputeLuminance", "kComputeRGBA16"}},
+124
View File
@@ -0,0 +1,124 @@
/****************************************************************************
** Meta object code from reading C++ file 'simple_config_dialog_qt.h'
**
** Created by: The Qt Meta Object Compiler version 69 (Qt 6.9.2)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
#include <QtCore/qmetatype.h>
#include "simple_config_dialog_qt.h"
#include <QtCore/qtmochelpers.h>
#include <memory>
#include <QtCore/qxptype_traits.h>
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'simple_config_dialog_qt.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 69
#error "This file was generated using the moc from 6.9.2. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif
#ifndef Q_CONSTINIT
#define Q_CONSTINIT
#endif
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
QT_WARNING_DISABLE_GCC("-Wuseless-cast")
namespace {
struct qt_meta_tag_ZN2xe3app20SimpleConfigDialogQtE_t {};
} // unnamed namespace
template <>
constexpr inline auto xe::app::SimpleConfigDialogQt::qt_create_metaobjectdata<
qt_meta_tag_ZN2xe3app20SimpleConfigDialogQtE_t>() {
namespace QMC = QtMocConstants;
QtMocHelpers::StringRefStorage qt_stringData{"xe::app::SimpleConfigDialogQt",
"OnSaveClicked",
"",
"OnDiscardClicked",
"OnAdvancedClicked",
"OnValueChanged"};
QtMocHelpers::UintData qt_methods{
// Slot 'OnSaveClicked'
QtMocHelpers::SlotData<void()>(1, 2, QMC::AccessPrivate, QMetaType::Void),
// Slot 'OnDiscardClicked'
QtMocHelpers::SlotData<void()>(3, 2, QMC::AccessPrivate, QMetaType::Void),
// Slot 'OnAdvancedClicked'
QtMocHelpers::SlotData<void()>(4, 2, QMC::AccessPrivate, QMetaType::Void),
// Slot 'OnValueChanged'
QtMocHelpers::SlotData<void()>(5, 2, QMC::AccessPrivate, QMetaType::Void),
};
QtMocHelpers::UintData qt_properties{};
QtMocHelpers::UintData qt_enums{};
return QtMocHelpers::metaObjectData<
SimpleConfigDialogQt, qt_meta_tag_ZN2xe3app20SimpleConfigDialogQtE_t>(
QMC::MetaObjectFlag{}, qt_stringData, qt_methods, qt_properties,
qt_enums);
}
Q_CONSTINIT const QMetaObject xe::app::SimpleConfigDialogQt::staticMetaObject = { {
QMetaObject::SuperData::link<QDialog::staticMetaObject>(),
qt_staticMetaObjectStaticContent<qt_meta_tag_ZN2xe3app20SimpleConfigDialogQtE_t>.stringdata,
qt_staticMetaObjectStaticContent<qt_meta_tag_ZN2xe3app20SimpleConfigDialogQtE_t>.data,
qt_static_metacall,
nullptr,
qt_staticMetaObjectRelocatingContent<qt_meta_tag_ZN2xe3app20SimpleConfigDialogQtE_t>.metaTypes,
nullptr
} };
void xe::app::SimpleConfigDialogQt::qt_static_metacall(QObject* _o,
QMetaObject::Call _c,
int _id, void** _a) {
auto* _t = static_cast<SimpleConfigDialogQt*>(_o);
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0:
_t->OnSaveClicked();
break;
case 1:
_t->OnDiscardClicked();
break;
case 2:
_t->OnAdvancedClicked();
break;
case 3:
_t->OnValueChanged();
break;
default:;
}
}
(void)_a;
}
const QMetaObject* xe::app::SimpleConfigDialogQt::metaObject() const {
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject()
: &staticMetaObject;
}
void* xe::app::SimpleConfigDialogQt::qt_metacast(const char* _clname) {
if (!_clname) return nullptr;
if (!strcmp(_clname, qt_staticMetaObjectStaticContent<qt_meta_tag_ZN2xe3app20SimpleConfigDialogQtE_t>.strings))
return static_cast<void*>(this);
return QDialog::qt_metacast(_clname);
}
int xe::app::SimpleConfigDialogQt::qt_metacall(QMetaObject::Call _c, int _id,
void** _a) {
_id = QDialog::qt_metacall(_c, _id, _a);
if (_id < 0) return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
if (_id < 4) qt_static_metacall(this, _c, _id, _a);
_id -= 4;
}
if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 4) *reinterpret_cast<QMetaType*>(_a[0]) = QMetaType();
_id -= 4;
}
return _id;
}
QT_WARNING_POP
File diff suppressed because it is too large Load Diff
+70
View File
@@ -0,0 +1,70 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2025 Xenia Canary. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_SIMPLE_CONFIG_DIALOG_QT_H_
#define XENIA_UI_SIMPLE_CONFIG_DIALOG_QT_H_
#include <QCheckBox>
#include <QComboBox>
#include <QDialog>
#include <QLabel>
#include <QSpinBox>
#include <QVBoxLayout>
#include <map>
#include <string>
#include "xenia/base/cvar.h"
namespace xe {
namespace app {
class EmulatorWindow;
class SimpleConfigDialogQt : public QDialog {
Q_OBJECT
public:
SimpleConfigDialogQt(QWidget* parent, EmulatorWindow* emulator_window);
~SimpleConfigDialogQt() override;
void ReloadConfigValues();
private slots:
void OnSaveClicked();
void OnDiscardClicked();
void OnAdvancedClicked();
void OnResetClicked();
void OnValueChanged();
private:
struct ConfigOption {
std::string cvar_name;
std::string current_value;
std::string pending_value;
QWidget* editor_widget = nullptr;
QLabel* label_widget = nullptr;
};
void LoadConfigValues();
void SaveConfigChanges();
void SetupUI();
void UpdatePendingValueFromEditor(ConfigOption* option);
void UpdateLabelModifiedState(ConfigOption* option);
std::string GetEditorValue(QWidget* editor, const std::string& cvar_name);
EmulatorWindow* emulator_window_;
std::map<std::string, ConfigOption> options_;
bool has_unsaved_changes_ = false;
};
} // namespace app
} // namespace xe
#endif // XENIA_UI_SIMPLE_CONFIG_DIALOG_QT_H_