diff options
Diffstat (limited to 'src/frontend/qt_sdl/CheatsDialog.cpp')
-rw-r--r-- | src/frontend/qt_sdl/CheatsDialog.cpp | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/src/frontend/qt_sdl/CheatsDialog.cpp b/src/frontend/qt_sdl/CheatsDialog.cpp new file mode 100644 index 0000000..05fedc5 --- /dev/null +++ b/src/frontend/qt_sdl/CheatsDialog.cpp @@ -0,0 +1,412 @@ +/* + Copyright 2016-2020 Arisotura + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#include <stdio.h> +#include <QFileDialog> +#include <QMessageBox> + +#include "types.h" +#include "Platform.h" +#include "Config.h" +#include "PlatformConfig.h" + +#include "CheatsDialog.h" +#include "ui_CheatsDialog.h" + + +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); + + 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() +{ + codeFile->Save(); + + closeDlg(); +} + +void CheatsDialog::on_CheatsDialog_rejected() +{ + 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); + } + }*/ +} |