mirror of https://github.com/mgba-emu/mgba.git
Qt: Allow loading of specific files from archives
This commit is contained in:
parent
72fa184bac
commit
fa36a3da81
1
CHANGES
1
CHANGES
|
@ -11,6 +11,7 @@ Features:
|
|||
- Wii: 240p support
|
||||
- 3DS: Adjustable screen darkening
|
||||
- Ability to temporarily load a savegame
|
||||
- Load specific files out of archives
|
||||
Bugfixes:
|
||||
- SDL: Fix axes being mapped wrong
|
||||
- GBA Memory: Fix mirror on non-overdumped Classic NES games
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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 "library.h"
|
||||
|
||||
#include "util/vfs.h"
|
||||
|
||||
DEFINE_VECTOR(mLibraryListing, struct mLibraryEntry);
|
||||
|
||||
void mLibraryInit(struct mLibrary* library) {
|
||||
mLibraryListingInit(&library->listing, 0);
|
||||
}
|
||||
|
||||
void mLibraryDeinit(struct mLibrary* library) {
|
||||
size_t i;
|
||||
for (i = 0; i < mLibraryListingSize(&library->listing); ++i) {
|
||||
struct mLibraryEntry* entry = mLibraryListingGetPointer(&library->listing, i);
|
||||
free(entry->filename);
|
||||
free(entry->title);
|
||||
}
|
||||
mLibraryListingDeinit(&library->listing);
|
||||
}
|
||||
|
||||
void mLibraryLoadDirectory(struct mLibrary* library, struct VDir* dir) {
|
||||
struct VDirEntry* dirent = dir->listNext(dir);
|
||||
while (dirent) {
|
||||
struct VFile* vf = dir->openFile(dir, dirent->name(dirent), O_RDONLY);
|
||||
if (!vf) {
|
||||
dirent = dir->listNext(dir);
|
||||
continue;
|
||||
}
|
||||
mLibraryAddEntry(library, dirent->name(dirent), vf);
|
||||
dirent = dir->listNext(dir);
|
||||
}
|
||||
}
|
||||
|
||||
void mLibraryAddEntry(struct mLibrary* library, const char* filename, struct VFile* vf) {
|
||||
struct mCore* core;
|
||||
if (!vf) {
|
||||
vf = VFileOpen(filename, O_RDONLY);
|
||||
}
|
||||
core = mCoreFindVF(vf);
|
||||
if (core) {
|
||||
core->init(core);
|
||||
core->loadROM(core, vf);
|
||||
|
||||
struct mLibraryEntry* entry = mLibraryListingAppend(&library->listing);
|
||||
core->getGameTitle(core, entry->internalTitle);
|
||||
core->getGameCode(core, entry->internalCode);
|
||||
entry->title = NULL;
|
||||
entry->filename = strdup(filename);
|
||||
entry->filesize = vf->size(vf);
|
||||
// Note: this destroys the VFile
|
||||
core->deinit(core);
|
||||
} else {
|
||||
vf->close(vf);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
#ifndef M_LIBRARY_H
|
||||
#define M_LIBRARY_H
|
||||
|
||||
#include "util/common.h"
|
||||
|
||||
#include "core/core.h"
|
||||
#include "util/vector.h"
|
||||
|
||||
struct mLibraryEntry {
|
||||
char* filename;
|
||||
char* title;
|
||||
char internalTitle[17];
|
||||
char internalCode[9];
|
||||
size_t filesize;
|
||||
enum mPlatform platform;
|
||||
};
|
||||
|
||||
DECLARE_VECTOR(mLibraryListing, struct mLibraryEntry);
|
||||
|
||||
struct mLibrary {
|
||||
struct mLibraryListing listing;
|
||||
};
|
||||
|
||||
void mLibraryInit(struct mLibrary*);
|
||||
void mLibraryDeinit(struct mLibrary*);
|
||||
|
||||
struct VDir;
|
||||
struct VFile;
|
||||
void mLibraryLoadDirectory(struct mLibrary* library, struct VDir* dir);
|
||||
void mLibraryAddEntry(struct mLibrary* library, const char* filename, struct VFile* vf);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,37 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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 "ArchiveInspector.h"
|
||||
|
||||
extern "C" {
|
||||
#include "util/vfs.h"
|
||||
}
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
ArchiveInspector::ArchiveInspector(const QString& filename, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
m_dir = VDirOpenArchive(filename.toUtf8().constData());
|
||||
if (m_dir) {
|
||||
m_model.loadDirectory(m_dir);
|
||||
}
|
||||
m_ui.archiveListing->setModel(&m_model);
|
||||
}
|
||||
|
||||
ArchiveInspector::~ArchiveInspector() {
|
||||
if (m_dir) {
|
||||
m_dir->close(m_dir);
|
||||
}
|
||||
}
|
||||
|
||||
VFile* ArchiveInspector::selectedVFile() const {
|
||||
QModelIndex index = m_ui.archiveListing->selectionModel()->currentIndex();
|
||||
if (!index.isValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_dir->openFile(m_dir, m_model.entryAt(index.row())->filename, O_RDONLY);
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
#ifndef QGBA_ARCHIVE_INSPECTOR
|
||||
#define QGBA_ARCHIVE_INSPECTOR
|
||||
|
||||
#include "LibraryModel.h"
|
||||
|
||||
#include "ui_ArchiveInspector.h"
|
||||
|
||||
struct VDir;
|
||||
struct VFile;
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class ArchiveInspector : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ArchiveInspector(const QString& filename, QWidget* parent = nullptr);
|
||||
virtual ~ArchiveInspector();
|
||||
|
||||
VFile* selectedVFile() const;
|
||||
|
||||
private:
|
||||
Ui::ArchiveInspector m_ui;
|
||||
|
||||
LibraryModel m_model;
|
||||
VDir* m_dir;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,80 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ArchiveInspector</class>
|
||||
<widget class="QDialog" name="ArchiveInspector">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Open in archive...</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Open</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QListView" name="archiveListing"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ArchiveInspector</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>199</x>
|
||||
<y>279</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>199</x>
|
||||
<y>149</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ArchiveInspector</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>199</x>
|
||||
<y>279</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>199</x>
|
||||
<y>149</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>archiveListing</sender>
|
||||
<signal>doubleClicked(QModelIndex)</signal>
|
||||
<receiver>ArchiveInspector</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>199</x>
|
||||
<y>129</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>199</x>
|
||||
<y>149</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
|
@ -68,6 +68,7 @@ endif()
|
|||
|
||||
set(SOURCE_FILES
|
||||
AboutScreen.cpp
|
||||
ArchiveInspector.cpp
|
||||
AudioProcessor.cpp
|
||||
CheatsModel.cpp
|
||||
CheatsView.cpp
|
||||
|
@ -85,6 +86,7 @@ set(SOURCE_FILES
|
|||
InputController.cpp
|
||||
InputProfile.cpp
|
||||
KeyEditor.cpp
|
||||
LibraryModel.cpp
|
||||
LoadSaveState.cpp
|
||||
LogController.cpp
|
||||
LogView.cpp
|
||||
|
@ -110,6 +112,7 @@ set(SOURCE_FILES
|
|||
|
||||
qt5_wrap_ui(UI_FILES
|
||||
AboutScreen.ui
|
||||
ArchiveInspector.ui
|
||||
CheatsView.ui
|
||||
GIFView.ui
|
||||
IOViewer.ui
|
||||
|
|
|
@ -45,6 +45,7 @@ GameController::GameController(QObject* parent)
|
|||
, m_inactiveKeys(0)
|
||||
, m_logLevels(0)
|
||||
, m_gameOpen(false)
|
||||
, m_vf(nullptr)
|
||||
, m_useBios(false)
|
||||
, m_audioThread(new QThread(this))
|
||||
, m_audioProcessor(AudioProcessor::create())
|
||||
|
@ -315,6 +316,14 @@ void GameController::loadGame(const QString& path) {
|
|||
return;
|
||||
}
|
||||
m_fname = info.canonicalFilePath();
|
||||
m_vf = nullptr;
|
||||
openGame();
|
||||
}
|
||||
|
||||
void GameController::loadGame(VFile* vf, const QString& base) {
|
||||
closeGame();
|
||||
m_fname = base;
|
||||
m_vf = vf;
|
||||
openGame();
|
||||
}
|
||||
|
||||
|
@ -330,7 +339,11 @@ void GameController::openGame(bool biosOnly) {
|
|||
}
|
||||
|
||||
if (!biosOnly) {
|
||||
if (m_vf) {
|
||||
m_threadContext.core = mCoreFindVF(m_vf);
|
||||
} else {
|
||||
m_threadContext.core = mCoreFind(m_fname.toUtf8().constData());
|
||||
}
|
||||
} else {
|
||||
m_threadContext.core = GBACoreCreate();
|
||||
}
|
||||
|
@ -357,13 +370,21 @@ void GameController::openGame(bool biosOnly) {
|
|||
m_drawContext = new uint32_t[width * height];
|
||||
m_frontBuffer = new uint32_t[width * height];
|
||||
|
||||
const char* base;
|
||||
if (!biosOnly) {
|
||||
mCoreLoadFile(m_threadContext.core, m_fname.toUtf8().constData());
|
||||
base = m_fname.toUtf8().constData();
|
||||
if (m_vf) {
|
||||
m_threadContext.core->loadROM(m_threadContext.core, m_vf);
|
||||
} else {
|
||||
char dirname[PATH_MAX];
|
||||
separatePath(m_bios.toUtf8().constData(), dirname, m_threadContext.core->dirs.baseName, 0);
|
||||
mDirectorySetAttachBase(&m_threadContext.core->dirs, VDirOpen(dirname));
|
||||
mCoreLoadFile(m_threadContext.core, base);
|
||||
mDirectorySetDetachBase(&m_threadContext.core->dirs);
|
||||
}
|
||||
} else {
|
||||
base = m_bios.toUtf8().constData();
|
||||
}
|
||||
char dirname[PATH_MAX];
|
||||
separatePath(base, dirname, m_threadContext.core->dirs.baseName, 0);
|
||||
mDirectorySetAttachBase(&m_threadContext.core->dirs, VDirOpen(dirname));
|
||||
|
||||
m_threadContext.core->setVideoBuffer(m_threadContext.core, m_drawContext, width);
|
||||
|
||||
|
@ -396,6 +417,7 @@ void GameController::openGame(bool biosOnly) {
|
|||
mCoreAutoloadPatch(m_threadContext.core);
|
||||
}
|
||||
}
|
||||
m_vf = nullptr;
|
||||
|
||||
if (!mCoreThreadStart(&m_threadContext)) {
|
||||
m_gameOpen = false;
|
||||
|
|
|
@ -102,6 +102,7 @@ signals:
|
|||
|
||||
public slots:
|
||||
void loadGame(const QString& path);
|
||||
void loadGame(VFile* vf, const QString& base = QString());
|
||||
void loadBIOS(const QString& path);
|
||||
void loadSave(const QString& path, bool temporary = true);
|
||||
void yankPak();
|
||||
|
@ -184,6 +185,7 @@ private:
|
|||
bool m_gameOpen;
|
||||
|
||||
QString m_fname;
|
||||
VFile* m_vf;
|
||||
QString m_bios;
|
||||
bool m_useBios;
|
||||
QString m_patch;
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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 "LibraryModel.h"
|
||||
|
||||
extern "C" {
|
||||
#include "util/vfs.h"
|
||||
}
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
LibraryModel::LibraryModel(QObject* parent)
|
||||
: QAbstractItemModel(parent)
|
||||
{
|
||||
mLibraryInit(&m_library);
|
||||
}
|
||||
|
||||
LibraryModel::~LibraryModel() {
|
||||
mLibraryDeinit(&m_library);
|
||||
}
|
||||
|
||||
void LibraryModel::loadDirectory(VDir* dir) {
|
||||
mLibraryLoadDirectory(&m_library, dir);
|
||||
}
|
||||
|
||||
const mLibraryEntry* LibraryModel::entryAt(int row) const {
|
||||
if ((unsigned) row < mLibraryListingSize(&m_library.listing)) {
|
||||
return mLibraryListingGetConstPointer(&m_library.listing, row);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QVariant LibraryModel::data(const QModelIndex& index, int role) const {
|
||||
if (!index.isValid()) {
|
||||
return QVariant();
|
||||
}
|
||||
if (role != Qt::DisplayRole) {
|
||||
return QVariant();
|
||||
}
|
||||
const mLibraryEntry* entry = mLibraryListingGetConstPointer(&m_library.listing, index.row());
|
||||
switch (index.column()) {
|
||||
case 0:
|
||||
return entry->filename;
|
||||
case 1:
|
||||
return (unsigned long long) entry->filesize;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant LibraryModel::headerData(int section, Qt::Orientation orientation, int role) const {
|
||||
if (role != Qt::DisplayRole) {
|
||||
return QAbstractItemModel::headerData(section, orientation, role);
|
||||
}
|
||||
if (orientation == Qt::Horizontal) {
|
||||
switch (section) {
|
||||
case 0:
|
||||
return tr("Filename");
|
||||
case 1:
|
||||
return tr("Size");
|
||||
}
|
||||
}
|
||||
return section;
|
||||
}
|
||||
|
||||
QModelIndex LibraryModel::index(int row, int column, const QModelIndex& parent) const {
|
||||
if (parent.isValid()) {
|
||||
return QModelIndex();
|
||||
}
|
||||
return createIndex(row, column, nullptr);
|
||||
}
|
||||
|
||||
QModelIndex LibraryModel::parent(const QModelIndex&) const {
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
int LibraryModel::columnCount(const QModelIndex& parent) const {
|
||||
if (parent.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
int LibraryModel::rowCount(const QModelIndex& parent) const {
|
||||
if (parent.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
return mLibraryListingSize(&m_library.listing);
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
#ifndef QGBA_LIBRARY_MODEL
|
||||
#define QGBA_LIBRARY_MODEL
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
extern "C" {
|
||||
#include "core/library.h"
|
||||
}
|
||||
|
||||
struct VDir;
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
class LibraryModel : public QAbstractItemModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LibraryModel(QObject* parent = nullptr);
|
||||
virtual ~LibraryModel();
|
||||
|
||||
void loadDirectory(VDir* dir);
|
||||
|
||||
const mLibraryEntry* entryAt(int row) const;
|
||||
|
||||
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
|
||||
virtual QModelIndex index(int row, int column, const QModelIndex& parent) const override;
|
||||
virtual QModelIndex parent(const QModelIndex& index) const override;
|
||||
|
||||
virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
|
||||
private:
|
||||
mLibrary m_library;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -15,6 +15,7 @@
|
|||
#include <QStackedLayout>
|
||||
|
||||
#include "AboutScreen.h"
|
||||
#include "ArchiveInspector.h"
|
||||
#include "CheatsView.h"
|
||||
#include "ConfigController.h"
|
||||
#include "Display.h"
|
||||
|
@ -323,6 +324,21 @@ QString Window::getFilters() const {
|
|||
return filters.join(";;");
|
||||
}
|
||||
|
||||
QString Window::getFiltersArchive() const {
|
||||
QStringList filters;
|
||||
|
||||
QStringList formats{
|
||||
#if defined(USE_LIBZIP) || defined(USE_ZLIB)
|
||||
"*.zip",
|
||||
#endif
|
||||
#ifdef USE_LZMA
|
||||
"*.7z",
|
||||
#endif
|
||||
};
|
||||
filters.append(tr("Archives (%1)").arg(formats.join(QChar(' '))));
|
||||
return filters.join(";;");
|
||||
}
|
||||
|
||||
void Window::selectROM() {
|
||||
QString filename = GBAApp::app()->getOpenFileName(this, tr("Select ROM"), getFilters());
|
||||
if (!filename.isEmpty()) {
|
||||
|
@ -330,6 +346,23 @@ void Window::selectROM() {
|
|||
}
|
||||
}
|
||||
|
||||
void Window::selectROMInArchive() {
|
||||
QString filename = GBAApp::app()->getOpenFileName(this, tr("Select ROM"), getFiltersArchive());
|
||||
if (filename.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ArchiveInspector* archiveInspector = new ArchiveInspector(filename);
|
||||
connect(archiveInspector, &QDialog::accepted, [this, archiveInspector]() {
|
||||
VFile* output = archiveInspector->selectedVFile();
|
||||
if (output) {
|
||||
m_controller->loadGame(output);
|
||||
}
|
||||
archiveInspector->close();
|
||||
});
|
||||
archiveInspector->setAttribute(Qt::WA_DeleteOnClose);
|
||||
archiveInspector->show();
|
||||
}
|
||||
|
||||
void Window::replaceROM() {
|
||||
QString filename = GBAApp::app()->getOpenFileName(this, tr("Select ROM"), getFilters());
|
||||
if (!filename.isEmpty()) {
|
||||
|
@ -850,13 +883,17 @@ void Window::setupMenu(QMenuBar* menubar) {
|
|||
installEventFilter(m_shortcutController);
|
||||
addControlledAction(fileMenu, fileMenu->addAction(tr("Load &ROM..."), this, SLOT(selectROM()), QKeySequence::Open),
|
||||
"loadROM");
|
||||
addControlledAction(fileMenu, fileMenu->addAction(tr("Load ROM in archive..."), this, SLOT(selectROMInArchive())),
|
||||
"loadROMInArchive");
|
||||
|
||||
addControlledAction(fileMenu, fileMenu->addAction(tr("Load &BIOS..."), this, SLOT(selectBIOS())), "loadBIOS");
|
||||
|
||||
QAction* loadTemporarySave = new QAction(tr("Load temporary save..."), fileMenu);
|
||||
connect(loadTemporarySave, &QAction::triggered, [this]() { this->selectSave(true); });
|
||||
m_gameActions.append(loadTemporarySave);
|
||||
m_gbaActions.append(loadTemporarySave);
|
||||
addControlledAction(fileMenu, loadTemporarySave, "loadTemporarySave");
|
||||
|
||||
addControlledAction(fileMenu, fileMenu->addAction(tr("Load &BIOS..."), this, SLOT(selectBIOS())), "loadBIOS");
|
||||
addControlledAction(fileMenu, fileMenu->addAction(tr("Load &patch..."), this, SLOT(selectPatch())), "loadPatch");
|
||||
addControlledAction(fileMenu, fileMenu->addAction(tr("Boot BIOS"), m_controller, SLOT(bootBIOS())), "bootBIOS");
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ signals:
|
|||
|
||||
public slots:
|
||||
void selectROM();
|
||||
void selectROMInArchive();
|
||||
void selectSave(bool temporary);
|
||||
void selectBIOS();
|
||||
void selectPatch();
|
||||
|
@ -148,6 +149,7 @@ private:
|
|||
void updateTitle(float fps = -1);
|
||||
|
||||
QString getFilters() const;
|
||||
QString getFiltersArchive() const;
|
||||
|
||||
GameController* m_controller;
|
||||
Display* m_display;
|
||||
|
|
Loading…
Reference in New Issue