Qt: Customizable paths for save games, save states, screenshots and patches

This commit is contained in:
Jeffrey Pfau 2016-01-15 14:29:19 -08:00
parent 89d53868da
commit a38beac307
16 changed files with 434 additions and 18 deletions

View File

@ -17,6 +17,7 @@ Features:
- Implemented cycle counting for sprite rendering
- Cleaner, unified settings window
- Added a setting for pausing when the emulator is not in focus
- Customizable paths for save games, save states, screenshots and patches
Bugfixes:
- Util: Fix PowerPC PNG read/write pixel order
- VFS: Fix VFileReadline and remove _vfdReadline

View File

@ -347,6 +347,11 @@ void GBAConfigMap(const struct GBAConfig* config, struct GBAOptions* opts) {
_lookupIntValue(config, "width", &opts->width);
_lookupIntValue(config, "height", &opts->height);
_lookupCharValue(config, "savegamePath", &opts->savegamePath);
_lookupCharValue(config, "savestatePath", &opts->savestatePath);
_lookupCharValue(config, "screenshotPath", &opts->screenshotPath);
_lookupCharValue(config, "patchPath", &opts->patchPath);
char* idleOptimization = 0;
if (_lookupCharValue(config, "idleOptimization", &idleOptimization)) {
if (strcasecmp(idleOptimization, "ignore") == 0) {
@ -409,6 +414,14 @@ struct Configuration* GBAConfigGetOverrides(struct GBAConfig* config) {
void GBAConfigFreeOpts(struct GBAOptions* opts) {
free(opts->bios);
free(opts->shader);
free(opts->savegamePath);
free(opts->savestatePath);
free(opts->screenshotPath);
free(opts->patchPath);
opts->bios = 0;
opts->shader = 0;
opts->savegamePath = 0;
opts->savestatePath = 0;
opts->screenshotPath = 0;
opts->patchPath = 0;
}

View File

@ -40,6 +40,11 @@ struct GBAOptions {
bool suspendScreensaver;
char* shader;
char* savegamePath;
char* savestatePath;
char* screenshotPath;
char* patchPath;
int volume;
bool mute;

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "directories.h"
#include "gba/context/config.h"
#include "util/vfs.h"
void GBADirectorySetInit(struct GBADirectorySet* dirs) {
@ -99,3 +100,33 @@ struct VFile* GBADirectorySetOpenPath(struct GBADirectorySet* dirs, const char*
}
return file;
}
void GBADirectorySetMapOptions(struct GBADirectorySet* dirs, const struct GBAOptions* opts) {
if (opts->savegamePath) {
if (dirs->save && dirs->save != dirs->base) {
dirs->save->close(dirs->save);
}
dirs->save = VDirOpen(opts->savegamePath);
}
if (opts->savestatePath) {
if (dirs->state && dirs->state != dirs->base) {
dirs->state->close(dirs->state);
}
dirs->state = VDirOpen(opts->savestatePath);
}
if (opts->screenshotPath) {
if (dirs->screenshot && dirs->screenshot != dirs->base) {
dirs->screenshot->close(dirs->screenshot);
}
dirs->screenshot = VDirOpen(opts->screenshotPath);
}
if (opts->patchPath) {
if (dirs->patch && dirs->patch != dirs->base) {
dirs->patch->close(dirs->patch);
}
dirs->patch = VDirOpen(opts->patchPath);
}
}

View File

@ -27,4 +27,7 @@ void GBADirectorySetDetachBase(struct GBADirectorySet* dirs);
struct VFile* GBADirectorySetOpenPath(struct GBADirectorySet* dirs, const char* path, bool (*filter)(struct VFile*));
struct GBAOptions;
void GBADirectorySetMapOptions(struct GBADirectorySet* dirs, const struct GBAOptions* opts);
#endif

View File

@ -401,6 +401,8 @@ void GBAMapOptionsToContext(const struct GBAOptions* opts, struct GBAThread* thr
}
threadContext->idleOptimization = opts->idleOptimization;
GBADirectorySetMapOptions(&threadContext->dirs, opts);
}
void GBAMapArgumentsToContext(const struct GBAArguments* args, struct GBAThread* threadContext) {
@ -441,7 +443,6 @@ bool GBAThreadStart(struct GBAThread* threadContext) {
return false;
}
GBADirectorySetInit(&threadContext->dirs);
_reloadDirectories(threadContext);
MutexInit(&threadContext->stateMutex);
@ -571,8 +572,6 @@ void GBAThreadJoin(struct GBAThread* threadContext) {
threadContext->patch->close(threadContext->patch);
threadContext->patch = 0;
}
GBADirectorySetDeinit(&threadContext->dirs);
}
bool GBAThreadIsActive(struct GBAThread* threadContext) {

View File

@ -128,6 +128,7 @@ ConfigController::~ConfigController() {
bool ConfigController::parseArguments(GBAArguments* args, int argc, char* argv[], SubParser* subparser) {
if (::parseArguments(args, &m_config, argc, argv, subparser)) {
GBAConfigFreeOpts(&m_opts);
GBAConfigMap(&m_config, &m_opts);
return true;
}
@ -262,6 +263,9 @@ void ConfigController::setMRU(const QList<QString>& mru) {
void ConfigController::write() {
GBAConfigSave(&m_config);
m_settings->sync();
GBAConfigFreeOpts(&m_opts);
GBAConfigMap(&m_config, &m_opts);
}
void ConfigController::makePortable() {

View File

@ -162,6 +162,16 @@ QString GBAApp::getSaveFileName(QWidget* owner, const QString& title, const QStr
return filename;
}
QString GBAApp::getOpenDirectoryName(QWidget* owner, const QString& title) {
interruptAll();
QString filename = QFileDialog::getExistingDirectory(owner, title, m_configController.getQtOption("lastDirectory").toString());
continueAll();
if (!filename.isEmpty()) {
m_configController.setQtOption("lastDirectory", QFileInfo(filename).dir().path());
}
return filename;
}
QFileDialog* GBAApp::getOpenFileDialog(QWidget* owner, const QString& title, const QString& filter) {
FileDialog* dialog = new FileDialog(this, owner, title, filter);
dialog->setAcceptMode(QFileDialog::AcceptOpen);

View File

@ -36,6 +36,7 @@ public:
QString getOpenFileName(QWidget* owner, const QString& title, const QString& filter = QString());
QString getSaveFileName(QWidget* owner, const QString& title, const QString& filter = QString());
QString getOpenDirectoryName(QWidget* owner, const QString& title);
QFileDialog* getOpenFileDialog(QWidget* owner, const QString& title, const QString& filter = QString());
QFileDialog* getSaveFileDialog(QWidget* owner, const QString& title, const QString& filter = QString());

View File

@ -19,6 +19,7 @@
extern "C" {
#include "gba/audio.h"
#include "gba/context/config.h"
#include "gba/context/directories.h"
#include "gba/gba.h"
#include "gba/serialize.h"
#include "gba/sharkport.h"
@ -216,6 +217,7 @@ GameController::~GameController() {
clearMultiplayerController();
closeGame();
GBACheatDeviceDestroy(&m_cheatDevice);
GBADirectorySetDeinit(&m_threadContext.dirs);
delete m_renderer;
delete[] m_drawContext;
delete[] m_frontBuffer;
@ -255,6 +257,7 @@ void GameController::setOptions(const GBAOptions* opts) {
setMute(opts->mute);
threadInterrupt();
GBADirectorySetMapOptions(&m_threadContext.dirs, opts);
m_threadContext.idleOptimization = opts->idleOptimization;
threadContinue();
}

View File

@ -40,6 +40,74 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC
loadSetting("allowOpposingDirections", m_ui.allowOpposingDirections);
loadSetting("suspendScreensaver", m_ui.suspendScreensaver);
loadSetting("pauseOnFocusLost", m_ui.pauseOnFocusLost);
loadSetting("savegamePath", m_ui.savegamePath);
loadSetting("savestatePath", m_ui.savestatePath);
loadSetting("screenshotPath", m_ui.screenshotPath);
loadSetting("patchPath", m_ui.patchPath);
if (m_ui.savegamePath->text().isEmpty()) {
m_ui.savegameSameDir->setChecked(true);
}
connect(m_ui.savegameSameDir, &QAbstractButton::toggled, [this] (bool e) {
if (e) {
m_ui.savegamePath->clear();
}
});
connect(m_ui.savegameBrowse, &QAbstractButton::pressed, [this] () {
QString path = GBAApp::app()->getOpenDirectoryName(this, "Select directory");
if (!path.isNull()) {
m_ui.savegameSameDir->setChecked(false);
m_ui.savegamePath->setText(path);
}
});
if (m_ui.savestatePath->text().isEmpty()) {
m_ui.savestateSameDir->setChecked(true);
}
connect(m_ui.savestateSameDir, &QAbstractButton::toggled, [this] (bool e) {
if (e) {
m_ui.savestatePath->clear();
}
});
connect(m_ui.savestateBrowse, &QAbstractButton::pressed, [this] () {
QString path = GBAApp::app()->getOpenDirectoryName(this, "Select directory");
if (!path.isNull()) {
m_ui.savestateSameDir->setChecked(false);
m_ui.savestatePath->setText(path);
}
});
if (m_ui.screenshotPath->text().isEmpty()) {
m_ui.screenshotSameDir->setChecked(true);
}
connect(m_ui.screenshotSameDir, &QAbstractButton::toggled, [this] (bool e) {
if (e) {
m_ui.screenshotPath->clear();
}
});
connect(m_ui.screenshotBrowse, &QAbstractButton::pressed, [this] () {
QString path = GBAApp::app()->getOpenDirectoryName(this, "Select directory");
if (!path.isNull()) {
m_ui.screenshotSameDir->setChecked(false);
m_ui.screenshotPath->setText(path);
}
});
if (m_ui.patchPath->text().isEmpty()) {
m_ui.patchSameDir->setChecked(true);
}
connect(m_ui.patchSameDir, &QAbstractButton::toggled, [this] (bool e) {
if (e) {
m_ui.patchPath->clear();
}
});
connect(m_ui.patchBrowse, &QAbstractButton::pressed, [this] () {
QString path = GBAApp::app()->getOpenDirectoryName(this, "Select directory");
if (!path.isNull()) {
m_ui.patchSameDir->setChecked(false);
m_ui.patchPath->setText(path);
}
});
double fastForwardRatio = loadSetting("fastForwardRatio").toDouble();
if (fastForwardRatio <= 0) {
@ -147,6 +215,10 @@ void SettingsView::updateConfig() {
saveSetting("allowOpposingDirections", m_ui.allowOpposingDirections);
saveSetting("suspendScreensaver", m_ui.suspendScreensaver);
saveSetting("pauseOnFocusLost", m_ui.pauseOnFocusLost);
saveSetting("savegamePath", m_ui.savegamePath);
saveSetting("savestatePath", m_ui.savestatePath);
saveSetting("screenshotPath", m_ui.screenshotPath);
saveSetting("patchPath", m_ui.patchPath);
if (m_ui.fastForwardUnbounded->isChecked()) {
saveSetting("fastForwardRatio", "-1");
@ -182,6 +254,7 @@ void SettingsView::updateConfig() {
m_controller->write();
emit pathsChanged();
emit biosLoaded(m_ui.bios->text());
}

View File

@ -26,6 +26,7 @@ signals:
void biosLoaded(const QString&);
void audioDriverChanged();
void displayDriverChanged();
void pathsChanged();
private slots:
void selectBios();

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>661</width>
<height>459</height>
<width>568</width>
<height>451</height>
</rect>
</property>
<property name="sizePolicy">
@ -25,6 +25,9 @@
</property>
<item row="1" column="1">
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="stackedWidgetPage1">
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
@ -553,6 +556,198 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="page">
<layout class="QFormLayout" name="formLayout_3">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::FieldsStayAtSizeHint</enum>
</property>
<item row="1" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Save games</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="savegamePath">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>170</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="savegameBrowse">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="savegameSameDir">
<property name="text">
<string>Same directory as the ROM</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="Line" name="line_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Save states</string>
</property>
</widget>
</item>
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLineEdit" name="savestatePath">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>170</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="savestateBrowse">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="savestateSameDir">
<property name="text">
<string>Same directory as the ROM</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="Line" name="line_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_23">
<property name="text">
<string>Screenshots</string>
</property>
</widget>
</item>
<item row="7" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QLineEdit" name="screenshotPath">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>170</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="screenshotBrowse">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="8" column="1">
<widget class="QCheckBox" name="screenshotSameDir">
<property name="text">
<string>Same directory as the ROM</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="2">
<widget class="Line" name="line_15">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_47">
<property name="text">
<string>Patches</string>
</property>
</widget>
</item>
<item row="10" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_26">
<item>
<widget class="QLineEdit" name="patchPath">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>170</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="patchBrowse">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="11" column="1">
<widget class="QCheckBox" name="patchSameDir">
<property name="text">
<string>Same directory as the ROM</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item row="1" column="0">
@ -576,7 +771,12 @@
</item>
<item>
<property name="text">
<string>Running</string>
<string>Emulation</string>
</property>
</item>
<item>
<property name="text">
<string>Paths</string>
</property>
</item>
</widget>
@ -640,5 +840,69 @@
</hint>
</hints>
</connection>
<connection>
<sender>savegameSameDir</sender>
<signal>toggled(bool)</signal>
<receiver>savegamePath</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>392</x>
<y>82</y>
</hint>
<hint type="destinationlabel">
<x>366</x>
<y>48</y>
</hint>
</hints>
</connection>
<connection>
<sender>savestateSameDir</sender>
<signal>toggled(bool)</signal>
<receiver>savestatePath</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>392</x>
<y>161</y>
</hint>
<hint type="destinationlabel">
<x>366</x>
<y>127</y>
</hint>
</hints>
</connection>
<connection>
<sender>screenshotSameDir</sender>
<signal>toggled(bool)</signal>
<receiver>screenshotPath</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>392</x>
<y>240</y>
</hint>
<hint type="destinationlabel">
<x>366</x>
<y>206</y>
</hint>
</hints>
</connection>
<connection>
<sender>patchSameDir</sender>
<signal>toggled(bool)</signal>
<receiver>patchPath</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>345</x>
<y>319</y>
</hint>
<hint type="destinationlabel">
<x>340</x>
<y>285</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -198,16 +198,7 @@ void Window::setConfig(ConfigController* config) {
void Window::loadConfig() {
const GBAOptions* opts = m_config->options();
m_log.setLevels(opts->logLevel);
m_controller->setOptions(opts);
m_display->lockAspectRatio(opts->lockAspectRatio);
m_display->filter(opts->resampleVideo);
if (opts->bios) {
m_controller->loadBIOS(opts->bios);
}
reloadConfig();
// TODO: Move these to ConfigController
if (opts->fpsTarget) {
@ -239,14 +230,28 @@ void Window::loadConfig() {
}
}
m_inputController.setScreensaverSuspendable(opts->suspendScreensaver);
m_mruFiles = m_config->getMRU();
updateMRU();
m_inputController.setConfiguration(m_config);
}
void Window::reloadConfig() {
const GBAOptions* opts = m_config->options();
m_log.setLevels(opts->logLevel);
m_controller->setOptions(opts);
m_display->lockAspectRatio(opts->lockAspectRatio);
m_display->filter(opts->resampleVideo);
if (opts->bios) {
m_controller->loadBIOS(opts->bios);
}
m_inputController.setScreensaverSuspendable(opts->suspendScreensaver);
}
void Window::saveConfig() {
m_inputController.saveConfiguration();
m_config->write();
@ -350,6 +355,7 @@ void Window::openSettingsWindow() {
connect(settingsWindow, SIGNAL(biosLoaded(const QString&)), m_controller, SLOT(loadBIOS(const QString&)));
connect(settingsWindow, SIGNAL(audioDriverChanged()), m_controller, SLOT(reloadAudioDriver()));
connect(settingsWindow, SIGNAL(displayDriverChanged()), this, SLOT(mustRestart()));
connect(settingsWindow, SIGNAL(pathsChanged()), this, SLOT(reloadConfig()));
openView(settingsWindow);
}

View File

@ -66,6 +66,7 @@ public slots:
void exitFullScreen();
void toggleFullScreen();
void loadConfig();
void reloadConfig();
void saveConfig();
void replaceROM();

View File

@ -164,6 +164,7 @@ int main(int argc, char** argv) {
GBAConfigFreeOpts(&opts);
GBAConfigDeinit(&config);
free(context.debugger);
GBADirectorySetDeinit(&context.dirs);
GBASDLDetachPlayer(&renderer.events, &renderer.player);
GBAInputMapDeinit(&inputMap);