From 7a4de9f3d922c298350c4a130e2682238d334e76 Mon Sep 17 00:00:00 2001 From: BigBahss Date: Fri, 4 Dec 2020 09:29:38 -0500 Subject: [PATCH] Add support for finding and opening any event script --- CHANGELOG.md | 2 +- docsrc/manual/editing-map-events.rst | 2 +- docsrc/manual/settings-and-options.rst | 2 +- forms/preferenceeditor.ui | 4 +-- include/editor.h | 5 ++-- include/mainwindow.h | 1 + include/project.h | 1 + src/core/parseutil.cpp | 2 +- src/editor.cpp | 36 ++++++++++++++++++++------ src/mainwindow.cpp | 24 ++++++++++++++--- src/project.cpp | 27 +++++++++++++++++++ 11 files changed, 86 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9b49704..aa367a92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ The **"Breaking Changes"** listed below are changes that have been made in the d - The window sizes and positions of the tileset editor, palette editor, and region map editor are now stored in `porymap.cfg`. - Add ruler tool for measuring metatile distance in events tab (Right-click to turn on/off, left-click to lock in place). - Add delete button to wild pokemon encounters tab. -- Add custom text editor commands in `Options -> Edit Preferences`, a tool-button next to the `Script` combo-box, and `Tools -> Open Project in Text Editor`. The tool-button will open the map's scripts file to the cooresponding script. +- Add custom text editor commands in `Options -> Edit Preferences`, a tool-button next to the `Script` combo-box, and `Tools -> Open Project in Text Editor`. The tool-button will open the containing file to the cooresponding script. ### Changed - Holding `shift` now toggles "Smart Path" drawing; when the "Smart Paths" checkbox is checked, holding `shift` will temporarily disable it. diff --git a/docsrc/manual/editing-map-events.rst b/docsrc/manual/editing-map-events.rst index cc2f017a..ca0b4e41 100644 --- a/docsrc/manual/editing-map-events.rst +++ b/docsrc/manual/editing-map-events.rst @@ -227,7 +227,7 @@ Open Map Scripts Clicking the ``Open Map Scripts`` button |open-map-scripts-button| will open the map's scripts file in your default text editor. If nothing happens when this button is clicked, you may need to associate a text editor with the `.inc` file extension (or `.pory` if you're using Porycript). -Additionally, if you specify a ``Goto Line Command`` in *Options -> Edit Preferences* then a tool-button will appear next to the `Script` combo-box for selected events. Clicking this button will open the map's scripts file directly to the cooresponding script (if the script can be found in that file). +Additionally, if you specify a ``Goto Line Command`` in *Options -> Edit Preferences* then a tool-button will appear next to the `Script` combo-box in the *Events* tab. Clicking this button will open the file that contains the script directly to the line number of that script. If the script cannot be found in the project then the current map's scripts file is opened. |go-to-script-button| .. |open-map-scripts-button| diff --git a/docsrc/manual/settings-and-options.rst b/docsrc/manual/settings-and-options.rst index 2e0ce77f..5a4968e3 100644 --- a/docsrc/manual/settings-and-options.rst +++ b/docsrc/manual/settings-and-options.rst @@ -31,7 +31,7 @@ determined by this file. ``monitor_files``, 1, global, yes, Whether porymap will monitor changes to project files ``region_map_dimensions``, 32x20, global, yes, The dimensions of the region map tilemap ``theme``, default, global, yes, The color theme for porymap windows and widgets - ``text_editor_goto_line``, , global, yes, The command that will be executed when clicking the tool-button next the ``Script`` combo-box. + ``text_editor_goto_line``, , global, yes, The command that will be executed when clicking the button next the ``Script`` combo-box. ``text_editor_open_directory``, , global, yes, The command that will be executed when clicking ``Open Project in Text Editor``. ``base_game_version``, , project, no, The base pret repo for this project ``use_encounter_json``, 1, project, yes, Enables wild encounter table editing diff --git a/forms/preferenceeditor.ui b/forms/preferenceeditor.ui index b082ec1d..2d9f25b0 100644 --- a/forms/preferenceeditor.ui +++ b/forms/preferenceeditor.ui @@ -76,7 +76,7 @@ - <html><head/><body><p>This is the command that will be executed when clicking the <span style=" font-weight:600;">Open Map Scripts</span> button<span style=" font-weight:600;">. %F</span> will be substituted with the scripts file path and <span style=" font-weight:600;">%L</span> will be substituted with the line number of the script for the currently selected event. <span style=" font-weight:600;">%F </span><span style=" font-style:italic;">must</span> be specified if <span style=" font-weight:600;">%L</span> is specified. If <span style=" font-weight:600;">%F</span> is <span style=" font-style:italic;">not</span> specified then the scripts file path will be appended to the end of the command.</p></body></html> + <html><head/><body><p><span style=" font-size:11pt;">When this command is set a button will appear next to the </span><span style=" font-size:11pt; font-weight:600; font-style:italic;">Script</span><span style=" font-size:11pt;"> combo-box in the </span><span style=" font-size:11pt; font-weight:600; font-style:italic;">Events</span><span style=" font-size:11pt;"> tab which executes this command.</span><span style=" font-size:11pt; font-weight:600;"> %F</span><span style=" font-size:11pt;"> will be substituted with the file path of the script and </span><span style=" font-size:11pt; font-weight:600;">%L</span><span style=" font-size:11pt;"> will be substituted with the line number of the script in that file. </span><span style=" font-size:11pt; font-weight:600;">%F </span><span style=" font-size:11pt; font-style:italic;">must</span><span style=" font-size:11pt;"> be given if </span><span style=" font-size:11pt; font-weight:600;">%L</span><span style=" font-size:11pt;"> is given. If </span><span style=" font-size:11pt; font-weight:600;">%F</span><span style=" font-size:11pt;"> is </span><span style=" font-size:11pt; font-style:italic;">not</span><span style=" font-size:11pt;"> given then the script's file path will be added to the end of the command. If the script can't be found then the current map's scripts file is opened.</span></p></body></html> Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop @@ -109,7 +109,7 @@ - <html><head/><body><p>This is the command that will be executed when clicking <span style=" font-weight:600;">Open Project in Text Editor</span> in the <span style=" font-weight:600;">Tools</span> menu. <span style=" font-weight:600;">%D</span> will be substituted with the current project's root directory. If <span style=" font-weight:600;">%D</span> is <span style=" font-style:italic;">not</span> specified then the project directory will be appended to the end of the command.</p></body></html> + <html><head/><body><p><span style=" font-size:11pt;">This is the command that is executed when clicking </span><span style=" font-size:11pt; font-weight:600; font-style:italic;">Open Project in Text Editor</span><span style=" font-size:11pt;"> in the </span><span style=" font-size:11pt; font-weight:600; font-style:italic;">Tools</span><span style=" font-size:11pt;"> menu. </span><span style=" font-size:11pt; font-weight:600;">%D</span><span style=" font-size:11pt;"> will be substituted with the project's root directory. If </span><span style=" font-size:11pt; font-weight:600;">%D</span><span style=" font-size:11pt;"> is </span><span style=" font-size:11pt; font-style:italic;">not</span><span style=" font-size:11pt;"> specified then the project directory will be added to the end of the command.</span></p></body></html> Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop diff --git a/include/editor.h b/include/editor.h index 21b413b1..90361ca3 100644 --- a/include/editor.h +++ b/include/editor.h @@ -155,8 +155,8 @@ public: void scaleMapView(int); public slots: - void openMapScripts(const QString &scriptLabel) const; - void openMapScripts() const { openMapScripts(QString()); } + void openMapScripts() const; + void openScript(const QString &scriptLabel) const; void openProjectInTextEditor() const; void maskNonVisibleConnectionTiles(); @@ -187,6 +187,7 @@ private: QString getMovementPermissionText(uint16_t collision, uint16_t elevation); QString getMetatileDisplayMessage(uint16_t metatileId); bool eventLimitReached(Map *, QString); + void openInTextEditor(const QString &path, int lineNum = 0) const; bool startDetachedProcess(const QString &command, const QString &workingDirectory = QString(), qint64 *pid = nullptr) const; diff --git a/include/mainwindow.h b/include/mainwindow.h index 2e81721d..653bd2bc 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -263,6 +263,7 @@ private: DraggablePixmapItem *selectedHealspot; QList registeredActions; + QVector openScriptButtons; bool isProgrammaticEventTabChange; bool projectHasUnsavedChanges; diff --git a/include/project.h b/include/project.h index 2dcaa345..afc82030 100644 --- a/include/project.h +++ b/include/project.h @@ -175,6 +175,7 @@ public: QString getScriptFileExtension(bool usePoryScript) const; QString getScriptDefaultString(bool usePoryScript, QString mapName) const; QString getMapScriptsFilePath(const QString &mapName) const; + QStringList getEventScriptsFilePaths() const; bool loadMapBorder(Map *map); diff --git a/src/core/parseutil.cpp b/src/core/parseutil.cpp index 9b3ac1ff..3b72a9b6 100644 --- a/src/core/parseutil.cpp +++ b/src/core/parseutil.cpp @@ -425,7 +425,7 @@ int ParseUtil::getScriptLineNumber(const QString &filePath, const QString &scrip if (scriptLabel.isEmpty()) return 0; - if (filePath.endsWith(".inc")) + if (filePath.endsWith(".inc") || filePath.endsWith(".s")) return getRawScriptLineNumber(readTextFile(filePath), scriptLabel); else if (filePath.endsWith(".pory")) return getPoryScriptLineNumber(readTextFile(filePath), scriptLabel); diff --git a/src/editor.cpp b/src/editor.cpp index ed0fd424..7a460222 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -2026,21 +2026,40 @@ void Editor::deleteEvent(Event *event) { //updateSelectedObjects(); } -void Editor::openMapScripts(const QString &scriptLabel) const { - const QString scriptsPath = project->getMapScriptsFilePath(map->name); +void Editor::openMapScripts() const { + const QString scriptPath = project->getMapScriptsFilePath(map->name); + openInTextEditor(scriptPath); +} + +void Editor::openScript(const QString &scriptLabel) const { + // Find the location of scriptLabel. + QStringList scriptPaths(project->getMapScriptsFilePath(map->name)); + scriptPaths << project->getEventScriptsFilePaths(); + int lineNum = 0; + QString scriptPath = scriptPaths.first(); + for (const auto &path : scriptPaths) { + lineNum = ParseUtil::getScriptLineNumber(path, scriptLabel); + if (lineNum != 0) { + scriptPath = path; + break; + } + } + + openInTextEditor(scriptPath, lineNum); +} + +void Editor::openInTextEditor(const QString &path, int lineNum) const { QString command = porymapConfig.getTextEditorGotoLine(); if (command.isEmpty()) { // Open map scripts in the system's default editor. - QDesktopServices::openUrl(QUrl::fromLocalFile(scriptsPath)); + QDesktopServices::openUrl(QUrl::fromLocalFile(path)); } else { if (command.contains("%F")) { - if (command.contains("%L")) { - const int lineNum = ParseUtil::getScriptLineNumber(scriptsPath, scriptLabel); + if (command.contains("%L")) command.replace("%L", QString::number(lineNum)); - } - command.replace("%F", scriptsPath); + command.replace("%F", path); } else { - command += ' ' + scriptsPath; + command += ' ' + path; } startDetachedProcess(command); } @@ -2056,6 +2075,7 @@ void Editor::openProjectInTextEditor() const { } bool Editor::startDetachedProcess(const QString &command, const QString &workingDirectory, qint64 *pid) const { + logInfo("Executing command: " + command); #ifdef Q_OS_WIN // On Windows, a QProcess command must be wrapped in a cmd.exe command. const QString program = QProcessEnvironment::systemEnvironment().value("COMSPEC"); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ebb232e6..5573a223 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1544,6 +1544,10 @@ void MainWindow::updateSelectedObjects() { } } + for (auto *button : openScriptButtons) + delete button; + openScriptButtons.clear(); + QMap event_obj_gfx_constants = editor->project->getEventObjGfxConstants(); QList frames; @@ -1866,22 +1870,26 @@ void MainWindow::updateSelectedObjects() { } else { combo->setCurrentText(value); - if (key == "script_label" && !porymapConfig.getTextEditorGotoLine().isEmpty()) { - // Add tool button next to combo to open scripts file to combo's current script label. + if (key == "script_label") { + // Add button next to combo which opens combo's current script. auto *hl = new QHBoxLayout(); hl->setSpacing(3); auto *openScriptButton = new QToolButton(widget); + openScriptButtons << openScriptButton; openScriptButton->setFixedSize(combo->height(), combo->height()); openScriptButton->setIcon(QFileIconProvider().icon(QFileIconProvider::File)); - openScriptButton->setToolTip("Go to this script definition in the map's scripts file."); + openScriptButton->setToolTip("Go to this script definition in text editor."); connect(openScriptButton, &QToolButton::clicked, - [this, combo]() { this->editor->openMapScripts(combo->currentText()); }); + [this, combo]() { this->editor->openScript(combo->currentText()); }); hl->addWidget(combo); hl->addWidget(openScriptButton); fl->addRow(new QLabel(field_labels[key], widget), hl); + if (porymapConfig.getTextEditorGotoLine().isEmpty()) + openScriptButton->hide(); } else { fl->addRow(new QLabel(field_labels[key], widget), combo); } + widget->setLayout(fl); frame->layout()->addWidget(widget); @@ -2587,6 +2595,14 @@ void MainWindow::on_actionEdit_Preferences_triggered() { } void MainWindow::togglePreferenceSpecificUi() { + if (porymapConfig.getTextEditorGotoLine().isEmpty()) { + for (auto *button : openScriptButtons) + button->hide(); + } else { + for (auto *button : openScriptButtons) + button->show(); + } + if (porymapConfig.getTextEditorOpenFolder().isEmpty()) ui->actionOpen_Project_in_Text_Editor->setEnabled(false); else diff --git a/src/project.cpp b/src/project.cpp index 6cbd7c92..2b2388cd 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -2435,6 +2435,33 @@ QString Project::getMapScriptsFilePath(const QString &mapName) const { return path; } +QStringList Project::getEventScriptsFilePaths() const { + QStringList filePaths(QDir::cleanPath(root + "/data/event_scripts.s")); + const QString scriptsDir = QDir::cleanPath(root + "/data/scripts"); + const QString mapsDir = QDir::cleanPath(root + "/data/maps"); + const bool usePoryscript = projectConfig.getUsePoryScript(); + + if (usePoryscript) { + QDirIterator it_pory_shared(scriptsDir, {"*.pory"}, QDir::Files); + while (it_pory_shared.hasNext()) + filePaths << it_pory_shared.next(); + + QDirIterator it_pory_maps(mapsDir, {"scripts.pory"}, QDir::Files, QDirIterator::Subdirectories); + while (it_pory_maps.hasNext()) + filePaths << it_pory_maps.next(); + } + + QDirIterator it_inc_shared(scriptsDir, {"*.inc"}, QDir::Files); + while (it_inc_shared.hasNext()) + filePaths << it_inc_shared.next(); + + QDirIterator it_inc_maps(mapsDir, {"scripts.inc"}, QDir::Files, QDirIterator::Subdirectories); + while (it_inc_maps.hasNext()) + filePaths << it_inc_maps.next(); + + return filePaths; +} + void Project::loadEventPixmaps(QList objects) { bool needs_update = false; for (Event *object : objects) {