From b60e54c07c3c34eea6f911882720c05869f3e8e2 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Thu, 8 Feb 2024 16:00:55 -0500 Subject: [PATCH 1/7] Close subwindows gracefully, prompt save on quit --- include/editor.h | 2 +- include/mainwindow.h | 7 +- src/editor.cpp | 9 ++- src/mainwindow.cpp | 150 +++++++++++++++++++++--------------- src/ui/mapimageexporter.cpp | 1 + src/ui/newmappopup.cpp | 1 + src/ui/regionmapeditor.cpp | 1 + src/ui/tileseteditor.cpp | 1 + 8 files changed, 100 insertions(+), 72 deletions(-) diff --git a/include/editor.h b/include/editor.h index f684b491..837b267c 100644 --- a/include/editor.h +++ b/include/editor.h @@ -43,7 +43,7 @@ public: public: Ui::MainWindow* ui; QObject *parent = nullptr; - Project *project = nullptr; + QPointer project = nullptr; Map *map = nullptr; Settings *settings; void saveProject(); diff --git a/include/mainwindow.h b/include/mainwindow.h index 6f969eba..5dc6b124 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -295,7 +295,7 @@ private slots: public: Ui::MainWindow *ui; - Editor *editor = nullptr; + QPointer editor = nullptr; private: QLabel *label_MapRulerStatus = nullptr; @@ -331,7 +331,6 @@ private: bool isProgrammaticEventTabChange; bool projectHasUnsavedChanges; - bool projectOpenFailure = false; bool newMapDefaultsSet = false; MapSortOrder mapSortOrder; @@ -348,7 +347,9 @@ private: void openSubWindow(QWidget * window); QString getExistingDirectory(QString); bool openProject(const QString &dir, bool initial = false); + bool closeProject(); void showProjectOpenFailure(); + void saveGlobalConfigs(); bool setInitialMap(); void setRecentMap(QString map_name); QStandardItem* createMapItem(QString mapName, int groupNum, int inGroupNum); @@ -379,7 +380,7 @@ private: void setTheme(QString); void updateTilesetEditor(); Event::Group getEventGroupFromTabWidget(QWidget *tab); - void closeSupplementaryWindows(); + bool closeSupplementaryWindows(); void setWindowDisabled(bool); void initTilesetEditor(); diff --git a/src/editor.cpp b/src/editor.cpp index 014fa489..a2e4f3f9 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -79,10 +79,11 @@ void Editor::saveUiFields() { } void Editor::closeProject() { - if (this->project) { - delete this->project; - this->project = nullptr; - } + if (!this->project) + return; + + Scripting::cb_ProjectClosed(this->project->root); + delete this->project; } void Editor::setEditingMap() { diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index f7e0dee1..beddb7ec 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -71,6 +71,7 @@ MainWindow::MainWindow(QWidget *parent) : MainWindow::~MainWindow() { delete label_MapRulerStatus; + delete editor; delete ui; } @@ -477,8 +478,12 @@ void MainWindow::setTheme(QString theme) { } bool MainWindow::openProject(const QString &dir, bool initial) { + if (!this->closeProject()) { + logInfo("Aborted project open."); + return false; + } + if (dir.isNull() || dir.length() <= 0) { - projectOpenFailure = true; if (!initial) setWindowDisabled(true); return false; } @@ -486,7 +491,6 @@ bool MainWindow::openProject(const QString &dir, bool initial) { const QString projectString = QString("%1project '%2'").arg(initial ? "recent " : "").arg(QDir::toNativeSeparators(dir)); if (!QDir(dir).exists()) { - projectOpenFailure = true; const QString errorMsg = QString("Failed to open %1: No such directory").arg(projectString); this->statusBar()->showMessage(errorMsg); if (initial) { @@ -503,43 +507,30 @@ bool MainWindow::openProject(const QString &dir, bool initial) { this->statusBar()->showMessage(openMessage); logInfo(openMessage); + // TODO: Don't save these yet userConfig.setProjectDir(dir); userConfig.load(); projectConfig.setProjectDir(dir); projectConfig.load(); - this->closeSupplementaryWindows(); this->newMapDefaultsSet = false; - if (isProjectOpen()) - Scripting::cb_ProjectClosed(editor->project->root); Scripting::init(this); - bool already_open = isProjectOpen() && (editor->project->root == dir); - if (!already_open) { - editor->closeProject(); - editor->project = new Project(this); - QObject::connect(editor->project, &Project::reloadProject, this, &MainWindow::on_action_Reload_Project_triggered); - QObject::connect(editor->project, &Project::mapCacheCleared, this, &MainWindow::onMapCacheCleared); - QObject::connect(editor->project, &Project::uncheckMonitorFilesAction, [this]() { - porymapConfig.setMonitorFiles(false); - if (this->preferenceEditor) - this->preferenceEditor->updateFields(); - }); - editor->project->set_root(dir); - } else { - editor->project->fileWatcher.removePaths(editor->project->fileWatcher.files()); - editor->project->clearMapCache(); - editor->project->clearTilesetCache(); - } + this->editor->project = new Project(this); + QObject::connect(this->editor->project, &Project::reloadProject, this, &MainWindow::on_action_Reload_Project_triggered); + QObject::connect(this->editor->project, &Project::mapCacheCleared, this, &MainWindow::onMapCacheCleared); + QObject::connect(this->editor->project, &Project::uncheckMonitorFilesAction, [this]() { + porymapConfig.setMonitorFiles(false); + if (this->preferenceEditor) + this->preferenceEditor->updateFields(); + }); + this->editor->project->set_root(dir); - this->projectOpenFailure = !(loadDataStructures() - && populateMapList() - && setInitialMap()); - - if (this->projectOpenFailure) { + if (!(loadDataStructures() && populateMapList() && setInitialMap())) { this->statusBar()->showMessage(QString("Failed to open %1").arg(projectString)); showProjectOpenFailure(); + delete this->editor->project; return false; } @@ -568,7 +559,7 @@ void MainWindow::showProjectOpenFailure() { } bool MainWindow::isProjectOpen() { - return !projectOpenFailure && editor && editor->project; + return editor && editor->project; } bool MainWindow::setInitialMap() { @@ -1228,12 +1219,10 @@ void MainWindow::openNewMapPopupWindow() { } if (!this->newMapPrompt) { this->newMapPrompt = new NewMapPopup(this, this->editor->project); + connect(this->newMapPrompt, &NewMapPopup::applied, this, &MainWindow::onNewMapCreated); } openSubWindow(this->newMapPrompt); - - connect(this->newMapPrompt, &NewMapPopup::applied, this, &MainWindow::onNewMapCreated); - this->newMapPrompt->setAttribute(Qt::WA_DeleteOnClose); } void MainWindow::on_action_NewMap_triggered() { @@ -1751,11 +1740,6 @@ void MainWindow::on_mapViewTab_tabBarClicked(int index) editor->setCursorRectVisible(false); } -void MainWindow::on_action_Exit_triggered() -{ - QApplication::quit(); -} - void MainWindow::on_mainTabBar_tabBarClicked(int index) { int oldIndex = ui->mainTabBar->currentIndex(); @@ -2486,11 +2470,8 @@ void MainWindow::importMapFromAdvanceMap1_92() void MainWindow::showExportMapImageWindow(ImageExporterMode mode) { if (!editor->project) return; - if (this->mapImageExporter) - delete this->mapImageExporter; - - this->mapImageExporter = new MapImageExporter(this, this->editor, mode); - this->mapImageExporter->setAttribute(Qt::WA_DeleteOnClose); + if (!this->mapImageExporter) + this->mapImageExporter = new MapImageExporter(this, this->editor, mode); openSubWindow(this->mapImageExporter); } @@ -2923,36 +2904,59 @@ bool MainWindow::initRegionMapEditor(bool silent) { return true; } -void MainWindow::closeSupplementaryWindows() { - delete this->tilesetEditor; - delete this->regionMapEditor; - delete this->mapImageExporter; - delete this->newMapPrompt; - delete this->shortcutsEditor; - delete this->customScriptsEditor; +// Attempt to close any open sub-windows of the main window, giving each a chance to abort the process. +// Each of these are expected to be a QPointer to a widget with WA_DeleteOnClose set, so manually deleting +// and nullifying the pointer members is not necessary here. +// TODO: Testing +bool MainWindow::closeSupplementaryWindows() { + if (this->tilesetEditor && !this->tilesetEditor->close()) + return false; + if (this->regionMapEditor && !this->regionMapEditor->close()) + return false; + if (this->mapImageExporter && !this->mapImageExporter->close()) + return false; + if (this->newMapPrompt && !this->newMapPrompt->close()) + return false; + if (this->shortcutsEditor && !this->shortcutsEditor->close()) + return false; + if (this->preferenceEditor && !this->preferenceEditor->close()) + return false; + if (this->customScriptsEditor && !this->customScriptsEditor->close()) + return false; if (this->projectSettingsEditor) this->projectSettingsEditor->closeQuietly(); + + return true; } -void MainWindow::closeEvent(QCloseEvent *event) { - if (isProjectOpen()) { - if (projectHasUnsavedChanges || (editor->map && editor->map->hasUnsavedChanges())) { - QMessageBox::StandardButton result = QMessageBox::question( - this, "porymap", "The project has been modified, save changes?", - QMessageBox::No | QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); +bool MainWindow::closeProject() { + if (!closeSupplementaryWindows()) + return false; - if (result == QMessageBox::Yes) { - editor->saveProject(); - } else if (result == QMessageBox::No) { - logWarn("Closing porymap with unsaved changes."); - } else if (result == QMessageBox::Cancel) { - event->ignore(); - return; - } + if (!isProjectOpen()) + return true; + + if (projectHasUnsavedChanges || (editor->map && editor->map->hasUnsavedChanges())) { + QMessageBox::StandardButton result = QMessageBox::question( + this, "porymap", "The project has been modified, save changes?", + QMessageBox::No | QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); + + if (result == QMessageBox::Yes) { + editor->saveProject(); + } else if (result == QMessageBox::No) { + logWarn("Closing project with unsaved changes."); + } else if (result == QMessageBox::Cancel) { + return false; } - projectConfig.save(); - userConfig.save(); } + projectConfig.save(); + userConfig.save(); + editor->closeProject(); + + return true; +} + +void MainWindow::saveGlobalConfigs() { porymapConfig.setMainGeometry( this->saveGeometry(), this->saveState(), @@ -2962,6 +2966,24 @@ void MainWindow::closeEvent(QCloseEvent *event) { ); porymapConfig.save(); shortcutsConfig.save(); +} + +void MainWindow::on_action_Exit_triggered() { + if (!closeProject()) + return; + + saveGlobalConfigs(); + + QApplication::quit(); +} + +void MainWindow::closeEvent(QCloseEvent *event) { + if (!closeProject()) { + event->ignore(); + return; + } + + saveGlobalConfigs(); QMainWindow::closeEvent(event); } diff --git a/src/ui/mapimageexporter.cpp b/src/ui/mapimageexporter.cpp index 099f2288..e36d9606 100644 --- a/src/ui/mapimageexporter.cpp +++ b/src/ui/mapimageexporter.cpp @@ -27,6 +27,7 @@ MapImageExporter::MapImageExporter(QWidget *parent_, Editor *editor_, ImageExpor QDialog(parent_), ui(new Ui::MapImageExporter) { + this->setAttribute(Qt::WA_DeleteOnClose); ui->setupUi(this); this->map = editor_->map; this->editor = editor_; diff --git a/src/ui/newmappopup.cpp b/src/ui/newmappopup.cpp index 2c4141bc..fdc3f79c 100644 --- a/src/ui/newmappopup.cpp +++ b/src/ui/newmappopup.cpp @@ -14,6 +14,7 @@ NewMapPopup::NewMapPopup(QWidget *parent, Project *project) : QMainWindow(parent), ui(new Ui::NewMapPopup) { + this->setAttribute(Qt::WA_DeleteOnClose); ui->setupUi(this); this->project = project; this->existingLayout = false; diff --git a/src/ui/regionmapeditor.cpp b/src/ui/regionmapeditor.cpp index 220f9cca..318bc517 100644 --- a/src/ui/regionmapeditor.cpp +++ b/src/ui/regionmapeditor.cpp @@ -26,6 +26,7 @@ RegionMapEditor::RegionMapEditor(QWidget *parent, Project *project) : QMainWindow(parent), ui(new Ui::RegionMapEditor) { + this->setAttribute(Qt::WA_DeleteOnClose); this->ui->setupUi(this); this->project = project; this->initShortcuts(); diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp index 4813790a..bd233974 100644 --- a/src/ui/tileseteditor.cpp +++ b/src/ui/tileseteditor.cpp @@ -20,6 +20,7 @@ TilesetEditor::TilesetEditor(Project *project, Map *map, QWidget *parent) : map(map), hasUnsavedChanges(false) { + this->setAttribute(Qt::WA_DeleteOnClose); this->setTilesets(this->map->layout->tileset_primary_label, this->map->layout->tileset_secondary_label); this->initUi(); } From db598a43db682ca84015f9e89f4f39456dd4dc09 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Mon, 15 Jul 2024 16:14:38 -0400 Subject: [PATCH 2/7] Write config files on close / save, not on modification --- include/config.h | 277 ++++-------- include/mainwindow.h | 1 - include/project.h | 1 + src/config.cpp | 750 +++---------------------------- src/core/block.cpp | 6 +- src/core/events.cpp | 26 +- src/core/heallocation.cpp | 2 +- src/core/map.cpp | 4 +- src/core/metatile.cpp | 10 +- src/core/metatileparser.cpp | 2 +- src/core/network.cpp | 16 +- src/core/tileset.cpp | 10 +- src/editor.cpp | 22 +- src/mainwindow.cpp | 111 +++-- src/project.cpp | 128 +++--- src/scriptapi/apimap.cpp | 6 +- src/ui/citymappixmapitem.cpp | 4 +- src/ui/customscriptseditor.cpp | 4 +- src/ui/eventframes.cpp | 16 +- src/ui/imageproviders.cpp | 3 +- src/ui/newmappopup.cpp | 12 +- src/ui/newtilesetdialog.cpp | 4 +- src/ui/paletteeditor.cpp | 4 +- src/ui/prefab.cpp | 21 +- src/ui/preferenceeditor.cpp | 28 +- src/ui/projectsettingseditor.cpp | 166 ++++--- src/ui/regionmapeditor.cpp | 4 +- src/ui/shortcutseditor.cpp | 1 + src/ui/tileseteditor.cpp | 30 +- src/ui/updatepromoter.cpp | 9 +- 30 files changed, 458 insertions(+), 1220 deletions(-) diff --git a/include/config.h b/include/config.h index 54398cca..89a27d24 100644 --- a/include/config.h +++ b/include/config.h @@ -33,20 +33,17 @@ class KeyValueConfigBase public: void save(); void load(); - void setSaveDisabled(bool disabled); virtual ~KeyValueConfigBase(); virtual void reset() = 0; protected: virtual QString getConfigFilepath() = 0; virtual void parseConfigKeyValue(QString key, QString value) = 0; virtual QMap getKeyValueMap() = 0; - virtual void onNewConfigFileCreated() = 0; + virtual void init() = 0; virtual void setUnreadKeys() = 0; bool getConfigBool(QString key, QString value); int getConfigInteger(QString key, QString value, int min = INT_MIN, int max = INT_MAX, int defaultValue = 0); uint32_t getConfigUint32(QString key, QString value, uint32_t min = 0, uint32_t max = UINT_MAX, uint32_t defaultValue = 0); -private: - bool saveDisabled = false; }; class PorymapConfig: public KeyValueConfigBase @@ -86,101 +83,24 @@ public: } void addRecentProject(QString project); void setRecentProjects(QStringList projects); - void setReopenOnLaunch(bool enabled); - void setMapSortOrder(MapSortOrder order); - void setPrettyCursors(bool enabled); + QString getRecentProject(); + QStringList getRecentProjects(); void setMainGeometry(QByteArray, QByteArray, QByteArray, QByteArray, QByteArray); void setTilesetEditorGeometry(QByteArray, QByteArray, QByteArray); void setPaletteEditorGeometry(QByteArray, QByteArray); void setRegionMapEditorGeometry(QByteArray, QByteArray); void setProjectSettingsEditorGeometry(QByteArray, QByteArray); void setCustomScriptsEditorGeometry(QByteArray, QByteArray); - void setCollisionOpacity(int opacity); - void setCollisionZoom(int zoom); - void setMetatilesZoom(int zoom); - void setTilesetEditorMetatilesZoom(int zoom); - void setTilesetEditorTilesZoom(int zoom); - void setShowPlayerView(bool enabled); - void setShowCursorTile(bool enabled); - void setShowBorder(bool enabled); - void setShowGrid(bool enabled); - void setShowTilesetEditorMetatileGrid(bool enabled); - void setShowTilesetEditorLayerGrid(bool enabled); - void setMonitorFiles(bool monitor); - void setTilesetCheckerboardFill(bool checkerboard); - void setTheme(QString theme); - void setTextEditorOpenFolder(const QString &command); - void setTextEditorGotoLine(const QString &command); - void setPaletteEditorBitDepth(int bitDepth); - void setProjectSettingsTab(int tab); - void setWarpBehaviorWarningDisabled(bool disabled); - void setCheckForUpdates(bool enabled); - void setLastUpdateCheckTime(QDateTime time); - void setLastUpdateCheckVersion(QVersionNumber version); - void setRateLimitTimes(QMap map); - QString getRecentProject(); - QStringList getRecentProjects(); - bool getReopenOnLaunch(); - MapSortOrder getMapSortOrder(); - bool getPrettyCursors(); QMap getMainGeometry(); QMap getTilesetEditorGeometry(); QMap getPaletteEditorGeometry(); QMap getRegionMapEditorGeometry(); QMap getProjectSettingsEditorGeometry(); QMap getCustomScriptsEditorGeometry(); - int getCollisionOpacity(); - int getCollisionZoom(); - int getMetatilesZoom(); - int getTilesetEditorMetatilesZoom(); - int getTilesetEditorTilesZoom(); - bool getShowPlayerView(); - bool getShowCursorTile(); - bool getShowBorder(); - bool getShowGrid(); - bool getShowTilesetEditorMetatileGrid(); - bool getShowTilesetEditorLayerGrid(); - bool getMonitorFiles(); - bool getTilesetCheckerboardFill(); - QString getTheme(); - QString getTextEditorOpenFolder(); - QString getTextEditorGotoLine(); - int getPaletteEditorBitDepth(); - int getProjectSettingsTab(); - bool getWarpBehaviorWarningDisabled(); - bool getCheckForUpdates(); - QDateTime getLastUpdateCheckTime(); - QVersionNumber getLastUpdateCheckVersion(); - QMap getRateLimitTimes(); -protected: - virtual QString getConfigFilepath() override; - virtual void parseConfigKeyValue(QString key, QString value) override; - virtual QMap getKeyValueMap() override; - virtual void onNewConfigFileCreated() override {}; - virtual void setUnreadKeys() override {}; -private: - QStringList recentProjects; + bool reopenOnLaunch; - QString stringFromByteArray(QByteArray); - QByteArray bytesFromString(QString); MapSortOrder mapSortOrder; bool prettyCursors; - QByteArray mainWindowGeometry; - QByteArray mainWindowState; - QByteArray mapSplitterState; - QByteArray mainSplitterState; - QByteArray metatilesSplitterState; - QByteArray tilesetEditorGeometry; - QByteArray tilesetEditorState; - QByteArray tilesetEditorSplitterState; - QByteArray paletteEditorGeometry; - QByteArray paletteEditorState; - QByteArray regionMapEditorGeometry; - QByteArray regionMapEditorState; - QByteArray projectSettingsEditorGeometry; - QByteArray projectSettingsEditorState; - QByteArray customScriptsEditorGeometry; - QByteArray customScriptsEditorState; int collisionOpacity; int collisionZoom; int metatilesZoom; @@ -204,6 +124,35 @@ private: QDateTime lastUpdateCheckTime; QVersionNumber lastUpdateCheckVersion; QMap rateLimitTimes; + +protected: + virtual QString getConfigFilepath() override; + virtual void parseConfigKeyValue(QString key, QString value) override; + virtual QMap getKeyValueMap() override; + virtual void init() override {}; + virtual void setUnreadKeys() override {}; + +private: + QString stringFromByteArray(QByteArray); + QByteArray bytesFromString(QString); + + QStringList recentProjects; + QByteArray mainWindowGeometry; + QByteArray mainWindowState; + QByteArray mapSplitterState; + QByteArray mainSplitterState; + QByteArray metatilesSplitterState; + QByteArray tilesetEditorGeometry; + QByteArray tilesetEditorState; + QByteArray tilesetEditorSplitterState; + QByteArray paletteEditorGeometry; + QByteArray paletteEditorState; + QByteArray regionMapEditorGeometry; + QByteArray regionMapEditorState; + QByteArray projectSettingsEditorGeometry; + QByteArray projectSettingsEditorState; + QByteArray customScriptsEditorGeometry; + QByteArray customScriptsEditorState; }; extern PorymapConfig porymapConfig; @@ -330,7 +279,7 @@ public: this->baseGameVersion = BaseGameVersion::pokeemerald; // Reset non-version-specific settings this->usePoryScript = false; - this->enableTripleLayerMetatiles = false; + this->tripleLayerMetatilesEnabled = false; this->defaultMetatileId = 1; this->defaultElevation = 3; this->defaultCollision = 0; @@ -354,52 +303,11 @@ public: static const QMap> defaultIdentifiers; static const QMap> defaultPaths; static const QStringList versionStrings; + static BaseGameVersion stringToBaseGameVersion(QString string, bool * ok = nullptr); + void reset(BaseGameVersion baseGameVersion); - void setBaseGameVersion(BaseGameVersion baseGameVersion); - BaseGameVersion getBaseGameVersion(); - QString getBaseGameVersionString(); - QString getBaseGameVersionString(BaseGameVersion version); - BaseGameVersion stringToBaseGameVersion(QString string, bool * ok = nullptr); - void setUsePoryScript(bool usePoryScript); - bool getUsePoryScript(); - void setProjectDir(QString projectDir); - QString getProjectDir(); - void setUseCustomBorderSize(bool enable); - bool getUseCustomBorderSize(); - void setEventWeatherTriggerEnabled(bool enable); - bool getEventWeatherTriggerEnabled(); - void setEventSecretBaseEnabled(bool enable); - bool getEventSecretBaseEnabled(); - void setHiddenItemQuantityEnabled(bool enable); - bool getHiddenItemQuantityEnabled(); - void setHiddenItemRequiresItemfinderEnabled(bool enable); - bool getHiddenItemRequiresItemfinderEnabled(); - void setHealLocationRespawnDataEnabled(bool enable); - bool getHealLocationRespawnDataEnabled(); - void setEventCloneObjectEnabled(bool enable); - bool getEventCloneObjectEnabled(); - void setFloorNumberEnabled(bool enable); - bool getFloorNumberEnabled(); - void setCreateMapTextFileEnabled(bool enable); - bool getCreateMapTextFileEnabled(); - void setTripleLayerMetatilesEnabled(bool enable); - bool getTripleLayerMetatilesEnabled(); - int getNumLayersInMetatile(); - int getNumTilesInMetatile(); - void setDefaultMetatileId(uint16_t metatileId); - uint16_t getDefaultMetatileId(); - void setDefaultElevation(uint16_t elevation); - uint16_t getDefaultElevation(); - void setDefaultCollision(uint16_t collision); - uint16_t getDefaultCollision(); - void setNewMapBorderMetatileIds(QList metatileIds); - QList getNewMapBorderMetatileIds(); - QString getDefaultPrimaryTileset(); - QString getDefaultSecondaryTileset(); - void setDefaultPrimaryTileset(QString tilesetName); - void setDefaultSecondaryTileset(QString tilesetName); - void setFilePath(const QString &pathId, const QString &path); void setFilePath(ProjectFilePath pathId, const QString &path); + void setFilePath(const QString &pathId, const QString &path); QString getCustomFilePath(ProjectFilePath pathId); QString getCustomFilePath(const QString &pathId); QString getFilePath(ProjectFilePath pathId); @@ -408,75 +316,35 @@ public: QString getCustomIdentifier(ProjectIdentifier id); QString getCustomIdentifier(const QString &id); QString getIdentifier(ProjectIdentifier id); - void setPrefabFilepath(QString filepath); - QString getPrefabFilepath(); - void setPrefabImportPrompted(bool prompted); - bool getPrefabImportPrompted(); - void setTilesetsHaveCallback(bool has); - bool getTilesetsHaveCallback(); - void setTilesetsHaveIsCompressed(bool has); - bool getTilesetsHaveIsCompressed(); - int getMetatileAttributesSize(); - void setMetatileAttributesSize(int size); - uint32_t getMetatileBehaviorMask(); - uint32_t getMetatileTerrainTypeMask(); - uint32_t getMetatileEncounterTypeMask(); - uint32_t getMetatileLayerTypeMask(); - void setMetatileBehaviorMask(uint32_t mask); - void setMetatileTerrainTypeMask(uint32_t mask); - void setMetatileEncounterTypeMask(uint32_t mask); - void setMetatileLayerTypeMask(uint32_t mask); - uint16_t getBlockMetatileIdMask(); - uint16_t getBlockCollisionMask(); - uint16_t getBlockElevationMask(); - void setBlockMetatileIdMask(uint16_t mask); - void setBlockCollisionMask(uint16_t mask); - void setBlockElevationMask(uint16_t mask); - bool getMapAllowFlagsEnabled(); - void setMapAllowFlagsEnabled(bool enabled); + QString getBaseGameVersionString(BaseGameVersion version); + QString getBaseGameVersionString(); + int getNumLayersInMetatile(); + int getNumTilesInMetatile(); void setEventIconPath(Event::Group group, const QString &path); QString getEventIconPath(Event::Group group); void setPokemonIconPath(const QString &species, const QString &path); QString getPokemonIconPath(const QString &species); QHash getPokemonIconPaths(); - void setCollisionSheetPath(const QString &path); - QString getCollisionSheetPath(); - void setCollisionSheetWidth(int width); - int getCollisionSheetWidth(); - void setCollisionSheetHeight(int height); - int getCollisionSheetHeight(); - void setWarpBehaviors(const QSet &behaviors); - QSet getWarpBehaviors(); -protected: - virtual QString getConfigFilepath() override; - virtual void parseConfigKeyValue(QString key, QString value) override; - virtual QMap getKeyValueMap() override; - virtual void onNewConfigFileCreated() override; - virtual void setUnreadKeys() override; -private: BaseGameVersion baseGameVersion; QString projectDir; - QMap identifiers; - QMap filePaths; bool usePoryScript; bool useCustomBorderSize; - bool enableEventWeatherTrigger; - bool enableEventSecretBase; - bool enableHiddenItemQuantity; - bool enableHiddenItemRequiresItemfinder; - bool enableHealLocationRespawnData; - bool enableEventCloneObject; - bool enableFloorNumber; - bool createMapTextFile; - bool enableTripleLayerMetatiles; + bool eventWeatherTriggerEnabled; + bool eventSecretBaseEnabled; + bool hiddenItemQuantityEnabled; + bool hiddenItemRequiresItemfinderEnabled; + bool healLocationRespawnDataEnabled; + bool eventCloneObjectEnabled; + bool floorNumberEnabled; + bool createMapTextFileEnabled; + bool tripleLayerMetatilesEnabled; uint16_t defaultMetatileId; uint16_t defaultElevation; uint16_t defaultCollision; QList newMapBorderMetatileIds; QString defaultPrimaryTileset; QString defaultSecondaryTileset; - QStringList readKeys; QString prefabFilepath; bool prefabImportPrompted; bool tilesetsHaveCallback; @@ -489,13 +357,25 @@ private: uint16_t blockMetatileIdMask; uint16_t blockCollisionMask; uint16_t blockElevationMask; - bool enableMapAllowFlags; - QMap eventIconPaths; - QHash pokemonIconPaths; + bool mapAllowFlagsEnabled; QString collisionSheetPath; int collisionSheetWidth; int collisionSheetHeight; QSet warpBehaviors; + +protected: + virtual QString getConfigFilepath() override; + virtual void parseConfigKeyValue(QString key, QString value) override; + virtual QMap getKeyValueMap() override; + virtual void init() override; + virtual void setUnreadKeys() override; + +private: + QStringList readKeys; + QMap identifiers; + QMap filePaths; + QMap eventIconPaths; + QHash pokemonIconPaths; }; extern ProjectConfig projectConfig; @@ -512,32 +392,29 @@ public: this->customScripts.clear(); this->readKeys.clear(); } - void setRecentMap(const QString &map); - QString getRecentMap(); - void setEncounterJsonActive(bool active); - bool getEncounterJsonActive(); - void setProjectDir(QString projectDir); - QString getProjectDir(); + void parseCustomScripts(QString input); + QString outputCustomScripts(); void setCustomScripts(QStringList scripts, QList enabled); QStringList getCustomScriptPaths(); QList getCustomScriptsEnabled(); - void parseCustomScripts(QString input); - QString outputCustomScripts(); + + QString projectDir; + QString recentMap; + bool useEncounterJson; + protected: virtual QString getConfigFilepath() override; virtual void parseConfigKeyValue(QString key, QString value) override; virtual QMap getKeyValueMap() override; - virtual void onNewConfigFileCreated() override; + virtual void init() override; virtual void setUnreadKeys() override; #ifdef CONFIG_BACKWARDS_COMPATABILITY friend class ProjectConfig; -#endif +#endif + private: - QString projectDir; - QString recentMap; - bool useEncounterJson; - QMap customScripts; QStringList readKeys; + QMap customScripts; }; extern UserConfig userConfig; @@ -567,7 +444,7 @@ protected: virtual QString getConfigFilepath() override; virtual void parseConfigKeyValue(QString key, QString value) override; virtual QMap getKeyValueMap() override; - virtual void onNewConfigFileCreated() override { }; + virtual void init() override { }; virtual void setUnreadKeys() override { }; private: diff --git a/include/mainwindow.h b/include/mainwindow.h index 512bb52c..bb4d4b91 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -355,7 +355,6 @@ private: void showProjectOpenFailure(); void saveGlobalConfigs(); bool setInitialMap(); - void setRecentMap(QString map_name); QStandardItem* createMapItem(QString mapName, int groupNum, int inGroupNum); void refreshRecentProjectsMenu(); diff --git a/include/project.h b/include/project.h index 643f74da..90172f39 100644 --- a/include/project.h +++ b/include/project.h @@ -153,6 +153,7 @@ public: void saveAllMaps(); void saveMap(Map*); void saveAllDataStructures(); + void saveConfig(); void saveMapLayouts(); void saveMapGroups(); void saveWildMonData(); diff --git a/src/config.cpp b/src/config.cpp index 177aeafa..1ee00c18 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -198,16 +198,9 @@ KeyValueConfigBase::~KeyValueConfigBase() { void KeyValueConfigBase::load() { reset(); QFile file(this->getConfigFilepath()); - if (!file.exists()) { - if (!file.open(QIODevice::WriteOnly)) { - logError(QString("Could not create config file '%1'").arg(this->getConfigFilepath())); - } else { - file.close(); - this->onNewConfigFileCreated(); - } - } - - if (!file.open(QIODevice::ReadOnly)) { + if (!file.exists()) + this->init(); + else if (!file.open(QIODevice::ReadOnly)) { logError(QString("Could not open config file '%1': ").arg(this->getConfigFilepath()) + file.errorString()); } @@ -234,15 +227,11 @@ void KeyValueConfigBase::load() { this->parseConfigKeyValue(match.captured("key").trimmed().toLower(), match.captured("value").trimmed()); } this->setUnreadKeys(); - this->save(); file.close(); } void KeyValueConfigBase::save() { - if (this->saveDisabled) - return; - QString text = ""; QMap map = this->getKeyValueMap(); for (QMap::iterator it = map.begin(); it != map.end(); it++) { @@ -287,11 +276,6 @@ uint32_t KeyValueConfigBase::getConfigUint32(QString key, QString value, uint32_ return qMin(max, qMax(min, result)); } -// For temporarily disabling saving during frequent config changes. -void KeyValueConfigBase::setSaveDisabled(bool disabled) { - this->saveDisabled = disabled; -} - const QMap mapSortOrderMap = { {MapSortOrder::Group, "group"}, {MapSortOrder::Layout, "layout"}, @@ -504,183 +488,10 @@ QByteArray PorymapConfig::bytesFromString(QString in) { void PorymapConfig::addRecentProject(QString project) { this->recentProjects.removeOne(project); this->recentProjects.prepend(project); - this->save(); } void PorymapConfig::setRecentProjects(QStringList projects) { this->recentProjects = projects; - this->save(); -} - -void PorymapConfig::setReopenOnLaunch(bool enabled) { - this->reopenOnLaunch = enabled; - this->save(); -} - -void PorymapConfig::setMapSortOrder(MapSortOrder order) { - this->mapSortOrder = order; - this->save(); -} - -void PorymapConfig::setPrettyCursors(bool enabled) { - this->prettyCursors = enabled; - this->save(); -} - -void PorymapConfig::setMonitorFiles(bool monitor) { - this->monitorFiles = monitor; - this->save(); -} - -void PorymapConfig::setTilesetCheckerboardFill(bool checkerboard) { - this->tilesetCheckerboardFill = checkerboard; - this->save(); -} - -void PorymapConfig::setMainGeometry(QByteArray mainWindowGeometry_, QByteArray mainWindowState_, - QByteArray mapSplitterState_, QByteArray mainSplitterState_, QByteArray metatilesSplitterState_) { - this->mainWindowGeometry = mainWindowGeometry_; - this->mainWindowState = mainWindowState_; - this->mapSplitterState = mapSplitterState_; - this->mainSplitterState = mainSplitterState_; - this->metatilesSplitterState = metatilesSplitterState_; - this->save(); -} - -void PorymapConfig::setTilesetEditorGeometry(QByteArray tilesetEditorGeometry_, QByteArray tilesetEditorState_, - QByteArray tilesetEditorSplitterState_) { - this->tilesetEditorGeometry = tilesetEditorGeometry_; - this->tilesetEditorState = tilesetEditorState_; - this->tilesetEditorSplitterState = tilesetEditorSplitterState_; - this->save(); -} - -void PorymapConfig::setPaletteEditorGeometry(QByteArray paletteEditorGeometry_, QByteArray paletteEditorState_) { - this->paletteEditorGeometry = paletteEditorGeometry_; - this->paletteEditorState = paletteEditorState_; - this->save(); -} - -void PorymapConfig::setRegionMapEditorGeometry(QByteArray regionMapEditorGeometry_, QByteArray regionMapEditorState_) { - this->regionMapEditorGeometry = regionMapEditorGeometry_; - this->regionMapEditorState = regionMapEditorState_; - this->save(); -} - -void PorymapConfig::setProjectSettingsEditorGeometry(QByteArray projectSettingsEditorGeometry_, QByteArray projectSettingsEditorState_) { - this->projectSettingsEditorGeometry = projectSettingsEditorGeometry_; - this->projectSettingsEditorState = projectSettingsEditorState_; - this->save(); -} - -void PorymapConfig::setCustomScriptsEditorGeometry(QByteArray customScriptsEditorGeometry_, QByteArray customScriptsEditorState_) { - this->customScriptsEditorGeometry = customScriptsEditorGeometry_; - this->customScriptsEditorState = customScriptsEditorState_; - this->save(); -} - -void PorymapConfig::setCollisionOpacity(int opacity) { - this->collisionOpacity = opacity; - // don't auto-save here because this can be called very frequently. -} - -void PorymapConfig::setCollisionZoom(int zoom) { - this->collisionZoom = zoom; - // don't auto-save here because this can be called very frequently. -} - -void PorymapConfig::setMetatilesZoom(int zoom) { - this->metatilesZoom = zoom; - // don't auto-save here because this can be called very frequently. -} - -void PorymapConfig::setTilesetEditorMetatilesZoom(int zoom) { - this->tilesetEditorMetatilesZoom = zoom; - // don't auto-save here because this can be called very frequently. -} - -void PorymapConfig::setTilesetEditorTilesZoom(int zoom) { - this->tilesetEditorTilesZoom = zoom; - // don't auto-save here because this can be called very frequently. -} - -void PorymapConfig::setShowPlayerView(bool enabled) { - this->showPlayerView = enabled; - this->save(); -} - -void PorymapConfig::setShowCursorTile(bool enabled) { - this->showCursorTile = enabled; - this->save(); -} - -void PorymapConfig::setShowBorder(bool enabled) { - this->showBorder = enabled; - this->save(); -} - -void PorymapConfig::setShowGrid(bool enabled) { - this->showGrid = enabled; - this->save(); -} - -void PorymapConfig::setShowTilesetEditorMetatileGrid(bool enabled) { - this->showTilesetEditorMetatileGrid = enabled; - this->save(); -} - -void PorymapConfig::setShowTilesetEditorLayerGrid(bool enabled) { - this->showTilesetEditorLayerGrid = enabled; - this->save(); -} - -void PorymapConfig::setTheme(QString theme) { - this->theme = theme; -} - -void PorymapConfig::setTextEditorOpenFolder(const QString &command) { - this->textEditorOpenFolder = command; - this->save(); -} - -void PorymapConfig::setTextEditorGotoLine(const QString &command) { - this->textEditorGotoLine = command; - this->save(); -} - -void PorymapConfig::setPaletteEditorBitDepth(int bitDepth) { - this->paletteEditorBitDepth = bitDepth; - this->save(); -} - -void PorymapConfig::setProjectSettingsTab(int tab) { - this->projectSettingsTab = tab; - this->save(); -} - -void PorymapConfig::setWarpBehaviorWarningDisabled(bool disabled) { - this->warpBehaviorWarningDisabled = disabled; - this->save(); -} - -void PorymapConfig::setCheckForUpdates(bool enabled) { - this->checkForUpdates = enabled; - this->save(); -} - -void PorymapConfig::setLastUpdateCheckTime(QDateTime time) { - this->lastUpdateCheckTime = time; - this->save(); -} - -void PorymapConfig::setLastUpdateCheckVersion(QVersionNumber version) { - this->lastUpdateCheckVersion = version; - this->save(); -} - -void PorymapConfig::setRateLimitTimes(QMap map) { - this->rateLimitTimes = map; - this->save(); } QString PorymapConfig::getRecentProject() { @@ -691,16 +502,40 @@ QStringList PorymapConfig::getRecentProjects() { return this->recentProjects; } -bool PorymapConfig::getReopenOnLaunch() { - return this->reopenOnLaunch; +void PorymapConfig::setMainGeometry(QByteArray mainWindowGeometry_, QByteArray mainWindowState_, + QByteArray mapSplitterState_, QByteArray mainSplitterState_, QByteArray metatilesSplitterState_) { + this->mainWindowGeometry = mainWindowGeometry_; + this->mainWindowState = mainWindowState_; + this->mapSplitterState = mapSplitterState_; + this->mainSplitterState = mainSplitterState_; + this->metatilesSplitterState = metatilesSplitterState_; } -MapSortOrder PorymapConfig::getMapSortOrder() { - return this->mapSortOrder; +void PorymapConfig::setTilesetEditorGeometry(QByteArray tilesetEditorGeometry_, QByteArray tilesetEditorState_, + QByteArray tilesetEditorSplitterState_) { + this->tilesetEditorGeometry = tilesetEditorGeometry_; + this->tilesetEditorState = tilesetEditorState_; + this->tilesetEditorSplitterState = tilesetEditorSplitterState_; } -bool PorymapConfig::getPrettyCursors() { - return this->prettyCursors; +void PorymapConfig::setPaletteEditorGeometry(QByteArray paletteEditorGeometry_, QByteArray paletteEditorState_) { + this->paletteEditorGeometry = paletteEditorGeometry_; + this->paletteEditorState = paletteEditorState_; +} + +void PorymapConfig::setRegionMapEditorGeometry(QByteArray regionMapEditorGeometry_, QByteArray regionMapEditorState_) { + this->regionMapEditorGeometry = regionMapEditorGeometry_; + this->regionMapEditorState = regionMapEditorState_; +} + +void PorymapConfig::setProjectSettingsEditorGeometry(QByteArray projectSettingsEditorGeometry_, QByteArray projectSettingsEditorState_) { + this->projectSettingsEditorGeometry = projectSettingsEditorGeometry_; + this->projectSettingsEditorState = projectSettingsEditorState_; +} + +void PorymapConfig::setCustomScriptsEditorGeometry(QByteArray customScriptsEditorGeometry_, QByteArray customScriptsEditorState_) { + this->customScriptsEditorGeometry = customScriptsEditorGeometry_; + this->customScriptsEditorState = customScriptsEditorState_; } QMap PorymapConfig::getMainGeometry() { @@ -761,98 +596,6 @@ QMap PorymapConfig::getCustomScriptsEditorGeometry() { return geometry; } -int PorymapConfig::getCollisionOpacity() { - return this->collisionOpacity; -} - -int PorymapConfig::getCollisionZoom() { - return this->collisionZoom; -} - -int PorymapConfig::getMetatilesZoom() { - return this->metatilesZoom; -} - -int PorymapConfig::getTilesetEditorMetatilesZoom() { - return this->tilesetEditorMetatilesZoom; -} - -int PorymapConfig::getTilesetEditorTilesZoom() { - return this->tilesetEditorTilesZoom; -} - -bool PorymapConfig::getShowPlayerView() { - return this->showPlayerView; -} - -bool PorymapConfig::getShowCursorTile() { - return this->showCursorTile; -} - -bool PorymapConfig::getShowBorder() { - return this->showBorder; -} - -bool PorymapConfig::getShowGrid() { - return this->showGrid; -} - -bool PorymapConfig::getShowTilesetEditorMetatileGrid() { - return this->showTilesetEditorMetatileGrid; -} - -bool PorymapConfig::getShowTilesetEditorLayerGrid() { - return this->showTilesetEditorLayerGrid; -} - -bool PorymapConfig::getMonitorFiles() { - return this->monitorFiles; -} - -bool PorymapConfig::getTilesetCheckerboardFill() { - return this->tilesetCheckerboardFill; -} - -QString PorymapConfig::getTheme() { - return this->theme; -} - -QString PorymapConfig::getTextEditorOpenFolder() { - return this->textEditorOpenFolder; -} - -QString PorymapConfig::getTextEditorGotoLine() { - return this->textEditorGotoLine; -} - -int PorymapConfig::getPaletteEditorBitDepth() { - return this->paletteEditorBitDepth; -} - -int PorymapConfig::getProjectSettingsTab() { - return this->projectSettingsTab; -} - -bool PorymapConfig::getWarpBehaviorWarningDisabled() { - return this->warpBehaviorWarningDisabled; -} - -bool PorymapConfig::getCheckForUpdates() { - return this->checkForUpdates; -} - -QDateTime PorymapConfig::getLastUpdateCheckTime() { - return this->lastUpdateCheckTime; -} - -QVersionNumber PorymapConfig::getLastUpdateCheckVersion() { - return this->lastUpdateCheckVersion; -} - -QMap PorymapConfig::getRateLimitTimes() { - return this->rateLimitTimes; -} - const QStringList ProjectConfig::versionStrings = { "pokeruby", "pokefirered", @@ -899,24 +642,24 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) { } else if (key == "use_custom_border_size") { this->useCustomBorderSize = getConfigBool(key, value); } else if (key == "enable_event_weather_trigger") { - this->enableEventWeatherTrigger = getConfigBool(key, value); + this->eventWeatherTriggerEnabled = getConfigBool(key, value); } else if (key == "enable_event_secret_base") { - this->enableEventSecretBase = getConfigBool(key, value); + this->eventSecretBaseEnabled = getConfigBool(key, value); } else if (key == "enable_hidden_item_quantity") { - this->enableHiddenItemQuantity = getConfigBool(key, value); + this->hiddenItemQuantityEnabled = getConfigBool(key, value); } else if (key == "enable_hidden_item_requires_itemfinder") { - this->enableHiddenItemRequiresItemfinder = getConfigBool(key, value); + this->hiddenItemRequiresItemfinderEnabled = getConfigBool(key, value); } else if (key == "enable_heal_location_respawn_data") { - this->enableHealLocationRespawnData = getConfigBool(key, value); + this->healLocationRespawnDataEnabled = getConfigBool(key, value); } else if (key == "enable_event_clone_object" || key == "enable_object_event_in_connection") { - this->enableEventCloneObject = getConfigBool(key, value); + this->eventCloneObjectEnabled = getConfigBool(key, value); key = "enable_event_clone_object"; // Backwards compatibiliy, replace old name above } else if (key == "enable_floor_number") { - this->enableFloorNumber = getConfigBool(key, value); + this->floorNumberEnabled = getConfigBool(key, value); } else if (key == "create_map_text_file") { - this->createMapTextFile = getConfigBool(key, value); + this->createMapTextFileEnabled = getConfigBool(key, value); } else if (key == "enable_triple_layer_metatiles") { - this->enableTripleLayerMetatiles = getConfigBool(key, value); + this->tripleLayerMetatilesEnabled = getConfigBool(key, value); } else if (key == "default_metatile") { this->defaultMetatileId = getConfigUint32(key, value, 0, Block::maxValue); } else if (key == "default_elevation") { @@ -956,10 +699,10 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) { } else if (key == "block_elevation_mask") { this->blockElevationMask = getConfigUint32(key, value, 0, Block::maxValue); } else if (key == "enable_map_allow_flags") { - this->enableMapAllowFlags = getConfigBool(key, value); + this->mapAllowFlagsEnabled = getConfigBool(key, value); #ifdef CONFIG_BACKWARDS_COMPATABILITY } else if (key == "recent_map") { - userConfig.setRecentMap(value); + userConfig.recentMap = value; } else if (key == "use_encounter_json") { userConfig.useEncounterJson = getConfigBool(key, value); } else if (key == "custom_scripts") { @@ -1028,14 +771,14 @@ void ProjectConfig::setUnreadKeys() { // Set game-version specific defaults for any config field that wasn't read bool isPokefirered = this->baseGameVersion == BaseGameVersion::pokefirered; if (!readKeys.contains("use_custom_border_size")) this->useCustomBorderSize = isPokefirered; - if (!readKeys.contains("enable_event_weather_trigger")) this->enableEventWeatherTrigger = !isPokefirered; - if (!readKeys.contains("enable_event_secret_base")) this->enableEventSecretBase = !isPokefirered; - if (!readKeys.contains("enable_hidden_item_quantity")) this->enableHiddenItemQuantity = isPokefirered; - if (!readKeys.contains("enable_hidden_item_requires_itemfinder")) this->enableHiddenItemRequiresItemfinder = isPokefirered; - if (!readKeys.contains("enable_heal_location_respawn_data")) this->enableHealLocationRespawnData = isPokefirered; - if (!readKeys.contains("enable_event_clone_object")) this->enableEventCloneObject = isPokefirered; - if (!readKeys.contains("enable_floor_number")) this->enableFloorNumber = isPokefirered; - if (!readKeys.contains("create_map_text_file")) this->createMapTextFile = (this->baseGameVersion != BaseGameVersion::pokeemerald); + if (!readKeys.contains("enable_event_weather_trigger")) this->eventWeatherTriggerEnabled = !isPokefirered; + if (!readKeys.contains("enable_event_secret_base")) this->eventSecretBaseEnabled = !isPokefirered; + if (!readKeys.contains("enable_hidden_item_quantity")) this->hiddenItemQuantityEnabled = isPokefirered; + if (!readKeys.contains("enable_hidden_item_requires_itemfinder")) this->hiddenItemRequiresItemfinderEnabled = isPokefirered; + if (!readKeys.contains("enable_heal_location_respawn_data")) this->healLocationRespawnDataEnabled = isPokefirered; + if (!readKeys.contains("enable_event_clone_object")) this->eventCloneObjectEnabled = isPokefirered; + if (!readKeys.contains("enable_floor_number")) this->floorNumberEnabled = isPokefirered; + if (!readKeys.contains("create_map_text_file")) this->createMapTextFileEnabled = (this->baseGameVersion != BaseGameVersion::pokeemerald); if (!readKeys.contains("new_map_border_metatiles")) this->newMapBorderMetatileIds = isPokefirered ? DEFAULT_BORDER_FRLG : DEFAULT_BORDER_RSE; if (!readKeys.contains("default_secondary_tileset")) this->defaultSecondaryTileset = isPokefirered ? "gTileset_PalletTown" : "gTileset_Petalburg"; if (!readKeys.contains("metatile_attributes_size")) this->metatileAttributesSize = Metatile::getDefaultAttributesSize(this->baseGameVersion); @@ -1043,7 +786,7 @@ void ProjectConfig::setUnreadKeys() { if (!readKeys.contains("metatile_terrain_type_mask")) this->metatileTerrainTypeMask = Metatile::getDefaultAttributesMask(this->baseGameVersion, Metatile::Attr::TerrainType); if (!readKeys.contains("metatile_encounter_type_mask")) this->metatileEncounterTypeMask = Metatile::getDefaultAttributesMask(this->baseGameVersion, Metatile::Attr::EncounterType); if (!readKeys.contains("metatile_layer_type_mask")) this->metatileLayerTypeMask = Metatile::getDefaultAttributesMask(this->baseGameVersion, Metatile::Attr::LayerType); - if (!readKeys.contains("enable_map_allow_flags")) this->enableMapAllowFlags = (this->baseGameVersion != BaseGameVersion::pokeruby); + if (!readKeys.contains("enable_map_allow_flags")) this->mapAllowFlagsEnabled = (this->baseGameVersion != BaseGameVersion::pokeruby); if (!readKeys.contains("warp_behaviors")) this->warpBehaviors = isPokefirered ? defaultWarpBehaviors_FRLG : defaultWarpBehaviors_RSE; } @@ -1052,15 +795,15 @@ QMap ProjectConfig::getKeyValueMap() { map.insert("base_game_version", baseGameVersionMap.value(this->baseGameVersion)); map.insert("use_poryscript", QString::number(this->usePoryScript)); map.insert("use_custom_border_size", QString::number(this->useCustomBorderSize)); - map.insert("enable_event_weather_trigger", QString::number(this->enableEventWeatherTrigger)); - map.insert("enable_event_secret_base", QString::number(this->enableEventSecretBase)); - map.insert("enable_hidden_item_quantity", QString::number(this->enableHiddenItemQuantity)); - map.insert("enable_hidden_item_requires_itemfinder", QString::number(this->enableHiddenItemRequiresItemfinder)); - map.insert("enable_heal_location_respawn_data", QString::number(this->enableHealLocationRespawnData)); - map.insert("enable_event_clone_object", QString::number(this->enableEventCloneObject)); - map.insert("enable_floor_number", QString::number(this->enableFloorNumber)); - map.insert("create_map_text_file", QString::number(this->createMapTextFile)); - map.insert("enable_triple_layer_metatiles", QString::number(this->enableTripleLayerMetatiles)); + map.insert("enable_event_weather_trigger", QString::number(this->eventWeatherTriggerEnabled)); + map.insert("enable_event_secret_base", QString::number(this->eventSecretBaseEnabled)); + map.insert("enable_hidden_item_quantity", QString::number(this->hiddenItemQuantityEnabled)); + map.insert("enable_hidden_item_requires_itemfinder", QString::number(this->hiddenItemRequiresItemfinderEnabled)); + map.insert("enable_heal_location_respawn_data", QString::number(this->healLocationRespawnDataEnabled)); + map.insert("enable_event_clone_object", QString::number(this->eventCloneObjectEnabled)); + map.insert("enable_floor_number", QString::number(this->floorNumberEnabled)); + map.insert("create_map_text_file", QString::number(this->createMapTextFileEnabled)); + map.insert("enable_triple_layer_metatiles", QString::number(this->tripleLayerMetatilesEnabled)); map.insert("default_metatile", Metatile::getMetatileIdString(this->defaultMetatileId)); map.insert("default_elevation", QString::number(this->defaultElevation)); map.insert("default_collision", QString::number(this->defaultCollision)); @@ -1082,7 +825,7 @@ QMap ProjectConfig::getKeyValueMap() { map.insert("block_metatile_id_mask", "0x" + QString::number(this->blockMetatileIdMask, 16).toUpper()); map.insert("block_collision_mask", "0x" + QString::number(this->blockCollisionMask, 16).toUpper()); map.insert("block_elevation_mask", "0x" + QString::number(this->blockElevationMask, 16).toUpper()); - map.insert("enable_map_allow_flags", QString::number(this->enableMapAllowFlags)); + map.insert("enable_map_allow_flags", QString::number(this->mapAllowFlagsEnabled)); map.insert("event_icon_path_object", this->eventIconPaths[Event::Group::Object]); map.insert("event_icon_path_warp", this->eventIconPaths[Event::Group::Warp]); map.insert("event_icon_path_coord", this->eventIconPaths[Event::Group::Coord]); @@ -1106,9 +849,10 @@ QMap ProjectConfig::getKeyValueMap() { return map; } -void ProjectConfig::onNewConfigFileCreated() { +void ProjectConfig::init() { QString dirName = QDir(this->projectDir).dirName().toLower(); if (baseGameVersionReverseMap.contains(dirName)) { + // TODO: Improve detection (ex: emerald or pokeemerald-2 aren't currently auto-detected) this->baseGameVersion = baseGameVersionReverseMap.value(dirName); logInfo(QString("Auto-detected base_game_version as '%1'").arg(dirName)); } else { @@ -1124,6 +868,8 @@ void ProjectConfig::onNewConfigFileCreated() { baseGameVersionComboBox->addItem("pokeemerald", BaseGameVersion::pokeemerald); form.addRow(new QLabel("Game Version"), baseGameVersionComboBox); + // TODO: Advanced button to open the project settings window (with some settings disabled) + QDialogButtonBox buttonBox(QDialogButtonBox::Ok, Qt::Horizontal, &dialog); QObject::connect(&buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); form.addRow(&buttonBox); @@ -1135,14 +881,6 @@ void ProjectConfig::onNewConfigFileCreated() { this->setUnreadKeys(); // Initialize version-specific options } -void ProjectConfig::setProjectDir(QString projectDir) { - this->projectDir = projectDir; -} - -QString ProjectConfig::getProjectDir() { - return this->projectDir; -} - void ProjectConfig::setFilePath(ProjectFilePath pathId, const QString &path) { if (!defaultPaths.contains(pathId)) return; if (path.isEmpty()) { @@ -1208,15 +946,6 @@ QString ProjectConfig::getIdentifier(ProjectIdentifier id) { return defaultIdentifiers.contains(id) ? defaultIdentifiers[id].second : QString(); } -void ProjectConfig::setBaseGameVersion(BaseGameVersion baseGameVersion) { - this->baseGameVersion = baseGameVersion; - this->save(); -} - -BaseGameVersion ProjectConfig::getBaseGameVersion() { - return this->baseGameVersion; -} - QString ProjectConfig::getBaseGameVersionString(BaseGameVersion version) { if (!baseGameVersionMap.contains(version)) { version = BaseGameVersion::pokeemerald; @@ -1228,287 +957,16 @@ QString ProjectConfig::getBaseGameVersionString() { return this->getBaseGameVersionString(this->baseGameVersion); } -void ProjectConfig::setUsePoryScript(bool usePoryScript) { - this->usePoryScript = usePoryScript; - this->save(); -} - -bool ProjectConfig::getUsePoryScript() { - return this->usePoryScript; -} - -void ProjectConfig::setUseCustomBorderSize(bool enable) { - this->useCustomBorderSize = enable; - this->save(); -} - -bool ProjectConfig::getUseCustomBorderSize() { - return this->useCustomBorderSize; -} - -void ProjectConfig::setEventWeatherTriggerEnabled(bool enable) { - this->enableEventWeatherTrigger = enable; - this->save(); -} - -bool ProjectConfig::getEventWeatherTriggerEnabled() { - return this->enableEventWeatherTrigger; -} - -void ProjectConfig::setEventSecretBaseEnabled(bool enable) { - this->enableEventSecretBase = enable; - this->save(); -} - -bool ProjectConfig::getEventSecretBaseEnabled() { - return this->enableEventSecretBase; -} - -void ProjectConfig::setHiddenItemQuantityEnabled(bool enable) { - this->enableHiddenItemQuantity = enable; - this->save(); -} - -bool ProjectConfig::getHiddenItemQuantityEnabled() { - return this->enableHiddenItemQuantity; -} - -void ProjectConfig::setHiddenItemRequiresItemfinderEnabled(bool enable) { - this->enableHiddenItemRequiresItemfinder = enable; - this->save(); -} - -bool ProjectConfig::getHiddenItemRequiresItemfinderEnabled() { - return this->enableHiddenItemRequiresItemfinder; -} - -void ProjectConfig::setHealLocationRespawnDataEnabled(bool enable) { - this->enableHealLocationRespawnData = enable; - this->save(); -} - -bool ProjectConfig::getHealLocationRespawnDataEnabled() { - return this->enableHealLocationRespawnData; -} - -void ProjectConfig::setEventCloneObjectEnabled(bool enable) { - this->enableEventCloneObject = enable; - this->save(); -} - -bool ProjectConfig::getEventCloneObjectEnabled() { - return this->enableEventCloneObject; -} - -void ProjectConfig::setFloorNumberEnabled(bool enable) { - this->enableFloorNumber = enable; - this->save(); -} - -bool ProjectConfig::getFloorNumberEnabled() { - return this->enableFloorNumber; -} - -void ProjectConfig::setCreateMapTextFileEnabled(bool enable) { - this->createMapTextFile = enable; - this->save(); -} - -bool ProjectConfig::getCreateMapTextFileEnabled() { - return this->createMapTextFile; -} - -void ProjectConfig::setTripleLayerMetatilesEnabled(bool enable) { - this->enableTripleLayerMetatiles = enable; - this->save(); -} - -bool ProjectConfig::getTripleLayerMetatilesEnabled() { - return this->enableTripleLayerMetatiles; -} - int ProjectConfig::getNumLayersInMetatile() { - return this->enableTripleLayerMetatiles ? 3 : 2; + return this->tripleLayerMetatilesEnabled ? 3 : 2; } int ProjectConfig::getNumTilesInMetatile() { - return this->enableTripleLayerMetatiles ? 12 : 8; -} - -void ProjectConfig::setDefaultMetatileId(uint16_t metatileId) { - this->defaultMetatileId = metatileId; - this->save(); -} - -uint16_t ProjectConfig::getDefaultMetatileId() { - return this->defaultMetatileId; -} - -void ProjectConfig::setDefaultElevation(uint16_t elevation) { - this->defaultElevation = elevation; - this->save(); -} - -uint16_t ProjectConfig::getDefaultElevation() { - return this->defaultElevation; -} - -void ProjectConfig::setDefaultCollision(uint16_t collision) { - this->defaultCollision = collision; - this->save(); -} - -uint16_t ProjectConfig::getDefaultCollision() { - return this->defaultCollision; -} - -void ProjectConfig::setNewMapBorderMetatileIds(QList metatileIds) { - this->newMapBorderMetatileIds = metatileIds; - this->save(); -} - -QList ProjectConfig::getNewMapBorderMetatileIds() { - return this->newMapBorderMetatileIds; -} - -QString ProjectConfig::getDefaultPrimaryTileset() { - return this->defaultPrimaryTileset; -} - -QString ProjectConfig::getDefaultSecondaryTileset() { - return this->defaultSecondaryTileset; -} - -void ProjectConfig::setDefaultPrimaryTileset(QString tilesetName) { - this->defaultPrimaryTileset = tilesetName; - this->save(); -} - -void ProjectConfig::setDefaultSecondaryTileset(QString tilesetName) { - this->defaultSecondaryTileset = tilesetName; - this->save(); -} - -void ProjectConfig::setPrefabFilepath(QString filepath) { - this->prefabFilepath = filepath; - this->save(); -} - -QString ProjectConfig::getPrefabFilepath() { - return this->prefabFilepath; -} - -void ProjectConfig::setPrefabImportPrompted(bool prompted) { - this->prefabImportPrompted = prompted; - this->save(); -} - -bool ProjectConfig::getPrefabImportPrompted() { - return this->prefabImportPrompted; -} - -void ProjectConfig::setTilesetsHaveCallback(bool has) { - this->tilesetsHaveCallback = has; - this->save(); -} - -bool ProjectConfig::getTilesetsHaveCallback() { - return this->tilesetsHaveCallback; -} - -void ProjectConfig::setTilesetsHaveIsCompressed(bool has) { - this->tilesetsHaveIsCompressed = has; - this->save(); -} - -bool ProjectConfig::getTilesetsHaveIsCompressed() { - return this->tilesetsHaveIsCompressed; -} - -int ProjectConfig::getMetatileAttributesSize() { - return this->metatileAttributesSize; -} - -void ProjectConfig::setMetatileAttributesSize(int size) { - this->metatileAttributesSize = size; - this->save(); -} - -uint32_t ProjectConfig::getMetatileBehaviorMask() { - return this->metatileBehaviorMask; -} - -uint32_t ProjectConfig::getMetatileTerrainTypeMask() { - return this->metatileTerrainTypeMask; -} - -uint32_t ProjectConfig::getMetatileEncounterTypeMask() { - return this->metatileEncounterTypeMask; -} - -uint32_t ProjectConfig::getMetatileLayerTypeMask() { - return this->metatileLayerTypeMask; -} - -void ProjectConfig::setMetatileBehaviorMask(uint32_t mask) { - this->metatileBehaviorMask = mask; - this->save(); -} - -void ProjectConfig::setMetatileTerrainTypeMask(uint32_t mask) { - this->metatileTerrainTypeMask = mask; - this->save(); -} - -void ProjectConfig::setMetatileEncounterTypeMask(uint32_t mask) { - this->metatileEncounterTypeMask = mask; - this->save(); -} - -void ProjectConfig::setMetatileLayerTypeMask(uint32_t mask) { - this->metatileLayerTypeMask = mask; - this->save(); -} - -uint16_t ProjectConfig::getBlockMetatileIdMask() { - return this->blockMetatileIdMask; -} - -uint16_t ProjectConfig::getBlockCollisionMask() { - return this->blockCollisionMask; -} - -uint16_t ProjectConfig::getBlockElevationMask() { - return this->blockElevationMask; -} - -void ProjectConfig::setBlockMetatileIdMask(uint16_t mask) { - this->blockMetatileIdMask = mask; - this->save(); -} - -void ProjectConfig::setBlockCollisionMask(uint16_t mask) { - this->blockCollisionMask = mask; - this->save(); -} - -void ProjectConfig::setBlockElevationMask(uint16_t mask) { - this->blockElevationMask = mask; - this->save(); -} - -bool ProjectConfig::getMapAllowFlagsEnabled() { - return this->enableMapAllowFlags; -} - -void ProjectConfig::setMapAllowFlagsEnabled(bool enabled) { - this->enableMapAllowFlags = enabled; - this->save(); + return this->tripleLayerMetatilesEnabled ? 12 : 8; } void ProjectConfig::setEventIconPath(Event::Group group, const QString &path) { this->eventIconPaths[group] = path; - this->save(); } QString ProjectConfig::getEventIconPath(Event::Group group) { @@ -1517,7 +975,6 @@ QString ProjectConfig::getEventIconPath(Event::Group group) { void ProjectConfig::setPokemonIconPath(const QString &species, const QString &path) { this->pokemonIconPaths[species] = path; - this->save(); } QString ProjectConfig::getPokemonIconPath(const QString &species) { @@ -1528,43 +985,6 @@ QHash ProjectConfig::getPokemonIconPaths() { return this->pokemonIconPaths; } -void ProjectConfig::setCollisionSheetPath(const QString &path) { - this->collisionSheetPath = path; - this->save(); -} - -QString ProjectConfig::getCollisionSheetPath() { - return this->collisionSheetPath; -} - -void ProjectConfig::setCollisionSheetWidth(int width) { - this->collisionSheetWidth = width; - this->save(); -} - -int ProjectConfig::getCollisionSheetWidth() { - return this->collisionSheetWidth; -} - -void ProjectConfig::setCollisionSheetHeight(int height) { - this->collisionSheetHeight = height; - this->save(); -} - -int ProjectConfig::getCollisionSheetHeight() { - return this->collisionSheetHeight; -} - -void ProjectConfig::setWarpBehaviors(const QSet &behaviors) { - this->warpBehaviors = behaviors; - this->save(); -} - -QSet ProjectConfig::getWarpBehaviors() { - return this->warpBehaviors; -} - - UserConfig userConfig; QString UserConfig::getConfigFilepath() { @@ -1596,38 +1016,12 @@ QMap UserConfig::getKeyValueMap() { return map; } -void UserConfig::onNewConfigFileCreated() { +void UserConfig::init() { QString dirName = QDir(this->projectDir).dirName().toLower(); this->useEncounterJson = true; this->customScripts.clear(); } -void UserConfig::setProjectDir(QString projectDir) { - this->projectDir = projectDir; -} - -QString UserConfig::getProjectDir() { - return this->projectDir; -} - -void UserConfig::setRecentMap(const QString &map) { - this->recentMap = map; - this->save(); -} - -QString UserConfig::getRecentMap() { - return this->recentMap; -} - -void UserConfig::setEncounterJsonActive(bool active) { - this->useEncounterJson = active; - this->save(); -} - -bool UserConfig::getEncounterJsonActive() { - return this->useEncounterJson; -} - // Read input from the config to get the script paths and whether each is enabled or disbled. // The format is a comma-separated list of paths. Each path can be followed (before the comma) // by a :0 or :1 to indicate whether it should be disabled or enabled, respectively. If neither @@ -1664,7 +1058,6 @@ void UserConfig::setCustomScripts(QStringList scripts, QList enabled) { size_t size = qMin(scripts.length(), enabled.length()); for (size_t i = 0; i < size; i++) this->customScripts.insert(scripts.at(i), enabled.at(i)); - this->save(); } QStringList UserConfig::getCustomScriptPaths() { @@ -1708,7 +1101,6 @@ QMap ShortcutsConfig::getKeyValueMap() { void ShortcutsConfig::setDefaultShortcuts(const QObjectList &objects) { storeShortcutsFromList(StoreType::Default, objects); - save(); } QList ShortcutsConfig::defaultShortcuts(const QObject *object) const { @@ -1717,14 +1109,12 @@ QList ShortcutsConfig::defaultShortcuts(const QObject *object) con void ShortcutsConfig::setUserShortcuts(const QObjectList &objects) { storeShortcutsFromList(StoreType::User, objects); - save(); } void ShortcutsConfig::setUserShortcuts(const QMultiMap &objects_keySequences) { for (auto *object : objects_keySequences.uniqueKeys()) if (!object->objectName().isEmpty() && !object->objectName().startsWith("_q_")) storeShortcuts(StoreType::User, cfgKey(object), objects_keySequences.values(object)); - save(); } QList ShortcutsConfig::userShortcuts(const QObject *object) const { diff --git a/src/core/block.cpp b/src/core/block.cpp index 9eab9d13..fc4fe774 100644 --- a/src/core/block.cpp +++ b/src/core/block.cpp @@ -47,9 +47,9 @@ uint16_t Block::rawValue() const { } void Block::setLayout() { - bitsMetatileId.setMask(projectConfig.getBlockMetatileIdMask()); - bitsCollision.setMask(projectConfig.getBlockCollisionMask()); - bitsElevation.setMask(projectConfig.getBlockElevationMask()); + bitsMetatileId.setMask(projectConfig.blockMetatileIdMask); + bitsCollision.setMask(projectConfig.blockCollisionMask); + bitsElevation.setMask(projectConfig.blockElevationMask); } bool Block::operator ==(Block other) const { diff --git a/src/core/events.cpp b/src/core/events.cpp index 40067e22..b0ea3e39 100644 --- a/src/core/events.cpp +++ b/src/core/events.cpp @@ -35,7 +35,7 @@ int Event::getEventIndex() { void Event::setDefaultValues(Project *) { this->setX(0); this->setY(0); - this->setElevation(projectConfig.getDefaultElevation()); + this->setElevation(projectConfig.defaultElevation); } void Event::readCustomValues(QJsonObject values) { @@ -195,7 +195,7 @@ EventFrame *ObjectEvent::createEventFrame() { OrderedJson::object ObjectEvent::buildEventJson(Project *) { OrderedJson::object objectJson; - if (projectConfig.getEventCloneObjectEnabled()) { + if (projectConfig.eventCloneObjectEnabled) { objectJson["type"] = "object"; } objectJson["graphics_id"] = this->getGfx(); @@ -259,7 +259,7 @@ const QSet expectedObjectFields = { QSet ObjectEvent::getExpectedFields() { QSet expectedFields = QSet(); expectedFields = expectedObjectFields; - if (projectConfig.getEventCloneObjectEnabled()) { + if (projectConfig.eventCloneObjectEnabled) { expectedFields.insert("type"); } expectedFields << "x" << "y"; @@ -788,10 +788,10 @@ OrderedJson::object HiddenItemEvent::buildEventJson(Project *) { hiddenItemJson["elevation"] = this->getElevation(); hiddenItemJson["item"] = this->getItem(); hiddenItemJson["flag"] = this->getFlag(); - if (projectConfig.getHiddenItemQuantityEnabled()) { + if (projectConfig.hiddenItemQuantityEnabled) { hiddenItemJson["quantity"] = this->getQuantity(); } - if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) { + if (projectConfig.hiddenItemRequiresItemfinderEnabled) { hiddenItemJson["underfoot"] = this->getUnderfoot(); } @@ -806,10 +806,10 @@ bool HiddenItemEvent::loadFromJson(QJsonObject json, Project *) { this->setElevation(ParseUtil::jsonToInt(json["elevation"])); this->setItem(ParseUtil::jsonToQString(json["item"])); this->setFlag(ParseUtil::jsonToQString(json["flag"])); - if (projectConfig.getHiddenItemQuantityEnabled()) { + if (projectConfig.hiddenItemQuantityEnabled) { this->setQuantity(ParseUtil::jsonToInt(json["quantity"])); } - if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) { + if (projectConfig.hiddenItemRequiresItemfinderEnabled) { this->setUnderfoot(ParseUtil::jsonToBool(json["underfoot"])); } @@ -821,10 +821,10 @@ bool HiddenItemEvent::loadFromJson(QJsonObject json, Project *) { void HiddenItemEvent::setDefaultValues(Project *project) { this->setItem(project->itemNames.value(0, "0")); this->setFlag(project->flagNames.value(0, "0")); - if (projectConfig.getHiddenItemQuantityEnabled()) { + if (projectConfig.hiddenItemQuantityEnabled) { this->setQuantity(1); } - if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) { + if (projectConfig.hiddenItemRequiresItemfinderEnabled) { this->setUnderfoot(false); } } @@ -839,10 +839,10 @@ const QSet expectedHiddenItemFields = { QSet HiddenItemEvent::getExpectedFields() { QSet expectedFields = QSet(); expectedFields = expectedHiddenItemFields; - if (projectConfig.getHiddenItemQuantityEnabled()) { + if (projectConfig.hiddenItemQuantityEnabled) { expectedFields << "quantity"; } - if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) { + if (projectConfig.hiddenItemRequiresItemfinderEnabled) { expectedFields << "underfoot"; } expectedFields << "x" << "y"; @@ -930,10 +930,10 @@ OrderedJson::object HealLocationEvent::buildEventJson(Project *) { } void HealLocationEvent::setDefaultValues(Project *) { - this->setElevation(projectConfig.getDefaultElevation()); + this->setElevation(projectConfig.defaultElevation); if (!this->getMap()) return; - bool respawnEnabled = projectConfig.getHealLocationRespawnDataEnabled(); + bool respawnEnabled = projectConfig.healLocationRespawnDataEnabled; const QString mapConstant = Map::mapConstantFromName(this->getMap()->name, false); const QString prefix = projectConfig.getIdentifier(respawnEnabled ? ProjectIdentifier::define_spawn_prefix : ProjectIdentifier::define_heal_locations_prefix); diff --git a/src/core/heallocation.cpp b/src/core/heallocation.cpp index 42d444af..7fb424da 100644 --- a/src/core/heallocation.cpp +++ b/src/core/heallocation.cpp @@ -24,7 +24,7 @@ HealLocation HealLocation::fromEvent(Event *fromEvent) { healLocation.index = event->getIndex(); healLocation.x = event->getX(); healLocation.y = event->getY(); - if (projectConfig.getHealLocationRespawnDataEnabled()) { + if (projectConfig.healLocationRespawnDataEnabled) { healLocation.respawnNPC = event->getRespawnNPC(); healLocation.respawnMap = Map::mapConstantFromName(event->getRespawnMap(), false); } diff --git a/src/core/map.cpp b/src/core/map.cpp index a0ecf404..7e584db8 100644 --- a/src/core/map.cpp +++ b/src/core/map.cpp @@ -499,9 +499,9 @@ QStringList Map::getScriptLabels(Event::Group group) { } QString Map::getScriptsFilePath() const { - const bool usePoryscript = projectConfig.getUsePoryScript(); + const bool usePoryscript = projectConfig.usePoryScript; auto path = QDir::cleanPath(QString("%1/%2/%3/scripts") - .arg(projectConfig.getProjectDir()) + .arg(projectConfig.projectDir) .arg(projectConfig.getFilePath(ProjectFilePath::data_map_folders)) .arg(this->name)); auto extension = Project::getScriptFileExtension(usePoryscript); diff --git a/src/core/metatile.cpp b/src/core/metatile.cpp index 1a3dc11b..5f79129c 100644 --- a/src/core/metatile.cpp +++ b/src/core/metatile.cpp @@ -100,7 +100,7 @@ uint32_t Metatile::getMaxAttributesMask() { {2, 0xFFFF}, {4, 0xFFFFFFFF}, }; - return maxMasks.value(projectConfig.getMetatileAttributesSize(), 0); + return maxMasks.value(projectConfig.metatileAttributesSize, 0); } void Metatile::setLayout(Project * project) { @@ -109,10 +109,10 @@ void Metatile::setLayout(Project * project) { for (uint16_t i = Block::getMaxMetatileId(); i > 0; i /= 16) numMetatileIdChars++; - uint32_t behaviorMask = projectConfig.getMetatileBehaviorMask(); - uint32_t terrainTypeMask = projectConfig.getMetatileTerrainTypeMask(); - uint32_t encounterTypeMask = projectConfig.getMetatileEncounterTypeMask(); - uint32_t layerTypeMask = projectConfig.getMetatileLayerTypeMask(); + uint32_t behaviorMask = projectConfig.metatileBehaviorMask; + uint32_t terrainTypeMask = projectConfig.metatileTerrainTypeMask; + uint32_t encounterTypeMask = projectConfig.metatileEncounterTypeMask; + uint32_t layerTypeMask = projectConfig.metatileLayerTypeMask; // Calculate mask of bits not used by standard behaviors so we can preserve this data. uint32_t unusedMask = ~(behaviorMask | terrainTypeMask | encounterTypeMask | layerTypeMask); diff --git a/src/core/metatileparser.cpp b/src/core/metatileparser.cpp index 5b399328..104b757a 100644 --- a/src/core/metatileparser.cpp +++ b/src/core/metatileparser.cpp @@ -80,7 +80,7 @@ QList MetatileParser::parse(QString filepath, bool *error, bool prima // AdvanceMap .bvd files only contain 8 tiles of data per metatile. // If the user has triple-layer metatiles enabled we need to fill the remaining 4 tiles ourselves. - if (projectConfig.getTripleLayerMetatilesEnabled()) { + if (projectConfig.tripleLayerMetatilesEnabled) { Tile tile = Tile(); for (int j = 0; j < 4; j++) tiles.append(tile); diff --git a/src/core/network.cpp b/src/core/network.cpp index 94594d68..4f2a1c19 100644 --- a/src/core/network.cpp +++ b/src/core/network.cpp @@ -9,15 +9,10 @@ static const int DefaultWaitTime = 120; NetworkAccessManager::NetworkAccessManager(QObject * parent) : QNetworkAccessManager(parent) { - // We store rate limit end times in the user's config so that Porymap will still respect them after a restart. - // To avoid reading/writing to a local file during network operations, we only read/write the file when the - // manager is created/destroyed respectively. - this->rateLimitTimes = porymapConfig.getRateLimitTimes(); this->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy); }; NetworkAccessManager::~NetworkAccessManager() { - porymapConfig.setRateLimitTimes(this->rateLimitTimes); qDeleteAll(this->cache); } @@ -47,8 +42,9 @@ NetworkReplyData * NetworkAccessManager::get(const QUrl &url) { data->m_url = url; // If we are rate-limited, don't send a new request. - if (this->rateLimitTimes.contains(url)) { - auto time = this->rateLimitTimes.value(url); + // We store rate limit end times in the user's config so that Porymap will still respect them after a restart. + if (porymapConfig.rateLimitTimes.contains(url)) { + auto time = porymapConfig.rateLimitTimes.value(url); if (!time.isNull() && time > QDateTime::currentDateTime()) { data->m_retryAfter = time; data->m_error = QString("Rate limit reached. Please try again after %1.").arg(data->m_retryAfter.toString()); @@ -56,7 +52,7 @@ NetworkReplyData * NetworkAccessManager::get(const QUrl &url) { return data; } // Rate limiting expired - this->rateLimitTimes.remove(url); + porymapConfig.rateLimitTimes.remove(url); } QNetworkReply * reply = QNetworkAccessManager::get(this->getRequest(url)); @@ -117,7 +113,7 @@ void NetworkAccessManager::processReply(QNetworkReply * reply, NetworkReplyData data->m_error = "Service busy or unavailable. "; } data->m_error.append(QString("Please try again after %1.").arg(data->m_retryAfter.toString())); - this->rateLimitTimes.insert(url, data->m_retryAfter); + porymapConfig.rateLimitTimes.insert(url, data->m_retryAfter); return; } @@ -129,7 +125,7 @@ void NetworkAccessManager::processReply(QNetworkReply * reply, NetworkReplyData data->m_retryAfter = ok ? QDateTime::fromSecsSinceEpoch(limitReset).toLocalTime() : QDateTime::currentDateTime().addSecs(DefaultWaitTime);; data->m_error = QString("Too many requests. Please try again after %1.").arg(data->m_retryAfter.toString()); - this->rateLimitTimes.insert(url, data->m_retryAfter); + porymapConfig.rateLimitTimes.insert(url, data->m_retryAfter); return; } diff --git a/src/core/tileset.cpp b/src/core/tileset.cpp index 85fab154..7e5729ee 100644 --- a/src/core/tileset.cpp +++ b/src/core/tileset.cpp @@ -238,7 +238,7 @@ bool Tileset::appendToHeaders(QString root, QString friendlyName, bool usingAsm) dataString.append(QString("\t.4byte gTilesetTiles_%1\n").arg(friendlyName)); dataString.append(QString("\t.4byte gTilesetPalettes_%1\n").arg(friendlyName)); dataString.append(QString("\t.4byte gMetatiles_%1\n").arg(friendlyName)); - if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) { + if (projectConfig.baseGameVersion == BaseGameVersion::pokefirered) { dataString.append("\t.4byte NULL @ animation callback\n"); dataString.append(QString("\t.4byte gMetatileAttributes_%1\n").arg(friendlyName)); } else { @@ -248,13 +248,13 @@ bool Tileset::appendToHeaders(QString root, QString friendlyName, bool usingAsm) } else { // Append to C file dataString.append(QString("const struct Tileset %1 =\n{\n").arg(this->name)); - if (projectConfig.getTilesetsHaveIsCompressed()) dataString.append(" .isCompressed = TRUE,\n"); + if (projectConfig.tilesetsHaveIsCompressed) dataString.append(" .isCompressed = TRUE,\n"); dataString.append(QString(" .isSecondary = %1,\n").arg(isSecondaryStr)); dataString.append(QString(" .tiles = gTilesetTiles_%1,\n").arg(friendlyName)); dataString.append(QString(" .palettes = gTilesetPalettes_%1,\n").arg(friendlyName)); dataString.append(QString(" .metatiles = gMetatiles_%1,\n").arg(friendlyName)); dataString.append(QString(" .metatileAttributes = gMetatileAttributes_%1,\n").arg(friendlyName)); - if (projectConfig.getTilesetsHaveCallback()) dataString.append(" .callback = NULL,\n"); + if (projectConfig.tilesetsHaveCallback) dataString.append(" .callback = NULL,\n"); dataString.append("};\n"); } file.write(dataString.toUtf8()); @@ -325,7 +325,7 @@ bool Tileset::appendToMetatiles(QString root, QString friendlyName, bool usingAs } else { // Append to C file dataString.append(QString("const u16 gMetatiles_%1[] = INCBIN_U16(\"%2\");\n").arg(friendlyName, metatilesPath)); - QString numBits = QString::number(projectConfig.getMetatileAttributesSize() * 8); + QString numBits = QString::number(projectConfig.metatileAttributesSize * 8); dataString.append(QString("const u%1 gMetatileAttributes_%2[] = INCBIN_U%1(\"%3\");\n").arg(numBits, friendlyName, metatileAttrsPath)); } file.write(dataString.toUtf8()); @@ -358,7 +358,7 @@ QHash Tileset::getHeaderMemberMap(bool usingAsm) int paddingOffset = usingAsm ? 1 : 0; // The position of metatileAttributes changes between games - bool isPokefirered = (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered); + bool isPokefirered = (projectConfig.baseGameVersion == BaseGameVersion::pokefirered); int metatileAttrPosition = (isPokefirered ? 6 : 5) + paddingOffset; auto map = QHash(); diff --git a/src/editor.cpp b/src/editor.cpp index a2e4f3f9..9557ee13 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -1501,7 +1501,7 @@ void Editor::displayMovementPermissionSelector() { connect(movement_permissions_selector_item, &SelectablePixmapItem::selectionChanged, [this](int x, int y, int, int) { this->setCollisionTabSpinBoxes(x, y); }); - movement_permissions_selector_item->select(projectConfig.getDefaultCollision(), projectConfig.getDefaultElevation()); + movement_permissions_selector_item->select(projectConfig.defaultCollision, projectConfig.defaultElevation); } scene_collision_metatiles->addItem(movement_permissions_selector_item); @@ -1684,7 +1684,7 @@ int Editor::getBorderDrawDistance(int dimension) { } void Editor::onToggleGridClicked(bool checked) { - porymapConfig.setShowGrid(checked); + porymapConfig.showGrid = checked; if (ui->graphicsView_Map->scene()) ui->graphicsView_Map->scene()->update(); } @@ -1947,7 +1947,7 @@ void Editor::toggleBorderVisibility(bool visible, bool enableScriptCallback) { this->setBorderItemsVisible(visible); this->setConnectionItemsVisible(visible); - porymapConfig.setShowBorder(visible); + porymapConfig.showBorder = visible; if (enableScriptCallback) Scripting::cb_BorderVisibilityToggled(visible); } @@ -1993,7 +1993,7 @@ void Editor::redrawObject(DraggablePixmapItem *item) { // Warp events display a warning if they're not positioned on a metatile with a warp behavior. void Editor::updateWarpEventWarning(Event *event) { - if (porymapConfig.getWarpBehaviorWarningDisabled()) + if (porymapConfig.warpBehaviorWarningDisabled) return; if (!project || !map || !event || event->getEventType() != Event::Type::Warp) return; @@ -2004,7 +2004,7 @@ void Editor::updateWarpEventWarning(Event *event) { metatile = Tileset::getMetatile(block.metatileId(), map->layout->tileset_primary, map->layout->tileset_secondary); } // metatile may be null if the warp is in the map border. Display the warning in this case - bool validWarpBehavior = metatile && projectConfig.getWarpBehaviors().contains(metatile->behavior()); + bool validWarpBehavior = metatile && projectConfig.warpBehaviors.contains(metatile->behavior()); warpEvent->setWarningEnabled(!validWarpBehavior); } @@ -2014,7 +2014,7 @@ void Editor::updateWarpEventWarning(Event *event) { // events when the Events tab is opened. This does not cover the case where metatiles are painted while // still on the Events tab, such as by Undo/Redo or the scripting API. void Editor::updateWarpEventWarnings() { - if (porymapConfig.getWarpBehaviorWarningDisabled()) + if (porymapConfig.warpBehaviorWarningDisabled) return; if (selected_events) { for (auto selection : *selected_events) @@ -2189,7 +2189,7 @@ void Editor::openScript(const QString &scriptLabel) const { } void Editor::openInTextEditor(const QString &path, int lineNum) { - QString command = porymapConfig.getTextEditorGotoLine(); + QString command = porymapConfig.textEditorGotoLine; if (command.isEmpty()) { // Open map scripts in the system's default editor. QDesktopServices::openUrl(QUrl::fromLocalFile(path)); @@ -2206,7 +2206,7 @@ void Editor::openInTextEditor(const QString &path, int lineNum) { } void Editor::openProjectInTextEditor() const { - QString command = porymapConfig.getTextEditorOpenFolder(); + QString command = porymapConfig.textEditorOpenFolder; if (command.contains("%D")) command.replace("%D", '\"' + project->root + '\"'); else @@ -2279,7 +2279,7 @@ void Editor::setCollisionTabSpinBoxes(uint16_t collision, uint16_t elevation) { // Custom collision graphics may be provided by the user. void Editor::setCollisionGraphics() { - QString filepath = projectConfig.getCollisionSheetPath(); + QString filepath = projectConfig.collisionSheetPath; QImage imgSheet; if (filepath.isEmpty()) { @@ -2299,8 +2299,8 @@ void Editor::setCollisionGraphics() { // Users are not required to provide an image that gives an icon for every elevation/collision combination. // Instead they tell us how many are provided in their image by specifying the number of columns and rows. - const int imgColumns = projectConfig.getCollisionSheetWidth(); - const int imgRows = projectConfig.getCollisionSheetHeight(); + const int imgColumns = projectConfig.collisionSheetWidth; + const int imgRows = projectConfig.collisionSheetHeight; // Create a pixmap for the selector on the Collision tab. If a project was previously opened we'll also need to refresh the selector. this->collisionSheetPixmap = QPixmap::fromImage(imgSheet).scaled(MovementPermissionsSelector::CellWidth * imgColumns, diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 981dc04e..3b48da1e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -70,14 +70,14 @@ MainWindow::MainWindow(QWidget *parent) : logInfo(QString("Launching Porymap v%1").arg(QCoreApplication::applicationVersion())); this->initWindow(); - if (porymapConfig.getReopenOnLaunch() && this->openProject(porymapConfig.getRecentProject(), true)) + if (porymapConfig.reopenOnLaunch && this->openProject(porymapConfig.getRecentProject(), true)) on_toolButton_Paint_clicked(); // there is a bug affecting macOS users, where the trackpad deilveres a bad touch-release gesture // the warning is a bit annoying, so it is disabled here QLoggingCategory::setFilterRules(QStringLiteral("qt.pointer.dispatch=false")); - if (porymapConfig.getCheckForUpdates()) + if (porymapConfig.checkForUpdates) this->checkForUpdates(false); } @@ -285,12 +285,12 @@ void MainWindow::checkForUpdates(bool requestedByUser) { openSubWindow(this->updatePromoter); } else { // This is an automatic update check. Only run if we haven't done one in the last 5 minutes - QDateTime lastCheck = porymapConfig.getLastUpdateCheckTime(); + QDateTime lastCheck = porymapConfig.lastUpdateCheckTime; if (lastCheck.addSecs(5*60) >= QDateTime::currentDateTime()) return; } this->updatePromoter->checkForUpdates(); - porymapConfig.setLastUpdateCheckTime(QDateTime::currentDateTime()); + porymapConfig.lastUpdateCheckTime = QDateTime::currentDateTime(); } #else void MainWindow::checkForUpdates(bool) {} @@ -420,7 +420,7 @@ void MainWindow::setProjectSpecificUI() // TODO: This index should come from an enum ui->mainTabBar->setTabEnabled(4, editor->project->wildEncountersLoaded); - bool hasFlags = projectConfig.getMapAllowFlagsEnabled(); + bool hasFlags = projectConfig.mapAllowFlagsEnabled; ui->checkBox_AllowRunning->setVisible(hasFlags); ui->checkBox_AllowBiking->setVisible(hasFlags); ui->checkBox_AllowEscaping->setVisible(hasFlags); @@ -428,11 +428,11 @@ void MainWindow::setProjectSpecificUI() ui->label_AllowBiking->setVisible(hasFlags); ui->label_AllowEscaping->setVisible(hasFlags); - ui->newEventToolButton->newWeatherTriggerAction->setVisible(projectConfig.getEventWeatherTriggerEnabled()); - ui->newEventToolButton->newSecretBaseAction->setVisible(projectConfig.getEventSecretBaseEnabled()); - ui->newEventToolButton->newCloneObjectAction->setVisible(projectConfig.getEventCloneObjectEnabled()); + ui->newEventToolButton->newWeatherTriggerAction->setVisible(projectConfig.eventWeatherTriggerEnabled); + ui->newEventToolButton->newSecretBaseAction->setVisible(projectConfig.eventSecretBaseEnabled); + ui->newEventToolButton->newCloneObjectAction->setVisible(projectConfig.eventCloneObjectEnabled); - bool floorNumEnabled = projectConfig.getFloorNumberEnabled(); + bool floorNumEnabled = projectConfig.floorNumberEnabled; ui->spinBox_FloorNumber->setVisible(floorNumEnabled); ui->label_FloorNumber->setVisible(floorNumEnabled); @@ -457,8 +457,7 @@ void MainWindow::mapSortOrder_changed(QAction *action) if (i != mapSortOrder) { ui->toolButton_MapSortOrder->setIcon(action->icon()); - mapSortOrder = static_cast(i); - porymapConfig.setMapSortOrder(mapSortOrder); + porymapConfig.mapSortOrder = static_cast(i); if (isProjectOpen()) { sortMapList(); @@ -485,26 +484,26 @@ void MainWindow::applyMapListFilter(QString filterText) } void MainWindow::loadUserSettings() { - ui->actionBetter_Cursors->setChecked(porymapConfig.getPrettyCursors()); - this->editor->settings->betterCursors = porymapConfig.getPrettyCursors(); - ui->actionPlayer_View_Rectangle->setChecked(porymapConfig.getShowPlayerView()); - this->editor->settings->playerViewRectEnabled = porymapConfig.getShowPlayerView(); - ui->actionCursor_Tile_Outline->setChecked(porymapConfig.getShowCursorTile()); - this->editor->settings->cursorTileRectEnabled = porymapConfig.getShowCursorTile(); - ui->checkBox_ToggleBorder->setChecked(porymapConfig.getShowBorder()); - ui->checkBox_ToggleGrid->setChecked(porymapConfig.getShowGrid()); - mapSortOrder = porymapConfig.getMapSortOrder(); + ui->actionBetter_Cursors->setChecked(porymapConfig.prettyCursors); + this->editor->settings->betterCursors = porymapConfig.prettyCursors; + ui->actionPlayer_View_Rectangle->setChecked(porymapConfig.showPlayerView); + this->editor->settings->playerViewRectEnabled = porymapConfig.showPlayerView; + ui->actionCursor_Tile_Outline->setChecked(porymapConfig.showCursorTile); + this->editor->settings->cursorTileRectEnabled = porymapConfig.showCursorTile; + ui->checkBox_ToggleBorder->setChecked(porymapConfig.showBorder); + ui->checkBox_ToggleGrid->setChecked(porymapConfig.showGrid); + mapSortOrder = porymapConfig.mapSortOrder; ui->horizontalSlider_CollisionTransparency->blockSignals(true); - this->editor->collisionOpacity = static_cast(porymapConfig.getCollisionOpacity()) / 100; - ui->horizontalSlider_CollisionTransparency->setValue(porymapConfig.getCollisionOpacity()); + this->editor->collisionOpacity = static_cast(porymapConfig.collisionOpacity) / 100; + ui->horizontalSlider_CollisionTransparency->setValue(porymapConfig.collisionOpacity); ui->horizontalSlider_CollisionTransparency->blockSignals(false); ui->horizontalSlider_MetatileZoom->blockSignals(true); - ui->horizontalSlider_MetatileZoom->setValue(porymapConfig.getMetatilesZoom()); + ui->horizontalSlider_MetatileZoom->setValue(porymapConfig.metatilesZoom); ui->horizontalSlider_MetatileZoom->blockSignals(false); ui->horizontalSlider_CollisionZoom->blockSignals(true); - ui->horizontalSlider_CollisionZoom->setValue(porymapConfig.getCollisionZoom()); + ui->horizontalSlider_CollisionZoom->setValue(porymapConfig.collisionZoom); ui->horizontalSlider_CollisionZoom->blockSignals(false); - setTheme(porymapConfig.getTheme()); + setTheme(porymapConfig.theme); } void MainWindow::restoreWindowState() { @@ -558,32 +557,38 @@ bool MainWindow::openProject(const QString &dir, bool initial) { this->statusBar()->showMessage(openMessage); logInfo(openMessage); - // TODO: Don't save these yet - userConfig.setProjectDir(dir); + userConfig.projectDir = dir; userConfig.load(); - projectConfig.setProjectDir(dir); + projectConfig.projectDir = dir; projectConfig.load(); this->newMapDefaultsSet = false; Scripting::init(this); + // Create the project this->editor->project = new Project(this); QObject::connect(this->editor->project, &Project::reloadProject, this, &MainWindow::on_action_Reload_Project_triggered); QObject::connect(this->editor->project, &Project::mapCacheCleared, this, &MainWindow::onMapCacheCleared); QObject::connect(this->editor->project, &Project::uncheckMonitorFilesAction, [this]() { - porymapConfig.setMonitorFiles(false); + porymapConfig.monitorFiles = false; if (this->preferenceEditor) this->preferenceEditor->updateFields(); }); this->editor->project->set_root(dir); + // Load the project if (!(loadDataStructures() && populateMapList() && setInitialMap())) { this->statusBar()->showMessage(QString("Failed to open %1").arg(projectString)); showProjectOpenFailure(); delete this->editor->project; + // TODO: Allow changing project settings at this point return false; } + + // Only create the config files once the project has opened successfully in case the user selected an invalid directory + userConfig.save(); + projectConfig.save(); showWindowTitle(); this->statusBar()->showMessage(QString("Opened %1").arg(projectString)); @@ -619,7 +624,7 @@ bool MainWindow::setInitialMap() { names = editor->project->mapNames; // Try to set most recently-opened map, if it's still in the list. - QString recentMap = userConfig.getRecentMap(); + QString recentMap = userConfig.recentMap; if (!recentMap.isEmpty() && names.contains(recentMap) && setMap(recentMap, true)) return true; @@ -687,11 +692,7 @@ QString MainWindow::getExistingDirectory(QString dir) { void MainWindow::on_action_Open_Project_triggered() { - QString recent = "."; - if (!userConfig.getRecentMap().isEmpty()) { - recent = userConfig.getRecentMap(); - } - QString dir = getExistingDirectory(recent); + QString dir = getExistingDirectory(!userConfig.recentMap.isEmpty() ? userConfig.recentMap : "."); if (!dir.isEmpty()) openProject(dir); } @@ -743,7 +744,7 @@ bool MainWindow::setMap(QString map_name, bool scrollTreeView) { connect(editor->map, &Map::mapNeedsRedrawing, this, &MainWindow::onMapNeedsRedrawing); connect(editor->map, &Map::modified, [this](){ this->markMapEdited(); }); - setRecentMap(map_name); + userConfig.recentMap = map_name; updateMapList(); Scripting::cb_MapOpened(map_name); @@ -829,10 +830,6 @@ void MainWindow::openWarpMap(QString map_name, int event_id, Event::Group event_ } } -void MainWindow::setRecentMap(QString mapName) { - userConfig.setRecentMap(mapName); -} - void MainWindow::displayMapProperties() { // Block signals to the comboboxes while they are being modified const QSignalBlocker blocker1(ui->comboBox_Song); @@ -1407,7 +1404,7 @@ void MainWindow::updateTilesetEditor() { } double MainWindow::getMetatilesZoomScale() { - return pow(3.0, static_cast(porymapConfig.getMetatilesZoom() - 30) / 30.0); + return pow(3.0, static_cast(porymapConfig.metatilesZoom - 30) / 30.0); } void MainWindow::redrawMetatileSelection() { @@ -1541,8 +1538,8 @@ void MainWindow::copy() { collisions.clear(); for (int i = 0; i < metatiles.length(); i++) { OrderedJson::object collision; - collision["collision"] = projectConfig.getDefaultCollision(); - collision["elevation"] = projectConfig.getDefaultElevation(); + collision["collision"] = projectConfig.defaultCollision; + collision["elevation"] = projectConfig.defaultElevation; collisions.append(collision); } } @@ -1781,10 +1778,10 @@ void MainWindow::on_mapViewTab_tabBarClicked(int index) editor->setEditingCollision(); } else if (index == 2) { editor->setEditingMap(); - if (projectConfig.getPrefabFilepath().isEmpty() && !projectConfig.getPrefabImportPrompted()) { + if (projectConfig.prefabFilepath.isEmpty() && !projectConfig.prefabImportPrompted) { // User hasn't set up prefabs and hasn't been prompted before. // Ask if they'd like to import the default prefabs file. - if (prefab.tryImportDefaultPrefabs(this, projectConfig.getBaseGameVersion())) + if (prefab.tryImportDefaultPrefabs(this, projectConfig.baseGameVersion)) prefab.updatePrefabUi(this->editor->map); } } @@ -1830,14 +1827,14 @@ void MainWindow::on_actionZoom_Out_triggered() { } void MainWindow::on_actionBetter_Cursors_triggered() { - porymapConfig.setPrettyCursors(ui->actionBetter_Cursors->isChecked()); + porymapConfig.prettyCursors = ui->actionBetter_Cursors->isChecked(); this->editor->settings->betterCursors = ui->actionBetter_Cursors->isChecked(); } void MainWindow::on_actionPlayer_View_Rectangle_triggered() { bool enabled = ui->actionPlayer_View_Rectangle->isChecked(); - porymapConfig.setShowPlayerView(enabled); + porymapConfig.showPlayerView = enabled; this->editor->settings->playerViewRectEnabled = enabled; if ((this->editor->map_item && this->editor->map_item->has_mouse) || (this->editor->collision_item && this->editor->collision_item->has_mouse)) { @@ -1849,7 +1846,7 @@ void MainWindow::on_actionPlayer_View_Rectangle_triggered() void MainWindow::on_actionCursor_Tile_Outline_triggered() { bool enabled = ui->actionCursor_Tile_Outline->isChecked(); - porymapConfig.setShowCursorTile(enabled); + porymapConfig.showCursorTile = enabled; this->editor->settings->cursorTileRectEnabled = enabled; if ((this->editor->map_item && this->editor->map_item->has_mouse) || (this->editor->collision_item && this->editor->collision_item->has_mouse)) { @@ -2198,7 +2195,7 @@ void MainWindow::eventTabChanged(int index) { void MainWindow::on_horizontalSlider_CollisionTransparency_valueChanged(int value) { this->editor->collisionOpacity = static_cast(value) / 100; - porymapConfig.setCollisionOpacity(value); + porymapConfig.collisionOpacity = value; this->editor->collision_item->draw(true); } @@ -2635,7 +2632,7 @@ void MainWindow::on_pushButton_ChangeDimensions_clicked() heightSpinBox->setValue(editor->map->getHeight()); bwidthSpinBox->setValue(editor->map->getBorderWidth()); bheightSpinBox->setValue(editor->map->getBorderHeight()); - if (projectConfig.getUseCustomBorderSize()) { + if (projectConfig.useCustomBorderSize) { form.addRow(new QLabel("Map Width"), widthSpinBox); form.addRow(new QLabel("Map Height"), heightSpinBox); form.addRow(new QLabel("Border Width"), bwidthSpinBox); @@ -2777,7 +2774,7 @@ void MainWindow::on_actionPreferences_triggered() { } void MainWindow::togglePreferenceSpecificUi() { - if (porymapConfig.getTextEditorOpenFolder().isEmpty()) + if (porymapConfig.textEditorOpenFolder.isEmpty()) ui->actionOpen_Project_in_Text_Editor->setEnabled(false); else ui->actionOpen_Project_in_Text_Editor->setEnabled(true); @@ -2797,7 +2794,7 @@ void MainWindow::openProjectSettingsEditor(int tab) { } void MainWindow::on_actionProject_Settings_triggered() { - this->openProjectSettingsEditor(porymapConfig.getProjectSettingsTab()); + this->openProjectSettingsEditor(porymapConfig.projectSettingsTab); } void MainWindow::onWarpBehaviorWarningClicked() { @@ -2843,7 +2840,7 @@ void MainWindow::reloadScriptEngine() { Scripting::init(this); Scripting::populateGlobalObject(this); // Lying to the scripts here, simulating a project reload - Scripting::cb_ProjectOpened(projectConfig.getProjectDir()); + Scripting::cb_ProjectOpened(projectConfig.projectDir); if (editor && editor->map) Scripting::cb_MapOpened(editor->map->name); } @@ -2870,7 +2867,7 @@ void MainWindow::on_tableWidget_CustomHeaderFields_cellChanged(int, int) } void MainWindow::on_horizontalSlider_MetatileZoom_valueChanged(int value) { - porymapConfig.setMetatilesZoom(value); + porymapConfig.metatilesZoom = value; double scale = pow(3.0, static_cast(value - 30) / 30.0); QTransform transform; @@ -2895,7 +2892,7 @@ void MainWindow::on_horizontalSlider_MetatileZoom_valueChanged(int value) { } void MainWindow::on_horizontalSlider_CollisionZoom_valueChanged(int value) { - porymapConfig.setCollisionZoom(value); + porymapConfig.collisionZoom = value; double scale = pow(3.0, static_cast(value - 30) / 30.0); QTransform transform; @@ -2981,7 +2978,6 @@ bool MainWindow::askToFixRegionMapEditor() { // Attempt to close any open sub-windows of the main window, giving each a chance to abort the process. // Each of these are expected to be a QPointer to a widget with WA_DeleteOnClose set, so manually deleting // and nullifying the pointer members is not necessary here. -// TODO: Testing bool MainWindow::closeSupplementaryWindows() { if (this->tilesetEditor && !this->tilesetEditor->close()) return false; @@ -3022,9 +3018,6 @@ bool MainWindow::closeProject() { return false; } } - projectConfig.save(); - userConfig.save(); - editor->closeProject(); return true; diff --git a/src/project.cpp b/src/project.cpp index c6550c6a..d50c305e 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -49,7 +49,7 @@ Project::~Project() void Project::initSignals() { // detect changes to specific filepaths being monitored QObject::connect(&fileWatcher, &QFileSystemWatcher::fileChanged, [this](QString changed){ - if (!porymapConfig.getMonitorFiles()) return; + if (!porymapConfig.monitorFiles) return; if (modifiedFileTimestamps.contains(changed)) { if (QDateTime::currentMSecsSinceEpoch() < modifiedFileTimestamps[changed]) { return; @@ -77,7 +77,7 @@ void Project::initSignals() { emit reloadProject(); } else if (choice == QMessageBox::No) { if (showAgainCheck.isChecked()) { - porymapConfig.setMonitorFiles(false); + porymapConfig.monitorFiles = false; emit uncheckMonitorFilesAction(); } } @@ -162,13 +162,13 @@ const QSet defaultTopLevelMapFields = { QSet Project::getTopLevelMapFields() { QSet topLevelMapFields = defaultTopLevelMapFields; - if (projectConfig.getMapAllowFlagsEnabled()) { + if (projectConfig.mapAllowFlagsEnabled) { topLevelMapFields.insert("allow_cycling"); topLevelMapFields.insert("allow_escaping"); topLevelMapFields.insert("allow_running"); } - if (projectConfig.getFloorNumberEnabled()) { + if (projectConfig.floorNumberEnabled) { topLevelMapFields.insert("floor_number"); } return topLevelMapFields; @@ -197,12 +197,12 @@ bool Project::loadMapData(Map* map) { map->show_location = ParseUtil::jsonToBool(mapObj["show_map_name"]); map->battle_scene = ParseUtil::jsonToQString(mapObj["battle_scene"]); - if (projectConfig.getMapAllowFlagsEnabled()) { + if (projectConfig.mapAllowFlagsEnabled) { map->allowBiking = ParseUtil::jsonToBool(mapObj["allow_cycling"]); map->allowEscaping = ParseUtil::jsonToBool(mapObj["allow_escaping"]); map->allowRunning = ParseUtil::jsonToBool(mapObj["allow_running"]); } - if (projectConfig.getFloorNumberEnabled()) { + if (projectConfig.floorNumberEnabled) { map->floorNumber = ParseUtil::jsonToInt(mapObj["floor_number"]); } map->sharedEventsMap = ParseUtil::jsonToQString(mapObj["shared_events_map"]); @@ -211,11 +211,10 @@ bool Project::loadMapData(Map* map) { // Events map->events[Event::Group::Object].clear(); QJsonArray objectEventsArr = mapObj["object_events"].toArray(); - bool hasCloneObjects = projectConfig.getEventCloneObjectEnabled(); for (int i = 0; i < objectEventsArr.size(); i++) { QJsonObject event = objectEventsArr[i].toObject(); // If clone objects are not enabled then no type field is present - QString type = hasCloneObjects ? ParseUtil::jsonToQString(event["type"]) : "object"; + QString type = projectConfig.eventCloneObjectEnabled ? ParseUtil::jsonToQString(event["type"]) : "object"; if (type.isEmpty() || type == "object") { ObjectEvent *object = new ObjectEvent(); object->loadFromJson(event, this); @@ -297,11 +296,11 @@ bool Project::loadMapData(Map* map) { heal->setMap(map); heal->setX(loc.x); heal->setY(loc.y); - heal->setElevation(projectConfig.getDefaultElevation()); + heal->setElevation(projectConfig.defaultElevation); heal->setLocationName(loc.mapName); heal->setIdName(loc.idName); heal->setIndex(loc.index); - if (projectConfig.getHealLocationRespawnDataEnabled()) { + if (projectConfig.healLocationRespawnDataEnabled) { heal->setRespawnMap(mapConstantsToMapNames.value(QString(mapPrefix + loc.respawnMap))); heal->setRespawnNPC(loc.respawnNPC); } @@ -438,7 +437,6 @@ bool Project::readMapLayouts() { "border_filepath", "blockdata_filepath", }; - bool useCustomBorderSize = projectConfig.getUseCustomBorderSize(); for (int i = 0; i < layouts.size(); i++) { QJsonObject layoutObj = layouts[i].toObject(); if (layoutObj.isEmpty()) @@ -479,7 +477,7 @@ bool Project::readMapLayouts() { return false; } layout->height = lheight; - if (useCustomBorderSize) { + if (projectConfig.useCustomBorderSize) { int bwidth = ParseUtil::jsonToInt(layoutObj["border_width"]); if (bwidth <= 0) { // 0 is an expected border width/height that should be handled, GF used it for the RS layouts in FRLG logWarn(QString("Invalid 'border_width' value '%1' for %2 in %3. Must be greater than 0. Using default (%4) instead.") @@ -545,7 +543,6 @@ void Project::saveMapLayouts() { OrderedJson::object layoutsObj; layoutsObj["layouts_table_label"] = layoutsLabel; - bool useCustomBorderSize = projectConfig.getUseCustomBorderSize(); OrderedJson::array layoutsArr; for (QString layoutId : mapLayoutsTableMaster) { MapLayout *layout = mapLayouts.value(layoutId); @@ -554,7 +551,7 @@ void Project::saveMapLayouts() { layoutObj["name"] = layout->name; layoutObj["width"] = layout->width; layoutObj["height"] = layout->height; - if (useCustomBorderSize) { + if (projectConfig.useCustomBorderSize) { layoutObj["border_width"] = layout->border_width; layoutObj["border_height"] = layout->border_height; } @@ -768,7 +765,7 @@ void Project::saveHealLocationsData(Map *map) { } // Create the definition text for each data table - bool respawnEnabled = projectConfig.getHealLocationRespawnDataEnabled(); + bool respawnEnabled = projectConfig.healLocationRespawnDataEnabled; const QString qualifiers = QString(healLocationDataQualifiers.isStatic ? "static " : "") + QString(healLocationDataQualifiers.isConst ? "const " : ""); @@ -951,10 +948,9 @@ void Project::saveTilesetMetatileAttributes(Tileset *tileset) { QFile attrs_file(tileset->metatile_attrs_path); if (attrs_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QByteArray data; - int attrSize = projectConfig.getMetatileAttributesSize(); for (Metatile *metatile : tileset->metatiles) { uint32_t attributes = metatile->getAttributes(); - for (int i = 0; i < attrSize; i++) + for (int i = 0; i < projectConfig.metatileAttributesSize; i++) data.append(static_cast(attributes >> (8 * i))); } attrs_file.write(data); @@ -1090,7 +1086,7 @@ void Project::setNewMapBlockdata(Map *map) { map->layout->blockdata.clear(); int width = map->getWidth(); int height = map->getHeight(); - Block block(projectConfig.getDefaultMetatileId(), projectConfig.getDefaultCollision(), projectConfig.getDefaultElevation()); + Block block(projectConfig.defaultMetatileId, projectConfig.defaultCollision, projectConfig.defaultElevation); for (int i = 0; i < width * height; i++) { map->layout->blockdata.append(block); } @@ -1119,8 +1115,7 @@ void Project::setNewMapBorder(Map *map) { int width = map->getBorderWidth(); int height = map->getBorderHeight(); - const QList configMetatileIds = projectConfig.getNewMapBorderMetatileIds(); - if (configMetatileIds.length() != width * height) { + if (projectConfig.newMapBorderMetatileIds.length() != width * height) { // Border size doesn't match the number of default border metatiles. // Fill the border with empty metatiles. for (int i = 0; i < width * height; i++) { @@ -1129,7 +1124,7 @@ void Project::setNewMapBorder(Map *map) { } else { // Fill the border with the default metatiles from the config. for (int i = 0; i < width * height; i++) { - map->layout->border.append(configMetatileIds.at(i)); + map->layout->border.append(projectConfig.newMapBorderMetatileIds.at(i)); } } @@ -1172,18 +1167,17 @@ void Project::saveMap(Map *map) { } // Create file data/maps//scripts.inc - QString text = this->getScriptDefaultString(projectConfig.getUsePoryScript(), map->name); - saveTextFile(mapDataDir + "/scripts" + this->getScriptFileExtension(projectConfig.getUsePoryScript()), text); + QString text = this->getScriptDefaultString(projectConfig.usePoryScript, map->name); + saveTextFile(mapDataDir + "/scripts" + this->getScriptFileExtension(projectConfig.usePoryScript), text); - bool usesTextFile = projectConfig.getCreateMapTextFileEnabled(); - if (usesTextFile) { + if (projectConfig.createMapTextFileEnabled) { // Create file data/maps//text.inc - saveTextFile(mapDataDir + "/text" + this->getScriptFileExtension(projectConfig.getUsePoryScript()), "\n"); + saveTextFile(mapDataDir + "/text" + this->getScriptFileExtension(projectConfig.usePoryScript), "\n"); } // Simply append to data/event_scripts.s. text = QString("\n\t.include \"%1%2/scripts.inc\"\n").arg(basePath, map->name); - if (usesTextFile) { + if (projectConfig.createMapTextFileEnabled) { text += QString("\t.include \"%1%2/text.inc\"\n").arg(basePath, map->name); } appendTextFile(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_event_scripts), text); @@ -1214,13 +1208,13 @@ void Project::saveMap(Map *map) { mapObj["requires_flash"] = map->requiresFlash; mapObj["weather"] = map->weather; mapObj["map_type"] = map->type; - if (projectConfig.getMapAllowFlagsEnabled()) { + if (projectConfig.mapAllowFlagsEnabled) { mapObj["allow_cycling"] = map->allowBiking; mapObj["allow_escaping"] = map->allowEscaping; mapObj["allow_running"] = map->allowRunning; } mapObj["show_map_name"] = map->show_location; - if (projectConfig.getFloorNumberEnabled()) { + if (projectConfig.floorNumberEnabled) { mapObj["floor_number"] = map->floorNumber; } mapObj["battle_scene"] = map->battle_scene; @@ -1328,6 +1322,12 @@ void Project::saveAllDataStructures() { saveMapGroups(); saveMapConstantsHeader(); saveWildMonData(); + saveConfig(); +} + +void Project::saveConfig() { + projectConfig.save(); + userConfig.save(); } void Project::loadTilesetAssets(Tileset* tileset) { @@ -1466,7 +1466,7 @@ void Project::loadTilesetMetatiles(Tileset* tileset) { if (attrs_file.open(QIODevice::ReadOnly)) { QByteArray data = attrs_file.readAll(); int num_metatiles = tileset->metatiles.count(); - int attrSize = projectConfig.getMetatileAttributesSize(); + int attrSize = projectConfig.metatileAttributesSize; int num_metatileAttrs = data.length() / attrSize; if (num_metatiles != num_metatileAttrs) { logWarn(QString("Metatile count %1 does not match metatile attribute count %2 in %3").arg(num_metatiles).arg(num_metatileAttrs).arg(tileset->name)); @@ -1603,7 +1603,7 @@ bool Project::readWildMonData() { wildMonData.clear(); encounterGroupLabels.clear(); this->wildEncountersLoaded = false; - if (!userConfig.getEncounterJsonActive()) { + if (!userConfig.useEncounterJson) { return true; } @@ -1813,7 +1813,7 @@ Project::DataQualifiers Project::getDataQualifiers(QString text, QString label) } QString Project::getDefaultPrimaryTilesetLabel() { - QString defaultLabel = projectConfig.getDefaultPrimaryTileset(); + QString defaultLabel = projectConfig.defaultPrimaryTileset; if (!this->primaryTilesetLabels.contains(defaultLabel)) { QString firstLabel = this->primaryTilesetLabels.first(); logWarn(QString("Unable to find default primary tileset '%1', using '%2' instead.").arg(defaultLabel).arg(firstLabel)); @@ -1823,7 +1823,7 @@ QString Project::getDefaultPrimaryTilesetLabel() { } QString Project::getDefaultSecondaryTilesetLabel() { - QString defaultLabel = projectConfig.getDefaultSecondaryTileset(); + QString defaultLabel = projectConfig.defaultSecondaryTileset; if (!this->secondaryTilesetLabels.contains(defaultLabel)) { QString firstLabel = this->secondaryTilesetLabels.first(); logWarn(QString("Unable to find default secondary tileset '%1', using '%2' instead.").arg(defaultLabel).arg(firstLabel)); @@ -1975,9 +1975,6 @@ bool Project::readFieldmapMasks() { const QStringList defineNames = defines.keys(); this->disabledSettingsNames = QSet(defineNames.constBegin(), defineNames.constEnd()); - // Avoid repeatedly writing the config file - projectConfig.setSaveDisabled(true); - // Read Block masks auto readBlockMask = [defines](const QString name, uint16_t *value) { auto it = defines.find(name); @@ -1992,21 +1989,22 @@ bool Project::readFieldmapMasks() { } return true; }; + uint16_t blockMask; if (readBlockMask(metatileIdMaskName, &blockMask)) - projectConfig.setBlockMetatileIdMask(blockMask); + projectConfig.blockMetatileIdMask = blockMask; if (readBlockMask(collisionMaskName, &blockMask)) - projectConfig.setBlockCollisionMask(blockMask); + projectConfig.blockCollisionMask = blockMask; if (readBlockMask(elevationMaskName, &blockMask)) - projectConfig.setBlockElevationMask(blockMask); + projectConfig.blockElevationMask = blockMask; // Read RSE metatile attribute masks auto it = defines.find(behaviorMaskName); if (it != defines.end()) - projectConfig.setMetatileBehaviorMask(static_cast(it.value())); + projectConfig.metatileBehaviorMask = static_cast(it.value()); it = defines.find(layerTypeMaskName); if (it != defines.end()) - projectConfig.setMetatileLayerTypeMask(static_cast(it.value())); + projectConfig.metatileLayerTypeMask = static_cast(it.value()); // pokefirered keeps its attribute masks in a separate table, parse this too. const QString attrTableName = projectConfig.getIdentifier(ProjectIdentifier::symbol_attribute_table); @@ -2023,13 +2021,13 @@ bool Project::readFieldmapMasks() { // Read terrain type mask uint32_t mask = attrTable.value(terrainTypeTableName).toUInt(&ok, 0); if (ok) { - projectConfig.setMetatileTerrainTypeMask(mask); + projectConfig.metatileTerrainTypeMask = mask; this->disabledSettingsNames.insert(terrainTypeTableName); } // Read encounter type mask mask = attrTable.value(encounterTypeTableName).toUInt(&ok, 0); if (ok) { - projectConfig.setMetatileEncounterTypeMask(mask); + projectConfig.metatileEncounterTypeMask = mask; this->disabledSettingsNames.insert(encounterTypeTableName); } // If we haven't already parsed behavior and layer type then try those too @@ -2037,7 +2035,7 @@ bool Project::readFieldmapMasks() { // Read behavior mask mask = attrTable.value(behaviorTableName).toUInt(&ok, 0); if (ok) { - projectConfig.setMetatileBehaviorMask(mask); + projectConfig.metatileBehaviorMask = mask; this->disabledSettingsNames.insert(behaviorTableName); } } @@ -2045,12 +2043,11 @@ bool Project::readFieldmapMasks() { // Read layer type mask mask = attrTable.value(layerTypeTableName).toUInt(&ok, 0); if (ok) { - projectConfig.setMetatileLayerTypeMask(mask); + projectConfig.metatileLayerTypeMask = mask; this->disabledSettingsNames.insert(layerTypeTableName); } } } - projectConfig.setSaveDisabled(false); return true; } @@ -2102,7 +2099,7 @@ bool Project::readHealLocations() { static const QRegularExpression re_comments("//.*?(\r\n?|\n)|/\\*.*?\\*/", QRegularExpression::DotMatchesEverythingOption); text.replace(re_comments, ""); - bool respawnEnabled = projectConfig.getHealLocationRespawnDataEnabled(); + bool respawnEnabled = projectConfig.healLocationRespawnDataEnabled; // Search for the name of the main Heal Locations table const QRegularExpression tableNameExpr(QString("%1\\s+(?[A-Za-z0-9_]+)\\[").arg(projectConfig.getIdentifier(ProjectIdentifier::symbol_heal_locations_type))); @@ -2260,7 +2257,7 @@ bool Project::readWeatherNames() { } bool Project::readCoordEventWeatherNames() { - if (!projectConfig.getEventWeatherTriggerEnabled()) + if (!projectConfig.eventWeatherTriggerEnabled) return true; const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_coord_event_weather)}; @@ -2273,7 +2270,7 @@ bool Project::readCoordEventWeatherNames() { } bool Project::readSecretBaseIds() { - if (!projectConfig.getEventSecretBaseEnabled()) + if (!projectConfig.eventSecretBaseEnabled) return true; const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_secret_bases)}; @@ -2316,7 +2313,7 @@ bool Project::readMetatileBehaviors() { if (defines.isEmpty()) { // Not having any metatile behavior names is ok (their values will be displayed instead). // If the user's metatiles can have nonzero values then warn them, as they likely want names. - if (projectConfig.getMetatileBehaviorMask()) + if (projectConfig.metatileBehaviorMask) logWarn(QString("Failed to read metatile behaviors from %1.").arg(filename)); return true; } @@ -2357,7 +2354,7 @@ bool Project::readObjEventGfxConstants() { bool Project::readMiscellaneousConstants() { miscConstants.clear(); - if (userConfig.getEncounterJsonActive()) { + if (userConfig.useEncounterJson) { const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_pokemon); const QString minLevelName = projectConfig.getIdentifier(ProjectIdentifier::define_min_level); const QString maxLevelName = projectConfig.getIdentifier(ProjectIdentifier::define_max_level); @@ -2436,9 +2433,8 @@ QStringList Project::getEventScriptsFilePaths() const { QStringList filePaths(QDir::cleanPath(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_event_scripts))); const QString scriptsDir = QDir::cleanPath(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_scripts_folders)); const QString mapsDir = QDir::cleanPath(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_map_folders)); - const bool usePoryscript = projectConfig.getUsePoryScript(); - if (usePoryscript) { + if (projectConfig.usePoryScript) { QDirIterator it_pory_shared(scriptsDir, {"*.pory"}, QDir::Files); while (it_pory_shared.hasNext()) filePaths << it_pory_shared.next(); @@ -2739,7 +2735,7 @@ QString Project::getExistingFilepath(QString filepath) { if (filepath.isEmpty() || QFile::exists(filepath)) return filepath; - filepath = QDir::cleanPath(projectConfig.getProjectDir() + QDir::separator() + filepath); + filepath = QDir::cleanPath(projectConfig.projectDir + QDir::separator() + filepath); if (QFile::exists(filepath)) return filepath; @@ -2752,25 +2748,19 @@ QString Project::getExistingFilepath(QString filepath) { // can be limited by fieldmap defines) // Once we've read data from the project files we can adjust these accordingly. void Project::applyParsedLimits() { - // Avoid repeatedly writing the config file - projectConfig.setSaveDisabled(true); - uint32_t maxMask = Metatile::getMaxAttributesMask(); - projectConfig.setMetatileBehaviorMask(projectConfig.getMetatileBehaviorMask() & maxMask); - projectConfig.setMetatileTerrainTypeMask(projectConfig.getMetatileTerrainTypeMask() & maxMask); - projectConfig.setMetatileEncounterTypeMask(projectConfig.getMetatileEncounterTypeMask() & maxMask); - projectConfig.setMetatileLayerTypeMask(projectConfig.getMetatileLayerTypeMask() & maxMask); + projectConfig.metatileBehaviorMask &= maxMask; + projectConfig.metatileTerrainTypeMask &= maxMask; + projectConfig.metatileEncounterTypeMask &= maxMask; + projectConfig.metatileLayerTypeMask &= maxMask; Block::setLayout(); Metatile::setLayout(this); Project::num_metatiles_primary = qMin(Project::num_metatiles_primary, Block::getMaxMetatileId() + 1); - projectConfig.setDefaultMetatileId(qMin(projectConfig.getDefaultMetatileId(), Block::getMaxMetatileId())); - projectConfig.setDefaultElevation(qMin(projectConfig.getDefaultElevation(), Block::getMaxElevation())); - projectConfig.setDefaultCollision(qMin(projectConfig.getDefaultCollision(), Block::getMaxCollision())); - projectConfig.setCollisionSheetHeight(qMin(projectConfig.getCollisionSheetHeight(), Block::getMaxElevation() + 1)); - projectConfig.setCollisionSheetWidth(qMin(projectConfig.getCollisionSheetWidth(), Block::getMaxCollision() + 1)); - - projectConfig.setSaveDisabled(false); - projectConfig.save(); + projectConfig.defaultMetatileId = qMin(projectConfig.defaultMetatileId, Block::getMaxMetatileId()); + projectConfig.defaultElevation = qMin(projectConfig.defaultElevation, Block::getMaxElevation()); + projectConfig.defaultCollision = qMin(projectConfig.defaultCollision, Block::getMaxCollision()); + projectConfig.collisionSheetHeight = qMin(projectConfig.collisionSheetHeight, Block::getMaxElevation() + 1); + projectConfig.collisionSheetWidth = qMin(projectConfig.collisionSheetWidth, Block::getMaxCollision() + 1); } diff --git a/src/scriptapi/apimap.cpp b/src/scriptapi/apimap.cpp index 3741092e..2911fe74 100644 --- a/src/scriptapi/apimap.cpp +++ b/src/scriptapi/apimap.cpp @@ -295,7 +295,7 @@ int MainWindow::getBorderHeight() { } void MainWindow::setBorderDimensions(int width, int height) { - if (!this->editor || !this->editor->map || !projectConfig.getUseCustomBorderSize()) + if (!this->editor || !this->editor->map || !projectConfig.useCustomBorderSize) return; if (width < 1 || height < 1 || width > MAX_BORDER_WIDTH || height > MAX_BORDER_HEIGHT) return; @@ -305,7 +305,7 @@ void MainWindow::setBorderDimensions(int width, int height) { } void MainWindow::setBorderWidth(int width) { - if (!this->editor || !this->editor->map || !projectConfig.getUseCustomBorderSize()) + if (!this->editor || !this->editor->map || !projectConfig.useCustomBorderSize) return; if (width < 1 || width > MAX_BORDER_WIDTH) return; @@ -315,7 +315,7 @@ void MainWindow::setBorderWidth(int width) { } void MainWindow::setBorderHeight(int height) { - if (!this->editor || !this->editor->map || !projectConfig.getUseCustomBorderSize()) + if (!this->editor || !this->editor->map || !projectConfig.useCustomBorderSize) return; if (height < 1 || height > MAX_BORDER_HEIGHT) return; diff --git a/src/ui/citymappixmapitem.cpp b/src/ui/citymappixmapitem.cpp index eb9a2b32..c0a96717 100644 --- a/src/ui/citymappixmapitem.cpp +++ b/src/ui/citymappixmapitem.cpp @@ -15,7 +15,7 @@ void CityMapPixmapItem::init() { if (!binFile.open(QIODevice::ReadOnly)) return; data = binFile.readAll(); - if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) { + if (projectConfig.baseGameVersion == BaseGameVersion::pokeruby) { for (int i = 0; i < data.size(); i++) data[i] = data[i] ^ 0x80; } @@ -46,7 +46,7 @@ void CityMapPixmapItem::save() { logError(QString("Cannot save city map tilemap to %1.").arg(file)); return; } - if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) { + if (projectConfig.baseGameVersion == BaseGameVersion::pokeruby) { for (int i = 0; i < data.size(); i++) data[i] = data[i] ^ 0x80; } diff --git a/src/ui/customscriptseditor.cpp b/src/ui/customscriptseditor.cpp index 31e2ad7a..13650053 100644 --- a/src/ui/customscriptseditor.cpp +++ b/src/ui/customscriptseditor.cpp @@ -11,7 +11,7 @@ CustomScriptsEditor::CustomScriptsEditor(QWidget *parent) : QMainWindow(parent), ui(new Ui::CustomScriptsEditor), - baseDir(userConfig.getProjectDir() + QDir::separator()) + baseDir(userConfig.projectDir + QDir::separator()) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); @@ -23,7 +23,7 @@ CustomScriptsEditor::CustomScriptsEditor(QWidget *parent) : for (int i = 0; i < paths.length(); i++) this->displayScript(paths.at(i), enabled.at(i)); - this->fileDialogDir = userConfig.getProjectDir(); + this->fileDialogDir = userConfig.projectDir; connect(ui->button_CreateNewScript, &QAbstractButton::clicked, this, &CustomScriptsEditor::createNewScript); connect(ui->button_LoadScript, &QAbstractButton::clicked, this, &CustomScriptsEditor::loadScript); diff --git a/src/ui/eventframes.cpp b/src/ui/eventframes.cpp index 7537588f..90d5b776 100644 --- a/src/ui/eventframes.cpp +++ b/src/ui/eventframes.cpp @@ -360,7 +360,7 @@ void ObjectFrame::initialize() { // script this->combo_script->setCurrentText(this->object->getScript()); - if (porymapConfig.getTextEditorGotoLine().isEmpty()) + if (porymapConfig.textEditorGotoLine.isEmpty()) this->button_script->hide(); // flag @@ -858,16 +858,16 @@ void HiddenItemFrame::initialize() { this->combo_flag->setTextItem(this->hiddenItem->getFlag()); // quantity - if (projectConfig.getHiddenItemQuantityEnabled()) { + if (projectConfig.hiddenItemQuantityEnabled) { this->spinner_quantity->setValue(this->hiddenItem->getQuantity()); } - this->hideable_quantity->setVisible(projectConfig.getHiddenItemQuantityEnabled()); + this->hideable_quantity->setVisible(projectConfig.hiddenItemQuantityEnabled); // underfoot - if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) { + if (projectConfig.hiddenItemRequiresItemfinderEnabled) { this->check_itemfinder->setChecked(this->hiddenItem->getUnderfoot()); } - this->hideable_itemfinder->setVisible(projectConfig.getHiddenItemRequiresItemfinderEnabled()); + this->hideable_itemfinder->setVisible(projectConfig.hiddenItemRequiresItemfinderEnabled); } void HiddenItemFrame::populate(Project *project) { @@ -971,7 +971,7 @@ void HealLocationFrame::connectSignals(MainWindow *window) { EventFrame::connectSignals(window); - if (projectConfig.getHealLocationRespawnDataEnabled()) { + if (projectConfig.healLocationRespawnDataEnabled) { this->combo_respawn_map->disconnect(); connect(this->combo_respawn_map, &QComboBox::currentTextChanged, [this](const QString &text) { this->healLocation->setRespawnMap(text); @@ -992,7 +992,7 @@ void HealLocationFrame::initialize() { const QSignalBlocker blocker(this); EventFrame::initialize(); - bool respawnEnabled = projectConfig.getHealLocationRespawnDataEnabled(); + bool respawnEnabled = projectConfig.healLocationRespawnDataEnabled; if (respawnEnabled) { this->combo_respawn_map->setTextItem(this->healLocation->getRespawnMap()); this->spinner_respawn_npc->setValue(this->healLocation->getRespawnNPC()); @@ -1008,6 +1008,6 @@ void HealLocationFrame::populate(Project *project) { const QSignalBlocker blocker(this); EventFrame::populate(project); - if (projectConfig.getHealLocationRespawnDataEnabled()) + if (projectConfig.healLocationRespawnDataEnabled) this->combo_respawn_map->addItems(project->mapNames); } diff --git a/src/ui/imageproviders.cpp b/src/ui/imageproviders.cpp index f52bf590..86f0c07a 100644 --- a/src/ui/imageproviders.cpp +++ b/src/ui/imageproviders.cpp @@ -48,7 +48,6 @@ QImage getMetatileImage( QList> palettes = Tileset::getBlockPalettes(primaryTileset, secondaryTileset, useTruePalettes); QPainter metatile_painter(&metatile_image); - bool isTripleLayerMetatile = projectConfig.getTripleLayerMetatilesEnabled(); const int numLayers = 3; // When rendering, metatiles always have 3 layers uint32_t layerType = metatile->layerType(); for (int layer = 0; layer < numLayers; layer++) @@ -60,7 +59,7 @@ QImage getMetatileImage( // Get the tile to render next Tile tile; int tileOffset = (y * 2) + x; - if (isTripleLayerMetatile) { + if (projectConfig.tripleLayerMetatilesEnabled) { tile = metatile->tiles.value(tileOffset + (l * 4)); } else { // "Vanilla" metatiles only have 8 tiles, but render 12. diff --git a/src/ui/newmappopup.cpp b/src/ui/newmappopup.cpp index fdc3f79c..be6499e6 100644 --- a/src/ui/newmappopup.cpp +++ b/src/ui/newmappopup.cpp @@ -49,7 +49,7 @@ void NewMapPopup::init() { ui->spinBox_NewMap_Floor_Number->setMaximum(127); // Hide config specific ui elements - bool hasFlags = projectConfig.getMapAllowFlagsEnabled(); + bool hasFlags = projectConfig.mapAllowFlagsEnabled; ui->checkBox_NewMap_Allow_Running->setVisible(hasFlags); ui->checkBox_NewMap_Allow_Biking->setVisible(hasFlags); ui->checkBox_NewMap_Allow_Escape_Rope->setVisible(hasFlags); @@ -57,13 +57,13 @@ void NewMapPopup::init() { ui->label_NewMap_Allow_Biking->setVisible(hasFlags); ui->label_NewMap_Allow_Escape_Rope->setVisible(hasFlags); - bool hasCustomBorders = projectConfig.getUseCustomBorderSize(); + bool hasCustomBorders = projectConfig.useCustomBorderSize; ui->spinBox_NewMap_BorderWidth->setVisible(hasCustomBorders); ui->spinBox_NewMap_BorderHeight->setVisible(hasCustomBorders); ui->label_NewMap_BorderWidth->setVisible(hasCustomBorders); ui->label_NewMap_BorderHeight->setVisible(hasCustomBorders); - bool hasFloorNumber = projectConfig.getFloorNumberEnabled(); + bool hasFloorNumber = projectConfig.floorNumberEnabled; ui->spinBox_NewMap_Floor_Number->setVisible(hasFloorNumber); ui->label_NewMap_Floor_Number->setVisible(hasFloorNumber); @@ -272,7 +272,7 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() { layout->name = QString("%1_Layout").arg(newMap->name); layout->width = this->ui->spinBox_NewMap_Width->value(); layout->height = this->ui->spinBox_NewMap_Height->value(); - if (projectConfig.getUseCustomBorderSize()) { + if (projectConfig.useCustomBorderSize) { layout->border_width = this->ui->spinBox_NewMap_BorderWidth->value(); layout->border_height = this->ui->spinBox_NewMap_BorderHeight->value(); } else { @@ -296,12 +296,12 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() { newMap->needsHealLocation = true; } - if (projectConfig.getMapAllowFlagsEnabled()) { + if (projectConfig.mapAllowFlagsEnabled) { newMap->allowRunning = this->ui->checkBox_NewMap_Allow_Running->isChecked(); newMap->allowBiking = this->ui->checkBox_NewMap_Allow_Biking->isChecked(); newMap->allowEscaping = this->ui->checkBox_NewMap_Allow_Escape_Rope->isChecked(); } - if (projectConfig.getFloorNumberEnabled()) { + if (projectConfig.floorNumberEnabled) { newMap->floorNumber = this->ui->spinBox_NewMap_Floor_Number->value(); } diff --git a/src/ui/newtilesetdialog.cpp b/src/ui/newtilesetdialog.cpp index e38c499e..fa951879 100644 --- a/src/ui/newtilesetdialog.cpp +++ b/src/ui/newtilesetdialog.cpp @@ -15,7 +15,7 @@ NewTilesetDialog::NewTilesetDialog(Project* project, QWidget *parent) : QRegularExpressionValidator *validator = new QRegularExpressionValidator(expression); this->ui->nameLineEdit->setValidator(validator); - bool checkerboard = porymapConfig.getTilesetCheckerboardFill(); + bool checkerboard = porymapConfig.tilesetCheckerboardFill; this->ui->fillCheckBox->setChecked(checkerboard); this->checkerboardFill = checkerboard; @@ -46,5 +46,5 @@ void NewTilesetDialog::NameOrSecondaryChanged() { void NewTilesetDialog::FillChanged() { this->checkerboardFill = this->ui->fillCheckBox->isChecked(); - porymapConfig.setTilesetCheckerboardFill(this->checkerboardFill); + porymapConfig.tilesetCheckerboardFill = this->checkerboardFill; } diff --git a/src/ui/paletteeditor.cpp b/src/ui/paletteeditor.cpp index 7422d7db..8dcd2a7a 100644 --- a/src/ui/paletteeditor.cpp +++ b/src/ui/paletteeditor.cpp @@ -87,7 +87,7 @@ PaletteEditor::PaletteEditor(Project *project, Tileset *primaryTileset, Tileset connect(this->pickButtons[i], &QToolButton::clicked, [this, i](){ this->pickColor(i); }); } - int bitDepth = porymapConfig.getPaletteEditorBitDepth(); + int bitDepth = porymapConfig.paletteEditorBitDepth; if (bitDepth == 15) { this->ui->bit_depth_15->setChecked(true); } else { @@ -233,7 +233,7 @@ void PaletteEditor::setBitDepth(int bits) { break; } this->bitDepth = bits; - porymapConfig.setPaletteEditorBitDepth(bits); + porymapConfig.paletteEditorBitDepth = bits; refreshColorUis(); setSignalsEnabled(true); } diff --git a/src/ui/prefab.cpp b/src/ui/prefab.cpp index c5ad7f9b..3559b9a8 100644 --- a/src/ui/prefab.cpp +++ b/src/ui/prefab.cpp @@ -23,7 +23,7 @@ const QString defaultFilepath = "prefabs.json"; void Prefab::loadPrefabs() { this->items.clear(); - QString filepath = projectConfig.getPrefabFilepath(); + QString filepath = projectConfig.prefabFilepath; if (filepath.isEmpty()) return; ParseUtil parser; @@ -86,15 +86,14 @@ void Prefab::loadPrefabs() { } void Prefab::savePrefabs() { - QString filepath = projectConfig.getPrefabFilepath(); - if (filepath.isEmpty()) { - filepath = defaultFilepath; - projectConfig.setPrefabFilepath(filepath); - } + if (projectConfig.prefabFilepath.isEmpty()) + projectConfig.prefabFilepath = defaultFilepath; + + QString filepath = projectConfig.prefabFilepath; QFileInfo info(filepath); if (info.isRelative()) { - filepath = QDir::cleanPath(projectConfig.getProjectDir() + QDir::separator() + filepath); + filepath = QDir::cleanPath(projectConfig.projectDir + QDir::separator() + filepath); } QFile prefabsFile(filepath); if (!prefabsFile.open(QIODevice::WriteOnly)) { @@ -287,7 +286,7 @@ bool Prefab::tryImportDefaultPrefabs(QWidget * parent, BaseGameVersion version, if (fileInfo.suffix().isEmpty()) filepath += ".json"; if (fileInfo.isRelative()) { - absFilepath = QDir::cleanPath(projectConfig.getProjectDir() + QDir::separator() + filepath); + absFilepath = QDir::cleanPath(projectConfig.projectDir + QDir::separator() + filepath); } else { absFilepath = filepath; } @@ -313,10 +312,10 @@ bool Prefab::tryImportDefaultPrefabs(QWidget * parent, BaseGameVersion version, bool acceptedImport = (prompt == QMessageBox::Yes); if (acceptedImport) { // Sets up the default prefabs.json filepath. - projectConfig.setPrefabFilepath(filepath); + projectConfig.prefabFilepath = filepath; QFile prefabsFile(absFilepath); if (!prefabsFile.open(QIODevice::WriteOnly)) { - projectConfig.setPrefabFilepath(QString()); + projectConfig.prefabFilepath = QString(); logError(QString("Error: Could not open %1 for writing").arg(absFilepath)); QMessageBox messageBox(parent); @@ -346,7 +345,7 @@ bool Prefab::tryImportDefaultPrefabs(QWidget * parent, BaseGameVersion version, this->loadPrefabs(); } - projectConfig.setPrefabImportPrompted(true); + projectConfig.prefabImportPrompted = true; return acceptedImport; } diff --git a/src/ui/preferenceeditor.cpp b/src/ui/preferenceeditor.cpp index eacc3f3d..a51b614d 100644 --- a/src/ui/preferenceeditor.cpp +++ b/src/ui/preferenceeditor.cpp @@ -44,28 +44,26 @@ void PreferenceEditor::initFields() { } void PreferenceEditor::updateFields() { - themeSelector->setCurrentText(porymapConfig.getTheme()); - ui->lineEdit_TextEditorOpenFolder->setText(porymapConfig.getTextEditorOpenFolder()); - ui->lineEdit_TextEditorGotoLine->setText(porymapConfig.getTextEditorGotoLine()); - ui->checkBox_MonitorProjectFiles->setChecked(porymapConfig.getMonitorFiles()); - ui->checkBox_OpenRecentProject->setChecked(porymapConfig.getReopenOnLaunch()); - ui->checkBox_CheckForUpdates->setChecked(porymapConfig.getCheckForUpdates()); + themeSelector->setCurrentText(porymapConfig.theme); + ui->lineEdit_TextEditorOpenFolder->setText(porymapConfig.textEditorOpenFolder); + ui->lineEdit_TextEditorGotoLine->setText(porymapConfig.textEditorGotoLine); + ui->checkBox_MonitorProjectFiles->setChecked(porymapConfig.monitorFiles); + ui->checkBox_OpenRecentProject->setChecked(porymapConfig.reopenOnLaunch); + ui->checkBox_CheckForUpdates->setChecked(porymapConfig.checkForUpdates); } void PreferenceEditor::saveFields() { - if (themeSelector->currentText() != porymapConfig.getTheme()) { + if (themeSelector->currentText() != porymapConfig.theme) { const auto theme = themeSelector->currentText(); - porymapConfig.setTheme(theme); + porymapConfig.theme = theme; emit themeChanged(theme); } - porymapConfig.setSaveDisabled(true); - porymapConfig.setTextEditorOpenFolder(ui->lineEdit_TextEditorOpenFolder->text()); - porymapConfig.setTextEditorGotoLine(ui->lineEdit_TextEditorGotoLine->text()); - porymapConfig.setMonitorFiles(ui->checkBox_MonitorProjectFiles->isChecked()); - porymapConfig.setReopenOnLaunch(ui->checkBox_OpenRecentProject->isChecked()); - porymapConfig.setCheckForUpdates(ui->checkBox_CheckForUpdates->isChecked()); - porymapConfig.setSaveDisabled(false); + porymapConfig.textEditorOpenFolder = ui->lineEdit_TextEditorOpenFolder->text(); + porymapConfig.textEditorGotoLine = ui->lineEdit_TextEditorGotoLine->text(); + porymapConfig.monitorFiles = ui->checkBox_MonitorProjectFiles->isChecked(); + porymapConfig.reopenOnLaunch = ui->checkBox_OpenRecentProject->isChecked(); + porymapConfig.checkForUpdates = ui->checkBox_CheckForUpdates->isChecked(); porymapConfig.save(); emit preferencesSaved(); diff --git a/src/ui/projectsettingseditor.cpp b/src/ui/projectsettingseditor.cpp index 950dd87b..8a360eb2 100644 --- a/src/ui/projectsettingseditor.cpp +++ b/src/ui/projectsettingseditor.cpp @@ -18,7 +18,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(QWidget *parent, Project *project) QMainWindow(parent), ui(new Ui::ProjectSettingsEditor), project(project), - baseDir(userConfig.getProjectDir() + QDir::separator()) + baseDir(projectConfig.projectDir + QDir::separator()) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); @@ -109,7 +109,7 @@ void ProjectSettingsEditor::initUi() { static const QRegularExpression expression_HexList(QString("^(%1,)*%1$").arg(regex_Hex)); // Comma-separated list of hex values QRegularExpressionValidator *validator_HexList = new QRegularExpressionValidator(expression_HexList); ui->lineEdit_BorderMetatiles->setValidator(validator_HexList); - this->setBorderMetatilesUi(projectConfig.getUseCustomBorderSize()); + this->setBorderMetatilesUi(projectConfig.useCustomBorderSize); // Validate that the text added to the warp behavior list could be a valid define // (we don't care whether it actually is a metatile behavior define) @@ -184,12 +184,12 @@ void ProjectSettingsEditor::disableParsedSetting(QWidget * widget, const QString // Remember the current settings tab for future sessions void ProjectSettingsEditor::on_mainTabs_tabBarClicked(int index) { - porymapConfig.setProjectSettingsTab(index); + porymapConfig.projectSettingsTab = index; } void ProjectSettingsEditor::setTab(int index) { ui->mainTabs->setCurrentIndex(index); - porymapConfig.setProjectSettingsTab(index); + porymapConfig.projectSettingsTab = index; } void ProjectSettingsEditor::setBorderMetatilesUi(bool customSize) { @@ -424,10 +424,10 @@ void ProjectSettingsEditor::refresh() { this->refreshing = true; // Block signals // Set combo box texts - ui->comboBox_DefaultPrimaryTileset->setTextItem(projectConfig.getDefaultPrimaryTileset()); - ui->comboBox_DefaultSecondaryTileset->setTextItem(projectConfig.getDefaultSecondaryTileset()); + ui->comboBox_DefaultPrimaryTileset->setTextItem(projectConfig.defaultPrimaryTileset); + ui->comboBox_DefaultSecondaryTileset->setTextItem(projectConfig.defaultSecondaryTileset); ui->comboBox_BaseGameVersion->setTextItem(projectConfig.getBaseGameVersionString()); - ui->comboBox_AttributesSize->setTextItem(QString::number(projectConfig.getMetatileAttributesSize())); + ui->comboBox_AttributesSize->setTextItem(QString::number(projectConfig.metatileAttributesSize)); this->updateAttributeLimits(ui->comboBox_AttributesSize->currentText()); this->prevIconSpecies = QString(); @@ -435,45 +435,44 @@ void ProjectSettingsEditor::refresh() { this->updatePokemonIconPath(ui->comboBox_IconSpecies->currentText()); // Set check box states - ui->checkBox_UsePoryscript->setChecked(projectConfig.getUsePoryScript()); - ui->checkBox_ShowWildEncounterTables->setChecked(userConfig.getEncounterJsonActive()); - ui->checkBox_CreateTextFile->setChecked(projectConfig.getCreateMapTextFileEnabled()); - ui->checkBox_EnableTripleLayerMetatiles->setChecked(projectConfig.getTripleLayerMetatilesEnabled()); - ui->checkBox_EnableRequiresItemfinder->setChecked(projectConfig.getHiddenItemRequiresItemfinderEnabled()); - ui->checkBox_EnableQuantity->setChecked(projectConfig.getHiddenItemQuantityEnabled()); - ui->checkBox_EnableCloneObjects->setChecked(projectConfig.getEventCloneObjectEnabled()); - ui->checkBox_EnableWeatherTriggers->setChecked(projectConfig.getEventWeatherTriggerEnabled()); - ui->checkBox_EnableSecretBases->setChecked(projectConfig.getEventSecretBaseEnabled()); - ui->checkBox_EnableRespawn->setChecked(projectConfig.getHealLocationRespawnDataEnabled()); - ui->checkBox_EnableAllowFlags->setChecked(projectConfig.getMapAllowFlagsEnabled()); - ui->checkBox_EnableFloorNumber->setChecked(projectConfig.getFloorNumberEnabled()); - ui->checkBox_EnableCustomBorderSize->setChecked(projectConfig.getUseCustomBorderSize()); - ui->checkBox_OutputCallback->setChecked(projectConfig.getTilesetsHaveCallback()); - ui->checkBox_OutputIsCompressed->setChecked(projectConfig.getTilesetsHaveIsCompressed()); - ui->checkBox_DisableWarning->setChecked(porymapConfig.getWarpBehaviorWarningDisabled()); + ui->checkBox_UsePoryscript->setChecked(projectConfig.usePoryScript); + ui->checkBox_ShowWildEncounterTables->setChecked(userConfig.useEncounterJson); + ui->checkBox_CreateTextFile->setChecked(projectConfig.createMapTextFileEnabled); + ui->checkBox_EnableTripleLayerMetatiles->setChecked(projectConfig.tripleLayerMetatilesEnabled); + ui->checkBox_EnableRequiresItemfinder->setChecked(projectConfig.hiddenItemRequiresItemfinderEnabled); + ui->checkBox_EnableQuantity->setChecked(projectConfig.hiddenItemQuantityEnabled); + ui->checkBox_EnableCloneObjects->setChecked(projectConfig.eventCloneObjectEnabled); + ui->checkBox_EnableWeatherTriggers->setChecked(projectConfig.eventWeatherTriggerEnabled); + ui->checkBox_EnableSecretBases->setChecked(projectConfig.eventSecretBaseEnabled); + ui->checkBox_EnableRespawn->setChecked(projectConfig.healLocationRespawnDataEnabled); + ui->checkBox_EnableAllowFlags->setChecked(projectConfig.mapAllowFlagsEnabled); + ui->checkBox_EnableFloorNumber->setChecked(projectConfig.floorNumberEnabled); + ui->checkBox_EnableCustomBorderSize->setChecked(projectConfig.useCustomBorderSize); + ui->checkBox_OutputCallback->setChecked(projectConfig.tilesetsHaveCallback); + ui->checkBox_OutputIsCompressed->setChecked(projectConfig.tilesetsHaveIsCompressed); + ui->checkBox_DisableWarning->setChecked(porymapConfig.warpBehaviorWarningDisabled); // Set spin box values - ui->spinBox_Elevation->setValue(projectConfig.getDefaultElevation()); - ui->spinBox_Collision->setValue(projectConfig.getDefaultCollision()); - ui->spinBox_FillMetatile->setValue(projectConfig.getDefaultMetatileId()); - ui->spinBox_MaxElevation->setValue(projectConfig.getCollisionSheetHeight() - 1); - ui->spinBox_MaxCollision->setValue(projectConfig.getCollisionSheetWidth() - 1); - ui->spinBox_BehaviorMask->setValue(projectConfig.getMetatileBehaviorMask() & ui->spinBox_BehaviorMask->maximum()); - ui->spinBox_EncounterTypeMask->setValue(projectConfig.getMetatileEncounterTypeMask() & ui->spinBox_EncounterTypeMask->maximum()); - ui->spinBox_LayerTypeMask->setValue(projectConfig.getMetatileLayerTypeMask() & ui->spinBox_LayerTypeMask->maximum()); - ui->spinBox_TerrainTypeMask->setValue(projectConfig.getMetatileTerrainTypeMask() & ui->spinBox_TerrainTypeMask->maximum()); - ui->spinBox_MetatileIdMask->setValue(projectConfig.getBlockMetatileIdMask() & ui->spinBox_MetatileIdMask->maximum()); - ui->spinBox_CollisionMask->setValue(projectConfig.getBlockCollisionMask() & ui->spinBox_CollisionMask->maximum()); - ui->spinBox_ElevationMask->setValue(projectConfig.getBlockElevationMask() & ui->spinBox_ElevationMask->maximum()); + ui->spinBox_Elevation->setValue(projectConfig.defaultElevation); + ui->spinBox_Collision->setValue(projectConfig.defaultCollision); + ui->spinBox_FillMetatile->setValue(projectConfig.defaultMetatileId); + ui->spinBox_MaxElevation->setValue(projectConfig.collisionSheetHeight - 1); + ui->spinBox_MaxCollision->setValue(projectConfig.collisionSheetWidth - 1); + ui->spinBox_BehaviorMask->setValue(projectConfig.metatileBehaviorMask & ui->spinBox_BehaviorMask->maximum()); + ui->spinBox_EncounterTypeMask->setValue(projectConfig.metatileEncounterTypeMask & ui->spinBox_EncounterTypeMask->maximum()); + ui->spinBox_LayerTypeMask->setValue(projectConfig.metatileLayerTypeMask & ui->spinBox_LayerTypeMask->maximum()); + ui->spinBox_TerrainTypeMask->setValue(projectConfig.metatileTerrainTypeMask & ui->spinBox_TerrainTypeMask->maximum()); + ui->spinBox_MetatileIdMask->setValue(projectConfig.blockMetatileIdMask & ui->spinBox_MetatileIdMask->maximum()); + ui->spinBox_CollisionMask->setValue(projectConfig.blockCollisionMask & ui->spinBox_CollisionMask->maximum()); + ui->spinBox_ElevationMask->setValue(projectConfig.blockElevationMask & ui->spinBox_ElevationMask->maximum()); // Set (and sync) border metatile IDs - auto metatileIds = projectConfig.getNewMapBorderMetatileIds(); - this->setBorderMetatileIds(false, metatileIds); - this->setBorderMetatileIds(true, metatileIds); + this->setBorderMetatileIds(false, projectConfig.newMapBorderMetatileIds); + this->setBorderMetatileIds(true, projectConfig.newMapBorderMetatileIds); // Set line edit texts - ui->lineEdit_PrefabsPath->setText(projectConfig.getPrefabFilepath()); - ui->lineEdit_CollisionGraphics->setText(projectConfig.getCollisionSheetPath()); + ui->lineEdit_PrefabsPath->setText(projectConfig.prefabFilepath); + ui->lineEdit_CollisionGraphics->setText(projectConfig.collisionSheetPath); ui->lineEdit_ObjectsIcon->setText(projectConfig.getEventIconPath(Event::Group::Object)); ui->lineEdit_WarpsIcon->setText(projectConfig.getEventIconPath(Event::Group::Warp)); ui->lineEdit_TriggersIcon->setText(projectConfig.getEventIconPath(Event::Group::Coord)); @@ -485,9 +484,8 @@ void ProjectSettingsEditor::refresh() { lineEdit->setText(projectConfig.getCustomIdentifier(lineEdit->objectName())); // Set warp behaviors - auto behaviorValues = projectConfig.getWarpBehaviors(); QStringList behaviorNames; - for (auto value : behaviorValues) { + for (auto value : projectConfig.warpBehaviors) { if (project->metatileBehaviorMapInverse.contains(value)) behaviorNames.append(project->metatileBehaviorMapInverse.value(value)); } @@ -500,50 +498,47 @@ void ProjectSettingsEditor::save() { if (!this->hasUnsavedChanges) return; - // Prevent a call to save() for each of the config settings - projectConfig.setSaveDisabled(true); - // Save combo box settings - projectConfig.setDefaultPrimaryTileset(ui->comboBox_DefaultPrimaryTileset->currentText()); - projectConfig.setDefaultSecondaryTileset(ui->comboBox_DefaultSecondaryTileset->currentText()); - projectConfig.setBaseGameVersion(projectConfig.stringToBaseGameVersion(ui->comboBox_BaseGameVersion->currentText())); - projectConfig.setMetatileAttributesSize(ui->comboBox_AttributesSize->currentText().toInt()); + projectConfig.defaultPrimaryTileset = ui->comboBox_DefaultPrimaryTileset->currentText(); + projectConfig.defaultSecondaryTileset = ui->comboBox_DefaultSecondaryTileset->currentText(); + projectConfig.baseGameVersion = projectConfig.stringToBaseGameVersion(ui->comboBox_BaseGameVersion->currentText()); + projectConfig.metatileAttributesSize = ui->comboBox_AttributesSize->currentText().toInt(); // Save check box settings - projectConfig.setUsePoryScript(ui->checkBox_UsePoryscript->isChecked()); - userConfig.setEncounterJsonActive(ui->checkBox_ShowWildEncounterTables->isChecked()); - projectConfig.setCreateMapTextFileEnabled(ui->checkBox_CreateTextFile->isChecked()); - projectConfig.setTripleLayerMetatilesEnabled(ui->checkBox_EnableTripleLayerMetatiles->isChecked()); - projectConfig.setHiddenItemRequiresItemfinderEnabled(ui->checkBox_EnableRequiresItemfinder->isChecked()); - projectConfig.setHiddenItemQuantityEnabled(ui->checkBox_EnableQuantity->isChecked()); - projectConfig.setEventCloneObjectEnabled(ui->checkBox_EnableCloneObjects->isChecked()); - projectConfig.setEventWeatherTriggerEnabled(ui->checkBox_EnableWeatherTriggers->isChecked()); - projectConfig.setEventSecretBaseEnabled(ui->checkBox_EnableSecretBases->isChecked()); - projectConfig.setHealLocationRespawnDataEnabled(ui->checkBox_EnableRespawn->isChecked()); - projectConfig.setMapAllowFlagsEnabled(ui->checkBox_EnableAllowFlags->isChecked()); - projectConfig.setFloorNumberEnabled(ui->checkBox_EnableFloorNumber->isChecked()); - projectConfig.setUseCustomBorderSize(ui->checkBox_EnableCustomBorderSize->isChecked()); - projectConfig.setTilesetsHaveCallback(ui->checkBox_OutputCallback->isChecked()); - projectConfig.setTilesetsHaveIsCompressed(ui->checkBox_OutputIsCompressed->isChecked()); - porymapConfig.setWarpBehaviorWarningDisabled(ui->checkBox_DisableWarning->isChecked()); + projectConfig.usePoryScript = ui->checkBox_UsePoryscript->isChecked(); + userConfig.useEncounterJson = ui->checkBox_ShowWildEncounterTables->isChecked(); + projectConfig.createMapTextFileEnabled = ui->checkBox_CreateTextFile->isChecked(); + projectConfig.tripleLayerMetatilesEnabled = ui->checkBox_EnableTripleLayerMetatiles->isChecked(); + projectConfig.hiddenItemRequiresItemfinderEnabled = ui->checkBox_EnableRequiresItemfinder->isChecked(); + projectConfig.hiddenItemQuantityEnabled = ui->checkBox_EnableQuantity->isChecked(); + projectConfig.eventCloneObjectEnabled = ui->checkBox_EnableCloneObjects->isChecked(); + projectConfig.eventWeatherTriggerEnabled = ui->checkBox_EnableWeatherTriggers->isChecked(); + projectConfig.eventSecretBaseEnabled = ui->checkBox_EnableSecretBases->isChecked(); + projectConfig.healLocationRespawnDataEnabled = ui->checkBox_EnableRespawn->isChecked(); + projectConfig.mapAllowFlagsEnabled = ui->checkBox_EnableAllowFlags->isChecked(); + projectConfig.floorNumberEnabled = ui->checkBox_EnableFloorNumber->isChecked(); + projectConfig.useCustomBorderSize = ui->checkBox_EnableCustomBorderSize->isChecked(); + projectConfig.tilesetsHaveCallback = ui->checkBox_OutputCallback->isChecked(); + projectConfig.tilesetsHaveIsCompressed = ui->checkBox_OutputIsCompressed->isChecked(); + porymapConfig.warpBehaviorWarningDisabled = ui->checkBox_DisableWarning->isChecked(); // Save spin box settings - projectConfig.setDefaultElevation(ui->spinBox_Elevation->value()); - projectConfig.setDefaultCollision(ui->spinBox_Collision->value()); - projectConfig.setDefaultMetatileId(ui->spinBox_FillMetatile->value()); - projectConfig.setCollisionSheetHeight(ui->spinBox_MaxElevation->value() + 1); - projectConfig.setCollisionSheetWidth(ui->spinBox_MaxCollision->value() + 1); - projectConfig.setMetatileBehaviorMask(ui->spinBox_BehaviorMask->value()); - projectConfig.setMetatileTerrainTypeMask(ui->spinBox_TerrainTypeMask->value()); - projectConfig.setMetatileEncounterTypeMask(ui->spinBox_EncounterTypeMask->value()); - projectConfig.setMetatileLayerTypeMask(ui->spinBox_LayerTypeMask->value()); - projectConfig.setBlockMetatileIdMask(ui->spinBox_MetatileIdMask->value()); - projectConfig.setBlockCollisionMask(ui->spinBox_CollisionMask->value()); - projectConfig.setBlockElevationMask(ui->spinBox_ElevationMask->value()); + projectConfig.defaultElevation = ui->spinBox_Elevation->value(); + projectConfig.defaultCollision = ui->spinBox_Collision->value(); + projectConfig.defaultMetatileId = ui->spinBox_FillMetatile->value(); + projectConfig.collisionSheetHeight = ui->spinBox_MaxElevation->value() + 1; + projectConfig.collisionSheetWidth = ui->spinBox_MaxCollision->value() + 1; + projectConfig.metatileBehaviorMask = ui->spinBox_BehaviorMask->value(); + projectConfig.metatileTerrainTypeMask = ui->spinBox_TerrainTypeMask->value(); + projectConfig.metatileEncounterTypeMask = ui->spinBox_EncounterTypeMask->value(); + projectConfig.metatileLayerTypeMask = ui->spinBox_LayerTypeMask->value(); + projectConfig.blockMetatileIdMask = ui->spinBox_MetatileIdMask->value(); + projectConfig.blockCollisionMask = ui->spinBox_CollisionMask->value(); + projectConfig.blockElevationMask = ui->spinBox_ElevationMask->value(); // Save line edit settings - projectConfig.setPrefabFilepath(ui->lineEdit_PrefabsPath->text()); - projectConfig.setCollisionSheetPath(ui->lineEdit_CollisionGraphics->text()); + projectConfig.prefabFilepath = ui->lineEdit_PrefabsPath->text(); + projectConfig.collisionSheetPath = ui->lineEdit_CollisionGraphics->text(); projectConfig.setEventIconPath(Event::Group::Object, ui->lineEdit_ObjectsIcon->text()); projectConfig.setEventIconPath(Event::Group::Warp, ui->lineEdit_WarpsIcon->text()); projectConfig.setEventIconPath(Event::Group::Coord, ui->lineEdit_TriggersIcon->text()); @@ -555,14 +550,13 @@ void ProjectSettingsEditor::save() { projectConfig.setIdentifier(lineEdit->objectName(), lineEdit->text()); // Save warp behaviors + projectConfig.warpBehaviors.clear(); QStringList behaviorNames = this->getWarpBehaviorsList(); - QSet behaviorValues; for (auto name : behaviorNames) - behaviorValues.insert(project->metatileBehaviorMap.value(name)); - projectConfig.setWarpBehaviors(behaviorValues); + projectConfig.warpBehaviors.insert(project->metatileBehaviorMap.value(name)); // Save border metatile IDs - projectConfig.setNewMapBorderMetatileIds(this->getBorderMetatileIds(ui->checkBox_EnableCustomBorderSize->isChecked())); + projectConfig.newMapBorderMetatileIds = this->getBorderMetatileIds(ui->checkBox_EnableCustomBorderSize->isChecked()); // Save pokemon icon paths const QString species = ui->comboBox_IconSpecies->currentText(); @@ -571,8 +565,10 @@ void ProjectSettingsEditor::save() { for (auto i = this->editedPokemonIconPaths.cbegin(), end = this->editedPokemonIconPaths.cend(); i != end; i++) projectConfig.setPokemonIconPath(i.key(), i.value()); - projectConfig.setSaveDisabled(false); projectConfig.save(); + userConfig.save(); + porymapConfig.save(); + this->hasUnsavedChanges = false; // Technically, a reload is not required for several of the config settings. @@ -611,7 +607,7 @@ void ProjectSettingsEditor::importDefaultPrefabsClicked(bool) { // If the prompt is accepted the prefabs file will be created and its filepath will be saved in the config. BaseGameVersion version = projectConfig.stringToBaseGameVersion(ui->comboBox_BaseGameVersion->currentText()); if (prefab.tryImportDefaultPrefabs(this, version, ui->lineEdit_PrefabsPath->text())) { - ui->lineEdit_PrefabsPath->setText(projectConfig.getPrefabFilepath()); // Refresh with new filepath + ui->lineEdit_PrefabsPath->setText(projectConfig.prefabFilepath); // Refresh with new filepath this->hasUnsavedChanges = true; } } diff --git a/src/ui/regionmapeditor.cpp b/src/ui/regionmapeditor.cpp index 13650c83..5cd0c9cb 100644 --- a/src/ui/regionmapeditor.cpp +++ b/src/ui/regionmapeditor.cpp @@ -202,7 +202,7 @@ void buildFireredDefaults(poryjson::Json &json) { poryjson::Json RegionMapEditor::buildDefaultJson() { poryjson::Json defaultJson; - switch (projectConfig.getBaseGameVersion()) { + switch (projectConfig.baseGameVersion) { case BaseGameVersion::pokeemerald: buildEmeraldDefaults(defaultJson); break; @@ -345,7 +345,7 @@ bool RegionMapEditor::buildConfigDialog() { // for sake of convenience, option to just use defaults for each basegame version QPushButton *config_useProjectDefault; - switch (projectConfig.getBaseGameVersion()) { + switch (projectConfig.baseGameVersion) { case BaseGameVersion::pokefirered: config_useProjectDefault = new QPushButton("\nUse pokefirered defaults\n"); break; diff --git a/src/ui/shortcutseditor.cpp b/src/ui/shortcutseditor.cpp index 83ac1147..30f9d62a 100644 --- a/src/ui/shortcutseditor.cpp +++ b/src/ui/shortcutseditor.cpp @@ -53,6 +53,7 @@ void ShortcutsEditor::saveShortcuts() { } shortcutsConfig.setUserShortcuts(objects_keySequences); + shortcutsConfig.save(); emit shortcutsSaved(); } diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp index bd233974..9ef50cc6 100644 --- a/src/ui/tileseteditor.cpp +++ b/src/ui/tileseteditor.cpp @@ -114,7 +114,7 @@ void TilesetEditor::initUi() { void TilesetEditor::setAttributesUi() { // Behavior - if (projectConfig.getMetatileBehaviorMask()) { + if (projectConfig.metatileBehaviorMask) { for (int num : project->metatileBehaviorMapInverse.keys()) { this->ui->comboBox_metatileBehaviors->addItem(project->metatileBehaviorMapInverse[num], num); } @@ -125,7 +125,7 @@ void TilesetEditor::setAttributesUi() { } // Terrain Type - if (projectConfig.getMetatileTerrainTypeMask()) { + if (projectConfig.metatileTerrainTypeMask) { this->ui->comboBox_terrainType->addItem("Normal", TERRAIN_NONE); this->ui->comboBox_terrainType->addItem("Grass", TERRAIN_GRASS); this->ui->comboBox_terrainType->addItem("Water", TERRAIN_WATER); @@ -138,7 +138,7 @@ void TilesetEditor::setAttributesUi() { } // Encounter Type - if (projectConfig.getMetatileEncounterTypeMask()) { + if (projectConfig.metatileEncounterTypeMask) { this->ui->comboBox_encounterType->addItem("None", ENCOUNTER_NONE); this->ui->comboBox_encounterType->addItem("Land", ENCOUNTER_LAND); this->ui->comboBox_encounterType->addItem("Water", ENCOUNTER_WATER); @@ -150,13 +150,13 @@ void TilesetEditor::setAttributesUi() { } // Layer Type - if (!projectConfig.getTripleLayerMetatilesEnabled()) { + if (!projectConfig.tripleLayerMetatilesEnabled) { this->ui->comboBox_layerType->addItem("Normal - Middle/Top", METATILE_LAYER_MIDDLE_TOP); this->ui->comboBox_layerType->addItem("Covered - Bottom/Middle", METATILE_LAYER_BOTTOM_MIDDLE); this->ui->comboBox_layerType->addItem("Split - Bottom/Top", METATILE_LAYER_BOTTOM_TOP); this->ui->comboBox_layerType->setEditable(false); this->ui->comboBox_layerType->setMinimumContentsLength(0); - if (!projectConfig.getMetatileLayerTypeMask()) { + if (!projectConfig.metatileLayerTypeMask) { // User doesn't have triple layer metatiles, but has no layer type attribute. // Porymap is still using the layer type value to render metatiles, and with // no mask set every metatile will be "Middle/Top", so just display the combo @@ -188,7 +188,7 @@ void TilesetEditor::initMetatileSelector() connect(this->metatileSelector, &TilesetEditorMetatileSelector::selectedMetatileChanged, this, &TilesetEditor::onSelectedMetatileChanged); - bool showGrid = porymapConfig.getShowTilesetEditorMetatileGrid(); + bool showGrid = porymapConfig.showTilesetEditorMetatileGrid; this->ui->actionMetatile_Grid->setChecked(showGrid); this->metatileSelector->showGrid = showGrid; @@ -198,7 +198,7 @@ void TilesetEditor::initMetatileSelector() this->ui->graphicsView_Metatiles->setScene(this->metatilesScene); this->ui->graphicsView_Metatiles->setResizeAnchor(QGraphicsView::AnchorViewCenter); - this->ui->horizontalSlider_MetatilesZoom->setValue(porymapConfig.getTilesetEditorMetatilesZoom()); + this->ui->horizontalSlider_MetatilesZoom->setValue(porymapConfig.tilesetEditorMetatilesZoom); } void TilesetEditor::initMetatileLayersItem() { @@ -213,7 +213,7 @@ void TilesetEditor::initMetatileLayersItem() { connect(this->metatileLayersItem, &MetatileLayersItem::hoveredTileCleared, this, &TilesetEditor::onHoveredTileCleared); - bool showGrid = porymapConfig.getShowTilesetEditorLayerGrid(); + bool showGrid = porymapConfig.showTilesetEditorLayerGrid; this->ui->actionLayer_Grid->setChecked(showGrid); this->metatileLayersItem->showGrid = showGrid; @@ -239,7 +239,7 @@ void TilesetEditor::initTileSelector() this->ui->graphicsView_Tiles->setScene(this->tilesScene); this->ui->graphicsView_Tiles->setResizeAnchor(QGraphicsView::AnchorViewCenter); - this->ui->horizontalSlider_TilesZoom->setValue(porymapConfig.getTilesetEditorTilesZoom()); + this->ui->horizontalSlider_TilesZoom->setValue(porymapConfig.tilesetEditorTilesZoom); } void TilesetEditor::initSelectedTileItem() { @@ -1070,13 +1070,13 @@ void TilesetEditor::on_actionShow_UnusedTiles_toggled(bool checked) { void TilesetEditor::on_actionMetatile_Grid_triggered(bool checked) { this->metatileSelector->showGrid = checked; this->metatileSelector->draw(); - porymapConfig.setShowTilesetEditorMetatileGrid(checked); + porymapConfig.showTilesetEditorMetatileGrid = checked; } void TilesetEditor::on_actionLayer_Grid_triggered(bool checked) { this->metatileLayersItem->showGrid = checked; this->metatileLayersItem->draw(); - porymapConfig.setShowTilesetEditorLayerGrid(checked); + porymapConfig.showTilesetEditorLayerGrid = checked; } void TilesetEditor::countMetatileUsage() { @@ -1188,7 +1188,7 @@ void TilesetEditor::on_copyButton_metatileLabel_clicked() { } void TilesetEditor::on_horizontalSlider_MetatilesZoom_valueChanged(int value) { - porymapConfig.setTilesetEditorMetatilesZoom(value); + porymapConfig.tilesetEditorMetatilesZoom = value; this->redrawMetatileSelector(); } @@ -1196,7 +1196,7 @@ void TilesetEditor::redrawMetatileSelector() { QSize size(this->metatileSelector->pixmap().width(), this->metatileSelector->pixmap().height()); this->ui->graphicsView_Metatiles->setSceneRect(0, 0, size.width(), size.height()); - double scale = pow(3.0, static_cast(porymapConfig.getTilesetEditorMetatilesZoom() - 30) / 30.0); + double scale = pow(3.0, static_cast(porymapConfig.tilesetEditorMetatilesZoom - 30) / 30.0); QTransform transform; transform.scale(scale, scale); size *= scale; @@ -1213,7 +1213,7 @@ void TilesetEditor::redrawMetatileSelector() { } void TilesetEditor::on_horizontalSlider_TilesZoom_valueChanged(int value) { - porymapConfig.setTilesetEditorTilesZoom(value); + porymapConfig.tilesetEditorTilesZoom = value; this->redrawTileSelector(); } @@ -1221,7 +1221,7 @@ void TilesetEditor::redrawTileSelector() { QSize size(this->tileSelector->pixmap().width(), this->tileSelector->pixmap().height()); this->ui->graphicsView_Tiles->setSceneRect(0, 0, size.width(), size.height()); - double scale = pow(3.0, static_cast(porymapConfig.getTilesetEditorTilesZoom() - 30) / 30.0); + double scale = pow(3.0, static_cast(porymapConfig.tilesetEditorTilesZoom - 30) / 30.0); QTransform transform; transform.scale(scale, scale); size *= scale; diff --git a/src/ui/updatepromoter.cpp b/src/ui/updatepromoter.cpp index 8ca2b6cd..7b9d39d6 100644 --- a/src/ui/updatepromoter.cpp +++ b/src/ui/updatepromoter.cpp @@ -20,8 +20,7 @@ UpdatePromoter::UpdatePromoter(QWidget *parent, NetworkAccessManager *manager) this->updatePreferences(); ui->checkBox_StopAlerts->setVisible(false); connect(ui->checkBox_StopAlerts, &QCheckBox::stateChanged, [this](int state) { - bool enable = (state != Qt::Checked); - porymapConfig.setCheckForUpdates(enable); + porymapConfig.checkForUpdates = (state != Qt::Checked); emit this->changedPreferences(); }); @@ -141,11 +140,11 @@ void UpdatePromoter::processWebpage(const QJsonDocument &data, const QUrl &nextU // Alert the user about the new version if the dialog wasn't already open. // Show the window, but also show the option to turn off automatic alerts in the future. // We only show this alert once for a given release. - if (!this->isVisible() && this->newVersion > porymapConfig.getLastUpdateCheckVersion()) { + if (!this->isVisible() && this->newVersion > porymapConfig.lastUpdateCheckVersion) { ui->checkBox_StopAlerts->setVisible(true); this->show(); } - porymapConfig.setLastUpdateCheckVersion(this->newVersion); + porymapConfig.lastUpdateCheckVersion = this->newVersion; } else { ui->label_Status->setText("Your version of Porymap is up to date!"); ui->label_Warning->setVisible(false); @@ -173,7 +172,7 @@ void UpdatePromoter::error(const QString &err, const QDateTime retryAfter) { void UpdatePromoter::updatePreferences() { const QSignalBlocker blocker(ui->checkBox_StopAlerts); - ui->checkBox_StopAlerts->setChecked(!porymapConfig.getCheckForUpdates()); + ui->checkBox_StopAlerts->setChecked(!porymapConfig.checkForUpdates); } void UpdatePromoter::dialogButtonClicked(QAbstractButton *button) { From 29ed696d9ed2bad01b68d07d2957fb44ed9fa463 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Mon, 15 Jul 2024 21:10:54 -0400 Subject: [PATCH 3/7] Auto-detect more version names --- include/config.h | 3 ++- src/config.cpp | 50 ++++++++++++++++++++++++-------------- src/ui/prefab.cpp | 3 +++ src/ui/regionmapeditor.cpp | 8 +++--- 4 files changed, 41 insertions(+), 23 deletions(-) diff --git a/include/config.h b/include/config.h index 89a27d24..7e87e986 100644 --- a/include/config.h +++ b/include/config.h @@ -158,6 +158,7 @@ private: extern PorymapConfig porymapConfig; enum BaseGameVersion { + none, pokeruby, pokefirered, pokeemerald, @@ -303,7 +304,7 @@ public: static const QMap> defaultIdentifiers; static const QMap> defaultPaths; static const QStringList versionStrings; - static BaseGameVersion stringToBaseGameVersion(QString string, bool * ok = nullptr); + static BaseGameVersion stringToBaseGameVersion(const QString &string); void reset(BaseGameVersion baseGameVersion); void setFilePath(ProjectFilePath pathId, const QString &path); diff --git a/src/config.cpp b/src/config.cpp index 1ee00c18..98681264 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -608,20 +608,32 @@ const QMap baseGameVersionMap = { {BaseGameVersion::pokeemerald, ProjectConfig::versionStrings[2]}, }; -const QMap baseGameVersionReverseMap = { - {ProjectConfig::versionStrings[0], BaseGameVersion::pokeruby}, - {ProjectConfig::versionStrings[1], BaseGameVersion::pokefirered}, - {ProjectConfig::versionStrings[2], BaseGameVersion::pokeemerald}, +const QMap versionDetectNames = { + {BaseGameVersion::pokeruby, {"ruby", "sapphire"}}, + {BaseGameVersion::pokefirered, {"firered", "leafgreen"}}, + {BaseGameVersion::pokeemerald, {"emerald"}}, }; -BaseGameVersion ProjectConfig::stringToBaseGameVersion(QString string, bool * ok) { - if (baseGameVersionReverseMap.contains(string)) { - if (ok) *ok = true; - return baseGameVersionReverseMap.value(string); - } else { - if (ok) *ok = false; - return BaseGameVersion::pokeemerald; +// If a string exclusively contains one version name we assume its identity, +// otherwise we leave it unknown and we'll need the user to tell us the version. +BaseGameVersion ProjectConfig::stringToBaseGameVersion(const QString &string) { + BaseGameVersion version = BaseGameVersion::none; + for (auto i = versionDetectNames.cbegin(), end = versionDetectNames.cend(); i != end; i++) { + // Compare the given string to all the possible names for this game version + const QStringList names = i.value(); + for (auto name : names) { + if (string.contains(name)) { + if (version != BaseGameVersion::none) { + // The given string matches multiple versions, so we can't be sure which it is. + return BaseGameVersion::none; + } + version = i.key(); + break; + } + } } + // We finished checking the names for each version; the name either matched 1 version or none. + return version; } ProjectConfig projectConfig; @@ -633,10 +645,11 @@ QString ProjectConfig::getConfigFilepath() { void ProjectConfig::parseConfigKeyValue(QString key, QString value) { if (key == "base_game_version") { - bool ok; - this->baseGameVersion = this->stringToBaseGameVersion(value.toLower(), &ok); - if (!ok) + this->baseGameVersion = this->stringToBaseGameVersion(value.toLower()); + if (this->baseGameVersion == BaseGameVersion::none) { logWarn(QString("Invalid config value for base_game_version: '%1'. Must be 'pokeruby', 'pokefirered' or 'pokeemerald'.").arg(value)); + this->baseGameVersion = BaseGameVersion::pokeemerald; + } } else if (key == "use_poryscript") { this->usePoryScript = getConfigBool(key, value); } else if (key == "use_custom_border_size") { @@ -851,10 +864,11 @@ QMap ProjectConfig::getKeyValueMap() { void ProjectConfig::init() { QString dirName = QDir(this->projectDir).dirName().toLower(); - if (baseGameVersionReverseMap.contains(dirName)) { - // TODO: Improve detection (ex: emerald or pokeemerald-2 aren't currently auto-detected) - this->baseGameVersion = baseGameVersionReverseMap.value(dirName); - logInfo(QString("Auto-detected base_game_version as '%1'").arg(dirName)); + + BaseGameVersion version = stringToBaseGameVersion(dirName); + if (version != BaseGameVersion::none) { + this->baseGameVersion = version; + logInfo(QString("Auto-detected base_game_version as '%1'").arg(getBaseGameVersionString(version))); } else { QDialog dialog(nullptr, Qt::WindowTitleHint); dialog.setWindowTitle("Project Configuration"); diff --git a/src/ui/prefab.cpp b/src/ui/prefab.cpp index 3559b9a8..594e811a 100644 --- a/src/ui/prefab.cpp +++ b/src/ui/prefab.cpp @@ -338,6 +338,9 @@ bool Prefab::tryImportDefaultPrefabs(QWidget * parent, BaseGameVersion version, case BaseGameVersion::pokeemerald: content = parser.readTextFile(":/text/prefabs_default_emerald.json"); break; + default: + content = QString(); + break; } prefabsFile.write(content.toUtf8()); diff --git a/src/ui/regionmapeditor.cpp b/src/ui/regionmapeditor.cpp index 5cd0c9cb..0a5451a7 100644 --- a/src/ui/regionmapeditor.cpp +++ b/src/ui/regionmapeditor.cpp @@ -206,14 +206,14 @@ poryjson::Json RegionMapEditor::buildDefaultJson() { case BaseGameVersion::pokeemerald: buildEmeraldDefaults(defaultJson); break; - case BaseGameVersion::pokeruby: buildRubyDefaults(defaultJson); break; - case BaseGameVersion::pokefirered: buildFireredDefaults(defaultJson); break; + default: + break; } return defaultJson; @@ -315,7 +315,7 @@ bool RegionMapEditor::buildConfigDialog() { QPushButton *delMapButton = new QPushButton("Delete Selected Region Map"); form.addRow(delMapButton); - connect(delMapButton, &QPushButton::clicked, [this, regionMapList, &updateJsonFromList] { + connect(delMapButton, &QPushButton::clicked, [regionMapList, &updateJsonFromList] { QListWidgetItem *item = regionMapList->currentItem(); if (item) { regionMapList->removeItemWidget(item); @@ -344,7 +344,7 @@ bool RegionMapEditor::buildConfigDialog() { // for sake of convenience, option to just use defaults for each basegame version - QPushButton *config_useProjectDefault; + QPushButton *config_useProjectDefault = nullptr; switch (projectConfig.baseGameVersion) { case BaseGameVersion::pokefirered: config_useProjectDefault = new QPushButton("\nUse pokefirered defaults\n"); From 9efe67a72f8952ba4fd6dd8dcff50f06565d2c9f Mon Sep 17 00:00:00 2001 From: GriffinR Date: Tue, 16 Jul 2024 14:19:47 -0400 Subject: [PATCH 4/7] Add sanity check to project opening --- include/mainwindow.h | 7 +- include/project.h | 3 + src/config.cpp | 2 + src/mainwindow.cpp | 165 +++++++++++++++++++++---------------------- src/project.cpp | 54 ++++++++++++++ 5 files changed, 143 insertions(+), 88 deletions(-) diff --git a/include/mainwindow.h b/include/mainwindow.h index bb4d4b91..e65605e0 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -344,9 +344,9 @@ private: bool setMap(QString, bool scrollTreeView = false); void redrawMapScene(); void refreshMapScene(); - bool loadDataStructures(); - bool loadProjectCombos(); - bool populateMapList(); + bool checkProjectSanity(); + bool loadProjectData(); + bool setProjectUI(); void sortMapList(); void openSubWindow(QWidget * window); QString getExistingDirectory(QString); @@ -376,7 +376,6 @@ private: void initMapSortOrder(); void initShortcuts(); void initExtraShortcuts(); - void setProjectSpecificUI(); void loadUserSettings(); void applyMapListFilter(QString filterText); void restoreWindowState(); diff --git a/include/project.h b/include/project.h index 90172f39..c9a1a0c0 100644 --- a/include/project.h +++ b/include/project.h @@ -97,6 +97,9 @@ public: DataQualifiers healLocationDataQualifiers; QString healLocationsTableName; + bool sanityCheck(); + bool load(); + QMap mapCache; Map* loadMap(QString); Map* getMap(QString); diff --git a/src/config.cpp b/src/config.cpp index 98681264..c294a0ee 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -890,6 +890,8 @@ void ProjectConfig::init() { if (dialog.exec() == QDialog::Accepted) { this->baseGameVersion = static_cast(baseGameVersionComboBox->currentData().toInt()); + } else { + // TODO: If user closes window Porymap assumes pokeemerald; it should instead abort project opening } } this->setUnreadKeys(); // Initialize version-specific options diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 3b48da1e..88c12103 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -413,35 +413,6 @@ void MainWindow::markMapEdited() { } } -// Update the UI using information we've read from the user's project files. -void MainWindow::setProjectSpecificUI() -{ - // Wild Encounters tab - // TODO: This index should come from an enum - ui->mainTabBar->setTabEnabled(4, editor->project->wildEncountersLoaded); - - bool hasFlags = projectConfig.mapAllowFlagsEnabled; - ui->checkBox_AllowRunning->setVisible(hasFlags); - ui->checkBox_AllowBiking->setVisible(hasFlags); - ui->checkBox_AllowEscaping->setVisible(hasFlags); - ui->label_AllowRunning->setVisible(hasFlags); - ui->label_AllowBiking->setVisible(hasFlags); - ui->label_AllowEscaping->setVisible(hasFlags); - - ui->newEventToolButton->newWeatherTriggerAction->setVisible(projectConfig.eventWeatherTriggerEnabled); - ui->newEventToolButton->newSecretBaseAction->setVisible(projectConfig.eventSecretBaseEnabled); - ui->newEventToolButton->newCloneObjectAction->setVisible(projectConfig.eventCloneObjectEnabled); - - bool floorNumEnabled = projectConfig.floorNumberEnabled; - ui->spinBox_FloorNumber->setVisible(floorNumEnabled); - ui->label_FloorNumber->setVisible(floorNumEnabled); - - Event::setIcons(); - editor->setCollisionGraphics(); - ui->spinBox_SelectedElevation->setMaximum(Block::getMaxElevation()); - ui->spinBox_SelectedCollision->setMaximum(Block::getMaxCollision()); -} - void MainWindow::mapSortOrder_changed(QAction *action) { QList items = ui->toolButton_MapSortOrder->menu()->actions(); @@ -528,13 +499,13 @@ void MainWindow::setTheme(QString theme) { } bool MainWindow::openProject(const QString &dir, bool initial) { - if (!this->closeProject()) { - logInfo("Aborted project open."); - return false; - } - if (dir.isNull() || dir.length() <= 0) { - if (!initial) setWindowDisabled(true); + // If this happened on startup it's because the user has no recent projects, which is fine. + // This shouldn't happen otherwise, but if it does then display an error. + if (!initial) { + logError("Failed to open project: Directory name cannot be empty"); + showProjectOpenFailure(); + } return false; } @@ -553,6 +524,13 @@ bool MainWindow::openProject(const QString &dir, bool initial) { return false; } + // The above checks can fail and the user will be allowed to continue with their currently-opened project (if there is one). + // We close the current project below, after which either the new project will open successfully or the window will be disabled. + if (!this->closeProject()) { + logInfo("Aborted project open."); + return false; + } + const QString openMessage = QString("Opening %1").arg(projectString); this->statusBar()->showMessage(openMessage); logInfo(openMessage); @@ -577,8 +555,14 @@ bool MainWindow::openProject(const QString &dir, bool initial) { }); this->editor->project->set_root(dir); + // Make sure project looks reasonable before attempting to load it + if (!checkProjectSanity()) { + delete this->editor->project; + return false; + } + // Load the project - if (!(loadDataStructures() && populateMapList() && setInitialMap())) { + if (!(loadProjectData() && setProjectUI() && setInitialMap())) { this->statusBar()->showMessage(QString("Failed to open %1").arg(projectString)); showProjectOpenFailure(); delete this->editor->project; @@ -606,12 +590,39 @@ bool MainWindow::openProject(const QString &dir, bool initial) { return true; } +bool MainWindow::loadProjectData() { + bool success = editor->project->load(); + Scripting::populateGlobalObject(this); + return success; +} + +bool MainWindow::checkProjectSanity() { + if (editor->project->sanityCheck()) + return true; + + QMessageBox msgBox; + msgBox.setIcon(QMessageBox::Critical); + msgBox.setText(QString("The selected directory appears to be invalid.")); + msgBox.setInformativeText(QString("The directory '%1' is missing key files.\n\n" + "Make sure you selected the correct project directory " + "(the one used to make your .gba file, e.g. 'pokeemerald').").arg(editor->project->root)); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setDefaultButton(QMessageBox::Ok); + auto tryAnyway = msgBox.addButton("Try Anyway", QMessageBox::ActionRole); + msgBox.exec(); + if (msgBox.clickedButton() == tryAnyway) { + // The user has chosen to try to load this project anyway. + // This will almost certainly fail, but they'll get a more specific error message. + return true; + } + return false; +} + void MainWindow::showProjectOpenFailure() { QString errorMsg = QString("There was an error opening the project. Please see %1 for full error details.").arg(getLogPath()); QMessageBox error(QMessageBox::Critical, "porymap", errorMsg, QMessageBox::Ok, this); error.setDetailedText(getMostRecentError()); error.exec(); - setWindowDisabled(true); } bool MainWindow::isProjectOpen() { @@ -975,45 +986,8 @@ void MainWindow::on_spinBox_FloorNumber_valueChanged(int offset) } } -bool MainWindow::loadDataStructures() { - Project *project = editor->project; - bool success = project->readMapLayouts() - && project->readRegionMapSections() - && project->readItemNames() - && project->readFlagNames() - && project->readVarNames() - && project->readMovementTypes() - && project->readInitialFacingDirections() - && project->readMapTypes() - && project->readMapBattleScenes() - && project->readWeatherNames() - && project->readCoordEventWeatherNames() - && project->readSecretBaseIds() - && project->readBgEventFacingDirections() - && project->readTrainerTypes() - && project->readMetatileBehaviors() - && project->readFieldmapProperties() - && project->readFieldmapMasks() - && project->readTilesetLabels() - && project->readTilesetMetatileLabels() - && project->readHealLocations() - && project->readMiscellaneousConstants() - && project->readSpeciesIconPaths() - && project->readWildMonData() - && project->readEventScriptLabels() - && project->readObjEventGfxConstants() - && project->readEventGraphics() - && project->readSongNames(); - - project->applyParsedLimits(); - setProjectSpecificUI(); - Scripting::populateGlobalObject(this); - - return success && loadProjectCombos(); -} - -bool MainWindow::loadProjectCombos() { - // set up project ui comboboxes +// Update the UI using information we've read from the user's project files. +bool MainWindow::setProjectUI() { Project *project = editor->project; // Block signals to the comboboxes while they are being modified @@ -1025,6 +999,7 @@ bool MainWindow::loadProjectCombos() { const QSignalBlocker blocker6(ui->comboBox_BattleScene); const QSignalBlocker blocker7(ui->comboBox_Type); + // Set up project comboboxes ui->comboBox_Song->clear(); ui->comboBox_Song->addItems(project->songNames); ui->comboBox_Location->clear(); @@ -1040,15 +1015,36 @@ bool MainWindow::loadProjectCombos() { ui->comboBox_Type->clear(); ui->comboBox_Type->addItems(project->mapTypes); - return true; -} + sortMapList(); -bool MainWindow::populateMapList() { - bool success = editor->project->readMapGroups(); - if (success) { - sortMapList(); - } - return success; + // Show/hide parts of the UI that are dependent on the user's project settings + + // Wild Encounters tab + // TODO: This index should come from an enum + ui->mainTabBar->setTabEnabled(4, editor->project->wildEncountersLoaded); + + bool hasFlags = projectConfig.mapAllowFlagsEnabled; + ui->checkBox_AllowRunning->setVisible(hasFlags); + ui->checkBox_AllowBiking->setVisible(hasFlags); + ui->checkBox_AllowEscaping->setVisible(hasFlags); + ui->label_AllowRunning->setVisible(hasFlags); + ui->label_AllowBiking->setVisible(hasFlags); + ui->label_AllowEscaping->setVisible(hasFlags); + + ui->newEventToolButton->newWeatherTriggerAction->setVisible(projectConfig.eventWeatherTriggerEnabled); + ui->newEventToolButton->newSecretBaseAction->setVisible(projectConfig.eventSecretBaseEnabled); + ui->newEventToolButton->newCloneObjectAction->setVisible(projectConfig.eventCloneObjectEnabled); + + bool floorNumEnabled = projectConfig.floorNumberEnabled; + ui->spinBox_FloorNumber->setVisible(floorNumEnabled); + ui->label_FloorNumber->setVisible(floorNumEnabled); + + Event::setIcons(); + editor->setCollisionGraphics(); + ui->spinBox_SelectedElevation->setMaximum(Block::getMaxElevation()); + ui->spinBox_SelectedCollision->setMaximum(Block::getMaxCollision()); + + return true; } void MainWindow::sortMapList() { @@ -3019,6 +3015,7 @@ bool MainWindow::closeProject() { } } editor->closeProject(); + setWindowDisabled(true); return true; } diff --git a/src/project.cpp b/src/project.cpp index d50c305e..7048812a 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -91,6 +91,60 @@ void Project::set_root(QString dir) { this->parser.set_root(dir); } +// Before attempting the initial project load we should check for a few notable files. +// If all are missing then we can warn the user, they may have accidentally selected the wrong folder. +bool Project::sanityCheck() { + // The goal with the file selection is to pick files that are important enough that any reasonable project would have + // at least 1 in the expected location, but unique enough that they're unlikely to overlap with a completely unrelated + // directory (e.g. checking for 'data/maps/' is a bad choice because it's too generic, pokeyellow would pass for instance) + static const QSet pathsToCheck = { + ProjectFilePath::json_map_groups, + ProjectFilePath::json_layouts, + ProjectFilePath::tilesets_headers, + ProjectFilePath::global_fieldmap, + }; + for (auto pathId : pathsToCheck) { + const QString path = QString("%1/%2").arg(this->root).arg(projectConfig.getFilePath(pathId)); + QFileInfo fileInfo(path); + if (fileInfo.exists() && fileInfo.isFile()) + return true; + } + return false; +} + +bool Project::load() { + bool success = readMapLayouts() + && readRegionMapSections() + && readItemNames() + && readFlagNames() + && readVarNames() + && readMovementTypes() + && readInitialFacingDirections() + && readMapTypes() + && readMapBattleScenes() + && readWeatherNames() + && readCoordEventWeatherNames() + && readSecretBaseIds() + && readBgEventFacingDirections() + && readTrainerTypes() + && readMetatileBehaviors() + && readFieldmapProperties() + && readFieldmapMasks() + && readTilesetLabels() + && readTilesetMetatileLabels() + && readHealLocations() + && readMiscellaneousConstants() + && readSpeciesIconPaths() + && readWildMonData() + && readEventScriptLabels() + && readObjEventGfxConstants() + && readEventGraphics() + && readSongNames() + && readMapGroups(); + applyParsedLimits(); + return success; +} + QString Project::getProjectTitle() { if (!root.isNull()) { return root.section('/', -1); From 4c25813bd33069c39f3222b9cfaf9d2b7834cb09 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Tue, 16 Jul 2024 16:26:59 -0400 Subject: [PATCH 5/7] Add project close option --- forms/mainwindow.ui | 9 +++ include/config.h | 2 + include/editor.h | 33 ++++++---- include/mainwindow.h | 4 +- include/scripting.h | 1 + src/config.cpp | 11 ++-- src/editor.cpp | 116 +++++++++++++++++++++++++++++------- src/mainwindow.cpp | 70 +++++++++++++++++++--- src/scriptapi/scripting.cpp | 19 +++--- 9 files changed, 214 insertions(+), 51 deletions(-) diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index a28f1db9..8e586198 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -3061,6 +3061,7 @@ + @@ -3415,6 +3416,14 @@ QAction::ApplicationSpecificRole + + + Close Project + + + Ctrl+W + + diff --git a/include/config.h b/include/config.h index 7e87e986..3f77aa90 100644 --- a/include/config.h +++ b/include/config.h @@ -54,6 +54,7 @@ public: } virtual void reset() override { this->recentProjects.clear(); + this->projectManuallyClosed = false; this->reopenOnLaunch = true; this->mapSortOrder = MapSortOrder::Group; this->prettyCursors = true; @@ -99,6 +100,7 @@ public: QMap getCustomScriptsEditorGeometry(); bool reopenOnLaunch; + bool projectManuallyClosed; MapSortOrder mapSortOrder; bool prettyCursors; int collisionOpacity; diff --git a/include/editor.h b/include/editor.h index 837b267c..8e30ae70 100644 --- a/include/editor.h +++ b/include/editor.h @@ -107,13 +107,13 @@ public: void updateWarpEventWarnings(); bool eventLimitReached(Map *, Event::Type); - QGraphicsScene *scene = nullptr; + QPointer scene = nullptr; QGraphicsPixmapItem *current_view = nullptr; - MapPixmapItem *map_item = nullptr; + QPointer map_item = nullptr; ConnectionPixmapItem* selected_connection_item = nullptr; QList connection_items; QGraphicsPathItem *connection_mask = nullptr; - CollisionPixmapItem *collision_item = nullptr; + QPointer collision_item = nullptr; QGraphicsItemGroup *events_group = nullptr; QList borderItems; QList gridLines; @@ -121,16 +121,15 @@ public: CursorTileRect *cursorMapTileRect = nullptr; MapRuler *map_ruler = nullptr; - QGraphicsScene *scene_metatiles = nullptr; - QGraphicsScene *scene_current_metatile_selection = nullptr; - QGraphicsScene *scene_selected_border_metatiles = nullptr; - QGraphicsScene *scene_collision_metatiles = nullptr; - QGraphicsScene *scene_elevation_metatiles = nullptr; - MetatileSelector *metatile_selector_item = nullptr; + QPointer scene_metatiles = nullptr; + QPointer scene_current_metatile_selection = nullptr; + QPointer scene_selected_border_metatiles = nullptr; + QPointer scene_collision_metatiles = nullptr; + QPointer metatile_selector_item = nullptr; - BorderMetatilesPixmapItem *selected_border_metatiles_item = nullptr; + QPointer selected_border_metatiles_item = nullptr; CurrentSelectedMetatilesPixmapItem *current_metatile_selection_item = nullptr; - MovementPermissionsSelector *movement_permissions_selector_item = nullptr; + QPointer movement_permissions_selector_item = nullptr; QList *selected_events = nullptr; @@ -168,6 +167,18 @@ private: const QImage collisionPlaceholder = QImage(":/images/collisions_unknown.png"); QPixmap collisionSheetPixmap; + void clearMap(); + void clearMetatileSelector(); + void clearMovementPermissionSelector(); + void clearMapMetatiles(); + void clearMapMovementPermissions(); + void clearBorderMetatiles(); + void clearCurrentMetatilesSelection(); + void clearMapEvents(); + //void clearMapConnections(); + void clearMapBorder(); + void clearMapGrid(); + void clearWildMonTables(); void setConnectionItemsVisible(bool); void setBorderItemsVisible(bool, qreal = 1); void setConnectionEditControlValues(MapConnection*); diff --git a/include/mainwindow.h b/include/mainwindow.h index e65605e0..41bf8a1e 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -167,6 +167,7 @@ public slots: private slots: void on_action_Open_Project_triggered(); void on_action_Reload_Project_triggered(); + void on_action_Close_Project_triggered(); void on_mapList_activated(const QModelIndex &index); void on_action_Save_Project_triggered(); void openWarpMap(QString map_name, int event_id, Event::Group event_group); @@ -347,10 +348,11 @@ private: bool checkProjectSanity(); bool loadProjectData(); bool setProjectUI(); + void clearProjectUI(); void sortMapList(); void openSubWindow(QWidget * window); QString getExistingDirectory(QString); - bool openProject(const QString &dir, bool initial = false); + bool openProject(QString dir, bool initial = false); bool closeProject(); void showProjectOpenFailure(); void saveGlobalConfigs(); diff --git a/include/scripting.h b/include/scripting.h index fb96e7ae..e2bfb1ff 100644 --- a/include/scripting.h +++ b/include/scripting.h @@ -30,6 +30,7 @@ class Scripting { public: Scripting(MainWindow *mainWindow); + static void stop(); static void init(MainWindow *mainWindow); static void populateGlobalObject(MainWindow *mainWindow); static QJSEngine *getEngine(); diff --git a/src/config.cpp b/src/config.cpp index c294a0ee..16853e8f 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -198,9 +198,9 @@ KeyValueConfigBase::~KeyValueConfigBase() { void KeyValueConfigBase::load() { reset(); QFile file(this->getConfigFilepath()); - if (!file.exists()) + if (!file.exists()) { this->init(); - else if (!file.open(QIODevice::ReadOnly)) { + } else if (!file.open(QIODevice::ReadOnly)) { logError(QString("Could not open config file '%1': ").arg(this->getConfigFilepath()) + file.errorString()); } @@ -306,6 +306,8 @@ void PorymapConfig::parseConfigKeyValue(QString key, QString value) { if (key == "recent_project") { this->recentProjects = value.split(",", Qt::SkipEmptyParts); this->recentProjects.removeDuplicates(); + } else if (key == "project_manually_closed") { + this->projectManuallyClosed = getConfigBool(key, value); } else if (key == "reopen_on_launch") { this->reopenOnLaunch = getConfigBool(key, value); } else if (key == "pretty_cursors") { @@ -417,6 +419,7 @@ void PorymapConfig::parseConfigKeyValue(QString key, QString value) { QMap PorymapConfig::getKeyValueMap() { QMap map; map.insert("recent_project", this->recentProjects.join(",")); + map.insert("project_manually_closed", this->projectManuallyClosed ? "1" : "0"); map.insert("reopen_on_launch", this->reopenOnLaunch ? "1" : "0"); map.insert("pretty_cursors", this->prettyCursors ? "1" : "0"); map.insert("map_sort_order", mapSortOrderMap.value(this->mapSortOrder)); @@ -882,7 +885,7 @@ void ProjectConfig::init() { baseGameVersionComboBox->addItem("pokeemerald", BaseGameVersion::pokeemerald); form.addRow(new QLabel("Game Version"), baseGameVersionComboBox); - // TODO: Advanced button to open the project settings window (with some settings disabled) + // TODO: Add an 'Advanced' button to open the project settings window (with some settings disabled) QDialogButtonBox buttonBox(QDialogButtonBox::Ok, Qt::Horizontal, &dialog); QObject::connect(&buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); @@ -891,7 +894,7 @@ void ProjectConfig::init() { if (dialog.exec() == QDialog::Accepted) { this->baseGameVersion = static_cast(baseGameVersionComboBox->currentData().toInt()); } else { - // TODO: If user closes window Porymap assumes pokeemerald; it should instead abort project opening + logWarn(QString("No base_game_version selected, using default '%1'").arg(getBaseGameVersionString(this->baseGameVersion))); } } this->setUnreadKeys(); // Initialize version-specific options diff --git a/src/editor.cpp b/src/editor.cpp index 9557ee13..d3116af4 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -81,8 +81,9 @@ void Editor::saveUiFields() { void Editor::closeProject() { if (!this->project) return; - Scripting::cb_ProjectClosed(this->project->root); + Scripting::stop(); + clearMap(); delete this->project; } @@ -204,9 +205,8 @@ void Editor::setEditingConnections() { this->cursorMapTileRect->setActive(false); } -void Editor::displayWildMonTables() { +void Editor::clearWildMonTables() { QStackedWidget *stack = ui->stackedWidget_WildMons; - QComboBox *labelCombo = ui->comboBox_EncounterGroupLabel; // delete widgets from previous map data if they exist while (stack->count()) { @@ -215,18 +215,24 @@ void Editor::displayWildMonTables() { delete oldWidget; } - labelCombo->clear(); + ui->comboBox_EncounterGroupLabel->clear(); +} + +void Editor::displayWildMonTables() { + clearWildMonTables(); // Don't try to read encounter data if it doesn't exist on disk for this map. if (!project->wildMonData.contains(map->constantName)) { return; } + QComboBox *labelCombo = ui->comboBox_EncounterGroupLabel; for (auto groupPair : project->wildMonData[map->constantName]) labelCombo->addItem(groupPair.first); labelCombo->setCurrentText(labelCombo->itemText(0)); + QStackedWidget *stack = ui->stackedWidget_WildMons; int labelIndex = 0; for (auto labelPair : project->wildMonData[map->constantName]) { @@ -1337,6 +1343,35 @@ void Editor::mouseEvent_collision(QGraphicsSceneMouseEvent *event, CollisionPixm } } +// On project close we want to leave the editor view empty. +// Otherwise a map is normally only cleared when a new one is being displayed. +void Editor::clearMap() { + clearMetatileSelector(); + clearMovementPermissionSelector(); + clearMapMetatiles(); + clearMapMovementPermissions(); + clearBorderMetatiles(); + clearCurrentMetatilesSelection(); + clearMapEvents(); + //clearMapConnections(); + clearMapBorder(); + clearMapGrid(); + clearWildMonTables(); + + // TODO: Handle connections after redesign PR. + selected_connection_item = nullptr; + connection_items.clear(); + connection_mask = nullptr; + + current_view = nullptr; + map = nullptr; + + // These are normally preserved between map displays, we only delete them now. + delete scene; + delete metatile_selector_item; + delete movement_permissions_selector_item; +} + bool Editor::displayMap() { if (!scene) { scene = new QGraphicsScene; @@ -1346,12 +1381,6 @@ bool Editor::displayMap() { scene->installEventFilter(this->map_ruler); } - if (map_item && scene) { - scene->removeItem(map_item); - delete map_item; - scene->removeItem(this->map_ruler); - } - displayMetatileSelector(); displayMovementPermissionSelector(); displayMapMetatiles(); @@ -1379,11 +1408,16 @@ bool Editor::displayMap() { return true; } -void Editor::displayMetatileSelector() { +void Editor::clearMetatileSelector() { if (metatile_selector_item && metatile_selector_item->scene()) { metatile_selector_item->scene()->removeItem(metatile_selector_item); delete scene_metatiles; } +} + +void Editor::displayMetatileSelector() { + clearMetatileSelector(); + scene_metatiles = new QGraphicsScene; if (!metatile_selector_item) { metatile_selector_item = new MetatileSelector(8, map); @@ -1408,7 +1442,17 @@ void Editor::displayMetatileSelector() { scene_metatiles->addItem(metatile_selector_item); } +void Editor::clearMapMetatiles() { + if (map_item && scene) { + scene->removeItem(map_item); + delete map_item; + scene->removeItem(this->map_ruler); + } +} + void Editor::displayMapMetatiles() { + clearMapMetatiles(); + map_item = new MapPixmapItem(map, this->metatile_selector_item, this->settings); connect(map_item, &MapPixmapItem::mouseEvent, this, &Editor::mouseEvent_map); connect(map_item, &MapPixmapItem::startPaint, this, &Editor::onMapStartPaint); @@ -1429,11 +1473,16 @@ void Editor::displayMapMetatiles() { ); } -void Editor::displayMapMovementPermissions() { +void Editor::clearMapMovementPermissions() { if (collision_item && scene) { scene->removeItem(collision_item); delete collision_item; } +} + +void Editor::displayMapMovementPermissions() { + clearMapMovementPermissions(); + collision_item = new CollisionPixmapItem(map, ui->spinBox_SelectedCollision, ui->spinBox_SelectedElevation, this->metatile_selector_item, this->settings, &this->collisionOpacity); connect(collision_item, &CollisionPixmapItem::mouseEvent, this, &Editor::mouseEvent_collision); @@ -1446,11 +1495,16 @@ void Editor::displayMapMovementPermissions() { scene->addItem(collision_item); } -void Editor::displayBorderMetatiles() { +void Editor::clearBorderMetatiles() { if (selected_border_metatiles_item && selected_border_metatiles_item->scene()) { selected_border_metatiles_item->scene()->removeItem(selected_border_metatiles_item); delete selected_border_metatiles_item; + delete scene_selected_border_metatiles; } +} + +void Editor::displayBorderMetatiles() { + clearBorderMetatiles(); scene_selected_border_metatiles = new QGraphicsScene; selected_border_metatiles_item = new BorderMetatilesPixmapItem(map, this->metatile_selector_item); @@ -1465,11 +1519,17 @@ void Editor::displayBorderMetatiles() { this, &Editor::onBorderMetatilesChanged); } -void Editor::displayCurrentMetatilesSelection() { +void Editor::clearCurrentMetatilesSelection() { if (current_metatile_selection_item && current_metatile_selection_item->scene()) { current_metatile_selection_item->scene()->removeItem(current_metatile_selection_item); delete current_metatile_selection_item; + current_metatile_selection_item = nullptr; + delete scene_current_metatile_selection; } +} + +void Editor::displayCurrentMetatilesSelection() { + clearCurrentMetatilesSelection(); scene_current_metatile_selection = new QGraphicsScene; current_metatile_selection_item = new CurrentSelectedMetatilesPixmapItem(map, this->metatile_selector_item); @@ -1485,11 +1545,15 @@ void Editor::redrawCurrentMetatilesSelection() { } } -void Editor::displayMovementPermissionSelector() { +void Editor::clearMovementPermissionSelector() { if (movement_permissions_selector_item && movement_permissions_selector_item->scene()) { movement_permissions_selector_item->scene()->removeItem(movement_permissions_selector_item); delete scene_collision_metatiles; } +} + +void Editor::displayMovementPermissionSelector() { + clearMovementPermissionSelector(); scene_collision_metatiles = new QGraphicsScene; if (!movement_permissions_selector_item) { @@ -1507,7 +1571,7 @@ void Editor::displayMovementPermissionSelector() { scene_collision_metatiles->addItem(movement_permissions_selector_item); } -void Editor::displayMapEvents() { +void Editor::clearMapEvents() { if (events_group) { for (QGraphicsItem *child : events_group->childItems()) { events_group->removeFromGroup(child); @@ -1519,9 +1583,13 @@ void Editor::displayMapEvents() { } delete events_group; + events_group = nullptr; } - selected_events->clear(); +} + +void Editor::displayMapEvents() { + clearMapEvents(); events_group = new QGraphicsItemGroup; scene->addItem(events_group); @@ -1626,7 +1694,7 @@ void Editor::maskNonVisibleConnectionTiles() { connection_mask = scene->addPath(mask, pen, brush); } -void Editor::displayMapBorder() { +void Editor::clearMapBorder() { for (QGraphicsPixmapItem* item : borderItems) { if (item->scene()) { item->scene()->removeItem(item); @@ -1634,6 +1702,10 @@ void Editor::displayMapBorder() { delete item; } borderItems.clear(); +} + +void Editor::displayMapBorder() { + clearMapBorder(); int borderWidth = map->getBorderWidth(); int borderHeight = map->getBorderHeight(); @@ -1646,7 +1718,7 @@ void Editor::displayMapBorder() { item->setX(x * 16); item->setY(y * 16); item->setZValue(-3); - scene->addItem(item); + scene->addItem(item); // TODO: If the scene is taking ownership here is a double-free possible? borderItems.append(item); } } @@ -1689,11 +1761,15 @@ void Editor::onToggleGridClicked(bool checked) { ui->graphicsView_Map->scene()->update(); } -void Editor::displayMapGrid() { +void Editor::clearMapGrid() { for (QGraphicsLineItem* item : gridLines) { if (item) delete item; } gridLines.clear(); +} + +void Editor::displayMapGrid() { + clearMapGrid(); ui->checkBox_ToggleGrid->disconnect(); int pixelWidth = map->getWidth() * 16; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 88c12103..3f90e133 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -70,7 +70,7 @@ MainWindow::MainWindow(QWidget *parent) : logInfo(QString("Launching Porymap v%1").arg(QCoreApplication::applicationVersion())); this->initWindow(); - if (porymapConfig.reopenOnLaunch && this->openProject(porymapConfig.getRecentProject(), true)) + if (porymapConfig.reopenOnLaunch && !porymapConfig.projectManuallyClosed && this->openProject(porymapConfig.getRecentProject(), true)) on_toolButton_Paint_clicked(); // there is a bug affecting macOS users, where the trackpad deilveres a bad touch-release gesture @@ -498,7 +498,7 @@ void MainWindow::setTheme(QString theme) { } } -bool MainWindow::openProject(const QString &dir, bool initial) { +bool MainWindow::openProject(QString dir, bool initial) { if (dir.isNull() || dir.length() <= 0) { // If this happened on startup it's because the user has no recent projects, which is fine. // This shouldn't happen otherwise, but if it does then display an error. @@ -526,7 +526,7 @@ bool MainWindow::openProject(const QString &dir, bool initial) { // The above checks can fail and the user will be allowed to continue with their currently-opened project (if there is one). // We close the current project below, after which either the new project will open successfully or the window will be disabled. - if (!this->closeProject()) { + if (!closeProject()) { logInfo("Aborted project open."); return false; } @@ -577,6 +577,7 @@ bool MainWindow::openProject(const QString &dir, bool initial) { showWindowTitle(); this->statusBar()->showMessage(QString("Opened %1").arg(projectString)); + porymapConfig.projectManuallyClosed = false; porymapConfig.addRecentProject(dir); refreshRecentProjectsMenu(); @@ -600,12 +601,14 @@ bool MainWindow::checkProjectSanity() { if (editor->project->sanityCheck()) return true; + logWarn(QString("The directory '%1' failed the project sanity check.").arg(editor->project->root)); + QMessageBox msgBox; msgBox.setIcon(QMessageBox::Critical); msgBox.setText(QString("The selected directory appears to be invalid.")); msgBox.setInformativeText(QString("The directory '%1' is missing key files.\n\n" "Make sure you selected the correct project directory " - "(the one used to make your .gba file, e.g. 'pokeemerald').").arg(editor->project->root)); + "(the one used to make your .gba file, e.g. 'pokeemerald').").arg(editor->project->root)); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setDefaultButton(QMessageBox::Ok); auto tryAnyway = msgBox.addButton("Try Anyway", QMessageBox::ActionRole); @@ -721,6 +724,11 @@ void MainWindow::on_action_Reload_Project_triggered() { openProject(editor->project->root); } +void MainWindow::on_action_Close_Project_triggered() { + closeProject(); + porymapConfig.projectManuallyClosed = true; +} + bool MainWindow::setMap(QString map_name, bool scrollTreeView) { logInfo(QString("Setting map to '%1'").arg(map_name)); if (map_name.isEmpty()) { @@ -1047,6 +1055,29 @@ bool MainWindow::setProjectUI() { return true; } +void MainWindow::clearProjectUI() { + // Block signals to the comboboxes while they are being modified + const QSignalBlocker blocker1(ui->comboBox_Song); + const QSignalBlocker blocker2(ui->comboBox_Location); + const QSignalBlocker blocker3(ui->comboBox_PrimaryTileset); + const QSignalBlocker blocker4(ui->comboBox_SecondaryTileset); + const QSignalBlocker blocker5(ui->comboBox_Weather); + const QSignalBlocker blocker6(ui->comboBox_BattleScene); + const QSignalBlocker blocker7(ui->comboBox_Type); + + ui->comboBox_Song->clear(); + ui->comboBox_Location->clear(); + ui->comboBox_PrimaryTileset->clear(); + ui->comboBox_SecondaryTileset->clear(); + ui->comboBox_Weather->clear(); + ui->comboBox_BattleScene->clear(); + ui->comboBox_Type->clear(); + + // Clear map list + mapListModel->clear(); + mapGroupItemsList->clear(); +} + void MainWindow::sortMapList() { Project *project = editor->project; @@ -2514,8 +2545,12 @@ void MainWindow::importMapFromAdvanceMap1_92() void MainWindow::showExportMapImageWindow(ImageExporterMode mode) { if (!editor->project) return; - if (!this->mapImageExporter) - this->mapImageExporter = new MapImageExporter(this, this->editor, mode); + // If the user is requesting this window again we assume it's for a new + // window (the map/mode may have changed), so delete the old window. + if (this->mapImageExporter) + delete this->mapImageExporter; + + this->mapImageExporter = new MapImageExporter(this, this->editor, mode); openSubWindow(this->mapImageExporter); } @@ -2972,24 +3007,41 @@ bool MainWindow::askToFixRegionMapEditor() { } // Attempt to close any open sub-windows of the main window, giving each a chance to abort the process. -// Each of these are expected to be a QPointer to a widget with WA_DeleteOnClose set, so manually deleting -// and nullifying the pointer members is not necessary here. +// Each of these windows is a widget with WA_DeleteOnClose set, so manually deleting them isn't necessary. +// Because they're tracked with QPointers nullifying them shouldn't be necessary either, but it seems the +// delete is happening too late and some of the pointers haven't been cleared by the time we need them to, +// so we nullify them all here anyway. bool MainWindow::closeSupplementaryWindows() { if (this->tilesetEditor && !this->tilesetEditor->close()) return false; + this->tilesetEditor = nullptr; + if (this->regionMapEditor && !this->regionMapEditor->close()) return false; + this->regionMapEditor = nullptr; + if (this->mapImageExporter && !this->mapImageExporter->close()) return false; + this->mapImageExporter = nullptr; + if (this->newMapPrompt && !this->newMapPrompt->close()) return false; + this->newMapPrompt = nullptr; + if (this->shortcutsEditor && !this->shortcutsEditor->close()) return false; + this->shortcutsEditor = nullptr; + if (this->preferenceEditor && !this->preferenceEditor->close()) return false; + this->preferenceEditor = nullptr; + if (this->customScriptsEditor && !this->customScriptsEditor->close()) return false; + this->customScriptsEditor = nullptr; + if (this->projectSettingsEditor) this->projectSettingsEditor->closeQuietly(); + this->projectSettingsEditor = nullptr; return true; } @@ -3014,8 +3066,10 @@ bool MainWindow::closeProject() { return false; } } + clearProjectUI(); editor->closeProject(); setWindowDisabled(true); + setWindowTitle(QCoreApplication::applicationName()); return true; } diff --git a/src/scriptapi/scripting.cpp b/src/scriptapi/scripting.cpp index 112585c7..82944be9 100644 --- a/src/scriptapi/scripting.cpp +++ b/src/scriptapi/scripting.cpp @@ -21,14 +21,19 @@ QMap callbackFunctions = { Scripting *instance = nullptr; +void Scripting::stop() { + if (!instance) return; + instance->engine->setInterrupted(true); + instance->scriptUtility->clearActions(); + qDeleteAll(instance->imageCache); + delete instance; + instance = nullptr; +} + void Scripting::init(MainWindow *mainWindow) { - mainWindow->ui->graphicsView_Map->clearOverlayMap(); - if (instance) { - instance->engine->setInterrupted(true); - instance->scriptUtility->clearActions(); - qDeleteAll(instance->imageCache); - delete instance; - } + if (mainWindow->ui->graphicsView_Map) + mainWindow->ui->graphicsView_Map->clearOverlayMap(); + Scripting::stop(); instance = new Scripting(mainWindow); } From 0012ea83e6c94cb68e330e24b196f968eefe6cfa Mon Sep 17 00:00:00 2001 From: GriffinR Date: Wed, 17 Jul 2024 12:31:07 -0400 Subject: [PATCH 6/7] Update changelog --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c9977a1..67e9a0b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,21 @@ and this project somewhat adheres to [Semantic Versioning](https://semver.org/sp The **"Breaking Changes"** listed below are changes that have been made in the decompilation projects (e.g. pokeemerald), which porymap requires in order to work properly. It also includes changes to the scripting API that may change the behavior of existing porymap scripts. If porymap is used with a project or API script that is not up-to-date with the breaking changes, then porymap will likely break or behave improperly. ## [Unreleased] +### Added +- Add a `Close Project` option +- An alert will be displayed when attempting to open a seemingly invalid project. + +### Changed +- The base game version is now auto-detected if the project name contains only one of "emerald", "firered/leafgreen", or "ruby/sapphire". +- It's now possible to cancel quitting if there are unsaved changes in sub-windows. + ### Fixed - Fix `Add Region Map...` not updating the region map settings file. - Fix some crashes on invalid region map tilesets. - Improve error reporting for invalid region map editor settings. +- Fix config files being written before the project is opened successfully. +- Fix the map and other project info still displaying if a new project fails to open. +- Fix unsaved changes being ignored when quitting (such as with Cmd+Q on macOS). ## [5.4.1] - 2024-03-21 ### Fixed From 80497805a157973184af3347e752b4f7c7b231ea Mon Sep 17 00:00:00 2001 From: GriffinR Date: Wed, 24 Jul 2024 12:00:34 -0400 Subject: [PATCH 7/7] Save project config on close --- src/editor.cpp | 1 + src/mainwindow.cpp | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/editor.cpp b/src/editor.cpp index d3116af4..54194a96 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -81,6 +81,7 @@ void Editor::saveUiFields() { void Editor::closeProject() { if (!this->project) return; + this->project->saveConfig(); Scripting::cb_ProjectClosed(this->project->root); Scripting::stop(); clearMap(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 3f90e133..721a3fa3 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -571,8 +571,7 @@ bool MainWindow::openProject(QString dir, bool initial) { } // Only create the config files once the project has opened successfully in case the user selected an invalid directory - userConfig.save(); - projectConfig.save(); + this->editor->project->saveConfig(); showWindowTitle(); this->statusBar()->showMessage(QString("Opened %1").arg(projectString));