diff options
Diffstat (limited to 'src/frontend/qt_sdl')
-rw-r--r-- | src/frontend/qt_sdl/CheatsDialog.cpp | 357 | ||||
-rw-r--r-- | src/frontend/qt_sdl/CheatsDialog.h | 33 | ||||
-rw-r--r-- | src/frontend/qt_sdl/CheatsDialog.ui | 4 | ||||
-rw-r--r-- | src/frontend/qt_sdl/PlatformConfig.cpp | 4 | ||||
-rw-r--r-- | src/frontend/qt_sdl/PlatformConfig.h | 2 | ||||
-rw-r--r-- | src/frontend/qt_sdl/main.cpp | 16 |
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); |