all repos — mgba @ a38beac307b7b42dbc5ad5806a92b91396bea555

mGBA Game Boy Advance Emulator

Qt: Customizable paths for save games, save states, screenshots and patches
Jeffrey Pfau jeffrey@endrift.com
Fri, 15 Jan 2016 14:29:19 -0800
commit

a38beac307b7b42dbc5ad5806a92b91396bea555

parent

89d53868da54cb0c058dd0b61c6267bdd6514012

M CHANGESCHANGES

@@ -17,6 +17,7 @@ - Libretro: Customizable idle loop removal

- 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
M src/gba/context/config.csrc/gba/context/config.c

@@ -347,6 +347,11 @@ _lookupIntValue(config, "fullscreen", &opts->fullscreen);

_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 @@

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; }
M src/gba/context/config.hsrc/gba/context/config.h

@@ -40,6 +40,11 @@ bool resampleVideo;

bool suspendScreensaver; char* shader; + char* savegamePath; + char* savestatePath; + char* screenshotPath; + char* patchPath; + int volume; bool mute;
M src/gba/context/directories.csrc/gba/context/directories.c

@@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this

* 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 @@ }

} 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); + } +}
M src/gba/context/directories.hsrc/gba/context/directories.h

@@ -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
M src/gba/supervisor/thread.csrc/gba/supervisor/thread.c

@@ -401,6 +401,8 @@ threadContext->audioBuffers = opts->audioBuffers;

} threadContext->idleOptimization = opts->idleOptimization; + + GBADirectorySetMapOptions(&threadContext->dirs, opts); } void GBAMapArgumentsToContext(const struct GBAArguments* args, struct GBAThread* threadContext) {

@@ -441,7 +443,6 @@ threadContext->state = THREAD_SHUTDOWN;

return false; } - GBADirectorySetInit(&threadContext->dirs); _reloadDirectories(threadContext); MutexInit(&threadContext->stateMutex);

@@ -571,8 +572,6 @@ if (threadContext->patch) {

threadContext->patch->close(threadContext->patch); threadContext->patch = 0; } - - GBADirectorySetDeinit(&threadContext->dirs); } bool GBAThreadIsActive(struct GBAThread* threadContext) {
M src/platform/qt/ConfigController.cppsrc/platform/qt/ConfigController.cpp

@@ -128,6 +128,7 @@ }

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::write() { GBAConfigSave(&m_config); m_settings->sync(); + + GBAConfigFreeOpts(&m_opts); + GBAConfigMap(&m_config, &m_opts); } void ConfigController::makePortable() {
M src/platform/qt/GBAApp.cppsrc/platform/qt/GBAApp.cpp

@@ -162,6 +162,16 @@ }

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);
M src/platform/qt/GBAApp.hsrc/platform/qt/GBAApp.h

@@ -36,6 +36,7 @@ Window* newWindow();

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());
M src/platform/qt/GameController.cppsrc/platform/qt/GameController.cpp

@@ -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 @@ disconnect();

clearMultiplayerController(); closeGame(); GBACheatDeviceDestroy(&m_cheatDevice); + GBADirectorySetDeinit(&m_threadContext.dirs); delete m_renderer; delete[] m_drawContext; delete[] m_frontBuffer;

@@ -255,6 +257,7 @@ setVolume(opts->volume);

setMute(opts->mute); threadInterrupt(); + GBADirectorySetMapOptions(&m_threadContext.dirs, opts); m_threadContext.idleOptimization = opts->idleOptimization; threadContinue(); }
M src/platform/qt/SettingsView.cppsrc/platform/qt/SettingsView.cpp

@@ -40,6 +40,74 @@ loadSetting("resampleVideo", m_ui.resampleVideo);

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 @@ saveSetting("resampleVideo", m_ui.resampleVideo);

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 @@ }

m_controller->write(); + emit pathsChanged(); emit biosLoaded(m_ui.bios->text()); }
M src/platform/qt/SettingsView.hsrc/platform/qt/SettingsView.h

@@ -26,6 +26,7 @@ signals:

void biosLoaded(const QString&); void audioDriverChanged(); void displayDriverChanged(); + void pathsChanged(); private slots: void selectBios();
M src/platform/qt/SettingsView.uisrc/platform/qt/SettingsView.ui

@@ -6,8 +6,8 @@ <property name="geometry">

<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 @@ <enum>QLayout::SetFixedSize</enum>

</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 @@ </widget>

</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 @@ </property>

</item> <item> <property name="text"> - <string>Running</string> + <string>Emulation</string> + </property> + </item> + <item> + <property name="text"> + <string>Paths</string> </property> </item> </widget>

@@ -637,6 +837,70 @@ </hint>

<hint type="destinationlabel"> <x>315</x> <y>209</y> + </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>
M src/platform/qt/Window.cppsrc/platform/qt/Window.cpp

@@ -198,16 +198,7 @@ }

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,12 +230,26 @@ shader->close(shader);

} } - 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() {

@@ -350,6 +355,7 @@ SettingsView* settingsWindow = new SettingsView(m_config, &m_inputController, m_shortcutController);

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); }
M src/platform/qt/Window.hsrc/platform/qt/Window.h

@@ -66,6 +66,7 @@ void enterFullScreen();

void exitFullScreen(); void toggleFullScreen(); void loadConfig(); + void reloadConfig(); void saveConfig(); void replaceROM();
M src/platform/sdl/main.csrc/platform/sdl/main.c

@@ -164,6 +164,7 @@ freeArguments(&args);

GBAConfigFreeOpts(&opts); GBAConfigDeinit(&config); free(context.debugger); + GBADirectorySetDeinit(&context.dirs); GBASDLDetachPlayer(&renderer.events, &renderer.player); GBAInputMapDeinit(&inputMap);