mirror of https://github.com/mgba-emu/mgba.git
Qt: Display hex values within cheats
This commit is contained in:
parent
8741a374a5
commit
ca6b2e7b09
|
@ -15,6 +15,7 @@ const uint32_t GBA_CHEAT_DEVICE_ID = 0xABADC0DE;
|
||||||
|
|
||||||
DEFINE_VECTOR(GBACheatList, struct GBACheat);
|
DEFINE_VECTOR(GBACheatList, struct GBACheat);
|
||||||
DEFINE_VECTOR(GBACheatSets, struct GBACheatSet*);
|
DEFINE_VECTOR(GBACheatSets, struct GBACheatSet*);
|
||||||
|
DEFINE_VECTOR(StringList, char*);
|
||||||
|
|
||||||
static const uint32_t _gsa1S[4] = { 0x09F4FBBD, 0x9681884A, 0x352027E9, 0xF3DEE5A7 };
|
static const uint32_t _gsa1S[4] = { 0x09F4FBBD, 0x9681884A, 0x352027E9, 0xF3DEE5A7 };
|
||||||
static const uint32_t _par3S[4] = { 0x7AA9648F, 0x7FAE6994, 0xC0EFAAD5, 0x42712C57 };
|
static const uint32_t _par3S[4] = { 0x7AA9648F, 0x7FAE6994, 0xC0EFAAD5, 0x42712C57 };
|
||||||
|
@ -188,6 +189,10 @@ static const char* _hex16(const char* line, uint16_t* out) {
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _registerLine(struct GBACheatSet* cheats, const char* line) {
|
||||||
|
*StringListAppend(&cheats->lines) = strdup(line);
|
||||||
|
}
|
||||||
|
|
||||||
// http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
|
// http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
|
||||||
static void _decryptGameShark(uint32_t* op1, uint32_t* op2, const uint32_t* seeds) {
|
static void _decryptGameShark(uint32_t* op1, uint32_t* op2, const uint32_t* seeds) {
|
||||||
uint32_t sum = 0xC6EF3720;
|
uint32_t sum = 0xC6EF3720;
|
||||||
|
@ -405,6 +410,7 @@ void GBACheatDeviceDestroy(struct GBACheatDevice* device) {
|
||||||
|
|
||||||
void GBACheatSetInit(struct GBACheatSet* set, const char* name) {
|
void GBACheatSetInit(struct GBACheatSet* set, const char* name) {
|
||||||
GBACheatListInit(&set->list, 4);
|
GBACheatListInit(&set->list, 4);
|
||||||
|
StringListInit(&set->lines, 4);
|
||||||
set->incompleteCheat = 0;
|
set->incompleteCheat = 0;
|
||||||
set->gsaVersion = 0;
|
set->gsaVersion = 0;
|
||||||
set->remainingAddresses = 0;
|
set->remainingAddresses = 0;
|
||||||
|
@ -422,6 +428,10 @@ void GBACheatSetInit(struct GBACheatSet* set, const char* name) {
|
||||||
|
|
||||||
void GBACheatSetDeinit(struct GBACheatSet* set) {
|
void GBACheatSetDeinit(struct GBACheatSet* set) {
|
||||||
GBACheatListDeinit(&set->list);
|
GBACheatListDeinit(&set->list);
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < StringListSize(&set->lines); ++i) {
|
||||||
|
free(*StringListGetPointer(&set->lines, i));
|
||||||
|
}
|
||||||
if (set->name) {
|
if (set->name) {
|
||||||
free(set->name);
|
free(set->name);
|
||||||
}
|
}
|
||||||
|
@ -463,6 +473,10 @@ void GBACheatRemoveSet(struct GBACheatDevice* device, struct GBACheatSet* cheats
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t op2) {
|
bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t op2) {
|
||||||
|
char line[14] = "XXXXXXXX XXXX";
|
||||||
|
snprintf(line, sizeof(line), "%08X %04X", op1, op2);
|
||||||
|
_registerLine(cheats, line);
|
||||||
|
|
||||||
enum GBACodeBreakerType type = op1 >> 28;
|
enum GBACodeBreakerType type = op1 >> 28;
|
||||||
struct GBACheat* cheat = 0;
|
struct GBACheat* cheat = 0;
|
||||||
|
|
||||||
|
@ -592,6 +606,10 @@ bool GBACheatAddCodeBreakerLine(struct GBACheatSet* cheats, const char* line) {
|
||||||
bool GBACheatAddGameShark(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
|
bool GBACheatAddGameShark(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
|
||||||
uint32_t o1 = op1;
|
uint32_t o1 = op1;
|
||||||
uint32_t o2 = op2;
|
uint32_t o2 = op2;
|
||||||
|
char line[18] = "XXXXXXXX XXXXXXXX";
|
||||||
|
snprintf(line, sizeof(line), "%08X %08X", op1, op2);
|
||||||
|
_registerLine(set, line);
|
||||||
|
|
||||||
switch (set->gsaVersion) {
|
switch (set->gsaVersion) {
|
||||||
case 0:
|
case 0:
|
||||||
_setGameSharkVersion(set, 1);
|
_setGameSharkVersion(set, 1);
|
||||||
|
@ -623,6 +641,10 @@ bool GBACheatAddGameSharkLine(struct GBACheatSet* cheats, const char* line) {
|
||||||
bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
|
bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
|
||||||
uint32_t o1 = op1;
|
uint32_t o1 = op1;
|
||||||
uint32_t o2 = op2;
|
uint32_t o2 = op2;
|
||||||
|
char line[18] = "XXXXXXXX XXXXXXXX";
|
||||||
|
snprintf(line, sizeof(line), "%08X %08X", op1, op2);
|
||||||
|
_registerLine(set, line);
|
||||||
|
|
||||||
switch (set->gsaVersion) {
|
switch (set->gsaVersion) {
|
||||||
case 0:
|
case 0:
|
||||||
// Try to detect GameShark version
|
// Try to detect GameShark version
|
||||||
|
|
|
@ -142,6 +142,7 @@ struct GBACheatHook {
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_VECTOR(GBACheatList, struct GBACheat);
|
DECLARE_VECTOR(GBACheatList, struct GBACheat);
|
||||||
|
DECLARE_VECTOR(StringList, char*);
|
||||||
|
|
||||||
struct GBACheatSet {
|
struct GBACheatSet {
|
||||||
struct GBACheatHook* hook;
|
struct GBACheatHook* hook;
|
||||||
|
@ -162,6 +163,7 @@ struct GBACheatSet {
|
||||||
int remainingAddresses;
|
int remainingAddresses;
|
||||||
|
|
||||||
char* name;
|
char* name;
|
||||||
|
struct StringList lines;
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_VECTOR(GBACheatSets, struct GBACheatSet*);
|
DECLARE_VECTOR(GBACheatSets, struct GBACheatSet*);
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
#include "CheatsModel.h"
|
#include "CheatsModel.h"
|
||||||
|
|
||||||
|
#include <QFont>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "gba/cheats.h"
|
#include "gba/cheats.h"
|
||||||
#include "util/vfs.h"
|
#include "util/vfs.h"
|
||||||
|
@ -23,8 +25,22 @@ QVariant CheatsModel::data(const QModelIndex& index, int role) const {
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (index.parent().isValid()) {
|
||||||
|
int row = index.row();
|
||||||
|
GBACheatSet* cheats = static_cast<GBACheatSet*>(index.internalPointer());
|
||||||
|
const char* line = *StringListGetPointer(&cheats->lines, row);
|
||||||
|
switch (role) {
|
||||||
|
case Qt::DisplayRole:
|
||||||
|
return line;
|
||||||
|
case Qt::FontRole:
|
||||||
|
return QFont("Courier New", 13);
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int row = index.row();
|
int row = index.row();
|
||||||
const GBACheatSet* cheats = static_cast<const GBACheatSet*>(index.internalPointer());
|
const GBACheatSet* cheats = *GBACheatSetsGetPointer(&m_device->cheats, index.row());
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
case Qt::EditRole:
|
case Qt::EditRole:
|
||||||
|
@ -37,12 +53,12 @@ QVariant CheatsModel::data(const QModelIndex& index, int role) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheatsModel::setData(const QModelIndex& index, const QVariant& value, int role) {
|
bool CheatsModel::setData(const QModelIndex& index, const QVariant& value, int role) {
|
||||||
if (!index.isValid()) {
|
if (!index.isValid() || index.parent().isValid()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int row = index.row();
|
int row = index.row();
|
||||||
GBACheatSet* cheats = static_cast<GBACheatSet*>(index.internalPointer());
|
GBACheatSet* cheats = *GBACheatSetsGetPointer(&m_device->cheats, index.row());
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
case Qt::EditRole:
|
case Qt::EditRole:
|
||||||
|
@ -60,10 +76,26 @@ bool CheatsModel::setData(const QModelIndex& index, const QVariant& value, int r
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex CheatsModel::index(int row, int column, const QModelIndex& parent) const {
|
QModelIndex CheatsModel::index(int row, int column, const QModelIndex& parent) const {
|
||||||
return createIndex(row, column, *GBACheatSetsGetPointer(&m_device->cheats, row));
|
if (parent.isValid()) {
|
||||||
|
return createIndex(row, column, *GBACheatSetsGetPointer(&m_device->cheats, parent.row()));
|
||||||
|
} else {
|
||||||
|
return createIndex(row, column, nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex CheatsModel::parent(const QModelIndex& index) const {
|
QModelIndex CheatsModel::parent(const QModelIndex& index) const {
|
||||||
|
if (!index.isValid()) {
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
const GBACheatSet* cheats = static_cast<const GBACheatSet*>(index.internalPointer());
|
||||||
|
if (!cheats) {
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < GBACheatSetsSize(&m_device->cheats); ++i) {
|
||||||
|
if (cheats == *GBACheatSetsGetPointer(&m_device->cheats, i)) {
|
||||||
|
return createIndex(i, 0, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +104,10 @@ Qt::ItemFlags CheatsModel::flags(const QModelIndex &index) const {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (index.parent().isValid()) {
|
||||||
|
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||||
|
}
|
||||||
|
|
||||||
return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +117,11 @@ int CheatsModel::columnCount(const QModelIndex& parent) const {
|
||||||
|
|
||||||
int CheatsModel::rowCount(const QModelIndex& parent) const {
|
int CheatsModel::rowCount(const QModelIndex& parent) const {
|
||||||
if (parent.isValid()) {
|
if (parent.isValid()) {
|
||||||
return 0;
|
if (parent.internalPointer()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const GBACheatSet* set = *GBACheatSetsGetPointer(&m_device->cheats, parent.row());
|
||||||
|
return StringListSize(&set->lines);
|
||||||
}
|
}
|
||||||
return GBACheatSetsSize(&m_device->cheats);
|
return GBACheatSetsSize(&m_device->cheats);
|
||||||
}
|
}
|
||||||
|
@ -90,15 +130,18 @@ GBACheatSet* CheatsModel::itemAt(const QModelIndex& index) {
|
||||||
if (!index.isValid()) {
|
if (!index.isValid()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return static_cast<GBACheatSet*>(index.internalPointer());
|
if (index.parent().isValid()) {
|
||||||
|
return static_cast<GBACheatSet*>(index.internalPointer());
|
||||||
|
}
|
||||||
|
return *GBACheatSetsGetPointer(&m_device->cheats, index.row());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatsModel::removeAt(const QModelIndex& index) {
|
void CheatsModel::removeAt(const QModelIndex& index) {
|
||||||
if (!index.isValid()) {
|
if (!index.isValid() || index.parent().isValid()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int row = index.row();
|
int row = index.row();
|
||||||
GBACheatSet* set = static_cast<GBACheatSet*>(index.internalPointer());
|
GBACheatSet* set = *GBACheatSetsGetPointer(&m_device->cheats, index.row());
|
||||||
beginRemoveRows(QModelIndex(), row, row);
|
beginRemoveRows(QModelIndex(), row, row);
|
||||||
GBACheatRemoveSet(m_device, set);
|
GBACheatRemoveSet(m_device, set);
|
||||||
GBACheatSetDeinit(set);
|
GBACheatSetDeinit(set);
|
||||||
|
@ -107,6 +150,18 @@ void CheatsModel::removeAt(const QModelIndex& index) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheatsModel::beginAppendRow(const QModelIndex& index) {
|
||||||
|
if (index.parent().isValid()) {
|
||||||
|
beginInsertRows(index.parent(), rowCount(index.parent()), rowCount(index.parent()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
beginInsertRows(index, rowCount(index), rowCount(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheatsModel::endAppendRow() {
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
|
||||||
void CheatsModel::loadFile(const QString& path) {
|
void CheatsModel::loadFile(const QString& path) {
|
||||||
VFile* vf = VFileOpen(path.toLocal8Bit().constData(), O_RDONLY);
|
VFile* vf = VFileOpen(path.toLocal8Bit().constData(), O_RDONLY);
|
||||||
if (!vf) {
|
if (!vf) {
|
||||||
|
@ -119,7 +174,7 @@ void CheatsModel::loadFile(const QString& path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatsModel::addSet(GBACheatSet* set) {
|
void CheatsModel::addSet(GBACheatSet* set) {
|
||||||
beginInsertRows(QModelIndex(), GBACheatSetsSize(&m_device->cheats), GBACheatSetsSize(&m_device->cheats) + 1);
|
beginInsertRows(QModelIndex(), GBACheatSetsSize(&m_device->cheats), GBACheatSetsSize(&m_device->cheats));
|
||||||
GBACheatAddSet(m_device, set);
|
GBACheatAddSet(m_device, set);
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,9 @@ public:
|
||||||
GBACheatSet* itemAt(const QModelIndex& index);
|
GBACheatSet* itemAt(const QModelIndex& index);
|
||||||
void removeAt(const QModelIndex& index);
|
void removeAt(const QModelIndex& index);
|
||||||
|
|
||||||
|
void beginAppendRow(const QModelIndex& index);
|
||||||
|
void endAppendRow();
|
||||||
|
|
||||||
void loadFile(const QString& path);
|
void loadFile(const QString& path);
|
||||||
void addSet(GBACheatSet* set);
|
void addSet(GBACheatSet* set);
|
||||||
|
|
||||||
|
|
|
@ -60,11 +60,13 @@ void CheatsView::addSet() {
|
||||||
void CheatsView::removeSet() {
|
void CheatsView::removeSet() {
|
||||||
GBACheatSet* set;
|
GBACheatSet* set;
|
||||||
QModelIndexList selection = m_ui.cheatList->selectionModel()->selectedIndexes();
|
QModelIndexList selection = m_ui.cheatList->selectionModel()->selectedIndexes();
|
||||||
if (selection.count() != 1) {
|
if (selection.count() < 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_controller->threadInterrupt();
|
m_controller->threadInterrupt();
|
||||||
m_model.removeAt(selection[0]);
|
for (const QModelIndex& index : selection) {
|
||||||
|
m_model.removeAt(selection[0]);
|
||||||
|
}
|
||||||
m_controller->threadContinue();
|
m_controller->threadContinue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +83,9 @@ void CheatsView::enterCheat(std::function<bool(GBACheatSet*, const char*)> callb
|
||||||
m_controller->threadInterrupt();
|
m_controller->threadInterrupt();
|
||||||
QStringList cheats = m_ui.codeEntry->toPlainText().split('\n', QString::SkipEmptyParts);
|
QStringList cheats = m_ui.codeEntry->toPlainText().split('\n', QString::SkipEmptyParts);
|
||||||
for (const QString& string : cheats) {
|
for (const QString& string : cheats) {
|
||||||
|
m_model.beginAppendRow(selection[0]);
|
||||||
callback(set, string.toLocal8Bit().constData());
|
callback(set, string.toLocal8Bit().constData());
|
||||||
|
m_model.endAppendRow();
|
||||||
}
|
}
|
||||||
m_controller->threadContinue();
|
m_controller->threadContinue();
|
||||||
m_ui.codeEntry->clear();
|
m_ui.codeEntry->clear();
|
||||||
|
|
|
@ -94,6 +94,9 @@
|
||||||
<property name="defaultDropAction">
|
<property name="defaultDropAction">
|
||||||
<enum>Qt::MoveAction</enum>
|
<enum>Qt::MoveAction</enum>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||||
|
</property>
|
||||||
<property name="headerHidden">
|
<property name="headerHidden">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
void NAME ## Shift(struct NAME* vector, size_t location, size_t difference); \
|
void NAME ## Shift(struct NAME* vector, size_t location, size_t difference); \
|
||||||
void NAME ## Unshift(struct NAME* vector, size_t location, size_t difference); \
|
void NAME ## Unshift(struct NAME* vector, size_t location, size_t difference); \
|
||||||
void NAME ## EnsureCapacity(struct NAME* vector, size_t capacity); \
|
void NAME ## EnsureCapacity(struct NAME* vector, size_t capacity); \
|
||||||
size_t NAME ## Size(struct NAME* vector); \
|
size_t NAME ## Size(const struct NAME* vector); \
|
||||||
|
|
||||||
#define DEFINE_VECTOR(NAME, TYPE) \
|
#define DEFINE_VECTOR(NAME, TYPE) \
|
||||||
void NAME ## Init(struct NAME* vector, size_t capacity) { \
|
void NAME ## Init(struct NAME* vector, size_t capacity) { \
|
||||||
|
@ -72,7 +72,7 @@
|
||||||
NAME ## Resize(vector, difference); \
|
NAME ## Resize(vector, difference); \
|
||||||
memmove(&vector->vector[location + difference], &vector->vector[location], (vector->size - location - difference) * sizeof(TYPE)); \
|
memmove(&vector->vector[location + difference], &vector->vector[location], (vector->size - location - difference) * sizeof(TYPE)); \
|
||||||
} \
|
} \
|
||||||
size_t NAME ## Size(struct NAME* vector) { \
|
size_t NAME ## Size(const struct NAME* vector) { \
|
||||||
return vector->size; \
|
return vector->size; \
|
||||||
} \
|
} \
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue