aboutsummaryrefslogtreecommitdiff
path: root/src/frontend/qt_sdl
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/qt_sdl')
-rw-r--r--src/frontend/qt_sdl/CheatsDialog.cpp357
-rw-r--r--src/frontend/qt_sdl/CheatsDialog.h33
-rw-r--r--src/frontend/qt_sdl/CheatsDialog.ui4
-rw-r--r--src/frontend/qt_sdl/PlatformConfig.cpp4
-rw-r--r--src/frontend/qt_sdl/PlatformConfig.h2
-rw-r--r--src/frontend/qt_sdl/main.cpp16
6 files changed, 408 insertions, 8 deletions
diff --git a/src/frontend/qt_sdl/CheatsDialog.cpp b/src/frontend/qt_sdl/CheatsDialog.cpp
index 2654e75..05fedc5 100644
--- a/src/frontend/qt_sdl/CheatsDialog.cpp
+++ b/src/frontend/qt_sdl/CheatsDialog.cpp
@@ -18,6 +18,7 @@
#include <stdio.h>
#include <QFileDialog>
+#include <QMessageBox>
#include "types.h"
#include "Platform.h"
@@ -32,30 +33,380 @@ CheatsDialog* CheatsDialog::currentDlg = nullptr;
extern char* EmuDirectory;
+namespace Frontend { extern ARCodeFile* CheatFile; }
+
CheatsDialog::CheatsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::CheatsDialog)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
- // setup UI here
+ codeFile = Frontend::CheatFile;
+
+ QStandardItemModel* model = new QStandardItemModel();
+ ui->tvCodeList->setModel(model);
+ connect(model, &QStandardItemModel::itemChanged, this, &CheatsDialog::onCheatEntryModified);
+ connect(ui->tvCodeList->selectionModel(), &QItemSelectionModel::selectionChanged, this, &CheatsDialog::onCheatSelectionChanged);
+
+ {
+ QStandardItem* root = model->invisibleRootItem();
+
+ for (ARCodeCatList::iterator i = codeFile->Categories.begin(); i != codeFile->Categories.end(); i++)
+ {
+ ARCodeCat& cat = *i;
+
+ QStandardItem* catitem = new QStandardItem(cat.Name);
+ catitem->setEditable(true);
+ catitem->setData(QVariant::fromValue(i));
+ root->appendRow(catitem);
+
+ for (ARCodeList::iterator j = cat.Codes.begin(); j != cat.Codes.end(); j++)
+ {
+ ARCode& code = *j;
+
+ QStandardItem* codeitem = new QStandardItem(code.Name);
+ codeitem->setEditable(true);
+ codeitem->setCheckable(true);
+ codeitem->setCheckState(code.Enabled ? Qt::Checked : Qt::Unchecked);
+ codeitem->setData(QVariant::fromValue(j));
+ catitem->appendRow(codeitem);
+ }
+ }
+ }
+
+ ui->txtCode->setPlaceholderText("");
+ codeChecker = new ARCodeChecker(ui->txtCode->document());
+
+ ui->btnNewARCode->setEnabled(false);
+ ui->btnDeleteCode->setEnabled(false);
+ ui->txtCode->setEnabled(false);
}
CheatsDialog::~CheatsDialog()
{
+ QAbstractItemModel* model = ui->tvCodeList->model();
+ ui->tvCodeList->setModel(nullptr);
+ delete model;
+
+ delete codeChecker;
+
delete ui;
}
void CheatsDialog::on_CheatsDialog_accepted()
{
- // save shit here
+ codeFile->Save();
closeDlg();
}
void CheatsDialog::on_CheatsDialog_rejected()
{
- // don't save shit here
+ codeFile->Load();
closeDlg();
}
+
+void CheatsDialog::on_btnNewCat_clicked()
+{
+ QStandardItem* root = ((QStandardItemModel*)ui->tvCodeList->model())->invisibleRootItem();
+
+ ARCodeCat cat;
+ cat.Codes.clear();
+ memset(cat.Name, 0, 128);
+ strncpy(cat.Name, "(new category)", 127);
+
+ codeFile->Categories.push_back(cat);
+ ARCodeCatList::iterator id = codeFile->Categories.end(); id--;
+
+ QStandardItem* catitem = new QStandardItem(cat.Name);
+ catitem->setEditable(true);
+ catitem->setData(QVariant::fromValue(id));
+ root->appendRow(catitem);
+
+ ui->tvCodeList->selectionModel()->select(catitem->index(), QItemSelectionModel::ClearAndSelect);
+ ui->tvCodeList->edit(catitem->index());
+}
+
+void CheatsDialog::on_btnNewARCode_clicked()
+{
+ QModelIndexList indices = ui->tvCodeList->selectionModel()->selectedIndexes();
+ if (indices.isEmpty())
+ {
+ // ????
+ return;
+ }
+
+ QStandardItemModel* model = (QStandardItemModel*)ui->tvCodeList->model();
+ QStandardItem* item = model->itemFromIndex(indices.first());
+ QStandardItem* parentitem;
+
+ QVariant data = item->data();
+ if (data.canConvert<ARCodeCatList::iterator>())
+ {
+ parentitem = item;
+ }
+ else if (data.canConvert<ARCodeList::iterator>())
+ {
+ parentitem = item->parent();
+ }
+ else
+ {
+ printf("what?? :(\n");
+ return;
+ }
+
+ ARCodeCatList::iterator it_cat = parentitem->data().value<ARCodeCatList::iterator>();
+ ARCodeCat& cat = *it_cat;
+
+ ARCode code;
+ memset(code.Name, 0, 128);
+ strncpy(code.Name, "(new AR code)", 127);
+ code.Enabled = true;
+ code.CodeLen = 0;
+ memset(code.Code, 0, sizeof(code.Code));
+
+ cat.Codes.push_back(code);
+ ARCodeList::iterator id = cat.Codes.end(); id--;
+
+ QStandardItem* codeitem = new QStandardItem(code.Name);
+ codeitem->setEditable(true);
+ codeitem->setCheckable(true);
+ codeitem->setCheckState(code.Enabled ? Qt::Checked : Qt::Unchecked);
+ codeitem->setData(QVariant::fromValue(id));
+ parentitem->appendRow(codeitem);
+
+ ui->tvCodeList->selectionModel()->select(codeitem->index(), QItemSelectionModel::ClearAndSelect);
+ ui->tvCodeList->edit(codeitem->index());
+}
+
+void CheatsDialog::on_btnDeleteCode_clicked()
+{
+ QModelIndexList indices = ui->tvCodeList->selectionModel()->selectedIndexes();
+ if (indices.isEmpty())
+ {
+ // ????
+ return;
+ }
+
+ QMessageBox::StandardButton res = QMessageBox::question(this,
+ "Confirm deletion",
+ "Really delete the selected item?",
+ QMessageBox::Yes|QMessageBox::No,
+ QMessageBox::No);
+ if (res != QMessageBox::Yes) return;
+
+ QStandardItemModel* model = (QStandardItemModel*)ui->tvCodeList->model();
+ QStandardItem* item = model->itemFromIndex(indices.first());
+
+ QVariant data = item->data();
+ if (data.canConvert<ARCodeCatList::iterator>())
+ {
+ ARCodeCatList::iterator it_cat = data.value<ARCodeCatList::iterator>();
+
+ (*it_cat).Codes.clear();
+ codeFile->Categories.erase(it_cat);
+
+ model->invisibleRootItem()->removeRow(item->row());
+ }
+ else if (data.canConvert<ARCodeList::iterator>())
+ {
+ ARCodeList::iterator it_code = data.value<ARCodeList::iterator>();
+ ARCodeCatList::iterator it_cat = item->parent()->data().value<ARCodeCatList::iterator>();
+
+ (*it_cat).Codes.erase(it_code);
+
+ item->parent()->removeRow(item->row());
+ }
+}
+
+void CheatsDialog::onCheatSelectionChanged(const QItemSelection& sel, const QItemSelection& desel)
+{
+ QModelIndexList indices = sel.indexes();
+ if (indices.isEmpty())
+ {
+ ui->btnNewARCode->setEnabled(false);
+ ui->btnDeleteCode->setEnabled(false);
+ ui->txtCode->setEnabled(false);
+ ui->txtCode->setPlaceholderText("");
+ ui->txtCode->clear();
+ }
+ else
+ {
+ QStandardItem* item = ((QStandardItemModel*)ui->tvCodeList->model())->itemFromIndex(indices.first());
+
+ QVariant data = item->data();
+ if (data.canConvert<ARCodeCatList::iterator>())
+ {
+ ui->btnDeleteCode->setEnabled(true);
+ ui->txtCode->setEnabled(false);
+ ui->txtCode->setPlaceholderText("");
+ ui->txtCode->clear();
+ }
+ else if (data.canConvert<ARCodeList::iterator>())
+ {
+ ARCode& code = *(data.value<ARCodeList::iterator>());
+
+ ui->btnDeleteCode->setEnabled(true);
+ ui->txtCode->setEnabled(true);
+ ui->txtCode->setPlaceholderText("(enter AR code here)");
+
+ QString codestr = "";
+ for (u32 i = 0; i < code.CodeLen; i += 2)
+ {
+ u32 c0 = code.Code[i+0];
+ u32 c1 = code.Code[i+1];
+ //codestr += QString("%1 %2\n").arg(c0, 8, 16, '0').arg(c1, 8, 16, '0').toUpper();
+ codestr += QString::asprintf("%08X %08X\n", c0, c1);
+ }
+ ui->txtCode->setPlainText(codestr);
+ }
+
+ ui->btnNewARCode->setEnabled(true);
+ }
+}
+
+void CheatsDialog::onCheatEntryModified(QStandardItem* item)
+{
+ QVariant data = item->data();
+ if (data.canConvert<ARCodeCatList::iterator>())
+ {
+ ARCodeCat& cat = *(data.value<ARCodeCatList::iterator>());
+
+ if (item->text().isEmpty())
+ {
+ QString oldname = QString(cat.Name);
+ item->setText(oldname.isEmpty() ? "(blank category name??)" : oldname);
+ }
+ else
+ {
+ strncpy(cat.Name, item->text().toStdString().c_str(), 127);
+ cat.Name[127] = '\0';
+ }
+ }
+ else if (data.canConvert<ARCodeList::iterator>())
+ {
+ ARCode& code = *(data.value<ARCodeList::iterator>());
+
+ if (item->text().isEmpty())
+ {
+ QString oldname = QString(code.Name);
+ item->setText(oldname.isEmpty() ? "(blank code name??)" : oldname);
+ }
+ else
+ {
+ strncpy(code.Name, item->text().toStdString().c_str(), 127);
+ code.Name[127] = '\0';
+ }
+
+ code.Enabled = (item->checkState() == Qt::Checked);
+ }
+}
+
+void CheatsDialog::on_txtCode_textChanged()
+{
+ QModelIndexList indices = ui->tvCodeList->selectionModel()->selectedIndexes();
+ if (indices.isEmpty())
+ return;
+
+ QStandardItem* item = ((QStandardItemModel*)ui->tvCodeList->model())->itemFromIndex(indices.first());
+ QVariant data = item->data();
+ if (!data.canConvert<ARCodeList::iterator>())
+ return;
+
+ bool error = false;
+ u32 codeout[2*64];
+ u32 codelen = 0;
+
+ QString text = ui->txtCode->document()->toPlainText();
+ QStringList lines = text.split('\n', QString::SkipEmptyParts);
+ for (QStringList::iterator it = lines.begin(); it != lines.end(); it++)
+ {
+ QString line = *it;
+ line = line.trimmed();
+ if (line.isEmpty()) continue;
+
+ if (line.length() > 17)
+ {
+ error = true;
+ break;
+ }
+
+ QStringList numbers = line.split(' ');
+ if (numbers.length() != 2)
+ {
+ error = true;
+ break;
+ }
+
+ QStringList::iterator jt = numbers.begin();
+ QString s0 = *jt++;
+ QString s1 = *jt++;
+
+ bool c0good, c1good;
+ u32 c0, c1;
+
+ c0 = s0.toUInt(&c0good, 16);
+ c1 = s1.toUInt(&c1good, 16);
+
+ if (!c0good || !c1good)
+ {
+ error = true;
+ break;
+ }
+
+ if (codelen >= 2*64)
+ {
+ error = true;
+ break;
+ }
+
+ codeout[codelen++] = c0;
+ codeout[codelen++] = c1;
+ }
+
+ ui->btnNewCat->setEnabled(!error);
+ ui->btnNewARCode->setEnabled(!error);
+ ui->btnDeleteCode->setEnabled(!error);
+ ui->tvCodeList->setEnabled(!error);
+ ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!error);
+
+ if (error) return;
+
+ ARCode& code = *(data.value<ARCodeList::iterator>());
+ memcpy(code.Code, codeout, codelen*sizeof(u32));
+ code.CodeLen = codelen;
+}
+
+void ARCodeChecker::highlightBlock(const QString& text)
+{
+ QTextCharFormat errformat; errformat.setForeground(Qt::red);
+
+ {
+ QRegularExpression expr("^\\s*[0-9A-Fa-f]{1,8} [0-9A-Fa-f]{1,8}\\s*$");
+ QRegularExpressionMatchIterator it = expr.globalMatch(text);
+ if (!it.hasNext())
+ {
+ setFormat(0, text.length(), errformat);
+ }
+ }
+
+ /*{
+ QRegularExpression expr("[^0-9A-Fa-f\\s]+");
+ QRegularExpressionMatchIterator it = expr.globalMatch(text);
+ while (it.hasNext())
+ {
+ QRegularExpressionMatch match = it.next();
+ setFormat(match.capturedStart(), match.capturedLength(), errformat);
+ }
+ }
+ {
+ QRegularExpression expr("[0-9A-Fa-f]{9,}");
+ QRegularExpressionMatchIterator it = expr.globalMatch(text);
+ while (it.hasNext())
+ {
+ QRegularExpressionMatch match = it.next();
+ setFormat(match.capturedStart(), match.capturedLength(), errformat);
+ }
+ }*/
+}
diff --git a/src/frontend/qt_sdl/CheatsDialog.h b/src/frontend/qt_sdl/CheatsDialog.h
index 99582c8..20f2c65 100644
--- a/src/frontend/qt_sdl/CheatsDialog.h
+++ b/src/frontend/qt_sdl/CheatsDialog.h
@@ -20,10 +20,31 @@
#define CHEATSDIALOG_H
#include <QDialog>
+#include <QAbstractItemModel>
+#include <QStandardItemModel>
+#include <QItemSelection>
+#include <QSyntaxHighlighter>
+
+#include "ARCodeFile.h"
+
+Q_DECLARE_METATYPE(ARCodeList::iterator)
+Q_DECLARE_METATYPE(ARCodeCatList::iterator)
namespace Ui { class CheatsDialog; }
class CheatsDialog;
+class ARCodeChecker : public QSyntaxHighlighter
+{
+ Q_OBJECT
+
+public:
+ ARCodeChecker(QTextDocument* parent) : QSyntaxHighlighter(parent) {}
+ ~ARCodeChecker() {}
+
+protected:
+ void highlightBlock(const QString& text) override;
+};
+
class CheatsDialog : public QDialog
{
Q_OBJECT
@@ -54,12 +75,20 @@ private slots:
void on_CheatsDialog_accepted();
void on_CheatsDialog_rejected();
- //
+ void on_btnNewCat_clicked();
+ void on_btnNewARCode_clicked();
+ void on_btnDeleteCode_clicked();
+
+ void onCheatSelectionChanged(const QItemSelection& sel, const QItemSelection& desel);
+ void onCheatEntryModified(QStandardItem* item);
+
+ void on_txtCode_textChanged();
private:
Ui::CheatsDialog* ui;
- //
+ ARCodeFile* codeFile;
+ ARCodeChecker* codeChecker;
};
#endif // CHEATSDIALOG_H
diff --git a/src/frontend/qt_sdl/CheatsDialog.ui b/src/frontend/qt_sdl/CheatsDialog.ui
index 493111d..d0bc586 100644
--- a/src/frontend/qt_sdl/CheatsDialog.ui
+++ b/src/frontend/qt_sdl/CheatsDialog.ui
@@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
- <string>AR cheat code editor - melonDS</string>
+ <string>Cheat code editor - melonDS</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
@@ -36,7 +36,7 @@
<item>
<widget class="QPushButton" name="btnDeleteCode">
<property name="text">
- <string>Delete code</string>
+ <string>Delete</string>
</property>
</widget>
</item>
diff --git a/src/frontend/qt_sdl/PlatformConfig.cpp b/src/frontend/qt_sdl/PlatformConfig.cpp
index bfb3f97..76c5f4b 100644
--- a/src/frontend/qt_sdl/PlatformConfig.cpp
+++ b/src/frontend/qt_sdl/PlatformConfig.cpp
@@ -72,6 +72,8 @@ char MicWavPath[1024];
char LastROMFolder[1024];
+int EnableCheats;
+
bool EnableJIT;
ConfigEntry PlatformConfigFile[] =
@@ -162,6 +164,8 @@ ConfigEntry PlatformConfigFile[] =
{"LastROMFolder", 1, LastROMFolder, 0, "", 1023},
+ {"EnableCheats", 0, &EnableCheats, 0, NULL, 0},
+
{"", -1, NULL, 0, NULL, 0}
};
diff --git a/src/frontend/qt_sdl/PlatformConfig.h b/src/frontend/qt_sdl/PlatformConfig.h
index 791bb07..bc9bba4 100644
--- a/src/frontend/qt_sdl/PlatformConfig.h
+++ b/src/frontend/qt_sdl/PlatformConfig.h
@@ -85,6 +85,8 @@ extern char MicWavPath[1024];
extern char LastROMFolder[1024];
+extern int EnableCheats;
+
}
#endif // PLATFORMCONFIG_H
diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp
index 903e654..f91f879 100644
--- a/src/frontend/qt_sdl/main.cpp
+++ b/src/frontend/qt_sdl/main.cpp
@@ -1067,6 +1067,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
menu->addSeparator();
actEnableCheats = menu->addAction("Enable cheats");
+ actEnableCheats->setCheckable(true);
connect(actEnableCheats, &QAction::triggered, this, &MainWindow::onEnableCheats);
actSetupCheats = menu->addAction("Setup cheat codes");
@@ -1218,6 +1219,10 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
actReset->setEnabled(false);
actStop->setEnabled(false);
+ actSetupCheats->setEnabled(false);
+
+
+ actEnableCheats->setChecked(Config::EnableCheats != 0);
actSavestateSRAMReloc->setChecked(Config::SavestateRelocSRAM != 0);
@@ -1662,7 +1667,8 @@ void MainWindow::onStop()
void MainWindow::onEnableCheats(bool checked)
{
- //
+ Config::EnableCheats = checked?1:0;
+ Frontend::EnableCheats(Config::EnableCheats != 0);
}
void MainWindow::onSetupCheats()
@@ -1881,6 +1887,8 @@ void MainWindow::onEmuStart()
actPause->setChecked(false);
actReset->setEnabled(true);
actStop->setEnabled(true);
+
+ actSetupCheats->setEnabled(true);
}
void MainWindow::onEmuStop()
@@ -1897,6 +1905,8 @@ void MainWindow::onEmuStop()
actPause->setEnabled(false);
actReset->setEnabled(false);
actStop->setEnabled(false);
+
+ actSetupCheats->setEnabled(false);
}
void MainWindow::onUpdateVideoSettings(bool glchange)
@@ -2028,6 +2038,8 @@ int main(int argc, char** argv)
micWavBuffer = nullptr;
Frontend::Init_ROM();
+ Frontend::EnableCheats(Config::EnableCheats != 0);
+
Frontend::Init_Audio(audioFreq);
if (Config::MicInputType == 1)
@@ -2084,6 +2096,8 @@ int main(int argc, char** argv)
Input::CloseJoystick();
+ Frontend::DeInit_ROM();
+
if (audioDevice) SDL_CloseAudioDevice(audioDevice);
if (micDevice) SDL_CloseAudioDevice(micDevice);