multiple scripts running at same time, menu interface for scripts

This commit is contained in:
ZappoMan 2013-12-16 09:16:51 -08:00
parent a220804fb0
commit 524a41468c
8 changed files with 106 additions and 40 deletions

View file

@ -139,8 +139,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
_recentMaxPackets(0), _recentMaxPackets(0),
_resetRecentMaxPacketsSoon(true), _resetRecentMaxPacketsSoon(true),
_swatch(NULL), _swatch(NULL),
_pasteMode(false), _pasteMode(false)
_scriptEngine(NULL)
{ {
_applicationStartupTime = startup_time; _applicationStartupTime = startup_time;
_window->setWindowTitle("Interface"); _window->setWindowTitle("Interface");
@ -259,7 +258,7 @@ Application::~Application() {
_sharedVoxelSystem.changeTree(new VoxelTree); _sharedVoxelSystem.changeTree(new VoxelTree);
VoxelTreeElement::removeDeleteHook(&_voxels); // we don't need to do this processing on shutdown VoxelTreeElement::removeDeleteHook(&_voxels); // we don't need to do this processing on shutdown
delete Menu::getInstance(); Menu::getInstance()->deleteLater();
delete _settings; delete _settings;
delete _followMode; delete _followMode;
@ -4388,12 +4387,6 @@ void Application::packetSentNotification(ssize_t length) {
void Application::loadScript() { void Application::loadScript() {
// shut down and stop any existing script // shut down and stop any existing script
if (_scriptEngine) {
_scriptEngine->stop();
_scriptEngine = NULL;
}
QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
QString suggestedName = desktopLocation.append("/script.js"); QString suggestedName = desktopLocation.append("/script.js");
@ -4425,32 +4418,30 @@ void Application::loadScript() {
delete[] entireFile; delete[] entireFile;
// start the script on a new thread... // start the script on a new thread...
_scriptEngine = new ScriptEngine(script); bool wantMenuItems = true; // tells the ScriptEngine object to add menu items for itself
ScriptEngine* scriptEngine = new ScriptEngine(script, wantMenuItems, fileName, Menu::getInstance());
// setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so // setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so
// we can use the same ones from the application. // we can use the same ones from the application.
_scriptEngine->getVoxelScriptingInterface()->setPacketSender(&_voxelEditSender); scriptEngine->getVoxelScriptingInterface()->setPacketSender(&_voxelEditSender);
_scriptEngine->getParticleScriptingInterface()->setPacketSender(&_particleEditSender); scriptEngine->getParticleScriptingInterface()->setPacketSender(&_particleEditSender);
//_scriptEngine->getVoxelScriptingInterface()->setJurisdictionListener();
//_scriptEngine->getParticleScriptingInterface()->setJurisdictionListener();
QThread* workerThread = new QThread(this); QThread* workerThread = new QThread(this);
// when the worker thread is started, call our engine's run.. // when the worker thread is started, call our engine's run..
connect(workerThread, SIGNAL(started()), _scriptEngine, SLOT(run())); connect(workerThread, SIGNAL(started()), scriptEngine, SLOT(run()));
// when the engine emits finished, call our threads quit // when the engine emits finished, call our threads quit
connect(_scriptEngine, SIGNAL(finished()), workerThread, SLOT(quit())); connect(scriptEngine, SIGNAL(finished()), workerThread, SLOT(quit()));
// when the thread is terminated, add both _scriptEngine and thread to the deleteLater queue // when the thread is terminated, add both scriptEngine and thread to the deleteLater queue
connect(workerThread, SIGNAL(terminated()), _scriptEngine, SLOT(deleteLater())); connect(workerThread, SIGNAL(terminated()), scriptEngine, SLOT(deleteLater()));
connect(workerThread, SIGNAL(terminated()), workerThread, SLOT(deleteLater())); connect(workerThread, SIGNAL(terminated()), workerThread, SLOT(deleteLater()));
// when the application is about to quit, stop our script engine so it unwinds properly // when the application is about to quit, stop our script engine so it unwinds properly
connect(this, SIGNAL(aboutToQuit()), _scriptEngine, SLOT(stop())); connect(this, SIGNAL(aboutToQuit()), scriptEngine, SLOT(stop()));
_scriptEngine->moveToThread(workerThread); scriptEngine->moveToThread(workerThread);
// Starts an event loop, and emits workerThread->started() // Starts an event loop, and emits workerThread->started()
workerThread->start(); workerThread->start();

View file

@ -497,8 +497,6 @@ private:
std::vector<VoxelFade> _voxelFades; std::vector<VoxelFade> _voxelFades;
std::vector<Avatar*> _avatarFades; std::vector<Avatar*> _avatarFades;
ScriptEngine* _scriptEngine;
}; };
#endif /* defined(__interface__Application__) */ #endif /* defined(__interface__Application__) */

View file

@ -92,6 +92,7 @@ Menu::Menu() :
addDisabledActionAndSeparator(fileMenu, "Scripts"); addDisabledActionAndSeparator(fileMenu, "Scripts");
addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, appInstance, SLOT(loadScript())); addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, appInstance, SLOT(loadScript()));
_activeScriptsMenu = fileMenu->addMenu("Running Scripts");
addDisabledActionAndSeparator(fileMenu, "Voxels"); addDisabledActionAndSeparator(fileMenu, "Voxels");
addActionToQMenuAndActionHash(fileMenu, MenuOption::ExportVoxels, Qt::CTRL | Qt::Key_E, appInstance, SLOT(exportVoxels())); addActionToQMenuAndActionHash(fileMenu, MenuOption::ExportVoxels, Qt::CTRL | Qt::Key_E, appInstance, SLOT(exportVoxels()));
@ -709,6 +710,13 @@ QAction* Menu::addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu,
return action; return action;
} }
void Menu::removeAction(QMenu* menu, const QString& actionName) {
qDebug() << "removeAction() menu=" << menu << " actionName=" << actionName << "\n";
menu->removeAction(_actionHash.value(actionName));
}
bool Menu::isOptionChecked(const QString& menuOption) { bool Menu::isOptionChecked(const QString& menuOption) {
return _actionHash.value(menuOption)->isChecked(); return _actionHash.value(menuOption)->isChecked();
} }

View file

@ -13,6 +13,8 @@
#include <QHash> #include <QHash>
#include <QKeySequence> #include <QKeySequence>
#include <AbstractMenuInterface.h>
enum FrustumDrawMode { enum FrustumDrawMode {
FRUSTUM_DRAW_MODE_ALL, FRUSTUM_DRAW_MODE_ALL,
FRUSTUM_DRAW_MODE_VECTORS, FRUSTUM_DRAW_MODE_VECTORS,
@ -37,7 +39,7 @@ class BandwidthDialog;
class VoxelStatsDialog; class VoxelStatsDialog;
class LodToolsDialog; class LodToolsDialog;
class Menu : public QMenuBar { class Menu : public QMenuBar, public AbstractMenuInterface {
Q_OBJECT Q_OBJECT
public: public:
static Menu* getInstance(); static Menu* getInstance();
@ -71,6 +73,15 @@ public:
// User Tweakable PPS from Voxel Server // User Tweakable PPS from Voxel Server
int getMaxVoxelPacketsPerSecond() const { return _maxVoxelPacketsPerSecond; } int getMaxVoxelPacketsPerSecond() const { return _maxVoxelPacketsPerSecond; }
virtual QMenu* getActiveScriptsMenu() { return _activeScriptsMenu;}
virtual QAction* addActionToQMenuAndActionHash(QMenu* destinationMenu,
const QString actionName,
const QKeySequence& shortcut = 0,
const QObject* receiver = NULL,
const char* member = NULL,
QAction::MenuRole role = QAction::NoRole);
virtual void removeAction(QMenu* menu, const QString& actionName);
public slots: public slots:
void bandwidthDetails(); void bandwidthDetails();
void voxelStatsDetails(); void voxelStatsDetails();
@ -110,12 +121,6 @@ private:
/// helper method to have separators with labels that are also compatible with OS X /// helper method to have separators with labels that are also compatible with OS X
void addDisabledActionAndSeparator(QMenu* destinationMenu, const QString& actionName); void addDisabledActionAndSeparator(QMenu* destinationMenu, const QString& actionName);
QAction* addActionToQMenuAndActionHash(QMenu* destinationMenu,
const QString actionName,
const QKeySequence& shortcut = 0,
const QObject* receiver = NULL,
const char* member = NULL,
QAction::MenuRole role = QAction::NoRole);
QAction* addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu, QAction* addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu,
const QString actionName, const QString actionName,
@ -141,6 +146,8 @@ private:
int _boundaryLevelAdjust; int _boundaryLevelAdjust;
QAction* _useVoxelShader; QAction* _useVoxelShader;
int _maxVoxelPacketsPerSecond; int _maxVoxelPacketsPerSecond;
QMenu* _activeScriptsMenu;
}; };
namespace MenuOption { namespace MenuOption {

View file

@ -416,7 +416,7 @@ void Particle::update() {
void Particle::runScript() { void Particle::runScript() {
if (!_updateScript.isEmpty()) { if (!_updateScript.isEmpty()) {
qDebug() << "Script: " << _updateScript << "\n"; //qDebug() << "Script: " << _updateScript << "\n";
QScriptEngine engine; QScriptEngine engine;

View file

@ -21,12 +21,40 @@
#include "ScriptEngine.h" #include "ScriptEngine.h"
ScriptEngine::ScriptEngine(QString scriptContents) { int ScriptEngine::_scriptNumber = 1;
ScriptEngine::ScriptEngine(QString scriptContents, bool wantMenuItems,
const char* scriptMenuName, AbstractMenuInterface* menu) {
_scriptContents = scriptContents; _scriptContents = scriptContents;
_isFinished = false; _isFinished = false;
_wantMenuItems = wantMenuItems;
if (scriptMenuName) {
_scriptMenuName = "Stop ";
_scriptMenuName.append(scriptMenuName);
} else {
_scriptMenuName = "Stop Script ";
_scriptNumber++;
_scriptMenuName.append(_scriptNumber);
}
_menu = menu;
}
void ScriptEngine::setupMenuItems() {
if (_menu && _wantMenuItems) {
_menu->addActionToQMenuAndActionHash(_menu->getActiveScriptsMenu(), _scriptMenuName, 0, this, SLOT(stop()));
}
}
void ScriptEngine::cleanMenuItems() {
if (_menu && _wantMenuItems) {
_menu->removeAction(_menu->getActiveScriptsMenu(), _scriptMenuName);
}
} }
void ScriptEngine::run() { void ScriptEngine::run() {
setupMenuItems();
QScriptEngine engine; QScriptEngine engine;
_voxelScriptingInterface.init(); _voxelScriptingInterface.init();
@ -68,12 +96,7 @@ void ScriptEngine::run() {
int thisFrame = 0; int thisFrame = 0;
qDebug() << "before while... thisFrame:" << thisFrame << "\n";
while (!_isFinished) { while (!_isFinished) {
qDebug() << "while... thisFrame:" << thisFrame << "\n";
int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * VISUAL_DATA_CALLBACK_USECS) - usecTimestampNow(); int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * VISUAL_DATA_CALLBACK_USECS) - usecTimestampNow();
if (usecToSleep > 0) { if (usecToSleep > 0) {
usleep(usecToSleep); usleep(usecToSleep);
@ -105,7 +128,6 @@ void ScriptEngine::run() {
} }
if (willSendVisualDataCallBack) { if (willSendVisualDataCallBack) {
qDebug() << "willSendVisualDataCallback thisFrame:" << thisFrame << "\n";
emit willSendVisualDataCallback(); emit willSendVisualDataCallback();
} }
@ -115,5 +137,6 @@ void ScriptEngine::run() {
qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n"; qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n";
} }
} }
cleanMenuItems();
emit finished(); emit finished();
} }

View file

@ -15,13 +15,15 @@
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QUrl> #include <QtCore/QUrl>
#include <VoxelScriptingInterface.h> #include <AbstractMenuInterface.h>
#include <ParticleScriptingInterface.h> #include <ParticleScriptingInterface.h>
#include <VoxelScriptingInterface.h>
class ScriptEngine : public QObject { class ScriptEngine : public QObject {
Q_OBJECT Q_OBJECT
public: public:
ScriptEngine(QString scriptContents); ScriptEngine(QString scriptContents, bool wantMenuItems = false,
const char* scriptMenuName = NULL, AbstractMenuInterface* menu = NULL);
/// Access the VoxelScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener /// Access the VoxelScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener
VoxelScriptingInterface* getVoxelScriptingInterface() { return &_voxelScriptingInterface; } VoxelScriptingInterface* getVoxelScriptingInterface() { return &_voxelScriptingInterface; }
@ -42,9 +44,17 @@ signals:
protected: protected:
QString _scriptContents; QString _scriptContents;
bool _isFinished; bool _isFinished;
void setupMenuItems();
void cleanMenuItems();
private: private:
VoxelScriptingInterface _voxelScriptingInterface; VoxelScriptingInterface _voxelScriptingInterface;
ParticleScriptingInterface _particleScriptingInterface; ParticleScriptingInterface _particleScriptingInterface;
bool _wantMenuItems;
QString _scriptMenuName;
AbstractMenuInterface* _menu;
static int _scriptNumber;
}; };
#endif /* defined(__hifi__ScriptEngine__) */ #endif /* defined(__hifi__ScriptEngine__) */

View file

@ -0,0 +1,29 @@
//
// AbstractMenuInterface.h
// hifi
//
// Created by Brad Hefta-Gaub on 12/16/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
//
#ifndef __hifi__AbstractMenuInterface__
#define __hifi__AbstractMenuInterface__
#include <QMenuBar>
//#include <QHash>
//#include <QKeySequence>
class AbstractMenuInterface {
public:
virtual QMenu* getActiveScriptsMenu() = 0;
virtual QAction* addActionToQMenuAndActionHash(QMenu* destinationMenu,
const QString actionName,
const QKeySequence& shortcut = 0,
const QObject* receiver = NULL,
const char* member = NULL,
QAction::MenuRole role = QAction::NoRole) = 0;
virtual void removeAction(QMenu* menu, const QString& actionName) = 0;
};
#endif /* defined(__hifi__AbstractMenuInterface__) */