diff --git a/cheats.h b/cheats.h index 9afee6df..54dd0889 100644 --- a/cheats.h +++ b/cheats.h @@ -81,6 +81,7 @@ int S9xModifyCheatGroup(uint32_t index, const std::string &name, const std::stri void S9xEnableCheatGroup(uint32_t index); void S9xDisableCheatGroup(uint32_t index); void S9xDeleteCheats(void); +std::string S9xCheatGroupToText(const SCheatGroup &g); std::string S9xCheatGroupToText(uint32_t index); void S9xDeleteCheatGroup(uint32_t index); bool8 S9xLoadCheatFile(const std::string &filename); diff --git a/cheats2.cpp b/cheats2.cpp index 95be454a..bd491d29 100644 --- a/cheats2.cpp +++ b/cheats2.cpp @@ -534,7 +534,7 @@ std::string S9xCheatToText(const SCheat &c) return std::string(output); } -std::string S9xCheatGroupToText(SCheatGroup &g) +std::string S9xCheatGroupToText(const SCheatGroup &g) { std::string text = ""; diff --git a/external/SPIRV-Cross b/external/SPIRV-Cross index 4e2fdb25..bccaa94d 160000 --- a/external/SPIRV-Cross +++ b/external/SPIRV-Cross @@ -1 +1 @@ -Subproject commit 4e2fdb25671c742a9fbe93a6034eb1542244c7e1 +Subproject commit bccaa94db814af33d8ef05c153e7c34d8bd4d685 diff --git a/external/glslang b/external/glslang index 3ebb72cc..9c7fd1a3 160000 --- a/external/glslang +++ b/external/glslang @@ -1 +1 @@ -Subproject commit 3ebb72cc7429f0ab8218104dc3687c659c0f364d +Subproject commit 9c7fd1a33e5cecbe465e1cd70170167d5e40d398 diff --git a/gtk/src/gtk_cheat.cpp b/gtk/src/gtk_cheat.cpp index 0aa8bf72..aaec629f 100644 --- a/gtk/src/gtk_cheat.cpp +++ b/gtk/src/gtk_cheat.cpp @@ -94,7 +94,6 @@ Snes9xCheats::Snes9xCheats() get_object("disable_all_button")->signal_clicked().connect(sigc::mem_fun(*this, &Snes9xCheats::disable_all)); get_object("delete_all_cheats_button")->signal_clicked().connect(sigc::mem_fun(*this, &Snes9xCheats::delete_all_cheats)); get_object("cheat_search_button")->signal_clicked().connect(sigc::mem_fun(*this, &Snes9xCheats::search_database)); - get_object("update_button")->signal_clicked().connect(sigc::mem_fun(*this, &Snes9xCheats::update_code)); gtk_widget_realize(GTK_WIDGET(window->gobj())); } @@ -288,7 +287,9 @@ void Snes9xCheats::search_database() for (const auto &dir : { S9xGetDirectory(CHEAT_DIR), get_config_dir(), - std::string(DATADIR) }) + std::string(DATADIR), + "/usr/share/snes9x", + "/usr/local/share/snes9x" }) { filename = dir + "/cheats.bml"; result = S9xImportCheatsFromDatabase(filename); diff --git a/qt/src/CheatsDialog.cpp b/qt/src/CheatsDialog.cpp index 6a922796..190e28ce 100644 --- a/qt/src/CheatsDialog.cpp +++ b/qt/src/CheatsDialog.cpp @@ -1,27 +1,202 @@ -#include "CheatsDialog.hpp" - -static const auto desired_flags = Qt::ItemFlag::ItemIsUserCheckable | - Qt::ItemFlag::ItemIsEnabled | - Qt::ItemFlag::ItemIsSelectable | - Qt::ItemFlag::ItemIsDragEnabled; - -CheatsDialog::CheatsDialog(QWidget *parent, EmuApplication *app_) - : app(app_), QDialog(parent) -{ - setupUi(this); - show(); - - QTreeWidgetItem *item = new QTreeWidgetItem(); - item->setFlags(desired_flags); - item->setCheckState(0, Qt::CheckState::Checked); - item->setText(1, "Invincibility"); - item->setText(2, "dd32-6dad"); - - treeWidget_cheats->insertTopLevelItem(0, item); - item = new QTreeWidgetItem(); - item->setFlags(desired_flags); - item->setCheckState(0, Qt::CheckState::Checked); - item->setText(1, "Torzx"); - item->setText(2, "7e0fff:ff\n7e0ff7:ff"); - treeWidget_cheats->insertTopLevelItem(1, item); +#include "CheatsDialog.hpp" +#include "EmuApplication.hpp" +#include "EmuConfig.hpp" +#include "../cheats.h" +#include "fscompat.h" + +#include +#include +#include + +extern SCheatData Cheat; +auto &clist = Cheat.group; + +static const auto desired_flags = Qt::ItemFlag::ItemIsUserCheckable | + Qt::ItemFlag::ItemIsEnabled | + Qt::ItemFlag::ItemIsSelectable | + Qt::ItemFlag::ItemIsDragEnabled; + +CheatsDialog::CheatsDialog(QWidget *parent, EmuApplication *app_) + : app(app_), QDialog(parent) +{ + setupUi(this); + + connect(pushButton_add, &QPushButton::clicked, [&] { addCode(); }); + connect(pushButton_remove, &QPushButton::clicked, [&] { removeCode(); }); + connect(pushButton_remove_all, &QPushButton::clicked, [&] { removeAll(); }); + connect(pushButton_check_database, &QPushButton::clicked, [&] { searchDatabase(); }); + connect(pushButton_update, &QPushButton::clicked, [&] { updateCurrent(); }); + + treeWidget_cheats->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + + connect(treeWidget_cheats, &QTreeWidget::itemChanged, [&](QTreeWidgetItem *item, int column) { + if (column != 0) + return; + + auto index = treeWidget_cheats->indexOfTopLevelItem(item); + + app->suspendThread(); + if (item->checkState(0) == Qt::Checked) + S9xEnableCheatGroup(index); + else + S9xDisableCheatGroup(index); + app->unsuspendThread(); + }); + + connect(treeWidget_cheats, &QTreeWidget::itemDoubleClicked, [&](QTreeWidgetItem *item, int column) { + lineEdit_description->setText(item->text(1)); + lineEdit_code->setText(item->text(2)); + }); + + if (app->config->cheat_dialog_width != 0) + resize(app->config->cheat_dialog_width, app->config->cheat_dialog_height); + + show(); +} + +void CheatsDialog::showEvent(QShowEvent *event) +{ + refreshList(); + QDialog::showEvent(event); +} + +void CheatsDialog::addCode() +{ + auto description = lineEdit_description->text().toStdString(); + auto code = lineEdit_code->text().toStdString(); + + if (description.empty()) + description = tr("No description").toStdString(); + + if (S9xAddCheatGroup(description, code) < 0) + { + QMessageBox::information(this, tr("Invalid Cheat"), tr("The cheat you entered was not valid.")); + return; + } + + refreshList(); + treeWidget_cheats->setTreePosition(treeWidget_cheats->topLevelItemCount() - 1); +} + +void CheatsDialog::removeCode() +{ + if (!treeWidget_cheats->currentIndex().isValid()) + return; + + auto index = treeWidget_cheats->currentIndex().row(); + app->suspendThread(); + S9xDeleteCheatGroup(index); + app->unsuspendThread(); + auto item = treeWidget_cheats->takeTopLevelItem(index); + if (item) + delete item; +} + +void CheatsDialog::disableAll() +{ + app->suspendThread(); + for (size_t i = 0; i < clist.size(); i++) + S9xDisableCheatGroup(i); + app->unsuspendThread(); + refreshList(); +} + +void CheatsDialog::removeAll() +{ + treeWidget_cheats->clear(); + app->suspendThread(); + S9xDeleteCheats(); + app->unsuspendThread(); +} + +void CheatsDialog::searchDatabase() +{ + std::initializer_list dirs = + { + EmuConfig::findConfigDir(), + QGuiApplication::applicationDirPath().toStdString(), + S9xGetDirectory(CHEAT_DIR), + "/usr/share/snes9x", + "/usr/local/share/snes9x" + }; + + bool found = false; + + for (auto &path : dirs) + { + auto filename = QDir(QString::fromStdString(path)).absoluteFilePath("cheats.bml").toStdString(); + app->suspendThread(); + auto result = S9xImportCheatsFromDatabase(filename); + app->unsuspendThread(); + if (result == 0) + { + refreshList(); + return; + } + + if (result == -1) + continue; + + if (result == -2) + { + QMessageBox::information(this, tr("No Cheats Found"), tr("No cheats for the current game were found in the database.")); + return; + } + } + + QMessageBox::information(this, tr("Unable to Open Cheats Database"), tr("cheats.bml was not found.")); +} + +void CheatsDialog::updateCurrent() +{ + if (!treeWidget_cheats->currentIndex().isValid()) + return; + + auto description = lineEdit_description->text().toStdString(); + auto code = lineEdit_code->text().toStdString(); + auto index = treeWidget_cheats->currentIndex().row(); + + if (description.empty()) + description = tr("No description").toStdString(); + + auto validated = S9xCheatValidate(code); + if (validated.empty()) + { + QMessageBox::information(this, tr("Invalid Cheat"), tr("The cheat you entered was not valid.")); + return; + } + + app->suspendThread(); + S9xModifyCheatGroup(index, description, validated); + app->unsuspendThread(); + + treeWidget_cheats->currentItem()->setText(1, lineEdit_description->text()); + treeWidget_cheats->currentItem()->setText(2, QString::fromStdString(validated)); +} + +void CheatsDialog::refreshList() +{ + treeWidget_cheats->clear(); + + QList items; + + app->suspendThread(); + for (const auto &c: clist) + { + auto i = new QTreeWidgetItem(); + i->setFlags(desired_flags); + i->setCheckState(0, c.enabled ? Qt::Checked : Qt::Unchecked); + i->setText(1, QString::fromStdString(c.name)); + i->setText(2, QString::fromStdString(S9xCheatGroupToText(c))); + items.push_back(i); + } + app->unsuspendThread(); + + treeWidget_cheats->insertTopLevelItems(0, items); +} + +void CheatsDialog::resizeEvent(QResizeEvent *event) +{ + app->config->cheat_dialog_width = event->size().width(); + app->config->cheat_dialog_height = event->size().height(); } \ No newline at end of file diff --git a/qt/src/CheatsDialog.hpp b/qt/src/CheatsDialog.hpp index 3bd5f836..4773b3d8 100644 --- a/qt/src/CheatsDialog.hpp +++ b/qt/src/CheatsDialog.hpp @@ -1,12 +1,20 @@ -#include "ui_CheatsDialog.h" - -class EmuApplication; - -class CheatsDialog : public QDialog, public Ui_Dialog -{ - public: - CheatsDialog(QWidget *parent, EmuApplication *app); - - EmuApplication *app; -}; - +#include "ui_CheatsDialog.h" + +class EmuApplication; + +class CheatsDialog : public QDialog, public Ui_Dialog +{ + public: + CheatsDialog(QWidget *parent, EmuApplication *app); + void addCode(); + void removeCode(); + void updateCurrent(); + void disableAll(); + void removeAll(); + void searchDatabase(); + void refreshList(); + void showEvent(QShowEvent *) override; + EmuApplication *app; + void resizeEvent(QResizeEvent *event) override; +}; + diff --git a/qt/src/EmuApplication.cpp b/qt/src/EmuApplication.cpp index 99f832a2..0455edfe 100644 --- a/qt/src/EmuApplication.cpp +++ b/qt/src/EmuApplication.cpp @@ -246,6 +246,7 @@ void EmuApplication::startThread() bool EmuApplication::openFile(std::string filename) { + window->gameChanging(); suspendThread(); auto result = core->openFile(filename); unsuspendThread(); diff --git a/qt/src/EmuConfig.cpp b/qt/src/EmuConfig.cpp index 96ea2822..36c04212 100644 --- a/qt/src/EmuConfig.cpp +++ b/qt/src/EmuConfig.cpp @@ -417,6 +417,11 @@ void EmuConfig::config(std::string filename, bool write) String("LastROMFolder", last_rom_folder); Int("MainWindowWidth", main_window_width); Int("MainWindowHeight", main_window_height); + Int("ShaderParametersDialogWidth", shader_parameters_dialog_width); + Int("ShaderParametersDialogHeight", shader_parameters_dialog_height); + Int("CheatDialogWidth", cheat_dialog_width); + Int("CheatDialogHeight", cheat_dialog_height); + int recent_count = recently_used.size(); Int("RecentlyUsedEntries", recent_count); if (!write) diff --git a/qt/src/EmuConfig.hpp b/qt/src/EmuConfig.hpp index 01ab6adb..7a05f58d 100644 --- a/qt/src/EmuConfig.hpp +++ b/qt/src/EmuConfig.hpp @@ -31,6 +31,10 @@ struct EmuConfig std::string last_rom_folder; int main_window_width = 0; int main_window_height = 0; + int cheat_dialog_width = 0; + int cheat_dialog_height = 0; + int shader_parameters_dialog_width = 0; + int shader_parameters_dialog_height = 0; std::vector recently_used; // General diff --git a/qt/src/EmuMainWindow.cpp b/qt/src/EmuMainWindow.cpp index bf29e04f..d0edde0d 100644 --- a/qt/src/EmuMainWindow.cpp +++ b/qt/src/EmuMainWindow.cpp @@ -18,7 +18,6 @@ #include "EmuCanvasOpenGL.hpp" #include "EmuCanvasQt.hpp" #include "CheatsDialog.hpp" -#include "ShaderParametersDialog.hpp" #undef KeyPress static EmuSettingsWindow *g_emu_settings_window = nullptr; @@ -265,7 +264,9 @@ void EmuMainWindow::createWidgets() auto cheats_item = emulation_menu->addAction(tr("&Cheats")); connect(cheats_item, &QAction::triggered, [&] { - auto cheats_dialog = new CheatsDialog(this, app); + if (!cheats_dialog) + cheats_dialog = std::make_unique(this, app); + cheats_dialog->show(); }); core_actions.push_back(cheats_item); @@ -662,4 +663,10 @@ void EmuMainWindow::shaderChanged() if (canvas) canvas->shaderChanged(); }); +} + +void EmuMainWindow::gameChanging() +{ + if (cheats_dialog) + cheats_dialog->close(); } \ No newline at end of file diff --git a/qt/src/EmuMainWindow.hpp b/qt/src/EmuMainWindow.hpp index 97756668..23cbc169 100644 --- a/qt/src/EmuMainWindow.hpp +++ b/qt/src/EmuMainWindow.hpp @@ -6,6 +6,7 @@ #include "EmuCanvas.hpp" class EmuApplication; +class CheatsDialog; class EmuMainWindow : public QMainWindow { @@ -35,6 +36,7 @@ class EmuMainWindow : public QMainWindow bool openFile(std::string filename); void recreateUIAssets(); void shaderChanged(); + void gameChanging(); std::vector getDisplayDeviceList(); EmuApplication *app; EmuCanvas *canvas; @@ -46,6 +48,8 @@ class EmuMainWindow : public QMainWindow static const size_t recent_menu_size = 10; static const size_t state_items_size = 10; + std::unique_ptr cheats_dialog; + bool manual_pause = false; bool focus_pause = false; bool minimized_pause = false; diff --git a/qt/src/ShaderParametersDialog.cpp b/qt/src/ShaderParametersDialog.cpp index 830d056b..00b7595d 100644 --- a/qt/src/ShaderParametersDialog.cpp +++ b/qt/src/ShaderParametersDialog.cpp @@ -7,6 +7,7 @@ #include #include #include +#include static bool is_simple(const EmuCanvas::Parameter &p) { @@ -129,6 +130,9 @@ ShaderParametersDialog::ShaderParametersDialog(EmuCanvas *parent_, std::vectorsetWidget(scroll_area_widget_contents); layout->addWidget(scroll_area); layout->addLayout(buttonbox, 0); + + if (config->shader_parameters_dialog_width != 0) + resize(config->shader_parameters_dialog_width, config->shader_parameters_dialog_height); } void ShaderParametersDialog::save() @@ -197,6 +201,12 @@ void ShaderParametersDialog::closeEvent(QCloseEvent *event) *parameters = saved_parameters; } +void ShaderParametersDialog::resizeEvent(QResizeEvent *event) +{ + config->shader_parameters_dialog_width = event->size().width(); + config->shader_parameters_dialog_height = event->size().height(); +} + ShaderParametersDialog::~ShaderParametersDialog() { } \ No newline at end of file diff --git a/qt/src/ShaderParametersDialog.hpp b/qt/src/ShaderParametersDialog.hpp index ee65bf5e..871e32db 100644 --- a/qt/src/ShaderParametersDialog.hpp +++ b/qt/src/ShaderParametersDialog.hpp @@ -16,6 +16,7 @@ class ShaderParametersDialog : public QDialog void refreshWidgets(); void showEvent(QShowEvent *event) override; void closeEvent(QCloseEvent *event) override; + void resizeEvent(QResizeEvent *event) override; void save(); void saveAs();