diff --git a/include/scripting.h b/include/scripting.h index e2bfb1ff..c08bbd74 100644 --- a/include/scripting.h +++ b/include/scripting.h @@ -30,8 +30,9 @@ class Scripting { public: Scripting(MainWindow *mainWindow); - static void stop(); + ~Scripting(); static void init(MainWindow *mainWindow); + static void stop(); static void populateGlobalObject(MainWindow *mainWindow); static QJSEngine *getEngine(); static void invokeAction(int actionIndex); diff --git a/include/scriptutility.h b/include/scriptutility.h index 639e71f6..0d6fca75 100644 --- a/include/scriptutility.h +++ b/include/scriptutility.h @@ -10,7 +10,8 @@ class ScriptUtility : public QObject public: ScriptUtility(MainWindow *mainWindow); - void clearActions(); + ~ScriptUtility(); + QString getActionFunctionName(int actionIndex); Q_INVOKABLE bool registerAction(QString functionName, QString actionName, QString shortcut = ""); Q_INVOKABLE bool registerToggleAction(QString functionName, QString actionName, QString shortcut = "", bool checked = false); @@ -59,6 +60,7 @@ private: MainWindow *window; QList registeredActions; + QSet activeTimers; QHash actionMap; }; diff --git a/include/ui/noscrollcombobox.h b/include/ui/noscrollcombobox.h index 43db9deb..7b6f7522 100644 --- a/include/ui/noscrollcombobox.h +++ b/include/ui/noscrollcombobox.h @@ -14,6 +14,8 @@ public: void setNumberItem(int value); void setHexItem(uint32_t value); void setClearButtonEnabled(bool enabled); + void setEditable(bool editable); + void setLineEdit(QLineEdit *edit); private: void setItem(int index, const QString &text); diff --git a/src/scriptapi/apiutility.cpp b/src/scriptapi/apiutility.cpp index 61b6e978..a4aeae96 100644 --- a/src/scriptapi/apiutility.cpp +++ b/src/scriptapi/apiutility.cpp @@ -7,6 +7,18 @@ ScriptUtility::ScriptUtility(MainWindow *mainWindow) { this->window = mainWindow; } +ScriptUtility::~ScriptUtility() { + if (window && window->ui && window->ui->menuTools) { + for (auto action : this->registeredActions) { + window->ui->menuTools->removeAction(action); + } + } + for (auto timer : this->activeTimers) { + timer->stop(); + delete timer; + } +} + bool ScriptUtility::registerAction(QString functionName, QString actionName, QString shortcut) { if (!window || !window->ui || !window->ui->menuTools) return false; @@ -44,12 +56,6 @@ bool ScriptUtility::registerToggleAction(QString functionName, QString actionNam return true; } -void ScriptUtility::clearActions() { - for (auto action : this->registeredActions) { - window->ui->menuTools->removeAction(action); - } -} - QString ScriptUtility::getActionFunctionName(int actionIndex) { return this->actionMap.value(actionIndex); } @@ -58,11 +64,15 @@ void ScriptUtility::setTimeout(QJSValue callback, int milliseconds) { if (!callback.isCallable() || milliseconds < 0) return; - QTimer *timer = new QTimer(0); + QTimer *timer = new QTimer(); connect(timer, &QTimer::timeout, [=](){ - this->callTimeoutFunction(callback); + if (this->activeTimers.remove(timer)) { + this->callTimeoutFunction(callback); + timer->deleteLater(); + } }); - connect(timer, &QTimer::timeout, timer, &QTimer::deleteLater); + + this->activeTimers.insert(timer); timer->setSingleShot(true); timer->start(milliseconds); } diff --git a/src/scriptapi/scripting.cpp b/src/scriptapi/scripting.cpp index 82944be9..71fbabca 100644 --- a/src/scriptapi/scripting.cpp +++ b/src/scriptapi/scripting.cpp @@ -1,8 +1,10 @@ +#include + #include "scripting.h" #include "log.h" #include "config.h" -QMap callbackFunctions = { +const QMap callbackFunctions = { {OnProjectOpened, "onProjectOpened"}, {OnProjectClosed, "onProjectClosed"}, {OnBlockChanged, "onBlockChanged"}, @@ -22,10 +24,6 @@ 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; } @@ -39,7 +37,7 @@ void Scripting::init(MainWindow *mainWindow) { Scripting::Scripting(MainWindow *mainWindow) { this->mainWindow = mainWindow; - this->engine = new QJSEngine(mainWindow); + this->engine = new QJSEngine(); this->engine->installExtensions(QJSEngine::ConsoleExtension); const QStringList paths = userConfig.getCustomScriptPaths(); const QList enabled = userConfig.getCustomScriptsEnabled(); @@ -51,6 +49,13 @@ Scripting::Scripting(MainWindow *mainWindow) { this->scriptUtility = new ScriptUtility(mainWindow); } +Scripting::~Scripting() { + this->engine->setInterrupted(true); + qDeleteAll(this->imageCache); + delete this->engine; + delete this->scriptUtility; +} + void Scripting::loadModules(QStringList moduleFiles) { for (QString filepath : moduleFiles) { QString validPath = Project::getExistingFilepath(filepath); @@ -79,6 +84,11 @@ void Scripting::populateGlobalObject(MainWindow *mainWindow) { instance->engine->globalObject().setProperty("overlay", instance->engine->newQObject(mainWindow->ui->graphicsView_Map)); instance->engine->globalObject().setProperty("utility", instance->engine->newQObject(instance->scriptUtility)); + // Note: QJSEngine also has these functions, but not in Qt 5.15. + QQmlEngine::setObjectOwnership(mainWindow, QQmlEngine::CppOwnership); + QQmlEngine::setObjectOwnership(mainWindow->ui->graphicsView_Map, QQmlEngine::CppOwnership); + QQmlEngine::setObjectOwnership(instance->scriptUtility, QQmlEngine::CppOwnership); + QJSValue constants = instance->engine->newObject(); // Get version numbers diff --git a/src/ui/noscrollcombobox.cpp b/src/ui/noscrollcombobox.cpp index fcb662c7..5288ad97 100644 --- a/src/ui/noscrollcombobox.cpp +++ b/src/ui/noscrollcombobox.cpp @@ -23,6 +23,18 @@ NoScrollComboBox::NoScrollComboBox(QWidget *parent) this->setValidator(validator); } +// On macOS QComboBox::setEditable and QComboBox::setLineEdit will override our changes to the focus policy, so we enforce it here. +void NoScrollComboBox::setEditable(bool editable) { + auto policy = focusPolicy(); + QComboBox::setEditable(editable); + setFocusPolicy(policy); +} +void NoScrollComboBox::setLineEdit(QLineEdit *edit) { + auto policy = focusPolicy(); + QComboBox::setLineEdit(edit); + setFocusPolicy(policy); +} + void NoScrollComboBox::wheelEvent(QWheelEvent *event) { // Only allow scrolling to modify contents when it explicitly has focus.