Qt: Add integrated configuration loader for the menu
Jeffrey Pfau jeffrey@endrift.com
Wed, 05 Nov 2014 02:17:26 -0800
6 files changed,
189 insertions(+),
49 deletions(-)
M
src/platform/qt/ConfigController.cpp
→
src/platform/qt/ConfigController.cpp
@@ -2,12 +2,76 @@ #include "ConfigController.h"
#include "GameController.h" +#include <QAction> +#include <QMenu> + extern "C" { #include "platform/commandline.h" } 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) : QObject(parent) , m_opts()@@ -16,6 +80,8 @@ GBAConfigInit(&m_config, PORT);
m_opts.audioSync = GameController::AUDIO_SYNC; m_opts.videoSync = GameController::VIDEO_SYNC; + m_opts.fpsTarget = 60; + m_opts.audioBuffers = 768; GBAConfigLoadDefaults(&m_config, &m_opts); GBAConfigLoad(&m_config); 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); } +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) { setOption(key, (int) value); + ConfigOption* option = m_optionSet[QString(key)]; + if (option) { + option->setValue(value); + } } void ConfigController::setOption(const char* key, int 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) { 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) { 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() {
M
src/platform/qt/ConfigController.h
→
src/platform/qt/ConfigController.h
@@ -1,16 +1,50 @@
#ifndef QGBA_CONFIG_CONTROLLER #define QGBA_CONFIG_CONTROLLER +#include <QMap> #include <QObject> +#include <QScopedPointer> +#include <QVariant> extern "C" { #include "gba-config.h" #include "util/configuration.h" } +class QAction; +class QMenu; + struct GBAArguments; 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 { Q_OBJECT@@ -23,17 +57,23 @@
const GBAOptions* options() const { return &m_opts; } bool parseArguments(GBAArguments* args, int argc, char* argv[]); + ConfigOption* addOption(const char* key); + void updateOption(const char* key); + public slots: void setOption(const char* key, bool value); void setOption(const char* key, int value); void setOption(const char* key, unsigned value); void setOption(const char* key, const char* value); + void setOption(const char* key, const QVariant& value); void write(); private: GBAConfig m_config; GBAOptions m_opts; + + QMap<QString, ConfigOption*> m_optionSet; }; }
M
src/platform/qt/GBAApp.cpp
→
src/platform/qt/GBAApp.cpp
@@ -12,12 +12,12 @@ using namespace QGBA;
GBAApp::GBAApp(int& argc, char* argv[]) : QApplication(argc, argv) + , m_window(&m_configController) { QApplication::setApplicationName(PROJECT_NAME); QApplication::setApplicationVersion(PROJECT_VERSION); GBAArguments args = {}; - m_window.setConfig(&m_configController); if (m_configController.parseArguments(&args, argc, argv)) { m_window.argumentsPassed(&args); } else {
M
src/platform/qt/GBAApp.h
→
src/platform/qt/GBAApp.h
@@ -20,8 +20,8 @@ protected:
bool event(QEvent*); private: - Window m_window; ConfigController m_configController; + Window m_window; }; }
M
src/platform/qt/Window.cpp
→
src/platform/qt/Window.cpp
@@ -20,12 +20,13 @@ }
using namespace QGBA; -Window::Window(QWidget* parent) +Window::Window(ConfigController* config, QWidget* parent) : QMainWindow(parent) , m_logView(new LogView()) , m_stateWindow(nullptr) , m_screenWidget(new WindowBackground()) , m_logo(":/res/mgba-1024.png") + , m_config(config) #ifdef USE_FFMPEG , m_videoView(nullptr) #endif@@ -396,27 +397,16 @@ m_gameActions.append(frameAdvance);
emulationMenu->addAction(frameAdvance); QMenu* target = emulationMenu->addMenu("FPS target"); - QAction* setTarget = new QAction(tr("15"), emulationMenu); - connect(setTarget, &QAction::triggered, [this]() { emit fpsTargetChanged(15); }); - target->addAction(setTarget); - setTarget = new QAction(tr("30"), emulationMenu); - connect(setTarget, &QAction::triggered, [this]() { emit fpsTargetChanged(30); }); - target->addAction(setTarget); - setTarget = new QAction(tr("45"), emulationMenu); - connect(setTarget, &QAction::triggered, [this]() { emit fpsTargetChanged(45); }); - target->addAction(setTarget); - setTarget = new QAction(tr("60"), emulationMenu); - 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); + ConfigOption* fpsTargetOption = m_config->addOption("fpsTarget"); + fpsTargetOption->connect([this](const QVariant& value) { emit fpsTargetChanged(value.toInt()); }); + fpsTargetOption->addValue(tr("15"), 15, target); + fpsTargetOption->addValue(tr("30"), 30, target); + fpsTargetOption->addValue(tr("45"), 45, target); + fpsTargetOption->addValue(tr("60"), 60, target); + fpsTargetOption->addValue(tr("90"), 90, target); + fpsTargetOption->addValue(tr("120"), 120, target); + fpsTargetOption->addValue(tr("240"), 240, target); + m_config->updateOption("fpsTarget"); emulationMenu->addSeparator();@@ -427,17 +417,15 @@ turbo->setShortcut(tr("Shift+Tab"));
connect(turbo, SIGNAL(triggered(bool)), m_controller, SLOT(setTurbo(bool))); emulationMenu->addAction(turbo); - QAction* videoSync = new QAction(tr("Sync to &video"), emulationMenu); - videoSync->setCheckable(true); - videoSync->setChecked(m_controller->videoSync()); - connect(videoSync, SIGNAL(triggered(bool)), m_controller, SLOT(setVideoSync(bool))); - emulationMenu->addAction(videoSync); + ConfigOption* videoSync = m_config->addOption("videoSync"); + videoSync->addBoolean(tr("Sync to &video"), emulationMenu); + videoSync->connect([this](const QVariant& value) { m_controller->setVideoSync(value.toBool()); }); + m_config->updateOption("videoSync"); - QAction* audioSync = new QAction(tr("Sync to &audio"), emulationMenu); - audioSync->setCheckable(true); - audioSync->setChecked(m_controller->audioSync()); - connect(audioSync, SIGNAL(triggered(bool)), m_controller, SLOT(setAudioSync(bool))); - emulationMenu->addAction(audioSync); + ConfigOption* audioSync = m_config->addOption("audioSync"); + audioSync->addBoolean(tr("Sync to &audio"), emulationMenu); + audioSync->connect([this](const QVariant& value) { m_controller->setAudioSync(value.toBool()); }); + m_config->updateOption("audioSync"); QMenu* videoMenu = menubar->addMenu(tr("&Video")); QMenu* frameMenu = videoMenu->addMenu(tr("Frame size"));@@ -468,25 +456,23 @@ frameMenu->addAction(setSize);
frameMenu->addAction(tr("Fullscreen"), this, SLOT(toggleFullScreen()), QKeySequence("Ctrl+F")); 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) { - QAction* setSkip = new QAction(QString::number(i), skipMenu); - connect(setSkip, &QAction::triggered, [this, i]() { - m_controller->setFrameskip(i); - }); - skipMenu->addAction(setSkip); + skip->addValue(QString::number(i), i, skipMenu); } + m_config->updateOption("frameskip"); QMenu* soundMenu = menubar->addMenu(tr("&Sound")); QMenu* buffersMenu = soundMenu->addMenu(tr("Buffer &size")); - QAction* setBuffer = new QAction(tr("512"), buffersMenu); - connect(setBuffer, &QAction::triggered, [this]() { emit audioBufferSamplesChanged(512); }); - buffersMenu->addAction(setBuffer); - setBuffer = new QAction(tr("1024"), buffersMenu); - connect(setBuffer, &QAction::triggered, [this]() { emit audioBufferSamplesChanged(1024); }); - buffersMenu->addAction(setBuffer); - setBuffer = new QAction(tr("2048"), buffersMenu); - connect(setBuffer, &QAction::triggered, [this]() { emit audioBufferSamplesChanged(2048); }); - buffersMenu->addAction(setBuffer); + ConfigOption* buffers = m_config->addOption("audioBuffers"); + buffers->connect([this](const QVariant& value) { emit audioBufferSamplesChanged(value.toInt()); }); + buffers->addValue(tr("512"), 512, buffersMenu); + buffers->addValue(tr("768"), 768, buffersMenu); + buffers->addValue(tr("1024"), 1024, buffersMenu); + buffers->addValue(tr("2048"), 2048, buffersMenu); + buffers->addValue(tr("4096"), 4096, buffersMenu); + m_config->updateOption("audioBuffers"); QMenu* debuggingMenu = menubar->addMenu(tr("&Debugging")); QAction* viewLogs = new QAction(tr("View &logs..."), debuggingMenu);
M
src/platform/qt/Window.h
→
src/platform/qt/Window.h
@@ -27,7 +27,7 @@ class Window : public QMainWindow {
Q_OBJECT public: - Window(QWidget* parent = nullptr); + Window(ConfigController* config, QWidget* parent = nullptr); virtual ~Window(); GameController* controller() { return m_controller; }