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),
_resetRecentMaxPacketsSoon(true),
_swatch(NULL),
_pasteMode(false),
_scriptEngine(NULL)
_pasteMode(false)
{
_applicationStartupTime = startup_time;
_window->setWindowTitle("Interface");
@ -259,7 +258,7 @@ Application::~Application() {
_sharedVoxelSystem.changeTree(new VoxelTree);
VoxelTreeElement::removeDeleteHook(&_voxels); // we don't need to do this processing on shutdown
delete Menu::getInstance();
Menu::getInstance()->deleteLater();
delete _settings;
delete _followMode;
@ -4388,12 +4387,6 @@ void Application::packetSentNotification(ssize_t length) {
void Application::loadScript() {
// shut down and stop any existing script
if (_scriptEngine) {
_scriptEngine->stop();
_scriptEngine = NULL;
}
QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
QString suggestedName = desktopLocation.append("/script.js");
@ -4425,32 +4418,30 @@ void Application::loadScript() {
delete[] entireFile;
// 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
// we can use the same ones from the application.
_scriptEngine->getVoxelScriptingInterface()->setPacketSender(&_voxelEditSender);
_scriptEngine->getParticleScriptingInterface()->setPacketSender(&_particleEditSender);
scriptEngine->getVoxelScriptingInterface()->setPacketSender(&_voxelEditSender);
scriptEngine->getParticleScriptingInterface()->setPacketSender(&_particleEditSender);
//_scriptEngine->getVoxelScriptingInterface()->setJurisdictionListener();
//_scriptEngine->getParticleScriptingInterface()->setJurisdictionListener();
QThread* workerThread = new QThread(this);
// 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
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
connect(workerThread, SIGNAL(terminated()), _scriptEngine, SLOT(deleteLater()));
// 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()), workerThread, SLOT(deleteLater()));
// 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()
workerThread->start();

View file

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

View file

@ -92,6 +92,7 @@ Menu::Menu() :
addDisabledActionAndSeparator(fileMenu, "Scripts");
addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, appInstance, SLOT(loadScript()));
_activeScriptsMenu = fileMenu->addMenu("Running Scripts");
addDisabledActionAndSeparator(fileMenu, "Voxels");
addActionToQMenuAndActionHash(fileMenu, MenuOption::ExportVoxels, Qt::CTRL | Qt::Key_E, appInstance, SLOT(exportVoxels()));
@ -709,6 +710,13 @@ QAction* Menu::addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu,
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) {
return _actionHash.value(menuOption)->isChecked();
}

View file

@ -13,6 +13,8 @@
#include <QHash>
#include <QKeySequence>
#include <AbstractMenuInterface.h>
enum FrustumDrawMode {
FRUSTUM_DRAW_MODE_ALL,
FRUSTUM_DRAW_MODE_VECTORS,
@ -37,7 +39,7 @@ class BandwidthDialog;
class VoxelStatsDialog;
class LodToolsDialog;
class Menu : public QMenuBar {
class Menu : public QMenuBar, public AbstractMenuInterface {
Q_OBJECT
public:
static Menu* getInstance();
@ -71,6 +73,15 @@ public:
// User Tweakable PPS from Voxel Server
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:
void bandwidthDetails();
void voxelStatsDetails();
@ -110,12 +121,6 @@ private:
/// helper method to have separators with labels that are also compatible with OS X
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,
const QString actionName,
@ -141,6 +146,8 @@ private:
int _boundaryLevelAdjust;
QAction* _useVoxelShader;
int _maxVoxelPacketsPerSecond;
QMenu* _activeScriptsMenu;
};
namespace MenuOption {

View file

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

View file

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

View file

@ -15,13 +15,15 @@
#include <QtCore/QObject>
#include <QtCore/QUrl>
#include <VoxelScriptingInterface.h>
#include <AbstractMenuInterface.h>
#include <ParticleScriptingInterface.h>
#include <VoxelScriptingInterface.h>
class ScriptEngine : public QObject {
Q_OBJECT
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
VoxelScriptingInterface* getVoxelScriptingInterface() { return &_voxelScriptingInterface; }
@ -42,9 +44,17 @@ signals:
protected:
QString _scriptContents;
bool _isFinished;
void setupMenuItems();
void cleanMenuItems();
private:
VoxelScriptingInterface _voxelScriptingInterface;
ParticleScriptingInterface _particleScriptingInterface;
bool _wantMenuItems;
QString _scriptMenuName;
AbstractMenuInterface* _menu;
static int _scriptNumber;
};
#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__) */