mirror of https://github.com/mgba-emu/mgba.git
Qt: Add integrated configuration loader for the menu
This commit is contained in:
parent
19346dff87
commit
8751f5cc0c
|
@ -2,12 +2,76 @@
|
||||||
|
|
||||||
#include "GameController.h"
|
#include "GameController.h"
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "platform/commandline.h"
|
#include "platform/commandline.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace QGBA;
|
using namespace QGBA;
|
||||||
|
|
||||||
|
ConfigOption::ConfigOption(QObject* parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigOption::connect(std::function<void(const QVariant&)> slot) {
|
||||||
|
m_slot = slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
QAction* ConfigOption::addValue(const QString& text, const QVariant& value, QMenu* parent) {
|
||||||
|
QAction* action = new QAction(text, parent);
|
||||||
|
action->setCheckable(true);
|
||||||
|
QObject::connect(action, &QAction::triggered, [this, value]() {
|
||||||
|
emit valueChanged(value);
|
||||||
|
});
|
||||||
|
parent->addAction(action);
|
||||||
|
m_actions.append(qMakePair(action, value));
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
QAction* ConfigOption::addValue(const QString& text, const char* value, QMenu* parent) {
|
||||||
|
return addValue(text, QString(value), parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
QAction* ConfigOption::addBoolean(const QString& text, QMenu* parent) {
|
||||||
|
QAction* action = new QAction(text, parent);
|
||||||
|
action->setCheckable(true);
|
||||||
|
QObject::connect(action, &QAction::triggered, [this, action]() {
|
||||||
|
emit valueChanged(action->isChecked());
|
||||||
|
});
|
||||||
|
parent->addAction(action);
|
||||||
|
m_actions.append(qMakePair(action, true));
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigOption::setValue(bool value) {
|
||||||
|
setValue(QVariant(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigOption::setValue(int value) {
|
||||||
|
setValue(QVariant(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigOption::setValue(unsigned value) {
|
||||||
|
setValue(QVariant(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigOption::setValue(const char* value) {
|
||||||
|
setValue(QVariant(QString(value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigOption::setValue(const QVariant& value) {
|
||||||
|
QPair<QAction*, QVariant> action;
|
||||||
|
foreach(action, m_actions) {
|
||||||
|
bool signalsEnabled = action.first->blockSignals(true);
|
||||||
|
action.first->setChecked(value == action.second);
|
||||||
|
action.first->blockSignals(signalsEnabled);
|
||||||
|
}
|
||||||
|
m_slot(value);
|
||||||
|
}
|
||||||
|
|
||||||
ConfigController::ConfigController(QObject* parent)
|
ConfigController::ConfigController(QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_opts()
|
, m_opts()
|
||||||
|
@ -16,6 +80,8 @@ ConfigController::ConfigController(QObject* parent)
|
||||||
|
|
||||||
m_opts.audioSync = GameController::AUDIO_SYNC;
|
m_opts.audioSync = GameController::AUDIO_SYNC;
|
||||||
m_opts.videoSync = GameController::VIDEO_SYNC;
|
m_opts.videoSync = GameController::VIDEO_SYNC;
|
||||||
|
m_opts.fpsTarget = 60;
|
||||||
|
m_opts.audioBuffers = 768;
|
||||||
GBAConfigLoadDefaults(&m_config, &m_opts);
|
GBAConfigLoadDefaults(&m_config, &m_opts);
|
||||||
GBAConfigLoad(&m_config);
|
GBAConfigLoad(&m_config);
|
||||||
GBAConfigMap(&m_config, &m_opts);
|
GBAConfigMap(&m_config, &m_opts);
|
||||||
|
@ -32,20 +98,68 @@ bool ConfigController::parseArguments(GBAArguments* args, int argc, char* argv[]
|
||||||
return ::parseArguments(args, &m_config, argc, argv, 0);
|
return ::parseArguments(args, &m_config, argc, argv, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConfigOption* ConfigController::addOption(const char* key) {
|
||||||
|
QString optionName(key);
|
||||||
|
|
||||||
|
if (m_optionSet.contains(optionName)) {
|
||||||
|
return m_optionSet[optionName];
|
||||||
|
}
|
||||||
|
ConfigOption* newOption = new ConfigOption(this);
|
||||||
|
m_optionSet[optionName] = newOption;
|
||||||
|
connect(newOption, &ConfigOption::valueChanged, [this, key](const QVariant& value) {
|
||||||
|
setOption(key, value);
|
||||||
|
});
|
||||||
|
return newOption;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigController::updateOption(const char* key) {
|
||||||
|
if (!key) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString optionName(key);
|
||||||
|
|
||||||
|
if (!m_optionSet.contains(optionName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_optionSet[optionName]->setValue(GBAConfigGetValue(&m_config, key));
|
||||||
|
}
|
||||||
|
|
||||||
void ConfigController::setOption(const char* key, bool value) {
|
void ConfigController::setOption(const char* key, bool value) {
|
||||||
setOption(key, (int) value);
|
setOption(key, (int) value);
|
||||||
|
ConfigOption* option = m_optionSet[QString(key)];
|
||||||
|
if (option) {
|
||||||
|
option->setValue(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigController::setOption(const char* key, int value) {
|
void ConfigController::setOption(const char* key, int value) {
|
||||||
GBAConfigSetIntValue(&m_config, key, value);
|
GBAConfigSetIntValue(&m_config, key, value);
|
||||||
|
ConfigOption* option = m_optionSet[QString(key)];
|
||||||
|
if (option) {
|
||||||
|
option->setValue(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigController::setOption(const char* key, unsigned value) {
|
void ConfigController::setOption(const char* key, unsigned value) {
|
||||||
GBAConfigSetUIntValue(&m_config, key, value);
|
GBAConfigSetUIntValue(&m_config, key, value);
|
||||||
|
ConfigOption* option = m_optionSet[QString(key)];
|
||||||
|
if (option) {
|
||||||
|
option->setValue(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigController::setOption(const char* key, const char* value) {
|
void ConfigController::setOption(const char* key, const char* value) {
|
||||||
GBAConfigSetValue(&m_config, key, value);
|
GBAConfigSetValue(&m_config, key, value);
|
||||||
|
ConfigOption* option = m_optionSet[QString(key)];
|
||||||
|
if (option) {
|
||||||
|
option->setValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigController::setOption(const char* key, const QVariant& value) {
|
||||||
|
QString stringValue(value.toString());
|
||||||
|
setOption(key, stringValue.toLocal8Bit().constData());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigController::write() {
|
void ConfigController::write() {
|
||||||
|
|
|
@ -1,16 +1,50 @@
|
||||||
#ifndef QGBA_CONFIG_CONTROLLER
|
#ifndef QGBA_CONFIG_CONTROLLER
|
||||||
#define QGBA_CONFIG_CONTROLLER
|
#define QGBA_CONFIG_CONTROLLER
|
||||||
|
|
||||||
|
#include <QMap>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QScopedPointer>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "gba-config.h"
|
#include "gba-config.h"
|
||||||
#include "util/configuration.h"
|
#include "util/configuration.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class QAction;
|
||||||
|
class QMenu;
|
||||||
|
|
||||||
struct GBAArguments;
|
struct GBAArguments;
|
||||||
|
|
||||||
namespace QGBA {
|
namespace QGBA {
|
||||||
|
|
||||||
|
class ConfigOption : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ConfigOption(QObject* parent = nullptr);
|
||||||
|
|
||||||
|
void connect(std::function<void(const QVariant&)>);
|
||||||
|
|
||||||
|
QAction* addValue(const QString& text, const QVariant& value, QMenu* parent = 0);
|
||||||
|
QAction* addValue(const QString& text, const char* value, QMenu* parent = 0);
|
||||||
|
QAction* addBoolean(const QString& text, QMenu* parent = 0);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setValue(bool value);
|
||||||
|
void setValue(int value);
|
||||||
|
void setValue(unsigned value);
|
||||||
|
void setValue(const char* value);
|
||||||
|
void setValue(const QVariant& value);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void valueChanged(const QVariant& value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::function<void(const QVariant&)> m_slot;
|
||||||
|
QList<QPair<QAction*, QVariant>> m_actions;
|
||||||
|
};
|
||||||
|
|
||||||
class ConfigController : public QObject {
|
class ConfigController : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -23,17 +57,23 @@ public:
|
||||||
const GBAOptions* options() const { return &m_opts; }
|
const GBAOptions* options() const { return &m_opts; }
|
||||||
bool parseArguments(GBAArguments* args, int argc, char* argv[]);
|
bool parseArguments(GBAArguments* args, int argc, char* argv[]);
|
||||||
|
|
||||||
|
ConfigOption* addOption(const char* key);
|
||||||
|
void updateOption(const char* key);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setOption(const char* key, bool value);
|
void setOption(const char* key, bool value);
|
||||||
void setOption(const char* key, int value);
|
void setOption(const char* key, int value);
|
||||||
void setOption(const char* key, unsigned value);
|
void setOption(const char* key, unsigned value);
|
||||||
void setOption(const char* key, const char* value);
|
void setOption(const char* key, const char* value);
|
||||||
|
void setOption(const char* key, const QVariant& value);
|
||||||
|
|
||||||
void write();
|
void write();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GBAConfig m_config;
|
GBAConfig m_config;
|
||||||
GBAOptions m_opts;
|
GBAOptions m_opts;
|
||||||
|
|
||||||
|
QMap<QString, ConfigOption*> m_optionSet;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,12 @@ using namespace QGBA;
|
||||||
|
|
||||||
GBAApp::GBAApp(int& argc, char* argv[])
|
GBAApp::GBAApp(int& argc, char* argv[])
|
||||||
: QApplication(argc, argv)
|
: QApplication(argc, argv)
|
||||||
|
, m_window(&m_configController)
|
||||||
{
|
{
|
||||||
QApplication::setApplicationName(PROJECT_NAME);
|
QApplication::setApplicationName(PROJECT_NAME);
|
||||||
QApplication::setApplicationVersion(PROJECT_VERSION);
|
QApplication::setApplicationVersion(PROJECT_VERSION);
|
||||||
|
|
||||||
GBAArguments args = {};
|
GBAArguments args = {};
|
||||||
m_window.setConfig(&m_configController);
|
|
||||||
if (m_configController.parseArguments(&args, argc, argv)) {
|
if (m_configController.parseArguments(&args, argc, argv)) {
|
||||||
m_window.argumentsPassed(&args);
|
m_window.argumentsPassed(&args);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -20,8 +20,8 @@ protected:
|
||||||
bool event(QEvent*);
|
bool event(QEvent*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Window m_window;
|
|
||||||
ConfigController m_configController;
|
ConfigController m_configController;
|
||||||
|
Window m_window;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,13 @@ extern "C" {
|
||||||
|
|
||||||
using namespace QGBA;
|
using namespace QGBA;
|
||||||
|
|
||||||
Window::Window(QWidget* parent)
|
Window::Window(ConfigController* config, QWidget* parent)
|
||||||
: QMainWindow(parent)
|
: QMainWindow(parent)
|
||||||
, m_logView(new LogView())
|
, m_logView(new LogView())
|
||||||
, m_stateWindow(nullptr)
|
, m_stateWindow(nullptr)
|
||||||
, m_screenWidget(new WindowBackground())
|
, m_screenWidget(new WindowBackground())
|
||||||
, m_logo(":/res/mgba-1024.png")
|
, m_logo(":/res/mgba-1024.png")
|
||||||
|
, m_config(config)
|
||||||
#ifdef USE_FFMPEG
|
#ifdef USE_FFMPEG
|
||||||
, m_videoView(nullptr)
|
, m_videoView(nullptr)
|
||||||
#endif
|
#endif
|
||||||
|
@ -396,27 +397,16 @@ void Window::setupMenu(QMenuBar* menubar) {
|
||||||
emulationMenu->addAction(frameAdvance);
|
emulationMenu->addAction(frameAdvance);
|
||||||
|
|
||||||
QMenu* target = emulationMenu->addMenu("FPS target");
|
QMenu* target = emulationMenu->addMenu("FPS target");
|
||||||
QAction* setTarget = new QAction(tr("15"), emulationMenu);
|
ConfigOption* fpsTargetOption = m_config->addOption("fpsTarget");
|
||||||
connect(setTarget, &QAction::triggered, [this]() { emit fpsTargetChanged(15); });
|
fpsTargetOption->connect([this](const QVariant& value) { emit fpsTargetChanged(value.toInt()); });
|
||||||
target->addAction(setTarget);
|
fpsTargetOption->addValue(tr("15"), 15, target);
|
||||||
setTarget = new QAction(tr("30"), emulationMenu);
|
fpsTargetOption->addValue(tr("30"), 30, target);
|
||||||
connect(setTarget, &QAction::triggered, [this]() { emit fpsTargetChanged(30); });
|
fpsTargetOption->addValue(tr("45"), 45, target);
|
||||||
target->addAction(setTarget);
|
fpsTargetOption->addValue(tr("60"), 60, target);
|
||||||
setTarget = new QAction(tr("45"), emulationMenu);
|
fpsTargetOption->addValue(tr("90"), 90, target);
|
||||||
connect(setTarget, &QAction::triggered, [this]() { emit fpsTargetChanged(45); });
|
fpsTargetOption->addValue(tr("120"), 120, target);
|
||||||
target->addAction(setTarget);
|
fpsTargetOption->addValue(tr("240"), 240, target);
|
||||||
setTarget = new QAction(tr("60"), emulationMenu);
|
m_config->updateOption("fpsTarget");
|
||||||
connect(setTarget, &QAction::triggered, [this]() { emit fpsTargetChanged(60); });
|
|
||||||
target->addAction(setTarget);
|
|
||||||
setTarget = new QAction(tr("90"), emulationMenu);
|
|
||||||
connect(setTarget, &QAction::triggered, [this]() { emit fpsTargetChanged(90); });
|
|
||||||
target->addAction(setTarget);
|
|
||||||
setTarget = new QAction(tr("120"), emulationMenu);
|
|
||||||
connect(setTarget, &QAction::triggered, [this]() { emit fpsTargetChanged(120); });
|
|
||||||
target->addAction(setTarget);
|
|
||||||
setTarget = new QAction(tr("240"), emulationMenu);
|
|
||||||
connect(setTarget, &QAction::triggered, [this]() { emit fpsTargetChanged(240); });
|
|
||||||
target->addAction(setTarget);
|
|
||||||
|
|
||||||
emulationMenu->addSeparator();
|
emulationMenu->addSeparator();
|
||||||
|
|
||||||
|
@ -427,17 +417,15 @@ void Window::setupMenu(QMenuBar* menubar) {
|
||||||
connect(turbo, SIGNAL(triggered(bool)), m_controller, SLOT(setTurbo(bool)));
|
connect(turbo, SIGNAL(triggered(bool)), m_controller, SLOT(setTurbo(bool)));
|
||||||
emulationMenu->addAction(turbo);
|
emulationMenu->addAction(turbo);
|
||||||
|
|
||||||
QAction* videoSync = new QAction(tr("Sync to &video"), emulationMenu);
|
ConfigOption* videoSync = m_config->addOption("videoSync");
|
||||||
videoSync->setCheckable(true);
|
videoSync->addBoolean(tr("Sync to &video"), emulationMenu);
|
||||||
videoSync->setChecked(m_controller->videoSync());
|
videoSync->connect([this](const QVariant& value) { m_controller->setVideoSync(value.toBool()); });
|
||||||
connect(videoSync, SIGNAL(triggered(bool)), m_controller, SLOT(setVideoSync(bool)));
|
m_config->updateOption("videoSync");
|
||||||
emulationMenu->addAction(videoSync);
|
|
||||||
|
|
||||||
QAction* audioSync = new QAction(tr("Sync to &audio"), emulationMenu);
|
ConfigOption* audioSync = m_config->addOption("audioSync");
|
||||||
audioSync->setCheckable(true);
|
audioSync->addBoolean(tr("Sync to &audio"), emulationMenu);
|
||||||
audioSync->setChecked(m_controller->audioSync());
|
audioSync->connect([this](const QVariant& value) { m_controller->setAudioSync(value.toBool()); });
|
||||||
connect(audioSync, SIGNAL(triggered(bool)), m_controller, SLOT(setAudioSync(bool)));
|
m_config->updateOption("audioSync");
|
||||||
emulationMenu->addAction(audioSync);
|
|
||||||
|
|
||||||
QMenu* videoMenu = menubar->addMenu(tr("&Video"));
|
QMenu* videoMenu = menubar->addMenu(tr("&Video"));
|
||||||
QMenu* frameMenu = videoMenu->addMenu(tr("Frame size"));
|
QMenu* frameMenu = videoMenu->addMenu(tr("Frame size"));
|
||||||
|
@ -468,25 +456,23 @@ void Window::setupMenu(QMenuBar* menubar) {
|
||||||
frameMenu->addAction(tr("Fullscreen"), this, SLOT(toggleFullScreen()), QKeySequence("Ctrl+F"));
|
frameMenu->addAction(tr("Fullscreen"), this, SLOT(toggleFullScreen()), QKeySequence("Ctrl+F"));
|
||||||
|
|
||||||
QMenu* skipMenu = videoMenu->addMenu(tr("Frame&skip"));
|
QMenu* skipMenu = videoMenu->addMenu(tr("Frame&skip"));
|
||||||
|
ConfigOption* skip = m_config->addOption("frameskip");
|
||||||
|
skip->connect([this](const QVariant& value) { m_controller->setFrameskip(value.toInt()); });
|
||||||
for (int i = 0; i <= 10; ++i) {
|
for (int i = 0; i <= 10; ++i) {
|
||||||
QAction* setSkip = new QAction(QString::number(i), skipMenu);
|
skip->addValue(QString::number(i), i, skipMenu);
|
||||||
connect(setSkip, &QAction::triggered, [this, i]() {
|
|
||||||
m_controller->setFrameskip(i);
|
|
||||||
});
|
|
||||||
skipMenu->addAction(setSkip);
|
|
||||||
}
|
}
|
||||||
|
m_config->updateOption("frameskip");
|
||||||
|
|
||||||
QMenu* soundMenu = menubar->addMenu(tr("&Sound"));
|
QMenu* soundMenu = menubar->addMenu(tr("&Sound"));
|
||||||
QMenu* buffersMenu = soundMenu->addMenu(tr("Buffer &size"));
|
QMenu* buffersMenu = soundMenu->addMenu(tr("Buffer &size"));
|
||||||
QAction* setBuffer = new QAction(tr("512"), buffersMenu);
|
ConfigOption* buffers = m_config->addOption("audioBuffers");
|
||||||
connect(setBuffer, &QAction::triggered, [this]() { emit audioBufferSamplesChanged(512); });
|
buffers->connect([this](const QVariant& value) { emit audioBufferSamplesChanged(value.toInt()); });
|
||||||
buffersMenu->addAction(setBuffer);
|
buffers->addValue(tr("512"), 512, buffersMenu);
|
||||||
setBuffer = new QAction(tr("1024"), buffersMenu);
|
buffers->addValue(tr("768"), 768, buffersMenu);
|
||||||
connect(setBuffer, &QAction::triggered, [this]() { emit audioBufferSamplesChanged(1024); });
|
buffers->addValue(tr("1024"), 1024, buffersMenu);
|
||||||
buffersMenu->addAction(setBuffer);
|
buffers->addValue(tr("2048"), 2048, buffersMenu);
|
||||||
setBuffer = new QAction(tr("2048"), buffersMenu);
|
buffers->addValue(tr("4096"), 4096, buffersMenu);
|
||||||
connect(setBuffer, &QAction::triggered, [this]() { emit audioBufferSamplesChanged(2048); });
|
m_config->updateOption("audioBuffers");
|
||||||
buffersMenu->addAction(setBuffer);
|
|
||||||
|
|
||||||
QMenu* debuggingMenu = menubar->addMenu(tr("&Debugging"));
|
QMenu* debuggingMenu = menubar->addMenu(tr("&Debugging"));
|
||||||
QAction* viewLogs = new QAction(tr("View &logs..."), debuggingMenu);
|
QAction* viewLogs = new QAction(tr("View &logs..."), debuggingMenu);
|
||||||
|
|
|
@ -27,7 +27,7 @@ class Window : public QMainWindow {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Window(QWidget* parent = nullptr);
|
Window(ConfigController* config, QWidget* parent = nullptr);
|
||||||
virtual ~Window();
|
virtual ~Window();
|
||||||
|
|
||||||
GameController* controller() { return m_controller; }
|
GameController* controller() { return m_controller; }
|
||||||
|
|
Loading…
Reference in New Issue