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
|
- Wii: 240p support
|
||||||
- 3DS: Adjustable screen darkening
|
- 3DS: Adjustable screen darkening
|
||||||
- Ability to temporarily load a savegame
|
- Ability to temporarily load a savegame
|
||||||
|
- Load specific files out of archives
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
- SDL: Fix axes being mapped wrong
|
- SDL: Fix axes being mapped wrong
|
||||||
- GBA Memory: Fix mirror on non-overdumped Classic NES games
|
- 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
|
set(SOURCE_FILES
|
||||||
AboutScreen.cpp
|
AboutScreen.cpp
|
||||||
|
ArchiveInspector.cpp
|
||||||
AudioProcessor.cpp
|
AudioProcessor.cpp
|
||||||
CheatsModel.cpp
|
CheatsModel.cpp
|
||||||
CheatsView.cpp
|
CheatsView.cpp
|
||||||
|
@ -85,6 +86,7 @@ set(SOURCE_FILES
|
||||||
InputController.cpp
|
InputController.cpp
|
||||||
InputProfile.cpp
|
InputProfile.cpp
|
||||||
KeyEditor.cpp
|
KeyEditor.cpp
|
||||||
|
LibraryModel.cpp
|
||||||
LoadSaveState.cpp
|
LoadSaveState.cpp
|
||||||
LogController.cpp
|
LogController.cpp
|
||||||
LogView.cpp
|
LogView.cpp
|
||||||
|
@ -110,6 +112,7 @@ set(SOURCE_FILES
|
||||||
|
|
||||||
qt5_wrap_ui(UI_FILES
|
qt5_wrap_ui(UI_FILES
|
||||||
AboutScreen.ui
|
AboutScreen.ui
|
||||||
|
ArchiveInspector.ui
|
||||||
CheatsView.ui
|
CheatsView.ui
|
||||||
GIFView.ui
|
GIFView.ui
|
||||||
IOViewer.ui
|
IOViewer.ui
|
||||||
|
|
|
@ -45,6 +45,7 @@ GameController::GameController(QObject* parent)
|
||||||
, m_inactiveKeys(0)
|
, m_inactiveKeys(0)
|
||||||
, m_logLevels(0)
|
, m_logLevels(0)
|
||||||
, m_gameOpen(false)
|
, m_gameOpen(false)
|
||||||
|
, m_vf(nullptr)
|
||||||
, m_useBios(false)
|
, m_useBios(false)
|
||||||
, m_audioThread(new QThread(this))
|
, m_audioThread(new QThread(this))
|
||||||
, m_audioProcessor(AudioProcessor::create())
|
, m_audioProcessor(AudioProcessor::create())
|
||||||
|
@ -315,6 +316,14 @@ void GameController::loadGame(const QString& path) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_fname = info.canonicalFilePath();
|
m_fname = info.canonicalFilePath();
|
||||||
|
m_vf = nullptr;
|
||||||
|
openGame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameController::loadGame(VFile* vf, const QString& base) {
|
||||||
|
closeGame();
|
||||||
|
m_fname = base;
|
||||||
|
m_vf = vf;
|
||||||
openGame();
|
openGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,7 +339,11 @@ void GameController::openGame(bool biosOnly) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!biosOnly) {
|
if (!biosOnly) {
|
||||||
m_threadContext.core = mCoreFind(m_fname.toUtf8().constData());
|
if (m_vf) {
|
||||||
|
m_threadContext.core = mCoreFindVF(m_vf);
|
||||||
|
} else {
|
||||||
|
m_threadContext.core = mCoreFind(m_fname.toUtf8().constData());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
m_threadContext.core = GBACoreCreate();
|
m_threadContext.core = GBACoreCreate();
|
||||||
}
|
}
|
||||||
|
@ -357,13 +370,21 @@ void GameController::openGame(bool biosOnly) {
|
||||||
m_drawContext = new uint32_t[width * height];
|
m_drawContext = new uint32_t[width * height];
|
||||||
m_frontBuffer = new uint32_t[width * height];
|
m_frontBuffer = new uint32_t[width * height];
|
||||||
|
|
||||||
|
const char* base;
|
||||||
if (!biosOnly) {
|
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 {
|
||||||
|
mCoreLoadFile(m_threadContext.core, base);
|
||||||
|
mDirectorySetDetachBase(&m_threadContext.core->dirs);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
char dirname[PATH_MAX];
|
base = m_bios.toUtf8().constData();
|
||||||
separatePath(m_bios.toUtf8().constData(), dirname, m_threadContext.core->dirs.baseName, 0);
|
|
||||||
mDirectorySetAttachBase(&m_threadContext.core->dirs, VDirOpen(dirname));
|
|
||||||
}
|
}
|
||||||
|
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);
|
m_threadContext.core->setVideoBuffer(m_threadContext.core, m_drawContext, width);
|
||||||
|
|
||||||
|
@ -396,6 +417,7 @@ void GameController::openGame(bool biosOnly) {
|
||||||
mCoreAutoloadPatch(m_threadContext.core);
|
mCoreAutoloadPatch(m_threadContext.core);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
m_vf = nullptr;
|
||||||
|
|
||||||
if (!mCoreThreadStart(&m_threadContext)) {
|
if (!mCoreThreadStart(&m_threadContext)) {
|
||||||
m_gameOpen = false;
|
m_gameOpen = false;
|
||||||
|
|
|
@ -102,6 +102,7 @@ signals:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void loadGame(const QString& path);
|
void loadGame(const QString& path);
|
||||||
|
void loadGame(VFile* vf, const QString& base = QString());
|
||||||
void loadBIOS(const QString& path);
|
void loadBIOS(const QString& path);
|
||||||
void loadSave(const QString& path, bool temporary = true);
|
void loadSave(const QString& path, bool temporary = true);
|
||||||
void yankPak();
|
void yankPak();
|
||||||
|
@ -184,6 +185,7 @@ private:
|
||||||
bool m_gameOpen;
|
bool m_gameOpen;
|
||||||
|
|
||||||
QString m_fname;
|
QString m_fname;
|
||||||
|
VFile* m_vf;
|
||||||
QString m_bios;
|
QString m_bios;
|
||||||
bool m_useBios;
|
bool m_useBios;
|
||||||
QString m_patch;
|
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 <QStackedLayout>
|
||||||
|
|
||||||
#include "AboutScreen.h"
|
#include "AboutScreen.h"
|
||||||
|
#include "ArchiveInspector.h"
|
||||||
#include "CheatsView.h"
|
#include "CheatsView.h"
|
||||||
#include "ConfigController.h"
|
#include "ConfigController.h"
|
||||||
#include "Display.h"
|
#include "Display.h"
|
||||||
|
@ -323,6 +324,21 @@ QString Window::getFilters() const {
|
||||||
return filters.join(";;");
|
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() {
|
void Window::selectROM() {
|
||||||
QString filename = GBAApp::app()->getOpenFileName(this, tr("Select ROM"), getFilters());
|
QString filename = GBAApp::app()->getOpenFileName(this, tr("Select ROM"), getFilters());
|
||||||
if (!filename.isEmpty()) {
|
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() {
|
void Window::replaceROM() {
|
||||||
QString filename = GBAApp::app()->getOpenFileName(this, tr("Select ROM"), getFilters());
|
QString filename = GBAApp::app()->getOpenFileName(this, tr("Select ROM"), getFilters());
|
||||||
if (!filename.isEmpty()) {
|
if (!filename.isEmpty()) {
|
||||||
|
@ -850,13 +883,17 @@ void Window::setupMenu(QMenuBar* menubar) {
|
||||||
installEventFilter(m_shortcutController);
|
installEventFilter(m_shortcutController);
|
||||||
addControlledAction(fileMenu, fileMenu->addAction(tr("Load &ROM..."), this, SLOT(selectROM()), QKeySequence::Open),
|
addControlledAction(fileMenu, fileMenu->addAction(tr("Load &ROM..."), this, SLOT(selectROM()), QKeySequence::Open),
|
||||||
"loadROM");
|
"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);
|
QAction* loadTemporarySave = new QAction(tr("Load temporary save..."), fileMenu);
|
||||||
connect(loadTemporarySave, &QAction::triggered, [this]() { this->selectSave(true); });
|
connect(loadTemporarySave, &QAction::triggered, [this]() { this->selectSave(true); });
|
||||||
m_gameActions.append(loadTemporarySave);
|
m_gameActions.append(loadTemporarySave);
|
||||||
m_gbaActions.append(loadTemporarySave);
|
m_gbaActions.append(loadTemporarySave);
|
||||||
addControlledAction(fileMenu, loadTemporarySave, "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("Load &patch..."), this, SLOT(selectPatch())), "loadPatch");
|
||||||
addControlledAction(fileMenu, fileMenu->addAction(tr("Boot BIOS"), m_controller, SLOT(bootBIOS())), "bootBIOS");
|
addControlledAction(fileMenu, fileMenu->addAction(tr("Boot BIOS"), m_controller, SLOT(bootBIOS())), "bootBIOS");
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ signals:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void selectROM();
|
void selectROM();
|
||||||
|
void selectROMInArchive();
|
||||||
void selectSave(bool temporary);
|
void selectSave(bool temporary);
|
||||||
void selectBIOS();
|
void selectBIOS();
|
||||||
void selectPatch();
|
void selectPatch();
|
||||||
|
@ -148,6 +149,7 @@ private:
|
||||||
void updateTitle(float fps = -1);
|
void updateTitle(float fps = -1);
|
||||||
|
|
||||||
QString getFilters() const;
|
QString getFilters() const;
|
||||||
|
QString getFiltersArchive() const;
|
||||||
|
|
||||||
GameController* m_controller;
|
GameController* m_controller;
|
||||||
Display* m_display;
|
Display* m_display;
|
||||||
|
|
Loading…
Reference in New Issue