Add support for finding and opening any event script

This commit is contained in:
BigBahss 2020-12-04 09:29:38 -05:00
parent afc0c0c501
commit 7a4de9f3d9
11 changed files with 86 additions and 20 deletions

View file

@ -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.

View file

@ -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|

View file

@ -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

View file

@ -76,7 +76,7 @@
<item row="6" column="0" colspan="2">
<widget class="QLabel" name="label_TextEditorGotoLineHelp">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This is the command that will be executed when clicking the &lt;span style=&quot; font-weight:600;&quot;&gt;Open Map Scripts&lt;/span&gt; button&lt;span style=&quot; font-weight:600;&quot;&gt;. %F&lt;/span&gt; will be substituted with the scripts file path and &lt;span style=&quot; font-weight:600;&quot;&gt;%L&lt;/span&gt; will be substituted with the line number of the script for the currently selected event. &lt;span style=&quot; font-weight:600;&quot;&gt;%F &lt;/span&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;must&lt;/span&gt; be specified if &lt;span style=&quot; font-weight:600;&quot;&gt;%L&lt;/span&gt; is specified. If &lt;span style=&quot; font-weight:600;&quot;&gt;%F&lt;/span&gt; is &lt;span style=&quot; font-style:italic;&quot;&gt;not&lt;/span&gt; specified then the scripts file path will be appended to the end of the command.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt;When this command is set a button will appear next to the &lt;/span&gt;&lt;span style=&quot; font-size:11pt; font-weight:600; font-style:italic;&quot;&gt;Script&lt;/span&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt; combo-box in the &lt;/span&gt;&lt;span style=&quot; font-size:11pt; font-weight:600; font-style:italic;&quot;&gt;Events&lt;/span&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt; tab which executes this command.&lt;/span&gt;&lt;span style=&quot; font-size:11pt; font-weight:600;&quot;&gt; %F&lt;/span&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt; will be substituted with the file path of the script and &lt;/span&gt;&lt;span style=&quot; font-size:11pt; font-weight:600;&quot;&gt;%L&lt;/span&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt; will be substituted with the line number of the script in that file. &lt;/span&gt;&lt;span style=&quot; font-size:11pt; font-weight:600;&quot;&gt;%F &lt;/span&gt;&lt;span style=&quot; font-size:11pt; font-style:italic;&quot;&gt;must&lt;/span&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt; be given if &lt;/span&gt;&lt;span style=&quot; font-size:11pt; font-weight:600;&quot;&gt;%L&lt;/span&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt; is given. If &lt;/span&gt;&lt;span style=&quot; font-size:11pt; font-weight:600;&quot;&gt;%F&lt;/span&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt; is &lt;/span&gt;&lt;span style=&quot; font-size:11pt; font-style:italic;&quot;&gt;not&lt;/span&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt; 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.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
@ -109,7 +109,7 @@
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_TextEditorOpenFolderHelp">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This is the command that will be executed when clicking &lt;span style=&quot; font-weight:600;&quot;&gt;Open Project in Text Editor&lt;/span&gt; in the &lt;span style=&quot; font-weight:600;&quot;&gt;Tools&lt;/span&gt; menu. &lt;span style=&quot; font-weight:600;&quot;&gt;%D&lt;/span&gt; will be substituted with the current project's root directory. If &lt;span style=&quot; font-weight:600;&quot;&gt;%D&lt;/span&gt; is &lt;span style=&quot; font-style:italic;&quot;&gt;not&lt;/span&gt; specified then the project directory will be appended to the end of the command.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt;This is the command that is executed when clicking &lt;/span&gt;&lt;span style=&quot; font-size:11pt; font-weight:600; font-style:italic;&quot;&gt;Open Project in Text Editor&lt;/span&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt; in the &lt;/span&gt;&lt;span style=&quot; font-size:11pt; font-weight:600; font-style:italic;&quot;&gt;Tools&lt;/span&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt; menu. &lt;/span&gt;&lt;span style=&quot; font-size:11pt; font-weight:600;&quot;&gt;%D&lt;/span&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt; will be substituted with the project's root directory. If &lt;/span&gt;&lt;span style=&quot; font-size:11pt; font-weight:600;&quot;&gt;%D&lt;/span&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt; is &lt;/span&gt;&lt;span style=&quot; font-size:11pt; font-style:italic;&quot;&gt;not&lt;/span&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt; specified then the project directory will be added to the end of the command.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>

View file

@ -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;

View file

@ -263,6 +263,7 @@ private:
DraggablePixmapItem *selectedHealspot;
QList<QAction *> registeredActions;
QVector<QToolButton *> openScriptButtons;
bool isProgrammaticEventTabChange;
bool projectHasUnsavedChanges;

View file

@ -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);

View file

@ -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);

View file

@ -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");

View file

@ -1544,6 +1544,10 @@ void MainWindow::updateSelectedObjects() {
}
}
for (auto *button : openScriptButtons)
delete button;
openScriptButtons.clear();
QMap<QString, int> event_obj_gfx_constants = editor->project->getEventObjGfxConstants();
QList<EventPropertiesFrame *> 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

View file

@ -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<Event*> objects) {
bool needs_update = false;
for (Event *object : objects) {