Merge pull request #552 from GriffinRichards/update-scripts-editor
Update custom scripts editor
BIN
docsrc/manual/images/scripting-capabilities/button-create.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
docsrc/manual/images/scripting-capabilities/button-load.png
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
docsrc/manual/images/scripting-capabilities/button-refresh.png
Normal file
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 81 KiB |
BIN
docsrc/manual/images/scripting-capabilities/delete.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
docsrc/manual/images/scripting-capabilities/file_edit.png
Executable file
After Width: | Height: | Size: 1.3 KiB |
BIN
docsrc/manual/images/scripting-capabilities/folder.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
docsrc/manual/images/scripting-capabilities/new-script.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
docsrc/manual/images/scripting-capabilities/refresh-prompt.png
Normal file
After Width: | Height: | Size: 34 KiB |
|
@ -11,32 +11,71 @@ Porymap is extensible via scripting capabilities. This allows the user to write
|
|||
- Procedurally Generated Maps
|
||||
- Randomize Grass Patterns
|
||||
|
||||
|
||||
Custom Scripts Editor
|
||||
---------------------
|
||||
|
||||
Your custom scripts can be managed with the Custom Scripts Editor accessible under ``Options -> Custom Scripts...``.
|
||||
|
||||
.. figure:: images/scripting-capabilities/custom-scripts-editor.png
|
||||
:alt: Custom Scripts Editor
|
||||
:width: 60%
|
||||
:align: center
|
||||
|
||||
Custom Scripts Editor
|
||||
|
||||
At the top there are three basic buttons for managing your scripts:
|
||||
- |button-create| Opens a prompt to create a new script file, which will be populated with a basic template.
|
||||
- |button-load| Lets you add an existing script file to Porymap that you've already created or downloaded from elsewhere.
|
||||
- |button-refresh| Any edits made to your scripts while Porymap is already open will not be reflected until you select this button.
|
||||
|
||||
Below these buttons is a list of all the custom scripts you have loaded for your project. Each entry will have a text box showing the path of the script file. This path can be freely updated, or you can choose a new path with the |button-folder| button next to it. The |button-edit| button will open the script file in your default text editor, and the |button-remove| button will remove it from the list. The check box to the left of the filepath indicates whether your script should be running. If you'd like to temporarily disable a script you can uncheck this box.
|
||||
|
||||
.. |button-create| image:: images/scripting-capabilities/button-create.png
|
||||
:height: 24
|
||||
.. |button-load| image:: images/scripting-capabilities/button-load.png
|
||||
:height: 24
|
||||
.. |button-refresh| image:: images/scripting-capabilities/button-refresh.png
|
||||
:height: 24
|
||||
.. |button-folder| image:: images/scripting-capabilities/folder.png
|
||||
:width: 24
|
||||
:height: 24
|
||||
.. |button-edit| image:: images/scripting-capabilities/file_edit.png
|
||||
:width: 24
|
||||
:height: 24
|
||||
.. |button-remove| image:: images/scripting-capabilities/delete.png
|
||||
:width: 24
|
||||
:height: 24
|
||||
|
||||
|
||||
Writing a Custom Script
|
||||
-----------------------
|
||||
|
||||
Let's write a custom script that will randomize grass patterns when the user is editing the map. This is useful, since it's cumbersome to manually add randomness to grass patches. With the custom script, it will happen automatically. Whenever the user paints a grass tile onto the map, the script will overwrite the tile with a random grass tile instead.
|
||||
|
||||
First, create a new script file called ``my_script.js``--place it in the project directory (e.g. ``pokefirered/``).
|
||||
First, open the ``Options -> Custom Scripts...`` window and select the |button-create| button. This will open a file save prompt; let's name our new script file ``my_script.js`` and save it. We've successfully added a new script! We can now see it listed in the editor.
|
||||
|
||||
Next, open the Porymap project config file, ``porymap.user.cfg``, in the project directory. Add the script file to the ``custom_scripts`` configuration value. Multiple script files can be loaded by separating the filepaths with a comma.
|
||||
.. figure:: images/scripting-capabilities/new-script.png
|
||||
:alt: Our New Script
|
||||
:width: 60%
|
||||
:align: center
|
||||
|
||||
.. code-block::
|
||||
|
||||
custom_scripts=my_script.js
|
||||
|
||||
Now that Porymap is configured to load the script file, let's write the actual code that will power the grass-randomizer. Scripts have access to several "callbacks" for events that occur while Porymap is running. This means our script can define functions for each of these callbacks. We're interested in the ``onBlockChanged()`` callback, since we want our script to take action whenever a user paints a block on the map.
|
||||
At the moment our script doesn't do anything. Let's select the |button-edit| button to open it and write the actual code that will power the grass-randomizer. Once the script file is open you will notice that there are several empty functions already inside. These are special "callback" functions that will be called automatically for certain events that occur while Porymap is running. We're interested in the ``onBlockChanged()`` callback, since we want our script to take action whenever a user paints a block on the map.
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
// Porymap callback when a block is painted.
|
||||
export function onBlockChanged(x, y, prevBlock, newBlock) {
|
||||
// Grass-randomizing logic goes here.
|
||||
}
|
||||
|
||||
// Porymap callback when a block is painted.
|
||||
export function onBlockChanged(x, y, prevBlock, newBlock) {
|
||||
// Grass-randomizing logic goes here.
|
||||
}
|
||||
|
||||
It's very **important** to remember to ``export`` the callback functions in the script. Otherwise, Porymap will not be able to execute them.
|
||||
We can leave the rest of the callback functions in here alone, or we can delete them because we're not using them. Every callback function does not need to be defined in your script. **Note**: For Porymap to be able to execute these callback functions they need to have the ``export`` keyword. The rest of the functions in your script do not need this keyword.
|
||||
|
||||
In addition to the callbacks, Porymap also supports a scripting API so that the script can interact with Porymap in interesting ways. For example, a script can change a block or add overlay text on the map. Since we want to paint random grass tiles, we'll be using the ``map.setMetatileId()`` function. Let's fill in the rest of the grass-randomizing code.
|
||||
|
||||
.. note::
|
||||
**For pokeemerald/pokeruby users**: We only have 1 regular grass metatile, but if you want to try this script you could replace ``const grassTiles = [0x8, 0x9, 0x10, 0x11];`` in the code below with ``const grassTiles = [0x1, 0x4, 0xD];`` to randomize using tall grass and flowers instead!
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
function randInt(min, max) {
|
||||
|
@ -58,7 +97,14 @@ In addition to the callbacks, Porymap also supports a scripting API so that the
|
|||
}
|
||||
}
|
||||
|
||||
Let's test the script out by re-launching Porymap. If we try to paint grass on the map, we should see our script inserting a nice randomized grass pattern.
|
||||
Let's apply our changes by selecting the |button-refresh| button. Because we've added a new script we'll be met with this confirmation prompt. Accept this prompt by selecting ``YES``.
|
||||
|
||||
.. figure:: images/scripting-capabilities/refresh-prompt.png
|
||||
:alt: Refresh Scripts Prompt
|
||||
:width: 60%
|
||||
:align: center
|
||||
|
||||
Now let's test our script! If we try to paint grass on the map, we should see our script inserting a nice randomized grass pattern.
|
||||
|
||||
.. figure:: images/scripting-capabilities/porymap-scripting-grass.gif
|
||||
:alt: Grass-Randomizing Script
|
||||
|
@ -81,7 +127,7 @@ The grass-randomizer script above happens implicitly when the user paints on the
|
|||
utility.registerAction("applyNightTint", "View Night Tint", "T")
|
||||
}
|
||||
|
||||
Then, to trigger the ``applyNightTint()`` function, we could either click ``Tools -> View Night Tint`` or use the ``T`` keyboard shortcut.
|
||||
Then, to trigger the ``applyNightTint()`` function, we could either click ``Tools -> View Night Tint`` or use the ``T`` keyboard shortcut. **Note**: Like callbacks, functions registered using ``utility.registerAction()`` also need the ``export`` keyword for Porymap to call them.
|
||||
|
||||
Now that we have an overview of how to utilize Porymap's scripting capabilities, the entire scripting API is documented below.
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>374</width>
|
||||
<width>535</width>
|
||||
<height>355</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -49,20 +49,40 @@
|
|||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="button_AddNewScript">
|
||||
<widget class="QPushButton" name="button_CreateNewScript">
|
||||
<property name="toolTip">
|
||||
<string>Create a new Porymap script file with a default template</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add New Script...</string>
|
||||
<string>Create New Script...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/add.ico</normaloff>:/icons/add.ico</iconset>
|
||||
<normaloff>:/icons/file_add.ico</normaloff>:/icons/file_add.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="button_ReloadScripts">
|
||||
<widget class="QPushButton" name="button_LoadScript">
|
||||
<property name="toolTip">
|
||||
<string>Add an existing script file to the list below</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reload Scripts</string>
|
||||
<string>Load Script...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/file_put.ico</normaloff>:/icons/file_put.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="button_RefreshScripts">
|
||||
<property name="toolTip">
|
||||
<string>Refresh all loaded scripts to account for any recent edits</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Refresh Scripts</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
|
@ -128,7 +148,7 @@
|
|||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::NoDragDrop</enum>
|
||||
<enum>QAbstractItemView::DragOnly</enum>
|
||||
</property>
|
||||
<property name="defaultDropAction">
|
||||
<enum>Qt::IgnoreAction</enum>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>129</width>
|
||||
<width>151</width>
|
||||
<height>34</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -24,16 +24,12 @@
|
|||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolButton" name="b_Choose">
|
||||
<widget class="QCheckBox" name="checkBox_Enable">
|
||||
<property name="toolTip">
|
||||
<string>Choose a new filepath for this script</string>
|
||||
<string>If unchecked this script will be ignored</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/folder.ico</normaloff>:/icons/folder.ico</iconset>
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -51,12 +47,16 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_Enable">
|
||||
<widget class="QToolButton" name="b_Choose">
|
||||
<property name="toolTip">
|
||||
<string>If unchecked this script will be ignored</string>
|
||||
<string>Choose a new filepath for this script</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/folder.ico</normaloff>:/icons/folder.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -70,7 +70,7 @@
|
|||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/edit_document.ico</normaloff>:/icons/edit_document.ico</iconset>
|
||||
<normaloff>:/icons/file_edit.ico</normaloff>:/icons/file_edit.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -31,10 +31,11 @@ private:
|
|||
Ui::CustomScriptsEditor *ui;
|
||||
|
||||
bool hasUnsavedChanges = false;
|
||||
QString importDir;
|
||||
QString fileDialogDir;
|
||||
const QString baseDir;
|
||||
|
||||
void displayScript(const QString &filepath, bool enabled);
|
||||
void displayNewScript(QString filepath);
|
||||
QString chooseScript(QString dir);
|
||||
void removeScript(QListWidgetItem * item);
|
||||
void replaceScript(QListWidgetItem * item);
|
||||
|
@ -52,8 +53,9 @@ private:
|
|||
|
||||
private slots:
|
||||
void dialogButtonClicked(QAbstractButton *button);
|
||||
void addNewScript();
|
||||
void reloadScripts();
|
||||
void createNewScript();
|
||||
void loadScript();
|
||||
void refreshScripts();
|
||||
void removeSelectedScripts();
|
||||
void openSelectedScripts();
|
||||
};
|
||||
|
|
Before Width: | Height: | Size: 1.6 KiB |
BIN
resources/icons/file_add.ico
Executable file
After Width: | Height: | Size: 1.2 KiB |
BIN
resources/icons/file_edit.ico
Executable file
After Width: | Height: | Size: 1.3 KiB |
BIN
resources/icons/file_put.ico
Executable file
After Width: | Height: | Size: 1 KiB |
|
@ -4,8 +4,10 @@
|
|||
<file>icons/collapse_all.ico</file>
|
||||
<file>icons/cursor.ico</file>
|
||||
<file>icons/delete.ico</file>
|
||||
<file>icons/edit_document.ico</file>
|
||||
<file>icons/expand_all.ico</file>
|
||||
<file>icons/file_add.ico</file>
|
||||
<file>icons/file_edit.ico</file>
|
||||
<file>icons/file_put.ico</file>
|
||||
<file>icons/fill_color_cursor.ico</file>
|
||||
<file>icons/fill_color.ico</file>
|
||||
<file>icons/folder_closed_map.ico</file>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
<file>text/prefabs_default_emerald.json</file>
|
||||
<file>text/prefabs_default_firered.json</file>
|
||||
<file>text/prefabs_default_ruby.json</file>
|
||||
<file>text/script_template.txt</file>
|
||||
<file>../CHANGELOG.md</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
71
resources/text/script_template.txt
Normal file
|
@ -0,0 +1,71 @@
|
|||
// Called when Porymap successfully opens a project.
|
||||
export function onProjectOpened(projectPath) {
|
||||
|
||||
}
|
||||
|
||||
// Called when Porymap closes a project. For example, this is called when opening a different project.
|
||||
export function onProjectClosed(projectPath) {
|
||||
|
||||
}
|
||||
|
||||
// Called when a map is opened.
|
||||
export function onMapOpened(mapName) {
|
||||
|
||||
}
|
||||
|
||||
// Called when a block is changed on the map. For example, this is called when a user paints a new tile or changes the collision property of a block.
|
||||
export function onBlockChanged(x, y, prevBlock, newBlock) {
|
||||
|
||||
}
|
||||
|
||||
// Called when a border metatile is changed.
|
||||
export function onBorderMetatileChanged(x, y, prevMetatileId, newMetatileId) {
|
||||
|
||||
}
|
||||
|
||||
// Called when the mouse enters a new map block.
|
||||
export function onBlockHoverChanged(x, y) {
|
||||
|
||||
}
|
||||
|
||||
// Called when the mouse exits the map.
|
||||
export function onBlockHoverCleared() {
|
||||
|
||||
}
|
||||
|
||||
// Called when the dimensions of the map are changed.
|
||||
export function onMapResized(oldWidth, oldHeight, newWidth, newHeight) {
|
||||
|
||||
}
|
||||
|
||||
// Called when the dimensions of the border are changed.
|
||||
export function onBorderResized(oldWidth, oldHeight, newWidth, newHeight) {
|
||||
|
||||
}
|
||||
|
||||
// Called when the map is updated by use of the Map Shift tool.
|
||||
export function onMapShifted(xDelta, yDelta) {
|
||||
|
||||
}
|
||||
|
||||
// Called when the currently loaded tileset is changed by switching to a new one or by saving changes to it in the Tileset Editor.
|
||||
export function onTilesetUpdated(tilesetName) {
|
||||
|
||||
}
|
||||
|
||||
// Called when the selected tab in the main tab bar is changed.
|
||||
// Tabs are indexed from left to right, starting at 0 (0: Map, 1: Events, 2: Header, 3: Connections, 4: Wild Pokemon).
|
||||
export function onMainTabChanged(oldTab, newTab) {
|
||||
|
||||
}
|
||||
|
||||
// Called when the selected tab in the map view tab bar is changed.
|
||||
// Tabs are indexed from left to right, starting at 0 (0: Metatiles, 1: Collision, 2: Prefabs).
|
||||
export function onMapViewTabChanged(oldTab, newTab) {
|
||||
|
||||
}
|
||||
|
||||
// Called when the visibility of the border and connecting maps is toggled on or off.
|
||||
export function onBorderVisibilityToggled(visible) {
|
||||
|
||||
}
|
|
@ -23,10 +23,11 @@ CustomScriptsEditor::CustomScriptsEditor(QWidget *parent) :
|
|||
for (int i = 0; i < paths.length(); i++)
|
||||
this->displayScript(paths.at(i), enabled.at(i));
|
||||
|
||||
this->importDir = userConfig.getProjectDir();
|
||||
this->fileDialogDir = userConfig.getProjectDir();
|
||||
|
||||
connect(ui->button_AddNewScript, &QAbstractButton::clicked, this, &CustomScriptsEditor::addNewScript);
|
||||
connect(ui->button_ReloadScripts, &QAbstractButton::clicked, this, &CustomScriptsEditor::reloadScripts);
|
||||
connect(ui->button_CreateNewScript, &QAbstractButton::clicked, this, &CustomScriptsEditor::createNewScript);
|
||||
connect(ui->button_LoadScript, &QAbstractButton::clicked, this, &CustomScriptsEditor::loadScript);
|
||||
connect(ui->button_RefreshScripts, &QAbstractButton::clicked, this, &CustomScriptsEditor::refreshScripts);
|
||||
connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &CustomScriptsEditor::dialogButtonClicked);
|
||||
|
||||
this->initShortcuts();
|
||||
|
@ -48,13 +49,17 @@ void CustomScriptsEditor::initShortcuts() {
|
|||
shortcut_open->setObjectName("shortcut_open");
|
||||
shortcut_open->setWhatsThis("Open Selected Scripts");
|
||||
|
||||
auto *shortcut_addNew = new Shortcut(QKeySequence(), this, SLOT(addNewScript()));
|
||||
shortcut_addNew->setObjectName("shortcut_addNew");
|
||||
shortcut_addNew->setWhatsThis("Add New Script...");
|
||||
auto *shortcut_createNew = new Shortcut(QKeySequence(), this, SLOT(createNewScript()));
|
||||
shortcut_createNew->setObjectName("shortcut_createNew");
|
||||
shortcut_createNew->setWhatsThis("Create New Script...");
|
||||
|
||||
auto *shortcut_reload = new Shortcut(QKeySequence(), this, SLOT(reloadScripts()));
|
||||
shortcut_reload->setObjectName("shortcut_reload");
|
||||
shortcut_reload->setWhatsThis("Reload Scripts");
|
||||
auto *shortcut_load = new Shortcut(QKeySequence(), this, SLOT(loadScript()));
|
||||
shortcut_load->setObjectName("shortcut_load");
|
||||
shortcut_load->setWhatsThis("Load Script...");
|
||||
|
||||
auto *shortcut_refresh = new Shortcut(QKeySequence(), this, SLOT(refreshScripts()));
|
||||
shortcut_refresh->setObjectName("shortcut_refresh");
|
||||
shortcut_refresh->setWhatsThis("Refresh Scripts");
|
||||
|
||||
shortcutsConfig.load();
|
||||
shortcutsConfig.setDefaultShortcuts(shortcutableObjects());
|
||||
|
@ -145,13 +150,54 @@ QString CustomScriptsEditor::chooseScript(QString dir) {
|
|||
return QFileDialog::getOpenFileName(this, "Choose Custom Script File", dir, "JavaScript Files (*.js)");
|
||||
}
|
||||
|
||||
void CustomScriptsEditor::addNewScript() {
|
||||
QString filepath = this->chooseScript(this->importDir);
|
||||
void CustomScriptsEditor::createNewScript() {
|
||||
QString filepath = QFileDialog::getSaveFileName(this, "Create New Script File", this->fileDialogDir + "/new_script.js", "JavaScript Files (*.js)");
|
||||
|
||||
// QFileDialog::getSaveFileName returns focus to the main editor window when closed. Workaround for this below
|
||||
this->raise();
|
||||
this->activateWindow();
|
||||
|
||||
if (filepath.isEmpty())
|
||||
return;
|
||||
this->importDir = filepath;
|
||||
this->fileDialogDir = filepath;
|
||||
|
||||
QFile scriptFile(filepath);
|
||||
if (!scriptFile.open(QIODevice::WriteOnly)) {
|
||||
logError(QString("Error: Could not open %1 for writing").arg(filepath));
|
||||
QMessageBox messageBox(this);
|
||||
messageBox.setText("Failed to create new script file!");
|
||||
messageBox.setInformativeText(QString("Could not open \"%1\" for writing").arg(filepath));
|
||||
messageBox.setIcon(QMessageBox::Warning);
|
||||
messageBox.exec();
|
||||
return;
|
||||
}
|
||||
ParseUtil parser;
|
||||
scriptFile.write(parser.readTextFile(":/text/script_template.txt").toUtf8());
|
||||
scriptFile.close();
|
||||
|
||||
this->displayNewScript(filepath);
|
||||
}
|
||||
|
||||
void CustomScriptsEditor::loadScript() {
|
||||
QString filepath = this->chooseScript(this->fileDialogDir);
|
||||
if (filepath.isEmpty())
|
||||
return;
|
||||
this->fileDialogDir = filepath;
|
||||
this->displayNewScript(filepath);
|
||||
}
|
||||
|
||||
void CustomScriptsEditor::displayNewScript(QString filepath) {
|
||||
if (filepath.startsWith(this->baseDir))
|
||||
filepath.remove(0, this->baseDir.length());
|
||||
|
||||
// Verify new script path is not already in list
|
||||
for (int i = 0; i < ui->list->count(); i++) {
|
||||
if (filepath == this->getScriptFilepath(ui->list->item(i), false)) {
|
||||
QMessageBox::information(this, "", QString("The script '%1' is already loaded").arg(filepath));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this->displayScript(filepath, true);
|
||||
this->markEdited();
|
||||
}
|
||||
|
@ -192,7 +238,7 @@ void CustomScriptsEditor::openSelectedScripts() {
|
|||
this->openScript(item);
|
||||
}
|
||||
|
||||
void CustomScriptsEditor::reloadScripts() {
|
||||
void CustomScriptsEditor::refreshScripts() {
|
||||
if (this->hasUnsavedChanges) {
|
||||
if (this->prompt("Scripts have been modified, save changes and reload the script engine?", QMessageBox::Yes) == QMessageBox::No)
|
||||
return;
|
||||
|
@ -218,7 +264,7 @@ void CustomScriptsEditor::save() {
|
|||
|
||||
userConfig.setCustomScripts(paths, enabledStates);
|
||||
this->hasUnsavedChanges = false;
|
||||
this->reloadScripts();
|
||||
this->refreshScripts();
|
||||
}
|
||||
|
||||
int CustomScriptsEditor::prompt(const QString &text, QMessageBox::StandardButton defaultButton) {
|
||||
|
|